This renames the "mock" code to "reference" because that's really what
it is.  Also, some code has been moved from the CDM repo to a common
utility directory so that it can be included here, and the oemcrypto
unit tests can now be built without having access to a current CDM
repo.

There are no functionality changes in this CL.
This commit is contained in:
Fred Gylys-Colwell
2018-05-10 15:28:20 -07:00
parent 16d9abca4c
commit 61f02edda4
65 changed files with 1586 additions and 1427 deletions

Binary file not shown.

View File

@@ -1,597 +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.
//
// Mock implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that reads data from a file
// to decide what it's current status is. It is used for testing cdm code.
// The following properties are read from the file:
// log_level: logging level to use.
// 0 = LOG_ERROR,
// 1 = LOG_WARN,
// 2 = LOG_INFO,
// 3 = LOG_DEBUG,
// 4 = LOG_VERBOSE
// kLogging*: All logging flags found in oemcrypto/include/oemcrypto_logging.h
// can be turned on (1) or off (0).
// security_level: returned by OEMCrypto_SecurityLevel.
// secure_lib: If set, then this will be used as a path to
// the L1 liboemcrypto.so that we can use secure buffers.
// current_hdcp: returned by OEMCrypto_GetHDCPCapability and
// used to verify the key control block in methods like DecryptCENC.
// HDCP_NONE = 0, // No HDCP supported, no secure data path.
// HDCP_V1 = 1, // HDCP version 1.0
// HDCP_V2 = 2, // HDCP version 2.0 Type 1.
// HDCP_V2_1 = 3, // HDCP version 2.1 Type 1.
// HDCP_V2_2 = 4, // HDCP version 2.2 Type 1.
// HDCP_NO_DIGITAL_OUTPUT = 0xff // No digital output.
// max_hdcp: returned by OEMCrypto_GetHDCPCapability. Same values as above.
// srm_update_supported: If "1", then srm update is supported.
// srm_initial_version: Initial value for srm version.
// This will be ignored after a reset. If this is not set, CurrentSRM will
// return NOT_IMPLEMENTED.
// srm_load_fail: If set to a nonzero number, then load_srm will
// fail and the version will not be updated. The number is converted to
// an OEMCryptoResult and returned.
// srm_load_version: If this is set, then it will be used as the
// new srm version after loading an SRM -- ignoring the contents of the SRM.
// If srm_load_version is -1, then the buffer passed into LoadSRM will be
// parsed.
// srm_blacklisted_device_attached: If set to "1", then a
// oemcrypto will act as if a blacklisted device is attached -- i.e.
// playback will be restricted to the local display only.
// srm_attached_device_id: If nonzero, the id of a blacklisted device.
// If this id is in the revocation list of an SRM file when it is loaded,
// playback will be restricted to the local display only.
// security_patch_level: This is the value returned by
// OEMCrypto_Security_Patch_Level. If the key control block requires a
// higher level, then OEMCrypto_LoadKeys will fail.
// max_buffer_size: maximum size of a buffer accepted by DecryptCENC and
// friends. If this is 0, there is no restriction. If it is 1, the
// minimum allowed value is used.
// use_keybox: If this is 1, then the test keybox is used. If this is zero,
// then the test OEM certificate is used.
// use_fallback: If this is nonzero, then the installed Level 1 library will
// be used to play content to a secure buffer. Decryption and key
// verification are done by the mock, but then the data is copied to the
// secure buffer using OEMCrypto_CopyBuffer. The filename of the fallback
// library is hardcoded to "level1_backup_liboemcrypto.so". It is
// recommended you use the install script to ensure you have the right
// filename.
//
#include <arpa/inet.h>
#include <dlfcn.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include <string>
#include <map>
#include "log.h"
#include "oem_cert.h"
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_logging.h"
#include "properties.h"
#include "string_conversions.h"
namespace wvoec_mock {
namespace {
typedef OEMCryptoResult (*L1_Initialize_t)(void);
typedef OEMCryptoResult (*L1_Terminate_t)(void);
typedef OEMCryptoResult (*L1_CopyBuffer_t)(const uint8_t* data_addr,
size_t data_length,
OEMCrypto_DestBufferDesc* out_buffer,
uint8_t subsample_flags);
const std::string kDefaultOptionsFile = "/data/mediadrm/oemcrypto/options.txt";
} // namespace
class AndroidModifiableCryptoEngine : public CryptoEngine {
public:
AndroidModifiableCryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
: CryptoEngine(file_system),
options_file_(kDefaultOptionsFile),
srm_loaded_(false),
srm_version_(0),
level1_valid_(false),
level1_library_(NULL) {
std::string path;
if (wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
&path)) {
options_file_ = path + "options.txt";
}
}
void MaybeReadOptionsFile() {
static time_t last_check = 0;
static time_t last_changed = 0;
time_t now = time(NULL);
if (now > last_check + 5) { // Check every five seconds.
last_check = now;
struct stat file_stat;
if (stat(options_file_.c_str(), &file_stat)) {
LOGE("Could not stat %s: %s", options_file_.c_str(), strerror(errno));
return;
}
if (file_stat.st_mtime > last_changed) {
last_changed = file_stat.st_mtime;
ReadOptionsFile();
}
}
}
void ReadOptionsFile() {
FILE *file = fopen(options_file_.c_str(), "r");
if (!file) {
LOGE("Could not read %s %s", options_file_.c_str(), strerror(errno));
return;
}
while (!feof(file)) {
char name[80 + 1];
int64_t value;
if (fscanf(file, "%80s %lld", name, &value)) {
LOGD("Option %s = %lld", name, value);
options_[std::string(name)] = value;
}
}
fclose(file);
InitializeLogging();
}
int64_t GetOption(const std::string &key, int64_t default_value) {
MaybeReadOptionsFile();
if (options_.find(key) == options_.end() ) {
LOGW("Option %s not set. Using default %lld", key.c_str(), default_value);
return default_value;
}
return options_[key];
}
void InitializeLogging() {
int log_level = GetOption("log_level", wvcdm::LOG_DEBUG);
int categories = 0;
if (GetOption("kLoggingTraceOEMCryptoCalls", 0) > 0)
categories |= kLoggingTraceOEMCryptoCalls;
if (GetOption("kLoggingDumpContentKeys", 0) > 0)
categories |= kLoggingDumpContentKeys;
if (GetOption("kLoggingDumpKeyControlBlocks", 0) > 0)
categories |= kLoggingDumpKeyControlBlocks;
if (GetOption("kLoggingDumpDerivedKeys", 0) > 0)
categories |= kLoggingDumpDerivedKeys;
if (GetOption("kLoggingTraceNonce", 0) > 0)
categories |= kLoggingTraceNonce;
if (GetOption("kLoggingTraceDecryption", 0) > 0)
categories |= kLoggingTraceDecryption;
if (GetOption("kLoggingTraceUsageTable", 0) > 0)
categories |= kLoggingTraceUsageTable;
if (GetOption("kLoggingTraceDecryptCalls", 0) > 0)
categories |= kLoggingTraceDecryptCalls;
if (GetOption("kLoggingDumpTraceAll", 0) > 0)
categories |= kLoggingDumpTraceAll;
SetLoggingSettings(log_level, categories);
}
#define QUOTE_DEFINE(A) #A
#define QUOTE(A) QUOTE_DEFINE(A)
#define LOOKUP(Name, Function) \
Name = (L1_##Name##t)dlsym(level1_library_, QUOTE(Function)); \
if (!Name) { \
LOGW("Could not load L1 %s.", \
QUOTE(Function)); \
Terminate(); \
return false; \
}
virtual bool Initialize() {
LOGD("OEMCrypto Mock With Options " " " __DATE__ " " __TIME__);
MaybeReadOptionsFile();
if (!GetOption("use_fallback", 1)) {
LOGD("Level 1 fallback ignored.");
return true;
}
level1_library_ = dlopen("level1_backup_liboemcrypto.so", RTLD_NOW);
if (level1_library_ == NULL) {
LOGE("Could not load backup: %s", dlerror());
return false;
}
LOOKUP(Initialize_, OEMCrypto_Initialize);
LOOKUP(Terminate_, OEMCrypto_Terminate);
LOOKUP(CopyBuffer_, OEMCrypto_CopyBuffer);
level1_valid_ = true;
OEMCryptoResult sts = Initialize_();
LOGD("L1 fall back initialized. status = %d.", sts);
if (sts != OEMCrypto_SUCCESS) {
LOGW("Terminating L1 because init failed.");
Terminate();
LOGW("Continuing Mock without L1 fallback.");
}
return true;
}
virtual void Terminate() {
if (level1_valid_) Terminate_();
if (level1_library_ != NULL) {
LOGD("Closing L1 fall back.\n");
dlclose(level1_library_);
level1_valid_ = false;
level1_library_ = NULL;
CopyBuffer_ = NULL;
Initialize_ = NULL;
Terminate_ = NULL;
} else {
LOGD("Terminate mock.\n");
}
}
const char *HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) {
switch (value) {
case HDCP_NONE:
return "No HDCP supported, no secure data path";
case HDCP_V1:
return "HDCP version 1.0";
case HDCP_V2:
return "HDCP version 2.0";
case HDCP_V2_1:
return "HDCP version 2.1";
case HDCP_V2_2:
return "HDCP version 2.2";
case HDCP_NO_DIGITAL_OUTPUT:
return "No HDCP device attached/using local display with secure path";
default:
return "<INVALID VALUE>";
}
}
OEMCrypto_ProvisioningMethod config_provisioning_method() {
if (GetOption("use_keybox", 1)) {
return OEMCrypto_Keybox;
} else {
return OEMCrypto_OEMCertificate;
}
}
OEMCryptoResult get_oem_certificate(SessionContext* session,
uint8_t* public_cert,
size_t* public_cert_length) {
if (GetOption("use_keybox", 1)) {
LOGD("OEM Cert asked for when use_keybox = 1.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (kOEMPublicCertSize == 0) {
LOGD("OEM Cert Size is 0.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (public_cert_length == NULL) {
LOGD("OEM Cert length is 0.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (*public_cert_length < kOEMPublicCertSize) {
*public_cert_length = kOEMPublicCertSize;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*public_cert_length = kOEMPublicCertSize;
if (public_cert == NULL) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
LOGE("Private RSA Key did not load correctly.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
}
// Returns "L3" for a software only library. L1 is for hardware protected
// data paths.
const char *config_security_level() {
switch (GetOption("security_level", 0)) {
default:
LOGW("Option security_level not set. Default is L3.");
case 3:
return "L3";
case 2:
return "L2";
case 1:
return "L1";
}
}
// Returns the HDCP version currently in use.
OEMCrypto_HDCP_Capability config_current_hdcp_capability() {
static OEMCrypto_HDCP_Capability current_hdcp = HDCP_NONE;
OEMCrypto_HDCP_Capability new_current_hdcp =
static_cast<OEMCrypto_HDCP_Capability>(GetOption("current_hdcp", 0));
if (current_hdcp != new_current_hdcp) {
LOGI("OEMCrypto current HDCP changed from %d (%s) to %d (%s)", current_hdcp,
HDCPCapabilityAsString(current_hdcp), new_current_hdcp,
HDCPCapabilityAsString(new_current_hdcp));
current_hdcp = new_current_hdcp;
}
return current_hdcp;
}
// Returns the max HDCP version supported.
OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
static OEMCrypto_HDCP_Capability max_hdcp = HDCP_NONE;
MaybeReadOptionsFile();
OEMCrypto_HDCP_Capability new_max_hdcp =
static_cast<OEMCrypto_HDCP_Capability>(GetOption("max_hdcp", 0));
if (max_hdcp != new_max_hdcp) {
LOGI("OEMCrypto max HDCP changed from %d (%s) to %d (%s)", max_hdcp,
HDCPCapabilityAsString(max_hdcp), new_max_hdcp,
HDCPCapabilityAsString(new_max_hdcp));
max_hdcp = new_max_hdcp;
}
return max_hdcp;
}
// This should start at 0, and be incremented only when a security patch has
// been applied to the device that fixes a security bug.
uint8_t config_security_patch_level() {
return GetOption("security_patch_level", 0);
}
size_t max_buffer_size() {
int max = GetOption("max_buffer_size", 0);
// If max is 1, just use default max buffer.
if (max == 1) return CryptoEngine::max_buffer_size();
return max; // If 0, no restriction. If something else, use that restriction.
}
bool srm_update_supported() {
int supported = GetOption("srm_update_supported", 0);
LOGI("OEMCrypto mock %s supporting SRM update.",
supported ? "is" : "is not");
return supported != 0;
}
OEMCryptoResult current_srm_version(uint16_t *version) {
if (srm_loaded_) {
LOGV("SRM loaded. version used is %d.", srm_version_);
*version = srm_version_;
return OEMCrypto_SUCCESS;
}
int value = GetOption("srm_initial_version", -1);
if (value > 0) {
LOGV("SRM version from get option: %d.", value);
srm_version_ = value;
*version = value;
return OEMCrypto_SUCCESS;
} else {
LOGI("SRM initial version is %d -- reporting not implemented.", value);
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
}
// Convert uint24 or uint40 into a uint64.
int64_t unpack_odd_bytes(const uint8_t *buffer, size_t length) {
uint8_t small_buffer[8];
memset(small_buffer, 0, 8);
if (length > 8) {
LOGE("OEMCrypto Mock: programmer error. unpack %d bytes.", length);
length = 8;
}
size_t offset = 8 - length;
memcpy(small_buffer + offset, buffer, length);
return wvcdm::htonll64(*reinterpret_cast<const int64_t*>(small_buffer));
}
OEMCryptoResult load_srm(const uint8_t *buffer, size_t buffer_length) {
if (!srm_update_supported()) {
LOGE("OEMCrypto mock update not supported, but load_srm called.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
int result = GetOption("srm_load_fail", 0);
if (result > 0) {
LOGE("OEMCrypto mock load_srm returning error %d.", result);
return static_cast<OEMCryptoResult>(result);
}
int new_version = GetOption("srm_load_version", -1);
if (new_version >= 0) {
if (new_version < srm_version_) {
LOGE("New SRM version is lower than existing SRM version: %d < %d",
new_version, srm_version_);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
srm_version_ = new_version;
LOGI("OEMCrypto mock told to change SRM version to %d.", srm_version_);
srm_loaded_ = true;
return OEMCrypto_SUCCESS;
}
if (buffer_length < 395) {
LOGE("OEMCrypto mock bad buffer size: %ld < 395.", buffer_length);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
uint8_t srm_id = buffer[0] >> 4;
uint8_t hdcp2_indicator = buffer[0] & 0x0F;
uint8_t reserved = buffer[1];
uint16_t version = htons(*reinterpret_cast<const uint16_t *>(&buffer[2]));
if (reserved) {
LOGE("OEMCrypto mock. SRM's second byte nonzero: %02X.", reserved);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
uint8_t generation = buffer[4];
if (generation > 1) {
LOGW("OEMCrypto mock. SRM Generation number is %d, but only first gen is parsed.",
generation);
LOGW("If the revoked device is in a a later generation, it will not be recognized.");
}
int64_t length = unpack_odd_bytes(buffer + 5, 3); // 24 bits.
if (length + 5 != buffer_length) {
LOGW("OEMCrypto mock. SRM length is %lld = 0x%llx, but I expected %zd = 0x%zx.",
length, length, buffer_length - 5, buffer_length - 5);
}
int64_t count = 0;
const uint8_t *ids;
if (srm_id == 8 && hdcp2_indicator == 0) {
// https://www.digital-cp.com/sites/default/files/specifications/HDCP%20Specification%20Rev1_4_Secure.pdf
count = buffer[8];
LOGI("OEMCrypto mock loading HDCP1 SRM. version = %d. count=%lld.",
version, count);
ids = buffer + 9;
if (buffer_length < 9 + count*5) {
LOGE("OEMCrypto mock bad buffer size for count = %lld: %d < %lld.",
count, buffer_length, 12 + count*5);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
} else if (srm_id == 9 && hdcp2_indicator == 1) {
// https://www.digital-cp.com/sites/default/files/specifications/HDCP%20on%20HDMI%20Specification%20Rev2_2_Final1.pdf
count = unpack_odd_bytes(buffer + 8, 2) >> 6; // 10 bits = 2 bytes - 6.
LOGI("OEMCrypto mock loading HDCP2 SRM. version = %d. count=%lld.",
version, count);
ids = buffer + 12;
if (buffer_length < 12 + count*5) {
LOGE("OEMCrypto mock bad buffer size for count: %d < %ld.",
buffer_length, 12 + count*5);
return OEMCrypto_ERROR_SHORT_BUFFER;
}
} else {
LOGE("OEMCrypto mock bad buffer start: %02X%02X%02X%02X...", buffer[0],
buffer[1], buffer[2], buffer[3]);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
for(size_t i = 0; i < count; i++) {
int64_t id = unpack_odd_bytes(ids + 5*i, 5);
srm_revocation_list_.push_back(id);
LOGI("OEMCrypto mock SRM revokes device %lld = 0x%llx", id, id);
}
srm_loaded_ = true;
srm_version_ = version;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult remove_srm() {
if (!srm_update_supported()) {
LOGE("OEMCrypto mock update not supported, bug load_srm called.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
srm_version_ = 0;
srm_loaded_ = false;
return OEMCrypto_SUCCESS;
}
bool srm_blacklisted_device_attached() {
if (GetOption("srm_load_version", -1) < 0) {
return scan_revoked_list();
}
static int blacklisted = 0;
int new_value = GetOption("srm_blacklisted_device_attached", 0);
if (new_value != blacklisted) {
LOGI("SRM blacklisted device changed from %d to %d", blacklisted,
new_value);
blacklisted = new_value;
}
return blacklisted > 0;
}
bool scan_revoked_list() {
static int64_t old_attached_id = 0;
int64_t attached_id = GetOption("srm_attached_device_id", 0);
bool print_all_ids = false;
if (attached_id != old_attached_id) {
LOGD("OEMCrypto mock -- ID of attached device is %lld = 0x%lld",
attached_id, attached_id);
old_attached_id = attached_id;
print_all_ids = true;
}
for (size_t i = 0; i < srm_revocation_list_.size(); i++) {
if (print_all_ids) {
LOGD("OEMCrypto mock: %d) revoked id %lld = 0x%lld.", i,
srm_revocation_list_[i], srm_revocation_list_[i]);
}
if (srm_revocation_list_[i] == attached_id) {
LOGD("OEMCrypto mock: attached device %lld = 0x%lld is revoked.",
attached_id, attached_id);
return true;
}
}
LOGD("OEMCrypto mock: attached device %lld is not revoked.", attached_id);
return false;
}
virtual void adjust_destination(OEMCrypto_DestBufferDesc *out_description,
size_t data_length, uint8_t subsample_flags) {
if (out_description->type != OEMCrypto_BufferType_Secure) return;
if (!level1_valid_) {
static bool warned_once = false;
if (!warned_once) {
warned_once = true;
LOGW("OEMCrypto Mock: given secure buffer with no level1 fallback.");
}
return;
}
if (subsample_flags & OEMCrypto_FirstSubsample) {
final_destination_.type = OEMCrypto_BufferType_Secure;
final_destination_.buffer.secure.handle =
out_description->buffer.secure.handle;
final_destination_.buffer.secure.max_length =
out_description->buffer.secure.max_length;
final_destination_.buffer.secure.offset =
out_description->buffer.secure.offset;
temp_buffer_.resize(final_destination_.buffer.secure.max_length);
temp_buffer_length_ = 0;
}
if (temp_buffer_length_ != out_description->buffer.secure.offset) {
LOGW("OEMCrypto: offset into secure buffer is not correct %zd != %zd.",
temp_buffer_length_, out_description->buffer.secure.offset);
}
size_t new_length = temp_buffer_length_ + data_length;
if (new_length > temp_buffer_.size()) {
LOGW("Temp buffer was not big enough. %zd > %zd.", new_length,
temp_buffer_.size());
temp_buffer_.resize(new_length);
}
destination_ = &temp_buffer_[temp_buffer_length_];
temp_buffer_length_ = new_length;
}
// Push destination buffer to L1 output.
virtual OEMCryptoResult PushDestination(
OEMCrypto_DestBufferDesc *out_description, uint8_t subsample_flags) {
if (level1_valid_ &&
(out_description->type == OEMCrypto_BufferType_Secure)) {
if (subsample_flags & OEMCrypto_LastSubsample) {
return CopyBuffer_(&temp_buffer_[0], temp_buffer_length_,
&final_destination_,
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample);
}
}
return OEMCrypto_SUCCESS;
}
private:
// If the SRM version has been loaded or not. If not, we use the system
// property to find the current SRM version.
bool srm_loaded_;
// Current srm version. Before an SRM has been loaded, this will be set from
// the system property.
int srm_version_;
// List of forbidden/revoked devices.
std::vector<int64_t> srm_revocation_list_;
std::map<std::string, int64_t> options_;
std::string options_file_;
bool level1_valid_;
void* level1_library_;
L1_CopyBuffer_t CopyBuffer_;
L1_Initialize_t Initialize_;
L1_Terminate_t Terminate_;
OEMCrypto_DestBufferDesc final_destination_;
std::vector<uint8_t> temp_buffer_;
size_t temp_buffer_length_; // Length of temp buffer currently in use.
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::auto_ptr<wvcdm::FileSystem> file_system) {
return new AndroidModifiableCryptoEngine(file_system);
}
} // namespace wvoec_mock

View File

@@ -1,28 +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.
#ifndef WV_KEYBOX_H_
#define WV_KEYBOX_H_
#include <stdint.h>
namespace wvoec_mock {
// This is the format of a Widevine keybox.
typedef struct { // 128 bytes total.
// C character string identifying the device. Null terminated.
uint8_t device_id_[32];
// 128 bit AES key assigned to device. Generated by Widevine.
uint8_t device_key_[16];
// Key Data. Encrypted data.
uint8_t data_[72];
// Constant code used to recognize a valid keybox "kbox" = 0x6b626f78.
uint8_t magic_[4];
// The CRC checksum of the first 124 bytes of the keybox.
uint8_t crc_[4];
} WidevineKeybox;
} // namespace wvoec_mock
#endif // WV_KEYBOX_H_

View File

@@ -1,121 +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.
#include "OEMCryptoCENC.h"
#include <string>
#include <gtest/gtest.h>
#include "log.h"
#include "oemcrypto_logging.h"
#include "oemcrypto_mock.cpp"
class OEMCryptoLoggingTest : public ::testing::Test {
protected:
OEMCryptoLoggingTest() {}
void SetUp() {
::testing::Test::SetUp();
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
}
void TearDown() {
OEMCrypto_Terminate();
::testing::Test::TearDown();
}
};
TEST_F(OEMCryptoLoggingTest, TestDumpHexFunctions) {
uint8_t vector[] = {0xFA, 0x11, 0x28, 0x33};
std::string buffer;
wvoec_mock::dump_hex_helper(buffer, "name", vector, 4u);
ASSERT_EQ("name = \n wvcdm::a2b_hex(\"FA112833\");\n", buffer);
uint8_t vector2[] = {
0xFA, 0x11, 0x28, 0x33, 0xFA, 0x11, 0x28, 0x33, 0xFA, 0x11,
0x28, 0x33, 0xFA, 0x11, 0x28, 0x33, 0xFA, 0x11, 0x28, 0x33,
0xFA, 0x11, 0x28, 0x33, 0x01, 0x14, 0x28, 0xAB, 0xFA, 0xCD,
0xEF, 0x67, 0x01, 0x14, 0x28, 0xAB, 0xFA, 0xCD, 0xEF, 0x67,
};
buffer.clear(); // dump_hex_helper appends to buffer
wvoec_mock::dump_hex_helper(buffer, "name", vector2, 40u);
ASSERT_EQ(
"name = \n "
"wvcdm::a2b_hex("
"\"FA112833FA112833FA112833FA112833FA112833FA112833011428ABFACDEF67\"\n "
" \"011428ABFACDEF67\");\n",
buffer);
buffer.clear(); // dump_hex_helper appends to buffer
wvoec_mock::dump_array_part_helper(buffer, "array", 5u, "name", vector2, 40u);
ASSERT_EQ(
"std::string s5_name = \n "
"wvcdm::a2b_hex("
"\"FA112833FA112833FA112833FA112833FA112833FA112833011428ABFACDEF67\"\n "
" \"011428ABFACDEF67\");\narray[5].name = message_ptr + "
"message.find(s5_name.data());\n",
buffer);
buffer.clear(); // dump_hex_helper appends to buffer
wvoec_mock::dump_array_part_helper(buffer, "array", 5u, "name", NULL, 40u);
ASSERT_EQ("array[5].name = NULL;\n", buffer);
}
TEST_F(OEMCryptoLoggingTest, TestChangeLoggingLevel) {
wvoec_mock::SetLoggingLevel(wvcdm::LOG_WARN);
ASSERT_EQ(wvcdm::LOG_WARN, wvcdm::g_cutoff);
wvoec_mock::SetLoggingLevel(wvcdm::LOG_INFO);
ASSERT_EQ(wvcdm::LOG_INFO, wvcdm::g_cutoff);
wvoec_mock::SetLoggingSettings(wvcdm::LOG_WARN,
wvoec_mock::kLoggingDumpTraceAll);
ASSERT_EQ(wvcdm::LOG_WARN, wvcdm::g_cutoff);
ASSERT_TRUE(wvoec_mock::LogCategoryEnabled(wvoec_mock::kLoggingDumpTraceAll));
wvoec_mock::TurnOffLoggingForAllCategories();
wvoec_mock::SetLoggingLevel(wvcdm::LOG_VERBOSE);
ASSERT_EQ(wvcdm::LOG_VERBOSE, wvcdm::g_cutoff);
wvoec_mock::SetLoggingLevel(wvcdm::LOG_WARN);
}
TEST_F(OEMCryptoLoggingTest, TestChangeLoggingCategories) {
using namespace wvoec_mock;
TurnOffLoggingForAllCategories();
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceDecryption |
kLoggingTraceOEMCryptoCalls));
AddLoggingForCategories(kLoggingDumpKeyControlBlocks |
kLoggingDumpDerivedKeys);
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceUsageTable));
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpTraceAll));
RemoveLoggingForCategories(kLoggingDumpKeyControlBlocks |
kLoggingTraceUsageTable);
ASSERT_FALSE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpDerivedKeys));
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceUsageTable));
TurnOffLoggingForAllCategories();
ASSERT_FALSE(LogCategoryEnabled(kLoggingTraceUsageTable));
AddLoggingForCategories(kLoggingDumpTraceAll);
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceOEMCryptoCalls));
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpContentKeys));
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpDerivedKeys));
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceNonce));
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceDecryption));
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceUsageTable));
ASSERT_TRUE(LogCategoryEnabled(kLoggingTraceDecryptCalls));
ASSERT_TRUE(LogCategoryEnabled(kLoggingDumpTraceAll));
RemoveLoggingForCategories(kLoggingDumpKeyControlBlocks);
ASSERT_FALSE(LogCategoryEnabled(kLoggingDumpKeyControlBlocks));
}

