Pick widevine oemcrypto-v18 change

No-Typo-Check: From a third party header file
Bug: 260918793
Test: unit tests
Test: atp v2/widevine-eng/drm_compliance
Change-Id: I36effd6a10a99bdb2399ab1f4a0fad026d607c70
This commit is contained in:
Kyle Zhang
2022-12-16 03:21:08 +00:00
parent 4586522c07
commit 11255b7426
105 changed files with 324641 additions and 299787 deletions

View File

@@ -58,6 +58,27 @@ using oemcrypto_core_message::features::CoreMessageFeatures;
constexpr size_t kTestSubsampleSectionSize = 256;
// Fill objects by consuming a source buffer of fuzzed data.
class FuzzedData {
public:
FuzzedData(const uint8_t* source, size_t source_size)
: source_(source), source_size_(source_size) {}
// Fill the destination buffer with fuzzed data.
void Fill(void* destination, size_t destination_size) {
if (source_ && destination) {
const size_t fill_size = std::min(source_size_, destination_size);
memcpy(destination, source_, fill_size);
source_ += fill_size;
source_size_ -= fill_size;
}
}
private:
const uint8_t* source_;
size_t source_size_;
};
// Encrypt a block of data using CTR mode.
void EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key,
const uint8_t* starting_iv, vector<uint8_t>* out_buffer) {
@@ -87,8 +108,8 @@ void EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key,
// the plaintext of that key so that it can encrypt the test data. It resizes
// the provided vectors and fills them with the expected and actual decrypt
// results. Returns the result of OEMCrypto_DecryptCENC().
OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key,
vector<uint8_t>* expected_data,
OEMCryptoResult DecryptCTR(const vector<uint8_t>& key_handle,
const uint8_t* key, vector<uint8_t>* expected_data,
vector<uint8_t>* actual_data) {
vector<uint8_t> encrypted_data(kTestSubsampleSectionSize);
expected_data->resize(encrypted_data.size());
@@ -108,7 +129,8 @@ OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key,
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
// Decrypt the data
return OEMCrypto_DecryptCENC(session_id, &sample_description, 1, &pattern);
return OEMCrypto_DecryptCENC(key_handle.data(), key_handle.size(),
&sample_description, 1, &pattern);
}
} // namespace
@@ -241,11 +263,9 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
gen_signature.resize(gen_signature_length);
}
if (!verify_request || result != OEMCrypto_SUCCESS) return result;
if (global_features.api_version >= kCoreMessagesAPI) {
std::string core_message(reinterpret_cast<char*>(data.data()),
core_message_length);
FillAndVerifyCoreRequest(core_message);
}
std::string core_message(reinterpret_cast<char*>(data.data()),
core_message_length);
FillAndVerifyCoreRequest(core_message);
VerifyRequestSignature(data, gen_signature, core_message_length);
return result;
}
@@ -361,14 +381,6 @@ void ProvisioningRoundTrip::FillAndVerifyCoreRequest(
EXPECT_EQ(global_features.api_version, core_request_.api_major_version);
EXPECT_EQ(session()->nonce(), core_request_.nonce);
EXPECT_EQ(session()->session_id(), core_request_.session_id);
size_t device_id_length = core_request_.device_id.size();
std::vector<uint8_t> device_id(device_id_length);
EXPECT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetDeviceID(device_id.data(), &device_id_length));
EXPECT_EQ(core_request_.device_id.size(), device_id_length);
std::string device_id_string(reinterpret_cast<char*>(device_id.data()),
device_id_length);
EXPECT_EQ(device_id_string, core_request_.device_id);
}
void ProvisioningRoundTrip::CreateDefaultResponse() {
@@ -420,17 +432,13 @@ void ProvisioningRoundTrip::
}
void ProvisioningRoundTrip::SignResponse() {
if (global_features.api_version >= kCoreMessagesAPI) {
CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
ASSERT_TRUE(
oemcrypto_core_message::serialize::CreateCoreProvisioningResponse(
features, core_response_, core_request_,
&serialized_core_message_));
// Resizing for huge core message length unit tests.
serialized_core_message_.resize(
std::max(required_core_message_size_, serialized_core_message_.size()));
}
CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreProvisioningResponse(
features, core_response_, core_request_, &serialized_core_message_));
// Resizing for huge core message length unit tests.
serialized_core_message_.resize(
std::max(required_core_message_size_, serialized_core_message_.size()));
// Make the message buffer a just big enough, or the
// required size, whichever is larger.
const size_t message_size =
@@ -459,14 +467,16 @@ void ProvisioningRoundTrip::SignResponse() {
}
void ProvisioningRoundTrip::InjectFuzzedResponseData(const uint8_t* data,
size_t size UNUSED) {
size_t size) {
// Interpreting fuzz data as unencrypted core_response + message_data
const size_t core_response_size = sizeof(ODK_ParsedProvisioning);
FuzzedData fuzzed_data(data, size);
// Copy core_response from data and serialize.
memcpy(&core_response_, data, core_response_size);
fuzzed_data.Fill(&core_response_, sizeof(core_response_));
// Copy provisioning message data into response_data.
memcpy(&response_data_, data + core_response_size, sizeof(response_data_));
fuzzed_data.Fill(&response_data_, sizeof(response_data_));
// Set nonce to one from session to pass nonce checks.
response_data_.nonce = session()->nonce();
}
@@ -498,30 +508,6 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponse(Session* session) {
return sts;
}
#ifdef TEST_OEMCRYPTO_V15
// If this platform supports v15 functions, then will test with them:
# define OEMCrypto_RewrapDeviceRSAKey_V15 OEMCrypto_RewrapDeviceRSAKey
# define OEMCrypto_RewrapDeviceRSAKey30_V15 OEMCrypto_RewrapDeviceRSAKey30
#else
// If this platform does not support v15 functions, we just need to stub these
// out so that the tests compile.
OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30_V15(
OEMCrypto_SESSION, const uint32_t*, const uint8_t*, size_t, const uint8_t*,
size_t, const uint8_t*, uint8_t*, size_t*) {
LOGE("Support for v15 functions not included. Define TEST_OEMCRYPTO_V15.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey_V15(
OEMCrypto_SESSION, const uint8_t*, size_t, const uint8_t*, size_t,
const uint32_t*, const uint8_t*, size_t, const uint8_t*, uint8_t*,
size_t*) {
LOGE("Support for v15 functions not included. Define TEST_OEMCRYPTO_V15.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
#endif
template <typename T>
const T* ProvisioningRoundTrip::RemapPointer(const T* response_pointer) const {
const uint8_t* original_pointer =
@@ -538,33 +524,12 @@ const T* ProvisioningRoundTrip::RemapPointer(const T* response_pointer) const {
OEMCryptoResult ProvisioningRoundTrip::LoadResponseNoRetry(
Session* session, size_t* wrapped_key_length) {
EXPECT_NE(session, nullptr);
if (global_features.api_version >= kCoreMessagesAPI) {
VerifyEncryptAndSignResponseLengths();
return OEMCrypto_LoadProvisioning(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size(),
wrapped_rsa_key_.data(), wrapped_key_length);
} else if (global_features.provisioning_method == OEMCrypto_Keybox) {
VerifyEncryptAndSignResponseLengths();
return OEMCrypto_RewrapDeviceRSAKey_V15(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), response_signature_.data(),
response_signature_.size(), RemapPointer(&response_data_.nonce),
RemapPointer(response_data_.rsa_key),
encrypted_response_data_.rsa_key_length,
RemapPointer(response_data_.rsa_key_iv), wrapped_rsa_key_.data(),
wrapped_key_length);
} else {
return OEMCrypto_RewrapDeviceRSAKey30_V15(
session->session_id(), &encrypted_response_data_.nonce,
RemapPointer(response_data_.enc_message_key),
response_data_.enc_message_key_length,
RemapPointer(response_data_.rsa_key),
encrypted_response_data_.rsa_key_length,
RemapPointer(response_data_.rsa_key_iv), wrapped_rsa_key_.data(),
wrapped_key_length);
}
VerifyEncryptAndSignResponseLengths();
return OEMCrypto_LoadProvisioning(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size(),
wrapped_rsa_key_.data(), wrapped_key_length);
}
void ProvisioningRoundTrip::VerifyLoadFailed() {
@@ -573,6 +538,68 @@ void ProvisioningRoundTrip::VerifyLoadFailed() {
ASSERT_EQ(zero, wrapped_rsa_key_);
}
void Provisioning40RoundTrip::PrepareSession(bool is_oem_key) {
const size_t buffer_size = 5000; // Make sure it is large enough.
std::vector<uint8_t> public_key(buffer_size);
size_t public_key_size = buffer_size;
std::vector<uint8_t> public_key_signature(buffer_size);
size_t public_key_signature_size = buffer_size;
std::vector<uint8_t> wrapped_private_key(buffer_size);
size_t wrapped_private_key_size = buffer_size;
OEMCrypto_PrivateKeyType key_type;
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_GenerateCertificateKeyPair(
session()->session_id(), public_key.data(), &public_key_size,
public_key_signature.data(), &public_key_signature_size,
wrapped_private_key.data(), &wrapped_private_key_size, &key_type));
wrapped_private_key.resize(wrapped_private_key_size);
public_key.resize(public_key_size);
if (is_oem_key) {
wrapped_oem_key_ = wrapped_private_key;
oem_public_key_ = public_key;
oem_key_type_ = key_type;
} else {
wrapped_drm_key_ = wrapped_private_key;
drm_public_key_ = public_key;
drm_key_type_ = key_type;
}
}
void Provisioning40RoundTrip::FillAndVerifyCoreRequest(
const std::string& core_message_string) {
EXPECT_TRUE(
oemcrypto_core_message::deserialize::CoreProvisioning40RequestFromMessage(
core_message_string, &core_request_));
EXPECT_EQ(global_features.api_version, core_request_.api_major_version);
EXPECT_EQ(session()->nonce(), core_request_.nonce);
EXPECT_EQ(session()->session_id(), core_request_.session_id);
}
void Provisioning40RoundTrip::VerifyRequestSignature(
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
size_t /* core_message_length */) {
ASSERT_NO_FATAL_FAILURE(
session()->VerifySignature(data, generated_signature.data(),
generated_signature.size(), kSign_RSASSA_PSS));
}
OEMCryptoResult Provisioning40RoundTrip::LoadOEMCertResponse() {
EXPECT_GE(wrapped_oem_key_.size(), 0UL);
return OEMCrypto_InstallOemPrivateKey(
session()->session_id(), oem_key_type_,
reinterpret_cast<const uint8_t*>(wrapped_oem_key_.data()),
wrapped_oem_key_.size());
}
OEMCryptoResult Provisioning40RoundTrip::LoadDRMCertResponse() {
EXPECT_GE(wrapped_drm_key_.size(), 0UL);
return OEMCrypto_LoadDRMPrivateKey(session()->session_id(), drm_key_type_,
wrapped_drm_key_.data(),
wrapped_drm_key_.size());
}
void LicenseRoundTrip::VerifyRequestSignature(
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
size_t core_message_length) {
@@ -682,11 +709,13 @@ void LicenseRoundTrip::InjectFuzzedTimerLimits(
}
void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data,
size_t size UNUSED) {
size_t size) {
// Interpreting fuzz data as unencrypted core_response + message_data
const size_t core_response_size = sizeof(ODK_ParsedLicense);
FuzzedData fuzzed_data(data, size);
// Copy core_response from data.
memcpy(&core_response_, data, core_response_size);
fuzzed_data.Fill(&core_response_, sizeof(core_response_));
// Maximum number of keys could be kMaxNumKeys(30). key_array_length can be
// any random value as it is read from fuzz data.
// Key data array(MessageKeyData keys[kMaxNumKeys]) will be looped over
@@ -697,10 +726,12 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data,
if (core_response_.key_array_length > kMaxNumKeys) {
core_response_.key_array_length = kMaxNumKeys;
}
// For corpus data, this value gets set to 4, but we need to test other
// scenarios too, hence reading key_array_length value.
set_num_keys(core_response_.key_array_length);
ConvertDataToValidBools(&core_response_);
// TODO(b/157520981): Once assertion bug is fixed, for loop can be removed.
// Workaround for the above bug: key_data.length and key_id.length are being
// used in AES decryption process and are expected to be a multiple of 16. An
@@ -721,7 +752,7 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data,
// Copy response_data from data and set nonce to match one in request to pass
// nonce validations.
memcpy(&response_data_, data + core_response_size, sizeof(response_data_));
fuzzed_data.Fill(&response_data_, sizeof(response_data_));
for (uint32_t i = 0; i < num_keys_; ++i) {
response_data_.keys[i].control.nonce = session()->nonce();
}
@@ -837,26 +868,22 @@ void LicenseRoundTrip::EncryptResponse(bool force_clear_kcb) {
void LicenseRoundTrip::CreateCoreLicenseResponseWithFeatures(
const CoreMessageFeatures& features) {
if (api_version_ < kCoreMessagesAPI) {
serialized_core_message_.resize(0);
} else {
if (core_request_.api_major_version == 0) {
// If we don't have a valid request, then we should at least set the
// version number of the request so that CreateCoreLicenseResponse can
// compute the version number of the response.
core_request_.api_major_version = ODK_MAJOR_VERSION;
core_request_.api_minor_version = ODK_MINOR_VERSION;
}
std::string request_hash_string(
reinterpret_cast<const char*>(request_hash_), sizeof(request_hash_));
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse(
features, core_response_, core_request_, request_hash_string,
&serialized_core_message_));
// Resize serialize core message to be just big enough or required core
// message size, whichever is larger.
serialized_core_message_.resize(
std::max(required_core_message_size_, serialized_core_message_.size()));
if (core_request_.api_major_version == 0) {
// If we don't have a valid request, then we should at least set the
// version number of the request so that CreateCoreLicenseResponse can
// compute the version number of the response.
core_request_.api_major_version = ODK_MAJOR_VERSION;
core_request_.api_minor_version = ODK_MINOR_VERSION;
}
std::string request_hash_string(reinterpret_cast<const char*>(request_hash_),
sizeof(request_hash_));
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse(
features, core_response_, core_request_, request_hash_string,
&serialized_core_message_));
// Resize serialize core message to be just big enough or required core
// message size, whichever is larger.
serialized_core_message_.resize(
std::max(required_core_message_size_, serialized_core_message_.size()));
}
void LicenseRoundTrip::SignEncryptedResponse() {
@@ -939,22 +966,10 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session,
reinterpret_cast<const uint8_t*>(&encrypted_response_data_),
reinterpret_cast<const uint8_t*>(&encrypted_response_data_) +
sizeof(encrypted_response_data_));
OEMCryptoResult result;
if (api_version_ < kCoreMessagesAPI) {
result = OEMCrypto_LoadKeys(
session->session_id(), double_message.data(),
encrypted_response_.size(), response_signature_.data(),
response_signature_.size(), core_response_.enc_mac_keys_iv,
core_response_.enc_mac_keys, core_response_.key_array_length,
core_response_.key_array, core_response_.pst,
core_response_.srm_restriction_data,
static_cast<OEMCrypto_LicenseType>(core_response_.license_type));
} else {
result = OEMCrypto_LoadLicense(
session->session_id(), double_message.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size());
}
OEMCryptoResult result = OEMCrypto_LoadLicense(
session->session_id(), double_message.data(), encrypted_response_.size(),
serialized_core_message_.size(), response_signature_.data(),
response_signature_.size());
if (verify_keys && result == OEMCrypto_SUCCESS) {
// Give the session object a copy of the license truth data so that it can
// call SelectKey, use key control information, and so that it has key data
@@ -979,7 +994,7 @@ OEMCryptoResult LicenseRoundTrip::ReloadResponse(Session* session) {
// This function verifies that the key control block reported by OEMCrypto agree
// with the truth key control block. Failures in this function probably
// indicate the OEMCrypto_LoadLicense/LoadKeys did not correctly process the key
// indicate the OEMCrypto_LoadLicense did not correctly process the key
// control block.
void LicenseRoundTrip::VerifyTestKeys(Session* session) {
for (unsigned int i = 0; i < num_keys_; i++) {
@@ -1264,15 +1279,16 @@ void EntitledMessage::VerifyDecrypt() {
for (unsigned int i = 0; i < num_keys_; i++) {
const EntitledContentKeyData* const key_data = &entitled_key_data_[i];
OEMCryptoResult result = OEMCrypto_SelectKey(
vector<uint8_t> key_handle;
OEMCryptoResult result = GetKeyHandleIntoVector(
entitled_key_session_, key_data->content_key_id,
key_data->content_key_id_length, OEMCrypto_CipherMode_CENC);
key_data->content_key_id_length, OEMCrypto_CipherMode_CENC, key_handle);
ASSERT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i;
vector<uint8_t> expected_data;
vector<uint8_t> actual_data;
result = DecryptCTR(entitled_key_session_, key_data->content_key_data,
&expected_data, &actual_data);
result = DecryptCTR(key_handle, key_data->content_key_data, &expected_data,
&actual_data);
EXPECT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i;
EXPECT_EQ(actual_data, expected_data) << "For key " << i;
}
@@ -1283,22 +1299,14 @@ void RenewalRoundTrip::VerifyRequestSignature(
size_t core_message_length) {
ASSERT_EQ(HMAC_SHA256_SIGNATURE_SIZE, generated_signature.size());
std::vector<uint8_t> expected_signature;
if (license_messages_->api_version() < kCoreMessagesAPI) {
// For v15 or earlier, we only sign the message body. Ignore the core
// message.
std::vector<uint8_t> subdata(data.begin() + core_message_length,
data.end());
session()->key_deriver().ClientSignBuffer(subdata, &expected_signature);
} else {
session()->key_deriver().ClientSignBuffer(data, &expected_signature);
}
session()->key_deriver().ClientSignBuffer(data, &expected_signature);
ASSERT_EQ(expected_signature, generated_signature);
}
void RenewalRoundTrip::FillAndVerifyCoreRequest(
const std::string& core_message_string) {
if (license_messages_->api_version() < kCoreMessagesAPI || is_release_) {
// For v15 or for a release, we expect that no core request was created.
if (is_release_) {
// For a release we expect that no core request was created.
EXPECT_FALSE(
oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage(
core_message_string, &core_request_));
@@ -1315,17 +1323,9 @@ void RenewalRoundTrip::FillAndVerifyCoreRequest(
}
void RenewalRoundTrip::CreateDefaultResponse() {
if (license_messages_->api_version() < kCoreMessagesAPI || is_release_) {
if (is_release_) {
uint32_t control = 0;
uint32_t nonce = 0;
// If this is a v15 device, and a v15 license, and the license used a nonce,
// then the response should require a new nonce, too.
if (global_features.api_version < kCoreMessagesAPI &&
(license_messages_->control() & wvoec::kControlNonceEnabled)) {
control = wvoec::kControlNonceEnabled;
session_->GenerateNonce();
nonce = session_->nonce();
}
// A single key object with no key id should update all keys.
constexpr size_t index = 0;
response_data_.keys[index].key_id_length = 0;
@@ -1347,29 +1347,19 @@ void RenewalRoundTrip::CreateDefaultResponse() {
void RenewalRoundTrip::EncryptAndSignResponse() {
// Renewal messages are not encrypted.
encrypted_response_data_ = response_data_;
// Either create a KeyRefreshObject for a call to RefreshKeys or a core
// response for a call to LoadRenewal.
if (license_messages_->api_version() < kCoreMessagesAPI) {
refresh_object_.key_id = FindSubstring(nullptr, 0);
refresh_object_.key_control_iv = FindSubstring(nullptr, 0);
refresh_object_.key_control =
FindSubstring(&response_data_.keys[0].control,
sizeof(response_data_.keys[0].control));
serialized_core_message_.resize(0);
} else {
// TODO(b/191724203): Test renewal server has different version from license
// server.
ASSERT_NE(license_messages_, nullptr);
CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(license_messages_->api_version());
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse(
features, core_request_, renewal_duration_seconds_,
&serialized_core_message_));
// Resize serialize core message to be just big enough or required core
// message size, whichever is larger.
serialized_core_message_.resize(
std::max(required_core_message_size_, serialized_core_message_.size()));
}
// Create a core response for a call to LoadRenewal.
// TODO(b/191724203): Test renewal server has different version from license
// server.
ASSERT_NE(license_messages_, nullptr);
CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(license_messages_->api_version());
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse(
features, core_request_, renewal_duration_seconds_,
&serialized_core_message_));
// Resize serialize core message to be just big enough or required core
// message size, whichever is larger.
serialized_core_message_.resize(
std::max(required_core_message_size_, serialized_core_message_.size()));
// Make the message buffer a just big enough, or the
// required size, whichever is larger.
const size_t message_size =
@@ -1441,17 +1431,10 @@ OEMCryptoResult RenewalRoundTrip::LoadResponse(Session* session) {
sizeof(encrypted_response_data_));
}
VerifyEncryptAndSignResponseLengths();
if (license_messages_->api_version() < kCoreMessagesAPI) {
return OEMCrypto_RefreshKeys(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), response_signature_.data(),
response_signature_.size(), 1, &refresh_object_);
} else {
return OEMCrypto_LoadRenewal(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size());
}
return OEMCrypto_LoadRenewal(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size());
}
std::unordered_map<util::EccCurve, std::unique_ptr<util::EccPrivateKey>,
@@ -1562,29 +1545,27 @@ void Session::GenerateDerivedKeysFromSessionKey() {
enc_context);
}
void Session::TestDecryptCTR(bool select_key_first,
void Session::TestDecryptCTR(bool get_fresh_key_handle_first,
OEMCryptoResult expected_result,
size_t key_index) {
OEMCryptoResult select_result = OEMCrypto_SUCCESS;
if (select_key_first) {
OEMCryptoResult getkeyhandle_result = OEMCrypto_SUCCESS;
if (get_fresh_key_handle_first) {
// Select the key (from FillSimpleMessage)
select_result = OEMCrypto_SelectKey(
session_id(), license_.keys[key_index].key_id,
license_.keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC);
getkeyhandle_result = GetKeyHandle(key_handle_, key_index);
}
vector<uint8_t> unencrypted_data;
vector<uint8_t> output_buffer;
const OEMCryptoResult decrypt_result =
DecryptCTR(session_id(), license_.keys[key_index].key_data,
DecryptCTR(key_handle_, license_.keys[key_index].key_data,
&unencrypted_data, &output_buffer);
// We only have a few errors that we test are reported.
ASSERT_NO_FATAL_FAILURE(
TestDecryptResult(expected_result, select_result, decrypt_result))
<< "Either SelectKey or DecryptCENC should return " << expected_result
<< ", but they returned " << select_result << " and " << decrypt_result
<< ", respectively.";
TestDecryptResult(expected_result, getkeyhandle_result, decrypt_result))
<< "Either GetKeyHandle or DecryptCENC should return " << expected_result
<< ", but they returned " << getkeyhandle_result << " and "
<< decrypt_result << ", respectively.";
if (expected_result == OEMCrypto_SUCCESS) { // No error.
ASSERT_EQ(unencrypted_data, output_buffer);
} else {
@@ -1592,44 +1573,85 @@ void Session::TestDecryptCTR(bool select_key_first,
}
}
void Session::TestDecryptEntitled(OEMCryptoResult expected_result,
OEMCrypto_SESSION session_id,
const uint8_t* content_key_id,
size_t content_key_id_length) {
// Select the key (from FillSimpleMessage)
const OEMCryptoResult getkeyhandle_result =
GetKeyHandleIntoVector(session_id, content_key_id, content_key_id_length,
OEMCrypto_CipherMode_CENC, key_handle_);
vector<uint8_t> unencrypted_data;
vector<uint8_t> output_buffer;
vector<uint8_t> encrypted_data(kTestSubsampleSectionSize);
vector<uint8_t> in_buffer(256);
vector<uint8_t> out_buffer(in_buffer.size());
OEMCrypto_SampleDescription sample_description;
OEMCrypto_SubSampleDescription subsample_description;
ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription(
in_buffer, out_buffer, &sample_description, &subsample_description));
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
EncryptCTR(unencrypted_data, content_key_id, &sample_description.iv[0],
&encrypted_data);
// Try to decrypt the data with oemcrypto session id.
const OEMCryptoResult decrypt_result = OEMCrypto_DecryptCENC(
key_handle_.data(), key_handle_.size(), &sample_description, 1, &pattern);
// We only have a few errors that we test are reported.
ASSERT_NO_FATAL_FAILURE(
TestDecryptResult(expected_result, getkeyhandle_result, decrypt_result))
<< "Either SelectKey or DecryptCENC should return " << expected_result
<< ", but they returned " << getkeyhandle_result << " and "
<< decrypt_result << ", respectively.";
}
OEMCryptoResult Session::GetKeyHandle(vector<uint8_t>& key_handle,
size_t key_index,
OEMCryptoCipherMode cipher_mode) {
return GetKeyHandleIntoVector(session_id(), license_.keys[key_index].key_id,
license_.keys[key_index].key_id_length,
cipher_mode, key_handle);
}
void Session::TestDecryptResult(OEMCryptoResult expected_result,
OEMCryptoResult actual_select_result,
OEMCryptoResult actual_getkeyhandle_result,
OEMCryptoResult actual_decrypt_result) {
// In most cases, we expect the result to come from either the select key or
// from the decrypt call.
if (expected_result == OEMCrypto_SUCCESS) { // No error.
ASSERT_EQ(OEMCrypto_SUCCESS, actual_select_result);
ASSERT_EQ(OEMCrypto_SUCCESS, actual_getkeyhandle_result);
ASSERT_EQ(OEMCrypto_SUCCESS, actual_decrypt_result);
} else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED ||
expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP ||
expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) {
// Key expired or output problems may be reported from select key or
// decrypt, but must be reported.
ASSERT_TRUE(actual_select_result == expected_result ||
ASSERT_TRUE(actual_getkeyhandle_result == expected_result ||
actual_decrypt_result == expected_result);
} else if (expected_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION &&
global_features.api_version >= kCoreMessagesAPI) {
} else if (expected_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION) {
// OEMCrypto is allowed to report either this warning or
// OEMCrypto_ERROR_INSUFFICIENT_HDCP depending on if it can disable
// restricted displays.
ASSERT_TRUE(
actual_select_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION ||
actual_select_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP ||
actual_getkeyhandle_result ==
OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION ||
actual_getkeyhandle_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP ||
actual_decrypt_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION ||
actual_decrypt_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP);
} else {
// OEM's can fine tune other error codes for debugging.
ASSERT_TRUE(actual_select_result != OEMCrypto_SUCCESS ||
ASSERT_TRUE(actual_getkeyhandle_result != OEMCrypto_SUCCESS ||
actual_decrypt_result != OEMCrypto_SUCCESS);
}
}
void Session::TestSelectExpired(size_t key_index) {
void Session::TestGetKeyHandleExpired(size_t key_index) {
if (global_features.api_version >= 13) {
OEMCryptoResult status = OEMCrypto_SelectKey(
session_id(), license().keys[key_index].key_id,
license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC);
// It is OK for SelectKey to succeed with an expired key, but if there is
OEMCryptoResult status = GetKeyHandle(key_handle_, key_index);
// It is OK for GetKeyHandle to succeed with an expired key, but if there is
// an error, it must be OEMCrypto_ERROR_KEY_EXIRED.
if (status != OEMCrypto_SUCCESS) {
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
@@ -2051,4 +2073,25 @@ void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length,
AppendToFile(file_name, reinterpret_cast<const char*>(data.data()),
data.size());
}
OEMCryptoResult GetKeyHandleIntoVector(OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length,
OEMCryptoCipherMode cipher_mode,
vector<uint8_t>& key_handle) {
size_t key_handle_length = 0;
const OEMCryptoResult result = OEMCrypto_GetKeyHandle(
session, key_id, key_id_length, cipher_mode, nullptr, &key_handle_length);
if (result == OEMCrypto_SUCCESS) {
LOGE(
"OEMCrypto_GetKeyHandle returned SUCCESS despite getting no key handle "
"buffer");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} else if (result != OEMCrypto_ERROR_SHORT_BUFFER) {
return result;
}
key_handle.resize(key_handle_length);
return OEMCrypto_GetKeyHandle(session, key_id, key_id_length, cipher_mode,
key_handle.data(), &key_handle_length);
}
} // namespace wvoec