Fall back to L3 if L1 has test keybox
Merge from Widevine repo of http://go/wvgerrit/142150 (part 2) For an EVT device, without a keybox or with a test keybox, we want it to fall back to L3. However, when running the unit or integration tests it should continue running tests with test keybox. This will allow us to test L1 oemcrypto on an EVT device, while still using an EVT device for dogfooding video content at the L3 level. Bug: 210807585 Bug: 210823889 Change-Id: I30c35134239db35bb39f11f75220063181987763
This commit is contained in:
@@ -309,6 +309,12 @@ class CdmEngine {
|
|||||||
return CryptoSession::SetDebugIgnoreKeyboxCount(count);
|
return CryptoSession::SetDebugIgnoreKeyboxCount(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This tells the OEMCrypto adapter to allow the device to continue with a
|
||||||
|
// test keybox. Otherwise, the keybox is reported as invalid.
|
||||||
|
static CdmResponseType SetAllowTestKeybox(bool allow) {
|
||||||
|
return CryptoSession::SetAllowTestKeybox(allow);
|
||||||
|
}
|
||||||
|
|
||||||
static CdmResponseType ParseDecryptHashString(const std::string& hash_string,
|
static CdmResponseType ParseDecryptHashString(const std::string& hash_string,
|
||||||
CdmSessionId* id,
|
CdmSessionId* id,
|
||||||
uint32_t* frame_number,
|
uint32_t* frame_number,
|
||||||
|
|||||||
@@ -299,6 +299,10 @@ class CryptoSession {
|
|||||||
// report that it needs provisioning instead.
|
// report that it needs provisioning instead.
|
||||||
static CdmResponseType SetDebugIgnoreKeyboxCount(uint32_t count);
|
static CdmResponseType SetDebugIgnoreKeyboxCount(uint32_t count);
|
||||||
|
|
||||||
|
// This tells the OEMCrypto adapter to allow the device to continue with a
|
||||||
|
// test keybox. Otherwise, the keybox is reported as invalid.
|
||||||
|
static CdmResponseType SetAllowTestKeybox(bool allow);
|
||||||
|
|
||||||
// Returns a system-wide singleton instance of SystemFallbackPolicy
|
// Returns a system-wide singleton instance of SystemFallbackPolicy
|
||||||
// to be used for communicating OTA keybox provisioning state between
|
// to be used for communicating OTA keybox provisioning state between
|
||||||
// apps. Returns a null pointer if OTA provisioning is not supported,
|
// apps. Returns a null pointer if OTA provisioning is not supported,
|
||||||
@@ -322,13 +326,10 @@ class CryptoSession {
|
|||||||
explicit CryptoSession(metrics::CryptoMetrics* crypto_metrics);
|
explicit CryptoSession(metrics::CryptoMetrics* crypto_metrics);
|
||||||
|
|
||||||
int session_count() const { return session_count_; }
|
int session_count() const { return session_count_; }
|
||||||
bool initialized() const { return initialized_; }
|
|
||||||
void set_initialized(bool initialized) { initialized_ = initialized; }
|
|
||||||
// Cache api version and fallback policy. Call this once at initialization.
|
// Cache api version and fallback policy. Call this once at initialization.
|
||||||
void CacheVersion();
|
void CacheVersion();
|
||||||
void OverrideNeedKeyboxForTesting(bool needs_keybox_provisioning) {
|
// Re-initialize for running tests with a test keybox.
|
||||||
needs_keybox_provisioning_ = needs_keybox_provisioning;
|
void ReinitializeForTest();
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class CryptoSessionForTest;
|
friend class CryptoSessionForTest;
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
|||||||
// report that it needs provisioning instead.
|
// report that it needs provisioning instead.
|
||||||
OEMCryptoResult OEMCrypto_SetDebugIgnoreKeyboxCount(uint32_t count);
|
OEMCryptoResult OEMCrypto_SetDebugIgnoreKeyboxCount(uint32_t count);
|
||||||
|
|
||||||
|
// This tells the OEMCrypto adapter to allow the device to continue with a
|
||||||
|
// test keybox. Otherwise, the keybox is reported as invalid.
|
||||||
|
OEMCryptoResult OEMCrypto_SetAllowTestKeybox(bool allow);
|
||||||
|
|
||||||
// This attempts to open a session at the desired security level.
|
// This attempts to open a session at the desired security level.
|
||||||
// If one level is not available, the other will be used instead.
|
// If one level is not available, the other will be used instead.
|
||||||
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||||
|
|||||||
@@ -358,6 +358,21 @@ void CryptoSession::Init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CryptoSession::ReinitializeForTest() {
|
||||||
|
if (initialized_) {
|
||||||
|
initialized_ = false;
|
||||||
|
if (OEMCrypto_SUCCESS != OEMCrypto_Terminate()) return;
|
||||||
|
}
|
||||||
|
// Give up if we cannot initialize at all.
|
||||||
|
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) return;
|
||||||
|
initialized_ = true;
|
||||||
|
// For integration and unit tests we will install a test keybox and do not
|
||||||
|
// need to do keybox provisioning.
|
||||||
|
needs_keybox_provisioning_ = false;
|
||||||
|
// This was skipped in Init because initialization failed.
|
||||||
|
CacheVersion();
|
||||||
|
}
|
||||||
|
|
||||||
void CryptoSession::CacheVersion() {
|
void CryptoSession::CacheVersion() {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
std::string api_version =
|
std::string api_version =
|
||||||
@@ -3061,6 +3076,11 @@ CdmResponseType CryptoSession::SetDebugIgnoreKeyboxCount(uint32_t count) {
|
|||||||
return MapOEMCryptoResult(status, UNKNOWN_ERROR, "SetDebugIgnoreKeyboxCount");
|
return MapOEMCryptoResult(status, UNKNOWN_ERROR, "SetDebugIgnoreKeyboxCount");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CdmResponseType CryptoSession::SetAllowTestKeybox(bool allow) {
|
||||||
|
OEMCryptoResult status = OEMCrypto_SetAllowTestKeybox(allow);
|
||||||
|
return MapOEMCryptoResult(status, UNKNOWN_ERROR, "SetAllowTestKeybox");
|
||||||
|
}
|
||||||
|
|
||||||
okp::SystemFallbackPolicy* CryptoSession::GetOkpFallbackPolicy() {
|
okp::SystemFallbackPolicy* CryptoSession::GetOkpFallbackPolicy() {
|
||||||
const auto getter = [&]() -> okp::SystemFallbackPolicy* {
|
const auto getter = [&]() -> okp::SystemFallbackPolicy* {
|
||||||
// If not set, then OTA keybox provisioning is not supported or
|
// If not set, then OTA keybox provisioning is not supported or
|
||||||
|
|||||||
@@ -641,6 +641,17 @@ std::string GetIgnoreCountFile() {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GetAllowTestKeyboxFile() {
|
||||||
|
std::string path;
|
||||||
|
if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL1,
|
||||||
|
&path)) {
|
||||||
|
LOGW("GetAllowTestKeyboxFile: Unable to get base path");
|
||||||
|
path = "/data/";
|
||||||
|
}
|
||||||
|
path += "debug_allow_test_keybox.txt";
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t GetDebugIgnoreKeyboxCount() {
|
uint32_t GetDebugIgnoreKeyboxCount() {
|
||||||
const std::string filename = GetIgnoreCountFile();
|
const std::string filename = GetIgnoreCountFile();
|
||||||
wvcdm::FileSystem file_system;
|
wvcdm::FileSystem file_system;
|
||||||
@@ -693,6 +704,49 @@ OEMCryptoResult SetDebugIgnoreKeyboxCount(uint32_t count) {
|
|||||||
return OEMCrypto_SUCCESS;
|
return OEMCrypto_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetAllowTestKeybox() {
|
||||||
|
const std::string filename = GetAllowTestKeyboxFile();
|
||||||
|
wvcdm::FileSystem file_system;
|
||||||
|
if (!file_system.Exists(filename)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto file = file_system.Open(filename, file_system.kReadOnly);
|
||||||
|
if (!file) {
|
||||||
|
LOGE("Error opening %s", filename.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ssize_t size = file_system.FileSize(filename);
|
||||||
|
std::string contents(size, ' ');
|
||||||
|
ssize_t size_read = file->Read(const_cast<char*>(contents.data()), size);
|
||||||
|
if (size != size_read) {
|
||||||
|
LOGE("Short allow_test_keybox = %zu", size_read);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// skip whitespace or any extra garbage.
|
||||||
|
return (std::string::npos != contents.find("true"));
|
||||||
|
}
|
||||||
|
|
||||||
|
OEMCryptoResult SetAllowTestKeybox(bool allow) {
|
||||||
|
const std::string filename = GetAllowTestKeyboxFile();
|
||||||
|
wvcdm::FileSystem file_system;
|
||||||
|
auto file =
|
||||||
|
file_system.Open(filename, file_system.kCreate | file_system.kTruncate);
|
||||||
|
if (!file) {
|
||||||
|
LOGE("Could not create file %s", filename.c_str());
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
const std::string contents = allow ? "true\n" : "false\n";
|
||||||
|
const size_t size = contents.size();
|
||||||
|
ssize_t size_written = file->Write(contents.data(), size);
|
||||||
|
if (static_cast<ssize_t>(size) != size_written) {
|
||||||
|
LOGE("Wrote %zd bytes of %s, not %zd, to file %s", size_written,
|
||||||
|
contents.c_str(), size, filename.c_str());
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
|
LOGD("Wrote %s to %s", contents.c_str(), filename.c_str());
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
struct LevelSession {
|
struct LevelSession {
|
||||||
FunctionPointers* fcn;
|
FunctionPointers* fcn;
|
||||||
OEMCrypto_SESSION session;
|
OEMCrypto_SESSION session;
|
||||||
@@ -816,6 +870,7 @@ class Adapter {
|
|||||||
level1_.BuildInformation());
|
level1_.BuildInformation());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
level1_failed_ = true;
|
||||||
FallBackToLevel3();
|
FallBackToLevel3();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -837,7 +892,6 @@ class Adapter {
|
|||||||
Level1Terminate();
|
Level1Terminate();
|
||||||
level1_ = FunctionPointers(); // revert to all null pointers.
|
level1_ = FunctionPointers(); // revert to all null pointers.
|
||||||
level1_valid_ = false;
|
level1_valid_ = false;
|
||||||
level1_failed_ = true;
|
|
||||||
// Note: if the function pointers are bad, we do not close the library and
|
// Note: if the function pointers are bad, we do not close the library and
|
||||||
// try again later. Instead, we permanently fall back to L3. This is a
|
// try again later. Instead, we permanently fall back to L3. This is a
|
||||||
// debatable choice: I decided the risk of a dlclose resource leak out
|
// debatable choice: I decided the risk of a dlclose resource leak out
|
||||||
@@ -1162,23 +1216,32 @@ class Adapter {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the system ID of the keybox. This should only be called if the device
|
||||||
|
// uses provisioning 2.0.
|
||||||
|
bool UsingTestKeybox() {
|
||||||
|
uint8_t key_data[256];
|
||||||
|
size_t key_data_len = sizeof(key_data);
|
||||||
|
OEMCryptoResult sts = OEMCrypto_GetKeyData(key_data, &key_data_len);
|
||||||
|
if (sts != OEMCrypto_SUCCESS) return true;
|
||||||
|
uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
|
||||||
|
uint32_t system_id = htonl(data[1]);
|
||||||
|
return system_id == 7912;
|
||||||
|
}
|
||||||
|
|
||||||
// Check the L1 keybox or cert. If it is valid, return success. If not, try to
|
// 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,
|
// install one. If one is not available, but OTA provisioning is supported,
|
||||||
// return OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING. If none of these work,
|
// return OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING. If none of these work,
|
||||||
// then return the status of the L3 keybox or cert.
|
// then return an error code. The caller should fall back to L3.
|
||||||
OEMCryptoResult ValidateOrInstallKeyboxOrCert() {
|
OEMCryptoResult ValidateOrInstallL1KeyboxOrCert() {
|
||||||
if (!level1_valid_) {
|
if (!level1_valid_) {
|
||||||
// TODO(b/189989043): add metrics.
|
// TODO(b/189989043): add metrics.
|
||||||
// If level 1 not initialized, then return level 3's answer.
|
// If level 1 not initialized, then return level 3's answer.
|
||||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
if (!level1_.IsKeyboxOrOEMCertValid) {
|
if (!level1_.IsKeyboxOrOEMCertValid) {
|
||||||
// TODO(b/189989043): add metrics.
|
// TODO(b/189989043): add metrics.
|
||||||
LOGE("L1 invalid function pointers. Falling back to L3");
|
LOGE("L1 invalid function pointers. Falling back to L3");
|
||||||
FallBackToLevel3();
|
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
|
||||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
// Check if the keybox or oem certificate is valid, if so, we are finished
|
// Check if the keybox or oem certificate is valid, if so, we are finished
|
||||||
// with initialization. Record some metrics and return success.
|
// with initialization. Record some metrics and return success.
|
||||||
@@ -1189,6 +1252,19 @@ class Adapter {
|
|||||||
const OEMCrypto_ProvisioningMethod provisioning_method =
|
const OEMCrypto_ProvisioningMethod provisioning_method =
|
||||||
level1_.GetProvisioningMethod ? level1_.GetProvisioningMethod()
|
level1_.GetProvisioningMethod ? level1_.GetProvisioningMethod()
|
||||||
: OEMCrypto_Keybox;
|
: OEMCrypto_Keybox;
|
||||||
|
// For production systems, we do wish to use a test keybox. We do not force
|
||||||
|
// a fallback to L3 at this point, because this can be overridden by test
|
||||||
|
// code that requires a test keybox.
|
||||||
|
if ((rot_valid == OEMCrypto_SUCCESS) &&
|
||||||
|
(provisioning_method == OEMCrypto_Keybox) && UsingTestKeybox()) {
|
||||||
|
if (GetAllowTestKeybox()) {
|
||||||
|
LOGW("Allowing device with test keybox installed.");
|
||||||
|
} else {
|
||||||
|
LOGW("Device has test keybox installed.");
|
||||||
|
return OEMCrypto_ERROR_KEYBOX_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rot_valid == OEMCrypto_SUCCESS) {
|
if (rot_valid == OEMCrypto_SUCCESS) {
|
||||||
// The keybox or certificate is valid -- that means initialization is done
|
// The keybox or certificate is valid -- that means initialization is done
|
||||||
// and we only have save some metrics and return.
|
// and we only have save some metrics and return.
|
||||||
@@ -1226,9 +1302,7 @@ class Adapter {
|
|||||||
wvcdm::metrics::
|
wvcdm::metrics::
|
||||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
|
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
|
||||||
}
|
}
|
||||||
FallBackToLevel3();
|
return file_attempt;
|
||||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
|
||||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOTAKeyboxSupported() {
|
bool IsOTAKeyboxSupported() {
|
||||||
@@ -1342,7 +1416,7 @@ OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
|||||||
// continue on.
|
// continue on.
|
||||||
if (status != OEMCrypto_SUCCESS) return status;
|
if (status != OEMCrypto_SUCCESS) return status;
|
||||||
const OEMCryptoResult keybox_status =
|
const OEMCryptoResult keybox_status =
|
||||||
gAdapter->ValidateOrInstallKeyboxOrCert();
|
gAdapter->ValidateOrInstallL1KeyboxOrCert();
|
||||||
uint32_t ignore_count = GetDebugIgnoreKeyboxCount();
|
uint32_t ignore_count = GetDebugIgnoreKeyboxCount();
|
||||||
if (keybox_status == OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING ||
|
if (keybox_status == OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING ||
|
||||||
ignore_count > 0) {
|
ignore_count > 0) {
|
||||||
@@ -1359,7 +1433,13 @@ OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
|||||||
return OEMCrypto_SUCCESS;
|
return OEMCrypto_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return keybox_status;
|
if (keybox_status == OEMCrypto_SUCCESS) {
|
||||||
|
return OEMCrypto_SUCCESS;
|
||||||
|
}
|
||||||
|
LOGW("Keybox error: %d. Falling back to L3.", keybox_status);
|
||||||
|
gAdapter->FallBackToLevel3();
|
||||||
|
// Return success if the L3 keybox or cert is valid.
|
||||||
|
return OEMCrypto_IsKeyboxOrOEMCertValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||||
@@ -1643,6 +1723,9 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert,
|
|||||||
OEMCryptoResult OEMCrypto_SetDebugIgnoreKeyboxCount(uint32_t count) {
|
OEMCryptoResult OEMCrypto_SetDebugIgnoreKeyboxCount(uint32_t count) {
|
||||||
return SetDebugIgnoreKeyboxCount(count);
|
return SetDebugIgnoreKeyboxCount(count);
|
||||||
}
|
}
|
||||||
|
OEMCryptoResult OEMCrypto_SetAllowTestKeybox(bool allow) {
|
||||||
|
return SetAllowTestKeybox(allow);
|
||||||
|
}
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|
||||||
extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id,
|
extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id,
|
||||||
|
|||||||
@@ -217,16 +217,8 @@ TestCryptoSession::TestCryptoSession(metrics::CryptoMetrics* crypto_metrics)
|
|||||||
// The first CryptoSession should have initialized OEMCrypto. This is right
|
// The first CryptoSession should have initialized OEMCrypto. This is right
|
||||||
// after that, so we should tell oemcrypto to use a test keybox.
|
// after that, so we should tell oemcrypto to use a test keybox.
|
||||||
if (session_count() == 1) {
|
if (session_count() == 1) {
|
||||||
OverrideNeedKeyboxForTesting(false);
|
CryptoSession::SetAllowTestKeybox(true);
|
||||||
// However, if the device does not have a keybox, initialization would have
|
ReinitializeForTest();
|
||||||
// failed. In that case we should try again.
|
|
||||||
if (!initialized()) {
|
|
||||||
// Give up if we cannot initialize at all.
|
|
||||||
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) return;
|
|
||||||
set_initialized(true);
|
|
||||||
// This was skipped in Init because initialization failed.
|
|
||||||
CacheVersion();
|
|
||||||
}
|
|
||||||
WvCdmTestBase::InstallTestRootOfTrust();
|
WvCdmTestBase::InstallTestRootOfTrust();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -506,8 +506,7 @@ CdmResponseType WvContentDecryptionModule::SetDebugIgnoreKeyboxCount(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::SetAllowTestKeybox(bool allow) {
|
CdmResponseType WvContentDecryptionModule::SetAllowTestKeybox(bool allow) {
|
||||||
// TODO(210807585) add functionality in next CL.
|
return CdmEngine::SetAllowTestKeybox(allow);
|
||||||
return NO_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::SetDecryptHash(
|
CdmResponseType WvContentDecryptionModule::SetDecryptHash(
|
||||||
|
|||||||
Reference in New Issue
Block a user