Use local provisioning server am: 44ba42f5cc
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/16058116 Change-Id: Ib10701963fc4ba89d37f49b95186640244576305
This commit is contained in:
committed by
Automerger Merge Worker
commit
556940237f
@@ -287,6 +287,19 @@ class CryptoSession {
|
||||
virtual CdmResponseType GetProvisioningMethod(
|
||||
SecurityLevel requested_security_level, CdmClientTokenType* token_type);
|
||||
|
||||
// OTA Provisioning
|
||||
// TODO(sigquit): include rest of http://go/wvgerrit/126004
|
||||
|
||||
// Generates an OTA provisioning request.
|
||||
// This should only be called by an instance of OtaKeyboxProvisioner.
|
||||
virtual CdmResponseType PrepareOtaProvisioningRequest(bool use_test_key,
|
||||
std::string* request);
|
||||
|
||||
// Loads an OTA provisioning response.
|
||||
// This should only be called by an instance of OtaKeyboxProvisioner.
|
||||
virtual CdmResponseType LoadOtaProvisioning(bool use_test_key,
|
||||
const std::string& response);
|
||||
|
||||
protected:
|
||||
// Creates an instance of CryptoSession with the given |crypto_metrics|.
|
||||
// |crypto_metrics| is owned by the caller, must NOT be null, and must
|
||||
@@ -294,6 +307,10 @@ class CryptoSession {
|
||||
explicit CryptoSession(metrics::CryptoMetrics* crypto_metrics);
|
||||
|
||||
int session_count() const { return session_count_; }
|
||||
bool initialized() const { return initialized_; }
|
||||
void OverrideInitializedForTesting(bool initialized) {
|
||||
initialized_ = initialized;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class CryptoSessionForTest;
|
||||
@@ -434,6 +451,7 @@ class CryptoSession {
|
||||
static bool initialized_;
|
||||
static int session_count_;
|
||||
static int termination_counter_;
|
||||
static bool needs_keybox_provisioning_;
|
||||
|
||||
enum CachedBooleanProperty {
|
||||
// Property has not yet been checked/cached.
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
// Initialize OEMCrypto, then check the keybox and see if it is valid. If not,
|
||||
// and OTA provisioning is supported, set needs_keybox_provisioning to true.
|
||||
// If the keybox is not valid and OTA provisioning is not supported, set
|
||||
// needs_keybox_provisioning to false and use L3 only.
|
||||
OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
||||
bool* needs_keybox_provisioning);
|
||||
|
||||
// This attempts to open a session at the desired security level.
|
||||
// If one level is not available, the other will be used instead.
|
||||
@@ -17,7 +23,6 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
|
||||
size_t keyBoxLength,
|
||||
SecurityLevel level);
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(SecurityLevel level);
|
||||
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
|
||||
SecurityLevel level);
|
||||
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
|
||||
|
||||
@@ -85,7 +85,7 @@ constexpr size_t kMaxSubsampleRegionSizes[] = {
|
||||
static_assert(ArraySize(kMaxSubsampleRegionSizes) ==
|
||||
RESOURCE_RATING_TIER_MAX - RESOURCE_RATING_TIER_MIN + 1,
|
||||
"The kMaxSubsampleRegionSizes table needs to be updated to "
|
||||
"reflect the supported range of resource rating tiers.");
|
||||
"reflect the supported range of resource rating tiers");
|
||||
|
||||
constexpr size_t kDefaultMaxSubsampleRegionSize = kMaxSubsampleRegionSizes[0];
|
||||
|
||||
@@ -171,6 +171,7 @@ size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm) {
|
||||
shared_mutex CryptoSession::static_field_mutex_;
|
||||
shared_mutex CryptoSession::oem_crypto_mutex_;
|
||||
bool CryptoSession::initialized_ = false;
|
||||
bool CryptoSession::needs_keybox_provisioning_ = false;
|
||||
int CryptoSession::session_count_ = 0;
|
||||
int CryptoSession::termination_counter_ = 0;
|
||||
std::unique_ptr<UsageTableHeader> CryptoSession::usage_table_header_l1_;
|
||||
@@ -321,8 +322,9 @@ void CryptoSession::Init() {
|
||||
sandbox_id.length());
|
||||
metrics_->oemcrypto_set_sandbox_.Record(sandbox_id);
|
||||
}
|
||||
M_TIME(sts = OEMCrypto_Initialize(), metrics_, oemcrypto_initialize_,
|
||||
sts);
|
||||
M_TIME(sts = OEMCrypto_InitializeAndCheckKeybox(
|
||||
&needs_keybox_provisioning_),
|
||||
metrics_, oemcrypto_initialize_, sts);
|
||||
});
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("OEMCrypto_Initialize failed: status = %d", static_cast<int>(sts));
|
||||
@@ -357,6 +359,10 @@ void CryptoSession::Init() {
|
||||
: kStringNotAvailable;
|
||||
LOGD("OEMCrypto version (L3 security level): %s.%s", api_version.c_str(),
|
||||
api_minor_version.c_str());
|
||||
if (needs_keybox_provisioning_) {
|
||||
LOGE("OEMCrypto needs provisioning");
|
||||
// TODO(fredgc,sigquit,rfrias): handle provisioning.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1440,7 +1446,7 @@ size_t CryptoSession::GetMaxSubsampleRegionSize() {
|
||||
|
||||
// If something went wrong, use the default.
|
||||
if (max_subsample_region_size_ == 0) {
|
||||
LOGW("Unable to get maximum subsample region size. Defaulting to %zu.",
|
||||
LOGW("Unable to get maximum subsample region size. Defaulting to %zu",
|
||||
kDefaultMaxSubsampleRegionSize);
|
||||
max_subsample_region_size_ = kDefaultMaxSubsampleRegionSize;
|
||||
}
|
||||
@@ -2994,7 +3000,7 @@ OEMCryptoResult CryptoSession::LegacyDecryptInChunks(
|
||||
|
||||
static_assert(sizeof(fake_sample.iv) == kAes128BlockSize,
|
||||
"The size of an AES-128 block and the size of an AES-128 "
|
||||
"IV have become misaligned.");
|
||||
"IV have become misaligned");
|
||||
memcpy(fake_sample.iv, block_end - kAes128BlockSize, kAes128BlockSize);
|
||||
}
|
||||
}
|
||||
@@ -3009,6 +3015,33 @@ OEMCryptoResult CryptoSession::LegacyDecryptInChunks(
|
||||
return sts;
|
||||
}
|
||||
|
||||
// TODO(sigquit): include rest of http://go/wvgerrit/126004
|
||||
|
||||
CdmResponseType CryptoSession::PrepareOtaProvisioningRequest(
|
||||
bool use_test_key, std::string* request) {
|
||||
RETURN_IF_NULL(request, PARAMETER_NULL);
|
||||
size_t buffer_length = 0;
|
||||
OEMCryptoResult status =
|
||||
OEMCrypto_GenerateOTARequest(nullptr, &buffer_length, use_test_key);
|
||||
if (status != OEMCrypto_ERROR_SHORT_BUFFER)
|
||||
return MapOEMCryptoResult(status, UNKNOWN_ERROR,
|
||||
"PrepareOtaProvisioningRequest");
|
||||
std::string temp_buffer(buffer_length, '\0');
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
|
||||
status = OEMCrypto_GenerateOTARequest(buf, &buffer_length, use_test_key);
|
||||
if (OEMCrypto_SUCCESS == status) request->assign(temp_buffer);
|
||||
return MapOEMCryptoResult(status, UNKNOWN_ERROR,
|
||||
"PrepareOtaProvisioningRequest");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::LoadOtaProvisioning(
|
||||
bool use_test_key, const std::string& response) {
|
||||
OEMCryptoResult status = OEMCrypto_ProcessOTAKeybox(
|
||||
reinterpret_cast<const uint8_t*>(response.data()), response.size(),
|
||||
use_test_key);
|
||||
return MapOEMCryptoResult(status, UNKNOWN_ERROR, "LoadOtaProvisioning");
|
||||
}
|
||||
|
||||
template <class Func>
|
||||
auto CryptoSession::WithStaticFieldWriteLock(const char* tag, Func body)
|
||||
-> decltype(body()) {
|
||||
|
||||
@@ -318,7 +318,12 @@ typedef OEMCryptoResult (*L1_LoadProvisioning_t)(
|
||||
size_t signature_length, uint8_t* wrapped_private_key,
|
||||
size_t* wrapped_private_key_length);
|
||||
typedef uint32_t (*L1_MinorAPIVersion_t)();
|
||||
|
||||
typedef OEMCryptoResult (*L1_GenerateOTARequest_t)(uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key);
|
||||
typedef OEMCryptoResult (*L1_ProcessOTAKeybox_t)(const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key);
|
||||
struct FunctionPointers {
|
||||
wvcdm::CdmSecurityLevel security_level;
|
||||
uint32_t version;
|
||||
@@ -415,6 +420,8 @@ struct FunctionPointers {
|
||||
L1_SelectKey_V13_t SelectKey_V13;
|
||||
L1_LoadTestKeybox_V13_t LoadTestKeybox_V13;
|
||||
L1_RefreshKeys_V14_t RefreshKeys_V14;
|
||||
L1_GenerateOTARequest_t GenerateOTARequest;
|
||||
L1_ProcessOTAKeybox_t ProcessOTAKeybox;
|
||||
};
|
||||
|
||||
size_t GetOffset(const std::string& message, const std::string& field) {
|
||||
@@ -643,7 +650,7 @@ struct LevelSession {
|
||||
if ((level1_.version >= min) && (level1_.version <= max)) { \
|
||||
level1_.Name = (L1_##Name##_t)dlsym(level1_library_, QUOTE(Function)); \
|
||||
if (!level1_.Name) { \
|
||||
LOGW("Could not load L1 %s. Falling Back to L3.", QUOTE(Function)); \
|
||||
LOGW("Could not load L1 %s. Falling back to L3.", QUOTE(Function)); \
|
||||
if (level1_.Terminate) level1_.Terminate(); \
|
||||
return false; \
|
||||
} \
|
||||
@@ -778,7 +785,7 @@ class Adapter {
|
||||
}
|
||||
OEMCryptoResult st = level1_.Initialize();
|
||||
if (st != OEMCrypto_SUCCESS) {
|
||||
LOGW("Could not initialize L1. Falling Back to L3.");
|
||||
LOGW("Could not initialize L1. Falling back to L3.");
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INITIALIZE_L1);
|
||||
@@ -790,7 +797,7 @@ class Adapter {
|
||||
metrics->SetL1MinApiVersion(kMinimumVersion);
|
||||
|
||||
if (level1_.version < kMinimumVersion) {
|
||||
LOGW("liboemcrypto.so is version %d, not %d. Falling Back to L3.",
|
||||
LOGW("liboemcrypto.so is version %d, not %d. Falling back to L3.",
|
||||
level1_.version, kMinimumVersion);
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_WRONG_L1_VERSION);
|
||||
@@ -887,6 +894,8 @@ class Adapter {
|
||||
LOOKUP_ALL(16, MaximumUsageTableHeaderSize, OEMCrypto_MaximumUsageTableHeaderSize);
|
||||
LOOKUP_ALL(16, LoadProvisioning, OEMCrypto_LoadProvisioning);
|
||||
LOOKUP_ALL(16, MinorAPIVersion, OEMCrypto_MinorAPIVersion);
|
||||
LOOKUP_ALL(16, GenerateOTARequest, OEMCrypto_GenerateOTARequest);
|
||||
LOOKUP_ALL(16, ProcessOTAKeybox, OEMCrypto_ProcessOTAKeybox);
|
||||
// clang-format on
|
||||
|
||||
// There was a mistake in version 16.3 of the header that did not rename
|
||||
@@ -915,81 +924,6 @@ class Adapter {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(119830252): make the code below available to a static adapter.
|
||||
// Check if the keybox or oem certificate is valid, if so, we are finished
|
||||
// with initialization.
|
||||
OEMCryptoResult root_valid = level1_.IsKeyboxOrOEMCertValid();
|
||||
OEMCrypto_ProvisioningMethod provisioning_method =
|
||||
level1_.GetProvisioningMethod();
|
||||
if (root_valid == OEMCrypto_SUCCESS) {
|
||||
// The keybox or certificate is valid -- that means initialization is done
|
||||
// and we only have save some metrics and return.
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
(provisioning_method == OEMCrypto_Keybox)
|
||||
? wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_KEYBOX
|
||||
: wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L1_WITH_PROVISIONING_3_0);
|
||||
return true;
|
||||
}
|
||||
// At this point, the keybox or cert is not valid. We look on the file
|
||||
// system for one. If it is there we try to install it.
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename;
|
||||
if (!wvcdm::Properties::GetFactoryKeyboxPath(&filename)) {
|
||||
// No keybox or cert file found. Give up.
|
||||
LOGW("Bad Level 1 Root of Trust. Falling Back to L3.");
|
||||
level1_.Terminate();
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_BAD_KEYBOX);
|
||||
return false;
|
||||
}
|
||||
ssize_t size = file_system.FileSize(filename);
|
||||
if (size <= 0) {
|
||||
// A keybox or cert file was found, but it has size 0. Give up.
|
||||
LOGW("Could not find %s. Falling Back to L3.", filename.c_str());
|
||||
level1_.Terminate();
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_OPEN_FACTORY_KEYBOX);
|
||||
return false;
|
||||
}
|
||||
auto file = file_system.Open(filename, file_system.kReadOnly);
|
||||
if (!file) {
|
||||
// A keybox or cert file was found, but can't open it. Give up.
|
||||
LOGW("Could not open %s. Falling Back to L3.", filename.c_str());
|
||||
level1_.Terminate();
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_OPEN_FACTORY_KEYBOX);
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> root_key(size);
|
||||
ssize_t size_read = file->Read(reinterpret_cast<char*>(&root_key[0]), size);
|
||||
if (level1_.InstallKeyboxOrOEMCert(&root_key[0], size_read) !=
|
||||
OEMCrypto_SUCCESS) {
|
||||
// A keybox or cert file was read, but I could not install it. Give up.
|
||||
LOGE("Could NOT install root key from %s. Falling Back to L3.",
|
||||
filename.c_str());
|
||||
level1_.Terminate();
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
|
||||
return false;
|
||||
}
|
||||
if (level1_.IsKeyboxOrOEMCertValid() != OEMCrypto_SUCCESS) {
|
||||
// A keybox or cert file was read and installed, but it is still not
|
||||
// valid. Give up.
|
||||
LOGE("Installed bad key from %s. Falling Back to L3.", filename.c_str());
|
||||
level1_.Terminate();
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
|
||||
return false;
|
||||
}
|
||||
// A valid keybox or cert file was read and installed. Yay! return success.
|
||||
LOGI("Installed root key from %s", filename.c_str());
|
||||
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_INSTALLED_KEYBOX);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1133,6 +1067,77 @@ class Adapter {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check the L1 keybox or cert. If it is valid, return success. If not, try to
|
||||
// install one. If one is not available, but OTA provisioning is supported,
|
||||
// return OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING. If none of these work,
|
||||
// then return the status of the L3 keybox or cert.
|
||||
OEMCryptoResult ValidateOrInstallKeyboxOrCert() {
|
||||
if (!level1_valid_) {
|
||||
// TODO(b/189989043): add metrics.
|
||||
// If level 1 not initialized, then return level 3's answer.
|
||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (!level1_.IsKeyboxOrOEMCertValid) {
|
||||
// TODO(b/189989043): add metrics.
|
||||
LOGE("L1 invalid function pointers. Falling back to L3");
|
||||
if (level1_.Terminate) level1_.Terminate();
|
||||
level1_valid_ = false;
|
||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// Check if the keybox or oem certificate is valid, if so, we are finished
|
||||
// with initialization. Record some metrics and return success.
|
||||
const OEMCryptoResult rot_valid = level1_.IsKeyboxOrOEMCertValid();
|
||||
wvcdm::metrics::OemCryptoDynamicAdapterMetrics& metrics =
|
||||
wvcdm::metrics::GetDynamicAdapterMetricsInstance();
|
||||
// Figure out provisioning method. Defaults to keybox.
|
||||
const OEMCrypto_ProvisioningMethod provisioning_method =
|
||||
level1_.GetProvisioningMethod ? level1_.GetProvisioningMethod()
|
||||
: OEMCrypto_Keybox;
|
||||
if (rot_valid == OEMCrypto_SUCCESS) {
|
||||
// The keybox or certificate is valid -- that means initialization is done
|
||||
// and we only have save some metrics and return.
|
||||
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
(provisioning_method == OEMCrypto_Keybox)
|
||||
? wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_KEYBOX
|
||||
: wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L1_WITH_PROVISIONING_3_0);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
// At this point, the L1 keybox or cert is not valid. If are able to
|
||||
// install one, then we look on the file system for one. If it is there we
|
||||
// try to install it.
|
||||
OEMCryptoResult file_attempt = TryToInstallKeybox();
|
||||
if (file_attempt == OEMCrypto_SUCCESS) {
|
||||
// If loading the keybox succeeded, we are done. good job.
|
||||
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_INSTALLED_KEYBOX);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
if (rot_valid == OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING) {
|
||||
// TODO(b/189989043): add metrics.
|
||||
return OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING;
|
||||
}
|
||||
if (file_attempt == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
// No keybox to load, and none installed, so give up.
|
||||
LOGW("Bad Level 1 Root of Trust. Falling back to L3");
|
||||
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_BAD_KEYBOX);
|
||||
} else {
|
||||
// There was a keybox to load, but there was an error loading it. So give
|
||||
// up.
|
||||
LOGW("Error installing Level 1 Root of Trust. Falling back to L3");
|
||||
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
|
||||
}
|
||||
if (level1_.Terminate) level1_.Terminate();
|
||||
level1_valid_ = false;
|
||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
private:
|
||||
bool level1_valid_;
|
||||
void* level1_library_;
|
||||
@@ -1149,6 +1154,51 @@ class Adapter {
|
||||
if (!var) return false;
|
||||
return !strcmp(var, "yes");
|
||||
}
|
||||
|
||||
// Try to install a keybox from the file system.
|
||||
OEMCryptoResult TryToInstallKeybox() {
|
||||
if (!level1_.InstallKeyboxOrOEMCert) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename;
|
||||
if (!wvcdm::Properties::GetFactoryKeyboxPath(&filename)) {
|
||||
// No keybox or cert file found. Give up.
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
const ssize_t size = file_system.FileSize(filename);
|
||||
if (size <= 0) {
|
||||
// The keybox file does not exit or has size 0.
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// After this, any error will be logged differently to metrics
|
||||
// because we found a keybox on the filesystem, so we expect it to work.
|
||||
auto file = file_system.Open(filename, file_system.kReadOnly);
|
||||
if (!file) {
|
||||
// A keybox or cert file was found, but can't open it. Give up, but
|
||||
// log it as a different error because the file did exist.
|
||||
LOGW("Could not open %s", filename.c_str());
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
std::vector<uint8_t> root_key(size);
|
||||
ssize_t size_read =
|
||||
file->Read(reinterpret_cast<char*>(root_key.data()), size);
|
||||
if (level1_.InstallKeyboxOrOEMCert(root_key.data(), size_read) !=
|
||||
OEMCrypto_SUCCESS) {
|
||||
// A keybox or cert file was read, but I could not install it. Give up.
|
||||
LOGE("Could NOT install root key from %s", filename.c_str());
|
||||
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||
}
|
||||
if (!level1_.IsKeyboxOrOEMCertValid) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
OEMCryptoResult rot_valid = level1_.IsKeyboxOrOEMCertValid();
|
||||
if (rot_valid == OEMCrypto_SUCCESS) {
|
||||
// A valid keybox or cert file was read and installed. Yay! return
|
||||
// success.
|
||||
LOGI("Installed root key from %s", filename.c_str());
|
||||
} else {
|
||||
LOGW("Installed root key from %s, but invalid(%d)", filename.c_str(),
|
||||
rot_valid);
|
||||
}
|
||||
return rot_valid;
|
||||
}
|
||||
};
|
||||
|
||||
static std::unique_ptr<Adapter> gAdapter;
|
||||
@@ -1156,6 +1206,23 @@ static std::unique_ptr<Adapter> gAdapter;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
||||
bool* needs_keybox_provisioning) {
|
||||
if (!needs_keybox_provisioning) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (!gAdapter) {
|
||||
gAdapter.reset(new Adapter());
|
||||
}
|
||||
const OEMCryptoResult status = gAdapter->Initialize();
|
||||
if (status != OEMCrypto_SUCCESS) return status;
|
||||
const OEMCryptoResult keybox_status =
|
||||
gAdapter->ValidateOrInstallKeyboxOrCert();
|
||||
if (keybox_status == OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING) {
|
||||
*needs_keybox_provisioning = true;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
return keybox_status;
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||
SecurityLevel level) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
|
||||
@@ -1183,15 +1250,6 @@ OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(
|
||||
return fcn->GetProvisioningMethod();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(SecurityLevel level) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
|
||||
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (fcn->IsKeyboxOrOEMCertValid == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->IsKeyboxOrOEMCertValid();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
|
||||
SecurityLevel level) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
@@ -2155,7 +2213,12 @@ extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid() {
|
||||
return OEMCrypto_IsKeyboxOrOEMCertValid(kLevelDefault);
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (fcn->IsKeyboxOrOEMCertValid == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->IsKeyboxOrOEMCertValid();
|
||||
}
|
||||
|
||||
extern "C" OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() {
|
||||
@@ -2733,3 +2796,24 @@ extern "C" OEMCryptoResult OEMCrypto_FreeSecureBuffer(
|
||||
}
|
||||
return pair.fcn->FreeSecureBuffer(pair.session, output_descriptor, secure_fd);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest(uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (fcn->GenerateOTARequest == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->GenerateOTARequest(buffer, buffer_length, use_test_key);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (fcn->ProcessOTAKeybox == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->ProcessOTAKeybox(buffer, buffer_length, use_test_key);
|
||||
}
|
||||
|
||||
17
libwvdrmengine/cdm/core/src/oemcrypto_ota_stubs.cpp
Normal file
17
libwvdrmengine/cdm/core/src/oemcrypto_ota_stubs.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2021 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"
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest(uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@@ -82,6 +82,32 @@ const std::string kCpStagingProvisioningServiceCertificate =
|
||||
"8598ed5751b38694419242a875d9e00d5a5832933024b934859ec8be78adccbb"
|
||||
"1ec7127ae9afeef9c5cd2e15bd3048e8ce652f7d8c5d595a0323238c598a28";
|
||||
|
||||
// Service certificate for qa.widevine.com
|
||||
const std::string kCpQAProvisioningServiceCertificate =
|
||||
"0abc02080312100ec8164669cc2fdfc253b3b5e763276e18abd8cdcf05228e02"
|
||||
"3082010a0282010100b24d497c0cc6ab5072f97623daa49b8d5564360654d8e5"
|
||||
"8df8db7a23158f1afdd04724cbadbe87001532d9d6dec3b06973666da7759ec3"
|
||||
"bf3083e2d9b85e7a47c340db796b085493a460eef31d56e3f15d857713c55cdb"
|
||||
"164fe09e2a06be7fb979ad55e33a59ade3712aed2445b89fc145556a9e0093fa"
|
||||
"36fc3ff4d05291a9633d20c80a13cd0d924ed9078395714c30b49019f4d6f5ba"
|
||||
"093ad958aee9a164ba73ec298f905662de5859d3e6fae41c063f262d29dae75e"
|
||||
"8654ac9d68f3e3fccc809573d0f90704a77f9bce391d0a5f265f438119e4fb0b"
|
||||
"ec27706f5c7fc888f665730b691a0431e30cb3b57dfd078838c44550c3b79b35"
|
||||
"0552a92a760f90c6cf02030100013a0f71612e7769646576696e652e636f6d12"
|
||||
"800331ca1662fdc97e02debdca5b6de35dce5da87b5f61b15745ccf83e66197c"
|
||||
"e31bc6379ae4f6a5e4fd8a0e76f979701c5a715c06d70908563626d0dd3986b5"
|
||||
"e623a7b6336789c67f0fc68f9ec68e045f85d9a06942f4af0fe47d801cf035af"
|
||||
"27924f1c4cd395d15ce2f92f48044254fdefe37320471d7009160f5293183ca4"
|
||||
"a09bca71f76f1457a80eebcf12706bd79256f1b02e67dc002fc81e18c00d880f"
|
||||
"04b0187e6ef59ae75eaaf6b16672a887b9657f1796607d1585d1998283af1650"
|
||||
"9bd9a170c262056aad69e222a4c3180d104a76d76da29082e4f2e5297d1ec44d"
|
||||
"ed98c999981688089d8ff2d62f0f13b96ce5e89a4c215d60f025fa29811fcdc1"
|
||||
"848fe0581f612f45733da4b4c8803ae8088dcb3b811ea9c691daccfbe9cbf603"
|
||||
"13e8f85eb68f2f1d8cdf9e4fc91a46157a90fffafbd9d408b319307ea4d3d4a9"
|
||||
"d2f177355ad361f5284057dec1b186beb85dcbda64bf00a164cecc66c1878961"
|
||||
"7748618d069c39f365e8347acdae777cc4e3c3c3c3fe9698c4f5ee1285b0e6a9"
|
||||
"675e";
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Below are several choices for licenseing servers: production, UAT, staging
|
||||
// and staging and maybe Google Play. We haven't tested with Google Play in a
|
||||
@@ -354,4 +380,8 @@ const std::string& ConfigTestEnv::GetLicenseServerUrl(
|
||||
}
|
||||
}
|
||||
|
||||
std::string ConfigTestEnv::QAProvisioningServiceCertificate() {
|
||||
return a2bs_hex(kCpQAProvisioningServiceCertificate);
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -116,6 +116,8 @@ class ConfigTestEnv {
|
||||
const std::string& provisioning_service_certificate) {
|
||||
provisioning_service_certificate_.assign(provisioning_service_certificate);
|
||||
}
|
||||
// The QA service certificate, used for a local provisioning server.
|
||||
static std::string QAProvisioningServiceCertificate();
|
||||
|
||||
private:
|
||||
void Init(ServerConfigurationId server_id);
|
||||
|
||||
11
libwvdrmengine/cdm/core/test/keybox_ota_test.cpp
Normal file
11
libwvdrmengine/cdm/core/test/keybox_ota_test.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine Master
|
||||
// License Agreement.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "crypto_session.h"
|
||||
|
||||
namespace wvcdm {
|
||||
TEST(OTAKeyboxTest, TestThatTheBuildFilesWork) { ASSERT_TRUE(true); }
|
||||
} // namespace wvcdm
|
||||
@@ -112,6 +112,11 @@ void show_menu(const char* prog_name, const std::string& extra_help_text) {
|
||||
<< " in the url" << std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::cout << " --qa_provisioning" << std::endl;
|
||||
std::cout << " use the QA provisioning cert and QA test keybox"
|
||||
<< std::endl
|
||||
<< std::endl;
|
||||
|
||||
std::cout << " --fake_sleep" << std::endl;
|
||||
std::cout << " Use a fake clock to sleep for duration tests. This cannot"
|
||||
<< " be used with a real OEMCrypto." << std::endl
|
||||
@@ -162,6 +167,7 @@ bool ExtractSignedMessage(const std::string& response,
|
||||
} // namespace
|
||||
|
||||
ConfigTestEnv WvCdmTestBase::default_config_(kContentProtectionUatServer);
|
||||
bool WvCdmTestBase::use_qa_test_keybox_ = false;
|
||||
|
||||
void WvCdmTestBase::StripeBuffer(std::vector<uint8_t>* buffer, size_t size,
|
||||
uint8_t init) {
|
||||
@@ -211,6 +217,13 @@ TestCryptoSession::TestCryptoSession(metrics::CryptoMetrics* crypto_metrics)
|
||||
// The first CryptoSession should have initialized OEMCrypto. This is right
|
||||
// after that, so should tell oemcrypto to use a test keybox.
|
||||
if (session_count() == 1) {
|
||||
if (!initialized()) {
|
||||
// If not initialized, try again and see if we are just missing a keybox.
|
||||
// Since we plan to install a test keybox, we can ignore keybox errors.
|
||||
const OEMCryptoResult status = ::OEMCrypto_Initialize();
|
||||
if (status != OEMCrypto_SUCCESS) return;
|
||||
OverrideInitializedForTesting(true);
|
||||
}
|
||||
WvCdmTestBase::InstallTestRootOfTrust();
|
||||
}
|
||||
}
|
||||
@@ -262,12 +275,14 @@ void WvCdmTestBase::SetUp() {
|
||||
}
|
||||
|
||||
void WvCdmTestBase::InstallTestRootOfTrust() {
|
||||
const wvoec::WidevineKeybox& test_keybox =
|
||||
use_qa_test_keybox_ ? wvoec::kQATestKeybox : wvoec::kTestKeybox;
|
||||
switch (wvoec::global_features.derive_key_method) {
|
||||
case wvoec::DeviceFeatures::LOAD_TEST_KEYBOX:
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadTestKeybox(
|
||||
reinterpret_cast<const uint8_t*>(&wvoec::kTestKeybox),
|
||||
sizeof(wvoec::kTestKeybox)));
|
||||
reinterpret_cast<const uint8_t*>(&test_keybox),
|
||||
sizeof(test_keybox)));
|
||||
break;
|
||||
case wvoec::DeviceFeatures::LOAD_TEST_RSA_KEY:
|
||||
// Rare case: used by devices with baked in DRM cert.
|
||||
@@ -451,6 +466,10 @@ bool WvCdmTestBase::Initialize(int argc, const char* const argv[],
|
||||
is_cast_receiver = true;
|
||||
} else if (arg == "--fake_sleep") {
|
||||
wvcdm::TestSleep::set_real_sleep(false);
|
||||
} else if (arg == "--qa_provisioning") {
|
||||
use_qa_test_keybox_ = true;
|
||||
default_config_.set_provisioning_service_certificate(
|
||||
default_config_.QAProvisioningServiceCertificate());
|
||||
} else if (arg.find("--gtest") == 0) {
|
||||
// gtest arguments will be passed to gtest by the main program.
|
||||
continue;
|
||||
|
||||
@@ -67,6 +67,9 @@ class WvCdmTestBase : public ::testing::Test {
|
||||
// arguments before any tests are created.
|
||||
static ConfigTestEnv default_config_;
|
||||
|
||||
// If the tests should use the QA test keybox.
|
||||
static bool use_qa_test_keybox_;
|
||||
|
||||
// Configuration for an individual test. This is initialized to be the
|
||||
// default configuration, but can be modified by the test itself.
|
||||
ConfigTestEnv config_;
|
||||
|
||||
@@ -1186,6 +1186,9 @@ void PrintTo(const enum OEMCryptoResult& value, ::std::ostream* os) {
|
||||
case OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION:
|
||||
*os << "OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION";
|
||||
break;
|
||||
case OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING:
|
||||
*os << "ERROR_NEEDS_KEYBOX_PROVISIONING";
|
||||
break;
|
||||
// ODK Values.
|
||||
case ODK_ERROR_CORE_MESSAGE:
|
||||
*os << "CORE_MESSAGE";
|
||||
|
||||
@@ -97,6 +97,10 @@ test_name := initialization_data_unittest
|
||||
test_src_dir := ../core/test
|
||||
include $(LOCAL_PATH)/unit-test.mk
|
||||
|
||||
test_name := keybox_ota_test
|
||||
test_src_dir := ../core/test
|
||||
include $(LOCAL_PATH)/unit-test.mk
|
||||
|
||||
test_name := license_keys_unittest
|
||||
test_src_dir := ../core/test
|
||||
include $(LOCAL_PATH)/unit-test.mk
|
||||
|
||||
@@ -624,6 +624,9 @@ typedef enum OEMCrypto_ProvisioningMethod {
|
||||
#define OEMCrypto_MinorAPIVersion _oecc108
|
||||
#define OEMCrypto_AllocateSecureBuffer _oecc109
|
||||
#define OEMCrypto_FreeSecureBuffer _oecc110
|
||||
// Reserved 111-112.
|
||||
#define OEMCrypto_GenerateOTARequest _oecc113
|
||||
#define OEMCrypto_ProcessOTAKeybox _oecc114
|
||||
// clang-format on
|
||||
|
||||
/// @addtogroup initcontrol
|
||||
@@ -2963,7 +2966,24 @@ OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void);
|
||||
* @retval OEMCrypto_ERROR_INVALID_RSA_KEY
|
||||
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
*
|
||||
* @threading
|
||||
* On devices that support OEMCrypto_GenerateOTARequest and
|
||||
* OEMCrypto_ProcessOTAKeybox, this function may return
|
||||
* OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING when a valid keybox is not
|
||||
* present.
|
||||
*
|
||||
* Parameters:
|
||||
* none
|
||||
*
|
||||
* Returns:
|
||||
* OEMCrypto_SUCCESS
|
||||
* OEMCrypto_ERROR_BAD_MAGIC
|
||||
* OEMCrypto_ERROR_BAD_CRC
|
||||
* OEMCrypto_ERROR_KEYBOX_INVALID
|
||||
* OEMCrypto_ERROR_INVALID_RSA_KEY
|
||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||
* OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING
|
||||
*
|
||||
* Threading:
|
||||
* This is a "Property Function" and may be called simultaneously with any
|
||||
* other property function or session function, but not any initialization or
|
||||
* usage table function, as if the CDM holds a read lock on the OEMCrypto
|
||||
@@ -4719,6 +4739,93 @@ OEMCryptoResult OEMCrypto_FreeSecureBuffer(
|
||||
|
||||
/// @}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/* The following functions are optional. They are only used if the device
|
||||
* supports OTA keybox provisioning. Widevine does not allow all devices to
|
||||
* support OTA provisioning. Using an OTA provisioned keybox usually lowers a
|
||||
* device's security profile in the DCSL. Please work with your Widevine Partner
|
||||
* Engineer before implementing these functions to make sure you understand the
|
||||
* security implications of using Keybox OTA Provisioning.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OEMCrypto_GenerateOTARequest
|
||||
*
|
||||
* Description:
|
||||
* Generate an OTA Keybox provisioning request. The format of the
|
||||
* message is specified in the document Keybox OTA Reprovisioning. If
|
||||
* use_test_key is true, then the debug model key and id should be
|
||||
* used. Widevine does not allow all devices to support OTA
|
||||
* provisioning. Using an OTA provisioned keybox usually lowers a device's
|
||||
* security profile in the DCSL.
|
||||
*
|
||||
* Parameters:
|
||||
* [out] buffer: where the provisioning request is stored.
|
||||
* [in/out] buffer_length: length of the request, in bytes.
|
||||
* [in] use_test_key: If true, use the debug model key. This is used for
|
||||
* testing the workflow.
|
||||
*
|
||||
* Returns:
|
||||
* OEMCrypto_SUCCESS on success
|
||||
* OEMCrypto_ERROR_SHORT_BUFFER - if buffer_length is too small.
|
||||
* OEMCrypto_ERROR_NOT_IMPLEMENTED
|
||||
* Any other error will be logged.
|
||||
*
|
||||
* Threading:
|
||||
* This is an "Initialization and Termination Function" and will not be called
|
||||
* simultaneously with any other function, as if the CDM holds a write lock on
|
||||
* the OEMCrypto system. It will be called only after
|
||||
* OEMCrypto_IsKeyboxOrOEMCertValid() returns
|
||||
* OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING immediately after initialization,
|
||||
* and before any session is opened.
|
||||
*
|
||||
* Version:
|
||||
* This method is new in API version 16.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_GenerateOTARequest(uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key);
|
||||
/*
|
||||
* OEMCrypto_ProcessOTAKeybox
|
||||
*
|
||||
* Description:
|
||||
* The buffer will be parsed as an OTA Keybox provisioning message, as
|
||||
* described in the document OTA Keybox Reprovisioning. The
|
||||
* signature will be verified. The keybox will be decrypted and verified. If
|
||||
* use_test_key is false, the keybox will be installed permanently.
|
||||
*
|
||||
* If use_test_keybox is true, do not use the real model key, use the debug
|
||||
* model key specified in OTA Keybox Reprovisioning.
|
||||
*
|
||||
* Parameters:
|
||||
* [in] buffer: pointer to provisioning response.
|
||||
* [in] buffer_length: length of the buffer, in bytes.
|
||||
* [in] use_test_key: If true, use the debug model key. This is used for
|
||||
* testing the workflow.
|
||||
*
|
||||
* Returns:
|
||||
* OEMCrypto_SUCCESS on success
|
||||
* OEMCrypto_ERROR_NOT_IMPLEMENTED
|
||||
* OEMCrypto_ERROR_SIGNATURE_FAILURE - signature of message was wrong.
|
||||
* OEMCrypto_ERROR_KEYBOX_INVALID - if the keybox was unpacked, but is
|
||||
* invalid.
|
||||
* OEMCrypto_ERROR_WRITE_KEYBOX - could not save keybox.
|
||||
* Any other error will be logged.
|
||||
*
|
||||
* Threading:
|
||||
* This is an "Initialization and Termination Function" and will not be called
|
||||
* simultaneously with any other function, as if the CDM holds a write lock on
|
||||
* the OEMCrypto system. It will only be called after
|
||||
* OEMCrypto_GenerateOTARequest.
|
||||
*
|
||||
* Version:
|
||||
* This method is new in API version 16.
|
||||
*/
|
||||
OEMCryptoResult OEMCrypto_ProcessOTAKeybox(const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key);
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/* The following functions are deprecated. They are not required for the
|
||||
|
||||
@@ -88,6 +88,7 @@ typedef enum OEMCryptoResult {
|
||||
OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES = 58,
|
||||
OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59,
|
||||
OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION = 60,
|
||||
OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING = 61,
|
||||
/* ODK return values */
|
||||
ODK_ERROR_BASE = 1000,
|
||||
ODK_ERROR_CORE_MESSAGE = ODK_ERROR_BASE,
|
||||
|
||||
@@ -18,6 +18,7 @@ LOCAL_SRC_FILES:= \
|
||||
oemcrypto_test.cpp \
|
||||
oemcrypto_test_android.cpp \
|
||||
oemcrypto_test_main.cpp \
|
||||
ota_keybox_test.cpp \
|
||||
wvcrc.cpp \
|
||||
../../cdm/util/test/test_sleep.cpp \
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace wvoec {
|
||||
// This is a test keybox. It will not be accepted by production systems. By
|
||||
// using a known keybox for these tests, the results for a given set of inputs
|
||||
// to a test are predictable and can be compared to the actual results.
|
||||
// clang-format off
|
||||
static const WidevineKeybox kTestKeybox = {
|
||||
// Sample keybox used for test vectors
|
||||
{
|
||||
@@ -49,6 +50,43 @@ static const WidevineKeybox kTestKeybox = {
|
||||
0x39, 0xf2, 0x94, 0xa7,
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// This test keybox is only accepted by the QA provisioning server.
|
||||
// It is not valid with the production provisioning server.
|
||||
// clang-format off
|
||||
static const WidevineKeybox kQATestKeybox = {
|
||||
// Sample keybox used for test vectors
|
||||
{
|
||||
// deviceID = WidevineQATestOnlyKeybox000
|
||||
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
|
||||
0x51, 0x41, 0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e,
|
||||
0x6c, 0x79, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78,
|
||||
0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
}, {
|
||||
// key
|
||||
0x03, 0x77, 0x0f, 0x4e, 0x29, 0x77, 0x4b, 0x43,
|
||||
0x9e, 0xd2, 0x8a, 0x94, 0x73, 0xb3, 0x26, 0x65,
|
||||
}, {
|
||||
// data (system ID 2000000 = 0x1E8480).
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x84, 0x80,
|
||||
0x90, 0x46, 0x8a, 0x1d, 0x27, 0x52, 0xca, 0xdb,
|
||||
0x5b, 0xf4, 0x67, 0xcb, 0xd3, 0x5e, 0x9e, 0xe9,
|
||||
0xb1, 0xcf, 0x89, 0x74, 0x08, 0x26, 0x96, 0x5b,
|
||||
0x43, 0x02, 0x7c, 0xb6, 0x4a, 0x9d, 0xf6, 0x7e,
|
||||
0x24, 0x82, 0x1d, 0xe2, 0x89, 0x52, 0x8e, 0xac,
|
||||
0xf2, 0x98, 0xac, 0x92, 0xa9, 0x40, 0x11, 0x9f,
|
||||
0x9f, 0xf8, 0x55, 0x84, 0x42, 0x04, 0x34, 0xbc,
|
||||
0x53, 0x14, 0x3d, 0x44, 0x97, 0x5c, 0xd9, 0xb4,
|
||||
}, {
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
}, {
|
||||
// Crc
|
||||
0x43, 0xa2, 0x67, 0x63,
|
||||
}
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
|
||||
// Used to verify the functions that manipulate RSA keys.
|
||||
|
||||
53
libwvdrmengine/oemcrypto/test/ota_keybox_test.cpp
Normal file
53
libwvdrmengine/oemcrypto/test/ota_keybox_test.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine License
|
||||
// Agreement.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "clock.h"
|
||||
#include "log.h"
|
||||
#include "oec_decrypt_fallback_chain.h"
|
||||
#include "oec_device_features.h"
|
||||
#include "oec_session_util.h"
|
||||
#include "oec_test_data.h"
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
#include "oemcrypto_types.h"
|
||||
#include "platform.h"
|
||||
#include "string_conversions.h"
|
||||
#include "test_sleep.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace wvoec {
|
||||
class OTAKeyboxProvisioningTest : public ::testing::Test, public SessionUtil {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
::testing::Test::SetUp();
|
||||
wvcdm::TestSleep::SyncFakeClock();
|
||||
const ::testing::TestInfo* const test_info =
|
||||
::testing::UnitTest::GetInstance()->current_test_info();
|
||||
LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name());
|
||||
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize());
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
OEMCrypto_Terminate();
|
||||
::testing::Test::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(OTAKeyboxProvisioningTest, BasicTest) {
|
||||
OEMCryptoResult result = OEMCrypto_IsKeyboxValid();
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
cout << " "
|
||||
<< "Keybox valid after initialization. Skipping rest of test." << endl;
|
||||
return;
|
||||
}
|
||||
ASSERT_EQ(result, OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING);
|
||||
cout << " "
|
||||
<< "OTA Keybox functions supported. Device needs provisioning." << endl;
|
||||
}
|
||||
} // namespace wvoec
|
||||
Reference in New Issue
Block a user