OEMCrypto v16.2

Merge from Widevine repo of http://go/wvgerrit/93404

This is the unit tests, reference code, and documentation for
OEMCrypto v16.2. Backwards compatibility should work for a v15
OEMCrypto.

Some review comments will be addressed in future CLs.

Bug: 141247171
Test: Unit tests
Test: Media GTS tests on bonito
Change-Id: I9d427c07580e180c0a4cfdc4a68f538d351c0ddd
This commit is contained in:
Fred Gylys-Colwell
2020-01-18 10:18:50 -08:00
parent 7665614b2e
commit db2050dff1
62 changed files with 2947 additions and 2286 deletions

View File

@@ -19,6 +19,7 @@
#include <stdint.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
@@ -137,26 +138,6 @@ class boringssl_ptr {
CORE_DISALLOW_COPY_AND_ASSIGN(boringssl_ptr);
};
OEMCrypto_Substring GetSubstring(const std::string& message,
const std::string& field, bool set_zero) {
OEMCrypto_Substring substring;
if (set_zero || field.empty() || message.empty()) {
substring.offset = 0;
substring.length = 0;
} else {
size_t pos = message.find(field);
if (pos == std::string::npos) {
LOGW("GetSubstring : Cannot find offset for %s", field.c_str());
substring.offset = 0;
substring.length = 0;
} else {
substring.offset = pos;
substring.length = field.length();
}
}
return substring;
}
Test_PST_Report::Test_PST_Report(const std::string& pst_in,
OEMCrypto_Usage_Entry_Status status_in)
: status(status_in), pst(pst_in) {
@@ -169,23 +150,29 @@ void RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse,
ResponseData>::SignAndVerifyRequest() {
// In the real world, a message should be signed by the client and
// verified by the server. This simulates that.
vector<uint8_t> data(message_size_);
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
OEMCryptoResult sts;
size_t gen_signature_length = 0;
size_t core_message_length = 0;
sts =
constexpr size_t small_size = 42; // arbitrary.
size_t message_size =
std::max(required_message_size_, core_message_length + small_size);
vector<uint8_t> data(message_size, 0);
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
ASSERT_EQ(
PrepAndSignRequest(session()->session_id(), data.data(), data.size(),
&core_message_length, nullptr, &gen_signature_length);
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
// If this fails, either the test needs to be modified, or the core message is
// very very large.
ASSERT_LT(core_message_length, message_size_);
&core_message_length, nullptr, &gen_signature_length),
OEMCrypto_ERROR_SHORT_BUFFER);
// Make the message buffer a little bigger than the core message, or the
// required size, whichever is larger.
message_size =
std::max(required_message_size_, core_message_length + small_size);
data.resize(message_size);
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
vector<uint8_t> gen_signature(gen_signature_length);
sts = PrepAndSignRequest(session()->session_id(), data.data(), data.size(),
&core_message_length, gen_signature.data(),
&gen_signature_length);
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(PrepAndSignRequest(session()->session_id(), data.data(),
data.size(), &core_message_length,
gen_signature.data(), &gen_signature_length),
OEMCrypto_SUCCESS);
if (global_features.api_version >= kCoreMessagesAPI) {
ASSERT_GT(data.size(), core_message_length);
std::string core_message(reinterpret_cast<char*>(data.data()),
@@ -247,7 +234,7 @@ void ProvisioningRoundTrip::FillAndVerifyCoreRequest(
EXPECT_TRUE(
oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage(
core_message_string, &core_request_));
EXPECT_EQ(global_features.api_version, core_request_.api_version);
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();
@@ -282,7 +269,7 @@ void ProvisioningRoundTrip::CreateDefaultResponse() {
} else {
response_data_.enc_message_key_length = 0;
}
core_response_.key_type = OEMCrypto_Supports_RSA_2048bit;
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(
@@ -296,12 +283,20 @@ void ProvisioningRoundTrip::EncryptAndSignResponse() {
&encrypted_response_data_);
core_response_.enc_private_key.length =
encrypted_response_data_.rsa_key_length;
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreProvisioningResponse(
core_response_, core_request_, &serialized_core_message_));
if (global_features.api_version >= kCoreMessagesAPI) {
ASSERT_TRUE(
oemcrypto_core_message::serialize::CreateCoreProvisioningResponse(
core_response_, core_request_, &serialized_core_message_));
}
// 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_);
encrypted_response_.resize(message_size);
for (size_t i = 0; i < encrypted_response_.size(); i++) {
encrypted_response_[i] = i % 0x100;
encrypted_response_[i] = i & 0xFF;
}
ASSERT_GE(encrypted_response_.size(), serialized_core_message_.size());
memcpy(encrypted_response_.data(), serialized_core_message_.data(),
@@ -322,19 +317,83 @@ void ProvisioningRoundTrip::EncryptAndSignResponse() {
OEMCryptoResult ProvisioningRoundTrip::LoadResponse(Session* session) {
EXPECT_NE(session, nullptr);
size_t wrapped_key_length = 0;
const OEMCryptoResult sts = OEMCrypto_LoadProvisioning(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size(), nullptr,
&wrapped_key_length);
const OEMCryptoResult sts = LoadResponseNoRetry(session, &wrapped_key_length);
if (sts != OEMCrypto_ERROR_SHORT_BUFFER) return sts;
wrapped_rsa_key_.clear();
wrapped_rsa_key_.assign(wrapped_key_length, 0);
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);
return LoadResponseNoRetry(session, &wrapped_key_length);
}
#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 session, const uint32_t* unaligned_nonce,
const uint8_t* encrypted_message_key, size_t encrypted_message_key_length,
const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key,
size_t* wrapped_rsa_key_length) {
LOGE("Support for v15 functions not included. Define TEST_OEMCRYPTO_V15.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey_V15(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length,
const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key,
size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv,
uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) {
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 =
reinterpret_cast<const uint8_t*>(response_pointer);
size_t delta =
original_pointer - reinterpret_cast<const uint8_t*>(&response_data_);
// Base offset should be 0 if this is a v15 message, which is the only time
// this function is called.
size_t base_offset = serialized_core_message_.size();
const uint8_t* new_pointer = encrypted_response_.data() + delta + base_offset;
return reinterpret_cast<const T*>(new_pointer);
}
OEMCryptoResult ProvisioningRoundTrip::LoadResponseNoRetry(
Session* session, size_t* wrapped_key_length) {
EXPECT_NE(session, nullptr);
if (global_features.api_version >= kCoreMessagesAPI) {
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) {
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);
}
}
void ProvisioningRoundTrip::VerifyLoadFailed() {
@@ -346,10 +405,17 @@ void ProvisioningRoundTrip::VerifyLoadFailed() {
void LicenseRoundTrip::VerifyRequestSignature(
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
size_t core_message_length) {
std::vector<uint8_t> subdata(data.begin() + core_message_length, data.end());
const std::vector<uint8_t> subdata(data.begin() + core_message_length,
data.end());
session()->VerifyRSASignature(subdata, generated_signature.data(),
generated_signature.size(), kSign_RSASSA_PSS);
SHA256(data.data(), core_message_length, core_response_.request_hash);
SHA256(data.data(), core_message_length, request_hash_);
// If the api version was not set by the test, then we record the api version
// from the request. Also, if the api was set to be higher than oemcrypto
// supports, then we lower it. This version will be used in the response.
if (api_version_ == 0) api_version_ = core_request_.api_major_version;
if (api_version_ > global_features.api_version)
api_version_ = global_features.api_version;
}
void LicenseRoundTrip::FillAndVerifyCoreRequest(
@@ -357,12 +423,16 @@ void LicenseRoundTrip::FillAndVerifyCoreRequest(
EXPECT_TRUE(
oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage(
core_message_string, &core_request_));
EXPECT_EQ(global_features.api_version, core_request_.api_version);
EXPECT_EQ(global_features.api_version, core_request_.api_major_version);
// If we are testing the latest OEMCrypto version, make sure it is built with
// the latest ODK version, too:
if (global_features.api_version == ODK_MAJOR_VERSION) {
EXPECT_EQ(ODK_MINOR_VERSION, core_request_.api_minor_version);
}
if (expect_request_has_correct_nonce_) {
EXPECT_EQ(session()->nonce(), core_request_.nonce);
}
EXPECT_EQ(session()->session_id(), core_request_.session_id);
if (api_version_ == 0) api_version_ = core_request_.api_version;
}
void LicenseRoundTrip::CreateDefaultResponse() {
@@ -371,10 +441,12 @@ void LicenseRoundTrip::CreateDefaultResponse() {
memset(response_data_.padding, 0, sizeof(response_data_.padding));
EXPECT_EQ(1, GetRandBytes(response_data_.mac_keys,
sizeof(response_data_.mac_keys)));
// For backwards compatibility, we use the license duration for each key's
// duration.
uint32_t duration = static_cast<uint32_t>(
core_response_.timer_limits.license_duration_seconds);
// For backwards compatibility, we use the largest limit in timer_limits for
// each key's duration.
uint32_t key_duration = static_cast<uint32_t>(
std::max({core_response_.timer_limits.rental_duration_seconds,
core_response_.timer_limits.total_playback_duration_seconds,
core_response_.timer_limits.initial_renewal_duration_seconds}));
// The key data for an entitlement license is an AES-256 key, otherwise the
// default is an AES_128 key.
uint32_t default_key_size =
@@ -393,7 +465,7 @@ void LicenseRoundTrip::CreateDefaultResponse() {
sizeof(response_data_.keys[i].control_iv)));
std::string kcVersion = "kc" + std::to_string(api_version_);
memcpy(response_data_.keys[i].control.verification, kcVersion.c_str(), 4);
response_data_.keys[i].control.duration = htonl(duration);
response_data_.keys[i].control.duration = htonl(key_duration);
response_data_.keys[i].control.nonce = htonl(session_->nonce());
response_data_.keys[i].control.control_bits = htonl(control_);
response_data_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR;
@@ -493,12 +565,20 @@ void LicenseRoundTrip::EncryptAndSignResponse() {
if (api_version_ < kCoreMessagesAPI) {
serialized_core_message_.resize(0);
} else {
std::string request_hash_string(
reinterpret_cast<const char*>(request_hash_), sizeof(request_hash_));
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse(
core_response_, core_request_, &serialized_core_message_));
core_response_, core_request_, request_hash_string,
&serialized_core_message_));
}
// 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_);
encrypted_response_.resize(message_size);
for (size_t i = 0; i < encrypted_response_.size(); i++) {
encrypted_response_[i] = i % 0x100;
}
@@ -522,15 +602,19 @@ void LicenseRoundTrip::EncryptAndSignResponse() {
OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) {
EXPECT_NE(session, nullptr);
// Some tests adjust the offset to be beyond the length of the message. Here,
// we create a duplicate of the message buffer so that these offsets do not
// point to garbage data. The goal is to make sure OEMCrypto is verifying that
// the offset points outside of the message -- we don't want OEMCrypto to look
// at what offset points to and return an error if the data is garbage. Since
// the memory after the message buffer is an exact copy of the message, we can
// increment the offset by the message size and get valid data.
// 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
// that the offset points outside of the message -- we don't want OEMCrypto to
// look at what offset points to and return an error if the data is
// garbage. Since the memory after the message buffer is an exact copy of the
// message, we can increment the offset by the message size and get valid
// data.
std::vector<uint8_t> double_message = encrypted_response_;
double_message.insert(double_message.end(), encrypted_response_.begin(),
encrypted_response_.end());
double_message.insert(
double_message.end(),
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(
@@ -584,11 +668,9 @@ void LicenseRoundTrip::VerifyTestKeys() {
if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(sizeof(block), size);
// control duration and bits stored in network byte order. For printing
// Note: we do not assume that duration is stored with each key after v16.
// control bits stored in network byte order. For printing
// we change to host byte order.
ASSERT_EQ(htonl_fnc(response_data_.keys[i].control.duration),
htonl_fnc(block.duration))
<< "For key " << i;
ASSERT_EQ(htonl_fnc(response_data_.keys[i].control.control_bits),
htonl_fnc(block.control_bits))
<< "For key " << i;
@@ -758,8 +840,8 @@ void RenewalRoundTrip::FillAndVerifyCoreRequest(
EXPECT_TRUE(
oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage(
core_message_string, &core_request_));
EXPECT_EQ(license_messages_->core_request().api_version,
core_request_.api_version);
EXPECT_EQ(license_messages_->core_request().api_major_version,
core_request_.api_major_version);
if (!is_release_) {
// For a license release, we do not expect the nonce to be correct. That
// is because a release might be sent without loading the license first.
@@ -786,12 +868,17 @@ void RenewalRoundTrip::CreateDefaultResponse() {
constexpr size_t index = 0;
response_data_.keys[index].key_id_length = 0;
response_data_.keys[index].key_id[0] = '\0';
std::string kcVersion = "kc" + std::to_string(core_request_.api_version);
std::string kcVersion =
"kc" + std::to_string(core_request_.api_major_version);
if (global_features.api_version < kCoreMessagesAPI) {
// For v15 or earlier devices, we use the api of the device.
kcVersion = "kc" + std::to_string(global_features.api_version);
}
memcpy(response_data_.keys[index].control.verification, kcVersion.c_str(),
4);
const uint32_t duration = static_cast<uint32_t>(
license_messages_->core_response()
.timer_limits.renewal_playback_duration_seconds);
.timer_limits.initial_renewal_duration_seconds);
response_data_.keys[index].control.duration = htonl(duration);
response_data_.keys[index].control.nonce = htonl(nonce);
response_data_.keys[index].control.control_bits = htonl(control);
@@ -801,12 +888,6 @@ void RenewalRoundTrip::CreateDefaultResponse() {
void RenewalRoundTrip::EncryptAndSignResponse() {
// Renewal messages are not encrypted.
encrypted_response_data_ = 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 % 0x100;
}
// Either create a KeyRefreshObject for a call to RefreshKeys or a core
// response for a call to LoadRenewal.
if (license_messages_->api_version() < kCoreMessagesAPI) {
@@ -818,7 +899,17 @@ void RenewalRoundTrip::EncryptAndSignResponse() {
serialized_core_message_.resize(0);
} else {
ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse(
core_request_, &serialized_core_message_));
core_request_, renewal_duration_seconds_, &serialized_core_message_));
}
// 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 % 0x100;
}
// Concatenate the core message and the response.
ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size());