OEMCrypto Backwards Compatible Usage Table
Merge from widevine of http://go/wvgerrit/23283 This CL adds the backwards compatiblity functions to the new usage tables in the oemcrypto mock reference code. b/31458046 b/32554171 Change-Id: I04901d95aceb8910406f7c514c26c29c2c575322
This commit is contained in:
@@ -48,7 +48,11 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(SecurityLevel level,
|
|||||||
uint32_t new_table_size,
|
uint32_t new_table_size,
|
||||||
uint8_t* header_buffer,
|
uint8_t* header_buffer,
|
||||||
size_t* header_buffer_length);
|
size_t* header_buffer_length);
|
||||||
|
OEMCryptoResult OEMCrypto_CreateOldUsageEntry(SecurityLevel level,
|
||||||
|
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);
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|
||||||
#endif // WVCDM_CORE_OEMCRYPTO_ADAPTER_H_
|
#endif // WVCDM_CORE_OEMCRYPTO_ADAPTER_H_
|
||||||
|
|||||||
@@ -240,6 +240,11 @@ typedef OEMCryptoResult (*L1_MoveEntry_t)(OEMCrypto_SESSION session,
|
|||||||
typedef OEMCryptoResult (*L1_CopyOldUsageEntry_t)(OEMCrypto_SESSION session,
|
typedef OEMCryptoResult (*L1_CopyOldUsageEntry_t)(OEMCrypto_SESSION session,
|
||||||
const uint8_t*pst,
|
const uint8_t*pst,
|
||||||
size_t pst_length);
|
size_t pst_length);
|
||||||
|
typedef OEMCryptoResult (*L1_CreateOldUsageEntry_t)(
|
||||||
|
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);
|
||||||
|
|
||||||
struct FunctionPointers {
|
struct FunctionPointers {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
@@ -303,6 +308,7 @@ struct FunctionPointers {
|
|||||||
L1_ShrinkUsageTableHeader_t ShrinkUsageTableHeader;
|
L1_ShrinkUsageTableHeader_t ShrinkUsageTableHeader;
|
||||||
L1_MoveEntry_t MoveEntry;
|
L1_MoveEntry_t MoveEntry;
|
||||||
L1_CopyOldUsageEntry_t CopyOldUsageEntry;
|
L1_CopyOldUsageEntry_t CopyOldUsageEntry;
|
||||||
|
L1_CreateOldUsageEntry_t CreateOldUsageEntry;
|
||||||
|
|
||||||
L1_LoadKeys_V8_t LoadKeys_V8;
|
L1_LoadKeys_V8_t LoadKeys_V8;
|
||||||
L1_GenerateRSASignature_V8_t GenerateRSASignature_V8;
|
L1_GenerateRSASignature_V8_t GenerateRSASignature_V8;
|
||||||
@@ -539,6 +545,7 @@ class Adapter {
|
|||||||
LOOKUP(ShrinkUsageTableHeader, OEMCrypto_ShrinkUsageTableHeader);
|
LOOKUP(ShrinkUsageTableHeader, OEMCrypto_ShrinkUsageTableHeader);
|
||||||
LOOKUP(MoveEntry, OEMCrypto_MoveEntry);
|
LOOKUP(MoveEntry, OEMCrypto_MoveEntry);
|
||||||
LOOKUP(CopyOldUsageEntry, OEMCrypto_CopyOldUsageEntry);
|
LOOKUP(CopyOldUsageEntry, OEMCrypto_CopyOldUsageEntry);
|
||||||
|
LOOKUP(CreateOldUsageEntry, OEMCrypto_CreateOldUsageEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -658,6 +665,8 @@ class Adapter {
|
|||||||
level3_.ShrinkUsageTableHeader = Level3_ShrinkUsageTableHeader;
|
level3_.ShrinkUsageTableHeader = Level3_ShrinkUsageTableHeader;
|
||||||
level3_.MoveEntry = Level3_MoveEntry;
|
level3_.MoveEntry = Level3_MoveEntry;
|
||||||
level3_.CopyOldUsageEntry = Level3_CopyOldUsageEntry;
|
level3_.CopyOldUsageEntry = Level3_CopyOldUsageEntry;
|
||||||
|
// TODO(fredgc): add stub.
|
||||||
|
// level3_.CreateOldUsageEntry = Level3_CreateOldUsageEntry;
|
||||||
|
|
||||||
level3_.version = Level3_APIVersion();
|
level3_.version = Level3_APIVersion();
|
||||||
}
|
}
|
||||||
@@ -926,10 +935,26 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(SecurityLevel level,
|
|||||||
const FunctionPointers* fcn = kAdapter->get(level);
|
const FunctionPointers* fcn = kAdapter->get(level);
|
||||||
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
if (fcn->version < 13) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
if (fcn->version < 13) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
if (!fcn->ShrinkUsageTableHeader) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
return fcn->ShrinkUsageTableHeader(new_table_size, header_buffer,
|
return fcn->ShrinkUsageTableHeader(new_table_size, header_buffer,
|
||||||
header_buffer_length);
|
header_buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
||||||
|
SecurityLevel level, 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 (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
const FunctionPointers* fcn = kAdapter->get(level);
|
||||||
|
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
|
if (fcn->version < 13) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
if (!fcn->CreateOldUsageEntry) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
return fcn->CreateOldUsageEntry(
|
||||||
|
time_since_license_received, time_since_first_decrypt,
|
||||||
|
time_since_last_decrypt, status, server_mac_key, client_mac_key, pst,
|
||||||
|
pst_length);
|
||||||
|
}
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
||||||
@@ -996,6 +1021,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
|
|||||||
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
|
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
|
||||||
const OEMCrypto_KeyObject* key_array, const uint8_t* pst,
|
const OEMCrypto_KeyObject* key_array, const uint8_t* pst,
|
||||||
size_t pst_length, const uint8_t* srm_requirement) {
|
size_t pst_length, const uint8_t* srm_requirement) {
|
||||||
|
|
||||||
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
LevelSession pair = kAdapter->get(session);
|
LevelSession pair = kAdapter->get(session);
|
||||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
@@ -1465,6 +1491,7 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(
|
|||||||
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
||||||
size_t signature_length) {
|
size_t signature_length) {
|
||||||
LOGE("TODO(fredgc): remove DeleteUsageEntry.");
|
LOGE("TODO(fredgc): remove DeleteUsageEntry.");
|
||||||
|
|
||||||
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
LevelSession pair = kAdapter->get(session);
|
LevelSession pair = kAdapter->get(session);
|
||||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
@@ -1480,6 +1507,7 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(
|
|||||||
extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(
|
extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(
|
||||||
const uint8_t* pst, size_t pst_length) {
|
const uint8_t* pst, size_t pst_length) {
|
||||||
LOGE("TODO(fredgc): remove ForceDeleteUsageEntry.");
|
LOGE("TODO(fredgc): remove ForceDeleteUsageEntry.");
|
||||||
|
|
||||||
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
|
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
|
||||||
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
|
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
|
||||||
@@ -1497,6 +1525,7 @@ extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_DeleteOldUsageTable() {
|
extern "C" OEMCryptoResult OEMCrypto_DeleteOldUsageTable() {
|
||||||
|
|
||||||
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
|
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
|
||||||
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
|
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
|
||||||
@@ -1626,15 +1655,13 @@ OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session,
|
|||||||
return pair.fcn->CopyOldUsageEntry(pair.session, pst, pst_length);
|
return pair.fcn->CopyOldUsageEntry(pair.session, pst, pst_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C" OEMCryptoResult OEMCrypto_CreateOldUsageEntry(
|
||||||
OEMCryptoResult Level3_CreateOldUsageEntry(uint64_t time_since_license_received,
|
uint64_t time_since_license_received, uint64_t time_since_first_decrypt,
|
||||||
uint64_t time_since_first_decrypt,
|
uint64_t time_since_last_decrypt, OEMCrypto_Usage_Entry_Status status,
|
||||||
uint64_t time_since_last_decrypt,
|
uint8_t* server_mac_key, uint8_t* client_mac_key, const uint8_t* pst,
|
||||||
OEMCrypto_Usage_Entry_Status status,
|
size_t pst_length) {
|
||||||
uint8_t *server_mac_key,
|
return OEMCrypto_CreateOldUsageEntry(
|
||||||
uint8_t *client_mac_key,
|
kLevelDefault, time_since_license_received, time_since_first_decrypt,
|
||||||
const uint8_t* pst,
|
time_since_last_decrypt, status, server_mac_key, client_mac_key, pst,
|
||||||
size_t pst_length) {
|
pst_length);
|
||||||
// TODO(fredgc): add this.
|
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,8 +251,8 @@ OEMCryptoResult Level3_SetDecryptHash(OEMCrypto_SESSION session,
|
|||||||
size_t hash_length);
|
size_t hash_length);
|
||||||
OEMCryptoResult Level3_VerifyDecryptHash(OEMCrypto_SESSION session,
|
OEMCryptoResult Level3_VerifyDecryptHash(OEMCrypto_SESSION session,
|
||||||
uint64_t* failure_data);
|
uint64_t* failure_data);
|
||||||
// TODO(fredgc): add stub for level3.
|
OEMCryptoResult Level3_CreateUsageTableHeader(uint8_t* header_buffer,
|
||||||
OEMCryptoResult Level3_CreateUsageTableHeader();
|
size_t* header_buffer_length);
|
||||||
OEMCryptoResult Level3_LoadUsageTableHeader(const uint8_t* buffer,
|
OEMCryptoResult Level3_LoadUsageTableHeader(const uint8_t* buffer,
|
||||||
size_t buffer_length);
|
size_t buffer_length);
|
||||||
OEMCryptoResult Level3_CreateNewUsageEntry(OEMCrypto_SESSION session,
|
OEMCryptoResult Level3_CreateNewUsageEntry(OEMCrypto_SESSION session,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ LOCAL_SRC_FILES:= \
|
|||||||
src/oemcrypto_logging.cpp \
|
src/oemcrypto_logging.cpp \
|
||||||
src/oemcrypto_mock.cpp \
|
src/oemcrypto_mock.cpp \
|
||||||
src/oemcrypto_nonce_table.cpp \
|
src/oemcrypto_nonce_table.cpp \
|
||||||
|
src/oemcrypto_old_usage_table_mock.cpp \
|
||||||
src/oemcrypto_rsa_key_shared.cpp \
|
src/oemcrypto_rsa_key_shared.cpp \
|
||||||
src/oemcrypto_session.cpp \
|
src/oemcrypto_session.cpp \
|
||||||
src/oemcrypto_session_key_table.cpp \
|
src/oemcrypto_session_key_table.cpp \
|
||||||
|
|||||||
@@ -1417,15 +1417,6 @@ extern "C" uint32_t OEMCrypto_SupportedCertificates() {
|
|||||||
}
|
}
|
||||||
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
|
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
|
||||||
OEMCrypto_Supports_RSA_CAST;
|
OEMCrypto_Supports_RSA_CAST;
|
||||||
if (!crypto_engine) {
|
|
||||||
LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit |
|
|
||||||
OEMCrypto_Supports_RSA_CAST;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt(
|
extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt(
|
||||||
@@ -1827,10 +1818,6 @@ extern "C" OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(
|
|||||||
if (!crypto_engine->config_supports_usage_table()) {
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
if (!header_buffer) {
|
|
||||||
LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null.");
|
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
|
||||||
}
|
|
||||||
return crypto_engine->usage_table().ShrinkUsageTableHeader(
|
return crypto_engine->usage_table().ShrinkUsageTableHeader(
|
||||||
new_table_size, header_buffer, header_buffer_length);
|
new_table_size, header_buffer, header_buffer_length);
|
||||||
}
|
}
|
||||||
@@ -1876,4 +1863,29 @@ extern "C" OEMCryptoResult OEMCrypto_CopyOldUsageEntry(
|
|||||||
return session_ctx->CopyOldUsageEntry(pstv);
|
return session_ctx->CopyOldUsageEntry(pstv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
OEMCryptoResult OEMCrypto_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 (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
|
||||||
|
LOGI("-- OEMCryptoResult OEMCrypto_CreateOldUsageEntry()\n");
|
||||||
|
}
|
||||||
|
if (!crypto_engine) {
|
||||||
|
LOGE("OEMCrypto_CreateOldUsageEntry: OEMCrypto Not Initialized.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
if (!crypto_engine->config_supports_usage_table()) {
|
||||||
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
return crypto_engine->usage_table().CreateOldUsageEntry(
|
||||||
|
time_since_license_received, time_since_first_decrypt,
|
||||||
|
time_since_last_decrypt, status, server_mac_key, client_mac_key, pst,
|
||||||
|
pst_length);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
@@ -0,0 +1,237 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock implementation of OEMCrypto APIs
|
||||||
|
//
|
||||||
|
#include "oemcrypto_old_usage_table_mock.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_mock.h"
|
||||||
|
#include "oemcrypto_logging.h"
|
||||||
|
#include "properties.h"
|
||||||
|
#include "pst_report.h"
|
||||||
|
#include "string_conversions.h"
|
||||||
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
OldUsageTableEntry::OldUsageTableEntry(const std::vector<uint8_t> &pst_hash)
|
||||||
|
: pst_hash_(pst_hash),
|
||||||
|
time_of_license_received_(time(NULL)),
|
||||||
|
time_of_first_decrypt_(0),
|
||||||
|
time_of_last_decrypt_(0),
|
||||||
|
status_(kUnused) {}
|
||||||
|
|
||||||
|
OldUsageTableEntry::~OldUsageTableEntry() {}
|
||||||
|
|
||||||
|
OldUsageTableEntry::OldUsageTableEntry(const OldStoredUsageEntry *buffer) {
|
||||||
|
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 + wvcdm::MAC_KEY_SIZE);
|
||||||
|
mac_key_client_.assign(buffer->mac_key_client,
|
||||||
|
buffer->mac_key_client + wvcdm::MAC_KEY_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
OldUsageTable::OldUsageTable(CryptoEngine *ce) {
|
||||||
|
ce_ = ce;
|
||||||
|
generation_ = 0;
|
||||||
|
table_.clear();
|
||||||
|
|
||||||
|
// Load saved table.
|
||||||
|
wvcdm::FileSystem *file_system = ce->file_system();
|
||||||
|
wvcdm::File *file;
|
||||||
|
std::string path;
|
||||||
|
// Note: this path is OK for a real implementation, but using security level 1
|
||||||
|
// would be better.
|
||||||
|
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
|
||||||
|
&path)) {
|
||||||
|
LOGE("OldUsageTable: Unable to get base path");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string filename = path + "UsageTable.dat";
|
||||||
|
if (!file_system->Exists(filename)) {
|
||||||
|
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||||
|
LOGI("OldUsageTable: No saved usage table. Creating new table.");
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
file->Close();
|
||||||
|
|
||||||
|
// 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 bool override_to_real = true;
|
||||||
|
const std::vector<uint8_t> &key = ce_->DeviceRootKey(override_to_real);
|
||||||
|
|
||||||
|
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[wvcdm::KEY_IV_SIZE];
|
||||||
|
memcpy(iv_buffer, encrypted_table->iv, wvcdm::KEY_IV_SIZE);
|
||||||
|
AES_KEY aes_key;
|
||||||
|
AES_set_decrypt_key(&key[0], 128, &aes_key);
|
||||||
|
AES_cbc_encrypt(&encrypted_buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
||||||
|
&buffer[SHA256_DIGEST_LENGTH + wvcdm::KEY_IV_SIZE],
|
||||||
|
file_size - SHA256_DIGEST_LENGTH - wvcdm::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));
|
||||||
|
file->Close();
|
||||||
|
if (stored_table->generation == generation_ + 1) {
|
||||||
|
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||||
|
LOGW("OldUsageTable: File is one generation old. Acceptable rollback.");
|
||||||
|
}
|
||||||
|
} else if (stored_table->generation == generation_ - 1) {
|
||||||
|
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||||
|
LOGW("OldUsageTable: File is one generation new. Acceptable rollback.");
|
||||||
|
}
|
||||||
|
// This might happen if the generation number was rolled back?
|
||||||
|
} else if (stored_table->generation != generation_) {
|
||||||
|
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(&stored_table->entries[i].entry);
|
||||||
|
table_[entry->pst_hash()] = entry;
|
||||||
|
}
|
||||||
|
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
|
||||||
|
LOGI("OldUsageTable: loaded %d entries.", stored_table->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OldUsageTableEntry *OldUsageTable::FindEntry(const std::vector<uint8_t> &pst) {
|
||||||
|
wvcdm::AutoLock 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(pst_hash);
|
||||||
|
wvcdm::AutoLock lock(lock_);
|
||||||
|
table_[pst_hash] = entry;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OldUsageTable::Clear() {
|
||||||
|
wvcdm::AutoLock 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.
|
||||||
|
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::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_mock
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Mock 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_MOCK_H_
|
||||||
|
#define OEMCRYPTO_OLD_USAGE_TABLE_MOCK_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "lock.h"
|
||||||
|
#include "OEMCryptoCENC.h"
|
||||||
|
#include "openssl/sha.h"
|
||||||
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
|
|
||||||
|
class CryptoEngine;
|
||||||
|
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[wvcdm::MAC_KEY_SIZE];
|
||||||
|
uint8_t mac_key_client[wvcdm::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[wvcdm::KEY_IV_SIZE];
|
||||||
|
int64_t generation;
|
||||||
|
uint64_t count;
|
||||||
|
AlignedOldStoredUsageEntry entries[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class OldUsageTableEntry {
|
||||||
|
public:
|
||||||
|
OldUsageTableEntry(const std::vector<uint8_t> &pst_hash);
|
||||||
|
OldUsageTableEntry(const OldStoredUsageEntry *buffer);
|
||||||
|
~OldUsageTableEntry();
|
||||||
|
const std::vector<uint8_t> &pst_hash() const { return pst_hash_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> pst_hash_;
|
||||||
|
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_;
|
||||||
|
wvcdm::Lock lock_;
|
||||||
|
int64_t generation_;
|
||||||
|
CryptoEngine *ce_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wvoec_mock
|
||||||
|
|
||||||
|
#endif // OEMCRYPTO_OLD_USAGE_TABLE_MOCK_H_
|
||||||
@@ -1015,7 +1015,10 @@ OEMCryptoResult SessionContext::UpdateUsageEntry(uint8_t* header_buffer,
|
|||||||
size_t* header_buffer_length,
|
size_t* header_buffer_length,
|
||||||
uint8_t* entry_buffer,
|
uint8_t* entry_buffer,
|
||||||
size_t* entry_buffer_length) {
|
size_t* entry_buffer_length) {
|
||||||
if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
if (!usage_entry_) {
|
||||||
|
LOGE("UpdateUsageEntry: Session has no entry.");
|
||||||
|
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
|
}
|
||||||
return ce_->usage_table().UpdateUsageEntry(this, usage_entry_, header_buffer,
|
return ce_->usage_table().UpdateUsageEntry(this, usage_entry_, header_buffer,
|
||||||
header_buffer_length, entry_buffer,
|
header_buffer_length, entry_buffer,
|
||||||
entry_buffer_length);
|
entry_buffer_length);
|
||||||
@@ -1043,7 +1046,7 @@ OEMCryptoResult SessionContext::MoveEntry(uint32_t new_index) {
|
|||||||
OEMCryptoResult SessionContext::CopyOldUsageEntry(
|
OEMCryptoResult SessionContext::CopyOldUsageEntry(
|
||||||
const std::vector<uint8_t>& pst) {
|
const std::vector<uint8_t>& pst) {
|
||||||
if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||||
return ce_->usage_table().CopyOldUsageEntry(usage_entry_, pst);
|
return usage_entry_->CopyOldUsageEntry(pst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,13 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "oemcrypto_engine_mock.h"
|
#include "oemcrypto_engine_mock.h"
|
||||||
#include "oemcrypto_logging.h"
|
#include "oemcrypto_logging.h"
|
||||||
|
#include "oemcrypto_old_usage_table_mock.h"
|
||||||
#include "properties.h"
|
#include "properties.h"
|
||||||
#include "pst_report.h"
|
#include "pst_report.h"
|
||||||
#include "string_conversions.h"
|
#include "string_conversions.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
|
namespace wvoec_mock {
|
||||||
namespace {
|
namespace {
|
||||||
const size_t kMagicLength = 8;
|
const size_t kMagicLength = 8;
|
||||||
const char* kEntryVerification = "USEENTRY";
|
const char* kEntryVerification = "USEENTRY";
|
||||||
@@ -31,13 +33,15 @@ const char* kHeaderVerification = "USEHEADR";
|
|||||||
// Offset into a signed block where we start encrypting. We need to
|
// Offset into a signed block where we start encrypting. We need to
|
||||||
// skip the signature and the iv.
|
// skip the signature and the iv.
|
||||||
const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
|
const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
|
||||||
|
|
||||||
// A structure that holds an usage entry and its signature.
|
// A structure that holds an usage entry and its signature.
|
||||||
struct SignedEntryBlock {
|
struct SignedEntryBlock {
|
||||||
uint8_t signature[SHA256_DIGEST_LENGTH];
|
uint8_t signature[SHA256_DIGEST_LENGTH];
|
||||||
uint8_t iv[SHA256_DIGEST_LENGTH];
|
uint8_t iv[SHA256_DIGEST_LENGTH];
|
||||||
uint8_t verification[kMagicLength];
|
uint8_t verification[kMagicLength];
|
||||||
wvoec_mock::StoredUsageEntry data;
|
StoredUsageEntry data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This has the data in the header of constant size. There is also an array
|
// This has the data in the header of constant size. There is also an array
|
||||||
// of generation numbers.
|
// of generation numbers.
|
||||||
struct SignedHeaderBlock {
|
struct SignedHeaderBlock {
|
||||||
@@ -50,8 +54,6 @@ struct SignedHeaderBlock {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace wvoec_mock {
|
|
||||||
|
|
||||||
UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index,
|
UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index,
|
||||||
int64_t generation)
|
int64_t generation)
|
||||||
: usage_table_(table), recent_decrypt_(false), forbid_report_(true) {
|
: usage_table_(table), recent_decrypt_(false), forbid_report_(true) {
|
||||||
@@ -286,6 +288,37 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
|||||||
return OEMCrypto_SUCCESS;
|
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() != wvcdm::MAC_KEY_SIZE) {
|
||||||
|
LOGE("CopyOldEntry: Old entry has bad server mac key.");
|
||||||
|
} else {
|
||||||
|
memcpy(data_.mac_key_server, &(old_entry->mac_key_server_[0]),
|
||||||
|
wvcdm::MAC_KEY_SIZE);
|
||||||
|
}
|
||||||
|
if (old_entry->mac_key_client_.size() != wvcdm::MAC_KEY_SIZE) {
|
||||||
|
LOGE("CopyOldEntry: Old entry has bad client mac key.");
|
||||||
|
} else {
|
||||||
|
memcpy(data_.mac_key_client, &(old_entry->mac_key_client_[0]),
|
||||||
|
wvcdm::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[0], wvcdm::MAC_KEY_SIZE);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t UsageTableEntry::SignedEntrySize() {
|
size_t UsageTableEntry::SignedEntrySize() {
|
||||||
size_t base = sizeof(SignedEntryBlock);
|
size_t base = sizeof(SignedEntryBlock);
|
||||||
// round up to make even number of blocks:
|
// round up to make even number of blocks:
|
||||||
@@ -293,6 +326,13 @@ size_t UsageTableEntry::SignedEntrySize() {
|
|||||||
return blocks * wvcdm::KEY_IV_SIZE;
|
return blocks * wvcdm::KEY_IV_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UsageTable::~UsageTable() {
|
||||||
|
if (old_table_) {
|
||||||
|
delete old_table_;
|
||||||
|
old_table_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t UsageTable::SignedHeaderSize(size_t count) {
|
size_t UsageTable::SignedHeaderSize(size_t count) {
|
||||||
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
|
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
|
||||||
// round up to make even number of blocks:
|
// round up to make even number of blocks:
|
||||||
@@ -329,7 +369,10 @@ OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
|
|||||||
OEMCryptoResult UsageTable::CreateNewUsageEntry(SessionContext* session,
|
OEMCryptoResult UsageTable::CreateNewUsageEntry(SessionContext* session,
|
||||||
UsageTableEntry** entry,
|
UsageTableEntry** entry,
|
||||||
uint32_t* usage_entry_number) {
|
uint32_t* usage_entry_number) {
|
||||||
if (!header_loaded_) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!header_loaded_) {
|
||||||
|
LOGE("CreateNewUsageEntry: Header not loaded.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
uint32_t index = generation_numbers_.size();
|
uint32_t index = generation_numbers_.size();
|
||||||
@@ -347,7 +390,10 @@ OEMCryptoResult UsageTable::LoadUsageEntry(SessionContext* session,
|
|||||||
UsageTableEntry** entry,
|
UsageTableEntry** entry,
|
||||||
uint32_t index,
|
uint32_t index,
|
||||||
const std::vector<uint8_t>& buffer) {
|
const std::vector<uint8_t>& buffer) {
|
||||||
if (!header_loaded_) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!header_loaded_) {
|
||||||
|
LOGE("CreateNewUsageEntry: Header not loaded.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
if (index >= generation_numbers_.size())
|
if (index >= generation_numbers_.size())
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
@@ -389,6 +435,10 @@ OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
|
|||||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||||
}
|
}
|
||||||
*header_buffer_length = signed_header_size;
|
*header_buffer_length = signed_header_size;
|
||||||
|
if (!header_buffer) {
|
||||||
|
LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null.");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
for (size_t i = new_table_size; i < sessions_.size(); i++) {
|
for (size_t i = new_table_size; i < sessions_.size(); i++) {
|
||||||
if (sessions_[i]) {
|
if (sessions_[i]) {
|
||||||
LOGE("ShrinkUsageTableHeader: session open for %d", i);
|
LOGE("ShrinkUsageTableHeader: session open for %d", i);
|
||||||
@@ -544,7 +594,7 @@ OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
|
|||||||
}
|
}
|
||||||
if (sessions_[new_index]) {
|
if (sessions_[new_index]) {
|
||||||
LOGE("MoveEntry: session open for %d", new_index);
|
LOGE("MoveEntry: session open for %d", new_index);
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
return OEMCrypto_ERROR_INVALID_SESSION;
|
||||||
}
|
}
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
LOGE("MoveEntry: null entry");
|
LOGE("MoveEntry: null entry");
|
||||||
@@ -636,15 +686,41 @@ OEMCryptoResult UsageTable::CreateUsageTableHeader(
|
|||||||
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult UsageTable::CopyOldUsageEntry(UsageTableEntry* entry,
|
OldUsageTableEntry* UsageTable::FindOldUsageEntry(
|
||||||
const std::vector<uint8_t>& pst) {
|
const std::vector<uint8_t>& pst) {
|
||||||
// TODO(fredgc): add this.
|
if (!old_table_) old_table_ = new OldUsageTable(ce_);
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
return old_table_->FindEntry(pst);
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult UsageTable::DeleteOldUsageTable() {
|
OEMCryptoResult UsageTable::DeleteOldUsageTable() {
|
||||||
// TODO(fredgc): add this.
|
if (old_table_) {
|
||||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
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 = time(NULL);
|
||||||
|
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 + wvcdm::MAC_KEY_SIZE);
|
||||||
|
old_entry->mac_key_client_.assign(client_mac_key,
|
||||||
|
client_mac_key + wvcdm::MAC_KEY_SIZE);
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ namespace wvoec_mock {
|
|||||||
class SessionContext;
|
class SessionContext;
|
||||||
class CryptoEngine;
|
class CryptoEngine;
|
||||||
class UsageTable;
|
class UsageTable;
|
||||||
|
class OldUsageTable;
|
||||||
|
class OldUsageTableEntry;
|
||||||
|
|
||||||
const size_t kMaxPSTLength = 255;
|
const size_t kMaxPSTLength = 255;
|
||||||
// This is the data we store offline.
|
// This is the data we store offline.
|
||||||
@@ -61,6 +63,7 @@ class UsageTableEntry {
|
|||||||
uint8_t* signed_buffer, size_t buffer_size);
|
uint8_t* signed_buffer, size_t buffer_size);
|
||||||
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
|
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
|
||||||
const std::vector<uint8_t>& buffer);
|
const std::vector<uint8_t>& buffer);
|
||||||
|
OEMCryptoResult CopyOldUsageEntry(const std::vector<uint8_t>& pst);
|
||||||
int64_t generation_number() { return data_.generation_number; }
|
int64_t generation_number() { return data_.generation_number; }
|
||||||
void set_generation_number(int64_t value) { data_.generation_number = value; }
|
void set_generation_number(int64_t value) { data_.generation_number = value; }
|
||||||
void set_index(int32_t index) { data_.index = index; }
|
void set_index(int32_t index) { data_.index = index; }
|
||||||
@@ -77,7 +80,9 @@ class UsageTableEntry {
|
|||||||
class UsageTable {
|
class UsageTable {
|
||||||
public:
|
public:
|
||||||
UsageTable(CryptoEngine* ce, wvcdm::FileSystem* file_system)
|
UsageTable(CryptoEngine* ce, wvcdm::FileSystem* file_system)
|
||||||
: ce_(ce), file_system_(file_system), header_loaded_(false){};
|
: ce_(ce), file_system_(file_system), header_loaded_(false),
|
||||||
|
old_table_(NULL){};
|
||||||
|
~UsageTable();
|
||||||
|
|
||||||
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
|
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
|
||||||
UsageTableEntry** entry,
|
UsageTableEntry** entry,
|
||||||
@@ -92,19 +97,25 @@ class UsageTable {
|
|||||||
uint8_t* entry_buffer,
|
uint8_t* entry_buffer,
|
||||||
size_t* entry_buffer_length);
|
size_t* entry_buffer_length);
|
||||||
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
|
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
|
||||||
OEMCryptoResult CopyOldUsageEntry(UsageTableEntry* entry,
|
|
||||||
const std::vector<uint8_t>& pst);
|
|
||||||
OEMCryptoResult DeleteOldUsageTable();
|
|
||||||
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
|
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
|
||||||
size_t* header_buffer_length);
|
size_t* header_buffer_length);
|
||||||
OEMCryptoResult LoadUsageTableHeader(const std::vector<uint8_t>& buffer);
|
OEMCryptoResult LoadUsageTableHeader(const std::vector<uint8_t>& buffer);
|
||||||
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
|
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
|
||||||
uint8_t* header_buffer,
|
uint8_t* header_buffer,
|
||||||
size_t* header_buffer_length);
|
size_t* header_buffer_length);
|
||||||
// Diassociates this entry with it's session.
|
|
||||||
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
|
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
|
||||||
void IncrementGeneration();
|
void IncrementGeneration();
|
||||||
static size_t SignedHeaderSize(size_t count);
|
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);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
|
OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
|
||||||
@@ -118,6 +129,7 @@ class UsageTable {
|
|||||||
int64_t master_generation_number_;
|
int64_t master_generation_number_;
|
||||||
std::vector<int64_t> generation_numbers_;
|
std::vector<int64_t> generation_numbers_;
|
||||||
std::vector<SessionContext*> sessions_;
|
std::vector<SessionContext*> sessions_;
|
||||||
|
OldUsageTable *old_table_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvoec_mock
|
} // namespace wvoec_mock
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
|
|||||||
license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR;
|
license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR;
|
||||||
}
|
}
|
||||||
memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length()));
|
memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length()));
|
||||||
|
pst_ = pst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
|
void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
|
||||||
@@ -857,6 +858,20 @@ void Session::LoadUsageEntry(uint32_t index, const vector<uint8_t>& buffer) {
|
|||||||
OEMCrypto_LoadUsageEntry(session_id(), index, &buffer[0], buffer.size()));
|
OEMCrypto_LoadUsageEntry(session_id(), index, &buffer[0], buffer.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::MoveUsageEntry(uint32_t new_index,
|
||||||
|
std::vector<uint8_t>* header_buffer,
|
||||||
|
OEMCryptoResult expect_result) {
|
||||||
|
|
||||||
|
ASSERT_NO_FATAL_FAILURE(open());
|
||||||
|
ASSERT_NO_FATAL_FAILURE(ReloadUsageEntry());
|
||||||
|
ASSERT_EQ(expect_result, OEMCrypto_MoveEntry(session_id(), new_index));
|
||||||
|
if (expect_result == OEMCrypto_SUCCESS) {
|
||||||
|
usage_entry_number_ = new_index;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(UpdateUsageEntry(header_buffer));
|
||||||
|
}
|
||||||
|
ASSERT_NO_FATAL_FAILURE(close());
|
||||||
|
}
|
||||||
|
|
||||||
void Session::GenerateReport(const std::string& pst, bool expect_success,
|
void Session::GenerateReport(const std::string& pst, bool expect_success,
|
||||||
Session* other) {
|
Session* other) {
|
||||||
ASSERT_TRUE(open_);
|
ASSERT_TRUE(open_);
|
||||||
@@ -897,6 +912,84 @@ void Session::GenerateReport(const std::string& pst, bool expect_success,
|
|||||||
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report().pst(), pst.length()));
|
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report().pst(), pst.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::VerifyPST(const Test_PST_Report& expected) {
|
||||||
|
wvcdm::Unpacked_PST_Report computed = pst_report();
|
||||||
|
EXPECT_EQ(expected.status, computed.status());
|
||||||
|
char* pst_ptr = reinterpret_cast<char *>(computed.pst());
|
||||||
|
std::string computed_pst(pst_ptr, pst_ptr + computed.pst_length());
|
||||||
|
ASSERT_EQ(expected.pst, computed_pst);
|
||||||
|
EXPECT_NEAR(expected.seconds_since_license_received,
|
||||||
|
computed.seconds_since_license_received(),
|
||||||
|
kLicenseReceivedTimeTolerance);
|
||||||
|
// Decrypt times only valid on licenses that have been active.
|
||||||
|
if (expected.status == kActive || expected.status == kInactiveUsed) {
|
||||||
|
EXPECT_NEAR(expected.seconds_since_first_decrypt,
|
||||||
|
computed.seconds_since_first_decrypt(),
|
||||||
|
kUsageTableTimeTolerance);
|
||||||
|
EXPECT_NEAR(expected.seconds_since_last_decrypt,
|
||||||
|
computed.seconds_since_last_decrypt(),
|
||||||
|
kUsageTableTimeTolerance);
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> signature(SHA_DIGEST_LENGTH);
|
||||||
|
unsigned int md_len = SHA_DIGEST_LENGTH;
|
||||||
|
if (!HMAC(EVP_sha1(), &mac_key_client_[0], mac_key_client_.size(),
|
||||||
|
&pst_report_buffer_[0] + SHA_DIGEST_LENGTH,
|
||||||
|
pst_report_buffer_.size() - SHA_DIGEST_LENGTH,
|
||||||
|
&signature[0], &md_len)) {
|
||||||
|
cout << "Error computing HMAC.\n";
|
||||||
|
dump_openssl_error();
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, memcmp(computed.signature(), &signature[0],
|
||||||
|
SHA_DIGEST_LENGTH));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t MaybeAdjustTime(int64_t t, time_t now) {
|
||||||
|
int64_t k10Minutes = 60 * 10; // in seconds.
|
||||||
|
if (t > k10Minutes) return now - t;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::GenerateVerifyReport(const std::string& pst,
|
||||||
|
OEMCrypto_Usage_Entry_Status status,
|
||||||
|
int64_t time_license_received,
|
||||||
|
int64_t time_first_decrypt,
|
||||||
|
int64_t time_last_decrypt) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(GenerateReport(pst));
|
||||||
|
Test_PST_Report expected(pst, status);
|
||||||
|
time_t now = time(NULL);
|
||||||
|
expected.seconds_since_license_received =
|
||||||
|
MaybeAdjustTime(time_license_received, now);
|
||||||
|
expected.seconds_since_first_decrypt =
|
||||||
|
MaybeAdjustTime(time_first_decrypt, now);
|
||||||
|
expected.seconds_since_last_decrypt = MaybeAdjustTime(time_last_decrypt, now);
|
||||||
|
ASSERT_NO_FATAL_FAILURE(VerifyPST(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::CreateOldEntry(const Test_PST_Report& report) {
|
||||||
|
OEMCryptoResult result = OEMCrypto_CreateOldUsageEntry(
|
||||||
|
report.seconds_since_license_received,
|
||||||
|
report.seconds_since_first_decrypt,
|
||||||
|
report.seconds_since_last_decrypt,
|
||||||
|
report.status, &mac_key_server_[0],
|
||||||
|
&mac_key_client_[0],
|
||||||
|
reinterpret_cast<const uint8_t*>(report.pst.c_str()),
|
||||||
|
report.pst.length());
|
||||||
|
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) return;
|
||||||
|
ASSERT_EQ(OEMCrypto_SUCCESS, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::CopyAndVerifyOldEntry(const Test_PST_Report& report,
|
||||||
|
std::vector<uint8_t>* header_buffer) {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(CreateNewUsageEntry());
|
||||||
|
OEMCryptoResult result = OEMCrypto_CopyOldUsageEntry(
|
||||||
|
session_id(), reinterpret_cast<const uint8_t*>(report.pst.c_str()),
|
||||||
|
report.pst.length());
|
||||||
|
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) return;
|
||||||
|
ASSERT_NO_FATAL_FAILURE(UpdateUsageEntry(header_buffer));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(GenerateReport(report.pst));
|
||||||
|
ASSERT_NO_FATAL_FAILURE(VerifyPST(report));
|
||||||
|
}
|
||||||
|
|
||||||
const uint8_t* Session::message_ptr() {
|
const uint8_t* Session::message_ptr() {
|
||||||
return reinterpret_cast<const uint8_t*>(&encrypted_license());
|
return reinterpret_cast<const uint8_t*>(&encrypted_license());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ const int kLongSleep = 2 * kSpeedMultiplier;
|
|||||||
const uint32_t kDuration = 2 * kSpeedMultiplier;
|
const uint32_t kDuration = 2 * kSpeedMultiplier;
|
||||||
const uint32_t kLongDuration = 5 * kSpeedMultiplier;
|
const uint32_t kLongDuration = 5 * kSpeedMultiplier;
|
||||||
const int32_t kTimeTolerance = 3 * kSpeedMultiplier;
|
const int32_t kTimeTolerance = 3 * kSpeedMultiplier;
|
||||||
|
const int kLicenseReceivedTimeTolerance = kSpeedMultiplier;
|
||||||
|
const time_t kUsageTableTimeTolerance = 10 * kSpeedMultiplier;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -102,6 +104,18 @@ struct RSAPrivateKeyMessage {
|
|||||||
uint32_t nonce;
|
uint32_t nonce;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Test_PST_Report {
|
||||||
|
Test_PST_Report(const std::string& pst_in,
|
||||||
|
OEMCrypto_Usage_Entry_Status status_in)
|
||||||
|
: pst(pst_in), status(status_in) {}
|
||||||
|
|
||||||
|
OEMCrypto_Usage_Entry_Status status;
|
||||||
|
int64_t seconds_since_license_received;
|
||||||
|
int64_t seconds_since_first_decrypt;
|
||||||
|
int64_t seconds_since_last_decrypt;
|
||||||
|
std::string pst;
|
||||||
|
};
|
||||||
|
|
||||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||||
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
// the low 64 bits of the IV counter, and leave the high 64 bits alone. This
|
||||||
// is different from the OpenSSL implementation, so we implement the CTR loop
|
// is different from the OpenSSL implementation, so we implement the CTR loop
|
||||||
@@ -267,6 +281,7 @@ class Session {
|
|||||||
OEMCryptoResult expect_result = OEMCrypto_SUCCESS);
|
OEMCryptoResult expect_result = OEMCrypto_SUCCESS);
|
||||||
// The usage entry number for this session's usage entry.
|
// The usage entry number for this session's usage entry.
|
||||||
uint32_t usage_entry_number() const { return usage_entry_number_; }
|
uint32_t usage_entry_number() const { return usage_entry_number_; }
|
||||||
|
void set_usage_entry_number(uint32_t v) { usage_entry_number_ = v; }
|
||||||
// The encrypted buffer holding the recently updated and saved usage entry.
|
// The encrypted buffer holding the recently updated and saved usage entry.
|
||||||
const vector<uint8_t>& encrypted_usage_entry() const {
|
const vector<uint8_t>& encrypted_usage_entry() const {
|
||||||
return encrypted_usage_entry_;
|
return encrypted_usage_entry_;
|
||||||
@@ -277,11 +292,32 @@ class Session {
|
|||||||
// order to verify signatures.
|
// order to verify signatures.
|
||||||
void GenerateReport(const std::string& pst, bool expect_success = true,
|
void GenerateReport(const std::string& pst, bool expect_success = true,
|
||||||
Session* other = 0);
|
Session* other = 0);
|
||||||
|
// Move this usage entry to a new index.
|
||||||
|
void MoveUsageEntry(uint32_t new_index, std::vector<uint8_t>* header_buffer,
|
||||||
|
OEMCryptoResult expect_result = OEMCrypto_SUCCESS);
|
||||||
|
// PST used in FillSimpleMesage.
|
||||||
|
string pst() const { return pst_; }
|
||||||
// Returns a pointer-like thing to the usage report generated by the previous
|
// Returns a pointer-like thing to the usage report generated by the previous
|
||||||
// call to GenerateReport.
|
// call to GenerateReport.
|
||||||
wvcdm::Unpacked_PST_Report pst_report() {
|
wvcdm::Unpacked_PST_Report pst_report() {
|
||||||
return wvcdm::Unpacked_PST_Report(&pst_report_buffer_[0]);
|
return wvcdm::Unpacked_PST_Report(&pst_report_buffer_[0]);
|
||||||
}
|
}
|
||||||
|
// Verify the PST report.
|
||||||
|
void VerifyPST(const Test_PST_Report& report);
|
||||||
|
// Generate and Verify the Usage Report. If any time is greater than 10
|
||||||
|
// minutes, it is assumed to be an absolute time, and time_since will be
|
||||||
|
// computed relative to now.
|
||||||
|
void GenerateVerifyReport(const std::string& pst,
|
||||||
|
OEMCrypto_Usage_Entry_Status status,
|
||||||
|
int64_t time_license_received = 0,
|
||||||
|
int64_t time_first_decrypt = 0,
|
||||||
|
int64_t time_last_decrypt = 0);
|
||||||
|
// Create an entry in the old usage table based on the given report.
|
||||||
|
void CreateOldEntry(const Test_PST_Report &report);
|
||||||
|
// Create a new entry and copy the old entry into it. Then very the report
|
||||||
|
// is right.
|
||||||
|
void CopyAndVerifyOldEntry(const Test_PST_Report &report,
|
||||||
|
std::vector<uint8_t>* header_buffer);
|
||||||
|
|
||||||
// The unencrypted license response or license renewal response.
|
// The unencrypted license response or license renewal response.
|
||||||
MessageData& license() { return license_; }
|
MessageData& license() { return license_; }
|
||||||
@@ -329,6 +365,7 @@ class Session {
|
|||||||
int num_keys_;
|
int num_keys_;
|
||||||
vector<uint8_t> encrypted_usage_entry_;
|
vector<uint8_t> encrypted_usage_entry_;
|
||||||
uint32_t usage_entry_number_;
|
uint32_t usage_entry_number_;
|
||||||
|
string pst_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -130,4 +130,12 @@ TEST_F(OEMCryptoAndroidNYCTest, MinVersionNumber11) {
|
|||||||
ASSERT_GE(version, 11u);
|
ASSERT_GE(version, 11u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These tests are required for O Android devices.
|
||||||
|
class OEMCryptoAndroidOCTest : public OEMCryptoAndroidNYCTest {};
|
||||||
|
|
||||||
|
TEST_F(OEMCryptoAndroidOCTest, MinVersionNumber13) {
|
||||||
|
uint32_t version = OEMCrypto_APIVersion();
|
||||||
|
ASSERT_GE(version, 13u);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvoec
|
} // namespace wvoec
|
||||||
|
|||||||
Reference in New Issue
Block a user