Source release 18.1.0
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user