View File

@@ -37,7 +37,6 @@ namespace wvoec3 {
#define Level3_GenerateSignature _lcc13
#define Level3_GenerateNonce _lcc14
#define Level3_RefreshKeys _lcc16
#define Level3_SelectKey _lcc17
#define Level3_RewrapDeviceRSAKey _lcc18
#define Level3_LoadDeviceRSAKey _lcc19
#define Level3_GenerateRSASignature _lcc20
@@ -60,7 +59,6 @@ namespace wvoec3 {
#define Level3_IsAntiRollbackHwPresent _lcc39
#define Level3_CopyBuffer _lcc40
#define Level3_QueryKeyControl _lcc41
#define Level3_LoadTestKeybox _lcc42
#define Level3_ForceDeleteUsageEntry _lcc43
#define Level3_LoadTestRSAKey _lcc45
#define Level3_SecurityPatchLevel _lcc46
@@ -71,7 +69,6 @@ namespace wvoec3 {
#define Level3_IsSRMUpdateSupported _lcc53
#define Level3_GetCurrentSRMVersion _lcc54
#define Level3_LoadSRM _lcc55
#define Level3_LoadKeys_V13 _lcc56
#define Level3_RemoveSRM _lcc57
#define Level3_CreateUsageTableHeader _lcc61
#define Level3_LoadUsageTableHeader _lcc62
@@ -82,6 +79,11 @@ namespace wvoec3 {
#define Level3_MoveEntry _lcc68
#define Level3_CopyOldUsageEntry _lcc69
#define Level3_CreateOldUsageEntry _lcc70
#define Level3_GetAnalogOutputFlags _lcc71
#define Level3_LoadTestKeybox _lcc78
#define Level3_LoadEntitledContentKeys _lcc79
#define Level3_SelectKey _lcc81
#define Level3_LoadKeys _lcc82
#else
#define Level3_Initialize _oecc01
#define Level3_Terminate _oecc02
@@ -97,7 +99,6 @@ namespace wvoec3 {
#define Level3_GenerateSignature _oecc13
#define Level3_GenerateNonce _oecc14
#define Level3_RefreshKeys _oecc16
#define Level3_SelectKey _oecc17
#define Level3_RewrapDeviceRSAKey _oecc18
#define Level3_LoadDeviceRSAKey _oecc19
#define Level3_DeriveKeysFromSessionKey _oecc21
@@ -118,7 +119,6 @@ namespace wvoec3 {
#define Level3_IsAntiRollbackHwPresent _oecc39
#define Level3_CopyBuffer _oecc40
#define Level3_QueryKeyControl _oecc41
#define Level3_LoadTestKeybox _oecc42
#define Level3_ForceDeleteUsageEntry _oecc43
#define Level3_GetHDCPCapability _oecc44
#define Level3_LoadTestRSAKey _oecc45
@@ -131,7 +131,6 @@ namespace wvoec3 {
#define Level3_IsSRMUpdateSupported _oecc53
#define Level3_GetCurrentSRMVersion _oecc54
#define Level3_LoadSRM _oecc55
#define Level3_LoadKeys_V13 _oecc56
#define Level3_RemoveSRM _oecc57
#define Level3_CreateUsageTableHeader _oecc61
#define Level3_LoadUsageTableHeader _oecc62
@@ -143,6 +142,11 @@ namespace wvoec3 {
#define Level3_MoveEntry _oecc68
#define Level3_CopyOldUsageEntry _oecc69
#define Level3_CreateOldUsageEntry _oecc70
#define Level3_GetAnalogOutputFlags _oecc71
#define Level3_LoadTestKeybox _oecc78
#define Level3_LoadEntitledContentKeys _oecc79
#define Level3_SelectKey _oecc81
#define Level3_LoadKeys _oecc82
#endif
#define Level3_GetInitializationState _oecl3o01
@@ -166,14 +170,6 @@ OEMCryptoResult Level3_GenerateSignature(OEMCrypto_SESSION session,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
// TODO(srujzs): Change this to LoadKeys once V14 has been implemented for
// Level 3.
OEMCryptoResult Level3_LoadKeys_V13(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length,
const uint8_t* enc_mac_keys_iv, const uint8_t* enc_mac_keys,
size_t num_keys, const OEMCrypto_KeyObject_V13* key_array,
const uint8_t* pst, size_t pst_length, const uint8_t* srm_requirement);
OEMCryptoResult Level3_RefreshKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
@@ -186,9 +182,6 @@ OEMCryptoResult Level3_QueryKeyControl(OEMCrypto_SESSION session,
size_t key_id_length,
uint8_t* key_control_block,
size_t* key_control_block_length);
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length);
OEMCryptoResult Level3_DecryptCENC(OEMCrypto_SESSION session,
const uint8_t *data_addr,
size_t data_length,
@@ -214,7 +207,6 @@ OEMCrypto_ProvisioningMethod Level3_GetProvisioningMethod();
OEMCryptoResult Level3_GetOEMPublicCertificate(OEMCrypto_SESSION session,
uint8_t *public_cert,
size_t *public_cert_length);
OEMCryptoResult Level3_LoadTestKeybox();
OEMCryptoResult Level3_IsKeyboxValid(void);
OEMCryptoResult Level3_GetDeviceID(uint8_t* deviceID,
size_t *idLength);
@@ -354,7 +346,28 @@ OEMCryptoResult Level3_CreateOldUsageEntry(uint64_t time_since_license_received,
uint8_t *client_mac_key,
const uint8_t* pst,
size_t pst_length);
uint32_t Level3_GetAnalogOutputFlags();
OEMCryptoResult Level3_LoadTestKeybox(const uint8_t *buffer, size_t length);
OEMCryptoResult Level3_LoadEntitledContentKeys(OEMCrypto_SESSION session,
size_t num_keys,
const OEMCrypto_EntitledContentKeyObject* key_array);
OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session,
const uint8_t* key_id,
size_t key_id_length,
OEMCryptoCipherMode cipher_mode);
OEMCryptoResult Level3_LoadKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
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,
size_t pst_length,
const uint8_t* srm_requirement,
OEMCrypto_LicenseType license_type);
/*
* Level3_GetInitializationState
*

View File

@@ -0,0 +1,67 @@
// 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.
#ifndef WV_OEMCRYPTO_TYPES_H_
#define WV_OEMCRYPTO_TYPES_H_
#include <stdint.h>
namespace wvoec {
// This is the format of a Widevine keybox.
typedef struct WidevineKeybox { // 128 bytes total.
// C character string identifying the device. Null terminated.
uint8_t device_id_[32];
// 128 bit AES key assigned to device. Generated by Widevine.
uint8_t device_key_[16];
// Key Data. Encrypted data.
uint8_t data_[72];
// Constant code used to recognize a valid keybox "kbox" = 0x6b626f78.
uint8_t magic_[4];
// The CRC checksum of the first 124 bytes of the keybox.
uint8_t crc_[4];
} WidevineKeybox;
// Key Control Block Bit Masks:
const uint32_t kControlObserveDataPath = (1<<31);
const uint32_t kControlObserveHDCP = (1<<30);
const uint32_t kControlObserveCGMS = (1<<29);
const uint32_t kControlRequireAntiRollbackHardware = (1<<28);
const uint32_t kSharedLicense = (1<<23);
const uint32_t kControlSRMVersionRequired = (1<<22);
const uint32_t kControlDisableAnalogOutput = (1<<21);
const uint32_t kControlSecurityPatchLevelShift = 15;
const uint32_t kControlSecurityPatchLevelMask =
(0x3F<<kControlSecurityPatchLevelShift);
const uint32_t kControlReplayMask = (0x03<<13);
const uint32_t kControlNonceRequired = (0x01<<13);
const uint32_t kControlNonceOrEntry = (0x02<<13);
const uint32_t kControlHDCPVersionShift = 9;
const uint32_t kControlHDCPVersionMask = (0x0F<<kControlHDCPVersionShift);
const uint32_t kControlAllowEncrypt = (1<<8);
const uint32_t kControlAllowDecrypt = (1<<7);
const uint32_t kControlAllowSign = (1<<6);
const uint32_t kControlAllowVerify = (1<<5);
const uint32_t kControlDataPathSecure = (1<<4);
const uint32_t kControlNonceEnabled = (1<<3);
const uint32_t kControlHDCPRequired = (1<<2);
const uint32_t kControlCGMSMask = (0x03);
const uint32_t kControlCGMSCopyFreely = (0x00);
const uint32_t kControlCGMSCopyOnce = (0x02);
const uint32_t kControlCGMSCopyNever = (0x03);
// Various constants and sizes:
static const size_t KEY_CONTROL_SIZE = 16;
static const size_t KEY_ID_SIZE = 16;
static const size_t KEY_IV_SIZE = 16;
static const size_t KEY_PAD_SIZE = 16;
static const size_t KEY_SIZE = 16;
static const size_t MAC_KEY_SIZE = 32;
static const size_t KEYBOX_KEY_DATA_SIZE = 72;
static const size_t SRM_REQUIREMENT_SIZE = 12;
} // namespace wvoec
#endif // WV_OEMCRYPTO_TYPES_H_

View File

@@ -84,12 +84,12 @@ class Unpacked_PST_Report {
int64_t time;
memcpy(&time, buffer_ + kseconds_since_license_received_offset,
sizeof(int64_t));
return wvcdm::ntohll64(time);
return ntohll64(time);
}
// Parameter time is in host byte order.
void set_seconds_since_license_received(int64_t time) const {
time = wvcdm::ntohll64(time);
time = ntohll64(time);
memcpy(buffer_ + kseconds_since_license_received_offset, &time,
sizeof(int64_t));
}
@@ -99,12 +99,12 @@ class Unpacked_PST_Report {
int64_t time;
memcpy(&time, buffer_ + kseconds_since_first_decrypt_offset,
sizeof(int64_t));
return wvcdm::ntohll64(time);
return ntohll64(time);
}
// Parameter time is in host byte order.
void set_seconds_since_first_decrypt(int64_t time) const {
time = wvcdm::ntohll64(time);
time = ntohll64(time);
memcpy(buffer_ + kseconds_since_first_decrypt_offset, &time,
sizeof(int64_t));
}
@@ -114,12 +114,12 @@ class Unpacked_PST_Report {
int64_t time;
memcpy(&time, buffer_ + kseconds_since_last_decrypt_offset,
sizeof(int64_t));
return wvcdm::ntohll64(time);
return ntohll64(time);
}
// Parameter time is in host byte order.
void set_seconds_since_last_decrypt(int64_t time) const {
time = wvcdm::ntohll64(time);
time = ntohll64(time);
memcpy(buffer_ + kseconds_since_last_decrypt_offset, &time,
sizeof(int64_t));
}

View File

@@ -1,4 +1,4 @@
# Mock OEMCrypto
# Reference OEMCrypto
This directory contains a testing-only implementation of OEMCrypto. **This
implementation is *NOT* suitable for production use and should *NOT* be released

View File

@@ -0,0 +1,41 @@
# 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.
# Define oemcrypto_dir and include this in your target.
{
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(util_dir)/include',
'<(oemcrypto_dir)/ref/src',
],
'direct_dependent_settings': {
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/../util/include',
],
},
'sources': [
'<(oemcrypto_dir)/ref/src/keys.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_auth_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_engine_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_key_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_keybox_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_nonce_table.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_old_usage_table_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_rsa_key_shared.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_session.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_session_key_table.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_usage_table_ref.cpp',
'<(oemcrypto_dir)/ref/src/wvcrc.cpp',
# TODO(fredgc) remove these:
'<(oemcrypto_dir)/ref/src/oemcrypto_logging.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_keybox_testkey.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_engine_device_properties.cpp',
],
'dependencies': [
'<(boringssl_dependency)',
],
}

View File

@@ -2,7 +2,7 @@
#include "oem_cert.h"
namespace wvoec_mock {
namespace wvoec_ref {
extern const uint32_t kOEMSystemId_Prod = 7346;
@@ -389,4 +389,4 @@ const uint8_t* kOEMPublicCert = kOEMPublicCert_Prod;
const size_t kOEMPrivateKeySize = kOEMPrivateKeySize_Prod;
const size_t kOEMPublicCertSize = kOEMPublicCertSize_Prod;
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -5,7 +5,7 @@
#include <stddef.h>
#include <stdint.h>
namespace wvoec_mock {
namespace wvoec_ref {
// Refer to the following in main modules
extern const uint32_t kOEMSystemId;
@@ -16,6 +16,6 @@ extern const uint8_t* kOEMPublicCert;
extern const size_t kOEMPrivateKeySize;
extern const size_t kOEMPublicCertSize;
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEM_CERT_H_

View File

@@ -2,18 +2,17 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_auth_mock.h"
#include "oemcrypto_auth_ref.h"
#include <vector>
#include "keys.h"
#include "log.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_logging.h"
#include "oemcrypto_rsa_key_shared.h"
#include "wv_cdm_constants.h"
namespace {
@@ -176,7 +175,7 @@ static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
} // namespace
namespace wvoec_mock {
namespace wvoec_ref {
AuthenticationRoot::AuthenticationRoot(OEMCrypto_ProvisioningMethod method) :
provisioning_method_(method),
@@ -202,4 +201,4 @@ bool AuthenticationRoot::Validate() {
return NO_ERROR == ValidateKeybox();
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,10 +2,10 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_AUTH_MOCK_H_
#define OEMCRYPTO_AUTH_MOCK_H_
#ifndef OEMCRYPTO_AUTH_REF_H_
#define OEMCRYPTO_AUTH_REF_H_
#include <stdint.h>
#include <vector>
@@ -13,12 +13,14 @@
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "oemcrypto_key_mock.h"
#include "oemcrypto_keybox_mock.h"
#include "disallow_copy_and_assign.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_keybox_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "wv_cdm_types.h"
#include "oemcrypto_scoped_ptr.h"
#include "oemcrypto_types.h"
namespace wvoec_mock {
namespace wvoec_ref {
class AuthenticationRoot {
public:
@@ -73,6 +75,6 @@ class AuthenticationRoot {
CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot);
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEMCRYPTO_AUTH_MOCK_H_
#endif // OEMCRYPTO_AUTH_REF_H_

View File

@@ -2,16 +2,16 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
namespace wvoec_mock {
namespace wvoec_ref {
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::auto_ptr<wvcdm::FileSystem> file_system) {
scoped_ptr<wvcdm::FileSystem> file_system) {
return new CryptoEngine(file_system);
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,17 +2,17 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that would be for a
// level 1 device.
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
namespace wvoec_mock {
namespace wvoec_ref {
class L1CryptoEngine : public CryptoEngine {
public:
explicit L1CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
explicit L1CryptoEngine(scoped_ptr<wvcdm::FileSystem> file_system)
: CryptoEngine(file_system) {}
bool config_local_display_only() { return true; }
@@ -31,8 +31,8 @@ class L1CryptoEngine : public CryptoEngine {
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::auto_ptr<wvcdm::FileSystem> file_system) {
scoped_ptr<wvcdm::FileSystem> file_system) {
return new L1CryptoEngine(file_system);
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,20 +2,20 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that would be for a device
// that does not have persistant storage or a keybox.
//
// Note: We also define it to be L2 for illustration only. Production devices
// are rarely level 2.
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
namespace wvoec_mock {
namespace wvoec_ref {
class CertOnlyCryptoEngine : public CryptoEngine {
public:
explicit CertOnlyCryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
explicit CertOnlyCryptoEngine(scoped_ptr<wvcdm::FileSystem> file_system)
: CryptoEngine(file_system) {}
bool config_local_display_only() { return true; }
@@ -30,8 +30,8 @@ class CertOnlyCryptoEngine : public CryptoEngine {
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::auto_ptr<wvcdm::FileSystem> file_system) {
scoped_ptr<wvcdm::FileSystem> file_system) {
return new CertOnlyCryptoEngine(file_system);
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,24 +2,24 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
// This file contains oemcrypto engine properties that would be for a
// level 2 device that does not have persistant storage or a keybox.
// Note: this is for illustration only. Production devices are rarely level 2.
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
#include <string.h>
#include "log.h"
#include "oem_cert.h"
namespace wvoec_mock {
namespace wvoec_ref {
class Prov30CryptoEngine : public CryptoEngine {
public:
explicit Prov30CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
explicit Prov30CryptoEngine(scoped_ptr<wvcdm::FileSystem> file_system)
: CryptoEngine(file_system) {}
bool config_local_display_only() { return true; }
@@ -77,8 +77,8 @@ class Prov30CryptoEngine : public CryptoEngine {
};
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::auto_ptr<wvcdm::FileSystem> file_system) {
scoped_ptr<wvcdm::FileSystem> file_system) {
return new Prov30CryptoEngine(file_system);
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,9 +2,9 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
#include <arpa/inet.h>
#include <assert.h>
@@ -17,19 +17,17 @@
#include "keys.h"
#include "log.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
namespace wvoec_mock {
namespace wvoec_ref {
// Note: The class CryptoEngine is configured at compile time by compiling in
// different device property files. The methods in this file are generic to
// all configurations. See the files oemcrypto_engine_device_properties*.cpp
// for methods that are configured for specific configurations.
CryptoEngine::CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system)
CryptoEngine::CryptoEngine(scoped_ptr<wvcdm::FileSystem> file_system)
: root_of_trust_(config_provisioning_method()),
file_system_(file_system),
usage_table_(this) {
@@ -123,4 +121,4 @@ OEMCryptoResult CryptoEngine::SetDestination(
return OEMCrypto_SUCCESS;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,10 +2,10 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef MOCK_OEMCRYPTO_ENGINE_MOCK_H_
#define MOCK_OEMCRYPTO_ENGINE_MOCK_H_
#ifndef REF_OEMCRYPTO_ENGINE_REF_H_
#define REF_OEMCRYPTO_ENGINE_REF_H_
#include <stdint.h>
#include <time.h>
@@ -18,14 +18,15 @@
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "file_store.h"
#include "lock.h"
#include "oemcrypto_auth_mock.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_scoped_ptr.h"
#include "oemcrypto_session.h"
#include "oemcrypto_usage_table_mock.h"
#include "wv_cdm_types.h"
#include "oemcrypto_usage_table_ref.h"
#include "oemcrypto_types.h"
namespace wvoec_mock {
namespace wvoec_ref {
typedef std::map<SessionId, SessionContext*> ActiveSessions;
@@ -37,7 +38,7 @@ class CryptoEngine {
// NOTE: The caller must instantiate a FileSystem object - ownership
// will be transferred to the new CryptoEngine object.
static CryptoEngine* MakeCryptoEngine(
std::auto_ptr<wvcdm::FileSystem> file_system);
scoped_ptr<wvcdm::FileSystem> file_system);
virtual ~CryptoEngine();
@@ -82,7 +83,7 @@ class CryptoEngine {
size_t GetNumberOfOpenSessions() { return sessions_.size(); }
size_t GetMaxNumberOfSessions() {
// An arbitrary limit for mock implementation.
// An arbitrary limit for ref implementation.
static const size_t kMaxSupportedOEMCryptoSessions = 64;
return kMaxSupportedOEMCryptoSessions;
}
@@ -148,6 +149,9 @@ 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; }
// Set destination pointer based on the output destination description.
OEMCryptoResult SetDestination(OEMCrypto_DestBufferDesc* out_description,
size_t data_length, uint8_t subsample_flags);
@@ -167,19 +171,19 @@ class CryptoEngine {
}
protected:
explicit CryptoEngine(std::auto_ptr<wvcdm::FileSystem> file_system);
explicit CryptoEngine(scoped_ptr<wvcdm::FileSystem> file_system);
uint8_t* destination_;
private:
ActiveSessions sessions_;
AuthenticationRoot root_of_trust_;
wvcdm::Lock session_table_lock_;
std::auto_ptr<wvcdm::FileSystem> file_system_;
scoped_ptr<wvcdm::FileSystem> file_system_;
UsageTable usage_table_;
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // MOCK_OEMCRYPTO_ENGINE_MOCK_H_
#endif // REF_OEMCRYPTO_ENGINE_REF_H_

View File

@@ -2,18 +2,18 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_key_mock.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_types.h"
#include <string.h>
#include <vector>
#include "log.h"
#include "oemcrypto_logging.h"
#include "wv_cdm_constants.h"
namespace wvoec_mock {
namespace wvoec_ref {
bool KeyControlBlock::Validate() {
if (memcmp(verification_, "kctl", 4) && // original verification
@@ -45,15 +45,15 @@ uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str,
KeyControlBlock::KeyControlBlock(
const std::vector<uint8_t>& key_control_string) {
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
if (key_control_string.size() < wvoec::KEY_CONTROL_SIZE) {
LOGE("KCB: BAD Size: %d (not %d)", key_control_string.size(),
wvcdm::KEY_CONTROL_SIZE);
wvoec::KEY_CONTROL_SIZE);
return;
}
memcpy(verification_, &key_control_string[0], 4);
duration_ = ExtractField(key_control_string, 1);
nonce_ = ExtractField(key_control_string, 2);
duration_ = ExtractField(key_control_string, 1);
nonce_ = ExtractField(key_control_string, 2);
control_bits_ = ExtractField(key_control_string, 3);
if (LogCategoryEnabled(kLoggingDumpKeyControlBlocks)) {
LOGD("KCB:");
@@ -63,19 +63,20 @@ KeyControlBlock::KeyControlBlock(
LOGD(" magic: %08X", verification());
LOGD(" bits: %08X", control_bits());
LOGD(" bit kSharedLicense %s.",
(control_bits() & kSharedLicense) ? "set" : "unset");
(control_bits() & wvoec::kSharedLicense) ? "set" : "unset");
LOGD(" bit kControlSRMVersionRequired %s.",
(control_bits() & kControlSRMVersionRequired) ? "set" : "unset");
(control_bits() & wvoec::kControlSRMVersionRequired) ? "set" : "unset");
LOGD(" bit kControlDisableAnalogOutput %s.",
(control_bits() & kControlDisableAnalogOutput) ? "set" : "unset");
(control_bits() & wvoec::kControlDisableAnalogOutput) ? "set"
: "unset");
LOGD(" bits kControlSecurityPatchLevel 0x%02x.",
(control_bits() & kControlSecurityPatchLevelMask)
>> kControlSecurityPatchLevelShift);
switch (control_bits() & kControlReplayMask) {
case kControlNonceRequired:
(control_bits() & wvoec::kControlSecurityPatchLevelMask) >>
wvoec::kControlSecurityPatchLevelShift);
switch (control_bits() & wvoec::kControlReplayMask) {
case wvoec::kControlNonceRequired:
LOGD(" bits kControlReplay kControlNonceRequired.");
break;
case kControlNonceOrEntry:
case wvoec::kControlNonceOrEntry:
LOGD(" bits kControlReplay kControlNonceOrEntry.");
break;
default:
@@ -83,28 +84,28 @@ KeyControlBlock::KeyControlBlock(
break;
}
LOGD(" bits kControlHDCPVersion 0x%02x.",
(control_bits() & kControlHDCPVersionMask)
>> kControlHDCPVersionShift);
(control_bits() & wvoec::kControlHDCPVersionMask) >>
wvoec::kControlHDCPVersionShift);
LOGD(" bit kControlAllowEncrypt %s.",
(control_bits() & kControlAllowEncrypt) ? "set" : "unset");
(control_bits() & wvoec::kControlAllowEncrypt) ? "set" : "unset");
LOGD(" bit kControlAllowDecrypt %s.",
(control_bits() & kControlAllowDecrypt) ? "set" : "unset");
(control_bits() & wvoec::kControlAllowDecrypt) ? "set" : "unset");
LOGD(" bit kControlAllowSign %s.",
(control_bits() & kControlAllowSign) ? "set" : "unset");
(control_bits() & wvoec::kControlAllowSign) ? "set" : "unset");
LOGD(" bit kControlAllowVerify %s.",
(control_bits() & kControlAllowVerify) ? "set" : "unset");
(control_bits() & wvoec::kControlAllowVerify) ? "set" : "unset");
LOGD(" bit kControlObserveDataPath %s.",
(control_bits() & kControlObserveDataPath) ? "set" : "unset");
(control_bits() & wvoec::kControlObserveDataPath) ? "set" : "unset");
LOGD(" bit kControlObserveHDCP %s.",
(control_bits() & kControlObserveHDCP) ? "set" : "unset");
(control_bits() & wvoec::kControlObserveHDCP) ? "set" : "unset");
LOGD(" bit kControlObserveCGMS %s.",
(control_bits() & kControlObserveCGMS) ? "set" : "unset");
(control_bits() & wvoec::kControlObserveCGMS) ? "set" : "unset");
LOGD(" bit kControlDataPathSecure %s.",
(control_bits() & kControlDataPathSecure) ? "set" : "unset");
(control_bits() & wvoec::kControlDataPathSecure) ? "set" : "unset");
LOGD(" bit kControlNonceEnabled %s.",
(control_bits() & kControlNonceEnabled) ? "set" : "unset");
(control_bits() & wvoec::kControlNonceEnabled) ? "set" : "unset");
LOGD(" bit kControlHDCPRequired %s.",
(control_bits() & kControlHDCPRequired) ? "set" : "unset");
(control_bits() & wvoec::kControlHDCPRequired) ? "set" : "unset");
uint32_t cgms_bits = control_bits() & 0x3;
const char* cgms_values[4] = {"free", "BAD", "once", "never"};
LOGD(" CGMS = %s", cgms_values[cgms_bits]);
@@ -118,7 +119,7 @@ void Key::UpdateDuration(const KeyControlBlock& control) {
void KeyControlBlock::RequireLocalDisplay() {
// Set all bits to require HDCP Local Display Only.
control_bits_ |= kControlHDCPVersionMask;
control_bits_ |= wvoec::kControlHDCPVersionMask;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,43 +2,16 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_KEY_MOCK_H_
#define OEMCRYPTO_KEY_MOCK_H_
#ifndef OEMCRYPTO_KEY_REF_H_
#define OEMCRYPTO_KEY_REF_H_
#include <stdint.h>
#include <string>
#include <vector>
namespace wvoec_mock {
const uint32_t kControlObserveDataPath = (1<<31);
const uint32_t kControlObserveHDCP = (1<<30);
const uint32_t kControlObserveCGMS = (1<<29);
const uint32_t kControlRequireAntiRollbackHardware = (1<<28);
const uint32_t kSharedLicense = (1<<23);
const uint32_t kControlSRMVersionRequired = (1<<22);
const uint32_t kControlDisableAnalogOutput = (1<<21);
const uint32_t kControlSecurityPatchLevelShift = 15;
const uint32_t kControlSecurityPatchLevelMask =
(0x3F<<kControlSecurityPatchLevelShift);
const uint32_t kControlReplayMask = (0x03<<13);
const uint32_t kControlNonceRequired = (0x01<<13);
const uint32_t kControlNonceOrEntry = (0x02<<13);
const uint32_t kControlHDCPVersionShift = 9;
const uint32_t kControlHDCPVersionMask = (0x0F<<kControlHDCPVersionShift);
const uint32_t kControlAllowEncrypt = (1<<8);
const uint32_t kControlAllowDecrypt = (1<<7);
const uint32_t kControlAllowSign = (1<<6);
const uint32_t kControlAllowVerify = (1<<5);
const uint32_t kControlDataPathSecure = (1<<4);
const uint32_t kControlNonceEnabled = (1<<3);
const uint32_t kControlHDCPRequired = (1<<2);
const uint32_t kControlCGMSMask = (0x03);
const uint32_t kControlCGMSCopyFreely = (0x00);
const uint32_t kControlCGMSCopyOnce = (0x02);
const uint32_t kControlCGMSCopyNever = (0x03);
namespace wvoec_ref {
class KeyControlBlock {
public:
@@ -109,6 +82,6 @@ class EntitlementKey : public Key {
std::vector<uint8_t> content_key_id_;
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEMCRYPTO_KEY_MOCK_H_
#endif // OEMCRYPTO_KEY_REF_H_

View File

@@ -2,23 +2,23 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_keybox_mock.h"
#include "oemcrypto_keybox_ref.h"
#include <arpa/inet.h> // needed for ntoh()
#include <string.h>
#include <sys/types.h>
#include <string>
#include "log.h"
#include "wv_keybox.h"
#include "oemcrypto_types.h"
#include "wvcrc32.h"
namespace wvoec_mock {
namespace wvoec_ref {
namespace {
const WidevineKeybox kTestKeybox = {
const wvoec::WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID
@@ -69,7 +69,7 @@ KeyboxError WvKeybox::Validate() {
uint32_t crc_stored;
uint8_t* crc_stored_bytes = (uint8_t*) &crc_stored;
memcpy(crc_stored_bytes, crc_, sizeof(crc_));
WidevineKeybox keybox;
wvoec::WidevineKeybox keybox;
memset(&keybox, 0, sizeof(keybox));
memcpy(keybox.device_id_, &device_id_[0], device_id_.size());
memcpy(keybox.device_key_, &device_key_[0], sizeof(keybox.device_key_));
@@ -91,8 +91,8 @@ bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) {
return false;
}
const WidevineKeybox* keybox
= reinterpret_cast<const WidevineKeybox*>(buffer);
const wvoec::WidevineKeybox* keybox
= reinterpret_cast<const wvoec::WidevineKeybox*>(buffer);
size_t device_id_length
= strnlen(reinterpret_cast<const char*>(keybox->device_id_), 32);
device_id_.assign(keybox->device_id_,
@@ -111,4 +111,4 @@ WvTestKeybox::WvTestKeybox() {
sizeof(kTestKeybox));
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,14 +2,14 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_KEYBOX_MOCK_H_
#define OEMCRYPTO_KEYBOX_MOCK_H_
#ifndef OEMCRYPTO_KEYBOX_REF_H_
#define OEMCRYPTO_KEYBOX_REF_H_
#include "oemcrypto_key_mock.h"
#include "oemcrypto_key_ref.h"
namespace wvoec_mock {
namespace wvoec_ref {
const int DEVICE_KEY_LENGTH = 16;
typedef uint8_t WvKeyboxKey[DEVICE_KEY_LENGTH];
@@ -48,6 +48,6 @@ class WvTestKeybox : public WvKeybox {
WvTestKeybox();
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEMCRYPTO_KEYBOX_MOCK_H_
#endif // OEMCRYPTO_KEYBOX_REF_H_

View File

@@ -4,16 +4,16 @@
//
// Test keybox.
#include "oemcrypto_keybox_mock.h"
#include "wv_keybox.h"
#include "oemcrypto_keybox_ref.h"
#include "oemcrypto_types.h"
namespace wvoec_mock {
namespace wvoec_ref {
namespace {
// Note: this is a valid keybox, but it is not accepted by production servers.
// However, it is different from the one used for most of the unit tests.
const WidevineKeybox kKeybox = {
const wvoec::WidevineKeybox kKeybox = {
// Sample keybox used for test vectors
{
// deviceID
@@ -53,4 +53,4 @@ bool WvKeybox::Prepare() {
return true;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -6,7 +6,7 @@
#include <stdio.h>
namespace wvoec_mock {
namespace wvoec_ref {
int logging_category_setting = 0x00;
@@ -49,7 +49,7 @@ void dump_hex_helper(std::string& buffer, std::string name,
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
for (size_t i = 0; i < length; i++) {
if (i == 0) {
buffer += "\n wvcdm::a2b_hex(\"";
buffer += "\n a2b_hex(\"";
} else if (i % 32 == 0) {
buffer += "\"\n \"";
}
@@ -103,4 +103,4 @@ void dump_array_part(std::string array, size_t index, std::string name,
LOGV(buffer.c_str());
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -11,7 +11,7 @@
#include "OEMCryptoCENC.h"
#include "log.h"
namespace wvoec_mock {
namespace wvoec_ref {
// The constants below represent integers with a single "on" bit that
// represents categories of logging This allows users to specify with
@@ -62,6 +62,6 @@ void dump_array_part_helper(std::string& buffer, std::string array,
void dump_array_part(std::string array, size_t index, std::string name,
const uint8_t* vector, size_t length);
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif

View File

@@ -2,11 +2,11 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_nonce_table.h"
namespace wvoec_mock {
namespace wvoec_ref {
void NonceTable::AddNonce(uint32_t nonce) {
int new_slot = -1;
@@ -66,4 +66,4 @@ void NonceTable::Flush() {
}
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,14 +2,14 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef MOCK_OEMCRYPTO_NONCE_TABLE_H_
#define MOCK_OEMCRYPTO_NONCE_TABLE_H_
#ifndef REF_OEMCRYPTO_NONCE_TABLE_H_
#define REF_OEMCRYPTO_NONCE_TABLE_H_
#include <stdint.h>
namespace wvoec_mock {
namespace wvoec_ref {
class NonceTable {
public:
@@ -35,6 +35,6 @@ class NonceTable {
uint32_t nonces_[kTableSize];
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // MOCK_OEMCRYPTO_NONCE_TABLE_H_
#endif // REF_OEMCRYPTO_NONCE_TABLE_H_

View File

@@ -2,12 +2,12 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref 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_mock.h"
#include "oemcrypto_old_usage_table_ref.h"
#include <string.h>
#include <time.h>
@@ -22,14 +22,15 @@
#include "file_store.h"
#include "log.h"
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
#include "oemcrypto_logging.h"
#include "properties.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"
#include "wv_cdm_constants.h"
namespace wvoec_mock {
namespace wvoec_ref {
OldUsageTableEntry::OldUsageTableEntry(const std::vector<uint8_t> &pst_hash)
: pst_hash_(pst_hash),
@@ -47,9 +48,9 @@ OldUsageTableEntry::OldUsageTableEntry(const OldStoredUsageEntry *buffer) {
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);
buffer->mac_key_server + wvoec::MAC_KEY_SIZE);
mac_key_client_.assign(buffer->mac_key_client,
buffer->mac_key_client + wvcdm::MAC_KEY_SIZE);
buffer->mac_key_client + wvoec::MAC_KEY_SIZE);
}
OldUsageTable::OldUsageTable(CryptoEngine *ce) {
@@ -58,16 +59,17 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) {
table_.clear();
// Load saved table.
wvcdm::FileSystem* file_system = ce->file_system();
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)) {
// 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)) {
if (LogCategoryEnabled(kLoggingTraceUsageTable)) {
@@ -119,14 +121,14 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) {
}
// Next, decrypt the table.
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted_table->iv, wvcdm::KEY_IV_SIZE);
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 + 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);
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
@@ -176,7 +178,8 @@ OldUsageTableEntry *OldUsageTable::FindEntry(const std::vector<uint8_t> &pst) {
return FindEntryLocked(pst);
}
OldUsageTableEntry *OldUsageTable::FindEntryLocked(const std::vector<uint8_t> &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.");
@@ -189,7 +192,8 @@ OldUsageTableEntry *OldUsageTable::FindEntryLocked(const std::vector<uint8_t> &p
return it->second;
}
OldUsageTableEntry *OldUsageTable::CreateEntry(const std::vector<uint8_t> &pst) {
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.");
@@ -210,15 +214,16 @@ void OldUsageTable::Clear() {
}
void OldUsageTable::DeleteFile(CryptoEngine *ce) {
wvcdm::FileSystem* file_system = ce->file_system();
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)) {
// 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)) {
@@ -228,7 +233,7 @@ void OldUsageTable::DeleteFile(CryptoEngine *ce) {
}
bool OldUsageTable::ComputeHash(const std::vector<uint8_t> &pst,
std::vector<uint8_t> &pst_hash) {
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);
@@ -239,4 +244,4 @@ bool OldUsageTable::ComputeHash(const std::vector<uint8_t> &pst,
return true;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -1,26 +1,26 @@
// 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.
// 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.
//
// Mock implementation of OEMCrypto APIs
// Ref 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_
#ifndef OEMCRYPTO_OLD_USAGE_TABLE_REF_H_
#define OEMCRYPTO_OLD_USAGE_TABLE_REF_H_
#include <stdint.h>
#include <map>
#include <string>
#include <vector>
#include "lock.h"
#include "OEMCryptoCENC.h"
#include "lock.h"
#include "oemcrypto_types.h"
#include "openssl/sha.h"
#include "wv_cdm_constants.h"
namespace wvoec_mock {
namespace wvoec_ref {
class CryptoEngine;
class UsagetTableEntry;
@@ -32,8 +32,8 @@ struct OldStoredUsageEntry {
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];
uint8_t mac_key_server[wvoec::MAC_KEY_SIZE];
uint8_t mac_key_client[wvoec::MAC_KEY_SIZE];
};
typedef union {
@@ -43,7 +43,7 @@ typedef union {
struct OldStoredUsageTable {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[wvcdm::KEY_IV_SIZE];
uint8_t iv[wvoec::KEY_IV_SIZE];
int64_t generation;
uint64_t count;
AlignedOldStoredUsageEntry entries[];
@@ -90,6 +90,6 @@ class OldUsageTable {
CryptoEngine *ce_;
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEMCRYPTO_OLD_USAGE_TABLE_MOCK_H_
#endif // OEMCRYPTO_OLD_USAGE_TABLE_REF_H_

View File

@@ -15,18 +15,18 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <iostream>
#include <string>
#include <vector>
#include "file_store.h"
#include "log.h"
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
#include "oemcrypto_logging.h"
#include "oemcrypto_session.h"
#include "oemcrypto_usage_table_mock.h"
#include "oemcrypto_usage_table_ref.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
namespace {
const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF};
@@ -38,7 +38,7 @@ uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) {
uint32_t value;
const uint8_t* src = reinterpret_cast<const uint8_t*>(unaligned_ptr);
uint8_t* dest = reinterpret_cast<uint8_t*>(&value);
for (unsigned long i=0; i < sizeof(value); i++) {
for (unsigned long i = 0; i < sizeof(value); i++) {
dest[i] = src[i];
}
return value;
@@ -46,14 +46,14 @@ uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) {
} // namespace
namespace wvoec_mock {
namespace wvoec_ref {
static CryptoEngine* crypto_engine = NULL;
typedef struct {
uint8_t signature[wvcdm::MAC_KEY_SIZE];
uint8_t context[wvcdm::MAC_KEY_SIZE];
uint8_t iv[wvcdm::KEY_IV_SIZE];
uint8_t signature[wvoec::MAC_KEY_SIZE];
uint8_t context[wvoec::MAC_KEY_SIZE];
uint8_t iv[wvoec::KEY_IV_SIZE];
uint8_t enc_rsa_key[];
} WrappedRSAKey;
@@ -68,7 +68,7 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
}
// NOTE: This requires a compatible Filesystem implementation.
// NOTE: Ownership of the FileSystem object is transferred to CryptoEngine
std::auto_ptr<wvcdm::FileSystem> fs(new wvcdm::FileSystem());
scoped_ptr<wvcdm::FileSystem> fs(new wvcdm::FileSystem());
crypto_engine = CryptoEngine::MakeCryptoEngine(fs);
if (!crypto_engine || !crypto_engine->Initialize()) {
@@ -102,8 +102,9 @@ extern "C" OEMCryptoResult OEMCrypto_Terminate(void) {
extern "C" OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_OpenSession"
"(OEMCrypto_SESSION *session)\n");
LOGI(
"-- OEMCryptoResult OEMCrypto_OpenSession"
"(OEMCrypto_SESSION *session)\n");
}
if (!crypto_engine) {
LOGE("OEMCrypto_OpenSession: OEMCrypto not initialized.");
@@ -117,15 +118,16 @@ extern "C" OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session) {
SessionId sid = crypto_engine->CreateSession();
*session = (OEMCrypto_SESSION)sid;
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGD("[OEMCrypto_OpenSession(): SID=%08X]", sid);
LOGD("[OEMCrypto_OpenSession(): SID=%08x]", sid);
}
return OEMCrypto_SUCCESS;
}
extern "C" OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_CloseSession"
"(OEMCrypto_SESSION session)\n");
LOGI(
"-- OEMCryptoResult OEMCrypto_CloseSession"
"(OEMCrypto_SESSION session)\n");
}
if (!crypto_engine) {
LOGE("OEMCrypto_CloseSession: OEMCrypto not initialized.");
@@ -198,11 +200,19 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
return OEMCrypto_SUCCESS;
}
static const uint64_t one_second = 1000000ull;
static uint64_t TimeStamp(void) {
struct timeval tv;
gettimeofday(&tv,NULL);
return tv.tv_sec * one_second + tv.tv_usec;
}
extern "C" OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
uint32_t* nonce) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_GenerateNonce"
"(OEMCrypto_SESSION session,\n");
LOGI(
"-- OEMCryptoResult OEMCrypto_GenerateNonce"
"(OEMCrypto_SESSION session,\n");
}
if (!crypto_engine) {
LOGE("OEMCrypto_GenerateNonce: OEMCrypto not initialized.");
@@ -215,12 +225,15 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
}
// Prevent nonce flood.
static time_t last_nonce_time = 0;
static int nonce_count = 0;
time_t now = time(NULL);
if (now == last_nonce_time) {
uint64_t now = TimeStamp();
static uint64_t last_nonce_time = now;
// For testing, we set nonce_flood_count to 1. Since count is initialized to
// 1, the very first nonce after initialization is counted as a flood.
static int nonce_count = 1;
if (now - last_nonce_time < one_second) {
nonce_count++;
if (nonce_count > 20) {
if (nonce_count > crypto_engine->nonce_flood_count()) {
LOGE("[OEMCrypto_GenerateNonce(): Nonce Flood detected]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -240,7 +253,7 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
session_ctx->AddNonce(nonce_value);
*nonce = nonce_value;
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("nonce = %08X\n", nonce_value);
LOGI("nonce = %08x\n", nonce_value);
}
return OEMCrypto_SUCCESS;
}
@@ -311,23 +324,23 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("message", message, message_length);
dump_hex("signature", signature, signature_length);
dump_hex("enc_mac_key_iv", enc_mac_key_iv, wvcdm::KEY_IV_SIZE);
dump_hex("enc_mac_keys", enc_mac_keys, 2 * wvcdm::MAC_KEY_SIZE);
dump_hex("enc_mac_key_iv", enc_mac_key_iv, wvoec::KEY_IV_SIZE);
dump_hex("enc_mac_keys", enc_mac_keys, 2 * wvoec::MAC_KEY_SIZE);
dump_hex("pst", pst, pst_length);
dump_hex("srm_requirement", srm_requirement, wvcdm::KEY_CONTROL_SIZE);
dump_hex("srm_requirement", srm_requirement, wvoec::KEY_CONTROL_SIZE);
for (size_t i = 0; i < num_keys; i++) {
LOGV("key_array[%zu].key_id_length=%zu;\n", i,
key_array[i].key_id_length);
dump_array_part("key_array", i, "key_id", key_array[i].key_id,
key_array[i].key_id_length);
dump_array_part("key_array", i, "key_data_iv", key_array[i].key_data_iv,
wvcdm::KEY_IV_SIZE);
wvoec::KEY_IV_SIZE);
dump_array_part("key_array", i, "key_data", key_array[i].key_data,
key_array[i].key_data_length);
dump_array_part("key_array", i, "key_control_iv",
key_array[i].key_control_iv, wvcdm::KEY_IV_SIZE);
key_array[i].key_control_iv, wvoec::KEY_IV_SIZE);
dump_array_part("key_array", i, "key_control", key_array[i].key_control,
wvcdm::KEY_IV_SIZE);
wvoec::KEY_IV_SIZE);
}
}
}
@@ -357,15 +370,15 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
}
// Range check
if (!RangeCheck(message, message_length, enc_mac_keys,
2 * wvcdm::MAC_KEY_SIZE, true) ||
!RangeCheck(message, message_length, enc_mac_key_iv, wvcdm::KEY_IV_SIZE,
if (!RangeCheck(message, message_length, enc_mac_keys, 2 * wvoec::MAC_KEY_SIZE,
true) ||
!RangeCheck(message, message_length, enc_mac_key_iv, wvoec::KEY_IV_SIZE, true) ||
!RangeCheck(message, message_length, pst, pst_length, true) ||
!RangeCheck(message, message_length, srm_requirement,
wvcdm::SRM_REQUIREMENT_SIZE, true)) {
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range "
"check.]");
wvoec::SRM_REQUIREMENT_SIZE, true)) {
LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range "
"check.]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -375,13 +388,15 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
!RangeCheck(message, message_length, key_array[i].key_data,
key_array[i].key_data_length, false) ||
!RangeCheck(message, message_length, key_array[i].key_data_iv,
wvcdm::KEY_IV_SIZE, false) ||
wvoec::KEY_IV_SIZE, false) ||
!RangeCheck(message, message_length, key_array[i].key_control,
wvcdm::KEY_CONTROL_SIZE, false) ||
wvoec::KEY_CONTROL_SIZE, false) ||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
wvcdm::KEY_IV_SIZE, false)) {
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range "
"check %d]", i);
wvoec::KEY_IV_SIZE, false)) {
LOGE(
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range "
"check %d]",
i);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
}
@@ -392,8 +407,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
}
extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
OEMCrypto_SESSION session,
size_t num_keys,
OEMCrypto_SESSION session, size_t num_keys,
const OEMCrypto_EntitledContentKeyObject* key_array) {
if (num_keys == 0) {
LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty.");
@@ -450,9 +464,9 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
if (!RangeCheck(message, message_length, key_array[i].key_id,
key_array[i].key_id_length, true) ||
!RangeCheck(message, message_length, key_array[i].key_control,
wvcdm::KEY_CONTROL_SIZE, false) ||
wvoec::KEY_CONTROL_SIZE, false) ||
!RangeCheck(message, message_length, key_array[i].key_control_iv,
wvcdm::KEY_IV_SIZE, true)) {
wvoec::KEY_IV_SIZE, true)) {
LOGE("[OEMCrypto_RefreshKeys(): Range Check %d]", i);
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -475,12 +489,12 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
key_id.assign(key_array[i].key_id,
key_array[i].key_id + key_array[i].key_id_length);
key_control.assign(key_array[i].key_control,
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
key_array[i].key_control + wvoec::KEY_CONTROL_SIZE);
if (key_array[i].key_control_iv == NULL) {
key_control_iv.clear();
} else {
key_control_iv.assign(key_array[i].key_control_iv,
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
key_array[i].key_control_iv + wvoec::KEY_IV_SIZE);
}
} else {
// key_id could be null if special control key type
@@ -488,7 +502,7 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
key_id.clear();
key_control_iv.clear();
key_control.assign(key_array[i].key_control,
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
key_array[i].key_control + wvoec::KEY_CONTROL_SIZE);
}
status = session_ctx->RefreshKey(key_id, key_control, key_control_iv);
@@ -520,14 +534,15 @@ extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl(
}
uint32_t* block = reinterpret_cast<uint32_t*>(key_control_block);
if ((key_control_block_length == NULL) ||
(*key_control_block_length < wvcdm::KEY_CONTROL_SIZE)) {
(*key_control_block_length < wvoec::KEY_CONTROL_SIZE)) {
LOGE("[OEMCrypto_QueryKeyControl(): OEMCrypto_ERROR_SHORT_BUFFER]");
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*key_control_block_length = wvcdm::KEY_CONTROL_SIZE;
*key_control_block_length = wvoec::KEY_CONTROL_SIZE;
if (key_id == NULL) {
LOGE("[OEMCrypto_QueryKeyControl(): key_id null. "
"OEMCrypto_ERROR_UNKNOWN_FAILURE]");
LOGE(
"[OEMCrypto_QueryKeyControl(): key_id null. "
"OEMCrypto_ERROR_UNKNOWN_FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -690,8 +705,8 @@ extern "C" OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
return OEMCrypto_ERROR_WRITE_KEYBOX;
}
extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox(
const uint8_t* buffer, size_t length) {
extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
size_t length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_LoadTestKeybox()\n");
}
@@ -869,7 +884,7 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
dump_hex("encrypted_message_key", encrypted_message_key,
encrypted_message_key_length);
dump_hex("enc_rsa_key", enc_rsa_key, enc_rsa_key_length);
dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
}
}
if (!crypto_engine) {
@@ -918,8 +933,9 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
if (!session_ctx->InstallRSAEncryptedKey(encrypted_message_key,
encrypted_message_key_length)) {
LOGE("OEMCrypto_RewrapDeviceRSAKey30: "
"Error loading encrypted_message_key.");
LOGE(
"OEMCrypto_RewrapDeviceRSAKey30: "
"Error loading encrypted_message_key.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -931,9 +947,10 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): "
"Encrypted RSA has bad padding: %d]",
padding);
LOGE(
"[OEMCrypto_RewrapDeviceRSAKey30(): "
"Encrypted RSA has bad padding: %d]",
padding);
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
@@ -973,7 +990,8 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
unsigned int sig_length = sizeof(wrapped->signature);
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
LOGI(("message verified with HMAC and mac_key_server, key = " +
wvcdm::b2a_hex(session_ctx->mac_key_server())).c_str());
wvcdm::b2a_hex(session_ctx->mac_key_server()))
.c_str());
}
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
session_ctx->mac_key_server().size(), wrapped->context,
@@ -996,7 +1014,7 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
const uint8_t* signature, size_t signature_length,
const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key,
size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv,
uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) {
uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) {
uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce);
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls | kLoggingTraceNonce)) {
LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(%d)\n", session);
@@ -1012,7 +1030,7 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
}
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("enc_rsa_key", enc_rsa_key, enc_rsa_key_length);
dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
}
}
if (!crypto_engine) {
@@ -1061,8 +1079,7 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
sizeof(uint32_t), true) ||
!RangeCheck(message, message_length, enc_rsa_key, enc_rsa_key_length,
true) ||
!RangeCheck(message, message_length, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE,
true)) {
!RangeCheck(message, message_length, enc_rsa_key_iv, wvoec::KEY_IV_SIZE, true)) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): - range check.]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -1122,7 +1139,8 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
unsigned int sig_length = sizeof(wrapped->signature);
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
LOGI(("message verified with HMAC and mac_key_server, key = " +
wvcdm::b2a_hex(session_ctx->mac_key_server())).c_str());
wvcdm::b2a_hex(session_ctx->mac_key_server()))
.c_str());
}
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
session_ctx->mac_key_server().size(), wrapped->context,
@@ -1382,7 +1400,7 @@ extern "C" OEMCryptoResult OEMCrypto_GetHDCPCapability(
}
extern "C" uint32_t OEMCrypto_GetAnalogOutputFlags() {
// TODO(b/69867568, fredgc): parameterize this.
// TODO(b/69867568, fredgc): parameterize this.
return 0;
}
@@ -1452,7 +1470,7 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt(
algorithm);
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("in_buffer", in_buffer, buffer_length);
dump_hex("iv", iv, wvcdm::KEY_IV_SIZE);
dump_hex("iv", iv, wvoec::KEY_IV_SIZE);
}
}
if (!crypto_engine) {
@@ -1491,7 +1509,7 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Decrypt(
algorithm);
if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) {
dump_hex("in_buffer", in_buffer, buffer_length);
dump_hex("iv", iv, wvcdm::KEY_IV_SIZE);
dump_hex("iv", iv, wvoec::KEY_IV_SIZE);
}
}
if (!crypto_engine) {
@@ -1670,9 +1688,10 @@ extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
return sts;
}
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(
OEMCrypto_SESSION, const uint8_t*, size_t, const uint8_t*, size_t,
const uint8_t*, size_t) {
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION,
const uint8_t*, size_t,
const uint8_t*, size_t,
const uint8_t*, size_t) {
// TODO(fredgc): delete this.
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
@@ -1757,8 +1776,7 @@ extern "C" OEMCryptoResult OEMCrypto_RemoveSRM() {
}
extern "C" OEMCryptoResult OEMCrypto_CreateUsageTableHeader(
uint8_t* header_buffer,
size_t* header_buffer_length) {
uint8_t* header_buffer, size_t* header_buffer_length) {
if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) {
LOGI("-- OEMCryptoResult OEMCrypto_CreateUsageTableHeader()\n");
}
@@ -1770,8 +1788,8 @@ extern "C" OEMCryptoResult OEMCrypto_CreateUsageTableHeader(
LOGE("OEMCrypto_CreateUsageTableHeader: Configured without Usage Tables.");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
return crypto_engine->usage_table()
.CreateUsageTableHeader(header_buffer, header_buffer_length);
return crypto_engine->usage_table().CreateUsageTableHeader(
header_buffer, header_buffer_length);
}
extern "C" OEMCryptoResult OEMCrypto_LoadUsageTableHeader(
@@ -1932,15 +1950,11 @@ extern "C" OEMCryptoResult OEMCrypto_CopyOldUsageEntry(
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) {
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");
}
@@ -1957,4 +1971,4 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(uint64_t time_since_license_receiv
pst_length);
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,7 +2,7 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_rsa_key_shared.h"
@@ -16,7 +16,7 @@
#include "oemcrypto_logging.h"
namespace wvoec_mock {
namespace wvoec_ref {
void dump_boringssl_error() {
int count = 0;
@@ -98,4 +98,4 @@ bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
}
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,7 +2,7 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_RSA_KEY_SHARED_H_
#define OEMCRYPTO_RSA_KEY_SHARED_H_
@@ -11,7 +11,7 @@
#include <openssl/rsa.h>
namespace wvoec_mock {
namespace wvoec_ref {
// Shared pointer with specialized destructor. This pointer is only shared
// from a CryptoEngine to a Session -- so we don't have to use full reference
@@ -37,6 +37,6 @@ class RSA_shared_ptr {
// Log errors from BoringSSL.
void dump_boringssl_error();
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEMCRYPTO_RSA_KEY_SHARED_H_

View File

@@ -0,0 +1,44 @@
#ifndef OEMCRYPTO_SCOPED_PTR_H_
#define OEMCRYPTO_SCOPED_PTR_H_
#include <stddef.h>
#include <memory>
#include <arpa/inet.h>
namespace wvoec_ref {
// TODO(fredgc, jfore): scoped_ptr may not be the best name for this smart
// pointer type. It basically works like auto_ptr which is deprecated.
#if __cplusplus < 201103L
template <typename T>
class scoped_ptr {
public:
explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
T* get() const { return ptr_.get(); }
private:
std::auto_ptr<T> ptr_;
};
#else
template <typename T>
class scoped_ptr {
public:
explicit scoped_ptr(T* p = nullptr) : ptr_(p) {}
scoped_ptr(scoped_ptr& r) { ptr_ = std::move(r.ptr_); }
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_.get(); }
T* get() const { return ptr_.get(); }
void reset(T* p = NULL) { ptr_.reset(); }
private:
std::unique_ptr<T> ptr_;
};
#endif
} // namespace wvoec_ref
#endif // OEMCRYPTO_SCOPED_PTR_H_

View File

@@ -2,7 +2,7 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_session.h"
@@ -26,12 +26,13 @@
#include "keys.h"
#include "log.h"
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_engine_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_logging.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_types.h"
#include "disallow_copy_and_assign.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
static const int kPssSaltLength = 20;
@@ -47,7 +48,7 @@ void ctr128_inc64(uint8_t* counter) {
}
} // namespace
namespace wvoec_mock {
namespace wvoec_ref {
/***************************************/
@@ -285,7 +286,7 @@ bool SessionContext::RSADeriveKeys(
return false;
}
session_key_.resize(decrypted_size);
if (decrypted_size != static_cast<int>(wvcdm::KEY_SIZE)) {
if (decrypted_size != static_cast<int>(wvoec::KEY_SIZE)) {
LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]",
decrypted_size);
dump_boringssl_error();
@@ -306,16 +307,7 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
return false;
}
const uint8_t* mac_key = NULL;
bool using_usage_mac_key_client = false;
if (mac_key_client_.size() == wvcdm::MAC_KEY_SIZE) {
// If we have a mac key, use it.
mac_key = &mac_key_client_[0];
} else if (usage_entry_status_ == kUsageEntryLoaded) {
// If not, but we have a usage entry, use its key.
mac_key = usage_entry_->mac_key_client();
using_usage_mac_key_client = true;
} else {
if (mac_key_client_.size() != wvoec::MAC_KEY_SIZE) {
return false;
}
@@ -324,11 +316,17 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
return false;
}
if (using_usage_mac_key_client &&
LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
std::vector<uint8_t> usage_entry_mac_key_client(
bool using_usage_entry_mac_key_client = false;
std::vector<uint8_t> usage_entry_mac_key_client;
if (usage_entry_status_ == kUsageEntryLoaded) {
usage_entry_mac_key_client.assign(
usage_entry_->mac_key_client(),
usage_entry_->mac_key_client() + wvcdm::MAC_KEY_SIZE * sizeof(uint8_t));
usage_entry_->mac_key_client() + wvoec::MAC_KEY_SIZE * sizeof(uint8_t));
using_usage_entry_mac_key_client =
mac_key_client_ == usage_entry_mac_key_client;
}
if (using_usage_entry_mac_key_client &&
LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
LOGI(("message signed with HMAC and usage_entry_'s mac_key_client, "
"mac_key_client = " +
wvcdm::b2a_hex(usage_entry_mac_key_client)).c_str());
@@ -338,8 +336,8 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
}
unsigned int md_len = *signature_length;
if (HMAC(EVP_sha256(), mac_key, wvcdm::MAC_KEY_SIZE, message, message_length,
signature, &md_len)) {
if (HMAC(EVP_sha256(), &mac_key_client_[0], wvoec::MAC_KEY_SIZE, message,
message_length, signature, &md_len)) {
*signature_length = md_len;
return true;
}
@@ -455,7 +453,7 @@ bool SessionContext::ValidateMessage(const uint8_t* given_message,
OEMCryptoResult SessionContext::CheckStatusOnline(uint32_t nonce,
uint32_t control) {
if (!(control & kControlNonceEnabled)) {
if (!(control & wvoec::kControlNonceEnabled)) {
LOGE("LoadKeys: Server provided Nonce_Required but Nonce_Enabled = 0.");
// Server error. Continue, and assume nonce required.
}
@@ -476,7 +474,7 @@ OEMCryptoResult SessionContext::CheckStatusOnline(uint32_t nonce,
OEMCryptoResult SessionContext::CheckStatusOffline(uint32_t nonce,
uint32_t control) {
if (control & kControlNonceEnabled) {
if (control & wvoec::kControlNonceEnabled) {
LOGE("KCB: Server provided NonceOrEntry but Nonce_Enabled = 1.");
// Server error. Continue, and assume nonce required.
}
@@ -498,17 +496,17 @@ OEMCryptoResult SessionContext::CheckStatusOffline(uint32_t nonce,
OEMCryptoResult SessionContext::CheckNonceOrEntry(
const KeyControlBlock& key_control_block) {
switch (key_control_block.control_bits() & kControlReplayMask) {
case kControlNonceRequired: // Online license. Nonce always required.
switch (key_control_block.control_bits() & wvoec::kControlReplayMask) {
case wvoec::kControlNonceRequired: // Online license. Nonce always required.
return CheckStatusOnline(key_control_block.nonce(),
key_control_block.control_bits());
break;
case kControlNonceOrEntry: // Offline license. Nonce required on first use.
case wvoec::kControlNonceOrEntry: // Offline license. Nonce required on first use.
return CheckStatusOffline(key_control_block.nonce(),
key_control_block.control_bits());
break;
default:
if ((key_control_block.control_bits() & kControlNonceEnabled) &&
if ((key_control_block.control_bits() & wvoec::kControlNonceEnabled) &&
(!CheckNonce(key_control_block.nonce()))) {
LOGE("LoadKeys: BAD Nonce");
return OEMCrypto_ERROR_INVALID_NONCE;
@@ -602,15 +600,15 @@ OEMCryptoResult SessionContext::LoadKeys(
enc_key_data.assign(key_array[i].key_data,
key_array[i].key_data + key_array[i].key_data_length);
key_data_iv.assign(key_array[i].key_data_iv,
key_array[i].key_data_iv + wvcdm::KEY_IV_SIZE);
key_array[i].key_data_iv + wvoec::KEY_IV_SIZE);
if (key_array[i].key_control == NULL) {
status = OEMCrypto_ERROR_UNKNOWN_FAILURE;
break;
}
key_control.assign(key_array[i].key_control,
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
key_array[i].key_control + wvoec::KEY_CONTROL_SIZE);
key_control_iv.assign(key_array[i].key_control_iv,
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
key_array[i].key_control_iv + wvoec::KEY_IV_SIZE);
OEMCryptoResult result =
InstallKey(key_id, enc_key_data, key_data_iv, key_control,
@@ -627,9 +625,9 @@ OEMCryptoResult SessionContext::LoadKeys(
if (enc_mac_keys != NULL) {
// V2.1 license protocol: update mac keys after processing license response
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
enc_mac_keys, enc_mac_keys + 2 * wvcdm::MAC_KEY_SIZE);
enc_mac_keys, enc_mac_keys + 2 * wvoec::MAC_KEY_SIZE);
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
enc_mac_key_iv, enc_mac_key_iv + wvoec::KEY_IV_SIZE);
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
LOGE("Failed to update mac keys.\n");
@@ -766,14 +764,14 @@ OEMCryptoResult SessionContext::InstallKey(
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if ((key_control_block.control_bits() &
kControlRequireAntiRollbackHardware) &&
wvoec::kControlRequireAntiRollbackHardware) &&
!ce_->config_is_anti_rollback_hw_present()) {
LOGE("Anti-rollback hardware is required but hardware not present.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t minimum_patch_level =
(key_control_block.control_bits() & kControlSecurityPatchLevelMask) >>
kControlSecurityPatchLevelShift;
(key_control_block.control_bits() & wvoec::kControlSecurityPatchLevelMask) >>
wvoec::kControlSecurityPatchLevelShift;
if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) {
LOGE("[InstallKey(): security patch level: %d. Minimum:%d]",
OEMCrypto_Security_Patch_Level(), minimum_patch_level);
@@ -784,13 +782,13 @@ OEMCryptoResult SessionContext::InstallKey(
LOGE("LoadKeys: Failed Nonce/PST check.");
return result;
}
if (key_control_block.control_bits() & kSharedLicense) {
if (key_control_block.control_bits() & wvoec::kSharedLicense) {
if (!second_license) {
LOGE("LoadKeys: Shared License, but no keys previously loaded.");
return OEMCrypto_ERROR_MISSING_MASTER;
}
}
if (key_control_block.control_bits() & kControlSRMVersionRequired) {
if (key_control_block.control_bits() & wvoec::kControlSRMVersionRequired) {
if (srm_requirements_status_ == NoSRMVersion) {
LOGE("[LoadKeys: control bit says SRM version required]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
@@ -821,7 +819,7 @@ bool SessionContext::InstallRSAEncryptedKey(
return false;
}
encryption_key_.resize(decrypted_size);
if (decrypted_size != static_cast<int>(wvcdm::KEY_SIZE)) {
if (decrypted_size != static_cast<int>(wvoec::KEY_SIZE)) {
LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]",
decrypted_size);
dump_boringssl_error();
@@ -844,7 +842,7 @@ OEMCryptoResult SessionContext::RefreshKey(
LOGE("Parse key control error.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if ((key_control_block.control_bits() & kControlNonceEnabled) &&
if ((key_control_block.control_bits() & wvoec::kControlNonceEnabled) &&
(!CheckNonce(key_control_block.nonce()))) {
LOGE("KCB: BAD Nonce");
return OEMCrypto_ERROR_INVALID_NONCE;
@@ -899,7 +897,7 @@ OEMCryptoResult SessionContext::RefreshKey(
}
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if ((key_control_block.control_bits() & kControlNonceEnabled) &&
if ((key_control_block.control_bits() & wvoec::kControlNonceEnabled) &&
(!CheckNonce(key_control_block.nonce()))) {
LOGE("KCB: BAD Nonce");
return OEMCrypto_ERROR_INVALID_NONCE;
@@ -913,8 +911,8 @@ bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
const uint8_t* enc_rsa_key_iv,
uint8_t* pkcs8_rsa_key) {
// Decrypt rsa key with keybox.
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key);
AES_cbc_encrypt(enc_rsa_key, pkcs8_rsa_key, enc_rsa_key_length, &aes_key,
@@ -927,8 +925,8 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
const uint8_t* enc_rsa_key_iv,
uint8_t* enc_rsa_key) {
// Encrypt rsa key with keybox.
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key);
AES_cbc_encrypt(pkcs8_rsa_key, enc_rsa_key, enc_rsa_key_length, &aes_key,
@@ -963,14 +961,14 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
LOGE("[%s(): control bit says not allowed.", log_string.c_str());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (control.control_bits() & kControlDataPathSecure) {
if (control.control_bits() & wvoec::kControlDataPathSecure) {
if (!ce_->config_closed_platform() &&
buffer_type == OEMCrypto_BufferType_Clear) {
LOGE("[%s(): Secure key with insecure buffer]", log_string.c_str());
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
}
if (control.control_bits() & kControlReplayMask) {
if (control.control_bits() & wvoec::kControlReplayMask) {
if (!CheckUsageEntry()) {
LOGE("[%s(): usage entry not valid]", log_string.c_str());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -985,10 +983,10 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
if (!ce_->config_local_display_only()) {
// Only look at HDCP and Analog restrictions if the display can be
// non-local.
if (control.control_bits() & kControlHDCPRequired) {
if (control.control_bits() & wvoec::kControlHDCPRequired) {
uint8_t required_hdcp =
(control.control_bits() & kControlHDCPVersionMask) >>
kControlHDCPVersionShift;
(control.control_bits() & wvoec::kControlHDCPVersionMask) >>
wvoec::kControlHDCPVersionShift;
if (ce_->srm_blacklisted_device_attached()) {
required_hdcp = HDCP_NO_DIGITAL_OUTPUT;
}
@@ -1002,7 +1000,7 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
}
if (!ce_->config_local_display_only() ||
buffer_type == OEMCrypto_BufferType_Clear) {
if (control.control_bits() & kControlDisableAnalogOutput) {
if (control.control_bits() & wvoec::kControlDisableAnalogOutput) {
LOGE("[%s(): control bit says disable analog.", log_string.c_str());
return OEMCrypto_ERROR_ANALOG_OUTPUT;
}
@@ -1026,7 +1024,7 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %d", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Encrypt", kControlAllowEncrypt,
OEMCryptoResult result = CheckKeyUse("Generic_Encrypt", wvoec::kControlAllowEncrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
@@ -1043,8 +1041,8 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
LOGE("[Generic_Encrypt(): FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvoec::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length, &aes_key, iv_buffer,
AES_ENCRYPT);
return OEMCrypto_SUCCESS;
@@ -1066,7 +1064,7 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
LOGE("[Generic_Decrypt(): CONTENT_KEY has wrong size.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Decrypt", kControlAllowDecrypt,
OEMCryptoResult result = CheckKeyUse("Generic_Decrypt", wvoec::kControlAllowDecrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
@@ -1084,8 +1082,8 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
LOGE("[Generic_Decrypt(): FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvoec::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length, &aes_key, iv_buffer,
AES_DECRYPT);
return OEMCrypto_SUCCESS;
@@ -1111,7 +1109,7 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
LOGE("[Generic_Sign(): CONTENT_KEY has wrong size; %d", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Sign", kControlAllowSign,
OEMCryptoResult result = CheckKeyUse("Generic_Sign", wvoec::kControlAllowSign,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_HMAC_SHA256) {
@@ -1147,7 +1145,7 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %d", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Verify", kControlAllowVerify,
OEMCryptoResult result = CheckKeyUse("Generic_Verify", wvoec::kControlAllowVerify,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_HMAC_SHA256) {
@@ -1178,8 +1176,8 @@ bool SessionContext::UpdateMacKeys(const std::vector<uint8_t>& enc_mac_keys,
return false;
}
mac_key_server_ = std::vector<uint8_t>(
mac_keys.begin(), mac_keys.begin() + wvcdm::MAC_KEY_SIZE);
mac_key_client_ = std::vector<uint8_t>(mac_keys.begin() + wvcdm::MAC_KEY_SIZE,
mac_keys.begin(), mac_keys.begin() + wvoec::MAC_KEY_SIZE);
mac_key_client_ = std::vector<uint8_t>(mac_keys.begin() + wvoec::MAC_KEY_SIZE,
mac_keys.end());
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
LOGI(("mac_key_client_ has been updated to = " +
@@ -1276,6 +1274,17 @@ OEMCryptoResult SessionContext::LoadUsageEntry(
ce_->usage_table().LoadUsageEntry(this, &usage_entry_, index, buffer);
if (usage_entry_) {
usage_entry_status_ = kUsageEntryLoaded;
// Copy the mac keys to the current session.
mac_key_server_ = std::vector<uint8_t>(
usage_entry_->mac_key_server(),
usage_entry_->mac_key_server() + wvoec::MAC_KEY_SIZE);
mac_key_client_ = std::vector<uint8_t>(
usage_entry_->mac_key_client(),
usage_entry_->mac_key_client() + wvoec::MAC_KEY_SIZE);
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
LOGI(("mac_key_client_ has been updated to = " +
wvcdm::b2a_hex(mac_key_client_)).c_str());
}
}
return result;
}
@@ -1510,22 +1519,12 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
int out_len = 0;
while (remaining) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX ctx_struct;
EVP_CIPHER_CTX* evp_cipher_ctx = &ctx_struct;
EVP_CIPHER_CTX_init(evp_cipher_ctx);
#else
EVP_CIPHER_CTX* evp_cipher_ctx = EVP_CIPHER_CTX_new();
#endif
EVP_CIPHER_CTX_set_padding(evp_cipher_ctx, 0);
if (!EVP_DecryptInit_ex(evp_cipher_ctx, EVP_aes_128_ctr(), NULL, key_u8,
aes_iv_u8)) {
LOGE("[DecryptCTR(): EVP_INIT ERROR]");
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX_cleanup(evp_cipher_ctx);
#else
EVP_CIPHER_CTX_free(evp_cipher_ctx);
#endif
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
@@ -1545,11 +1544,7 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
if (!EVP_DecryptUpdate(evp_cipher_ctx, &clear_data[l], &out_len,
&cipher_data[l], decrypt_length)) {
LOGE("[DecryptCTR(): EVP_UPDATE_ERROR]");
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX_cleanup(evp_cipher_ctx);
#else
EVP_CIPHER_CTX_free(evp_cipher_ctx);
#endif
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
l += decrypt_length;
@@ -1560,18 +1555,10 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
&clear_data[cipher_data_length - remaining],
&final)) {
LOGE("[DecryptCTR(): EVP_FINAL_ERROR]");
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX_cleanup(evp_cipher_ctx);
#else
EVP_CIPHER_CTX_free(evp_cipher_ctx);
#endif
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_CIPHER_CTX_cleanup(evp_cipher_ctx);
#else
EVP_CIPHER_CTX_free(evp_cipher_ctx);
#endif
// If remaining is not zero, reset the iv before the second pass.
if (remaining) {
@@ -1582,4 +1569,4 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
return OEMCrypto_SUCCESS;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,10 +2,10 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef MOCK_OEMCRYPTO_SESSION_H_
#define MOCK_OEMCRYPTO_SESSION_H_
#ifndef REF_OEMCRYPTO_SESSION_H_
#define REF_OEMCRYPTO_SESSION_H_
#include <stdint.h>
#include <time.h>
@@ -15,17 +15,15 @@
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "file_store.h"
#include "lock.h"
#include "oemcrypto_auth_mock.h"
#include "oemcrypto_key_mock.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_usage_table_mock.h"
#include "wv_cdm_types.h"
#include "oemcrypto_usage_table_ref.h"
#include "oemcrypto_types.h"
namespace wvoec_mock {
namespace wvoec_ref {
class CryptoEngine;
typedef uint32_t SessionId;
@@ -245,6 +243,6 @@ class SessionContext {
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // MOCK_OEMCRYPTO_SESSION_H_
#endif // REF_OEMCRYPTO_SESSION_H_

View File

@@ -2,14 +2,14 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_session_key_table.h"
#include "keys.h"
#include "log.h"
namespace wvoec_mock {
namespace wvoec_ref {
SessionKeyTable::~SessionKeyTable() {
for (KeyMap::iterator i = keys_.begin(); i != keys_.end(); ++i) {
@@ -116,4 +116,4 @@ bool EntitlementKeyTable::GetEntitlementKey(
return true;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,19 +2,20 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
#define MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
#ifndef REF_OEMCRYPTO_SESSION_KEY_TABLE_H_
#define REF_OEMCRYPTO_SESSION_KEY_TABLE_H_
#include <stdint.h>
#include <map>
#include <vector>
#include "oemcrypto_key_mock.h"
#include "wv_cdm_types.h"
#include "disallow_copy_and_assign.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_types.h"
namespace wvoec_mock {
namespace wvoec_ref {
class SessionContext;
class CryptoEngine;
@@ -65,6 +66,6 @@ class EntitlementKeyTable {
CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeyTable);
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // MOCK_OEMCRYPTO_SESSION_KEY_TABLE_H_
#endif // REF_OEMCRYPTO_SESSION_KEY_TABLE_H_

View File

@@ -2,9 +2,9 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#include "oemcrypto_usage_table_mock.h"
#include "oemcrypto_usage_table_ref.h"
#include <string.h>
#include <time.h>
@@ -19,15 +19,16 @@
#include "file_store.h"
#include "log.h"
#include "oemcrypto_engine_mock.h"
#include "oemcrypto_engine_ref.h"
#include "oemcrypto_logging.h"
#include "oemcrypto_old_usage_table_mock.h"
#include "properties.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"
#include "pst_report.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
namespace wvoec_mock {
namespace wvoec_ref {
namespace {
const size_t kMagicLength = 8;
const char* kEntryVerification = "USEENTRY";
@@ -84,19 +85,19 @@ bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) {
bool UsageTableEntry::VerifyMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client) {
return (server.size() == wvcdm::MAC_KEY_SIZE) &&
(client.size() == wvcdm::MAC_KEY_SIZE) &&
(0 == memcmp(&server[0], data_.mac_key_server, wvcdm::MAC_KEY_SIZE)) &&
(0 == memcmp(&client[0], data_.mac_key_client, wvcdm::MAC_KEY_SIZE));
return (server.size() == wvoec::MAC_KEY_SIZE) &&
(client.size() == wvoec::MAC_KEY_SIZE) &&
(0 == memcmp(&server[0], data_.mac_key_server, wvoec::MAC_KEY_SIZE)) &&
(0 == memcmp(&client[0], data_.mac_key_client, wvoec::MAC_KEY_SIZE));
}
bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client) {
if ((server.size() != wvcdm::MAC_KEY_SIZE) ||
(client.size() != wvcdm::MAC_KEY_SIZE))
if ((server.size() != wvoec::MAC_KEY_SIZE) ||
(client.size() != wvoec::MAC_KEY_SIZE))
return false;
memcpy(data_.mac_key_server, &server[0], wvcdm::MAC_KEY_SIZE);
memcpy(data_.mac_key_client, &client[0], wvcdm::MAC_KEY_SIZE);
memcpy(data_.mac_key_server, &server[0], wvoec::MAC_KEY_SIZE);
memcpy(data_.mac_key_client, &client[0], wvoec::MAC_KEY_SIZE);
return true;
}
@@ -130,13 +131,12 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
if (pst.size() == 0 || pst.size() > kMaxPSTLength ||
pst.size() != data_.pst_length) {
LOGE("ReportUsage: bad pst length = %d, should be %d.",
pst.size(), data_.pst_length);
LOGE("ReportUsage: bad pst length = %d, should be %d.", pst.size(),
data_.pst_length);
return OEMCrypto_ERROR_WRONG_PST;
}
if (memcmp(&pst[0], data_.pst, data_.pst_length)) {
LOGE("ReportUsage: wrong pst %s, should be %s.",
wvcdm::b2a_hex(pst).c_str(),
LOGE("ReportUsage: wrong pst %s, should be %s.", wvcdm::b2a_hex(pst).c_str(),
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
return OEMCrypto_ERROR_WRONG_PST;
}
@@ -163,12 +163,13 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
std::vector<uint8_t> mac_key_client(
data_.mac_key_client,
data_.mac_key_client + wvcdm::MAC_KEY_SIZE * sizeof(uint8_t));
data_.mac_key_client + wvoec::MAC_KEY_SIZE * sizeof(uint8_t));
LOGI(("message signed with HMAC and data_.mac_key_client, "
"mac_key_client = " +
wvcdm::b2a_hex(mac_key_client)).c_str());
wvcdm::b2a_hex(mac_key_client))
.c_str());
}
if (!HMAC(EVP_sha1(), data_.mac_key_client, wvcdm::MAC_KEY_SIZE,
if (!HMAC(EVP_sha1(), data_.mac_key_client, wvoec::MAC_KEY_SIZE,
buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH,
pst_report.signature(), &md_len)) {
LOGE("ReportUsage: could not compute signature.");
@@ -209,9 +210,9 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
const std::vector<uint8_t>& key = ce->DeviceRootKey(override_to_real);
// Encrypt the entry.
RAND_bytes(encrypted->iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(
@@ -265,8 +266,8 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
}
// Next, decrypt the entry.
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
@@ -279,7 +280,8 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kEntryVerification),
kMagicLength).c_str(),
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kEntryVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
}
@@ -306,23 +308,23 @@ OEMCryptoResult UsageTableEntry::CopyOldUsageEntry(
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) {
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]),
wvcdm::MAC_KEY_SIZE);
wvoec::MAC_KEY_SIZE);
}
if (old_entry->mac_key_client_.size() != wvcdm::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]),
wvcdm::MAC_KEY_SIZE);
wvoec::MAC_KEY_SIZE);
if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) {
std::vector<uint8_t> mac_key_client(
data_.mac_key_client,
data_.mac_key_client + wvcdm::MAC_KEY_SIZE * sizeof(uint8_t));
LOGI(("data_.mac_key_client has changed to = " +
wvcdm::b2a_hex(mac_key_client)).c_str());
data_.mac_key_client + wvoec::MAC_KEY_SIZE * sizeof(uint8_t));
LOGI(("data_.mac_key_client has changed to = " +
wvcdm::b2a_hex(mac_key_client)).c_str());
}
}
if (pst.size() > kMaxPSTLength) {
@@ -336,12 +338,11 @@ OEMCryptoResult UsageTableEntry::CopyOldUsageEntry(
return OEMCrypto_SUCCESS;
}
size_t UsageTableEntry::SignedEntrySize() {
size_t base = sizeof(SignedEntryBlock);
// round up to make even number of blocks:
size_t blocks = (base - 1) / wvcdm::KEY_IV_SIZE + 1;
return blocks * wvcdm::KEY_IV_SIZE;
size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1;
return blocks * wvoec::KEY_IV_SIZE;
}
UsageTable::~UsageTable() {
@@ -354,8 +355,8 @@ UsageTable::~UsageTable() {
size_t UsageTable::SignedHeaderSize(size_t count) {
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
// round up to make even number of blocks:
size_t blocks = (base - 1) / wvcdm::KEY_IV_SIZE + 1;
return blocks * wvcdm::KEY_IV_SIZE;
size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1;
return blocks * wvoec::KEY_IV_SIZE;
}
OEMCryptoResult UsageTable::UpdateUsageEntry(SessionContext* session,
@@ -503,9 +504,9 @@ OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer,
const std::vector<uint8_t>& key = ce_->DeviceRootKey(override_to_real);
// Encrypt the entry.
RAND_bytes(encrypted->iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(
@@ -558,8 +559,8 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
}
// Next, decrypt the entry.
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
@@ -572,7 +573,8 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kHeaderVerification),
kMagicLength).c_str(),
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kHeaderVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
}
@@ -641,11 +643,13 @@ bool UsageTable::SaveGenerationNumber() {
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,
// TODO(jfore, rfrias): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&path)) {
LOGE("UsageTable: Unable to get base path");
return false;
}
}*/
// On a real implementation, you should NOT put the generation number in
// a file in user space. It should be stored in secure memory.
std::string filename = path + "GenerationNumber.dat";
@@ -666,16 +670,17 @@ bool UsageTable::LoadGenerationNumber(bool or_make_new_one) {
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,
// TODO(jfore, rfrias): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&path)) {
LOGE("UsageTable: Unable to get base path");
return false;
}
}*/
// On a real implementation, you should NOT put the generation number in
// a file in user space. It should be stored in secure memory.
std::string filename = path + "GenerationNumber.dat";
wvcdm::File* file = file_system->Open(filename,
wvcdm::FileSystem::kReadOnly);
wvcdm::File* file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
if (!file) {
if (or_make_new_one) {
RAND_bytes(reinterpret_cast<uint8_t*>(&master_generation_number_),
@@ -702,7 +707,7 @@ OEMCryptoResult UsageTable::CreateUsageTableHeader(
*header_buffer_length = signed_header_size;
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) {
for (size_t i = 0; i < sessions_.size(); ++i) {
if (sessions_[i] != NULL) {
LOGE("CreateUsageTableHeader: index %d used by session.", i);
return OEMCrypto_ERROR_INVALID_SESSION;
@@ -736,8 +741,8 @@ OEMCryptoResult UsageTable::CreateOldUsageEntry(
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);
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;
@@ -745,10 +750,10 @@ OEMCryptoResult UsageTable::CreateOldUsageEntry(
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);
server_mac_key + wvoec::MAC_KEY_SIZE);
old_entry->mac_key_client_.assign(client_mac_key,
client_mac_key + wvcdm::MAC_KEY_SIZE);
client_mac_key + wvoec::MAC_KEY_SIZE);
return OEMCrypto_SUCCESS;
}
} // namespace wvoec_mock
} // namespace wvoec_ref

View File

@@ -2,10 +2,10 @@
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Mock implementation of OEMCrypto APIs
// Ref implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_USAGE_TABLE_MOCK_H_
#define OEMCRYPTO_USAGE_TABLE_MOCK_H_
#ifndef OEMCRYPTO_USAGE_TABLE_REF_H_
#define OEMCRYPTO_USAGE_TABLE_REF_H_
#include <stdint.h>
#include <map>
@@ -13,12 +13,10 @@
#include <vector>
#include "OEMCryptoCENC.h"
#include "file_store.h"
#include "lock.h"
#include "openssl/sha.h"
#include "wv_cdm_constants.h"
#include "oemcrypto_types.h"
namespace wvoec_mock {
namespace wvoec_ref {
class SessionContext;
class CryptoEngine;
@@ -34,8 +32,8 @@ struct StoredUsageEntry {
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];
uint8_t mac_key_server[wvoec::MAC_KEY_SIZE];
uint8_t mac_key_client[wvoec::MAC_KEY_SIZE];
uint32_t index;
uint8_t pst[kMaxPSTLength+1]; // add 1 for padding.
uint8_t pst_length;
@@ -134,6 +132,6 @@ class UsageTable {
OldUsageTable *old_table_;
};
} // namespace wvoec_mock
} // namespace wvoec_ref
#endif // OEMCRYPTO_USAGE_TABLE_MOCK_H_
#endif // OEMCRYPTO_USAGE_TABLE_REF_H_

View File

@@ -7,6 +7,8 @@
#include "oec_device_features.h"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstring>
@@ -141,6 +143,11 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
if (api_version < 12) FilterOut(&filter, "*API12*");
if (api_version < 13) FilterOut(&filter, "*API13*");
if (api_version < 14) FilterOut(&filter, "*API14*");
// Some tests may require root access. If user is not root, filter these tests
// out.
if (getuid()) {
FilterOut(&filter, "UsageTableTest.TimeRollbackPrevention");
}
// Performance tests take a long time. Filter them out if they are not
// specifically requested.
if (filter.find("Performance") == std::string::npos) {

View File

@@ -4,7 +4,7 @@
#include <string>
#include "OEMCryptoCENC.h"
#include "wv_keybox.h"
#include "oemcrypto_types.h"
namespace wvoec {

View File

@@ -26,14 +26,12 @@
#include <vector>
#include "OEMCryptoCENC.h"
#include "disallow_copy_and_assign.h"
#include "log.h"
#include "oec_device_features.h"
#include "oec_test_data.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_types.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
#include "wv_keybox.h"
using namespace std;
@@ -102,14 +100,14 @@ Session::Session()
: open_(false),
forced_session_id_(false),
session_id_(0),
mac_key_server_(wvcdm::MAC_KEY_SIZE),
mac_key_client_(wvcdm::MAC_KEY_SIZE),
enc_key_(wvcdm::KEY_SIZE),
mac_key_server_(MAC_KEY_SIZE),
mac_key_client_(MAC_KEY_SIZE),
enc_key_(KEY_SIZE),
public_rsa_(0),
message_size_(sizeof(MessageData)),
num_keys_(4), // Most tests only use 4 keys.
// Other tests will explicitly call set_num_keys.
has_entitlement_license_(false) {
// Most tests only use 4 keys. Other tests will explicitly call
// set_num_keys.
num_keys_(4) {
// Stripe the padded message.
for (size_t i = 0; i < sizeof(padded_message_.padding); i++) {
padded_message_.padding[i] = i % 0x100;
@@ -187,7 +185,7 @@ void Session::DeriveKey(const uint8_t* key, const vector<uint8_t>& context,
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
ASSERT_NE(static_cast<void*>(NULL), cmac_ctx);
ASSERT_EQ(1, CMAC_Init(cmac_ctx, key, wvcdm::KEY_SIZE, cipher, 0));
ASSERT_EQ(1, CMAC_Init(cmac_ctx, key, KEY_SIZE, cipher, 0));
std::vector<uint8_t> message;
message.push_back(counter);
@@ -223,7 +221,7 @@ void Session::DeriveKeys(const uint8_t* master_key,
}
void Session::GenerateDerivedKeysFromKeybox(
const wvoec_mock::WidevineKeybox& keybox) {
const wvoec::WidevineKeybox& keybox) {
GenerateNonce();
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
@@ -269,9 +267,9 @@ void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {
key_array_, pst_ptr, pst.length(), NULL,
OEMCrypto_ContentLicense));
// Update new generated keys.
memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE,
wvcdm::MAC_KEY_SIZE);
memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE,
MAC_KEY_SIZE);
} else {
ASSERT_EQ(
OEMCrypto_SUCCESS,
@@ -299,9 +297,9 @@ void Session::LoadEnitlementTestKeys(const std::string& pst,
key_array_, pst_ptr, pst.length(), NULL,
OEMCrypto_EntitlementLicense));
// Update new generated keys.
memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE,
wvcdm::MAC_KEY_SIZE);
memcpy(&mac_key_server_[0], license_.mac_keys, MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + MAC_KEY_SIZE,
MAC_KEY_SIZE);
} else {
ASSERT_EQ(
expected_sts,
@@ -313,7 +311,6 @@ void Session::LoadEnitlementTestKeys(const std::string& pst,
}
void Session::FillEntitledKeyArray() {
has_entitlement_license_ = true;
for (size_t i = 0; i < num_keys_; ++i) {
EntitledContentKeyData* key_data = &entitled_key_data_[i];
@@ -480,7 +477,7 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length);
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data,
sizeof(license_.keys[i].key_data)));
license_.keys[i].key_data_length = wvcdm::KEY_SIZE;
license_.keys[i].key_data_length = KEY_SIZE;
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv,
sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
@@ -494,14 +491,14 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(license_.keys[i].control.verification, "kc12", 4);
} else if (control & wvoec_mock::kControlSecurityPatchLevelMask) {
} else if (control & wvoec::kControlSecurityPatchLevelMask) {
// For versions before 12, we require the special key control block only
// when there are newer features present.
memcpy(license_.keys[i].control.verification, "kc11", 4);
} else if (control & wvoec_mock::kControlRequireAntiRollbackHardware) {
} else if (control & wvoec::kControlRequireAntiRollbackHardware) {
memcpy(license_.keys[i].control.verification, "kc10", 4);
} else if (control & (wvoec_mock::kControlHDCPVersionMask |
wvoec_mock::kControlReplayMask)) {
} else if (control & (wvoec::kControlHDCPVersionMask |
wvoec::kControlReplayMask)) {
memcpy(license_.keys[i].control.verification, "kc09", 4);
} else {
memcpy(license_.keys[i].control.verification, "kctl", 4);
@@ -527,7 +524,7 @@ void Session::FillSimpleEntitlementMessage(
memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length);
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data,
sizeof(license_.keys[i].key_data)));
license_.keys[i].key_data_length = wvcdm::KEY_SIZE * 2; // AES-256 keys
license_.keys[i].key_data_length = KEY_SIZE * 2; // AES-256 keys
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv,
sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
@@ -541,14 +538,14 @@ void Session::FillSimpleEntitlementMessage(
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(license_.keys[i].control.verification, "kc12", 4);
} else if (control & wvoec_mock::kControlSecurityPatchLevelMask) {
} else if (control & wvoec::kControlSecurityPatchLevelMask) {
// For versions before 12, we require the special key control block only
// when there are newer features present.
memcpy(license_.keys[i].control.verification, "kc11", 4);
} else if (control & wvoec_mock::kControlRequireAntiRollbackHardware) {
} else if (control & wvoec::kControlRequireAntiRollbackHardware) {
memcpy(license_.keys[i].control.verification, "kc10", 4);
} else if (control & (wvoec_mock::kControlHDCPVersionMask |
wvoec_mock::kControlReplayMask)) {
} else if (control & (wvoec::kControlHDCPVersionMask |
wvoec::kControlReplayMask)) {
memcpy(license_.keys[i].control.verification, "kc09", 4);
} else {
memcpy(license_.keys[i].control.verification, "kctl", 4);
@@ -592,22 +589,21 @@ void Session::EncryptAndSign() {
encrypted_license() = license_;
uint8_t iv_buffer[16];
memcpy(iv_buffer, &license_.mac_key_iv[0], wvcdm::KEY_IV_SIZE);
memcpy(iv_buffer, &license_.mac_key_iv[0], KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
AES_cbc_encrypt(&license_.mac_keys[0], &encrypted_license().mac_keys[0],
2 * wvcdm::MAC_KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
2 * MAC_KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
int key_size = has_entitlement_license() ? 256 : 128;
for (unsigned int i = 0; i < num_keys_; i++) {
memcpy(iv_buffer, &license_.keys[i].control_iv[0], wvcdm::KEY_IV_SIZE);
AES_set_encrypt_key(&license_.keys[i].key_data[0], key_size, &aes_key);
memcpy(iv_buffer, &license_.keys[i].control_iv[0], KEY_IV_SIZE);
AES_set_encrypt_key(&license_.keys[i].key_data[0], 128, &aes_key);
AES_cbc_encrypt(
reinterpret_cast<const uint8_t*>(&license_.keys[i].control),
reinterpret_cast<uint8_t*>(&encrypted_license().keys[i].control),
wvcdm::KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
memcpy(iv_buffer, &license_.keys[i].key_iv[0], wvcdm::KEY_IV_SIZE);
memcpy(iv_buffer, &license_.keys[i].key_iv[0], KEY_IV_SIZE);
AES_set_encrypt_key(&enc_key_[0], 128, &aes_key);
AES_cbc_encrypt(
&license_.keys[i].key_data[0], &encrypted_license().keys[i].key_data[0],
@@ -622,14 +618,14 @@ void Session::EncryptAndSign() {
void Session::EncryptProvisioningMessage(
RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted,
const vector<uint8_t>& encryption_key) {
ASSERT_EQ(encryption_key.size(), wvcdm::KEY_SIZE);
ASSERT_EQ(encryption_key.size(), KEY_SIZE);
*encrypted = *data;
size_t padding = wvcdm::KEY_SIZE - (data->rsa_key_length % wvcdm::KEY_SIZE);
size_t padding = KEY_SIZE - (data->rsa_key_length % KEY_SIZE);
memset(data->rsa_key + data->rsa_key_length, static_cast<uint8_t>(padding),
padding);
encrypted->rsa_key_length = data->rsa_key_length + padding;
uint8_t iv_buffer[16];
memcpy(iv_buffer, &data->rsa_key_iv[0], wvcdm::KEY_IV_SIZE);
memcpy(iv_buffer, &data->rsa_key_iv[0], KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&encryption_key[0], 128, &aes_key);
AES_cbc_encrypt(&data->rsa_key[0], &encrypted->rsa_key[0],
@@ -742,8 +738,8 @@ void Session::TestDecryptCTR(bool select_key_first,
for (size_t i = 0; i < unencryptedData.size(); i++)
unencryptedData[i] = i % 256;
EXPECT_EQ(1, GetRandBytes(&unencryptedData[0], unencryptedData.size()));
vector<uint8_t> encryptionIv(wvcdm::KEY_IV_SIZE);
EXPECT_EQ(1, GetRandBytes(&encryptionIv[0], wvcdm::KEY_IV_SIZE));
vector<uint8_t> encryptionIv(KEY_IV_SIZE);
EXPECT_EQ(1, GetRandBytes(&encryptionIv[0], KEY_IV_SIZE));
vector<uint8_t> encryptedData(unencryptedData.size());
EncryptCTR(unencryptedData, license_.keys[key_index].key_data,
&encryptionIv[0], &encryptedData);
@@ -895,7 +891,7 @@ void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
memcpy(message.rsa_key, rsa_key.data(), rsa_key.size());
message.rsa_key_length = rsa_key.size();
}
EXPECT_EQ(1, GetRandBytes(message.rsa_key_iv, wvcdm::KEY_IV_SIZE));
EXPECT_EQ(1, GetRandBytes(message.rsa_key_iv, KEY_IV_SIZE));
message.nonce = nonce_;
EncryptProvisioningMessage(&message, encrypted, *encryption_key);
@@ -1198,15 +1194,17 @@ void Session::VerifyPST(const Test_PST_Report& expected) {
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,
time_t now = time(NULL);
int64_t age = now - expected.time_created; // How old is this report.
EXPECT_NEAR(expected.seconds_since_license_received + age,
computed.seconds_since_license_received(),
kTimeTolerance);
// Decrypt times only valid on licenses that have been active.
if (expected.status == kActive || expected.status == kInactiveUsed) {
EXPECT_NEAR(expected.seconds_since_first_decrypt,
EXPECT_NEAR(expected.seconds_since_first_decrypt + age,
computed.seconds_since_first_decrypt(),
kUsageTableTimeTolerance);
EXPECT_NEAR(expected.seconds_since_last_decrypt,
EXPECT_NEAR(expected.seconds_since_last_decrypt + age,
computed.seconds_since_last_decrypt(),
kUsageTableTimeTolerance);
}
@@ -1232,13 +1230,10 @@ static int64_t MaybeAdjustTime(int64_t t, time_t now) {
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);
void Session::VerifyReport(Test_PST_Report expected,
int64_t time_license_received,
int64_t time_first_decrypt,
int64_t time_last_decrypt) {
time_t now = time(NULL);
expected.seconds_since_license_received =
MaybeAdjustTime(time_license_received, now);
@@ -1248,6 +1243,17 @@ void Session::GenerateVerifyReport(const std::string& pst,
ASSERT_NO_FATAL_FAILURE(VerifyPST(expected));
}
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);
ASSERT_NO_FATAL_FAILURE(VerifyReport(expected, time_license_received,
time_first_decrypt, time_last_decrypt));
}
void Session::CreateOldEntry(const Test_PST_Report& report) {
OEMCryptoResult result = OEMCrypto_CreateOldUsageEntry(
report.seconds_since_license_received,

View File

@@ -12,8 +12,8 @@
#include <vector>
#include "oec_device_features.h"
#include "oemcrypto_types.h"
#include "pst_report.h"
#include "wv_cdm_constants.h"
using namespace std;
@@ -66,10 +66,10 @@ const size_t kMaxDecryptSize = 100 * 1024; // In specification.
typedef struct {
uint8_t key_id[kTestKeyIdMaxLength];
size_t key_id_length;
uint8_t key_data[wvcdm::MAC_KEY_SIZE];
uint8_t key_data[MAC_KEY_SIZE];
size_t key_data_length;
uint8_t key_iv[wvcdm::KEY_IV_SIZE];
uint8_t control_iv[wvcdm::KEY_IV_SIZE];
uint8_t key_iv[KEY_IV_SIZE];
uint8_t control_iv[KEY_IV_SIZE];
KeyControlBlock control;
// Note: cipher_mode may not be part of a real signed message. For these
// tests, it is convenient to keep it in this structure anyway.
@@ -79,8 +79,8 @@ typedef struct {
// This structure will be signed to simulate a message from the server.
struct MessageData {
MessageKeyData keys[kMaxNumKeys];
uint8_t mac_key_iv[wvcdm::KEY_IV_SIZE];
uint8_t mac_keys[2 * wvcdm::MAC_KEY_SIZE];
uint8_t mac_key_iv[KEY_IV_SIZE];
uint8_t mac_keys[2 * MAC_KEY_SIZE];
uint8_t pst[kMaxPSTLength];
};
@@ -88,7 +88,7 @@ struct MessageData {
// server.
struct RSAPrivateKeyMessage {
uint8_t rsa_key[kMaxTestRSAKeyLength];
uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE];
uint8_t rsa_key_iv[KEY_IV_SIZE];
size_t rsa_key_length;
uint32_t nonce;
};
@@ -96,20 +96,21 @@ struct RSAPrivateKeyMessage {
struct Test_PST_Report {
Test_PST_Report(const std::string& pst_in,
OEMCrypto_Usage_Entry_Status status_in)
: status(status_in), pst(pst_in) {}
: status(status_in), pst(pst_in), time_created(time(NULL)) {}
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;
time_t time_created;
};
struct EntitledContentKeyData {
uint8_t entitlement_key_id[wvcdm::KEY_SIZE];
uint8_t content_key_id[wvcdm::KEY_SIZE];
uint8_t content_key_data_iv[wvcdm::KEY_SIZE];
uint8_t content_key_data[wvcdm::KEY_SIZE];
uint8_t entitlement_key_id[KEY_SIZE];
uint8_t content_key_id[KEY_SIZE];
uint8_t content_key_data_iv[KEY_SIZE];
uint8_t content_key_data[KEY_SIZE];
};
// Increment counter for AES-CTR. The CENC spec specifies we increment only
@@ -151,7 +152,7 @@ class Session {
vector<uint8_t>* enc_context);
// Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and
// also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromKeybox(const wvoec_mock::WidevineKeybox& keybox);
void GenerateDerivedKeysFromKeybox(const wvoec::WidevineKeybox& keybox);
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromSessionKey();
@@ -331,9 +332,14 @@ class Session {
// Verify the values in the PST report. The signature should have been
// verified in GenerateReport, above.
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.
// 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 VerifyReport(Test_PST_Report report,
int64_t time_license_received = 0,
int64_t time_first_decrypt = 0,
int64_t time_last_decrypt = 0);
// Same as above, but generates the report with the given status.
void GenerateVerifyReport(const std::string& pst,
OEMCrypto_Usage_Entry_Status status,
int64_t time_license_received = 0,
@@ -372,9 +378,6 @@ class Session {
// The size of the encrypted message.
size_t message_size() { return message_size_; }
// If this session has an entitlement license.
bool has_entitlement_license() const { return has_entitlement_license_; }
private:
// Generate mac and enc keys give the master key.
void DeriveKeys(const uint8_t* master_key,
@@ -404,7 +407,6 @@ class Session {
vector<uint8_t> encrypted_usage_entry_;
uint32_t usage_entry_number_;
string pst_;
bool has_entitlement_license_;
// Clear Entitlement key data. This is the backing data for
// |entitled_key_array_|.

View File

@@ -10,7 +10,8 @@
#include <string>
#include "OEMCryptoCENC.h"
#include "wv_keybox.h"
#include "oemcrypto_types.h"
namespace wvoec {
@@ -20,7 +21,7 @@ namespace wvoec {
// The first keybox, kTestKeybox, with deviceID "TestKey01" is used for most of
// the tests. It should be loaded by OEMCrypto when OEMCrypto_LoadTestKeybox
// is called.
static const wvoec_mock::WidevineKeybox kTestKeybox = {
static const wvoec::WidevineKeybox kTestKeybox = {
// Sample keybox used for test vectors
{
// deviceID = WidevineTestOnlyKeybox000
@@ -55,7 +56,7 @@ static const wvoec_mock::WidevineKeybox kTestKeybox = {
// These are old test keyboxes. The first keybox can be used to update an
// older OEMCrypto because it is the same keybox that was previously used in
// unit tests.
static const wvoec_mock::WidevineKeybox kValidKeybox01 = {
static const wvoec::WidevineKeybox kValidKeybox01 = {
// Sample keybox used for test vectors
{
// deviceID
@@ -87,7 +88,7 @@ static const wvoec_mock::WidevineKeybox kValidKeybox01 = {
}
};
static const wvoec_mock::WidevineKeybox kValidKeybox02 = {
static const wvoec::WidevineKeybox kValidKeybox02 = {
// Sample keybox used for test vectors
{
// deviceID
@@ -119,7 +120,7 @@ static const wvoec_mock::WidevineKeybox kValidKeybox02 = {
}
};
static const wvoec_mock::WidevineKeybox kValidKeybox03 = {
static const wvoec::WidevineKeybox kValidKeybox03 = {
// Sample keybox used for test vectors
{
// deviceID

View File

@@ -82,10 +82,10 @@ void SessionUtil::CreateWrappedRSAKey(uint32_t allowed_schemes,
}
}
void SessionUtil::InstallKeybox(const wvoec_mock::WidevineKeybox& keybox,
void SessionUtil::InstallKeybox(const wvoec::WidevineKeybox& keybox,
bool good) {
uint8_t wrapped[sizeof(wvoec_mock::WidevineKeybox)];
size_t length = sizeof(wvoec_mock::WidevineKeybox);
uint8_t wrapped[sizeof(wvoec::WidevineKeybox)];
size_t length = sizeof(wvoec::WidevineKeybox);
keybox_ = keybox;
ASSERT_EQ(
OEMCrypto_SUCCESS,

View File

@@ -26,7 +26,7 @@ public:
// If force is true, we assert that the key loads successfully.
void CreateWrappedRSAKey(uint32_t allowed_schemes, bool force);
void InstallKeybox(const wvoec_mock::WidevineKeybox& keybox, bool good);
void InstallKeybox(const wvoec::WidevineKeybox& keybox, bool good);
void EnsureTestKeys();
@@ -34,7 +34,7 @@ public:
std::vector<uint8_t> encoded_rsa_key_;
std::vector<uint8_t> wrapped_rsa_key_;
wvoec_mock::WidevineKeybox keybox_;
wvoec::WidevineKeybox keybox_;
};
} // namespace wvoec

View File

@@ -33,11 +33,12 @@
#include "oec_session_util.h"
#include "oec_test_data.h"
#include "oemcrypto_session_tests_helper.h"
#include "oemcrypto_key_mock.h"
#include "properties.h"
#include "oemcrypto_types.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_keybox.h"
#ifdef CDM_TESTS
#include "properties.h"
#endif
using ::testing::Bool;
using ::testing::Combine;
@@ -63,11 +64,7 @@ void PrintTo(const tuple<OEMCrypto_CENCEncryptPatternDesc, OEMCryptoCipherMode,
namespace {
int GetRandBytes(unsigned char* buf, int num) {
// returns 1 on success, -1 if not supported, or 0 if other failure.
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
return RAND_pseudo_bytes(buf, num);
#else
return RAND_bytes(buf, num);
#endif
}
} // namespace
@@ -79,7 +76,9 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil {
virtual void SetUp() {
::testing::Test::SetUp();
#ifdef CDM_TESTS
wvcdm::Properties::Init();
#endif
wvcdm::g_cutoff = wvcdm::LOG_INFO;
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
@@ -681,7 +680,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, GoodForceKeybox) {
ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX,
global_features.derive_key_method)
<< "ForceKeybox tests will modify the installed keybox.";
wvoec_mock::WidevineKeybox keybox = kValidKeybox02;
wvoec::WidevineKeybox keybox = kValidKeybox02;
OEMCryptoResult sts;
InstallKeybox(keybox, true);
sts = OEMCrypto_IsKeyboxValid();
@@ -697,7 +696,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadCRCForceKeybox) {
ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX,
global_features.derive_key_method)
<< "ForceKeybox tests will modify the installed keybox.";
wvoec_mock::WidevineKeybox keybox = kValidKeybox02;
wvoec::WidevineKeybox keybox = kValidKeybox02;
keybox.crc_[1] ^= 42;
OEMCryptoResult sts;
InstallKeybox(keybox, false);
@@ -709,7 +708,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadMagicForceKeybox) {
ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX,
global_features.derive_key_method)
<< "ForceKeybox tests will modify the installed keybox.";
wvoec_mock::WidevineKeybox keybox = kValidKeybox02;
wvoec::WidevineKeybox keybox = kValidKeybox02;
keybox.magic_[1] ^= 42;
OEMCryptoResult sts;
InstallKeybox(keybox, false);
@@ -721,7 +720,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadDataForceKeybox) {
ASSERT_EQ(DeviceFeatures::FORCE_TEST_KEYBOX,
global_features.derive_key_method)
<< "ForceKeybox tests will modify the installed keybox.";
wvoec_mock::WidevineKeybox keybox = kValidKeybox02;
wvoec::WidevineKeybox keybox = kValidKeybox02;
keybox.data_[1] ^= 42;
OEMCryptoResult sts;
InstallKeybox(keybox, false);
@@ -774,7 +773,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
}
@@ -791,7 +790,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeySeveralNonce) {
s.GenerateNonce(); // three.
s.GenerateNonce(); // four.
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, first_nonce));
s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, first_nonce));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
}
@@ -964,7 +963,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) {
vector<uint8_t> bad_buffer(
s.encrypted_license().keys[1].key_data,
s.encrypted_license().keys[1].key_data + wvcdm::KEY_SIZE);
s.encrypted_license().keys[1].key_data + wvoec::KEY_SIZE);
s.key_array()[1].key_data = &bad_buffer[0];
OEMCryptoResult sts = OEMCrypto_LoadKeys(
@@ -1038,7 +1037,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0,
wvoec_mock::kControlNonceEnabled,
wvoec::kControlNonceEnabled,
42)); // bad nonce.
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
OEMCryptoResult sts = OEMCrypto_LoadKeys(
@@ -1056,7 +1055,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
uint32_t nonce = s.get_nonce();
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, nonce));
s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, nonce));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
ASSERT_NO_FATAL_FAILURE(s.close());
@@ -1064,7 +1063,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0,
wvoec_mock::kControlNonceEnabled,
wvoec::kControlNonceEnabled,
nonce)); // same old nonce.
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
OEMCryptoResult sts = OEMCrypto_LoadKeys(
@@ -1076,6 +1075,57 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) {
ASSERT_NE(OEMCrypto_SUCCESS, sts);
}
// This tests that a nonce cannot be used in new session.
TEST_F(OEMCryptoSessionTests, LoadKeyNonceReopenSession) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
uint32_t nonce = s.get_nonce();
// Do not use the nonce now. Close session and use it after re-opening.
ASSERT_NO_FATAL_FAILURE(s.close());
// Actually, this isn't the same session. OEMCrypto opens a new session, but
// we are guarding against the possiblity that it re-uses the session data
// and might not clear out the nonce table correctly.
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec::kControlNonceEnabled,
nonce)); // same old nonce
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
OEMCryptoResult sts = OEMCrypto_LoadKeys(
s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0],
s.signature().size(), s.encrypted_license().mac_key_iv,
s.encrypted_license().mac_keys, s.num_keys(), s.key_array(), NULL, 0,
NULL, OEMCrypto_ContentLicense);
ASSERT_NE(OEMCrypto_SUCCESS, sts);
}
// This tests that a nonce cannot be used in wrong session.
TEST_F(OEMCryptoSessionTests, LoadKeyNonceWrongSession) {
Session s1;
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
uint32_t nonce = s1.get_nonce();
// Do not use the nonce. Also, leave the session open. We want to make sure
// that s and s1 do NOT share a nonce table. This is different from the
// LoadKeyNonceReopenSession in that we do not close s1.
Session s2;
ASSERT_NO_FATAL_FAILURE(s2.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
ASSERT_NO_FATAL_FAILURE(s2.FillSimpleMessage(0, wvoec::kControlNonceEnabled,
nonce)); // nonce from session s1
ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign());
OEMCryptoResult sts = OEMCrypto_LoadKeys(
s2.session_id(), s2.message_ptr(), s2.message_size(), &s2.signature()[0],
s2.signature().size(), s2.encrypted_license().mac_key_iv,
s2.encrypted_license().mac_keys, s2.num_keys(), s2.key_array(), NULL, 0,
NULL, OEMCrypto_ContentLicense);
ASSERT_NE(OEMCrypto_SUCCESS, sts);
}
TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
@@ -1191,7 +1241,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
int kNoKeys = 0;
ASSERT_NE(
@@ -1207,7 +1257,7 @@ TEST_F(OEMCryptoSessionTests, QueryKeyControl) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
// Note: successful cases are tested in VerifyTestKeys.
@@ -1234,7 +1284,7 @@ TEST_F(OEMCryptoSessionTests, AntiRollbackHardwareRequired) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlRequireAntiRollbackHardware, 0));
0, wvoec::kControlRequireAntiRollbackHardware, 0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
OEMCryptoResult sts = OEMCrypto_LoadKeys(
s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0],
@@ -1256,7 +1306,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, patch_level << wvoec_mock::kControlSecurityPatchLevelShift, 0));
0, patch_level << wvoec::kControlSecurityPatchLevelShift, 0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_EQ(
OEMCrypto_SUCCESS,
@@ -1272,7 +1322,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, (patch_level + 1) << wvoec_mock::kControlSecurityPatchLevelShift,
0, (patch_level + 1) << wvoec::kControlSecurityPatchLevelShift,
0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_EQ(
@@ -1289,7 +1339,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, (patch_level - 1) << wvoec_mock::kControlSecurityPatchLevelShift,
0, (patch_level - 1) << wvoec::kControlSecurityPatchLevelShift,
0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_EQ(
@@ -1331,8 +1381,8 @@ class SessionTestDecryptWithHDCP : public OEMCryptoSessionTests,
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0,
(version << wvoec_mock::kControlHDCPVersionShift) |
wvoec_mock::kControlObserveHDCP | wvoec_mock::kControlHDCPRequired,
(version << wvoec::kControlHDCPVersionShift) |
wvoec::kControlObserveHDCP | wvoec::kControlHDCPRequired,
0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
@@ -1376,14 +1426,14 @@ TEST_P(SessionTestRefreshKeyTest, RefreshWithNonce) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
kDuration, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_));
s.GenerateNonce();
// License renewal message is signed by client and verified by the server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(num_keys_,
wvoec_mock::kControlNonceEnabled,
wvoec::kControlNonceEnabled,
s.get_nonce(), OEMCrypto_SUCCESS));
}
@@ -1406,14 +1456,14 @@ TEST_P(SessionTestRefreshKeyTest, RefreshOldNonceAPI11) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
uint32_t nonce = s.get_nonce();
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(kDuration, wvoec_mock::kControlNonceEnabled, nonce));
s.FillSimpleMessage(kDuration, wvoec::kControlNonceEnabled, nonce));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_));
// License renewal message is signed by client and verified by the server.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
// Tryinng to reuse the same nonce.
ASSERT_NO_FATAL_FAILURE(
s.RefreshTestKeys(num_keys_, wvoec_mock::kControlNonceEnabled, nonce,
s.RefreshTestKeys(num_keys_, wvoec::kControlNonceEnabled, nonce,
OEMCrypto_ERROR_INVALID_NONCE));
}
@@ -1422,7 +1472,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshBadNonceAPI11) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
kDuration, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_));
s.GenerateNonce();
@@ -1430,7 +1480,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshBadNonceAPI11) {
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
uint32_t nonce = s.get_nonce() ^ 42;
ASSERT_NO_FATAL_FAILURE(
s.RefreshTestKeys(num_keys_, wvoec_mock::kControlNonceEnabled, nonce,
s.RefreshTestKeys(num_keys_, wvoec::kControlNonceEnabled, nonce,
OEMCrypto_ERROR_INVALID_NONCE));
}
@@ -1440,7 +1490,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshLargeBuffer) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
kDuration, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_));
s.GenerateNonce();
@@ -1448,7 +1498,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshLargeBuffer) {
// This uses a large buffer for the renewal message.
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature(kMaxMessageSize));
ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(num_keys_,
wvoec_mock::kControlNonceEnabled,
wvoec::kControlNonceEnabled,
s.get_nonce(), OEMCrypto_SUCCESS));
}
@@ -1460,7 +1510,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshWithNoSelectKey) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
kDuration, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_));
// Call select key before the refresh. No calls below to TestDecryptCTR with
@@ -1474,7 +1524,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshWithNoSelectKey) {
// message is not actually encrypted. It is, however, signed.
// FillRefreshMessage fills the message with a duration of kLongDuration.
ASSERT_NO_FATAL_FAILURE(s.FillRefreshMessage(
num_keys_, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
num_keys_, wvoec::kControlNonceEnabled, s.get_nonce()));
s.ServerSignBuffer(reinterpret_cast<const uint8_t*>(&s.encrypted_license()),
s.message_size(), &s.signature());
OEMCrypto_KeyRefreshObject key_array[num_keys_];
@@ -2082,7 +2132,7 @@ TEST_F(OEMCryptoSessionTests, DecryptSecureToClear) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration,
wvoec_mock::kControlObserveDataPath | wvoec_mock::kControlDataPathSecure,
wvoec::kControlObserveDataPath | wvoec::kControlDataPathSecure,
0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
@@ -2095,7 +2145,7 @@ TEST_F(OEMCryptoSessionTests, DecryptNoAnalogToClearAPI13) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlDisableAnalogOutput, 0));
kDuration, wvoec::kControlDisableAnalogOutput, 0));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
ASSERT_NO_FATAL_FAILURE(
@@ -2107,7 +2157,7 @@ TEST_F(OEMCryptoSessionTests, KeyDuration) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce()));
kDuration, wvoec::kControlNonceEnabled, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(true, OEMCrypto_SUCCESS));
@@ -3769,22 +3819,22 @@ class GenericCryptoTest : public OEMCryptoSessionTests {
ASSERT_NO_FATAL_FAILURE(
session_.FillSimpleMessage(duration, control, nonce, pst));
session_.license().keys[0].control.control_bits |=
htonl(wvoec_mock::kControlAllowEncrypt);
htonl(wvoec::kControlAllowEncrypt);
session_.license().keys[1].control.control_bits |=
htonl(wvoec_mock::kControlAllowDecrypt);
htonl(wvoec::kControlAllowDecrypt);
session_.license().keys[2].control.control_bits |=
htonl(wvoec_mock::kControlAllowSign);
htonl(wvoec::kControlAllowSign);
session_.license().keys[3].control.control_bits |=
htonl(wvoec_mock::kControlAllowVerify);
htonl(wvoec::kControlAllowVerify);
session_.license().keys[2].key_data_length = wvcdm::MAC_KEY_SIZE;
session_.license().keys[3].key_data_length = wvcdm::MAC_KEY_SIZE;
session_.license().keys[2].key_data_length = wvoec::MAC_KEY_SIZE;
session_.license().keys[3].key_data_length = wvoec::MAC_KEY_SIZE;
clear_buffer_.assign(buffer_size_, 0);
for (size_t i = 0; i < clear_buffer_.size(); i++) {
clear_buffer_[i] = 1 + i % 250;
}
for (size_t i = 0; i < wvcdm::KEY_IV_SIZE; i++) {
for (size_t i = 0; i < wvoec::KEY_IV_SIZE; i++) {
iv_[i] = i;
}
}
@@ -3800,8 +3850,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests {
ASSERT_EQ(0,
AES_set_encrypt_key(session_.license().keys[key_index].key_data,
AES_BLOCK_SIZE * 8, &aes_key));
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv_, wvcdm::KEY_IV_SIZE);
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, iv_, wvoec::KEY_IV_SIZE);
out_buffer->resize(in_buffer.size());
ASSERT_GT(in_buffer.size(), 0u);
ASSERT_EQ(0u, in_buffer.size() % AES_BLOCK_SIZE);
@@ -3815,7 +3865,7 @@ class GenericCryptoTest : public OEMCryptoSessionTests {
unsigned int md_len = SHA256_DIGEST_LENGTH;
signature->resize(SHA256_DIGEST_LENGTH);
HMAC(EVP_sha256(), session_.license().keys[key_index].key_data,
wvcdm::MAC_KEY_SIZE, &in_buffer[0], in_buffer.size(),
wvoec::MAC_KEY_SIZE, &in_buffer[0], in_buffer.size(),
signature->data(), &md_len);
}
@@ -3899,7 +3949,7 @@ class GenericCryptoTest : public OEMCryptoSessionTests {
size_t buffer_size_;
vector<uint8_t> clear_buffer_;
vector<uint8_t> encrypted_buffer_;
uint8_t iv_[wvcdm::KEY_IV_SIZE];
uint8_t iv_[wvoec::KEY_IV_SIZE];
Session session_;
};
@@ -3994,7 +4044,7 @@ TEST_F(GenericCryptoTest, GenericKeyDecryptSameBufferAPI12) {
TEST_F(GenericCryptoTest, GenericSecureToClear) {
session_.license().keys[1].control.control_bits |= htonl(
wvoec_mock::kControlObserveDataPath | wvoec_mock::kControlDataPathSecure);
wvoec::kControlObserveDataPath | wvoec::kControlDataPathSecure);
EncryptAndLoadKeys();
unsigned int key_index = 1;
vector<uint8_t> encrypted;
@@ -4316,7 +4366,7 @@ class GenericCryptoKeyIdLengthTest : public GenericCryptoTest {
const uint32_t kNoNonce = 0;
session_.set_num_keys(5);
ASSERT_NO_FATAL_FAILURE(session_.FillSimpleMessage(
kDuration, wvoec_mock::kControlAllowDecrypt, kNoNonce));
kDuration, wvoec::kControlAllowDecrypt, kNoNonce));
SetUniformKeyIdLength(16); // Start with all key ids being 16 bytes.
// But, we are testing that the key ids do not have to have the same length.
session_.SetKeyId(0, "123456789012"); // 12 bytes (common key id length).
@@ -4407,7 +4457,7 @@ class UsageTableTest : public GenericCryptoTest {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
@@ -4454,7 +4504,7 @@ TEST_P(UsageTableTestWithMAC, OnlineLicense) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -4484,7 +4534,7 @@ TEST_P(UsageTableTestWithMAC, ForbidReportWithNoUpdate) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -4514,7 +4564,7 @@ TEST_P(UsageTableTestWithMAC, OnlineLicenseWithRefresh) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -4527,7 +4577,7 @@ TEST_P(UsageTableTestWithMAC, OnlineLicenseWithRefresh) {
size_t kAllKeys = 1;
ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(
kAllKeys,
wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), OEMCrypto_SUCCESS));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(
@@ -4543,7 +4593,7 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -4574,7 +4624,7 @@ TEST_F(UsageTableTest, OnlineEmptyPST) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -4594,7 +4644,7 @@ TEST_F(UsageTableTest, OnlineMissingEntry) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
// ENTRY NOT CREATED: ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -4613,7 +4663,7 @@ TEST_F(UsageTableTest, TwoHundredEntries) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
std::string pst1 = "pst saved";
ASSERT_NO_FATAL_FAILURE(s1.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s1.get_nonce(), pst1));
ASSERT_NO_FATAL_FAILURE(s1.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s1.CreateNewUsageEntry());
@@ -4633,7 +4683,7 @@ TEST_F(UsageTableTest, TwoHundredEntries) {
char c2 = 'A' + (i%26);
pst = pst + c1 + c2;
ASSERT_NO_FATAL_FAILURE(sessions[i].FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, sessions[i].get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, sessions[i].get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(sessions[i].EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(sessions[i].CreateNewUsageEntry());
ASSERT_EQ(sessions[i].usage_entry_number(), i + 1);
@@ -4645,13 +4695,13 @@ TEST_F(UsageTableTest, TwoHundredEntries) {
sleep(kShortSleep);
for (size_t i = 0; i < ENTRY_COUNT; i++) {
ASSERT_NO_FATAL_FAILURE(sessions[i].open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
std::string pst = "pst ";
char c1 = 'A' + (i/26);
char c2 = 'A' + (i%26);
pst = pst + c1 + c2;
// Reuse license message created above.
ASSERT_NO_FATAL_FAILURE(sessions[i].ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_))
<< "Failed to reload license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(
@@ -4670,7 +4720,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoEncrypt) {
std::string pst = "A PST";
uint32_t nonce = session_.get_nonce();
MakeFourKeys(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
nonce, pst);
ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
@@ -4707,7 +4757,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoDecrypt) {
std::string pst = "my_pst";
uint32_t nonce = session_.get_nonce();
MakeFourKeys(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
nonce, pst);
ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
@@ -4744,7 +4794,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoSign) {
std::string pst = "my_pst";
uint32_t nonce = session_.get_nonce();
MakeFourKeys(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
nonce, pst);
ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
@@ -4792,7 +4842,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoVerify) {
std::string pst = "my_pst";
uint32_t nonce = session_.get_nonce();
MakeFourKeys(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
nonce, pst);
ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
@@ -4835,7 +4885,7 @@ TEST_P(UsageTableTestWithMAC, OfflineLicenseRefresh) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
@@ -4846,7 +4896,7 @@ TEST_P(UsageTableTestWithMAC, OfflineLicenseRefresh) {
ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature());
size_t kAllKeys = 1;
ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(
kAllKeys, wvoec_mock::kControlNonceOrEntry, 0, OEMCrypto_SUCCESS));
kAllKeys, wvoec::kControlNonceOrEntry, 0, OEMCrypto_SUCCESS));
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(
@@ -4862,10 +4912,10 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicense) {
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// We will reuse the encrypted and signed message, so we don't call
// FillSimpleMessage again.
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kUnused));
@@ -4882,10 +4932,10 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithRefresh) {
time_t loaded = time(NULL);
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// We will reuse the encrypted and signed message, so we don't call
// FillSimpleMessage again.
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kUnused, loaded, 0, 0));
@@ -4899,7 +4949,7 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithRefresh) {
decrypt_time)); // last decrypt
size_t kAllKeys = 1;
ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(
kAllKeys, wvoec_mock::kControlNonceOrEntry, 0, OEMCrypto_SUCCESS));
kAllKeys, wvoec::kControlNonceOrEntry, 0, OEMCrypto_SUCCESS));
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kActive,
@@ -4920,10 +4970,10 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithTerminate) {
encrypted_usage_header_.size()));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// We will reuse the encrypted and signed message, so we don't call
// FillSimpleMessage again.
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kUnused));
@@ -4937,13 +4987,14 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) {
std::string pst = "my_pst";
Session s;
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
time_t loaded = time(NULL);
// Offline license with new mac keys should fail.
Session s2;
ASSERT_NO_FATAL_FAILURE(s2.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
ASSERT_NO_FATAL_FAILURE(s2.FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, s2.get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, s2.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s2.LoadUsageEntry(s));
uint8_t* pst_ptr = s2.encrypted_license().pst;
@@ -4959,11 +5010,14 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) {
// Offline license with same mac keys should still be OK.
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s.GenerateVerifyReport(pst, kUnused));
ASSERT_NO_FATAL_FAILURE(
s.GenerateVerifyReport(pst, kUnused,
loaded, // license loaded.
0, 0)); // first and last decrypt
}
// An offline license should not load on the first call if the nonce is bad.
@@ -4974,7 +5028,7 @@ TEST_P(UsageTableTestWithMAC, OfflineBadNonce) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, 42, pst));
s.FillSimpleMessage(0, wvoec::kControlNonceOrEntry, 42, pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
uint8_t* pst_ptr = s.encrypted_license().pst;
OEMCryptoResult sts = OEMCrypto_LoadKeys(
@@ -4993,7 +5047,7 @@ TEST_P(UsageTableTestWithMAC, OfflineEmptyPST) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
ASSERT_NO_FATAL_FAILURE(
s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, s.get_nonce()));
s.FillSimpleMessage(0, wvoec::kControlNonceOrEntry, s.get_nonce()));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
OEMCryptoResult sts = OEMCrypto_LoadKeys(
s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0],
@@ -5031,8 +5085,8 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) {
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(
s.LoadTestKeys(pst, new_mac_keys_)); // Reload the license
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); // Should be able to decrypt.
@@ -5075,7 +5129,7 @@ TEST_P(UsageTableTestWithMAC, BadRange) {
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry());
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
uint8_t* pst_ptr = s.license().pst; // Bad: not in encrypted_license.
ASSERT_NE(
@@ -5094,7 +5148,7 @@ TEST_F(UsageTableTest, UpdateFailsWithNullPtr) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -5124,7 +5178,7 @@ class UsageTableDefragTest : public UsageTableTest {
char c2 = 'A' + (index % 26);
pst = pst + c1 + c2;
ASSERT_NO_FATAL_FAILURE(s->FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, s->get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, s->get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s->EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s->CreateNewUsageEntry());
ASSERT_EQ(s->usage_entry_number(), index);
@@ -5136,8 +5190,8 @@ class UsageTableDefragTest : public UsageTableTest {
void ReloadLicense(Session* s, time_t start) {
ASSERT_NO_FATAL_FAILURE(s->open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(s));
ASSERT_NO_FATAL_FAILURE(s->ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(s));
ASSERT_NO_FATAL_FAILURE(s->LoadTestKeys(s->pst(), new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s->UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s->TestDecryptCTR());
@@ -5351,10 +5405,10 @@ TEST_F(UsageTableTest, ReloadUsageTableWithSkew) {
// Reload the license, and save the header.
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// We will reuse the encrypted and signed message, so we don't call
// FillSimpleMessage again.
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
vector<uint8_t> old_usage_header_2_ = encrypted_usage_header_;
@@ -5370,14 +5424,13 @@ TEST_F(UsageTableTest, ReloadUsageTableWithSkew) {
OEMCrypto_LoadUsageTableHeader(NULL,
old_usage_header_2_.size()));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// Cannot load an entry with if header didn't load.
ASSERT_EQ(
OEMCrypto_ERROR_UNKNOWN_FAILURE,
OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(),
&s.encrypted_usage_entry()[0],
s.encrypted_usage_entry().size()));
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.close());
// Modified header generates error.
@@ -5387,14 +5440,13 @@ TEST_F(UsageTableTest, ReloadUsageTableWithSkew) {
OEMCrypto_LoadUsageTableHeader(&bad_header[0],
bad_header.size()));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// Cannot load an entry with if header didn't load.
ASSERT_EQ(
OEMCrypto_ERROR_UNKNOWN_FAILURE,
OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(),
&s.encrypted_usage_entry()[0],
s.encrypted_usage_entry().size()));
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.close());
// Old by 2 generation numbers is error.
@@ -5402,14 +5454,13 @@ TEST_F(UsageTableTest, ReloadUsageTableWithSkew) {
OEMCrypto_LoadUsageTableHeader(&old_usage_header_2_[0],
old_usage_header_2_.size()));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// Cannot load an entry with if header didn't load.
ASSERT_NE(
OEMCrypto_SUCCESS,
OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(),
&s.encrypted_usage_entry()[0],
s.encrypted_usage_entry().size()));
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.close());
// Old by 1 generation numbers is just warning.
@@ -5418,12 +5469,12 @@ TEST_F(UsageTableTest, ReloadUsageTableWithSkew) {
old_usage_header_1_.size()));
// Everything else should still work. Skew by 1 is just a warning.
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_EQ(
OEMCrypto_WARNING_GENERATION_SKEW,
OEMCrypto_LoadUsageEntry(s.session_id(), s.usage_entry_number(),
&s.encrypted_usage_entry()[0],
s.encrypted_usage_entry().size()));
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s.close());
@@ -5435,7 +5486,7 @@ TEST_F(UsageTableTest, GenerateReportWrongPST) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst));
0, wvoec::kControlNonceOrEntry, s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_));
@@ -5460,15 +5511,15 @@ TEST_F(UsageTableTest, TimingTest) {
sleep(kLongSleep);
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst1, new_mac_keys_));
time_t first_decrypt1 = time(NULL);
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s2.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
ASSERT_NO_FATAL_FAILURE(s2.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
ASSERT_NO_FATAL_FAILURE(s2.LoadTestKeys(pst2, new_mac_keys_));
time_t first_decrypt2 = time(NULL);
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
@@ -5498,8 +5549,8 @@ TEST_F(UsageTableTest, TimingTest) {
sleep(kLongSleep);
time_t third_decrypt = time(NULL);
ASSERT_NO_FATAL_FAILURE(s2.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
ASSERT_NO_FATAL_FAILURE(s2.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2));
ASSERT_NO_FATAL_FAILURE(s2.LoadTestKeys(pst2, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_));
@@ -5532,7 +5583,7 @@ TEST_F(UsageTableTest, VerifyUsageTimes) {
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
0, wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired,
s.get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry());
@@ -5616,6 +5667,86 @@ TEST_F(UsageTableTest, VerifyUsageTimes) {
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
}
// NOTE: This test needs root access since clock_settime messes with the system
// time in order to verify that OEMCrypto protects against rollbacks in usage
// entries. Therefore, this test is filtered if not run as root.
// We don't test roll-forward protection or instances where the user rolls back
// the time to the last decrypt call since this requires hardware-secure clocks
// to guarantee.
TEST_F(UsageTableTest, TimeRollbackPrevention) {
std::string pst = "my_pst";
Session s1;
cout << "This test temporarily rolls back the system time in order to verify "
<< "that the usage report accounts for the change. It then rolls "
<< "the time back forward to the absolute time." << endl;
// We use clock_gettime(CLOCK_REALTIME, ...) over time(...) so we can easily
// set the time using clock_settime.
timespec current_time;
ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &current_time));
time_t loaded = current_time.tv_sec;
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s1, pst));
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst, new_mac_keys_));
ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &current_time));
time_t first_decrypt = current_time.tv_sec;
// Monotonic clock can't be changed. We use this since system clock will be
// unreliable.
ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &current_time));
time_t first_decrypt_monotonic = current_time.tv_sec;
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s1.close());
// Imitate playback.
sleep(kLongDuration * 2);
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s1.close());
ASSERT_EQ(0, clock_gettime(CLOCK_REALTIME, &current_time));
// Rollback the wall clock time.
cout << "Rolling the system time back..." << endl;
timeval current_time_of_day = {};
current_time_of_day.tv_sec = current_time.tv_sec - kLongDuration * 10;
ASSERT_EQ(0, settimeofday(&current_time_of_day, NULL));
// Try to playback again.
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst, new_mac_keys_));
ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &current_time));
time_t third_decrypt = current_time.tv_sec;
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s1.GenerateReport(pst));
Test_PST_Report expected(pst, kActive);
// Restore wall clock to its original position to verify that OEMCrypto does
// not report negative times.
ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, &current_time));
current_time_of_day.tv_sec =
first_decrypt + current_time.tv_sec - first_decrypt_monotonic;
cout << "Rolling the system time forward to the absolute time..." << endl;
ASSERT_EQ(0, settimeofday(&current_time_of_day, NULL));
// Need to update time created since the verification checks the time of PST
// report creation.
expected.time_created = current_time_of_day.tv_sec;
ASSERT_NO_FATAL_FAILURE(
s1.VerifyReport(expected, loaded, first_decrypt,
first_decrypt + third_decrypt - first_decrypt_monotonic));
ASSERT_NO_FATAL_FAILURE(s1.close());
}
// This is a special case where a group of assets can be licensed with a master
// key. In order for this to work, a single session must first load a device
// specific license, and then a shared content license. This shared license is
@@ -5626,10 +5757,10 @@ TEST_F(UsageTableTest, LoadSharedLicense) {
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// We will reuse the encrypted and signed message, so we don't call
// FillSimpleMessage again.
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, true));
// The second set of keys are in the shared license. They will have the
@@ -5642,7 +5773,7 @@ TEST_F(UsageTableTest, LoadSharedLicense) {
s.license().keys[i].key_id_length);
s.license().keys[i].control.nonce = 0;
s.license().keys[i].control.control_bits =
htonl(wvoec_mock::kSharedLicense);
htonl(wvoec::kSharedLicense);
}
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, false));
@@ -5656,8 +5787,8 @@ TEST_F(UsageTableTest, LoadSharedLicenseWithNoMaster) {
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
// This time, we do NOT load the master license. This should
// generate an error below.
// ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, true));
@@ -5671,7 +5802,7 @@ TEST_F(UsageTableTest, LoadSharedLicenseWithNoMaster) {
s.license().keys[i].key_id_length);
s.license().keys[i].control.nonce = 0;
s.license().keys[i].control.control_bits =
htonl(wvoec_mock::kSharedLicense);
htonl(wvoec::kSharedLicense);
}
ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign());
uint8_t* pst_ptr = s.encrypted_license().pst;
@@ -5692,8 +5823,8 @@ TEST_F(UsageTableTest, PSTLargeBuffer) {
ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst));
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(s.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s));
ASSERT_NO_FATAL_FAILURE(
s.LoadTestKeys(pst, new_mac_keys_)); // Reload the license
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); // Should be able to decrypt.

