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:
@@ -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() {
|
||||
uint32_t version;
|
||||
std::string api_version =
|
||||
@@ -3061,6 +3076,11 @@ CdmResponseType CryptoSession::SetDebugIgnoreKeyboxCount(uint32_t count) {
|
||||
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() {
|
||||
const auto getter = [&]() -> okp::SystemFallbackPolicy* {
|
||||
// If not set, then OTA keybox provisioning is not supported or
|
||||
|
||||
@@ -641,6 +641,17 @@ std::string GetIgnoreCountFile() {
|
||||
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() {
|
||||
const std::string filename = GetIgnoreCountFile();
|
||||
wvcdm::FileSystem file_system;
|
||||
@@ -693,6 +704,49 @@ OEMCryptoResult SetDebugIgnoreKeyboxCount(uint32_t count) {
|
||||
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 {
|
||||
FunctionPointers* fcn;
|
||||
OEMCrypto_SESSION session;
|
||||
@@ -816,6 +870,7 @@ class Adapter {
|
||||
level1_.BuildInformation());
|
||||
}
|
||||
} else {
|
||||
level1_failed_ = true;
|
||||
FallBackToLevel3();
|
||||
}
|
||||
return result;
|
||||
@@ -837,7 +892,6 @@ class Adapter {
|
||||
Level1Terminate();
|
||||
level1_ = FunctionPointers(); // revert to all null pointers.
|
||||
level1_valid_ = false;
|
||||
level1_failed_ = true;
|
||||
// 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
|
||||
// debatable choice: I decided the risk of a dlclose resource leak out
|
||||
@@ -1162,23 +1216,32 @@ class Adapter {
|
||||
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
|
||||
// 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() {
|
||||
// then return an error code. The caller should fall back to L3.
|
||||
OEMCryptoResult ValidateOrInstallL1KeyboxOrCert() {
|
||||
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;
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
if (!level1_.IsKeyboxOrOEMCertValid) {
|
||||
// TODO(b/189989043): add metrics.
|
||||
LOGE("L1 invalid function pointers. Falling back to L3");
|
||||
FallBackToLevel3();
|
||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return 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.
|
||||
@@ -1189,6 +1252,19 @@ class Adapter {
|
||||
const OEMCrypto_ProvisioningMethod provisioning_method =
|
||||
level1_.GetProvisioningMethod ? level1_.GetProvisioningMethod()
|
||||
: 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) {
|
||||
// The keybox or certificate is valid -- that means initialization is done
|
||||
// and we only have save some metrics and return.
|
||||
@@ -1226,9 +1302,7 @@ class Adapter {
|
||||
wvcdm::metrics::
|
||||
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
|
||||
}
|
||||
FallBackToLevel3();
|
||||
return level3_.IsKeyboxOrOEMCertValid ? level3_.IsKeyboxOrOEMCertValid()
|
||||
: OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return file_attempt;
|
||||
}
|
||||
|
||||
bool IsOTAKeyboxSupported() {
|
||||
@@ -1342,7 +1416,7 @@ OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
||||
// continue on.
|
||||
if (status != OEMCrypto_SUCCESS) return status;
|
||||
const OEMCryptoResult keybox_status =
|
||||
gAdapter->ValidateOrInstallKeyboxOrCert();
|
||||
gAdapter->ValidateOrInstallL1KeyboxOrCert();
|
||||
uint32_t ignore_count = GetDebugIgnoreKeyboxCount();
|
||||
if (keybox_status == OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING ||
|
||||
ignore_count > 0) {
|
||||
@@ -1359,7 +1433,13 @@ OEMCryptoResult OEMCrypto_InitializeAndCheckKeybox(
|
||||
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,
|
||||
@@ -1643,6 +1723,9 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert,
|
||||
OEMCryptoResult OEMCrypto_SetDebugIgnoreKeyboxCount(uint32_t count) {
|
||||
return SetDebugIgnoreKeyboxCount(count);
|
||||
}
|
||||
OEMCryptoResult OEMCrypto_SetAllowTestKeybox(bool allow) {
|
||||
return SetAllowTestKeybox(allow);
|
||||
}
|
||||
} // namespace wvcdm
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id,
|
||||
|
||||
Reference in New Issue
Block a user