RenewLicense test updates.

This commit is contained in:
Fred Gylys-Colwell
2019-12-15 17:01:22 -08:00
parent f328c85fc3
commit dc346cf70a
9 changed files with 1020 additions and 1036 deletions

View File

@@ -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);
/*

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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.

View File

@@ -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;

View File

@@ -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());
}

View File

@@ -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