View File

@@ -142,10 +142,10 @@ TEST_F(OEMCryptoAndroidOCTest, MinVersionNumber13) {
ASSERT_GE(version, 13u);
}
// These tests are required for Pi Android devices.
class OEMCryptoAndroidPiTest : public OEMCryptoAndroidOCTest {};
// These tests are required for Pi MR1 Android devices.
class OEMCryptoAndroidPiMR1Test : public OEMCryptoAndroidOCTest {};
TEST_F(OEMCryptoAndroidPiTest, MinVersionNumber14) {
TEST_F(OEMCryptoAndroidPiMR1Test, MinVersionNumber14) {
uint32_t version = OEMCrypto_APIVersion();
ASSERT_GE(version, 14u);
}

View File

@@ -4,7 +4,9 @@
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_device_features.h"
#ifdef CDM_TESTS
#include "properties.h"
#endif
static void acknowledge_cast() {
std::cout
@@ -15,7 +17,9 @@ static void acknowledge_cast() {
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
#ifdef CDM_TESTS
wvcdm::Properties::Init();
#endif
wvcdm::g_cutoff = wvcdm::LOG_INFO;
bool is_cast_receiver = false;
bool force_load_test_keybox = false;

View File

@@ -0,0 +1,40 @@
# This is a gyp file for building the OEMCrypto unit tests with the reference
# code from the stand-alone source code.
{
'variables': {
# Override the variables below for the location of various gyp files.
# Alternatively, set the environment variable CDM_DIR to point to a recent
# version of the source CDM.
'boringssl_dependency%': '<!(echo $CDM_DIR)/third_party/boringssl/boringssl.gyp:legacy_ssl',
'gtest_dependency%': '<!(echo $CDM_DIR)/third_party/gmock.gyp:gtest',
'gmock_dependency%': '<!(echo $CDM_DIR)/third_party/gmock.gyp:gmock',
'oemcrypto_dir%': '..',
'util_dir%': '../../util',
'platform_specific_dir%': '<!(echo $CDM_DIR)/linux/src',
},
'targets': [
{
'target_name': 'oemcrypto_unittests',
'type': 'executable',
'sources': [
'oemcrypto_test_main.cpp',
'<(platform_specific_dir)/file_store.cpp',
'<(platform_specific_dir)/lock.cpp',
'<(platform_specific_dir)/log.cpp',
'<(util_dir)/src/string_conversions.cpp',
],
'includes': [
'oemcrypto_unittests.gypi',
'../ref/oec_ref.gypi',
],
'libraries': [
'-lpthread', # gtest
],
'dependencies': [
'<(boringssl_dependency)',
'<(gtest_dependency)',
'<(gmock_dependency)',
],
},
],
}

View File

@@ -0,0 +1,25 @@
# 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.
#
# Include this in any custom unit test targets.
# Does not include the test runner main.
{
'sources': [
'oec_device_features.cpp',
'oec_session_util.cpp',
'oemcrypto_session_tests_helper.cpp',
'oemcrypto_test.cpp',
],
'include_dirs': [
'<(util_dir)/include',
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/test',
],
'defines': [
'OEMCRYPTO_TESTS',
],
'dependencies': [
'<(boringssl_dependency)',
],
}

24
util/include/clock.h Normal file
View File

@@ -0,0 +1,24 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Clock - Platform independent interface for a time library
//
#ifndef WVCDM_UTIL_CLOCK_H_
#define WVCDM_UTIL_CLOCK_H_
#include <stdint.h>
namespace wvcdm {
// Provides time related information. The implementation is platform dependent.
class Clock {
public:
Clock() {}
virtual ~Clock() {}
// Provides the number of seconds since an epoch - 01/01/1970 00:00 UTC
virtual int64_t GetCurrentTime();
};
} // namespace wvcdm
#endif // WVCDM_UTIL_CLOCK_H_

View File

@@ -0,0 +1,15 @@
// Copyright 2018 Google Inc. All Rights Reserved.
#ifndef WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_
#define WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_
namespace wvcdm {
#define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
} // namespace wvcdm
#endif // WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_

80
util/include/file_store.h Normal file
View File

@@ -0,0 +1,80 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// File - Platform independent interface for a File class
//
#ifndef WVCDM_UTIL_FILE_STORE_H_
#define WVCDM_UTIL_FILE_STORE_H_
#include <unistd.h>
#include <string>
#include <vector>
#include "disallow_copy_and_assign.h"
namespace wvcdm {
// File class. The implementation is platform dependent.
class File {
public:
virtual ssize_t Read(char* buffer, size_t bytes);
virtual ssize_t Write(const char* buffer, size_t bytes);
virtual void Close();
protected:
class Impl;
File(Impl*);
virtual ~File();
private:
Impl* impl_;
friend class FileSystem;
CORE_DISALLOW_COPY_AND_ASSIGN(File);
};
class FileSystem {
public:
class Impl;
// defines as bit flag
enum OpenFlags {
kNoFlags = 0,
kCreate = 1,
kReadOnly = 2, // defaults to read and write access
kTruncate = 4
};
FileSystem();
FileSystem(const std::string& origin, void* extra_data);
virtual ~FileSystem();
virtual File* Open(const std::string& file_path, int flags);
virtual bool Exists(const std::string& file_path);
virtual bool Remove(const std::string& file_path);
virtual ssize_t FileSize(const std::string& file_path);
// Return the filenames stored at dir_path.
// dir_path will be stripped from the returned names.
virtual bool List(const std::string& dir_path,
std::vector<std::string>* names);
const std::string& origin() const { return origin_; }
void SetOrigin(const std::string& origin);
const std::string& identifier() const { return identifier_; }
void SetIdentifier(const std::string& identifier);
bool IsGlobal() const { return identifier_.empty(); }
private:
Impl* impl_;
std::string origin_;
std::string identifier_;
CORE_DISALLOW_COPY_AND_ASSIGN(FileSystem);
};
} // namespace wvcdm
#endif // WVCDM_UTIL_FILE_STORE_H_

51
util/include/lock.h Normal file
View File

@@ -0,0 +1,51 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Lock - Platform independent interface for a Mutex class
//
#ifndef WVCDM_UTIL_LOCK_H_
#define WVCDM_UTIL_LOCK_H_
#include "disallow_copy_and_assign.h"
namespace wvcdm {
// Simple lock class. The implementation is platform dependent.
//
// The lock must be unlocked by the thread that locked it.
// The lock is also not recursive (ie. cannot be taken multiple times).
class Lock {
public:
Lock();
~Lock();
void Acquire();
void Release();
friend class AutoLock;
private:
class Impl;
Impl* impl_;
CORE_DISALLOW_COPY_AND_ASSIGN(Lock);
};
// Manages the lock automatically. It will be locked when AutoLock
// is constructed and release when AutoLock goes out of scope.
class AutoLock {
public:
explicit AutoLock(Lock& lock) : lock_(&lock) { lock_->Acquire(); }
explicit AutoLock(Lock* lock) : lock_(lock) { lock_->Acquire(); }
~AutoLock() { lock_->Release(); }
private:
Lock* lock_;
CORE_DISALLOW_COPY_AND_ASSIGN(AutoLock);
};
} // namespace wvcdm
#endif // WVCDM_UTIL_LOCK_H_

46
util/include/log.h Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Log - Platform independent interface for a Logging class
//
#ifndef WVCDM_UTIL_LOG_H_
#define WVCDM_UTIL_LOG_H_
namespace wvcdm {
// Simple logging class. The implementation is platform dependent.
typedef enum {
LOG_ERROR,
LOG_WARN,
LOG_INFO,
LOG_DEBUG,
LOG_VERBOSE
} LogPriority;
extern LogPriority g_cutoff;
// Enable/disable verbose logging (LOGV).
// This function is supplied for cases where the system layer does not
// initialize logging. This is also needed to initialize logging in
// unit tests.
void InitLogging();
void Log(const char* file, const char* function, int line, LogPriority level,
const char* fmt, ...);
// Log APIs
#ifndef LOGE
#define LOGE(...) Log(__FILE__, __func__, __LINE__, \
wvcdm::LOG_ERROR, __VA_ARGS__)
#define LOGW(...) Log(__FILE__, __func__, __LINE__, \
wvcdm::LOG_WARN, __VA_ARGS__)
#define LOGI(...) Log(__FILE__, __func__, __LINE__, \
wvcdm::LOG_INFO, __VA_ARGS__)
#define LOGD(...) Log(__FILE__, __func__, __LINE__, \
wvcdm::LOG_DEBUG, __VA_ARGS__)
#define LOGV(...) Log(__FILE__, __func__, __LINE__, \
wvcdm::LOG_VERBOSE, __VA_ARGS__)
#endif
} // namespace wvcdm
#endif // WVCDM_UTIL_LOG_H_

