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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user