RenewLicense test updates.
This commit is contained in:
@@ -319,7 +319,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
|
||||
*/
|
||||
OEMCryptoResult ODK_PrepareCoreRenewalRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_size,
|
||||
const ODK_NonceValues* nonce_values, const ODK_ClockValues* clock_values,
|
||||
const ODK_NonceValues* nonce_values, ODK_ClockValues* clock_values,
|
||||
uint64_t system_time_seconds);
|
||||
|
||||
/*
|
||||
|
||||
@@ -130,15 +130,24 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest(
|
||||
OEMCryptoResult ODK_PrepareCoreRenewalRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_length,
|
||||
const ODK_NonceValues* nonce_values,
|
||||
const ODK_ClockValues* clock_values, uint64_t system_time_seconds) {
|
||||
ODK_ClockValues* clock_values, uint64_t system_time_seconds) {
|
||||
ODK_RenewalMessage renewal_request = {
|
||||
{0},
|
||||
};
|
||||
if (odk_sub_overflow_u64(system_time_seconds,
|
||||
clock_values->time_of_first_decrypt,
|
||||
&renewal_request.playback_time)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
if (clock_values->time_of_first_decrypt == 0) {
|
||||
/* It is OK to preemptively request a renewal before playback starts.
|
||||
* We'll treat this as asking for a renewal at playback time 0. */
|
||||
renewal_request.playback_time = 0;
|
||||
} else {
|
||||
/* Otherwise, playback_time is relative to the first decrypt. */
|
||||
if (odk_sub_overflow_u64(system_time_seconds,
|
||||
clock_values->time_of_first_decrypt,
|
||||
&renewal_request.playback_time)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
}
|
||||
/* Save time for this request so that we can verify the response. */
|
||||
clock_values->time_of_renewal_request = renewal_request.playback_time;
|
||||
return ODK_PrepareRequest(message, message_length, core_message_length,
|
||||
ODK_Renewal_Request_Type, nonce_values,
|
||||
&renewal_request.core_message);
|
||||
@@ -187,32 +196,41 @@ OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length,
|
||||
if (err != OEMCrypto_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This function should not be used for legacy licenses. */
|
||||
if (license_response.core_message.nonce_values.api_version != 16) {
|
||||
return ODK_UNSUPPORTED_API;
|
||||
}
|
||||
|
||||
if (parsed_license->nonce_required) {
|
||||
if (initial_license_load) {
|
||||
if (nonce_values->nonce != license_response.core_message.nonce_values.nonce ||
|
||||
nonce_values->session_id != license_response.core_message.nonce_values.session_id) {
|
||||
if (nonce_values->nonce !=
|
||||
license_response.core_message.nonce_values.nonce ||
|
||||
nonce_values->session_id !=
|
||||
license_response.core_message.nonce_values.session_id) {
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
}
|
||||
} else { /* !initial_license_load */
|
||||
nonce_values->nonce = license_response.core_message.nonce_values.nonce;
|
||||
nonce_values->session_id = license_response.core_message.nonce_values.session_id;
|
||||
nonce_values->session_id =
|
||||
license_response.core_message.nonce_values.session_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (initial_license_load &&
|
||||
memcmp(request_hash, parsed_license->request_hash, ODK_SHA256_HASH_SIZE)) {
|
||||
/* For v16, in order to be backwards compatible with a v15 license server,
|
||||
* OEMCrypto stores a hash of the core license request and only signs the
|
||||
* message body. Here, when we process the license response, we verify that
|
||||
* the server has the same hash of the core request. */
|
||||
if (initial_license_load && memcmp(request_hash, parsed_license->request_hash,
|
||||
ODK_SHA256_HASH_SIZE)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
/* If the license has a provider session token (pst), then OEMCrypto should
|
||||
* have a usage entry loaded. */
|
||||
if (usage_entry_present && parsed_license->pst.length == 0) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
/* If the license loaded OK, then we should save off the timer limits. */
|
||||
if (!timer_limits) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
*timer_limits = parsed_license->timer_limits;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -223,7 +241,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
const ODK_TimerLimits* timer_limits,
|
||||
ODK_ClockValues* clock_values,
|
||||
uint64_t* timer_value) {
|
||||
if (!nonce_values || !timer_limits || !clock_values || !timer_value) {
|
||||
if (!nonce_values || !timer_limits || !clock_values) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -243,6 +261,13 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
* Section: Renewal Message
|
||||
*/
|
||||
|
||||
/* If a renewal request is lost in transit, we should throw it out and create
|
||||
* a new one. We use the timestamp to make sure we have the latest request.
|
||||
*/
|
||||
if (clock_values->time_of_renewal_request < renewal_response.playback_time) {
|
||||
return ODK_STALE_RENEWAL;
|
||||
}
|
||||
|
||||
uint64_t playback_timer = 0;
|
||||
if (odk_sub_overflow_u64(clock_values->time_when_timer_expires, system_time,
|
||||
&playback_timer)) {
|
||||
@@ -268,7 +293,8 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
}
|
||||
|
||||
/* todo: when to return ODK_DISABLE_TIMER */
|
||||
*timer_value = timer_limits->renewal_playback_duration_seconds;
|
||||
if (timer_value)
|
||||
*timer_value = timer_limits->renewal_playback_duration_seconds;
|
||||
return ODK_SET_TIMER;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,6 +188,13 @@ OEMCryptoResult ODK_UpdateLastPlaybackTime(uint64_t system_time_seconds,
|
||||
if (clock_values->timer_status == ODK_TIMER_EXPIRED) {
|
||||
return ODK_TIMER_EXPIRED;
|
||||
}
|
||||
/* If the clock status is already marked as inactive, then playback is
|
||||
* not allowed. */
|
||||
/* TODO(b/142415188): add helper function. */
|
||||
if (clock_values->status > kActive) {
|
||||
clock_values->timer_status = ODK_TIMER_EXPIRED;
|
||||
return ODK_TIMER_EXPIRED;
|
||||
}
|
||||
if (clock_values->time_when_timer_expires > 0 &&
|
||||
system_time_seconds > clock_values->time_when_timer_expires) {
|
||||
clock_values->timer_status = ODK_TIMER_EXPIRED;
|
||||
|
||||
@@ -191,7 +191,6 @@ void expect_eq_buf(const void* s1, const void* s2, size_t n) {
|
||||
std::fstream out(tmp, std::ios::out | std::ios::binary);
|
||||
out.write((char*)buffers[i], n);
|
||||
out.close();
|
||||
std:
|
||||
std::cerr << "buffer " << i << " dumped to " << tmp << std::endl;
|
||||
}
|
||||
FAIL();
|
||||
|
||||
@@ -195,7 +195,7 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
|
||||
// Some tests may require root access. If user is not root, filter these tests
|
||||
// out.
|
||||
if (!CanChangeTime()) {
|
||||
FilterOut(&filter, "OEMCryptoUsageTableTest.TimeRollbackPrevention");
|
||||
FilterOut(&filter, "*TimeRollbackPrevention*");
|
||||
}
|
||||
// Performance tests take a long time. Filter them out if they are not
|
||||
// specifically requested.
|
||||
|
||||
@@ -138,7 +138,6 @@ void KeyDeriver::set_mac_keys(const uint8_t* mac_keys) {
|
||||
|
||||
void KeyDeriver::ServerSignBuffer(const uint8_t* data, size_t data_length,
|
||||
std::vector<uint8_t>* signature) const {
|
||||
ASSERT_LE(data_length, kMaxMessageSize);
|
||||
ASSERT_EQ(mac_key_server_.size(), MAC_KEY_SIZE);
|
||||
signature->assign(SHA256_DIGEST_LENGTH, 0);
|
||||
unsigned int sig_len = SHA256_DIGEST_LENGTH;
|
||||
|
||||
@@ -317,10 +317,10 @@ void ProvisioningRoundTrip::EncryptAndSignResponse() {
|
||||
&response_signature_);
|
||||
}
|
||||
|
||||
OEMCryptoResult ProvisioningRoundTrip::LoadResponse() {
|
||||
OEMCryptoResult ProvisioningRoundTrip::LoadResponse(Session* session) {
|
||||
size_t wrapped_key_length = 0;
|
||||
const OEMCryptoResult sts = OEMCrypto_LoadProvisioning(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
session->session_id(), encrypted_response_.data(),
|
||||
encrypted_response_.size(), serialized_core_message_.size(),
|
||||
response_signature_.data(), response_signature_.size(), nullptr,
|
||||
&wrapped_key_length);
|
||||
@@ -328,7 +328,7 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponse() {
|
||||
wrapped_rsa_key_.clear();
|
||||
wrapped_rsa_key_.assign(wrapped_key_length, 0);
|
||||
return OEMCrypto_LoadProvisioning(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
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);
|
||||
@@ -397,11 +397,30 @@ 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 & control_) ? 1 : 0;
|
||||
((wvoec::kControlNonceEnabled | wvoec::kControlNonceOrEntry |
|
||||
wvoec::kControlNonceRequired) &
|
||||
control_)
|
||||
? 1
|
||||
: 0;
|
||||
core_response_.license_type = license_type_;
|
||||
FillCoreResponseSubstrings();
|
||||
}
|
||||
|
||||
void LicenseRoundTrip::CreateResponseWithGenericCryptoKeys() {
|
||||
CreateDefaultResponse();
|
||||
response_data_.keys[0].control.control_bits |=
|
||||
htonl(wvoec::kControlAllowEncrypt);
|
||||
response_data_.keys[1].control.control_bits |=
|
||||
htonl(wvoec::kControlAllowDecrypt);
|
||||
response_data_.keys[2].control.control_bits |=
|
||||
htonl(wvoec::kControlAllowSign);
|
||||
response_data_.keys[3].control.control_bits |=
|
||||
htonl(wvoec::kControlAllowVerify);
|
||||
response_data_.keys[2].key_data_length = wvoec::MAC_KEY_SIZE;
|
||||
response_data_.keys[3].key_data_length = wvoec::MAC_KEY_SIZE;
|
||||
FillCoreResponseSubstrings();
|
||||
}
|
||||
|
||||
void LicenseRoundTrip::FillCoreResponseSubstrings() {
|
||||
if (update_mac_keys_) {
|
||||
core_response_.enc_mac_keys_iv = FindSubstring(
|
||||
@@ -496,7 +515,7 @@ void LicenseRoundTrip::EncryptAndSignResponse() {
|
||||
&response_signature_);
|
||||
}
|
||||
|
||||
OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) {
|
||||
// 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
|
||||
@@ -510,7 +529,7 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
OEMCryptoResult result;
|
||||
if (api_version_ < kCoreMessagesAPI) {
|
||||
result = OEMCrypto_LoadKeys(
|
||||
session_->session_id(), double_message.data(),
|
||||
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,
|
||||
@@ -519,7 +538,7 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
static_cast<OEMCrypto_LicenseType>(core_response_.license_type));
|
||||
} else {
|
||||
result = OEMCrypto_LoadLicense(
|
||||
session_->session_id(), double_message.data(),
|
||||
session->session_id(), double_message.data(),
|
||||
encrypted_response_.size(), serialized_core_message_.size(),
|
||||
response_signature_.data(), response_signature_.size());
|
||||
}
|
||||
@@ -527,10 +546,10 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
// 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
|
||||
// to verify decrypt operations.
|
||||
session_->set_license(response_data_);
|
||||
session->set_license(response_data_);
|
||||
// Also, if the license has new mac keys, then install them now.
|
||||
if (core_response_.enc_mac_keys.length > 0) {
|
||||
session_->set_mac_keys(response_data_.mac_keys);
|
||||
session->set_mac_keys(response_data_.mac_keys);
|
||||
}
|
||||
|
||||
// Note: we verify content licenses here. For entitlement license, we verify
|
||||
@@ -540,6 +559,11 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse() {
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult LicenseRoundTrip::ReloadResponse(Session* session) {
|
||||
session->GenerateDerivedKeysFromSessionKey();
|
||||
return LoadResponse(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
|
||||
@@ -729,9 +753,13 @@ void RenewalRoundTrip::FillAndVerifyCoreRequest(
|
||||
oec_util::ParseRenewalRequest(core_message_string, &core_request_));
|
||||
EXPECT_EQ(license_messages_->core_request().api_version,
|
||||
core_request_.api_version);
|
||||
EXPECT_EQ(license_messages_->core_request().nonce, core_request_.nonce);
|
||||
EXPECT_EQ(license_messages_->core_request().session_id,
|
||||
core_request_.session_id);
|
||||
if (!is_release_) {
|
||||
// For a license release, we don not expect the nonce to be correct. That
|
||||
// is because a release might be sent without loading the license first.
|
||||
EXPECT_EQ(license_messages_->core_request().nonce, core_request_.nonce);
|
||||
EXPECT_EQ(license_messages_->core_request().session_id,
|
||||
core_request_.session_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,15 +828,15 @@ void RenewalRoundTrip::EncryptAndSignResponse() {
|
||||
&response_signature_);
|
||||
}
|
||||
|
||||
OEMCryptoResult RenewalRoundTrip::LoadResponse() {
|
||||
OEMCryptoResult RenewalRoundTrip::LoadResponse(Session* session) {
|
||||
if (license_messages_->api_version() < kCoreMessagesAPI) {
|
||||
return OEMCrypto_RefreshKeys(
|
||||
session_->session_id(), encrypted_response_.data(),
|
||||
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(),
|
||||
session->session_id(), encrypted_response_.data(),
|
||||
encrypted_response_.size(), serialized_core_message_.size(),
|
||||
response_signature_.data(), response_signature_.size());
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ void PrintTo(const vector<uint8_t>& value, ostream* os);
|
||||
namespace wvoec {
|
||||
|
||||
// Make sure this is larger than kMaxKeysPerSession, in oemcrypto_test.cpp
|
||||
constexpr size_t kMaxNumKeys = 35;
|
||||
constexpr size_t kMaxNumKeys = 30;
|
||||
|
||||
namespace {
|
||||
#if defined(TEST_SPEED_MULTIPLIER) // Can slow test time limits when
|
||||
@@ -66,7 +66,7 @@ constexpr int kDefaultKeyIdLength = 16;
|
||||
|
||||
constexpr size_t kMaxPSTLength = 255; // In specification.
|
||||
constexpr size_t kMaxMessageSize = 8 * 1024; // In specification.
|
||||
constexpr size_t kMaxCoreMessage = 20 * kMaxNumKeys + 150; // Rough estimate.
|
||||
constexpr size_t kMaxCoreMessage = 200 * kMaxNumKeys + 200; // Rough estimate.
|
||||
|
||||
typedef struct {
|
||||
uint8_t key_id[kTestKeyIdMaxLength];
|
||||
@@ -177,7 +177,9 @@ class RoundTrip {
|
||||
// Attempt to load the response and return the error. Short buffer errors are
|
||||
// handled by LoadResponse, not the caller. All other errors should be
|
||||
// handled by the caller.
|
||||
virtual OEMCryptoResult LoadResponse() = 0;
|
||||
virtual OEMCryptoResult LoadResponse() { return LoadResponse(session_); }
|
||||
// As with LoadResponse, but load into a different session.
|
||||
virtual OEMCryptoResult LoadResponse(Session* session) = 0;
|
||||
|
||||
// Accessors are all read/write because tests modify default values.
|
||||
Session* session() { return session_; }
|
||||
@@ -188,14 +190,10 @@ class RoundTrip {
|
||||
std::vector<uint8_t>& encrypted_response_buffer() {
|
||||
return encrypted_response_;
|
||||
}
|
||||
void set_session(Session* session) { session_ = session; }
|
||||
|
||||
// Set the size of the buffer used the encrypted license.
|
||||
// Must be between sizeof(MessageData) and kMaxMessageSize.
|
||||
void set_message_size(size_t size) {
|
||||
message_size_ = size;
|
||||
ASSERT_GE(message_size_, sizeof(ResponseData) + kMaxCoreMessage);
|
||||
ASSERT_LE(message_size_, kMaxMessageSize);
|
||||
}
|
||||
void set_message_size(size_t size) { message_size_ = size; }
|
||||
// The size of the encrypted message.
|
||||
size_t message_size() { return message_size_; }
|
||||
std::vector<uint8_t>& response_signature() { return response_signature_; }
|
||||
@@ -245,7 +243,8 @@ class ProvisioningRoundTrip
|
||||
virtual void PrepareSession(const wvoec::WidevineKeybox& keybox);
|
||||
void CreateDefaultResponse() override;
|
||||
void EncryptAndSignResponse() override;
|
||||
OEMCryptoResult LoadResponse() override;
|
||||
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
|
||||
OEMCryptoResult LoadResponse(Session* session) override;
|
||||
void VerifyLoadFailed();
|
||||
const std::vector<uint8_t>& encoded_rsa_key() { return encoded_rsa_key_; }
|
||||
const std::vector<uint8_t>& wrapped_rsa_key() { return wrapped_rsa_key_; }
|
||||
@@ -282,14 +281,21 @@ class LicenseRoundTrip
|
||||
pst_(""),
|
||||
minimum_srm_version_(0),
|
||||
update_mac_keys_(true),
|
||||
api_version_(0),
|
||||
api_version_(kCurrentAPI),
|
||||
expect_request_has_correct_nonce_(true),
|
||||
license_type_(OEMCrypto_ContentLicense) {}
|
||||
void CreateDefaultResponse() override;
|
||||
// Create a license with four keys, one each that is allowed to do generic
|
||||
// encrypt, decrypt, sign and verify.
|
||||
void CreateResponseWithGenericCryptoKeys();
|
||||
// Fill the |core_response| substrings.
|
||||
virtual void FillCoreResponseSubstrings();
|
||||
void EncryptAndSignResponse() override;
|
||||
OEMCryptoResult LoadResponse() override;
|
||||
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
|
||||
OEMCryptoResult LoadResponse(Session* session) override;
|
||||
// Reload an offline license into a different session. This derives new mac
|
||||
// keys and then calls LoadResponse.
|
||||
OEMCryptoResult ReloadResponse(Session* session);
|
||||
void VerifyTestKeys();
|
||||
// Set the default key control block for all keys. This is used in
|
||||
// CreateDefaultResponse. The key control block determines the restrictions
|
||||
@@ -368,10 +374,13 @@ class RenewalRoundTrip : public RoundTrip<
|
||||
RenewalRoundTrip(LicenseRoundTrip* license_messages)
|
||||
: RoundTrip(license_messages->session()),
|
||||
license_messages_(license_messages),
|
||||
refresh_object_() {}
|
||||
refresh_object_(),
|
||||
is_release_(false) {}
|
||||
void CreateDefaultResponse() override;
|
||||
void EncryptAndSignResponse() override;
|
||||
OEMCryptoResult LoadResponse() override;
|
||||
OEMCryptoResult LoadResponse() override { return LoadResponse(session_); }
|
||||
OEMCryptoResult LoadResponse(Session* session) override;
|
||||
void set_is_release(bool is_release) { is_release_ = is_release; }
|
||||
|
||||
protected:
|
||||
void VerifyRequestSignature(const vector<uint8_t>& data,
|
||||
@@ -382,6 +391,7 @@ class RenewalRoundTrip : public RoundTrip<
|
||||
const std::string& core_message_string) override;
|
||||
LicenseRoundTrip* license_messages_;
|
||||
OEMCrypto_KeyRefreshObject refresh_object_;
|
||||
bool is_release_; // If this is a license release, and not a real renewal.
|
||||
};
|
||||
|
||||
class EntitledMessage {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user