Refactor
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:
BIN
docs/Widevine_DRM_Device_Provisioning_Models.pdf
Normal file
BIN
docs/Widevine_DRM_Device_Provisioning_Models.pdf
Normal file
Binary file not shown.
@@ -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
|
||||
@@ -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_
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
67
oemcrypto/include/oemcrypto_types.h
Normal file
67
oemcrypto/include/oemcrypto_types.h
Normal 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_
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
41
oemcrypto/ref/oec_ref.gypi
Normal file
41
oemcrypto/ref/oec_ref.gypi
Normal 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)',
|
||||
],
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
44
oemcrypto/ref/src/oemcrypto_scoped_ptr.h
Normal file
44
oemcrypto/ref/src/oemcrypto_scoped_ptr.h
Normal 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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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) {
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_keybox.h"
|
||||
#include "oemcrypto_types.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
@@ -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,
|
||||
@@ -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_|.
|
||||
@@ -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
|
||||
@@ -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,
|
||||
@@ -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
|
||||
@@ -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, ¤t_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, ¤t_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, ¤t_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, ¤t_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(¤t_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, ¤t_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, ¤t_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(¤t_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.
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
40
oemcrypto/test/oemcrypto_unittests.gyp
Normal file
40
oemcrypto/test/oemcrypto_unittests.gyp
Normal 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)',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
25
oemcrypto/test/oemcrypto_unittests.gypi
Normal file
25
oemcrypto/test/oemcrypto_unittests.gypi
Normal 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
24
util/include/clock.h
Normal 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_
|
||||
15
util/include/disallow_copy_and_assign.h
Normal file
15
util/include/disallow_copy_and_assign.h
Normal 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
80
util/include/file_store.h
Normal 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
51
util/include/lock.h
Normal 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
46
util/include/log.h
Normal 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_
|
||||
30
util/include/string_conversions.h
Normal file
30
util/include/string_conversions.h
Normal 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_
|
||||
293
util/src/string_conversions.cpp
Normal file
293
util/src/string_conversions.cpp
Normal 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
|
||||
Reference in New Issue
Block a user