Fall back to L3 if L1 has test keybox am: 31faf51933
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/16507243 Change-Id: I68c4410d36a984062a041846c131ea90c0c8c646
This commit is contained in:
committed by
Automerger Merge Worker
commit
cbb5bd0f7a
@@ -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