Source release 18.1.0

This commit is contained in:
John "Juce" Bruce
2023-06-23 15:45:08 -07:00
parent 2baa7c6e2b
commit b2c35151ad
2074 changed files with 196004 additions and 427059 deletions

View File

@@ -7,6 +7,7 @@
#include "oec_session_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <openssl/aes.h>
#include <openssl/bio.h>
@@ -44,6 +45,8 @@
using namespace std;
using testing::AnyOf;
// GTest requires PrintTo to be in the same namespace as the thing it prints,
// which is std::vector in this case.
namespace std {
@@ -108,8 +111,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());
@@ -129,7 +132,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
@@ -262,11 +266,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;
}
@@ -382,14 +384,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() {
@@ -441,17 +435,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 =
@@ -521,30 +511,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 =
@@ -561,33 +527,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() {
@@ -596,6 +541,223 @@ 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 Provisioning40CastRoundTrip::PrepareSession() {
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);
wrapped_drm_key_ = wrapped_private_key;
drm_public_key_ = public_key;
drm_key_type_ = key_type;
}
void Provisioning40CastRoundTrip::LoadDRMPrivateKey() {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadDRMPrivateKey(session()->session_id(), drm_key_type_,
wrapped_drm_key_.data(),
wrapped_drm_key_.size()));
}
void Provisioning40CastRoundTrip::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 Provisioning40CastRoundTrip::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));
}
// Creates a prov2 response
void Provisioning40CastRoundTrip::CreateDefaultResponse() {
uint32_t algorithm_n = htonl(allowed_schemes_);
memcpy(response_data_.rsa_key, "SIGN", 4);
memcpy(response_data_.rsa_key + 4, &algorithm_n, 4);
memcpy(response_data_.rsa_key + 8, encoded_rsa_key_.data(),
encoded_rsa_key_.size());
response_data_.rsa_key_length = 8 + encoded_rsa_key_.size();
response_data_.nonce = session_->nonce();
response_data_.enc_message_key_length = 0;
core_response_.key_type = OEMCrypto_RSA_Private_Key;
core_response_.enc_private_key =
FindSubstring(response_data_.rsa_key, response_data_.rsa_key_length);
core_response_.enc_private_key_iv = FindSubstring(
response_data_.rsa_key_iv, sizeof(response_data_.rsa_key_iv));
core_response_.encrypted_message_key = FindSubstring(
response_data_.enc_message_key, response_data_.enc_message_key_length);
}
void Provisioning40CastRoundTrip::EncryptAndSignResponse() {
session()->key_deriver().PadAndEncryptProvisioningMessage(
&response_data_, &encrypted_response_data_);
core_response_.enc_private_key.length =
encrypted_response_data_.rsa_key_length;
SignResponse();
}
void Provisioning40CastRoundTrip::SignResponse() {
CoreMessageFeatures features =
CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION);
// Create prov 2 request struct from prov 4 request
oemcrypto_core_message::ODK_ProvisioningRequest core_request_prov2;
core_request_prov2.api_minor_version = core_request_.api_minor_version;
core_request_prov2.api_major_version = core_request_.api_major_version;
core_request_prov2.nonce = core_request_.nonce;
core_request_prov2.session_id = core_request_.session_id;
memcpy(&core_request_prov2.counter_info, &core_request_.counter_info,
sizeof(core_request_.counter_info));
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreProvisioningResponse(
features, core_response_, core_request_prov2, &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 =
std::max(required_message_size_, serialized_core_message_.size() +
sizeof(encrypted_response_data_));
// Stripe the encrypted message.
encrypted_response_.resize(message_size);
for (size_t i = 0; i < encrypted_response_.size(); i++) {
encrypted_response_[i] = i & 0xFF;
}
ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size());
memcpy(encrypted_response_.data(), serialized_core_message_.data(),
serialized_core_message_.size());
ASSERT_GE(encrypted_response_.size(),
serialized_core_message_.size() + sizeof(encrypted_response_data_));
memcpy(encrypted_response_.data() + serialized_core_message_.size(),
reinterpret_cast<const uint8_t*>(&encrypted_response_data_),
sizeof(encrypted_response_data_));
session()->key_deriver().ServerSignBuffer(encrypted_response_.data(),
encrypted_response_.size(),
&response_signature_);
SetEncryptAndSignResponseLengths();
}
OEMCryptoResult Provisioning40CastRoundTrip::LoadResponse(Session* session) {
EXPECT_NE(session, nullptr);
// Write corpus for oemcrypto_load_provisioning_fuzz. Fuzz script expects
// unencrypted response from provisioning server as input corpus data.
// Data will be encrypted and signed again explicitly by fuzzer script after
// mutations.
if (ShouldGenerateCorpus()) {
const std::string file_name =
GetFileName("oemcrypto_load_provisioning_fuzz_seed_corpus");
// Corpus for license response fuzzer should be in the format:
// unencrypted (core_response + response_data).
AppendToFile(file_name, reinterpret_cast<const char*>(&core_response_),
sizeof(ODK_ParsedProvisioning));
AppendToFile(file_name, reinterpret_cast<const char*>(&response_data_),
sizeof(response_data_));
}
size_t wrapped_key_length = 0;
OEMCryptoResult sts = LoadResponseNoRetry(session, &wrapped_key_length);
if (sts != OEMCrypto_ERROR_SHORT_BUFFER) return sts;
wrapped_rsa_key_.assign(wrapped_key_length, 0);
sts = LoadResponseNoRetry(session, &wrapped_key_length);
if (sts == OEMCrypto_SUCCESS) {
wrapped_rsa_key_.resize(wrapped_key_length);
}
return sts;
}
OEMCryptoResult Provisioning40CastRoundTrip::LoadResponseNoRetry(
Session* session, size_t* wrapped_key_length) {
EXPECT_NE(session, nullptr);
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 LicenseRoundTrip::VerifyRequestSignature(
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
size_t core_message_length) {
@@ -678,16 +840,14 @@ void LicenseRoundTrip::CreateDefaultResponse() {
// Fill in the default core_response_ fields, except the substrings, which are
// filled in the next function.
core_response_.nonce_required =
((wvoec::kControlNonceEnabled | wvoec::kControlNonceOrEntry |
wvoec::kControlNonceRequired) &
control_)
? 1
: 0;
(wvoec::kControlNonceEnabled | wvoec::kControlNonceOrEntry |
wvoec::kControlNonceRequired) &
control_;
core_response_.license_type = license_type_;
FillCoreResponseSubstrings();
}
void LicenseRoundTrip::ConvertDataToValidBools(ODK_ParsedLicense* t) {
void LicenseRoundTrip::ConvertDataToValidBools(ODK_Packing_ParsedLicense* t) {
t->nonce_required = ConvertByteToValidBoolean(&t->nonce_required);
t->timer_limits.soft_enforce_playback_duration = ConvertByteToValidBoolean(
&t->timer_limits.soft_enforce_playback_duration);
@@ -706,19 +866,19 @@ void LicenseRoundTrip::InjectFuzzedTimerLimits(
void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data,
size_t size) {
// Interpreting fuzz data as unencrypted core_response + message_data
// Interpreting fuzz data as unencrypted core_response + response_data +
// key_array
FuzzedData fuzzed_data(data, size);
// Copy core_response from data.
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
// key_array_length number of times during LoadLicense. If key_array_length is
// more than kMaxNumKeys, setting it to max value of kMaxNumKeys as we should
// not go out of bounds of this array length. For corpus, this value is
// already hard coded to 4.
// Copy response_data from data.
fuzzed_data.Fill(&response_data_, sizeof(response_data_));
// If key_array_length is more than kMaxNumKeys, we set it to kMaxNumKeys to
// prevent it from going out of bounds. For corpus, this value is already hard
// coded to 4.
if (core_response_.key_array_length > kMaxNumKeys) {
core_response_.key_array_length = kMaxNumKeys;
}
@@ -726,6 +886,13 @@ void LicenseRoundTrip::InjectFuzzedResponseData(const uint8_t* data,
// 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);
// Copy key_array from data.
key_array_.resize(num_keys_);
core_response_.key_array = key_array_.data();
fuzzed_data.Fill(core_response_.key_array,
num_keys_ * sizeof(*core_response_.key_array));
ConvertDataToValidBools(&core_response_);
// TODO(b/157520981): Once assertion bug is fixed, for loop can be removed.
@@ -746,9 +913,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.
fuzzed_data.Fill(&response_data_, sizeof(response_data_));
// Set nonce to match one in request to pass nonce validations.
for (uint32_t i = 0; i < num_keys_; ++i) {
response_data_.keys[i].control.nonce = htonl(session()->nonce());
}
@@ -795,27 +960,30 @@ void LicenseRoundTrip::FillCoreResponseSubstrings() {
sizeof(response_data_.srm_restriction_data));
}
core_response_.key_array_length = num_keys_;
key_array_.clear();
for (unsigned int i = 0; i < num_keys_; i++) {
core_response_.key_array[i].key_id = FindSubstring(
response_data_.keys[i].key_id, response_data_.keys[i].key_id_length);
core_response_.key_array[i].key_data_iv = FindSubstring(
response_data_.keys[i].key_iv, sizeof(response_data_.keys[i].key_iv));
core_response_.key_array[i].key_data =
FindSubstring(response_data_.keys[i].key_data,
response_data_.keys[i].key_data_length);
OEMCrypto_KeyObject obj;
obj.key_id = FindSubstring(response_data_.keys[i].key_id,
response_data_.keys[i].key_id_length);
obj.key_data_iv = FindSubstring(response_data_.keys[i].key_iv,
sizeof(response_data_.keys[i].key_iv));
obj.key_data = FindSubstring(response_data_.keys[i].key_data,
response_data_.keys[i].key_data_length);
if (core_request().api_major_version < kClearControlBlockAPIMajor ||
(core_request().api_major_version == kClearControlBlockAPIMajor &&
core_request().api_minor_version < kClearControlBlockAPIMinor)) {
core_response_.key_array[i].key_control_iv =
obj.key_control_iv =
FindSubstring(response_data_.keys[i].control_iv,
sizeof(response_data_.keys[i].control_iv));
} else {
core_response_.key_array[i].key_control_iv = FindSubstring(nullptr, 0);
obj.key_control_iv = FindSubstring(nullptr, 0);
}
core_response_.key_array[i].key_control =
FindSubstring(&response_data_.keys[i].control,
sizeof(response_data_.keys[i].control));
obj.key_control = FindSubstring(&response_data_.keys[i].control,
sizeof(response_data_.keys[i].control));
key_array_.push_back(obj);
}
core_response_.key_array = key_array_.data();
core_response_.key_array_length = static_cast<uint32_t>(key_array_.size());
}
void LicenseRoundTrip::EncryptResponse(bool force_clear_kcb) {
@@ -864,26 +1032,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() {
@@ -944,11 +1108,14 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session,
const std::string file_name =
GetFileName("oemcrypto_load_license_fuzz_seed_corpus");
// Corpus for license response fuzzer should be in the format:
// core_response + response_data.
// core_response + response_data + key_array.
AppendToFile(file_name, reinterpret_cast<const char*>(&core_response_),
sizeof(ODK_ParsedLicense));
sizeof(core_response_));
AppendToFile(file_name, reinterpret_cast<const char*>(&response_data_),
sizeof(response_data_));
AppendToFile(
file_name, reinterpret_cast<const char*>(core_response_.key_array),
core_response_.key_array_length * sizeof(*core_response_.key_array));
}
// Some tests adjust the offset to be beyond the length of the message. Here,
@@ -966,22 +1133,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
@@ -1006,7 +1161,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++) {
@@ -1291,15 +1446,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;
}
@@ -1310,22 +1466,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_));
@@ -1342,17 +1490,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;
@@ -1374,29 +1514,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 =
@@ -1468,17 +1598,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>,
@@ -1589,29 +1712,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 {
@@ -1623,11 +1744,10 @@ void Session::TestDecryptEntitled(OEMCryptoResult expected_result,
OEMCrypto_SESSION session_id,
const uint8_t* content_key_id,
size_t content_key_id_length) {
OEMCryptoResult select_result = OEMCrypto_SUCCESS;
// Select the key (from FillSimpleMessage)
select_result =
OEMCrypto_SelectKey(session_id, content_key_id, content_key_id_length,
OEMCrypto_CipherMode_CENC);
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;
@@ -1644,55 +1764,61 @@ void Session::TestDecryptEntitled(OEMCryptoResult expected_result,
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(session_id, &sample_description, 1, &pattern);
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, select_result, decrypt_result))
TestDecryptResult(expected_result, getkeyhandle_result, decrypt_result))
<< "Either SelectKey or DecryptCENC should return " << expected_result
<< ", but they returned " << select_result << " and " << decrypt_result
<< ", respectively.";
<< ", 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);
@@ -1852,8 +1978,15 @@ void Session::VerifyRsaSignature(const vector<uint8_t>& message,
const util::RsaSignatureAlgorithm algorithm =
padding_scheme == kSign_RSASSA_PSS ? util::kRsaPssDefault
: util::kRsaPkcs1Cast;
const OEMCryptoResult result = public_rsa_->VerifySignature(
message.data(), message.size(), signature, signature_length, algorithm);
OEMCrypto_SignatureHashAlgorithm hash_algorithm = OEMCrypto_SHA1;
if (algorithm == util::kRsaPssDefault) {
ASSERT_THAT(
OEMCrypto_GetSignatureHashAlgorithm(session_id(), &hash_algorithm),
AnyOf(OEMCrypto_SUCCESS, OEMCrypto_ERROR_NOT_IMPLEMENTED));
}
const OEMCryptoResult result =
public_rsa_->VerifySignature(message.data(), message.size(), signature,
signature_length, algorithm, hash_algorithm);
ASSERT_EQ(result, OEMCrypto_SUCCESS) << "RSA signature check failed";
}
@@ -1886,10 +2019,7 @@ bool Session::GenerateRsaSessionKey(vector<uint8_t>* session_key,
}
*session_key = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
*enc_session_key = public_rsa_->EncryptSessionKey(*session_key);
if (enc_session_key->empty()) {
return false;
}
return true;
return !enc_session_key->empty();
}
bool Session::GenerateEccSessionKey(vector<uint8_t>* session_key,
@@ -2114,4 +2244,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