Add OEMCrypto tests for Cast prov 4 flow
Expected flow, which begins with a device that has already been provisioned with Prov 4 stage 1: 1. OEMCrypto_InstallOEMPrivateKey() 2. OEMCrypto_GenerateCertificateKeyPair() -> wrapped_csr_priv 3. OEMCrypto_LoadDRMPrivateKey(wrapped_csr_priv) 4. OEMCrypto_PrepAndSignProvisioningRequest() to create a Prov 4 provisioning request message type with a CAST request in the message body 5. Server sends a Prov 2 response. Server side derivation uses CSR keys to derive session key, mac keys, and encryption keys. 6. OEMCrypto_DeriveKeysFromSessionKey(), same derivation as server side 7. OEMCrypto_LoadProvisioning(), use derived keys to verify + decrypt The OEMCrypto_LoadDRMPrivateKey() step can happen before or after the PrepAndSignProvisioningRequest() call. Test: tests fail Bug: 259452440 Merged from https://widevine-internal-review.googlesource.com/172310 Change-Id: Id5e6737b187339ec93e3d0d03c28e2b379d60747
This commit is contained in:
committed by
Robert Shih
parent
5a17d8ebd9
commit
27421a9161
@@ -603,6 +603,161 @@ OEMCryptoResult Provisioning40RoundTrip::LoadDRMCertResponse() {
|
||||
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(kSign_RSASSA_PSS);
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user