Source release 16.4.0

This commit is contained in:
John W. Bruce
2020-10-09 16:08:56 -07:00
parent 160df9f57a
commit 9d17a531ee
562 changed files with 52913 additions and 37426 deletions

View File

@@ -2,8 +2,29 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// OEMCrypto unit tests
//
/**
* @mainpage OEMCrypto Unit Tests
*
* The OEMCrypto unit tests are designed to verify that an implementation of
* OEMCrypto is correctly supporting the OEMCrypto API.
*
* @defgroup basic Basic Functionality Tests
* Basic functionality tests.
*
* @defgroup license License Request Tests
* Test for requesting and loading licenses.
*
* @defgroup renewal License Renewal Tests
* Tests for renewing licenses.
*
* @defgroup decrypt Decrypt Tests
* Tests for decrypting content.
*
* @defgroup usage_table Usage Table Tests
* Tests that use the usage table.
*/
#include <ctype.h>
#include <openssl/aes.h>
#include <openssl/err.h>
@@ -17,6 +38,7 @@
#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <functional>
#include <iostream>
#include <map>
#include <string>
@@ -82,6 +104,9 @@ constexpr size_t kBufferOverrunPadding = 16;
// Resource tiers:
constexpr size_t KiB = 1024;
constexpr size_t MiB = 1024 * 1024;
// Huge input buffer length used for OEMCryptoMemory* tests.
constexpr size_t kHugeInputBufferLength = 100 * MiB;
constexpr bool kCheckStatus = true;
// With OEMCrypto v15 and above, we have different resource requirements
// depending on the resource rating reported by OEMCrypto. This function looks
// up the required value for the specified resource for the target OEMCrypto
@@ -93,6 +118,32 @@ T GetResourceValue(T (&resource_values)[N]) {
return resource_values[global_features.resource_rating - 1];
}
// Used for testing oemcrypto APIs with huge buffers.
typedef const std::function<OEMCryptoResult(size_t)> oemcrypto_function;
// Function to test APIs that expect a buffer length as input
// by passing huge buffer lengths upto end_buffer_length and test that the API
// doesn't crash.
void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f,
size_t start_buffer_length,
size_t end_buffer_length,
bool check_status) {
OEMCryptoResult sts = OEMCrypto_SUCCESS;
for (size_t buffer_length = start_buffer_length;
buffer_length < end_buffer_length &&
(sts == OEMCrypto_SUCCESS || sts == OEMCrypto_ERROR_SHORT_BUFFER ||
!check_status);
buffer_length *= 2) {
sts = f(buffer_length);
}
}
// Function to test APIs that expect a buffer length as input
// by passing huge buffer lengths upto kHugeInputBufferLength and test that
// the API doesn't crash.
void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, bool check_status) {
TestHugeLengthDoesNotCrashAPI(f, 1, kHugeInputBufferLength, check_status);
}
// After API 16, we require 300 entries in the usage table. Before API 16, we
// required 200.
size_t RequiredUsageSize() {
@@ -148,19 +199,27 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
}
};
//
// General tests.
// This test is first, becuase it might give an idea why other
// tests are failing when the device has the wrong keybox installed.
/// @addtogroup basic
/// @{
/**
* Verifies initialization and logs version information.
* This test is first, because it might give an idea why other
* tests are failing when the device has the wrong keybox installed.
*/
TEST_F(OEMCryptoClientTest, VersionNumber) {
const std::string log_message =
"OEMCrypto unit tests for API 16.3. Tests last updated 2020-06-01";
"OEMCrypto unit tests for API 16.4. Tests last updated 2020-10-07";
cout << " " << log_message << "\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);
EXPECT_EQ(ODK_MINOR_VERSION, 3);
// 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.
EXPECT_GE(ODK_MINOR_VERSION, 3);
EXPECT_LE(ODK_MINOR_VERSION, 4);
EXPECT_EQ(kCurrentAPI, 16u);
const char* level = OEMCrypto_SecurityLevel();
ASSERT_NE(nullptr, level);
@@ -186,14 +245,18 @@ TEST_F(OEMCryptoClientTest, VersionNumber) {
ASSERT_LE(version, kCurrentAPI);
}
// The resource rating is a number from 1 to 4. The first three levels were
// initially defined in API 15 and they were expanded in API 16.
/**
* The resource rating is a number from 1 to 4. The first three levels
* were initially defined in API 15 and they were expanded in API 16.
*/
TEST_F(OEMCryptoClientTest, ResourceRatingAPI15) {
ASSERT_GE(OEMCrypto_ResourceRatingTier(), 1u);
ASSERT_LE(OEMCrypto_ResourceRatingTier(), 4u);
}
// OEMCrypto must declare what type of provisioning scheme it uses.
/**
* OEMCrypto must declare what type of provisioning scheme it uses.
*/
TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) {
OEMCrypto_ProvisioningMethod provisioning_method =
OEMCrypto_GetProvisioningMethod();
@@ -228,10 +291,10 @@ TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) {
OEMCrypto_HDCP_Capability current, maximum;
sts = OEMCrypto_GetHDCPCapability(&current, &maximum);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
printf(" Current HDCP Capability: 0x%02x = %s.\n", current,
HDCPCapabilityAsString(current));
printf(" Maximum HDCP Capability: 0x%02x = %s.\n", maximum,
HDCPCapabilityAsString(maximum));
printf(" Current HDCP Capability: 0x%02x = %s.\n",
static_cast<unsigned int>(current), HDCPCapabilityAsString(current));
printf(" Maximum HDCP Capability: 0x%02x = %s.\n",
static_cast<unsigned int>(maximum), HDCPCapabilityAsString(maximum));
}
TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
@@ -255,6 +318,14 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) {
OEMCrypto_LoadSRM(bad_srm.data(), bad_srm.size()));
}
TEST_F(OEMCryptoClientTest, OEMCryptoMemoryLoadSrmForLargeSrm) {
auto oemcrypto_function = [](size_t buffer_length) {
vector<uint8_t> srm_buffer(buffer_length);
return OEMCrypto_LoadSRM(srm_buffer.data(), srm_buffer.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) {
size_t sessions_count;
ASSERT_EQ(OEMCrypto_SUCCESS,
@@ -285,6 +356,15 @@ TEST_F(OEMCryptoClientTest, NormalInitTermination) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
}
// Test that set sandbox doesn't crash for a large sandbox id leangth.
TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForLargeSandboxIdLength) {
auto oemcrypto_function = [](size_t buffer_length) {
vector<uint8_t> buffer(buffer_length);
return OEMCrypto_SetSandbox(buffer.data(), buffer.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus);
}
//
// Session Tests
//
@@ -375,6 +455,17 @@ TEST_F(OEMCryptoClientTest, GetRandomLargeBuffer) {
ASSERT_LE(count, 3); // P(count > 3) = 1/256^3 = 6e-8.
}
// Verify that GetRandom doesn't crash for large input lengths.
TEST_F(OEMCryptoClientTest, OEMCryptoMemoryGetRandomForLargeBuffer) {
auto oemcrypto_function = [](size_t buffer_length) {
vector<uint8_t> buffer(buffer_length);
// TODO(ellurubharath, fredgc): Need to re-evaluate this on a real device
// as GetRandom can be slow.
return OEMCrypto_GetRandom(buffer.data(), buffer.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus);
}
TEST_F(OEMCryptoClientTest, GenerateNonce) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
@@ -509,6 +600,131 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) {
ASSERT_EQ(input_buffer, output_buffer);
}
TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForHugeBufferLengths) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> input_buffer;
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure;
auto oemcrypto_function = [&s, &dest_buffer_descriptor,
&input_buffer](size_t buffer_length) {
input_buffer.resize(buffer_length);
int secure_fd;
OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer(
s.session_id(), buffer_length, &dest_buffer_descriptor, &secure_fd);
if (sts != OEMCrypto_SUCCESS) {
LOGI("Secure buffers are not supported.");
return sts;
}
dest_buffer_descriptor.buffer.secure.handle_length = buffer_length;
OEMCryptoResult status = OEMCrypto_CopyBuffer(
s.session_id(), input_buffer.data(), buffer_length,
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor,
secure_fd);
return status;
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
TEST_F(OEMCryptoClientTest,
OEMCryptoMemoryCopyBufferDirectForHugeBufferLengths) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> input_buffer;
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Direct;
auto oemcrypto_function = [&s, &dest_buffer_descriptor,
&input_buffer](size_t buffer_length) {
input_buffer.resize(buffer_length);
OEMCryptoResult status = OEMCrypto_CopyBuffer(
s.session_id(), input_buffer.data(), buffer_length,
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
return status;
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForOutOfRangeOffset) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> input_buffer;
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure;
size_t buffer_length = KiB;
input_buffer.resize(buffer_length);
int secure_fd;
if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length,
&dest_buffer_descriptor,
&secure_fd) != OEMCrypto_SUCCESS) {
LOGI("Secure buffers are not supported.");
return;
}
dest_buffer_descriptor.buffer.secure.handle_length = buffer_length;
auto oemcrypto_function = [&s, &dest_buffer_descriptor, &input_buffer,
&buffer_length](size_t offset) {
dest_buffer_descriptor.buffer.secure.offset = offset;
return OEMCrypto_CopyBuffer(
s.session_id(), input_buffer.data(), buffer_length,
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor,
secure_fd);
}
TEST_F(OEMCryptoClientTest,
OEMCryptoMemoryCopyBufferForOutOfRangeHandleLength) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> input_buffer;
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Secure;
size_t buffer_length = KiB;
input_buffer.resize(buffer_length);
int secure_fd;
if (OEMCrypto_AllocateSecureBuffer(s.session_id(), buffer_length,
&dest_buffer_descriptor,
&secure_fd) != OEMCrypto_SUCCESS) {
LOGI("Secure buffers are not supported.");
return;
}
dest_buffer_descriptor.buffer.secure.handle_length = kHugeInputBufferLength;
ASSERT_NO_FATAL_FAILURE(
OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), buffer_length,
&dest_buffer_descriptor,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample));
OEMCrypto_FreeSecureBuffer(s.session_id(), &dest_buffer_descriptor,
secure_fd);
}
TEST_F(OEMCryptoClientTest, ClearCopyTestInvalidSubsampleFlag) {
uint8_t oemcrypto_invalid_subsample_flag = 85;
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
size_t max_size = GetResourceValue(kMaxSubsampleSize);
vector<uint8_t> input_buffer(max_size);
GetRandBytes(input_buffer.data(), input_buffer.size());
vector<uint8_t> output_buffer(max_size);
OEMCrypto_DestBufferDesc dest_buffer_descriptor;
dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear;
dest_buffer_descriptor.buffer.clear.address = output_buffer.data();
dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size();
ASSERT_NO_FATAL_FAILURE(OEMCrypto_CopyBuffer(
s.session_id(), input_buffer.data(), input_buffer.size(),
&dest_buffer_descriptor, oemcrypto_invalid_subsample_flag));
}
TEST_F(OEMCryptoClientTest, CanLoadTestKeys) {
ASSERT_NE(DeviceFeatures::NO_METHOD, global_features.derive_key_method)
<< "Session tests cannot run with out a test keybox or RSA cert.";
@@ -532,6 +748,33 @@ class OEMCryptoKeyboxTest : public OEMCryptoClientTest {
}
};
// Test that OEMCrypto_InstallKeyboxOrOEMCert doesn't crash for large keybox.
TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryInstallKeyboxForHugeKeyboxBuffer) {
auto f = [](size_t keybox_length) {
vector<uint8_t> keybox(keybox_length);
memcpy(keybox.data(), &kTestKeybox, sizeof(kTestKeybox));
return OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size());
};
// Starting at sizeof(kTestKeybox) as we are copying valid keybox
// at beginning of generated buffers.
TestHugeLengthDoesNotCrashAPI(f, sizeof(kTestKeybox), kHugeInputBufferLength,
kCheckStatus);
}
// This test verifies that load test key box doesn't crash for large
// buffer length.
TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryLoadTestKeyBoxForHugeKeyboxBuffer) {
auto f = [](size_t keybox_length) {
vector<uint8_t> keybox(keybox_length);
memcpy(keybox.data(), &kTestKeybox, sizeof(kTestKeybox));
return OEMCrypto_LoadTestKeybox(keybox.data(), keybox.size());
};
// Starting at sizeof(kTestKeybox) as we are copying valid keybox
// at beginning of generated buffers.
TestHugeLengthDoesNotCrashAPI(f, sizeof(kTestKeybox), kHugeInputBufferLength,
kCheckStatus);
}
// This test is used to print the device ID to stdout.
TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
OEMCryptoResult sts;
@@ -543,6 +786,15 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
}
TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetDeviceIdForHugeIdLength) {
auto oemcrypto_function = [](size_t input_length) {
size_t device_id_length = input_length;
vector<uint8_t> device_id(device_id_length);
return OEMCrypto_GetDeviceID(device_id.data(), &device_id_length);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) {
OEMCryptoResult sts;
uint8_t dev_id[128];
@@ -570,11 +822,20 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) {
sts = OEMCrypto_GetKeyData(key_data, &key_data_len);
uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
printf(" NormalGetKeyData: system_id = %d = 0x%04X, version=%d\n",
printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n",
htonl(data[1]), htonl(data[1]), htonl(data[0]));
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
}
TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForLargeIdLength) {
auto oemcrypto_function = [](size_t input_length) {
size_t key_data_length = input_length;
vector<uint8_t> key_data(key_data_length);
return OEMCrypto_GetKeyData(key_data.data(), &key_data_length);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus);
}
TEST_F(OEMCryptoKeyboxTest, GetKeyDataNullPointer) {
OEMCryptoResult sts;
uint8_t key_data[256];
@@ -606,6 +867,42 @@ TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) {
enc_context.data(), enc_context.size()));
}
TEST_F(OEMCryptoKeyboxTest,
OEMCryptoMemoryGenerateDerivedKeysForLargeMacContextLength) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
auto oemcrypto_function = [&s, &mac_context,
&enc_context](size_t buffer_length) {
mac_context.resize(buffer_length);
return OEMCrypto_GenerateDerivedKeys(s.session_id(), mac_context.data(),
mac_context.size(), enc_context.data(),
enc_context.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
TEST_F(OEMCryptoKeyboxTest,
OEMCryptoMemoryGenerateDerivedKeysForLargeEncContextLength) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
auto oemcrypto_function = [&s, &mac_context,
&enc_context](size_t buffer_length) {
enc_context.resize(buffer_length);
return OEMCrypto_GenerateDerivedKeys(s.session_id(), mac_context.data(),
mac_context.size(), enc_context.data(),
enc_context.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
// This class is for tests that have an OEM Certificate instead of a keybox.
class OEMCryptoProv30Test : public OEMCryptoClientTest {};
@@ -644,6 +941,11 @@ TEST_F(OEMCryptoProv30Test, OEMCertValid) {
ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert(kVerify)); // Load and verify.
}
/// @}
/// @addtogroup license
/// @{
// This verifies that the OEM Certificate cannot be used for other RSA padding
// schemes. Those schemes should only be used by cast receiver certificates.
TEST_F(OEMCryptoProv30Test, OEMCertForbiddenPaddingScheme) {
@@ -711,6 +1013,27 @@ TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) {
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
}
TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForLargeCertLength) {
if (wrapped_rsa_key_.size() == 0) {
// If we don't have a wrapped key yet, create one.
// This wrapped key will be shared by all sessions in the test.
ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey());
}
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
// Install the DRM Cert's RSA key.
ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key_));
ASSERT_NO_FATAL_FAILURE(s.PreparePublicKey());
auto oemcrypto_function = [](size_t input_length) {
size_t public_cert_length = input_length;
vector<uint8_t> public_cert(public_cert_length);
return OEMCrypto_GetOEMPublicCertificate(public_cert.data(),
&public_cert_length);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus);
}
//
// AddKey Tests
//
@@ -836,6 +1159,7 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonce) {
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
}
// Verify that a preloaded license may be loaded without first signing the
@@ -849,6 +1173,8 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequest) {
license_messages_.set_api_version(license_api_version_);
}
license_messages_.set_control(0);
// Notice that we do not call SignAndVerifyRequest -- we do not need a request
// in order to generate a response for a preloaded license.
// The test code uses the core request to create the core response.
license_messages_.core_request().api_major_version = ODK_MAJOR_VERSION;
license_messages_.core_request().api_minor_version = ODK_MINOR_VERSION;
@@ -861,6 +1187,34 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequest) {
ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session2));
ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse(&session2));
ASSERT_NO_FATAL_FAILURE(session2.TestDecryptCTR(true, OEMCrypto_SUCCESS));
}
// Verify that a license may be reloaded without a nonce, but with a nonzero
// rental duration. In order to start the rental clock, we sign a dummy license
// instead.
TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequestRentalDuration) {
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
license_messages_.set_control(0);
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
// It is not recommended for a license without a nonce to have a nonzero
// rental duration. But there are content providers that have licenses with
// this policy.
license_messages_.core_response().timer_limits.rental_duration_seconds =
kDuration;
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
// Load license in a different session, which did not create the request.
Session session2;
ASSERT_NO_FATAL_FAILURE(session2.open());
ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session2));
// However, in order to start the rental clock, we have to sign something. So
// we will sign a dummy license request.
LicenseRoundTrip dummy_license(&session2);
ASSERT_NO_FATAL_FAILURE(dummy_license.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse(&session2));
ASSERT_NO_FATAL_FAILURE(session2.TestDecryptCTR(true, OEMCrypto_SUCCESS));
}
// Verify that a license may be loaded with a nonce.
@@ -870,6 +1224,7 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonce) {
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
}
// Verify that a second license may not be loaded in a session.
@@ -1336,6 +1691,10 @@ TEST_F(OEMCryptoLicenseTestAPI16, BadCoreHashAPI16) {
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
}
/// @}
/// @addtogroup decrypt
/// @{
// LoadKeys should fail if we try to load keys with no keys.
TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeys) {
@@ -1520,6 +1879,58 @@ TEST_P(OEMCryptoLicenseTest, QueryKeyControl) {
strlen(key_id), reinterpret_cast<uint8_t*>(&block), &size));
}
// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_id_length.
TEST_F(OEMCryptoLicenseTestAPI16,
OEMCryptoMemoryQueryKeyControlForHugeKeyIdLength) {
ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce());
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
OEMCrypto_SESSION session_id = session_.session_id();
vector<uint8_t> valid_key_id(
license_messages_.response_data().keys[0].key_id,
license_messages_.response_data().keys[0].key_id + kTestKeyIdMaxLength);
auto oemcrypto_function = [&session_id,
&valid_key_id](size_t additional_key_id_length) {
vector<uint8_t> key_id(valid_key_id);
key_id.resize(valid_key_id.size() + additional_key_id_length);
KeyControlBlock block;
size_t size = sizeof(block);
return OEMCrypto_QueryKeyControl(session_id, key_id.data(), key_id.size(),
reinterpret_cast<uint8_t*>(&block), &size);
};
// We do not want to stop as soon as API results in an error as it would
// return error on first iteration as key_id is invalid.
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus);
}
// Test OEMCrypto_QueryKeyControl doesn't crash for huge key_control_block
// length.
TEST_F(OEMCryptoLicenseTestAPI16,
OEMCryptoMemoryQueryKeyControlForHugeKeyControlBlockLength) {
ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce());
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
OEMCrypto_SESSION session_id = session_.session_id();
uint8_t* key_id = license_messages_.response_data().keys[0].key_id;
size_t key_id_length =
license_messages_.response_data().keys[0].key_id_length;
auto oemcrypto_function = [&session_id, &key_id,
&key_id_length](size_t buffer_length) {
size_t key_control_block_length = buffer_length;
vector<uint8_t> key_control_block(key_control_block_length);
return OEMCrypto_QueryKeyControl(session_id, key_id, key_id_length,
key_control_block.data(),
&key_control_block_length);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
// If the device says it supports anti-rollback in the hardware, then it should
// accept a key control block with the anti-rollback hardware bit set.
// Otherwise, it should reject that key control block.
@@ -1718,6 +2129,11 @@ TEST_P(OEMCryptoSessionTestDecryptWithHDCP, DecryptAPI09) {
INSTANTIATE_TEST_CASE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP,
Range(1, 6));
/// @}
/// @addtogroup renewal
/// @{
//
// Load, Refresh Keys Test
//
@@ -1903,6 +2319,30 @@ TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) {
OEMCrypto_GetHashErrorCode(session_.session_id(), &frame_number));
}
// This test verifies that OEMCrypto_SetDecryptHash doesn't crash for a very
// large hash buffer.
TEST_F(OEMCryptoLicenseTestAPI16,
OEMCryptoMemoryDecryptHashForLargeHashBuffer) {
uint32_t session_id = session_.session_id();
auto f = [session_id](size_t hash_length) {
uint32_t frame_number = 1;
vector<uint8_t> hash_buffer(hash_length);
return OEMCrypto_SetDecryptHash(session_id, frame_number,
hash_buffer.data(), hash_buffer.size());
};
TestHugeLengthDoesNotCrashAPI(f, sizeof(uint32_t), kHugeInputBufferLength,
kCheckStatus);
}
// This test verifies OEMCrypto_SetDecryptHash for out of range frame number.
TEST_P(OEMCryptoLicenseTest, DecryptHashForOutOfRangeFrameNumber) {
uint32_t frame_number = 40;
uint32_t hash = 42;
ASSERT_NO_FATAL_FAILURE(OEMCrypto_SetDecryptHash(
session_.session_id(), frame_number,
reinterpret_cast<const uint8_t*>(&hash), sizeof(hash)));
}
//
// Decrypt Tests -- these test Decrypt CTR mode only.
//
@@ -3075,6 +3515,50 @@ TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) {
enc_context.data(), enc_context.size()));
}
TEST_F(OEMCryptoUsesCertificate,
OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeMacContext) {
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(),
encoded_rsa_key_.size()));
ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
session_.FillDefaultContext(&mac_context, &enc_context);
OEMCrypto_SESSION session_id = session_.session_id();
auto oemcrypto_function = [&session_id, &enc_context, &mac_context,
&enc_session_key](size_t buffer_length) {
mac_context.resize(buffer_length);
return OEMCrypto_DeriveKeysFromSessionKey(
session_id, enc_session_key.data(), enc_session_key.size(),
mac_context.data(), mac_context.size(), enc_context.data(),
enc_context.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
TEST_F(OEMCryptoUsesCertificate,
OEMCryptoMemoryDeriveKeysFromSessionKeyForLargeEncContext) {
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(),
encoded_rsa_key_.size()));
ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
session_.FillDefaultContext(&mac_context, &enc_context);
OEMCrypto_SESSION session_id = session_.session_id();
auto oemcrypto_function = [&session_id, &enc_context, &mac_context,
&enc_session_key](size_t buffer_length) {
enc_context.resize(buffer_length);
return OEMCrypto_DeriveKeysFromSessionKey(
session_id, enc_session_key.data(), enc_session_key.size(),
mac_context.data(), mac_context.size(), enc_context.data(),
enc_context.size());
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
}
// This test attempts to use alternate algorithms for loaded device certs.
class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
protected:
@@ -3178,19 +3662,82 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
OEMCryptoResult sts = provisioning_messages.LoadResponse();
encoded_rsa_key_ = provisioning_messages.encoded_rsa_key();
wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key();
key_loaded_ = (wrapped_rsa_key_.size() > 0);
key_loaded_ = (OEMCrypto_SUCCESS == sts);
if (key_loaded_) {
encoded_rsa_key_ = provisioning_messages.encoded_rsa_key();
wrapped_rsa_key_ = provisioning_messages.wrapped_rsa_key();
EXPECT_GT(wrapped_rsa_key_.size(), 0u);
EXPECT_EQ(nullptr, find(wrapped_rsa_key_, encoded_rsa_key_));
}
if (force) {
EXPECT_EQ(OEMCrypto_SUCCESS, sts);
EXPECT_EQ(nullptr, find(wrapped_rsa_key_, encoded_rsa_key_));
ASSERT_TRUE(key_loaded_);
}
}
bool key_loaded_;
};
TEST_F(OEMCryptoLoadsCertificateAlternates,
OEMCryptoMemoryGenerateRSASignatureForLargeBuffer) {
OEMCryptoResult sts;
LoadWithAllowedSchemes(kSign_PKCS1_Block1, false);
// If the device is a cast receiver, then this scheme is required.
if (global_features.cast_receiver) ASSERT_TRUE(key_loaded_);
if (key_loaded_) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
sts = OEMCrypto_LoadDRMPrivateKey(s.session_id(), OEMCrypto_RSA_Private_Key,
wrapped_rsa_key_.data(),
wrapped_rsa_key_.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
vector<uint8_t> message_buffer(10);
size_t signature_length = 0;
sts = OEMCrypto_GenerateRSASignature(s.session_id(), message_buffer.data(),
message_buffer.size(), nullptr,
&signature_length, kSign_PKCS1_Block1);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
ASSERT_NE(static_cast<size_t>(0), signature_length);
vector<uint8_t> signature(signature_length);
auto oemcrypto_function = [&](size_t buffer_length) {
message_buffer.resize(buffer_length);
return OEMCrypto_GenerateRSASignature(
s.session_id(), message_buffer.data(), message_buffer.size(),
signature.data(), &signature_length, kSign_PKCS1_Block1);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
s.close();
}
}
TEST_F(OEMCryptoLoadsCertificateAlternates,
OEMCryptoMemoryGenerateRSASignatureForLargeSignatureLength) {
OEMCryptoResult sts;
LoadWithAllowedSchemes(kSign_PKCS1_Block1, false);
// If the device is a cast receiver, then this scheme is required.
if (global_features.cast_receiver) ASSERT_TRUE(key_loaded_);
if (key_loaded_) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
sts = OEMCrypto_LoadDRMPrivateKey(s.session_id(), OEMCrypto_RSA_Private_Key,
wrapped_rsa_key_.data(),
wrapped_rsa_key_.size());
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
vector<uint8_t> message_buffer(50);
vector<uint8_t> signature;
auto oemcrypto_function = [&](size_t signature_length) {
signature.resize(signature_length);
return OEMCrypto_GenerateRSASignature(
s.session_id(), message_buffer.data(), message_buffer.size(),
signature.data(), &signature_length, kSign_PKCS1_Block1);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus);
s.close();
}
}
// The alternate padding is only required for cast receivers, but all devices
// should forbid the alternate padding for regular certificates.
TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) {
@@ -3201,7 +3748,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) {
// The alternate padding is only required for cast receivers, but if a device
// does load an alternate certificate, it should NOT use it for generating
// a license request signature.
TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1_API16) {
TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) {
// Try to load an RSA key with alternative padding schemes. This signing
// scheme is used by cast receivers.
LoadWithAllowedSchemes(kSign_PKCS1_Block1, false);
@@ -4282,6 +4829,9 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest {
if (alter_data) {
signature[0] ^= 42;
}
if (signature.size() < signature_size) {
signature.resize(signature_size);
}
sts = OEMCrypto_SelectKey(session_.session_id(),
session_.license().keys[key_index].key_id,
@@ -4357,6 +4907,17 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) {
ASSERT_EQ(expected_encrypted, buffer);
}
TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemorySelectKeyForHugeKeyIdLength) {
EncryptAndLoadKeys();
OEMCrypto_SESSION session_id = session_.session_id();
auto oemcrypto_function = [session_id](size_t key_id_length) {
vector<uint8_t> key_id(key_id_length);
return OEMCrypto_SelectKey(session_id, key_id.data(), key_id.size(),
OEMCrypto_CipherMode_CTR);
};
TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus);
}
// Test Generic_Decrypt works correctly.
TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) {
EncryptAndLoadKeys();
@@ -4821,6 +5382,11 @@ INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoTest,
INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest,
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
/// @}
/// @addtogroup usage_table
/// @{
// Test usage table functionality.
class LicenseWithUsageEntry {
public:
@@ -5871,7 +6437,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) {
OEMCryptoResult status = OEMCrypto_SUCCESS;
while (successful_count < attempt_count && status == OEMCrypto_SUCCESS) {
wvcdm::TestSleep::SyncFakeClock();
LOGD("Creating license for entry %zd", successful_count);
LOGD("Creating license for entry %zu", successful_count);
entries.push_back(
std::unique_ptr<LicenseWithUsageEntry>(new LicenseWithUsageEntry()));
entries.back()->set_pst("pst " + std::to_string(successful_count));
@@ -5897,7 +6463,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) {
successful_count++;
}
}
LOGD("successful_count = %d", successful_count);
LOGD("successful_count = %zu", successful_count);
if (status != OEMCrypto_SUCCESS) {
// If we failed to create this many entries because of limited resources,
// then the error returned should be insufficient resources.
@@ -6009,6 +6575,38 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) {
ASSERT_EQ(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse());
}
TEST_P(OEMCryptoUsageTableTest, LoadAndReloadEntries) {
constexpr size_t kEntryCount = 10;
std::vector<LicenseWithUsageEntry> entries(kEntryCount);
for (LicenseWithUsageEntry& entry : entries) {
entry.license_messages().set_api_version(license_api_version_);
}
for (size_t i = 0; i < kEntryCount; ++i) {
const std::string create_description =
"Creating entry #" + std::to_string(i);
// Create and update a new entry.
LicenseWithUsageEntry& new_entry = entries[i];
ASSERT_NO_FATAL_FAILURE(new_entry.MakeOfflineAndClose(this))
<< create_description;
// Reload all entries, starting with the most recently created.
for (size_t j = 0; j <= i; ++j) {
const std::string reload_description =
"Reloading entry #" + std::to_string(i - j) +
", after creating entry #" + std::to_string(i);
LicenseWithUsageEntry& old_entry = entries[i - j];
ASSERT_NO_FATAL_FAILURE(old_entry.session().open());
ASSERT_NO_FATAL_FAILURE(old_entry.ReloadUsageEntry())
<< reload_description;
ASSERT_NO_FATAL_FAILURE(
old_entry.session().UpdateUsageEntry(&encrypted_usage_header_))
<< reload_description;
ASSERT_NO_FATAL_FAILURE(old_entry.session().close());
}
}
}
// A usage report with the wrong pst should fail.
TEST_P(OEMCryptoUsageTableTest, GenerateReportWrongPST) {
LicenseWithUsageEntry entry;
@@ -6174,9 +6772,7 @@ TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) {
// on a device that allows an application to set the clock.
class OEMCryptoUsageTableTestWallClock : public OEMCryptoUsageTableTest {
public:
void SetUp() override {
OEMCryptoUsageTableTest::SetUp();
}
void SetUp() override { OEMCryptoUsageTableTest::SetUp(); }
void TearDown() override {
wvcdm::TestSleep::ResetRollback();
@@ -6320,4 +6916,5 @@ INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoUsageTableDefragTest,
INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoUsageTableTestWallClock,
Values<uint32_t>(kCurrentAPI));
/// @}
} // namespace wvoec