Use local provisioning server

Merge from Widevine repo of http://go/wvgerrit/133703 and
http://ag/14707867

In order to use a local provisioning server, we need to use a
different test keybox system id that is in the dev device database
instead of the production database. We also need to use a local
license server that uses the dev license server.

Bug: 187646550
Test: GtsMediaTestCases

Change-Id: Ice89143dd26de22757375a770c6bac716fcbc057

Add Keybox OTA Provisioning functions to OEMCrypto header

Merge from Widevine repo of http://go/wvgerrit/133704 and
http://go/ag/14707868

Bug: 188228998
Change-Id: Iff54bc2870e87bf7239e179e1d02fbcc8df6198f

Stub build changes to support OTA Keybox

Merge from Widevine repo of http://go/wvgerrit/133725 and
http://go/ag/14781459

This CL adds a new unit test file for testing OTA keybox
reprovisioning functionality. This new test is built when running the
dynamic adapter in the linux build, and in the Android build.

Bug: 187646550
Change-Id: I625513840188f95e74831ef2ea399e827e837439

Add OTA Keybox functions to dynamic adapter

Merge from Widevine repo of http://go/wvgerrit/125843
and http://go/ag/14781460

Bug: 187646550
Change-Id: Ief78ed10599c091690e0d7dc488ea71674c763b5

Refactor dynamic adapter keybox verification

Merge from Widevine repo of http://go/wvgerrit/133727
http://go/ag/14812524

The keybox validation needs to be done separately from initializing
the library so that we can support Keybox OTA Reprovisioning.

If L1 loads, but the keybox is missing, the initialization should
succeed. When the keybox is validated, the adapter should try to look
for a keybox on the filesystem. if none is found, it should either
return NEEDS PROVISIONING or an error.

Bug: 187646550
Change-Id: I34a8c365a5a5ca35c379bea827c85c749964744c

Update crypto session to use new OTA keybox functionality

Merge from Widevine repo of http://go/wvgerrit/133728 and
http://go/ag/14812525

This CL stubs out two new CryptoSession functions that call the new
OEMCrypto functions for OTA Keybox Provisioning. It builds!  Yay!

It also adds a boolean needs_keybox_provisioning that is set to true
when OEMCrypto reports that it needs a keybox. This should only happen
if there is no keybox installed and oemcrypto supports provisioning.

Bug: 187646550
Merged-In: Ide9533943125aa13b8899b652b118a0b410c882c
Change-Id: Ide9533943125aa13b8899b652b118a0b410c882c
This commit is contained in:
Fred Gylys-Colwell
2021-05-25 01:33:04 +00:00
committed by Alex Dale
parent b847732abd
commit 44ba42f5cc
17 changed files with 527 additions and 98 deletions

View File

@@ -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()) {

View File

@@ -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);
}

View 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;
}