View File

@@ -0,0 +1,30 @@
// Copyright 2013 Google Inc. All Rights Reserved.
#ifndef WVCDM_UTIL_STRING_CONVERSIONS_H_
#define WVCDM_UTIL_STRING_CONVERSIONS_H_
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <vector>
namespace wvcdm {
std::vector<uint8_t> a2b_hex(const std::string& b);
std::vector<uint8_t> a2b_hex(const std::string& label, const std::string& b);
std::string a2bs_hex(const std::string& b);
std::string b2a_hex(const std::vector<uint8_t>& b);
std::string b2a_hex(const std::string& b);
std::string Base64Encode(const std::vector<uint8_t>& bin_input);
std::vector<uint8_t> Base64Decode(const std::string& bin_input);
std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input);
std::string Base64SafeEncodeNoPad(const std::vector<uint8_t>& bin_input);
std::vector<uint8_t> Base64SafeDecode(const std::string& bin_input);
std::string HexEncode(const uint8_t* bytes, unsigned size);
std::string IntToString(int value);
int64_t htonll64(int64_t x);
inline int64_t ntohll64(int64_t x) { return htonll64(x); }
} // namespace wvcdm
#endif // WVCDM_UTIL_STRING_CONVERSIONS_H_

View File

@@ -0,0 +1,293 @@
// Copyright 2013 Google Inc. All Rights Reserved.
#include "string_conversions.h"
#include <arpa/inet.h>
#include <ctype.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
#include "log.h"
namespace wvcdm {
static const char kBase64Codes[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// Gets the low |n| bits of |in|.
#define GET_LOW_BITS(in, n) ((in) & ((1 << (n)) - 1))
// Gets the given (zero-indexed) bits [a, b) of |in|.
#define GET_BITS(in, a, b) GET_LOW_BITS((in) >> (a), (b) - (a))
// Calculates a/b using round-up division (only works for positive numbers).
#define CEIL_DIVIDE(a, b) ((((a) - 1) / (b)) + 1)
int DecodeBase64Char(char c) {
const char* it = strchr(kBase64Codes, c);
if (it == NULL)
return -1;
return it - kBase64Codes;
}
bool DecodeHexChar(char ch, unsigned char* digit) {
if (ch >= '0' && ch <= '9') {
*digit = ch - '0';
} else {
ch = tolower(ch);
if ((ch >= 'a') && (ch <= 'f')) {
*digit = ch - 'a' + 10;
} else {
return false;
}
}
return true;
}
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
std::vector<uint8_t> a2b_hex(const std::string& byte) {
std::vector<uint8_t> array;
unsigned int count = byte.size();
if (count == 0 || (count % 2) != 0) {
LOGE("Invalid input size %u for string %s", count, byte.c_str());
return array;
}
for (unsigned int i = 0; i < count / 2; ++i) {
unsigned char msb = 0; // most significant 4 bits
unsigned char lsb = 0; // least significant 4 bits
if (!DecodeHexChar(byte[i * 2], &msb) ||
!DecodeHexChar(byte[i * 2 + 1], &lsb)) {
LOGE("Invalid hex value %c%c at index %d", byte[i * 2], byte[i * 2 + 1],
i);
return array;
}
array.push_back((msb << 4) | lsb);
}
return array;
}
// converts an ascii hex string(2 bytes per digit) into a decimal byte string
// dump the string with the label.
std::vector<uint8_t> a2b_hex(const std::string& label,
const std::string& byte) {
std::cout << std::endl
<< "[[DUMP: " << label << " ]= \"" << byte << "\"]" << std::endl
<< std::endl;
return a2b_hex(byte);
}
std::string a2bs_hex(const std::string& byte) {
std::vector<uint8_t> array = a2b_hex(byte);
return std::string(array.begin(), array.end());
}
std::string b2a_hex(const std::vector<uint8_t>& byte) {
return HexEncode(&byte[0], byte.size());
}
std::string b2a_hex(const std::string& byte) {
return HexEncode(reinterpret_cast<const uint8_t*>(byte.data()),
byte.length());
}
// Encode for standard base64 encoding (RFC4648).
// https://en.wikipedia.org/wiki/Base64
// Text | M | a | n |
// ASCI | 77 (0x4d) | 97 (0x61) | 110 (0x6e) |
// Bits | 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 |
// Index | 19 | 22 | 5 | 46 |
// Base64 | T | W | F | u |
// | <----------------- 24-bits -----------------> |
std::string Base64Encode(const std::vector<uint8_t>& bin_input) {
if (bin_input.empty()) {
return std::string();
}
// |temp| stores a 24-bit block that is treated as an array where insertions
// occur from high to low.
uint32_t temp = 0;
size_t out_index = 0;
const size_t out_size = CEIL_DIVIDE(bin_input.size(), 3) * 4;
std::string result(out_size, '\0');
for (size_t i = 0; i < bin_input.size(); i++) {
// "insert" 8-bits of data
temp |= (bin_input[i] << ((2 - (i % 3)) * 8));
if (i % 3 == 2) {
result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)];
result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)];
result[out_index++] = kBase64Codes[GET_BITS(temp, 6, 12)];
result[out_index++] = kBase64Codes[GET_BITS(temp, 0, 6)];
temp = 0;
}
}
if (bin_input.size() % 3 == 1) {
result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)];
result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)];
result[out_index++] = '=';
result[out_index++] = '=';
} else if (bin_input.size() % 3 == 2) {
result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)];
result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)];
result[out_index++] = kBase64Codes[GET_BITS(temp, 6, 12)];
result[out_index++] = '=';
}
return result;
}
// Filename-friendly base64 encoding (RFC4648), commonly referred to
// as Base64WebSafeEncode.
//
// This is the encoding required to interface with the provisioning server, as
// well as for certain license server transactions. It is also used for logging
// certain strings. The difference between web safe encoding vs regular encoding
// is that the web safe version replaces '+' with '-' and '/' with '_'.
std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
if (bin_input.empty()) {
return std::string();
}
std::string ret = Base64Encode(bin_input);
for (size_t i = 0; i < ret.size(); i++) {
if (ret[i] == '+')
ret[i] = '-';
else if (ret[i] == '/')
ret[i] = '_';
}
return ret;
}
std::string Base64SafeEncodeNoPad(const std::vector<uint8_t>& bin_input) {
std::string b64_output = Base64SafeEncode(bin_input);
// Output size: ceiling [ bin_input.size() * 4 / 3 ].
b64_output.resize((bin_input.size() * 4 + 2) / 3);
return b64_output;
}
// Decode for standard base64 encoding (RFC4648).
std::vector<uint8_t> Base64Decode(const std::string& b64_input) {
if (b64_input.empty()) {
return std::vector<uint8_t>();
}
const size_t out_size_max = CEIL_DIVIDE(b64_input.size() * 3, 4);
std::vector<uint8_t> result(out_size_max, '\0');
// |temp| stores 24-bits of data that is treated as an array where insertions
// occur from high to low.
uint32_t temp = 0;
size_t out_index = 0;
size_t i;
for (i = 0; i < b64_input.size(); i++) {
if (b64_input[i] == '=') {
// Verify an '=' only appears at the end. We want i to remain at the
// first '=', so we need an inner loop.
for (size_t j = i; j < b64_input.size(); j++) {
if (b64_input[j] != '=') {
LOGE("base64Decode failed");
return std::vector<uint8_t>();
}
}
break;
}
const int decoded = DecodeBase64Char(b64_input[i]);
if (decoded < 0) {
LOGE("base64Decode failed");
return std::vector<uint8_t>();
}
// "insert" 6-bits of data
temp |= (decoded << ((3 - (i % 4)) * 6));
if (i % 4 == 3) {
result[out_index++] = GET_BITS(temp, 16, 24);
result[out_index++] = GET_BITS(temp, 8, 16);
result[out_index++] = GET_BITS(temp, 0, 8);
temp = 0;
}
}
switch (i % 4) {
case 1:
LOGE("base64Decode failed");
return std::vector<uint8_t>();
case 2:
result[out_index++] = GET_BITS(temp, 16, 24);
break;
case 3:
result[out_index++] = GET_BITS(temp, 16, 24);
result[out_index++] = GET_BITS(temp, 8, 16);
break;
}
result.resize(out_index);
return result;
}
// Decode for Filename-friendly base64 encoding (RFC4648), commonly referred
// as Base64WebSafeDecode. Add padding if needed.
std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
if (b64_input.empty()) {
return std::vector<uint8_t>();
}
// Make a copy so we can modify it to replace the web-safe special characters
// with the normal ones.
std::string input_copy = b64_input;
for (size_t i = 0; i < input_copy.size(); i++) {
if (input_copy[i] == '-')
input_copy[i] = '+';
else if (input_copy[i] == '_')
input_copy[i] = '/';
}
return Base64Decode(input_copy);
}
std::string HexEncode(const uint8_t* in_buffer, unsigned int size) {
static const char kHexChars[] = "0123456789ABCDEF";
// Each input byte creates two output hex characters.
std::string out_buffer(size * 2, '\0');
for (unsigned int i = 0; i < size; ++i) {
char byte = in_buffer[i];
out_buffer[(i << 1)] = kHexChars[(byte >> 4) & 0xf];
out_buffer[(i << 1) + 1] = kHexChars[byte & 0xf];
}
return out_buffer;
}
std::string IntToString(int value) {
// log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
// So round up to allocate 3 output characters per byte, plus 1 for '-'.
const int kOutputBufSize = 3 * sizeof(int) + 1;
char buffer[kOutputBufSize];
memset(buffer, 0, kOutputBufSize);
snprintf(buffer, kOutputBufSize, "%d", value);
std::string out_string(buffer);
return out_string;
}
int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order)
union {
uint32_t array[2];
int64_t number;
} mixed;
mixed.number = 1;
if (mixed.array[0] == 1) { // Little Endian.
mixed.number = x;
uint32_t temp = mixed.array[0];
mixed.array[0] = htonl(mixed.array[1]);
mixed.array[1] = htonl(temp);
return mixed.number;
} else { // Big Endian.
return x;
}
}
} // namespace wvcdm