OEMCrypto v16.1
Merge of http://go/wvgerrit/93404 This CL updates the Widevine CDM to support OEMCrypto v16.1 Test: Tested in 16.2 CL Bug: 141247171 Change-Id: I69bd993500f6fb63bf6010c8b0250dc7acc3d71b
This commit is contained in:
@@ -11,8 +11,6 @@ LOCAL_SRC_FILES:= \
|
||||
src/oemcrypto_keybox_ref.cpp \
|
||||
src/oemcrypto_keybox_testkey.cpp \
|
||||
src/oemcrypto_ref.cpp \
|
||||
src/oemcrypto_nonce_table.cpp \
|
||||
src/oemcrypto_old_usage_table_ref.cpp \
|
||||
src/oemcrypto_rsa_key_shared.cpp \
|
||||
src/oemcrypto_session.cpp \
|
||||
src/oemcrypto_session_key_table.cpp \
|
||||
|
||||
@@ -53,7 +53,7 @@ class Prov30CryptoEngine : public CryptoEngine {
|
||||
if (kOEMPublicCertSize == 0) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (public_cert_length == NULL) {
|
||||
if (public_cert_length == nullptr) {
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (*public_cert_length < kOEMPublicCertSize) {
|
||||
@@ -61,7 +61,7 @@ class Prov30CryptoEngine : public CryptoEngine {
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*public_cert_length = kOEMPublicCertSize;
|
||||
if (public_cert == NULL) {
|
||||
if (public_cert == nullptr) {
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "oemcrypto_engine_ref.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <chrono>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
@@ -17,6 +16,7 @@
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "clock.h"
|
||||
#include "keys.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_key_ref.h"
|
||||
@@ -88,23 +88,26 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) {
|
||||
if (it != sessions_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
time_t CryptoEngine::OnlineTime() {
|
||||
int64_t CryptoEngine::OnlineTime() {
|
||||
// Use the monotonic clock for times that don't have to be stable across
|
||||
// device boots.
|
||||
std::chrono::steady_clock clock;
|
||||
return clock.now().time_since_epoch() / std::chrono::seconds(1);
|
||||
int64_t now = wvcdm::Clock().GetCurrentTime();
|
||||
static int64_t then = now;
|
||||
if (now < then) now = then;
|
||||
then = now;
|
||||
return now;
|
||||
}
|
||||
|
||||
time_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
||||
int64_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
||||
struct TimeInfo {
|
||||
// The max time recorded through this function call.
|
||||
time_t previous_time;
|
||||
int64_t previous_time;
|
||||
// If the wall time is rollbacked to before the previous_time, this member
|
||||
// is updated to reflect the offset.
|
||||
time_t rollback_offset;
|
||||
int64_t rollback_offset;
|
||||
// Pad the struct so that TimeInfo is a multiple of 16.
|
||||
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
|
||||
};
|
||||
@@ -135,7 +138,7 @@ time_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
||||
if (!file) {
|
||||
LOGE("RollbackCorrectedOfflineTime: File open failed: %s",
|
||||
filename.c_str());
|
||||
return time(NULL);
|
||||
return OnlineTime();
|
||||
}
|
||||
file->Read(reinterpret_cast<char*>(&encrypted_buffer[0]), sizeof(TimeInfo));
|
||||
// Decrypt the encrypted TimeInfo buffer.
|
||||
@@ -147,9 +150,9 @@ time_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
||||
memcpy(&time_info, &clear_buffer[0], sizeof(TimeInfo));
|
||||
}
|
||||
|
||||
time_t current_time;
|
||||
int64_t current_time;
|
||||
// Add any time offsets in the past to the current time.
|
||||
current_time = time(NULL) + time_info.rollback_offset;
|
||||
current_time = OnlineTime() + time_info.rollback_offset;
|
||||
if (time_info.previous_time > current_time) {
|
||||
// Time has been rolled back.
|
||||
// Update the rollback offset.
|
||||
@@ -174,7 +177,7 @@ time_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
||||
if (!file) {
|
||||
LOGE("RollbackCorrectedOfflineTime: File open failed: %s",
|
||||
filename.c_str());
|
||||
return time(NULL);
|
||||
return OnlineTime();
|
||||
}
|
||||
file->Write(reinterpret_cast<char*>(&encrypted_buffer[0]), sizeof(TimeInfo));
|
||||
|
||||
@@ -183,9 +186,9 @@ time_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
||||
}
|
||||
|
||||
bool CryptoEngine::NonceCollision(uint32_t nonce) {
|
||||
for (const auto & session_pair : sessions_) {
|
||||
for (const auto& session_pair : sessions_) {
|
||||
const SessionContext* session = session_pair.second;
|
||||
if (session->NonceCollision(nonce)) return true;
|
||||
if (nonce == session->nonce()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -199,45 +202,45 @@ OEMCrypto_HDCP_Capability CryptoEngine::config_maximum_hdcp_capability() {
|
||||
}
|
||||
|
||||
OEMCryptoResult CryptoEngine::SetDestination(
|
||||
OEMCrypto_DestBufferDesc* out_description, size_t data_length,
|
||||
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
|
||||
uint8_t subsample_flags) {
|
||||
size_t max_length = 0;
|
||||
switch (out_description->type) {
|
||||
switch (out_description.type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
destination_ = out_description->buffer.clear.address;
|
||||
max_length = out_description->buffer.clear.max_length;
|
||||
destination_ = out_description.buffer.clear.address;
|
||||
max_length = out_description.buffer.clear.address_length;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
destination_ =
|
||||
reinterpret_cast<uint8_t*>(out_description->buffer.secure.handle) +
|
||||
out_description->buffer.secure.offset;
|
||||
max_length = out_description->buffer.secure.max_length -
|
||||
out_description->buffer.secure.offset;
|
||||
reinterpret_cast<uint8_t*>(out_description.buffer.secure.handle) +
|
||||
out_description.buffer.secure.offset;
|
||||
max_length = out_description.buffer.secure.handle_length -
|
||||
out_description.buffer.secure.offset;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
// Direct buffer type is only used on some specialized devices where
|
||||
// oemcrypto has a direct connection to the screen buffer. It is not,
|
||||
// for example, supported on Android.
|
||||
destination_ = NULL;
|
||||
destination_ = nullptr;
|
||||
break;
|
||||
default:
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
size_t max_allowed = max_output_size();
|
||||
const size_t max_allowed = max_sample_size();
|
||||
if (max_allowed > 0 &&
|
||||
(max_allowed < max_length || max_allowed < data_length)) {
|
||||
LOGE("Output too large (or buffer too small).");
|
||||
return OEMCrypto_ERROR_OUTPUT_TOO_LARGE;
|
||||
}
|
||||
|
||||
if (out_description->type != OEMCrypto_BufferType_Direct &&
|
||||
if (out_description.type != OEMCrypto_BufferType_Direct &&
|
||||
max_length < data_length) {
|
||||
LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]");
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
adjust_destination(out_description, data_length, subsample_flags);
|
||||
if ((out_description->type != OEMCrypto_BufferType_Direct) &&
|
||||
(destination_ == NULL)) {
|
||||
if ((out_description.type != OEMCrypto_BufferType_Direct) &&
|
||||
(destination_ == nullptr)) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
|
||||
@@ -31,6 +31,9 @@ typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
||||
|
||||
class CryptoEngine {
|
||||
public:
|
||||
static const uint32_t kApiVersion = 16;
|
||||
static const uint32_t kMinorApiVersion = 0;
|
||||
|
||||
// This is like a factory method, except we choose which version to use at
|
||||
// compile time. It is defined in several source files. The build system
|
||||
// should choose which one to use by only linking in the correct one.
|
||||
@@ -87,12 +90,11 @@ class CryptoEngine {
|
||||
return kMaxSupportedOEMCryptoSessions;
|
||||
}
|
||||
|
||||
time_t OnlineTime();
|
||||
// The OEMCrypto system time. Prevents time rollback.
|
||||
// TODO(b/145836634): Combine RollbackCorrectedOfflineTime with OnlineTime().
|
||||
int64_t SystemTime() { return RollbackCorrectedOfflineTime(); }
|
||||
|
||||
time_t RollbackCorrectedOfflineTime();
|
||||
|
||||
// Verify that this nonce does not collide with another nonce in any session's
|
||||
// nonce table.
|
||||
// Verify that this nonce does not collide with another nonce in any session.
|
||||
virtual bool NonceCollision(uint32_t nonce);
|
||||
|
||||
// Returns the HDCP version currently in use.
|
||||
@@ -133,12 +135,15 @@ class CryptoEngine {
|
||||
return OEMCrypto_Keybox;
|
||||
}
|
||||
|
||||
virtual OEMCryptoResult get_oem_certificate(SessionContext* session,
|
||||
uint8_t* public_cert,
|
||||
virtual OEMCryptoResult get_oem_certificate(uint8_t* public_cert,
|
||||
size_t* public_cert_length) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
virtual OEMCryptoResult load_oem_private_key(SessionContext* session) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
// Used for OEMCrypto_IsAntiRollbackHwPresent.
|
||||
virtual bool config_is_anti_rollback_hw_present() { return false; }
|
||||
|
||||
@@ -150,14 +155,14 @@ class CryptoEngine {
|
||||
// been applied to the device that fixes a security bug.
|
||||
virtual uint8_t config_security_patch_level() { return 0; }
|
||||
|
||||
// If 0 no restriction, otherwise it's the max buffer for DecryptCENC.
|
||||
// This is the same as the max subsample size, not the sample or frame size.
|
||||
virtual size_t max_buffer_size() { return 1024 * 100; } // 100 KiB.
|
||||
// If 0 no restriction, otherwise it's the max subsample size for
|
||||
// DecryptCENC. This is not the same as the max sample or buffer size.
|
||||
virtual size_t max_subsample_size() { return 1024 * 100; } // 100 KiB
|
||||
|
||||
// If 0 no restriction, otherwise it's the max output buffer for DecryptCENC
|
||||
// and CopyBuffer. This is the same as the max frame or sample size, not the
|
||||
// subsample size.
|
||||
virtual size_t max_output_size() { return 0; }
|
||||
// If 0 no restriction, otherwise it's the max sample size for DecryptCENC.
|
||||
// This is the same as the max input and output buffer size for DecryptCENC
|
||||
// and CopyBuffer. It is not the same as the max subsample size.
|
||||
virtual size_t max_sample_size() { return 1024 * 1024; } // 1 MiB
|
||||
|
||||
virtual bool srm_update_supported() { return false; }
|
||||
|
||||
@@ -176,8 +181,8 @@ class CryptoEngine {
|
||||
|
||||
virtual bool srm_blacklisted_device_attached() { return false; }
|
||||
|
||||
// Rate limit for nonce generation. Default to 20 nonce/second.
|
||||
virtual int nonce_flood_count() { return 20; }
|
||||
// Rate limit for nonce generation. Default to 200 nonce/second.
|
||||
virtual int nonce_flood_count() { return 200; }
|
||||
|
||||
// Limit for size of usage table. If this is zero, then the
|
||||
// size is unlimited -- or limited only by memory size.
|
||||
@@ -186,24 +191,32 @@ class CryptoEngine {
|
||||
virtual uint32_t resource_rating() { return 1; }
|
||||
|
||||
// Set destination pointer based on the output destination description.
|
||||
OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_description,
|
||||
size_t data_length, uint8_t subsample_flags);
|
||||
OEMCryptoResult SetDestination(
|
||||
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
|
||||
uint8_t subsample_flags);
|
||||
|
||||
// The current destination.
|
||||
uint8_t* destination() { return destination_; }
|
||||
|
||||
// Subclasses can adjust the destination -- for use in testing.
|
||||
virtual void adjust_destination(OEMCrypto_DestBufferDesc* out_description,
|
||||
size_t data_length, uint8_t subsample_flags) {
|
||||
}
|
||||
virtual void adjust_destination(
|
||||
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
|
||||
uint8_t subsample_flags) {}
|
||||
|
||||
// Push destination buffer to output -- used by subclasses for testing.
|
||||
virtual OEMCryptoResult PushDestination(
|
||||
OEMCrypto_DestBufferDesc* out_description, uint8_t subsample_flags) {
|
||||
const OEMCrypto_DestBufferDesc& out_description,
|
||||
uint8_t subsample_flags) {
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
protected:
|
||||
// System clock, measuring time in seconds.
|
||||
int64_t OnlineTime();
|
||||
|
||||
// System clock with antirollback protection, measuring time in seconds.
|
||||
int64_t RollbackCorrectedOfflineTime();
|
||||
|
||||
explicit CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system);
|
||||
virtual SessionContext* MakeSession(SessionId sid);
|
||||
virtual UsageTable* MakeUsageTable();
|
||||
|
||||
@@ -22,7 +22,8 @@ bool KeyControlBlock::Validate() {
|
||||
memcmp(verification_, "kc12", 4) && // add in version 12 api
|
||||
memcmp(verification_, "kc13", 4) && // add in version 13 api
|
||||
memcmp(verification_, "kc14", 4) && // add in version 14 api
|
||||
memcmp(verification_, "kc15", 4)) { // add in version 15 api
|
||||
memcmp(verification_, "kc15", 4) && // add in version 15 api
|
||||
memcmp(verification_, "kc16", 4)) { // add in version 16 api
|
||||
LOGE("KCB: BAD verification string: %4.4s", verification_);
|
||||
valid_ = false;
|
||||
} else {
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
WvKeybox::WvKeybox() : loaded_(false) {}
|
||||
WvKeybox::WvKeybox() : loaded_(false) {
|
||||
static std::string fake_device_id = "device_with_no_keybox";
|
||||
device_id_.assign(fake_device_id.begin(), fake_device_id.end());
|
||||
}
|
||||
|
||||
KeyboxError WvKeybox::Validate() {
|
||||
if (!loaded_) {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
//
|
||||
// Reference implementation of OEMCrypto APIs
|
||||
//
|
||||
#include "oemcrypto_nonce_table.h"
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
void NonceTable::AddNonce(uint32_t nonce) {
|
||||
int new_slot = -1;
|
||||
int oldest_slot = -1;
|
||||
|
||||
// Flush any nonces that have been checked but not flushed.
|
||||
// After flush, nonces will be either valid or invalid.
|
||||
Flush();
|
||||
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
// Increase age of all valid nonces.
|
||||
if (kNTStateValid == state_[i]) {
|
||||
++age_[i];
|
||||
if (-1 == oldest_slot) {
|
||||
oldest_slot = i;
|
||||
} else {
|
||||
if (age_[i] > age_[oldest_slot]) {
|
||||
oldest_slot = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (-1 == new_slot) {
|
||||
age_[i] = 0;
|
||||
nonces_[i] = nonce;
|
||||
state_[i] = kNTStateValid;
|
||||
new_slot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-1 == new_slot) {
|
||||
// reuse oldest
|
||||
// assert (oldest_slot != -1)
|
||||
int i = oldest_slot;
|
||||
age_[i] = 0;
|
||||
nonces_[i] = nonce;
|
||||
state_[i] = kNTStateValid;
|
||||
}
|
||||
}
|
||||
|
||||
bool NonceTable::CheckNonce(uint32_t nonce) {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (kNTStateInvalid != state_[i]) {
|
||||
if (nonce == nonces_[i]) {
|
||||
state_[i] = kNTStateFlushPending;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NonceTable::NonceCollision(uint32_t nonce) const {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (nonce == nonces_[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NonceTable::Flush() {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
if (kNTStateFlushPending == state_[i]) {
|
||||
state_[i] = kNTStateInvalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvoec_ref
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
//
|
||||
// Reference implementation of OEMCrypto APIs
|
||||
//
|
||||
#ifndef REF_OEMCRYPTO_NONCE_TABLE_H_
|
||||
#define REF_OEMCRYPTO_NONCE_TABLE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
class NonceTable {
|
||||
public:
|
||||
static const int kTableSize = 4;
|
||||
NonceTable() {
|
||||
for (int i = 0; i < kTableSize; ++i) {
|
||||
state_[i] = kNTStateInvalid;
|
||||
}
|
||||
}
|
||||
~NonceTable() {}
|
||||
void AddNonce(uint32_t nonce);
|
||||
bool CheckNonce(uint32_t nonce);
|
||||
// Verify that the nonce is not the same as any in this table.
|
||||
bool NonceCollision(uint32_t nonce) const;
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
enum NonceTableState {
|
||||
kNTStateInvalid,
|
||||
kNTStateValid,
|
||||
kNTStateFlushPending
|
||||
};
|
||||
NonceTableState state_[kTableSize];
|
||||
uint32_t age_[kTableSize];
|
||||
uint32_t nonces_[kTableSize];
|
||||
};
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
#endif // REF_OEMCRYPTO_NONCE_TABLE_H_
|
||||
@@ -1,239 +0,0 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
//
|
||||
// Reference implementation of OEMCrypto APIs
|
||||
//
|
||||
// This is from the v12 version of oemcrypto usage tables. It is used for
|
||||
// devices that upgrade from v12 to v13 in the field, and need to convert from
|
||||
// the old type of usage table to the new.
|
||||
#include "oemcrypto_old_usage_table_ref.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
#include "oemcrypto_engine_ref.h"
|
||||
// TODO(fredgc): Setting the device files base bath is currently broken as
|
||||
// wvcdm::Properties is no longer used by the reference code.
|
||||
//#include "properties.h"
|
||||
#include "pst_report.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table,
|
||||
const std::vector<uint8_t> &pst_hash)
|
||||
: pst_hash_(pst_hash),
|
||||
old_usage_table_(old_usage_table),
|
||||
time_of_license_received_(
|
||||
old_usage_table_->ce_->RollbackCorrectedOfflineTime()),
|
||||
time_of_first_decrypt_(0),
|
||||
time_of_last_decrypt_(0),
|
||||
status_(kUnused) {}
|
||||
|
||||
OldUsageTableEntry::~OldUsageTableEntry() {}
|
||||
|
||||
OldUsageTableEntry::OldUsageTableEntry(OldUsageTable *old_usage_table,
|
||||
const OldStoredUsageEntry *buffer)
|
||||
: old_usage_table_(old_usage_table) {
|
||||
pst_hash_.assign(buffer->pst_hash, buffer->pst_hash + SHA256_DIGEST_LENGTH);
|
||||
time_of_license_received_ = buffer->time_of_license_received;
|
||||
time_of_first_decrypt_ = buffer->time_of_first_decrypt;
|
||||
time_of_last_decrypt_ = buffer->time_of_last_decrypt;
|
||||
status_ = buffer->status;
|
||||
mac_key_server_.assign(buffer->mac_key_server,
|
||||
buffer->mac_key_server + wvoec::MAC_KEY_SIZE);
|
||||
mac_key_client_.assign(buffer->mac_key_client,
|
||||
buffer->mac_key_client + wvoec::MAC_KEY_SIZE);
|
||||
}
|
||||
|
||||
OldUsageTable::OldUsageTable(CryptoEngine *ce) {
|
||||
ce_ = ce;
|
||||
generation_ = 0;
|
||||
table_.clear();
|
||||
|
||||
// Load saved table.
|
||||
wvcdm::FileSystem *file_system = ce->file_system();
|
||||
std::unique_ptr<wvcdm::File> file;
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
// TODO(fredgc, jfore): Address how this property is presented to the ref.
|
||||
// For now, the path is empty.
|
||||
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3, &path)) {
|
||||
LOGE("OldUsageTable: Unable to get base path");
|
||||
return;
|
||||
}*/
|
||||
std::string filename = path + "UsageTable.dat";
|
||||
if (!file_system->Exists(filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t file_size = file_system->FileSize(filename);
|
||||
std::vector<uint8_t> encrypted_buffer(file_size);
|
||||
std::vector<uint8_t> buffer(file_size);
|
||||
OldStoredUsageTable *stored_table =
|
||||
reinterpret_cast<OldStoredUsageTable *>(&buffer[0]);
|
||||
OldStoredUsageTable *encrypted_table =
|
||||
reinterpret_cast<OldStoredUsageTable *>(&encrypted_buffer[0]);
|
||||
|
||||
file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
LOGE("OldUsageTable: File open failed: %s", path.c_str());
|
||||
return;
|
||||
}
|
||||
file->Read(reinterpret_cast<char *>(&encrypted_buffer[0]), file_size);
|
||||
|
||||
// Verify the signature of the usage table file.
|
||||
|
||||
// This should be encrypted and signed with a device specific key.
|
||||
// For the reference implementation, I'm just going to use the keybox key.
|
||||
const std::vector<uint8_t> &key = ce_->DeviceRootKey();
|
||||
if (key.empty()) {
|
||||
LOGE("OldUsageTable: DeviceRootKey is unexpectedly empty.");
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
|
||||
unsigned int sig_length = sizeof(computed_signature);
|
||||
if (!HMAC(EVP_sha256(), &key[0], key.size(),
|
||||
&encrypted_buffer[SHA256_DIGEST_LENGTH],
|
||||
file_size - SHA256_DIGEST_LENGTH, computed_signature,
|
||||
&sig_length)) {
|
||||
LOGE("OldUsageTable: Could not recreate signature.");
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
if (memcmp(encrypted_table->signature, computed_signature, sig_length)) {
|
||||
LOGE("OldUsageTable: Invalid signature given: %s",
|
||||
wvcdm::HexEncode(&encrypted_buffer[0], sig_length).c_str());
|
||||
LOGE("OldUsageTable: Invalid signature computed: %s",
|
||||
wvcdm::HexEncode(computed_signature, sig_length).c_str());
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Next, decrypt the table.
|
||||
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
|
||||
memcpy(iv_buffer, encrypted_table->iv, wvoec::KEY_IV_SIZE);
|
||||
AES_KEY aes_key;
|
||||
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||
AES_cbc_encrypt(&encrypted_buffer[SHA256_DIGEST_LENGTH + wvoec::KEY_IV_SIZE],
|
||||
&buffer[SHA256_DIGEST_LENGTH + wvoec::KEY_IV_SIZE],
|
||||
file_size - SHA256_DIGEST_LENGTH - wvoec::KEY_IV_SIZE, &aes_key,
|
||||
iv_buffer, AES_DECRYPT);
|
||||
|
||||
// Next, read the generation number from a different location.
|
||||
// On a real implementation, you should NOT put the generation number in
|
||||
// a file in user space. It should be stored in secure memory. For the
|
||||
// reference implementation, we'll just pretend this is secure.
|
||||
std::string filename2 = path + "GenerationNumber.dat";
|
||||
file = file_system->Open(filename2, wvcdm::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
LOGE("OldUsageTable: File open failed: %s (clearing table)", path.c_str());
|
||||
generation_ = 0;
|
||||
table_.clear();
|
||||
return;
|
||||
}
|
||||
file->Read(reinterpret_cast<char *>(&generation_), sizeof(int64_t));
|
||||
if ((stored_table->generation > generation_ + 1) ||
|
||||
(stored_table->generation < generation_ - 1)) {
|
||||
LOGE("OldUsageTable: Rollback detected. Clearing Usage Table. %lx -> %lx",
|
||||
generation_, stored_table->generation);
|
||||
table_.clear();
|
||||
generation_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, the stored table looks valid. We can load in all the
|
||||
// entries.
|
||||
for (uint64_t i = 0; i < stored_table->count; i++) {
|
||||
OldUsageTableEntry *entry =
|
||||
new OldUsageTableEntry(this, &stored_table->entries[i].entry);
|
||||
table_[entry->pst_hash()] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
OldUsageTableEntry *OldUsageTable::FindEntry(const std::vector<uint8_t> &pst) {
|
||||
std::unique_lock<std::mutex> lock(lock_);
|
||||
return FindEntryLocked(pst);
|
||||
}
|
||||
|
||||
OldUsageTableEntry *OldUsageTable::FindEntryLocked(
|
||||
const std::vector<uint8_t> &pst) {
|
||||
std::vector<uint8_t> pst_hash;
|
||||
if (!ComputeHash(pst, pst_hash)) {
|
||||
LOGE("OldUsageTable: Could not compute hash of pst.");
|
||||
return NULL;
|
||||
}
|
||||
EntryMap::iterator it = table_.find(pst_hash);
|
||||
if (it == table_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
OldUsageTableEntry *OldUsageTable::CreateEntry(
|
||||
const std::vector<uint8_t> &pst) {
|
||||
std::vector<uint8_t> pst_hash;
|
||||
if (!ComputeHash(pst, pst_hash)) {
|
||||
LOGE("OldUsageTable: Could not compute hash of pst.");
|
||||
return NULL;
|
||||
}
|
||||
OldUsageTableEntry *entry = new OldUsageTableEntry(this, pst_hash);
|
||||
std::unique_lock<std::mutex> lock(lock_);
|
||||
table_[pst_hash] = entry;
|
||||
return entry;
|
||||
}
|
||||
|
||||
void OldUsageTable::Clear() {
|
||||
std::unique_lock<std::mutex> lock(lock_);
|
||||
for (EntryMap::iterator i = table_.begin(); i != table_.end(); ++i) {
|
||||
if (i->second) delete i->second;
|
||||
}
|
||||
table_.clear();
|
||||
}
|
||||
|
||||
void OldUsageTable::DeleteFile(CryptoEngine *ce) {
|
||||
wvcdm::FileSystem *file_system = ce->file_system();
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
// TODO(jfore): Address how this property is presented to the ref. For now,
|
||||
// the path is empty.
|
||||
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3, &path)) {
|
||||
LOGE("OldUsageTable: Unable to get base path");
|
||||
return;
|
||||
}*/
|
||||
std::string filename = path + "UsageTable.dat";
|
||||
if (file_system->Exists(filename)) {
|
||||
if (!file_system->Remove(filename)) {
|
||||
LOGE("DeleteOldUsageTable: error removing file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OldUsageTable::ComputeHash(const std::vector<uint8_t> &pst,
|
||||
std::vector<uint8_t> &pst_hash) {
|
||||
// The PST is not fixed size, and we have no promises that it is reasonbly
|
||||
// sized, so we compute a hash of it, and store that instead.
|
||||
pst_hash.resize(SHA256_DIGEST_LENGTH);
|
||||
SHA256_CTX context;
|
||||
if (!SHA256_Init(&context)) return false;
|
||||
if (!SHA256_Update(&context, &pst[0], pst.size())) return false;
|
||||
if (!SHA256_Final(&pst_hash[0], &context)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wvoec_ref
|
||||
@@ -1,101 +0,0 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
//
|
||||
// Reference implementation of OEMCrypto APIs
|
||||
//
|
||||
// This is from the v12 version of oemcrypto usage tables. It is used for
|
||||
// devices that upgrade from v12 to v13 in the field, and need to convert from
|
||||
// the old type of usage table to the new.
|
||||
#ifndef OEMCRYPTO_OLD_USAGE_TABLE_REF_H_
|
||||
#define OEMCRYPTO_OLD_USAGE_TABLE_REF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oemcrypto_types.h"
|
||||
#include "openssl/sha.h"
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
class CryptoEngine;
|
||||
class OldUsageTable;
|
||||
class UsagetTableEntry;
|
||||
|
||||
struct OldStoredUsageEntry {
|
||||
// To save disk space, we only store a hash of the pst.
|
||||
uint8_t pst_hash[SHA256_DIGEST_LENGTH];
|
||||
int64_t time_of_license_received;
|
||||
int64_t time_of_first_decrypt;
|
||||
int64_t time_of_last_decrypt;
|
||||
enum OEMCrypto_Usage_Entry_Status status;
|
||||
uint8_t mac_key_server[wvoec::MAC_KEY_SIZE];
|
||||
uint8_t mac_key_client[wvoec::MAC_KEY_SIZE];
|
||||
};
|
||||
|
||||
typedef union {
|
||||
struct OldStoredUsageEntry entry;
|
||||
uint8_t padding[128]; // multiple of block size and bigger than entry size.
|
||||
} AlignedOldStoredUsageEntry;
|
||||
|
||||
struct OldStoredUsageTable {
|
||||
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||
uint8_t iv[wvoec::KEY_IV_SIZE];
|
||||
int64_t generation;
|
||||
uint64_t count;
|
||||
AlignedOldStoredUsageEntry entries[];
|
||||
};
|
||||
|
||||
class OldUsageTableEntry {
|
||||
public:
|
||||
OldUsageTableEntry(OldUsageTable *old_usage_table,
|
||||
const std::vector<uint8_t> &pst_hash);
|
||||
OldUsageTableEntry(OldUsageTable *old_usage_table,
|
||||
const OldStoredUsageEntry *buffer);
|
||||
~OldUsageTableEntry();
|
||||
const std::vector<uint8_t> &pst_hash() const { return pst_hash_; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> pst_hash_;
|
||||
const OldUsageTable *old_usage_table_;
|
||||
int64_t time_of_license_received_;
|
||||
int64_t time_of_first_decrypt_;
|
||||
int64_t time_of_last_decrypt_;
|
||||
enum OEMCrypto_Usage_Entry_Status status_;
|
||||
std::vector<uint8_t> mac_key_server_;
|
||||
std::vector<uint8_t> mac_key_client_;
|
||||
|
||||
friend class UsageTableEntry;
|
||||
friend class UsageTable;
|
||||
};
|
||||
|
||||
class OldUsageTable {
|
||||
public:
|
||||
OldUsageTable(CryptoEngine *ce);
|
||||
~OldUsageTable() { Clear(); }
|
||||
OldUsageTableEntry *FindEntry(const std::vector<uint8_t> &pst);
|
||||
OldUsageTableEntry *CreateEntry(const std::vector<uint8_t> &pst);
|
||||
void Clear();
|
||||
static void DeleteFile(CryptoEngine *ce);
|
||||
|
||||
private:
|
||||
OldUsageTableEntry *FindEntryLocked(const std::vector<uint8_t> &pst);
|
||||
bool ComputeHash(const std::vector<uint8_t> &pst,
|
||||
std::vector<uint8_t> &pst_hash);
|
||||
|
||||
typedef std::map<std::vector<uint8_t>, OldUsageTableEntry *> EntryMap;
|
||||
EntryMap table_;
|
||||
std::mutex lock_;
|
||||
int64_t generation_;
|
||||
CryptoEngine *ce_;
|
||||
|
||||
friend class OldUsageTableEntry;
|
||||
};
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
#endif // OEMCRYPTO_OLD_USAGE_TABLE_REF_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,50 +34,50 @@ void RSA_shared_ptr::reset() {
|
||||
RSA_free(rsa_key_);
|
||||
}
|
||||
key_owned_ = false;
|
||||
rsa_key_ = NULL;
|
||||
rsa_key_ = nullptr;
|
||||
}
|
||||
|
||||
bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
|
||||
assert(buffer != NULL);
|
||||
assert(buffer != nullptr);
|
||||
reset();
|
||||
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
|
||||
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
|
||||
if (bio == NULL) {
|
||||
if (bio == nullptr) {
|
||||
LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]");
|
||||
return false;
|
||||
}
|
||||
bool success = true;
|
||||
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
|
||||
if (pkcs8_pki == NULL) {
|
||||
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
|
||||
if (pkcs8_pki == nullptr) {
|
||||
BIO_reset(bio);
|
||||
pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
|
||||
if (pkcs8_pki == NULL) {
|
||||
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]");
|
||||
pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
|
||||
if (pkcs8_pki == nullptr) {
|
||||
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr]");
|
||||
dump_boringssl_error();
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
EVP_PKEY* evp = NULL;
|
||||
EVP_PKEY* evp = nullptr;
|
||||
if (success) {
|
||||
evp = EVP_PKCS82PKEY(pkcs8_pki);
|
||||
if (evp == NULL) {
|
||||
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]");
|
||||
if (evp == nullptr) {
|
||||
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned nullptr]");
|
||||
dump_boringssl_error();
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
rsa_key_ = EVP_PKEY_get1_RSA(evp);
|
||||
if (rsa_key_ == NULL) {
|
||||
if (rsa_key_ == nullptr) {
|
||||
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
|
||||
success = false;
|
||||
}
|
||||
key_owned_ = true;
|
||||
}
|
||||
if (evp != NULL) {
|
||||
if (evp != nullptr) {
|
||||
EVP_PKEY_free(evp);
|
||||
}
|
||||
if (pkcs8_pki != NULL) {
|
||||
if (pkcs8_pki != nullptr) {
|
||||
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
|
||||
}
|
||||
BIO_free(bio);
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace wvoec_ref {
|
||||
// counting.
|
||||
class RSA_shared_ptr {
|
||||
public:
|
||||
RSA_shared_ptr() : rsa_key_(NULL), key_owned_(false) {}
|
||||
RSA_shared_ptr() : rsa_key_(nullptr), key_owned_(false) {}
|
||||
~RSA_shared_ptr() { reset(); };
|
||||
// Explicitly allow copy as share.
|
||||
explicit RSA_shared_ptr(const RSA_shared_ptr& other) :
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,9 +15,9 @@
|
||||
#include <openssl/rsa.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "odk_structs.h"
|
||||
#include "oemcrypto_auth_ref.h"
|
||||
#include "oemcrypto_key_ref.h"
|
||||
#include "oemcrypto_nonce_table.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "oemcrypto_session_key_table.h"
|
||||
#include "oemcrypto_types.h"
|
||||
@@ -37,6 +37,7 @@ class SessionContextKeys {
|
||||
virtual size_t size() = 0;
|
||||
virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0;
|
||||
virtual Key* Find(const KeyId& key_id) = 0;
|
||||
virtual Key* FirstKey() = 0;
|
||||
virtual void Remove(const KeyId& key_id) = 0;
|
||||
virtual void UpdateDuration(const KeyControlBlock& control) = 0;
|
||||
|
||||
@@ -58,25 +59,11 @@ class SessionContextKeys {
|
||||
};
|
||||
|
||||
class SessionContext {
|
||||
private:
|
||||
SessionContext() {}
|
||||
|
||||
public:
|
||||
SessionContext(CryptoEngine* ce, SessionId sid, const RSA_shared_ptr& rsa_key)
|
||||
: valid_(true),
|
||||
ce_(ce),
|
||||
id_(sid),
|
||||
current_content_key_(NULL),
|
||||
session_keys_(NULL),
|
||||
rsa_key_(rsa_key),
|
||||
allowed_schemes_(kSign_RSASSA_PSS),
|
||||
usage_entry_(NULL),
|
||||
srm_requirements_status_(NoSRMVersion),
|
||||
usage_entry_status_(kNoUsageEntry),
|
||||
compute_hash_(false),
|
||||
current_hash_(0),
|
||||
bad_frame_number_(0),
|
||||
hash_error_(OEMCrypto_SUCCESS) {}
|
||||
SessionContext(CryptoEngine* ce, SessionId sid,
|
||||
const RSA_shared_ptr& rsa_key);
|
||||
SessionContext() = delete;
|
||||
virtual ~SessionContext();
|
||||
|
||||
bool isValid() { return valid_; }
|
||||
@@ -87,8 +74,21 @@ class SessionContext {
|
||||
virtual bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
|
||||
const std::vector<uint8_t>& mac_context,
|
||||
const std::vector<uint8_t>& enc_context);
|
||||
virtual bool GenerateSignature(const uint8_t* message, size_t message_length,
|
||||
uint8_t* signature, size_t* signature_length);
|
||||
virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t* core_message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
virtual OEMCryptoResult PrepAndSignRenewalRequest(uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t* core_message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
virtual OEMCryptoResult PrepAndSignProvisioningRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_length,
|
||||
uint8_t* signature, size_t* signature_length);
|
||||
// The size of an RSA signature. This is used when signing as a CAST
|
||||
// receiver.
|
||||
size_t RSASignatureSize();
|
||||
virtual OEMCryptoResult GenerateRSASignature(
|
||||
const uint8_t* message, size_t message_length, uint8_t* signature,
|
||||
@@ -96,13 +96,9 @@ class SessionContext {
|
||||
virtual bool ValidateMessage(const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
OEMCryptoResult DecryptCENC(const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted,
|
||||
uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type,
|
||||
uint8_t subsample_flags);
|
||||
OEMCryptoResult DecryptSamples(
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
|
||||
size_t buffer_length, const uint8_t* iv,
|
||||
@@ -119,8 +115,11 @@ class SessionContext {
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
void StartTimer();
|
||||
uint32_t CurrentTimer(); // (seconds).
|
||||
virtual OEMCryptoResult LoadLicense(const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
virtual OEMCryptoResult LoadKeys(
|
||||
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
||||
size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv,
|
||||
@@ -128,8 +127,14 @@ class SessionContext {
|
||||
const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst,
|
||||
OEMCrypto_Substring srm_restriction_data,
|
||||
OEMCrypto_LicenseType license_type);
|
||||
virtual OEMCryptoResult LoadKeysNoSignature(
|
||||
const uint8_t* message, size_t message_length,
|
||||
OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
|
||||
size_t num_keys, const OEMCrypto_KeyObject* key_array,
|
||||
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
|
||||
OEMCrypto_LicenseType license_type);
|
||||
virtual OEMCryptoResult LoadEntitledContentKeys(
|
||||
const uint8_t* message, size_t message_length, size_t num_keys,
|
||||
const uint8_t* message, size_t message_length, size_t key_array_length,
|
||||
const OEMCrypto_EntitledContentKeyObject* key_array);
|
||||
virtual OEMCryptoResult InstallKey(
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_data,
|
||||
@@ -143,6 +148,11 @@ class SessionContext {
|
||||
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
|
||||
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
|
||||
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
|
||||
virtual OEMCryptoResult LoadRenewal(const uint8_t* message,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length);
|
||||
virtual OEMCryptoResult RefreshKey(
|
||||
const KeyId& key_id, const std::vector<uint8_t>& key_control,
|
||||
const std::vector<uint8_t>& key_control_iv);
|
||||
@@ -171,13 +181,14 @@ class SessionContext {
|
||||
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
|
||||
uint32_t allowed_schemes() const { return allowed_schemes_; }
|
||||
|
||||
void AddNonce(uint32_t nonce);
|
||||
bool CheckNonce(uint32_t nonce);
|
||||
// Verify that the nonce does not match any in this session's nonce table.
|
||||
bool NonceCollision(uint32_t nonce) const {
|
||||
return nonce_table_.NonceCollision(nonce);
|
||||
}
|
||||
void FlushNonces();
|
||||
// Return true if nonce was set.
|
||||
bool set_nonce(uint32_t nonce);
|
||||
uint32_t nonce() const { return nonce_values_.nonce; }
|
||||
ODK_NonceValues& nonce_values() { return nonce_values_; }
|
||||
|
||||
bool CheckNonce(uint32_t nonce) const {
|
||||
return nonce != 0 && nonce == nonce_values_.nonce;
|
||||
};
|
||||
|
||||
virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
|
||||
virtual OEMCryptoResult LoadUsageEntry(uint32_t index,
|
||||
@@ -190,9 +201,21 @@ class SessionContext {
|
||||
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
|
||||
uint8_t* buffer, size_t* buffer_length);
|
||||
OEMCryptoResult MoveEntry(uint32_t new_index);
|
||||
OEMCryptoResult CopyOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||
bool usage_entry_present() const { return usage_entry_ != nullptr; }
|
||||
|
||||
protected:
|
||||
// Signature size of the currently loaded private key.
|
||||
size_t CertSignatureSize();
|
||||
// Signature size when using a keybox or OEM Cert's private key.
|
||||
size_t ROTSignatureSize();
|
||||
virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
virtual OEMCryptoResult GenerateSignature(const uint8_t* message,
|
||||
size_t message_length,
|
||||
uint8_t* signature,
|
||||
size_t* signature_length);
|
||||
bool DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context, int counter,
|
||||
std::vector<uint8_t>* out);
|
||||
@@ -211,18 +234,19 @@ class SessionContext {
|
||||
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
|
||||
// Check that the usage entry status is valid for offline use.
|
||||
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
|
||||
|
||||
OEMCryptoResult DecryptSubsample(
|
||||
const OEMCrypto_SubSampleDescription& subsample,
|
||||
const uint8_t* cipher_data, uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE],
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, bool is_encrypted,
|
||||
uint8_t* clear_data,
|
||||
size_t cipher_data_length, uint8_t* clear_data,
|
||||
OEMCryptoBufferType buffer_type);
|
||||
OEMCryptoResult DecryptCBC(const uint8_t* key, const uint8_t* iv,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data,
|
||||
size_t cipher_data_length, uint8_t* clear_data);
|
||||
OEMCryptoResult PatternDecryptCTR(
|
||||
const uint8_t* key, const uint8_t* iv, size_t block_offset,
|
||||
OEMCryptoResult PatternDecryptCBC(
|
||||
const uint8_t* key, const uint8_t* iv,
|
||||
const OEMCrypto_CENCEncryptPatternDesc* pattern,
|
||||
const uint8_t* cipher_data, size_t cipher_data_length,
|
||||
uint8_t* clear_data);
|
||||
@@ -244,10 +268,13 @@ class SessionContext {
|
||||
std::vector<uint8_t> session_key_;
|
||||
const Key* current_content_key_;
|
||||
SessionContextKeys* session_keys_;
|
||||
NonceTable nonce_table_;
|
||||
ODK_NonceValues nonce_values_;
|
||||
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
|
||||
RSA_shared_ptr rsa_key_;
|
||||
uint32_t allowed_schemes_; // for RSA signatures.
|
||||
time_t timer_start_;
|
||||
bool decrypt_started_; // If the license has been used in this session.
|
||||
ODK_TimerLimits timer_limits_;
|
||||
ODK_ClockValues clock_values_;
|
||||
UsageTableEntry* usage_entry_;
|
||||
SRMVersionStatus srm_requirements_status_;
|
||||
enum UsageEntryStatus {
|
||||
@@ -265,6 +292,12 @@ class SessionContext {
|
||||
uint32_t bad_frame_number_; // Frame number with bad hash.
|
||||
OEMCryptoResult hash_error_; // Error code for first bad frame.
|
||||
|
||||
// The bare minimum state machine is to only call each of these function
|
||||
// categories at most once.
|
||||
bool state_nonce_created_;
|
||||
bool state_request_signed_;
|
||||
bool state_response_loaded_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace wvoec_ref {
|
||||
|
||||
SessionKeyTable::~SessionKeyTable() {
|
||||
for (KeyMap::iterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
if (NULL != i->second) {
|
||||
if (nullptr != i->second) {
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) {
|
||||
|
||||
Key* SessionKeyTable::Find(const KeyId key_id) {
|
||||
if (keys_.find(key_id) == keys_.end()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return keys_[key_id];
|
||||
}
|
||||
@@ -59,11 +59,11 @@ Key* EntitlementKeyTable::Find(const KeyId key_id) {
|
||||
ContentIdToEntitlementIdMap::iterator it =
|
||||
contentid_to_entitlementid_.find(key_id);
|
||||
if (it == contentid_to_entitlementid_.end()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (keys_.find(it->second) == keys_.end()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return keys_[it->second];
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ class SessionKeyTable {
|
||||
|
||||
bool Insert(const KeyId key_id, const Key& key_data);
|
||||
Key* Find(const KeyId key_id);
|
||||
Key* FirstKey() { return keys_.begin()->second; }
|
||||
void Remove(const KeyId key_id);
|
||||
void UpdateDuration(const KeyControlBlock& control);
|
||||
size_t size() const { return keys_.size(); }
|
||||
@@ -52,6 +53,7 @@ class EntitlementKeyTable {
|
||||
~EntitlementKeyTable() {}
|
||||
bool Insert(const KeyId key_id, const Key& key_data);
|
||||
Key* Find(const KeyId key_id);
|
||||
Key* FirstKey() { return keys_.begin()->second; }
|
||||
void Remove(const KeyId key_id);
|
||||
void UpdateDuration(const KeyControlBlock& control);
|
||||
size_t size() const { return contentid_to_entitlementid_.size(); }
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
#include "odk.h"
|
||||
#include "oemcrypto_engine_ref.h"
|
||||
#include "oemcrypto_old_usage_table_ref.h"
|
||||
// TODO(fredgc): Setting the device files base bath is currently broken as
|
||||
// wvcdm::Properties is no longer used by the reference code.
|
||||
//#include "properties.h"
|
||||
@@ -71,8 +71,7 @@ OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) {
|
||||
data_.pst_length = pst_length;
|
||||
if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
memcpy(data_.pst, pst, pst_length);
|
||||
data_.time_of_license_received =
|
||||
usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
data_.time_of_license_received = usage_table_->ce_->SystemTime();
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -101,25 +100,7 @@ bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UsageTableEntry::CheckForUse() {
|
||||
if (Inactive()) return false;
|
||||
recent_decrypt_ = true;
|
||||
if (data_.status == kUnused) {
|
||||
data_.status = kActive;
|
||||
data_.time_of_first_decrypt =
|
||||
usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void UsageTableEntry::Deactivate(const std::vector<uint8_t>& pst) {
|
||||
if (data_.status == kUnused) {
|
||||
data_.status = kInactiveUnused;
|
||||
} else if (data_.status == kActive) {
|
||||
data_.status = kInactiveUsed;
|
||||
}
|
||||
void UsageTableEntry::ForbidReport() {
|
||||
forbid_report_ = true;
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
@@ -151,7 +132,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
wvcdm::Unpacked_PST_Report pst_report(buffer);
|
||||
int64_t now = usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
int64_t now = usage_table_->ce_->SystemTime();
|
||||
pst_report.set_seconds_since_license_received(now -
|
||||
data_.time_of_license_received);
|
||||
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
|
||||
@@ -170,12 +151,29 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
void UsageTableEntry::UpdateAndIncrement() {
|
||||
void UsageTableEntry::UpdateAndIncrement(ODK_ClockValues* clock_values) {
|
||||
if (recent_decrypt_) {
|
||||
data_.time_of_last_decrypt =
|
||||
usage_table_->ce_->RollbackCorrectedOfflineTime();
|
||||
data_.time_of_last_decrypt = usage_table_->ce_->SystemTime();
|
||||
recent_decrypt_ = false;
|
||||
}
|
||||
data_.time_of_license_received = clock_values->time_of_license_signed;
|
||||
data_.time_of_first_decrypt = clock_values->time_of_first_decrypt;
|
||||
// Use the most recent time_of_last_decrypt.
|
||||
if (static_cast<uint64_t>(data_.time_of_last_decrypt) <
|
||||
clock_values->time_of_last_decrypt) {
|
||||
// For the reference implementation, we update the clock_values on every
|
||||
// decrypt.
|
||||
data_.time_of_last_decrypt = clock_values->time_of_last_decrypt;
|
||||
} else {
|
||||
// For this reference implementation of OEMCrypto, we regularly update
|
||||
// clock_values->time_of_last_decrypt and we could just update
|
||||
// data_.time_of_last_decrypt here. However, I'm including the line below to
|
||||
// make it clear that you could do it the other way around. When this
|
||||
// function is called, the two values should be synced so that the usage
|
||||
// entry can be saved with the correct value.
|
||||
clock_values->time_of_last_decrypt = data_.time_of_last_decrypt;
|
||||
}
|
||||
data_.status = clock_values->status;
|
||||
data_.generation_number++;
|
||||
usage_table_->IncrementGeneration();
|
||||
forbid_report_ = false;
|
||||
@@ -194,7 +192,7 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
|
||||
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
|
||||
SignedEntryBlock* encrypted =
|
||||
reinterpret_cast<SignedEntryBlock*>(signed_buffer);
|
||||
clear->data = this->data_; // Copy the current data.
|
||||
clear->data = data_; // Copy the current data.
|
||||
memcpy(clear->verification, kEntryVerification, kMagicLength);
|
||||
|
||||
// This should be encrypted and signed with a device specific key.
|
||||
@@ -228,7 +226,8 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values) {
|
||||
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
if (buffer.size() > SignedEntrySize())
|
||||
LOGW("LoadUsageTableEntry: buffer is large. %d > %d", buffer.size(),
|
||||
@@ -295,39 +294,10 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||
LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status);
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
this->data_ = clear->data;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTableEntry::CopyOldUsageEntry(
|
||||
const std::vector<uint8_t>& pst) {
|
||||
OldUsageTableEntry* old_entry = usage_table_->FindOldUsageEntry(pst);
|
||||
if (!old_entry) return OEMCrypto_ERROR_WRONG_PST;
|
||||
data_.time_of_license_received = old_entry->time_of_license_received_;
|
||||
data_.time_of_first_decrypt = old_entry->time_of_first_decrypt_;
|
||||
data_.time_of_last_decrypt = old_entry->time_of_last_decrypt_;
|
||||
data_.status = old_entry->status_;
|
||||
if (old_entry->mac_key_server_.size() != wvoec::MAC_KEY_SIZE) {
|
||||
LOGE("CopyOldEntry: Old entry has bad server mac key.");
|
||||
} else {
|
||||
memcpy(data_.mac_key_server, &(old_entry->mac_key_server_[0]),
|
||||
wvoec::MAC_KEY_SIZE);
|
||||
}
|
||||
if (old_entry->mac_key_client_.size() != wvoec::MAC_KEY_SIZE) {
|
||||
LOGE("CopyOldEntry: Old entry has bad client mac key.");
|
||||
} else {
|
||||
memcpy(data_.mac_key_client, &(old_entry->mac_key_client_[0]),
|
||||
wvoec::MAC_KEY_SIZE);
|
||||
}
|
||||
if (pst.size() > kMaxPSTLength) {
|
||||
LOGE("CopyOldEntry: PST Length was too large. Truncating.");
|
||||
data_.pst_length = kMaxPSTLength;
|
||||
} else {
|
||||
data_.pst_length = pst.size();
|
||||
}
|
||||
memcpy(data_.pst, pst.data(), data_.pst_length);
|
||||
data_.pst[data_.pst_length] = '\0';
|
||||
return OEMCrypto_SUCCESS;
|
||||
data_ = clear->data;
|
||||
return ODK_ReloadClockValues(
|
||||
clock_values, data_.time_of_license_received, data_.time_of_first_decrypt,
|
||||
data_.time_of_last_decrypt, data_.status, ce->SystemTime());
|
||||
}
|
||||
|
||||
size_t UsageTableEntry::SignedEntrySize() {
|
||||
@@ -337,12 +307,7 @@ size_t UsageTableEntry::SignedEntrySize() {
|
||||
return blocks * wvoec::KEY_IV_SIZE;
|
||||
}
|
||||
|
||||
UsageTable::~UsageTable() {
|
||||
if (old_table_) {
|
||||
delete old_table_;
|
||||
old_table_ = NULL;
|
||||
}
|
||||
}
|
||||
UsageTable::~UsageTable() {}
|
||||
|
||||
size_t UsageTable::SignedHeaderSize(size_t count) {
|
||||
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
|
||||
@@ -351,12 +316,10 @@ size_t UsageTable::SignedHeaderSize(size_t count) {
|
||||
return blocks * wvoec::KEY_IV_SIZE;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
||||
UsageTableEntry* entry,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length) {
|
||||
OEMCryptoResult UsageTable::UpdateUsageEntry(
|
||||
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
|
||||
size_t* header_buffer_length, uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length, ODK_ClockValues* clock_values) {
|
||||
size_t signed_header_size = SignedHeaderSize(generation_numbers_.size());
|
||||
if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() ||
|
||||
*header_buffer_length < signed_header_size) {
|
||||
@@ -368,7 +331,7 @@ OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
||||
*header_buffer_length = signed_header_size;
|
||||
if ((!header_buffer) || (!entry_buffer))
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
entry->UpdateAndIncrement();
|
||||
entry->UpdateAndIncrement(clock_values);
|
||||
generation_numbers_[entry->index()] = entry->generation_number();
|
||||
OEMCryptoResult result =
|
||||
entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length);
|
||||
@@ -408,7 +371,8 @@ OEMCryptoResult UsageTable::CreateNewUsageEntry(SessionContext* session,
|
||||
OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry,
|
||||
uint32_t index,
|
||||
const std::vector<uint8_t>& buffer) {
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values) {
|
||||
if (!header_loaded_) {
|
||||
LOGE("CreateNewUsageEntry: Header not loaded.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
@@ -427,7 +391,8 @@ OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
||||
}
|
||||
UsageTableEntry* new_entry = MakeEntry(index);
|
||||
|
||||
OEMCryptoResult status = new_entry->LoadData(ce_, index, buffer);
|
||||
OEMCryptoResult status =
|
||||
new_entry->LoadData(ce_, index, buffer, clock_values);
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
delete new_entry;
|
||||
return status;
|
||||
@@ -722,7 +687,7 @@ OEMCryptoResult UsageTable::CreateUsageTableHeader(
|
||||
if (!LoadGenerationNumber(true)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
// Make sure there are no entries that are currently tied to an open session.
|
||||
for (size_t i = 0; i < sessions_.size(); ++i) {
|
||||
if (sessions_[i] != NULL) {
|
||||
if (sessions_[i] != nullptr) {
|
||||
LOGE("CreateUsageTableHeader: index %d used by session.", i);
|
||||
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
}
|
||||
@@ -733,41 +698,4 @@ OEMCryptoResult UsageTable::CreateUsageTableHeader(
|
||||
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||
}
|
||||
|
||||
OldUsageTableEntry* UsageTable::FindOldUsageEntry(
|
||||
const std::vector<uint8_t>& pst) {
|
||||
if (!old_table_) old_table_ = new OldUsageTable(ce_);
|
||||
return old_table_->FindEntry(pst);
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::DeleteOldUsageTable() {
|
||||
if (old_table_) {
|
||||
old_table_->Clear();
|
||||
delete old_table_;
|
||||
old_table_ = NULL;
|
||||
}
|
||||
OldUsageTable::DeleteFile(ce_);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
OEMCryptoResult UsageTable::CreateOldUsageEntry(
|
||||
uint64_t time_since_license_received, uint64_t time_since_first_decrypt,
|
||||
uint64_t time_since_last_decrypt, OEMCrypto_Usage_Entry_Status status,
|
||||
uint8_t* server_mac_key, uint8_t* client_mac_key, const uint8_t* pst,
|
||||
size_t pst_length) {
|
||||
if (!old_table_) old_table_ = new OldUsageTable(ce_);
|
||||
std::vector<uint8_t> pstv(pst, pst + pst_length);
|
||||
OldUsageTableEntry* old_entry = old_table_->CreateEntry(pstv);
|
||||
|
||||
int64_t now = ce_->RollbackCorrectedOfflineTime();
|
||||
old_entry->time_of_license_received_ = now - time_since_license_received;
|
||||
old_entry->time_of_first_decrypt_ = now - time_since_first_decrypt;
|
||||
old_entry->time_of_last_decrypt_ = now - time_since_last_decrypt;
|
||||
old_entry->status_ = status;
|
||||
old_entry->mac_key_server_.assign(server_mac_key,
|
||||
server_mac_key + wvoec::MAC_KEY_SIZE);
|
||||
old_entry->mac_key_client_.assign(client_mac_key,
|
||||
client_mac_key + wvoec::MAC_KEY_SIZE);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
@@ -13,16 +13,15 @@
|
||||
#include <vector>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "odk_structs.h"
|
||||
#include "oemcrypto_types.h"
|
||||
#include "openssl/sha.h"
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
class SessionContext;
|
||||
class CryptoEngine;
|
||||
class UsageTable;
|
||||
class OldUsageTable;
|
||||
class OldUsageTableEntry;
|
||||
|
||||
const size_t kMaxPSTLength = 255;
|
||||
// This is the data we store offline.
|
||||
@@ -44,29 +43,34 @@ class UsageTableEntry {
|
||||
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
|
||||
virtual ~UsageTableEntry(); // Free memory, remove reference in header.
|
||||
bool Inactive() { return data_.status >= kInactive; }
|
||||
// Mark this entry as modified and forbid a usage report until the data has
|
||||
// been saved. This is done on important events like first decrypt and
|
||||
// deactivation.
|
||||
void ForbidReport();
|
||||
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
|
||||
bool VerifyPST(const uint8_t* pst, size_t pst_length);
|
||||
bool VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client);
|
||||
bool SetMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client);
|
||||
// Returns false if the entry is inactive. Otherwise, returns true.
|
||||
// If the status was unused, it is updated, and decrypt times are flaged
|
||||
// for update.
|
||||
bool CheckForUse();
|
||||
void Deactivate(const std::vector<uint8_t>& pst);
|
||||
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
|
||||
uint8_t* buffer, size_t* buffer_length);
|
||||
virtual void UpdateAndIncrement();
|
||||
virtual void UpdateAndIncrement(ODK_ClockValues* clock_values);
|
||||
// Save all data to the give buffer. This should be called after updating the
|
||||
// data.
|
||||
OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session,
|
||||
uint8_t* signed_buffer, size_t buffer_size);
|
||||
// Load all data from the buffer, and then update clock_values.
|
||||
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
virtual OEMCryptoResult CopyOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values);
|
||||
int64_t generation_number() { return data_.generation_number; }
|
||||
void set_generation_number(int64_t value) { data_.generation_number = value; }
|
||||
void set_index(int32_t index) { data_.index = index; }
|
||||
uint32_t index() { return data_.index; }
|
||||
void set_recent_decrypt(bool recent_decrypt) {
|
||||
recent_decrypt_ = recent_decrypt;
|
||||
}
|
||||
static size_t SignedEntrySize();
|
||||
const uint8_t* mac_key_server() { return data_.mac_key_server; }
|
||||
const uint8_t* mac_key_client() { return data_.mac_key_client; }
|
||||
@@ -80,8 +84,7 @@ class UsageTableEntry {
|
||||
|
||||
class UsageTable {
|
||||
public:
|
||||
explicit UsageTable(CryptoEngine* ce)
|
||||
: ce_(ce), header_loaded_(false), old_table_(NULL) {};
|
||||
explicit UsageTable(CryptoEngine* ce) : ce_(ce), header_loaded_(false){};
|
||||
virtual ~UsageTable();
|
||||
|
||||
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
|
||||
@@ -89,13 +92,12 @@ class UsageTable {
|
||||
uint32_t* usage_entry_number);
|
||||
OEMCryptoResult LoadUsageEntry(SessionContext* session,
|
||||
UsageTableEntry** entry, uint32_t index,
|
||||
const std::vector<uint8_t>& buffer);
|
||||
OEMCryptoResult UpdateUsageEntry(SessionContext* session,
|
||||
UsageTableEntry* entry,
|
||||
uint8_t* header_buffer,
|
||||
size_t* header_buffer_length,
|
||||
uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length);
|
||||
const std::vector<uint8_t>& buffer,
|
||||
ODK_ClockValues* clock_values);
|
||||
OEMCryptoResult UpdateUsageEntry(
|
||||
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
|
||||
size_t* header_buffer_length, uint8_t* entry_buffer,
|
||||
size_t* entry_buffer_length, ODK_ClockValues* clock_values);
|
||||
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
|
||||
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
|
||||
size_t* header_buffer_length);
|
||||
@@ -106,15 +108,6 @@ class UsageTable {
|
||||
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
|
||||
void IncrementGeneration();
|
||||
static size_t SignedHeaderSize(size_t count);
|
||||
OldUsageTableEntry* FindOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||
OEMCryptoResult DeleteOldUsageTable();
|
||||
OEMCryptoResult CreateOldUsageEntry(uint64_t time_since_license_received,
|
||||
uint64_t time_since_first_decrypt,
|
||||
uint64_t time_since_last_decrypt,
|
||||
OEMCrypto_Usage_Entry_Status status,
|
||||
uint8_t* server_mac_key,
|
||||
uint8_t* client_mac_key,
|
||||
const uint8_t* pst, size_t pst_length);
|
||||
|
||||
protected:
|
||||
virtual UsageTableEntry* MakeEntry(uint32_t index);
|
||||
@@ -128,7 +121,6 @@ class UsageTable {
|
||||
int64_t master_generation_number_;
|
||||
std::vector<int64_t> generation_numbers_;
|
||||
std::vector<SessionContext*> sessions_;
|
||||
OldUsageTable* old_table_;
|
||||
|
||||
friend class UsageTableEntry;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user