Files
ce_cdm/oemcrypto/test/oemcrypto_license_test.cpp
2024-11-27 00:07:23 +00:00

981 lines
44 KiB
C++

// 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 <string>
#include "platform.h"
#include "test_sleep.h"
using ::testing::Range;
namespace wvoec {
/// @addtogroup license
/// @{
// 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(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_NE(OEMCrypto_SUCCESS, 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_NE(OEMCrypto_SUCCESS, 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) {
license_messages_.skip_request_hash();
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];
const std::vector<uint8_t> context = session_.GetDefaultContext();
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadLicense(
session_.session_id(), context.data(), context.size(),
session_.enc_session_key().data(),
session_.enc_session_key().size(), 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_NE(OEMCrypto_SUCCESS, 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) {
if (wvoec::global_features.api_version < 17) {
GTEST_SKIP() << "Test for versions 17 and up only.";
}
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);
RecordWvProperty("security_patch_level", std::to_string(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());
}
}
//
// Load, Refresh Keys Test
//
// Refresh keys should work if the license uses a nonce.
TEST_P(OEMCryptoRefreshTest, RefreshWithNonce) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
}
// Refresh keys should work if the license does not use a nonce.
TEST_P(OEMCryptoRefreshTest, RefreshNoNonce) {
license_messages_.set_control(0);
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
}
// Refresh keys should NOT work if a license has not been loaded.
TEST_P(OEMCryptoRefreshTestAPI16, RefreshNoLicense) {
Session s;
s.open();
constexpr size_t message_size = kMaxCoreMessage + 42;
std::vector<uint8_t> data(message_size);
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
size_t gen_signature_length = 0;
size_t core_message_length = 0;
OEMCryptoResult sts = OEMCrypto_PrepAndSignRenewalRequest(
s.session_id(), data.data(), data.size(), &core_message_length, nullptr,
&gen_signature_length);
ASSERT_LT(core_message_length, message_size);
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
vector<uint8_t> gen_signature(gen_signature_length);
sts = OEMCrypto_PrepAndSignRenewalRequest(
s.session_id(), data.data(), data.size(), &core_message_length,
gen_signature.data(), &gen_signature_length);
}
ASSERT_NE(OEMCrypto_SUCCESS, sts);
}
// Refresh keys should fail if the nonce is not in the session.
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadNonce) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
renewal_messages.core_request().nonce ^= 42;
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
}
// Refresh keys should fail if the session_id does not match the license.
TEST_P(OEMCryptoRefreshTestAPI16, RefreshBadSessionID) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
renewal_messages.core_request().session_id += 1;
LoadRenewal(&renewal_messages, OEMCrypto_ERROR_INVALID_NONCE);
}
// Refresh keys should handle the maximum message size.
TEST_P(OEMCryptoRefreshTest, RefreshLargeBuffer) {
LoadLicense();
RenewalRoundTrip renewal_messages(&license_messages_);
const size_t max_size = GetResourceValue(kLargeMessageSize);
renewal_messages.set_message_size(max_size);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
}
// This situation would occur if an app only uses one key in the license. When
// that happens, GetKeyHandle would be called before the first decrypt, and then
// would not need to be called again, even if the license is refreshed.
TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) {
LoadLicense();
// Call select key before the refresh. No calls below to TestDecryptCTR with
// select key set to true.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true));
// This should still be valid key, even if the refresh failed, because this
// is before the original license duration.
wvutil::TestSleep::Sleep(kShortSleep);
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
// This should be after duration of the original license, but before the
// expiration of the refresh message. This should fail until we have loaded
// the renewal.
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
// After we've loaded the renewal, decrypt should succeed again.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
}
// Test that playback clock is correctly started and that the license can be
// renewed.
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadSuccess) {
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
// First version to support Renew on Load.
constexpr uint32_t kFeatureVersion = 18;
// Loading the license should start the playback clock.
LoadLicense();
// Sleep until just after rental window is over.
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
if (license_api_version_ < kFeatureVersion ||
global_features.api_version < kFeatureVersion) {
// If the feature is not supported, then we expect failure because the
// playback clock was not started and we are outside the rental window.
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(true, OEMCrypto_ERROR_KEY_EXPIRED));
return;
} else {
// If the feature is supported, we expect decrypt to work because we are
// still within the initial renewal window, and the playback clock should
// have started.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS));
}
// This is after the initial renewal duration, so we expect failure before
// loading the renewal.
wvutil::TestSleep::Sleep(kShortSleep + kLongSleep);
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED));
RenewalRoundTrip renewal_messages(&license_messages_);
MakeRenewalRequest(&renewal_messages);
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
// After we've loaded the renewal, decrypt should succeed again.
ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false));
}
TEST_P(OEMCryptoRefreshTest, RenewLicenseLoadOutsideRentalDuration) {
license_messages_.core_response().renewal_delay_base = OEMCrypto_License_Load;
timer_limits_.rental_duration_seconds = kDuration; // 2 seconds.
timer_limits_.initial_renewal_duration_seconds = kLongDuration; // 5 seconds.
// Sleep until just after rental window is over.
wvutil::TestSleep::Sleep(kDuration + kShortSleep);
// Loading the license should start the playback clock.
LoadLicense();
// If the license is loaded after the rental duration window, we expect
// failure.
ASSERT_NO_FATAL_FAILURE(
session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
}
INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest,
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
// These tests only work when the license has a core message.
INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16,
Range<uint32_t>(kCoreMessagesAPI, kCurrentAPI + 1));
/// @}
} // namespace wvoec