Sync oemcrypto files from cdm udc-dev to Android
Changes included in this CL: 166806: Update OEMCrypto_GetDeviceInformation() | https://widevine-internal-review.googlesource.com/c/cdm/+/166806 166808: Update Android L3 after OEMCrypto_GetDeviceInformation() signature changes | https://widevine-internal-review.googlesource.com/c/cdm/+/166808 166809: Decode device info and write it to CSR payload | https://widevine-internal-review.googlesource.com/c/cdm/+/166809 167158: Fix Android include path and copy_files | https://widevine-internal-review.googlesource.com/c/cdm/+/167158 167159: Fix common typos and use inclusive language suggested by Android linter | https://widevine-internal-review.googlesource.com/c/cdm/+/167159 165618: Explicitly state python3 where needed. | https://widevine-internal-review.googlesource.com/c/cdm/+/165618 166757: Update Android.bp for Android | https://widevine-internal-review.googlesource.com/c/cdm/+/166757 164993: Refactor basic oemcrypto unit tests | https://widevine-internal-review.googlesource.com/c/cdm/+/164993 164978: Update OEMCrypto Unit Test Docs | https://widevine-internal-review.googlesource.com/c/cdm/+/164978 166941: Update make files for OEMCrypto | https://widevine-internal-review.googlesource.com/c/cdm/+/166941 165279: Refactor license unit tests | https://widevine-internal-review.googlesource.com/c/cdm/+/165279 165318: Refactor provisioning unit tests | https://widevine-internal-review.googlesource.com/c/cdm/+/165318 164800: Add extra check for renew on license load unit test | https://widevine-internal-review.googlesource.com/c/cdm/+/164800 165860: Remove duplicate definition of MaybeHex() | https://widevine-internal-review.googlesource.com/c/cdm/+/165860 164889: Updated CoreCommonRequestFromMessage and fix test | https://widevine-internal-review.googlesource.com/c/cdm/+/164889 164967: Add OPK pre-hook and post-hook error codes | https://widevine-internal-review.googlesource.com/c/cdm/+/164967 165140: Add hidden device_id_length to v18 provisioning message | https://widevine-internal-review.googlesource.com/c/cdm/+/165140 165204: Fix memory leak in oemcrypto test | https://widevine-internal-review.googlesource.com/c/cdm/+/165204 165958: Fix oemcrypto_generic_verify_fuzz mutator signature offset | https://widevine-internal-review.googlesource.com/c/cdm/+/165958 166037: Support SHA-256 in OEMCrypto Session Util | https://widevine-internal-review.googlesource.com/c/cdm/+/166037 Test: Run GtsMediaTests on Pixel 7 Bug: 270612144 Change-Id: Iff0820a2de7d043a820470a130af65b0dcadb759
This commit is contained in:
807
libwvdrmengine/oemcrypto/test/oemcrypto_license_test.cpp
Normal file
807
libwvdrmengine/oemcrypto/test/oemcrypto_license_test.cpp
Normal file
@@ -0,0 +1,807 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
//
|
||||
|
||||
#include "oemcrypto_license_test.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_basic_test.h"
|
||||
#include "oemcrypto_resource_test.h"
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
#include "platform.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
// Function to test APIs that expect a buffer length as input
|
||||
// by passing huge buffer lengths up to 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to test APIs that expect a buffer length as input
|
||||
// by passing huge buffer lengths up to kHugeInputBufferLength and test that
|
||||
// the API doesn't crash.
|
||||
void TestHugeLengthDoesNotCrashAPI(oemcrypto_function f, bool check_status) {
|
||||
TestHugeLengthDoesNotCrashAPI(f, 1, kHugeInputBufferLength, check_status);
|
||||
}
|
||||
|
||||
// This test verifies that OEMCrypto can load the total number of keys required
|
||||
// for the reported resource level.
|
||||
void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session) {
|
||||
const size_t max_total_keys = GetResourceValue(kMaxTotalKeys);
|
||||
ASSERT_LE(num_keys_per_session, kMaxNumKeys) << "Update test constants.";
|
||||
std::vector<std::unique_ptr<Session>> sessions;
|
||||
std::vector<std::unique_ptr<LicenseRoundTrip>> licenses;
|
||||
size_t total_keys = 0;
|
||||
for (size_t i = 0; total_keys < max_total_keys; i++) {
|
||||
sessions.push_back(std::unique_ptr<Session>(new Session()));
|
||||
licenses.push_back(std::unique_ptr<LicenseRoundTrip>(
|
||||
new LicenseRoundTrip(sessions[i].get())));
|
||||
const size_t num_keys =
|
||||
std::min(max_total_keys - total_keys, num_keys_per_session);
|
||||
licenses[i]->set_num_keys(static_cast<uint32_t>(num_keys));
|
||||
total_keys += num_keys;
|
||||
ASSERT_NO_FATAL_FAILURE(sessions[i]->open());
|
||||
ASSERT_NO_FATAL_FAILURE(util->InstallTestDrmKey(sessions[i].get()));
|
||||
ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest());
|
||||
}
|
||||
for (size_t i = 0; i < licenses.size(); i++) {
|
||||
ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse());
|
||||
}
|
||||
constexpr bool kSelectKeyFirst = true;
|
||||
for (size_t i = 0; i < licenses.size(); i++) {
|
||||
for (size_t key_index = 0; key_index < licenses[i]->num_keys();
|
||||
key_index++) {
|
||||
ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR(
|
||||
kSelectKeyFirst, OEMCrypto_SUCCESS, key_index));
|
||||
}
|
||||
}
|
||||
// Second call to decrypt for each session.
|
||||
for (size_t i = 0; i < licenses.size(); i++) {
|
||||
for (size_t key_index = 0; key_index < licenses[i]->num_keys();
|
||||
key_index++) {
|
||||
ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR(
|
||||
kSelectKeyFirst, OEMCrypto_SUCCESS, key_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoSessionTestKeyboxTest, TestKeyboxIsValid) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoSessionTests,
|
||||
OEMCryptoMemoryPrepareLicenseRequestForHugeRequestMessageLength) {
|
||||
TestPrepareLicenseRequestForHugeBufferLengths(
|
||||
[](size_t message_size, LicenseRoundTrip* license_messages) {
|
||||
license_messages->set_message_size(message_size);
|
||||
},
|
||||
kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoSessionTests,
|
||||
OEMCryptoMemoryPrepareLicenseRequestForHugeCoreMessageLength) {
|
||||
TestPrepareLicenseRequestForHugeBufferLengths(
|
||||
[](size_t core_message_size, LicenseRoundTrip* license_messages) {
|
||||
license_messages->set_core_message_size(core_message_size);
|
||||
},
|
||||
kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoSessionTests,
|
||||
OEMCryptoMemoryPrepareLicenseRequestForHugeSignatureLength) {
|
||||
// There is a limit of signature length that gets validated. Hence not
|
||||
// checking status as we would like to test it for all possible signature
|
||||
// lengths.
|
||||
TestPrepareLicenseRequestForHugeBufferLengths(
|
||||
[](size_t length, LicenseRoundTrip* license_messages) {
|
||||
license_messages->set_request_signature_size(length);
|
||||
},
|
||||
!kCheckStatus);
|
||||
}
|
||||
|
||||
// Verify that a license may be signed.
|
||||
TEST_P(OEMCryptoLicenseTest, SignLicenseRequest) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
}
|
||||
|
||||
// Verify that a large license request may be signed.
|
||||
TEST_P(OEMCryptoLicenseTest, SignLargeLicenseRequest) {
|
||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||
license_messages_.set_message_size(max_size);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
}
|
||||
|
||||
// Verify that a license may be loaded without a nonce.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonce) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
license_messages_.set_control(0);
|
||||
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
|
||||
// request. This test is important for the preloaded licenses used by ATSC and
|
||||
// CAS.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequest) {
|
||||
if (license_api_version_ > global_features.api_version) {
|
||||
// We should not attempt to preload a license with an API higher than that
|
||||
// of OEMCrypto.
|
||||
license_api_version_ = global_features.api_version;
|
||||
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 =
|
||||
global_features.api_version;
|
||||
license_messages_.core_request().api_minor_version = 0;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
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(InstallTestDrmKey(&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 placeholder
|
||||
// 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(InstallTestDrmKey(&session2));
|
||||
// However, in order to start the rental clock, we have to sign something. So
|
||||
// we will sign a placeholder 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.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonce) {
|
||||
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());
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
|
||||
}
|
||||
|
||||
// Verify that a second license may not be loaded in a session.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyNoNonceTwiceAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
license_messages_.set_control(0);
|
||||
license_messages_.skip_nonce_check();
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
// A second load, should NOT succeed.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Verify that a second license may not be loaded in a session.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonceTwiceAPI16) {
|
||||
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());
|
||||
// A second load, should NOT succeed.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// This tests load license with an 8k license response.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyLargeBuffer) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||
license_messages_.set_message_size(max_size);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
//---------------------------------------------------------------------------//
|
||||
// Each of the following LoadKeyWithBadRange_* tests is similar. They verify
|
||||
// that OEMCrypto_LoadLicense checks the range of all the pointers. It should
|
||||
// reject a message if the pointer does not point into the message buffer.
|
||||
//---------------------------------------------------------------------------//
|
||||
//---------------------------------------------------------------------------//
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_enc_mac_keys) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().enc_mac_keys.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_enc_mac_keys_iv) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().enc_mac_keys_iv.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_id) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().key_array[0].key_id.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_data) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().key_array[1].key_data.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_data_iv) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().key_array[1].key_data_iv.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_control) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().key_array[2].key_control.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_key_control_iv) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().key_array[2].key_control_iv.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadRange_pst) {
|
||||
license_messages_.set_control(wvoec::kControlNonceOrEntry);
|
||||
license_messages_.set_pst("my_pst");
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// See the comment in LicenseRoundTrip::LoadResponse for why we increment by
|
||||
// the message size.
|
||||
license_messages_.core_response().pst.offset +=
|
||||
sizeof(license_messages_.response_data());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
// If we have a pst, then we need a usage entry.
|
||||
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
//---------------------------------------------------------------------------//
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
// Test that LoadKeys fails when a key is loaded with no key control block.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithNullKeyControl) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
license_messages_.core_response().key_array[2].key_control.offset = 0;
|
||||
license_messages_.core_response().key_array[2].key_control.length = 0;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Verify that LoadKeys fails when a key's nonce is wrong.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadNonce) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
for (unsigned int i = 0; i < license_messages_.num_keys(); i++)
|
||||
license_messages_.response_data().keys[i].control.nonce ^= 42;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Verify that LoadKeys fails when the core message's nonce is wrong.
|
||||
TEST_F(OEMCryptoLicenseTestAPI16, LoadKeyWithBadNonce2) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
license_messages_.core_request().nonce ^= 42;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Verify that LoadKeys fails when the core message's session is wrong.
|
||||
TEST_F(OEMCryptoLicenseTestAPI16, LoadKeyWithBadNonce3) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
license_messages_.core_request().session_id++;
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Verify that LoadKeys fails when an attempt is made to use a nonce twice.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithRepeatNonce) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
const uint32_t nonce = session_.nonce();
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
// This is the first attempt. It should succeed.
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
|
||||
// Now, open a new session and try to load a license with the same nonce.
|
||||
session_.close();
|
||||
ASSERT_NO_FATAL_FAILURE(session_.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session_));
|
||||
license_messages_.skip_nonce_check();
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
// Repeat the nonce.
|
||||
license_messages_.core_request().nonce = nonce;
|
||||
for (unsigned int i = 0; i < license_messages_.num_keys(); i++)
|
||||
license_messages_.response_data().keys[i].control.nonce = htonl(nonce);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// This tests that a nonce cannot be used in new session. This is similar to
|
||||
// the previous test, but does not use the nonce in the first session. The nonce
|
||||
// should be tied to a session, so generating a nonce in the first session and
|
||||
// then using it in the second session should fail.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyNonceReopenSession) {
|
||||
ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce());
|
||||
uint32_t nonce = session_.nonce();
|
||||
// Do not use the nonce now. Close session and use it after re-opening.
|
||||
ASSERT_NO_FATAL_FAILURE(session_.close());
|
||||
|
||||
// Actually, this isn't the same session. OEMCrypto opens a new session, but
|
||||
// we are guarding against the possibility that it re-uses the session data
|
||||
// and might not clear out the nonce correctly.
|
||||
ASSERT_NO_FATAL_FAILURE(session_.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&session_));
|
||||
license_messages_.skip_nonce_check();
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
license_messages_.core_request().nonce = nonce;
|
||||
for (unsigned int i = 0; i < license_messages_.num_keys(); i++)
|
||||
license_messages_.response_data().keys[i].control.nonce = htonl(nonce);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// This tests that a nonce cannot be used in wrong session. This is similar to
|
||||
// the previous test, except we do not close session 1 before we open session 2.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyNonceWrongSession) {
|
||||
// First, open a session and generate a nonce. We don't use the nonce in this
|
||||
// session.
|
||||
Session s2;
|
||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s2));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.GenerateNonce());
|
||||
uint32_t nonce = s2.nonce();
|
||||
|
||||
// Do not use the nonce. Also, leave the session open. We want to make sure
|
||||
// that session_ and s2 do NOT share a nonce. This is different from
|
||||
// the LoadKeyNonceReopenSession in that we do not close s1.
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
license_messages_.core_request().nonce = nonce;
|
||||
for (unsigned int i = 0; i < license_messages_.num_keys(); i++)
|
||||
license_messages_.response_data().keys[i].control.nonce = htonl(nonce);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// LoadKeys should fail if the key control block as a bad verification string.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadVerification) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
license_messages_.response_data().keys[1].control.verification[2] = 'Z';
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// This test verifies that LoadKeys still works when the message is not aligned
|
||||
// in memory on a word (2 or 4 byte) boundary.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyUnalignedMessageAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
|
||||
std::vector<uint8_t> buffer(1, '0'); // A string of 1 byte long.
|
||||
size_t offset = buffer.size();
|
||||
ASSERT_EQ(1u, offset);
|
||||
// We assume that vectors are allocated on as a small chunk of data that is
|
||||
// aligned on a word boundary. I.e. we assume buffer is word aligned. Next,
|
||||
// we append the message to buffer after the single padding byte.
|
||||
buffer.insert(buffer.end(),
|
||||
license_messages_.encrypted_response_buffer().begin(),
|
||||
license_messages_.encrypted_response_buffer().end());
|
||||
// Thus, buffer[offset] is NOT word aligned.
|
||||
const uint8_t* unaligned_message = &buffer[offset];
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadLicense(
|
||||
session_.session_id(), unaligned_message,
|
||||
license_messages_.encrypted_response_buffer().size(),
|
||||
license_messages_.serialized_core_message().size(),
|
||||
license_messages_.response_signature().data(),
|
||||
license_messages_.response_signature().size()));
|
||||
}
|
||||
|
||||
// Verifies that a session can't reload a license without being closed and
|
||||
// reopened.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadLicenseAgainFailureAPI16) {
|
||||
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());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
license_messages_.response_signature()[0] ^= 42;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE,
|
||||
license_messages_.LoadResponse());
|
||||
}
|
||||
// LoadKeys should fail if we try to load keys with no keys.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeys) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
license_messages_.set_control(0);
|
||||
license_messages_.set_num_keys(0);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
// Like the previous test, except we ask for a nonce first.
|
||||
TEST_P(OEMCryptoLicenseTest, LoadKeyNoKeyWithNonce) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
license_messages_.set_num_keys(0);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// @addtogroup security
|
||||
/// @{
|
||||
|
||||
// Following two tests will test huge values for num bytes clear, num bytes
|
||||
// encrypted, input data length and clear address, clear address_length.
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForHugeNumBytesClearAndBuffers) {
|
||||
TestDecryptCENCForHugeBufferLengths(
|
||||
[](size_t message_size, OEMCrypto_SampleDescription* sample_description) {
|
||||
OEMCrypto_SubSampleDescription* sub_samples =
|
||||
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||
sample_description->subsamples);
|
||||
sub_samples[0].num_bytes_clear =
|
||||
sub_samples[0].num_bytes_clear + message_size;
|
||||
},
|
||||
!kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
DecryptCENCForNumBytesClearPlusEncryptedOverflowsSize) {
|
||||
LoadLicense();
|
||||
vector<uint8_t> key_handle;
|
||||
GetKeyHandleIntoVector(session_.session_id(),
|
||||
session_.license().keys[0].key_id,
|
||||
session_.license().keys[0].key_id_length,
|
||||
OEMCrypto_CipherMode_CENC, key_handle);
|
||||
|
||||
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 = ~0;
|
||||
|
||||
// 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(key_handle.data(), key_handle.size(),
|
||||
&sample_description, 1, &pattern));
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForHugeNumBytesEncryptedAndBuffers) {
|
||||
TestDecryptCENCForHugeBufferLengths(
|
||||
[](size_t message_size, OEMCrypto_SampleDescription* sample_description) {
|
||||
OEMCrypto_SubSampleDescription* sub_samples =
|
||||
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||
sample_description->subsamples);
|
||||
sub_samples[0].num_bytes_encrypted =
|
||||
sub_samples[0].num_bytes_encrypted + message_size;
|
||||
},
|
||||
!kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForHugeSecureHandleLength) {
|
||||
TestDecryptCENCForHugeBufferLengths(
|
||||
[](size_t message_size, OEMCrypto_SampleDescription* sample_description) {
|
||||
OEMCrypto_SubSampleDescription* sub_samples =
|
||||
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||
sample_description->subsamples);
|
||||
// TestDecryptCENCForHugeBufferLengths alloctes huge secure handle
|
||||
// buffer.
|
||||
sample_description->buffers.output_descriptor.type =
|
||||
OEMCrypto_BufferType_Secure;
|
||||
sub_samples[0].num_bytes_clear =
|
||||
sub_samples[0].num_bytes_clear + message_size;
|
||||
},
|
||||
!kCheckStatus);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesClear) {
|
||||
TestDecryptCENCForOutOfRangeOffsetsAndLengths(
|
||||
[](OEMCrypto_SampleDescription* sample_description) {
|
||||
OEMCrypto_SubSampleDescription* sub_samples =
|
||||
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||
sample_description->subsamples);
|
||||
sub_samples[0].num_bytes_clear = sub_samples[0].num_bytes_clear + 1;
|
||||
},
|
||||
!kDecryptCENCSecureBuffer);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForOutOfRangeNumBytesEncryptedAPI16) {
|
||||
TestDecryptCENCForOutOfRangeOffsetsAndLengths(
|
||||
[](OEMCrypto_SampleDescription* sample_description) {
|
||||
OEMCrypto_SubSampleDescription* sub_samples =
|
||||
const_cast<OEMCrypto_SubSampleDescription*>(
|
||||
sample_description->subsamples);
|
||||
sub_samples[0].num_bytes_encrypted =
|
||||
sub_samples[0].num_bytes_encrypted + 1;
|
||||
},
|
||||
!kDecryptCENCSecureBuffer);
|
||||
}
|
||||
|
||||
TEST_P(OEMCryptoLicenseTest,
|
||||
OEMCryptoMemoryDecryptCENCForOutOfRangeSecureBufferOffset) {
|
||||
TestDecryptCENCForOutOfRangeOffsetsAndLengths(
|
||||
[](OEMCrypto_SampleDescription* sample_description) {
|
||||
sample_description->buffers.output_descriptor.type =
|
||||
OEMCrypto_BufferType_Secure;
|
||||
sample_description->buffers.output_descriptor.buffer.secure.offset =
|
||||
sample_description->buffers.output_descriptor.buffer.secure
|
||||
.secure_buffer_length +
|
||||
1;
|
||||
},
|
||||
kDecryptCENCSecureBuffer);
|
||||
}
|
||||
|
||||
// After loading keys, we should be able to query the key control block. If we
|
||||
// attempt to query a key that has not been loaded, the error should be
|
||||
// NO_CONTENT_KEY.
|
||||
TEST_P(OEMCryptoLicenseTest, QueryKeyControl) {
|
||||
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());
|
||||
|
||||
// Note: successful cases are tested in VerifyTestKeys.
|
||||
KeyControlBlock block;
|
||||
size_t size = sizeof(block) - 1;
|
||||
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
|
||||
session_.session_id(), license_messages_.response_data().keys[0].key_id,
|
||||
license_messages_.response_data().keys[0].key_id_length,
|
||||
reinterpret_cast<uint8_t*>(&block), &size);
|
||||
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
return;
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||
const char* key_id = "no_key";
|
||||
size = sizeof(block);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY,
|
||||
OEMCrypto_QueryKeyControl(
|
||||
session_.session_id(), reinterpret_cast<const uint8_t*>(key_id),
|
||||
strlen(key_id), reinterpret_cast<uint8_t*>(&block), &size));
|
||||
}
|
||||
|
||||
// This case tests against the issue where certain 16.4.x SDK versions return a
|
||||
// clear key control block (KCB) in the license response. An OEMCrypto v17.1+
|
||||
// implementation should be able to handle the clear KCB in the 16.4.x response
|
||||
// and load the license correctly.
|
||||
TEST_F(OEMCryptoSessionTests, ClearKcbAPI17) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
|
||||
// Set odk version in the license response to be 16.4
|
||||
oemcrypto_core_message::features::CoreMessageFeatures features = {};
|
||||
features.maximum_major_version = 16;
|
||||
features.maximum_minor_version = 4;
|
||||
constexpr bool kForceClearKcb = true;
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
license_messages.EncryptAndSignResponseWithCoreMessageFeatures(
|
||||
features, kForceClearKcb));
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
|
||||
|
||||
KeyControlBlock block;
|
||||
size_t size = sizeof(block);
|
||||
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
|
||||
s.session_id(), license_messages.response_data().keys[0].key_id,
|
||||
license_messages.response_data().keys[0].key_id_length,
|
||||
reinterpret_cast<uint8_t*>(&block), &size);
|
||||
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
return;
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
// 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.
|
||||
TEST_P(OEMCryptoLicenseTest, AntiRollbackHardwareRequired) {
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest());
|
||||
license_messages_.set_control(wvoec::kControlRequireAntiRollbackHardware);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse());
|
||||
OEMCryptoResult sts = license_messages_.LoadResponse();
|
||||
if (OEMCrypto_IsAntiRollbackHwPresent()) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
} else {
|
||||
ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, sts);
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that OEMCrypto can load the number of keys required for
|
||||
// the reported resource level.
|
||||
TEST_P(OEMCryptoLicenseTest, MinimumKeys) {
|
||||
const size_t num_keys = GetResourceValue(kMaxKeysPerSession);
|
||||
ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating.";
|
||||
license_messages_.set_num_keys(static_cast<uint32_t>(num_keys));
|
||||
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());
|
||||
|
||||
constexpr bool kSelectKeyFirst = true;
|
||||
for (size_t key_index = 0; key_index < num_keys; key_index++) {
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
session_.TestDecryptCTR(kSelectKeyFirst, OEMCrypto_SUCCESS, key_index));
|
||||
}
|
||||
}
|
||||
|
||||
// This test verifies that OEMCrypto can load the total number of keys required
|
||||
// for the reported resource level. This maximizes keys per session.
|
||||
TEST_P(OEMCryptoLicenseTest, MaxTotalKeysPerSession) {
|
||||
const size_t max_num_keys = GetResourceValue(kMaxKeysPerSession);
|
||||
TestMaxKeys(this, max_num_keys);
|
||||
}
|
||||
|
||||
// This test verifies that OEMCrypto can load the total number of keys required
|
||||
// for the reported resource level. This maximizes number of sessions.
|
||||
TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) {
|
||||
const size_t max_total_keys = GetResourceValue(kMaxTotalKeys);
|
||||
const size_t max_sessions = GetResourceValue(kMaxConcurrentSession);
|
||||
const size_t max_num_keys = max_total_keys / max_sessions + 1;
|
||||
TestMaxKeys(this, max_num_keys);
|
||||
}
|
||||
|
||||
// This test verifies that the minimum patch level can be required. The device
|
||||
// should accept a key control block with the current patch level, and it should
|
||||
// reject any key control blocks with a future patch level.
|
||||
TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
|
||||
uint8_t patch_level = OEMCrypto_Security_Patch_Level();
|
||||
printf(" Current Patch Level: %u.\n", patch_level);
|
||||
{
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.set_control(patch_level
|
||||
<< wvoec::kControlSecurityPatchLevelShift);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
|
||||
EXPECT_EQ(global_features.api_version, license_messages.api_version());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
|
||||
}
|
||||
// Reject any future patch levels.
|
||||
if (patch_level < 0x3F) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.set_control((patch_level + 1)
|
||||
<< wvoec::kControlSecurityPatchLevelShift);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, license_messages.LoadResponse());
|
||||
}
|
||||
// Accept an old patch level.
|
||||
if (patch_level > 0) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.set_control((patch_level - 1)
|
||||
<< wvoec::kControlSecurityPatchLevelShift);
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
} // namespace wvoec
|
||||
Reference in New Issue
Block a user