Merge OEMCrypto KDF and usage functions
Since KDF functions are only used right before specific functions, this merges them to simplify internal state within OEMCrypto. Fixes: 299527712 Change-Id: I426cfcdc102bd73cf65cd809b213da2474f44b34
This commit is contained in:
committed by
Robert Shih
parent
b04fda2908
commit
488a4647db
@@ -37,6 +37,23 @@ using namespace std;
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<uint8_t> CreateContext(const char* prefix,
|
||||
const std::vector<uint8_t>& context,
|
||||
uint32_t suffix) {
|
||||
std::vector<uint8_t> ret;
|
||||
// +1 to include the null-terminator
|
||||
ret.insert(ret.end(), prefix, prefix + strlen(prefix) + 1);
|
||||
ret.insert(ret.end(), context.begin(), context.end());
|
||||
const uint32_t suffix_net = htonl(suffix);
|
||||
auto* ptr = reinterpret_cast<const uint8_t*>(&suffix_net);
|
||||
ret.insert(ret.end(), ptr, ptr + sizeof(suffix_net));
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Encryptor::set_enc_key(const std::vector<uint8_t>& enc_key) {
|
||||
enc_key_ = enc_key;
|
||||
}
|
||||
@@ -119,8 +136,21 @@ void KeyDeriver::DeriveKey(const uint8_t* key, size_t master_key_size,
|
||||
// this function, then there is something wrong with the test program and its
|
||||
// dependency on BoringSSL.
|
||||
void KeyDeriver::DeriveKeys(const uint8_t* master_key, size_t master_key_size,
|
||||
const vector<uint8_t>& mac_key_context,
|
||||
const vector<uint8_t>& enc_key_context) {
|
||||
const vector<uint8_t>& context) {
|
||||
// TODO: Use ODK constants instead
|
||||
DeriveKeys(master_key, master_key_size, context, "AUTHENTICATION",
|
||||
"ENCRYPTION");
|
||||
}
|
||||
|
||||
void KeyDeriver::DeriveKeys(const uint8_t* master_key, size_t master_key_size,
|
||||
const vector<uint8_t>& context,
|
||||
const char* mac_label, const char* enc_label) {
|
||||
// TODO: Use ODK constants instead
|
||||
const std::vector<uint8_t> mac_key_context =
|
||||
CreateContext(mac_label, context, 0x200);
|
||||
const std::vector<uint8_t> enc_key_context =
|
||||
CreateContext(enc_label, context, 0x80);
|
||||
|
||||
// Generate derived key for mac key
|
||||
std::vector<uint8_t> mac_key_part2;
|
||||
DeriveKey(master_key, master_key_size, mac_key_context, 1, &mac_key_server_);
|
||||
|
||||
@@ -73,8 +73,10 @@ class KeyDeriver : public Encryptor {
|
||||
|
||||
// Generate mac and enc keys give the master key.
|
||||
void DeriveKeys(const uint8_t* master_key, size_t master_key_size,
|
||||
const std::vector<uint8_t>& mac_key_context,
|
||||
const std::vector<uint8_t>& enc_key_context);
|
||||
const std::vector<uint8_t>& context);
|
||||
void DeriveKeys(const uint8_t* master_key, size_t master_key_size,
|
||||
const std::vector<uint8_t>& context, const char* mac_label,
|
||||
const char* enc_label);
|
||||
// Sign the buffer with server's mac key.
|
||||
void ServerSignBuffer(const uint8_t* data, size_t data_length,
|
||||
std::vector<uint8_t>* signature) const;
|
||||
|
||||
@@ -234,7 +234,8 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
|
||||
// verified by the server. This simulates that.
|
||||
size_t gen_signature_length = 0;
|
||||
size_t core_message_length = 0;
|
||||
constexpr size_t small_size = 42; // arbitrary.
|
||||
const vector<uint8_t> context = session()->GetDefaultContext();
|
||||
const size_t small_size = context.size(); // arbitrary.
|
||||
if (RequestHasNonce()) {
|
||||
session()->GenerateNonce();
|
||||
}
|
||||
@@ -252,7 +253,10 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
|
||||
size_t message_size =
|
||||
std::max(required_message_size_, core_message_length + small_size);
|
||||
vector<uint8_t> data(message_size);
|
||||
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
|
||||
memcpy(&data[core_message_length], context.data(), context.size());
|
||||
for (size_t i = context.size() + core_message_length; i < data.size(); i++) {
|
||||
data[i] = i & 0xFF;
|
||||
}
|
||||
if (ShouldGenerateCorpus()) {
|
||||
WriteRequestApiCorpus<CoreRequest>(gen_signature_length,
|
||||
core_message_length, data);
|
||||
@@ -348,29 +352,37 @@ void ProvisioningRoundTrip::PrepareSession(
|
||||
const wvoec::WidevineKeybox& keybox) {
|
||||
ASSERT_NO_FATAL_FAILURE(session_->open());
|
||||
if (global_features.provisioning_method == OEMCrypto_Keybox) {
|
||||
session_->GenerateDerivedKeysFromKeybox(keybox);
|
||||
encryptor_ = session_->key_deriver();
|
||||
keybox_ = &keybox;
|
||||
} else if (global_features.provisioning_method ==
|
||||
OEMCrypto_BootCertificateChain) {
|
||||
// TODO(chelu): change this to CSR provisioning.
|
||||
session_->LoadOEMCert(true);
|
||||
session_->GenerateRsaSessionKey(&message_key_, &encrypted_message_key_);
|
||||
encryptor_.set_enc_key(message_key_);
|
||||
session_->GenerateRsaSessionKey();
|
||||
encryptor_.set_enc_key(session_->session_key());
|
||||
} else {
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_OEMCertificate);
|
||||
session_->LoadOEMCert(true);
|
||||
session_->GenerateRsaSessionKey(&message_key_, &encrypted_message_key_);
|
||||
encryptor_.set_enc_key(message_key_);
|
||||
session_->GenerateRsaSessionKey();
|
||||
encryptor_.set_enc_key(session_->session_key());
|
||||
}
|
||||
}
|
||||
|
||||
void ProvisioningRoundTrip::VerifyRequestSignature(
|
||||
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
|
||||
size_t /* core_message_length */) {
|
||||
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
size_t core_message_length) {
|
||||
if (keybox_ == nullptr) {
|
||||
session()->VerifyRsaSignature(data, generated_signature.data(),
|
||||
generated_signature.size(), kSign_RSASSA_PSS);
|
||||
} else {
|
||||
// Setup the derived keys using the proto message (ignoring the core
|
||||
// message).
|
||||
ASSERT_LE(core_message_length, data.size());
|
||||
const std::vector<uint8_t> base_message(data.begin() + core_message_length,
|
||||
data.end());
|
||||
session()->GenerateDerivedKeysFromKeybox(*keybox_, base_message);
|
||||
encryptor_ = session()->key_deriver();
|
||||
request_ = base_message;
|
||||
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
|
||||
ASSERT_EQ(HMAC_SHA256_SIGNATURE_SIZE, generated_signature.size());
|
||||
std::vector<uint8_t> expected_signature;
|
||||
@@ -403,11 +415,11 @@ void ProvisioningRoundTrip::CreateDefaultResponse() {
|
||||
response_data_.rsa_key_length = encoded_rsa_key_.size();
|
||||
}
|
||||
response_data_.nonce = session_->nonce();
|
||||
if (encrypted_message_key_.size() > 0) {
|
||||
ASSERT_LE(encrypted_message_key_.size(), kMaxTestRSAKeyLength);
|
||||
memcpy(response_data_.enc_message_key, encrypted_message_key_.data(),
|
||||
encrypted_message_key_.size());
|
||||
response_data_.enc_message_key_length = encrypted_message_key_.size();
|
||||
if (session_->enc_session_key().size() > 0) {
|
||||
ASSERT_LE(session_->enc_session_key().size(), kMaxTestRSAKeyLength);
|
||||
memcpy(response_data_.enc_message_key, session_->enc_session_key().data(),
|
||||
session_->enc_session_key().size());
|
||||
response_data_.enc_message_key_length = session_->enc_session_key().size();
|
||||
} else {
|
||||
response_data_.enc_message_key_length = 0;
|
||||
}
|
||||
@@ -463,9 +475,6 @@ void ProvisioningRoundTrip::SignResponse() {
|
||||
memcpy(encrypted_response_.data() + serialized_core_message_.size(),
|
||||
reinterpret_cast<const uint8_t*>(&encrypted_response_data_),
|
||||
sizeof(encrypted_response_data_));
|
||||
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
session()->GenerateDerivedKeysFromSessionKey();
|
||||
}
|
||||
session()->key_deriver().ServerSignBuffer(encrypted_response_.data(),
|
||||
encrypted_response_.size(),
|
||||
&response_signature_);
|
||||
@@ -532,10 +541,10 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponseNoRetry(
|
||||
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);
|
||||
session->session_id(), request_.data(), request_.size(),
|
||||
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() {
|
||||
@@ -754,11 +763,13 @@ 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);
|
||||
const std::vector<uint8_t> context = session->GetDefaultContext();
|
||||
return OEMCrypto_LoadProvisioningCast(
|
||||
session->session_id(), session->enc_session_key().data(),
|
||||
session->enc_session_key().size(), context.data(), context.size(),
|
||||
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(
|
||||
@@ -1118,6 +1129,8 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session,
|
||||
core_response_.key_array_length * sizeof(*core_response_.key_array));
|
||||
}
|
||||
|
||||
const vector<uint8_t> context = session->GetDefaultContext();
|
||||
|
||||
// Some tests adjust the offset to be beyond the length of the message. Here,
|
||||
// we create a duplicate of the main message buffer so that these offsets do
|
||||
// not point to garbage data. The goal is to make sure OEMCrypto is verifying
|
||||
@@ -1134,7 +1147,9 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session,
|
||||
reinterpret_cast<const uint8_t*>(&encrypted_response_data_) +
|
||||
sizeof(encrypted_response_data_));
|
||||
OEMCryptoResult result = OEMCrypto_LoadLicense(
|
||||
session->session_id(), double_message.data(), encrypted_response_.size(),
|
||||
session->session_id(), context.data(), context.size(),
|
||||
session->enc_session_key().data(), session->enc_session_key().size(),
|
||||
double_message.data(), encrypted_response_.size(),
|
||||
serialized_core_message_.size(), response_signature_.data(),
|
||||
response_signature_.size());
|
||||
if (verify_keys && result == OEMCrypto_SUCCESS) {
|
||||
@@ -1659,63 +1674,42 @@ void Session::GenerateNonce(int* error_counter) {
|
||||
}
|
||||
}
|
||||
|
||||
void Session::FillDefaultContext(vector<uint8_t>* mac_context,
|
||||
vector<uint8_t>* enc_context) {
|
||||
/* Context strings
|
||||
* These context strings are normally created by the CDM layer
|
||||
vector<uint8_t> Session::GetDefaultContext() {
|
||||
/* Context string
|
||||
* This context string is normally created by the CDM layer
|
||||
* from a license request message.
|
||||
* They are used to test MAC and ENC key generation.
|
||||
*/
|
||||
*mac_context = wvutil::a2b_hex(
|
||||
"41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff"
|
||||
"de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873"
|
||||
"4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a"
|
||||
"230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635"
|
||||
"34333231180120002a0c31383836373837343035000000000200");
|
||||
*enc_context = wvutil::a2b_hex(
|
||||
"454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95"
|
||||
"c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb"
|
||||
"e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408"
|
||||
"0112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231"
|
||||
"180120002a0c31383836373837343035000000000080");
|
||||
return wvutil::a2b_hex(
|
||||
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
|
||||
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
|
||||
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
|
||||
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
|
||||
"38373430350000");
|
||||
}
|
||||
|
||||
// This should only be called if the device uses Provisioning 2.0. A failure in
|
||||
// this function is probably caused by a bad keybox.
|
||||
void Session::GenerateDerivedKeysFromKeybox(
|
||||
const wvoec::WidevineKeybox& keybox) {
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
FillDefaultContext(&mac_context, &enc_context);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_GenerateDerivedKeys(
|
||||
session_id(), mac_context.data(), mac_context.size(),
|
||||
enc_context.data(), enc_context.size()));
|
||||
return GenerateDerivedKeysFromKeybox(keybox, GetDefaultContext());
|
||||
}
|
||||
|
||||
void Session::GenerateDerivedKeysFromKeybox(
|
||||
const wvoec::WidevineKeybox& keybox, const std::vector<uint8_t>& context) {
|
||||
key_deriver_.DeriveKeys(keybox.device_key_, sizeof(keybox.device_key_),
|
||||
mac_context, enc_context);
|
||||
context);
|
||||
}
|
||||
|
||||
void Session::GenerateDerivedKeysFromSessionKey() {
|
||||
// Uses test certificate.
|
||||
vector<uint8_t> session_key;
|
||||
vector<uint8_t> enc_session_key;
|
||||
ASSERT_TRUE(public_rsa_ || public_ec_)
|
||||
<< "No public RSA/ECC key loaded in test code";
|
||||
// A failure here probably indicates that there is something wrong with the
|
||||
// test program and its dependency on BoringSSL.
|
||||
ASSERT_TRUE(GenerateSessionKey(&session_key, &enc_session_key));
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
FillDefaultContext(&mac_context, &enc_context);
|
||||
// A failure here is probably caused by having the wrong RSA key loaded.
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_DeriveKeysFromSessionKey(
|
||||
session_id(), enc_session_key.data(), enc_session_key.size(),
|
||||
mac_context.data(), mac_context.size(), enc_context.data(),
|
||||
enc_context.size()));
|
||||
GenerateDerivedKeysFromSessionKey(GetDefaultContext());
|
||||
}
|
||||
|
||||
key_deriver_.DeriveKeys(session_key.data(), session_key.size(), mac_context,
|
||||
enc_context);
|
||||
void Session::GenerateDerivedKeysFromSessionKey(
|
||||
const std::vector<uint8_t>& context) {
|
||||
// Uses test certificate.
|
||||
ASSERT_TRUE(GenerateSessionKey());
|
||||
key_deriver_.DeriveKeys(session_key_.data(), session_key_.size(), context);
|
||||
}
|
||||
|
||||
void Session::TestDecryptCTR(bool get_fresh_key_handle_first,
|
||||
@@ -2016,19 +2010,17 @@ void Session::VerifySignature(const vector<uint8_t>& message,
|
||||
FAIL() << "No public RSA or ECC key loaded in test code";
|
||||
}
|
||||
|
||||
bool Session::GenerateRsaSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* enc_session_key) {
|
||||
bool Session::GenerateRsaSessionKey() {
|
||||
if (!public_rsa_) {
|
||||
cerr << "No public RSA key loaded in test code\n";
|
||||
return false;
|
||||
}
|
||||
*session_key = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
|
||||
*enc_session_key = public_rsa_->EncryptSessionKey(*session_key);
|
||||
return !enc_session_key->empty();
|
||||
session_key_ = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
|
||||
enc_session_key_ = public_rsa_->EncryptSessionKey(session_key_);
|
||||
return !enc_session_key_.empty();
|
||||
}
|
||||
|
||||
bool Session::GenerateEccSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* ecdh_public_key_data) {
|
||||
bool Session::GenerateEccSessionKey() {
|
||||
if (!public_ec_) {
|
||||
cerr << "No public ECC key loaded in test code\n";
|
||||
return false;
|
||||
@@ -2043,24 +2035,23 @@ bool Session::GenerateEccSessionKey(vector<uint8_t>* session_key,
|
||||
<< util::EccCurveToString(curve) << std::endl;
|
||||
return false;
|
||||
}
|
||||
*session_key = server_ephemeral_keys_[curve]->DeriveSessionKey(*public_ec_);
|
||||
if (session_key->empty()) {
|
||||
session_key_ = server_ephemeral_keys_[curve]->DeriveSessionKey(*public_ec_);
|
||||
if (session_key_.empty()) {
|
||||
return false;
|
||||
}
|
||||
*ecdh_public_key_data = server_ephemeral_keys_[curve]->SerializeAsPublicKey();
|
||||
if (ecdh_public_key_data->empty()) {
|
||||
session_key->clear();
|
||||
enc_session_key_ = server_ephemeral_keys_[curve]->SerializeAsPublicKey();
|
||||
if (enc_session_key_.empty()) {
|
||||
session_key_.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Session::GenerateSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* key_material) {
|
||||
bool Session::GenerateSessionKey() {
|
||||
if (public_rsa_ != nullptr) {
|
||||
return GenerateRsaSessionKey(session_key, key_material);
|
||||
return GenerateRsaSessionKey();
|
||||
} else if (public_ec_ != nullptr) {
|
||||
return GenerateEccSessionKey(session_key, key_material);
|
||||
return GenerateEccSessionKey();
|
||||
}
|
||||
cerr << "No public RSA or ECC key loaded in test code\n";
|
||||
return false;
|
||||
|
||||
@@ -276,7 +276,7 @@ class ProvisioningRoundTrip
|
||||
const std::vector<uint8_t>& encoded_rsa_key)
|
||||
: RoundTrip(session),
|
||||
allowed_schemes_(kSign_RSASSA_PSS),
|
||||
encryptor_(),
|
||||
keybox_(nullptr),
|
||||
encoded_rsa_key_(encoded_rsa_key) {}
|
||||
// Prepare the session for signing the request.
|
||||
virtual void PrepareSession(const wvoec::WidevineKeybox& keybox);
|
||||
@@ -317,9 +317,9 @@ class ProvisioningRoundTrip
|
||||
|
||||
uint32_t allowed_schemes_;
|
||||
Encryptor encryptor_;
|
||||
std::vector<uint8_t> request_;
|
||||
const wvoec::WidevineKeybox* keybox_;
|
||||
// The message key used for Prov 3.0.
|
||||
std::vector<uint8_t> message_key_;
|
||||
std::vector<uint8_t> encrypted_message_key_;
|
||||
std::vector<uint8_t> encoded_rsa_key_;
|
||||
std::vector<uint8_t> wrapped_rsa_key_;
|
||||
};
|
||||
@@ -673,15 +673,17 @@ class Session {
|
||||
// and try again if a nonce flood has been detected. If error_counter is
|
||||
// not null, it will be incremented when a nonce flood is detected.
|
||||
void GenerateNonce(int* error_counter = nullptr);
|
||||
// Fill the vectors with test context which generate known mac and enc keys.
|
||||
void FillDefaultContext(vector<uint8_t>* mac_context,
|
||||
vector<uint8_t>* enc_context);
|
||||
// Fill the vector with test context which generate known mac and enc keys.
|
||||
std::vector<uint8_t> GetDefaultContext();
|
||||
// Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and
|
||||
// also fill out enc_key_, mac_key_server_, and mac_key_client_.
|
||||
void GenerateDerivedKeysFromKeybox(const wvoec::WidevineKeybox& keybox);
|
||||
void GenerateDerivedKeysFromKeybox(const wvoec::WidevineKeybox& keybox,
|
||||
const std::vector<uint8_t>& context);
|
||||
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
|
||||
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
|
||||
void GenerateDerivedKeysFromSessionKey();
|
||||
void GenerateDerivedKeysFromSessionKey(const std::vector<uint8_t>& context);
|
||||
// Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption.
|
||||
void TestDecryptCTR(bool get_fresh_key_handle_first = true,
|
||||
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
|
||||
@@ -747,17 +749,14 @@ class Session {
|
||||
// Encrypts a known session key with public_rsa_ for use in future calls to
|
||||
// OEMCrypto_DeriveKeysFromSessionKey or OEMCrypto_RewrapDeviceRSAKey30.
|
||||
// The unencrypted session key is stored in session_key.
|
||||
bool GenerateRsaSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* enc_session_key);
|
||||
bool GenerateRsaSessionKey();
|
||||
// Derives a session key with public_ec_ and a ephemeral "server" ECC key
|
||||
// for use in future calls to OEMCrypto_DeriveKeysFromSessionKey.
|
||||
// The unencrypted session key is stored in session_key.
|
||||
bool GenerateEccSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* ecdh_public_key_data);
|
||||
bool GenerateEccSessionKey();
|
||||
// Based on the key type installed, call GenerateRsaSessionKey or
|
||||
// GenerateEccSessionKey.
|
||||
bool GenerateSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* key_material);
|
||||
bool GenerateSessionKey();
|
||||
|
||||
// Calls OEMCrypto_RewrapDeviceRSAKey30 with the given provisioning response
|
||||
// message. If force is true, we assert that the key loads successfully.
|
||||
@@ -840,6 +839,11 @@ class Session {
|
||||
// functions.
|
||||
vector<uint8_t>& key_handle() { return key_handle_; }
|
||||
|
||||
const std::vector<uint8_t>& session_key() const { return session_key_; }
|
||||
const std::vector<uint8_t>& enc_session_key() const {
|
||||
return enc_session_key_;
|
||||
}
|
||||
|
||||
const KeyDeriver& key_deriver() const { return key_deriver_; }
|
||||
void set_mac_keys(const uint8_t* mac_keys) {
|
||||
key_deriver_.set_mac_keys(mac_keys);
|
||||
@@ -882,6 +886,8 @@ class Session {
|
||||
vector<uint8_t> pst_report_buffer_;
|
||||
MessageData license_ = {};
|
||||
vector<uint8_t> key_handle_;
|
||||
std::vector<uint8_t> session_key_;
|
||||
std::vector<uint8_t> enc_session_key_;
|
||||
|
||||
vector<uint8_t> encrypted_usage_entry_;
|
||||
uint32_t usage_entry_number_ = 0;
|
||||
|
||||
@@ -49,7 +49,6 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, ForbidUseAsDRMCert) {
|
||||
if (key_loaded_) {
|
||||
// The other padding scheme should fail.
|
||||
DisallowForbiddenPaddingDRMKey(kSign_RSASSA_PSS, 83);
|
||||
DisallowDeriveKeys();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,26 +51,6 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
|
||||
licenseRequest, signature.data(), signature_length, scheme));
|
||||
}
|
||||
|
||||
void DisallowDeriveKeys() {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||
s.GenerateNonce();
|
||||
vector<uint8_t> session_key;
|
||||
vector<uint8_t> enc_session_key;
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
s.FillDefaultContext(&mac_context, &enc_context);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_DeriveKeysFromSessionKey(
|
||||
s.session_id(), enc_session_key.data(),
|
||||
enc_session_key.size(), mac_context.data(),
|
||||
mac_context.size(), enc_context.data(), enc_context.size()));
|
||||
}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void LoadCastCertificateKey(bool force) {
|
||||
if (!wvoec::global_features.cast_receiver) {
|
||||
|
||||
@@ -472,9 +472,12 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyUnalignedMessageAPI16) {
|
||||
license_messages_.encrypted_response_buffer().end());
|
||||
// Thus, buffer[offset] is NOT word aligned.
|
||||
const uint8_t* unaligned_message = &buffer[offset];
|
||||
const std::vector<uint8_t> context = session_.GetDefaultContext();
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadLicense(
|
||||
session_.session_id(), unaligned_message,
|
||||
session_.session_id(), context.data(), context.size(),
|
||||
session_.enc_session_key().data(),
|
||||
session_.enc_session_key().size(), unaligned_message,
|
||||
license_messages_.encrypted_response_buffer().size(),
|
||||
license_messages_.serialized_core_message().size(),
|
||||
license_messages_.response_signature().data(),
|
||||
|
||||
@@ -67,24 +67,6 @@ TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
|
||||
}
|
||||
|
||||
// This tests GenerateDerivedKeys with an 8k context.
|
||||
TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||
vector<uint8_t> mac_context(max_size);
|
||||
vector<uint8_t> enc_context(max_size);
|
||||
// Stripe the data so the two vectors are not identical, and not all zeroes.
|
||||
for (size_t i = 0; i < max_size; i++) {
|
||||
mac_context[i] = i % 0x100;
|
||||
enc_context[i] = (3 * i) % 0x100;
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_GenerateDerivedKeys(
|
||||
s.session_id(), mac_context.data(), mac_context.size(),
|
||||
enc_context.data(), enc_context.size()));
|
||||
}
|
||||
|
||||
// This verifies that the device really does claim to have a certificate.
|
||||
// It should be filtered out for devices that have a keybox.
|
||||
TEST_F(OEMCryptoProv30Test, DeviceClaimsOEMCertificate) {
|
||||
@@ -164,7 +146,6 @@ TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) {
|
||||
// Derive keys from the session key -- this should use the DRM Cert's key.
|
||||
// It should NOT use the OEM Private key because that key should not have
|
||||
// been loaded.
|
||||
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey());
|
||||
// Now fill a message and try to load it.
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.set_control(0);
|
||||
@@ -745,14 +726,8 @@ TEST_F(OEMCryptoLoadsCertificate, SignProvisioningRequest) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
s.LoadOEMCert(true);
|
||||
} else {
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
|
||||
s.GenerateDerivedKeysFromKeybox(keybox_);
|
||||
}
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(keybox_));
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
|
||||
}
|
||||
|
||||
@@ -764,16 +739,10 @@ TEST_F(OEMCryptoLoadsCertificate, SignLargeProvisioningRequestAPI16) {
|
||||
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
|
||||
}
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
s.LoadOEMCert(true);
|
||||
} else {
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
|
||||
s.GenerateDerivedKeysFromKeybox(keybox_);
|
||||
}
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||
provisioning_messages.set_message_size(max_size);
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(keybox_));
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
|
||||
}
|
||||
|
||||
@@ -788,7 +757,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) {
|
||||
}
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(keybox_));
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
|
||||
@@ -1326,41 +1295,17 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||
vector<uint8_t> session_key;
|
||||
vector<uint8_t> enc_session_key;
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
s.FillDefaultContext(&mac_context, &enc_context);
|
||||
|
||||
enc_session_key = wvutil::a2b_hex(
|
||||
"7789c619aa3b9fa3c0a53f57a4abc6"
|
||||
"02157c8aa57e3c6fb450b0bea22667fb"
|
||||
"0c3200f9d9d618e397837c720dc2dadf"
|
||||
"486f33590744b2a4e54ca134ae7dbf74"
|
||||
"434c2fcf6b525f3e132262f05ea3b3c1"
|
||||
"198595c0e52b573335b2e8a3debd0d0d"
|
||||
"d0306f8fcdde4e76476be71342957251"
|
||||
"e1688c9ca6c1c34ed056d3b989394160"
|
||||
"cf6937e5ce4d39cc73d11a2e93da21a2"
|
||||
"fa019d246c852fe960095b32f120c3c2"
|
||||
"7085f7b64aac344a68d607c0768676ce"
|
||||
"d4c5b2d057f7601921b453a451e1dea0"
|
||||
"843ebfef628d9af2784d68e86b730476"
|
||||
"e136dfe19989de4be30a4e7878efcde5"
|
||||
"ad2b1254f80c0c5dd3cf111b56572217"
|
||||
"b9f58fc1dacbf74b59d354a1e62cfa0e"
|
||||
"bf");
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.SignAndVerifyRequest();
|
||||
license_messages.CreateDefaultResponse();
|
||||
|
||||
start_time = clock.now();
|
||||
count = 0;
|
||||
do {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_DeriveKeysFromSessionKey(
|
||||
s.session_id(), enc_session_key.data(),
|
||||
enc_session_key.size(), mac_context.data(),
|
||||
mac_context.size(), enc_context.data(), enc_context.size()));
|
||||
license_messages.LoadResponse(&s, /* verify_keys= */ false);
|
||||
count++;
|
||||
} while (clock.now() - start_time < kTestDuration);
|
||||
delta_time = clock.now() - start_time;
|
||||
@@ -1376,24 +1321,4 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) {
|
||||
derive_keys_time);
|
||||
}
|
||||
|
||||
// Test DeriveKeysFromSessionKey using the maximum size for the HMAC context.
|
||||
TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) {
|
||||
vector<uint8_t> session_key;
|
||||
vector<uint8_t> enc_session_key;
|
||||
ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key));
|
||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||
vector<uint8_t> mac_context(max_size);
|
||||
vector<uint8_t> enc_context(max_size);
|
||||
// Stripe the data so the two vectors are not identical, and not all zeroes.
|
||||
for (size_t i = 0; i < max_size; i++) {
|
||||
mac_context[i] = i % 0x100;
|
||||
enc_context[i] = (3 * i) % 0x100;
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_DeriveKeysFromSessionKey(
|
||||
session_.session_id(), enc_session_key.data(),
|
||||
enc_session_key.size(), mac_context.data(), mac_context.size(),
|
||||
enc_context.data(), enc_context.size()));
|
||||
}
|
||||
|
||||
} // namespace wvoec
|
||||
|
||||
@@ -173,15 +173,11 @@ class OTAKeyboxProvisioningTest : public ::testing::Test, public SessionUtil {
|
||||
TEST_F(OTAKeyboxProvisioningTest, BasicTest) {
|
||||
OEMCryptoResult result = OEMCrypto_IsKeyboxValid();
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
cout << " "
|
||||
<< "Keybox valid after initialization. Skipping rest of test." << endl;
|
||||
return;
|
||||
GTEST_SKIP() << "Keybox valid after initialization. Skipping rest of test.";
|
||||
}
|
||||
if (result != OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING) {
|
||||
cout << " "
|
||||
<< "OTA Keybox functions not supported. Skipping rest of test."
|
||||
<< endl;
|
||||
return;
|
||||
GTEST_SKIP()
|
||||
<< "OTA Keybox functions not supported. Skipping rest of test.";
|
||||
}
|
||||
cout << " "
|
||||
<< "OTA Keybox functions supported. Device needs provisioning." << endl;
|
||||
@@ -235,28 +231,11 @@ TEST_F(OTAKeyboxProvisioningTest, BasicTest) {
|
||||
const std::vector<uint8_t> model_key = GetModelKey(device_id);
|
||||
#endif
|
||||
// The server should derive the same set of keys as the client.
|
||||
const std::string mac_label = "WV_SIGN";
|
||||
std::vector<uint8_t> mac_context(mac_label.begin(), mac_label.end());
|
||||
mac_context.push_back(0);
|
||||
std::copy(cert.begin(), cert.end(), std::back_inserter(mac_context));
|
||||
std::copy(device_id.begin(), device_id.end(),
|
||||
std::back_inserter(mac_context));
|
||||
uint32_t bit_size = MAC_KEY_SIZE * 8 * 2;
|
||||
std::string bit_size_string = wvutil::EncodeUint32(bit_size);
|
||||
std::copy(bit_size_string.begin(), bit_size_string.end(),
|
||||
std::back_inserter(mac_context));
|
||||
std::string enc_label = "WV_ENCRYPT";
|
||||
std::vector<uint8_t> enc_context(enc_label.begin(), enc_label.end());
|
||||
enc_context.push_back(0);
|
||||
std::copy(cert.begin(), cert.end(), std::back_inserter(enc_context));
|
||||
std::copy(device_id.begin(), device_id.end(),
|
||||
std::back_inserter(enc_context));
|
||||
bit_size = KEY_SIZE * 8;
|
||||
bit_size_string = wvutil::EncodeUint32(bit_size);
|
||||
std::copy(bit_size_string.begin(), bit_size_string.end(),
|
||||
std::back_inserter(enc_context));
|
||||
KeyDeriver keys;
|
||||
keys.DeriveKeys(model_key.data(), model_key.size(), mac_context, enc_context);
|
||||
std::vector<uint8_t> context = cert;
|
||||
context.insert(context.end(), device_id.begin(), device_id.end());
|
||||
keys.DeriveKeys(model_key.data(), model_key.size(), context, "WV_SIGN",
|
||||
"WV_ENCRYPT");
|
||||
const std::vector<uint8_t> message(
|
||||
request.data(),
|
||||
request.data() + request.size() - HMAC_SHA256_SIGNATURE_SIZE);
|
||||
|
||||
Reference in New Issue
Block a user