Update OEMCrypto test comments and logs
Merge from Widevine repo of http://go/wvgerrit/121886 This CL merges some changes from branch rvc-dev to sc-dev that prepared it for merge. One change is that the unit tests now say they are part of Android S instead of R. Bug: 180546871 Change-Id: I2ebbd8f7b8586389ebb75f3743a2dc2ad8caa214
This commit is contained in:
@@ -137,6 +137,11 @@ void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f,
|
||||
!check_status);
|
||||
buffer_length *= 2) {
|
||||
sts = f(buffer_length);
|
||||
if (check_status && sts != OEMCrypto_SUCCESS &&
|
||||
sts != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
LOGI("Test exits huge buffer loop for length:%zu, status:%d",
|
||||
buffer_length, sts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +175,17 @@ const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB};
|
||||
// const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576};
|
||||
// clang-format on
|
||||
|
||||
// Return a printable string from data. If all the characters are printable,
|
||||
// then just use the string. Otherwise, convert to hex.
|
||||
std::string MaybeHex(const uint8_t* data, size_t length) {
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
if (!isprint(data[i])) return "0x" + wvcdm::HexEncode(data, length);
|
||||
}
|
||||
return std::string(reinterpret_cast<const char*>(data), length);
|
||||
}
|
||||
std::string MaybeHex(const std::vector<uint8_t>& data) {
|
||||
return MaybeHex(data.data(), data.size());
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
||||
@@ -202,6 +218,17 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) {
|
||||
Session s;
|
||||
s.open();
|
||||
OEMCrypto_DestBufferDesc output_descriptor;
|
||||
int secure_fd = kHugeRandomNumber;
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_FreeSecureBuffer(s.session_id(), &output_descriptor,
|
||||
secure_fd));
|
||||
s.close();
|
||||
}
|
||||
|
||||
/// @addtogroup basic
|
||||
/// @{
|
||||
|
||||
@@ -212,15 +239,20 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
|
||||
*/
|
||||
TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||
const std::string log_message =
|
||||
"OEMCrypto unit tests for API 16.4. Tests last updated 2020-10-07";
|
||||
"OEMCrypto unit tests for API 16.3 or 4. Tests last updated 2021-02-22";
|
||||
cout << " " << log_message << "\n";
|
||||
cout << " "
|
||||
<< "These tests are part of Android S."
|
||||
<< "\n";
|
||||
LOGI("%s", log_message.c_str());
|
||||
// If any of the following fail, then it is time to update the log message
|
||||
// above.
|
||||
EXPECT_EQ(ODK_MAJOR_VERSION, 16);
|
||||
// Note on minor versions. Widevine requires version 16.3 or greater for CE
|
||||
// CDM and Android devices. For CE CDM devices that do not support usage
|
||||
// tables, we strongly recommend 16.4.
|
||||
// tables, we strongly recommend 16.4. Note: This is the version of the ODK
|
||||
// library built into the tests, which might be different from the version
|
||||
// that is pre-compiled into liboemcrypto.so.
|
||||
EXPECT_GE(ODK_MINOR_VERSION, 3);
|
||||
EXPECT_LE(ODK_MINOR_VERSION, 4);
|
||||
EXPECT_EQ(kCurrentAPI, 16u);
|
||||
@@ -229,7 +261,9 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
|
||||
ASSERT_EQ('L', level[0]);
|
||||
cout << " OEMCrypto Security Level is " << level << endl;
|
||||
uint32_t version = OEMCrypto_APIVersion();
|
||||
cout << " OEMCrypto API version is " << version << endl;
|
||||
uint32_t minor_version = OEMCrypto_MinorAPIVersion();
|
||||
cout << " OEMCrypto API version is " << version << "."
|
||||
<< minor_version << endl;
|
||||
if (OEMCrypto_SupportsUsageTable()) {
|
||||
cout << " OEMCrypto supports usage tables" << endl;
|
||||
} else {
|
||||
@@ -661,8 +695,8 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) {
|
||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
|
||||
dest_buffer_descriptor.buffer.clear.address = output_buffer.data();
|
||||
dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size() - 1;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
ASSERT_NE(
|
||||
OEMCrypto_SUCCESS,
|
||||
OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(),
|
||||
input_buffer.size(), &dest_buffer_descriptor,
|
||||
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
|
||||
@@ -896,8 +930,8 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
|
||||
uint8_t dev_id[128] = {0};
|
||||
size_t dev_id_len = 128;
|
||||
sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len);
|
||||
cout << " NormalGetDeviceId: dev_id = " << dev_id
|
||||
<< " len = " << dev_id_len << endl;
|
||||
cout << " NormalGetDeviceId: dev_id = "
|
||||
<< MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
@@ -1039,7 +1073,7 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) {
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
dev_id.resize(dev_id_len);
|
||||
cout << " NormalGetDeviceId: dev_id = " << dev_id.data()
|
||||
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
||||
<< " len = " << dev_id_len << endl;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
@@ -2355,6 +2389,39 @@ TEST_P(OEMCryptoLicenseTest,
|
||||
!kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize) {
|
||||
LoadLicense();
|
||||
OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[0].key_id,
|
||||
session_.license().keys[0].key_id_length,
|
||||
OEMCrypto_CipherMode_CTR);
|
||||
|
||||
size_t input_buffer_size = 1;
|
||||
vector<uint8_t> in_buffer(input_buffer_size);
|
||||
vector<uint8_t> out_buffer(in_buffer.size());
|
||||
|
||||
OEMCrypto_SampleDescription sample_description;
|
||||
OEMCrypto_SubSampleDescription subsample_description;
|
||||
GenerateSimpleSampleDescription(in_buffer, out_buffer, &sample_description,
|
||||
&subsample_description);
|
||||
|
||||
OEMCrypto_SubSampleDescription* sub_samples =
|
||||
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||
sample_description.subsamples);
|
||||
// If Decrypt cenc API does not check for overflow on clear + encrypted
|
||||
// addition operation. This will result in 1 which will match with input data
|
||||
// length, which causes validation to pass.
|
||||
sub_samples[0].num_bytes_clear = 2;
|
||||
sub_samples[0].num_bytes_encrypted = 0xFFFFFFFFFFFFFFFF;
|
||||
|
||||
// Create the pattern description (always 0,0 for CTR)
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
|
||||
// Try to decrypt the data
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1,
|
||||
&pattern));
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) {
|
||||
TestDecryptCENCForHugeBufferLengths(
|
||||
@@ -3850,50 +3917,17 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
OEMCrypto_SUCCESS);
|
||||
}
|
||||
|
||||
void TestDecryptCENC() {
|
||||
OEMCryptoResult sts;
|
||||
void TestDecryptCENC() { ASSERT_EQ(DecryptCENC(), OEMCrypto_SUCCESS); }
|
||||
|
||||
// OEMCrypto only supports providing a decrypt hash for one sample.
|
||||
if (samples_.size() > 1) verify_crc_ = false;
|
||||
|
||||
// If supported, check the decrypt hashes.
|
||||
if (verify_crc_) {
|
||||
const TestSample& sample = samples_[0];
|
||||
|
||||
uint32_t hash =
|
||||
wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size());
|
||||
ASSERT_EQ(OEMCrypto_SetDecryptHash(
|
||||
session_.session_id(), 1,
|
||||
reinterpret_cast<const uint8_t*>(&hash), sizeof(hash)),
|
||||
OEMCrypto_SUCCESS);
|
||||
}
|
||||
|
||||
// Build an array of just the sample descriptions.
|
||||
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||
sample_descriptions.reserve(samples_.size());
|
||||
for (TestSample& sample : samples_) {
|
||||
// This must be deferred until this point in case the test modifies the
|
||||
// buffer before testing decrypt.
|
||||
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||
// Append to the description array.
|
||||
sample_descriptions.push_back(sample.description);
|
||||
}
|
||||
|
||||
// Perform decryption using the test data that was previously set up.
|
||||
sts = DecryptFallbackChain::Decrypt(
|
||||
session_.session_id(), sample_descriptions.data(),
|
||||
sample_descriptions.size(), cipher_mode_, &pattern_);
|
||||
ASSERT_EQ(sts, OEMCrypto_SUCCESS);
|
||||
|
||||
// Validate the decrypted data.
|
||||
void ValidateDecryptedData() {
|
||||
for (TestSample& sample : samples_) {
|
||||
if (sample.description.buffers.output_descriptor.type ==
|
||||
OEMCrypto_BufferType_Clear) {
|
||||
const size_t total_size = sample.description.buffers.input_data_length;
|
||||
// To verify there is no buffer overrun after decrypting, look at the
|
||||
// padded bytes just after the data buffer that was written. It should
|
||||
// not have changed from the original 0xaa that we set in MakeBuffer
|
||||
// function.
|
||||
// padded bytes just after the data buffer that was written. It
|
||||
// should not have changed from the original 0xaa that we set in
|
||||
// MakeBuffer function.
|
||||
if (decrypt_inplace_) {
|
||||
EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size,
|
||||
sample.encrypted_buffer.end(), 0xaa),
|
||||
@@ -3919,6 +3953,41 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
}
|
||||
}
|
||||
|
||||
OEMCryptoResult DecryptCENC() {
|
||||
// OEMCrypto only supports providing a decrypt hash for one sample.
|
||||
if (samples_.size() > 1) verify_crc_ = false;
|
||||
|
||||
// If supported, check the decrypt hashes.
|
||||
if (verify_crc_) {
|
||||
const TestSample& sample = samples_[0];
|
||||
|
||||
uint32_t hash =
|
||||
wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size());
|
||||
OEMCrypto_SetDecryptHash(session_.session_id(), 1,
|
||||
reinterpret_cast<const uint8_t*>(&hash),
|
||||
sizeof(hash));
|
||||
}
|
||||
|
||||
// Build an array of just the sample descriptions.
|
||||
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||
sample_descriptions.reserve(samples_.size());
|
||||
for (TestSample& sample : samples_) {
|
||||
// This must be deferred until this point in case the test modifies the
|
||||
// buffer before testing decrypt.
|
||||
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||
// Append to the description array.
|
||||
sample_descriptions.push_back(sample.description);
|
||||
}
|
||||
|
||||
// Perform decryption using the test data that was previously set up.
|
||||
OEMCryptoResult result = DecryptFallbackChain::Decrypt(
|
||||
session_.session_id(), sample_descriptions.data(),
|
||||
sample_descriptions.size(), cipher_mode_, &pattern_);
|
||||
if (result != OEMCrypto_SUCCESS) return result;
|
||||
ValidateDecryptedData();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Parameters of test case
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern_;
|
||||
OEMCryptoCipherMode cipher_mode_;
|
||||
@@ -4094,7 +4163,6 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) {
|
||||
// max_sample_size.
|
||||
const size_t subsample_size =
|
||||
std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size);
|
||||
|
||||
size_t bytes_remaining = max_sample_size;
|
||||
std::vector<SubsampleSize> subsample_sizes;
|
||||
while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) {
|
||||
@@ -4113,6 +4181,103 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSampleAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(TestDecryptCENC());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||
OEMCryptoMemoryDecryptCENCForHugeNumberOfSubSamples) {
|
||||
auto oemcrypto_function = [&](size_t number_of_subsamples) {
|
||||
std::vector<SubsampleSize> subsample_sizes;
|
||||
while (number_of_subsamples-- > 0) {
|
||||
subsample_sizes.push_back({1, 1});
|
||||
}
|
||||
SetSubsampleSizes(subsample_sizes);
|
||||
LoadLicense();
|
||||
MakeBuffers();
|
||||
EncryptData();
|
||||
OEMCryptoResult result = DecryptCENC();
|
||||
// Closing the session and opening it for next iteration.
|
||||
// If it is last iteration, session will be closed in teardown method of
|
||||
// class.
|
||||
session_.close();
|
||||
session_.open();
|
||||
InstallTestRSAKey(&session_);
|
||||
return result;
|
||||
};
|
||||
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||
OEMCryptoMemoryCheckDecryptCENCStatusForHugeNumberOfSubSamples) {
|
||||
size_t number_of_subsamples = 10000;
|
||||
std::vector<SubsampleSize> subsample_sizes;
|
||||
while (number_of_subsamples-- > 0) {
|
||||
subsample_sizes.push_back({100, 100});
|
||||
}
|
||||
SetSubsampleSizes(subsample_sizes);
|
||||
LoadLicense();
|
||||
MakeBuffers();
|
||||
EncryptData();
|
||||
// Build an array of just the sample descriptions.
|
||||
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||
sample_descriptions.reserve(samples_.size());
|
||||
for (TestSample& sample : samples_) {
|
||||
// This must be deferred until this point in case the test modifies the
|
||||
// buffer before testing decrypt.
|
||||
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||
// Append to the description array.
|
||||
sample_descriptions.push_back(sample.description);
|
||||
}
|
||||
OEMCryptoResult result = OEMCrypto_DecryptCENC(
|
||||
session_.session_id(), sample_descriptions.data(), 1, &pattern_);
|
||||
LOGD("Large number of subsamples test has return code %d", result);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||
OEMCryptoMemoryCheckDecryptCENCStatusForHugeSubSample) {
|
||||
std::vector<SubsampleSize> subsample_sizes;
|
||||
subsample_sizes.push_back({100000, 100000});
|
||||
SetSubsampleSizes(subsample_sizes);
|
||||
LoadLicense();
|
||||
MakeBuffers();
|
||||
EncryptData();
|
||||
// Build an array of just the sample descriptions.
|
||||
std::vector<OEMCrypto_SampleDescription> sample_descriptions;
|
||||
sample_descriptions.reserve(samples_.size());
|
||||
for (TestSample& sample : samples_) {
|
||||
// This must be deferred until this point in case the test modifies the
|
||||
// buffer before testing decrypt.
|
||||
sample.description.buffers.input_data = sample.encrypted_buffer.data();
|
||||
// Append to the description array.
|
||||
sample_descriptions.push_back(sample.description);
|
||||
}
|
||||
OEMCryptoResult result = OEMCrypto_DecryptCENC(
|
||||
session_.session_id(), sample_descriptions.data(), 1, &pattern_);
|
||||
LOGD("Large subsample test has return code %d", result);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoSessionTestsDecryptTests,
|
||||
OEMCryptoMemoryDecryptCENCForHugeNumberOfSamples) {
|
||||
auto oemcrypto_function = [&](size_t number_of_samples) {
|
||||
std::vector<std::vector<SubsampleSize>> samples;
|
||||
std::vector<SubsampleSize> subsample_sizes;
|
||||
subsample_sizes.push_back({1, 1});
|
||||
while (number_of_samples-- > 0) {
|
||||
samples.push_back(subsample_sizes);
|
||||
}
|
||||
SetSampleSizes(samples);
|
||||
LoadLicense();
|
||||
MakeBuffers();
|
||||
EncryptData();
|
||||
OEMCryptoResult result = DecryptCENC();
|
||||
// Closing the session and opening it for next iteration.
|
||||
// If it is last iteration, session will be closed in teardown method of
|
||||
// class.
|
||||
session_.close();
|
||||
session_.open();
|
||||
InstallTestRSAKey(&session_);
|
||||
return result;
|
||||
};
|
||||
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, 1, 2 * MiB, kCheckStatus);
|
||||
}
|
||||
|
||||
// Based on the resource rating, OEMCrypto should be able to handle the maximum
|
||||
// subsample size.
|
||||
TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSubsample) {
|
||||
|
||||
Reference in New Issue
Block a user