Cherry pick cdm udc-widevine-release changes to udc-widevine-dev to be in sync with 18.3 release
Merged from go/wvgerrit/178231 Bug: 290252845 Test: WVTS tests seem to be running and passing Change-Id: Ifff9123a73e173e835a6e89ba7c2760e1cd500fd (cherry picked from commit 6889845d2e7e24f22c00b333335c34259b3fc96e)
This commit is contained in:
@@ -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(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) {
|
||||
@@ -685,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);
|
||||
@@ -713,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;
|
||||
}
|
||||
@@ -733,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.
|
||||
@@ -753,11 +913,9 @@ 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 = session()->nonce();
|
||||
response_data_.keys[i].control.nonce = htonl(session()->nonce());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,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) {
|
||||
@@ -947,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,
|
||||
@@ -1855,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,
|
||||
|
||||
Reference in New Issue
Block a user