Always store the Prov 4.0 OEM cert in global storage

(This is a merge of http://go/wvgerrit/153550.)

On CE CDM, storage is split between global and per-origin storage, and
one type of storage cannot be used to access the other. (Though, until
an upcoming commit lands, the tests will allow it.) On Android, both
types of storage access the same filesystem. This means that code may
run fine on Android but fail on CE CDM.

The OEM Cert in Provisioning 4.0 is a global file that should only
exist once, but it was being accessed through the per-origin storage,
which would result in a separate OEM Cert being provisioned for each app
& origin on CE CDM. This patch changes the Prov 4.0 code to access it
through the global storage, using techniques similar to how the Usage
Table Header code does this.

Test: x86-64 w/ storage separated
Test: build_and_run_all_unit_tests.sh
Bug: 236400627
Change-Id: I301d250fc9543e62949a4d9fdcbdd109bd941384
This commit is contained in:
John "Juce" Bruce
2022-06-17 15:29:44 -07:00
parent 4455aeceed
commit b41eeac78c
5 changed files with 39 additions and 17 deletions

View File

@@ -441,6 +441,7 @@ enum CdmResponseType : int32_t {
PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2 = 383,
PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE = 384,
PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE = 385,
PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3 = 386,
// Don't forget to add new values to
// * core/test/test_printers.cpp.
// * android/include/mapErrors-inl.h

View File

@@ -841,8 +841,9 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
return NO_ERROR;
}
if (query_token == QUERY_KEY_SYSTEM_ID) {
wvutil::FileSystem global_file_system;
SystemIdExtractor extractor(security_level, crypto_session.get(),
file_system_);
&global_file_system);
uint32_t system_id;
if (!extractor.ExtractSystemId(&system_id)) {
LOGW("ExtractSystemId failed");
@@ -1203,9 +1204,16 @@ CdmProvisioningStatus CdmEngine::GetProvisioningStatus(
if (handle.HasCertificate(property_set.use_atsc_mode())) {
return kProvisioned;
}
if (crypto_session->GetPreProvisionTokenType() == kClientTokenBootCertChain &&
!handle.HasOemCertificate()) {
return kNeedsOemCertProvisioning;
if (crypto_session->GetPreProvisionTokenType() == kClientTokenBootCertChain) {
wvutil::FileSystem global_file_system;
DeviceFiles global_handle(&global_file_system);
if (!global_handle.Init(cdm_security_level)) {
LOGE("Failed to initialize global device files.");
return kUnknownProvisionStatus;
}
if (!global_handle.HasOemCertificate()) {
return kNeedsOemCertProvisioning;
}
}
return kNeedsDrmCertProvisioning;
}

View File

@@ -323,24 +323,25 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
return PROVISIONING_4_FILE_SYSTEM_IS_NULL;
}
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
DeviceFiles file_handle(file_system);
if (!file_handle.Init(security_level)) {
LOGE("Failed to initialize DeviceFiles");
wvutil::FileSystem global_file_system;
DeviceFiles global_file_handle(&global_file_system);
if (!global_file_handle.Init(security_level)) {
LOGE("Failed to initialize global DeviceFiles");
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES;
}
ProvisioningRequest provisioning_request;
// Determine the current stage by checking if OEM cert exists.
std::string stored_oem_cert;
if (file_handle.HasOemCertificate()) {
if (global_file_handle.HasOemCertificate()) {
// This is second stage requesting for DRM cert. We try to use the stored
// OEM cert. In case of error, we just fall back to the first stage
// provisioning (request for an OEM cert).
if (!RetrieveOemCertificateAndLoadPrivateKey(*crypto_session_, file_handle,
stored_oem_cert)) {
if (!RetrieveOemCertificateAndLoadPrivateKey(
*crypto_session_, global_file_handle, stored_oem_cert)) {
stored_oem_cert.clear();
LOGD("Deleting the stored OEM certificate due to unsuccessful read");
if (!file_handle.RemoveOemCertificate()) {
if (!global_file_handle.RemoveOemCertificate()) {
// This should not happen.
LOGE("Failed to delete the OEM certificate certificate");
}
@@ -507,23 +508,31 @@ CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
CloseSession();
DeviceFiles file_handle(file_system);
if (!file_handle.Init(security_level)) {
LOGE("Failed to initialize DeviceFiles");
wvutil::FileSystem global_file_system;
DeviceFiles global_file_handle(&global_file_system);
if (!global_file_handle.Init(security_level)) {
LOGE("Failed to initialize global DeviceFiles");
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2;
}
// Check the stage of the provisioning by checking if an OEM cert is already
// stored in the file system.
if (!file_handle.HasOemCertificate()) {
if (!global_file_handle.HasOemCertificate()) {
// No OEM cert already stored => the response is expected to be an OEM cert.
if (!file_handle.StoreOemCertificate(device_certificate, private_key)) {
if (!global_file_handle.StoreOemCertificate(device_certificate,
private_key)) {
LOGE("Failed to store provisioning 4 OEM certificate");
return PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE;
}
} else {
// The response is assumed to be an DRM cert.
if (!file_handle.StoreCertificate(device_certificate, private_key)) {
DeviceFiles per_origin_file_handle(file_system);
if (!per_origin_file_handle.Init(security_level)) {
LOGE("Failed to initialize per-origin DeviceFiles");
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3;
}
if (!per_origin_file_handle.StoreCertificate(device_certificate,
private_key)) {
LOGE("Failed to store provisioning 4 DRM certificate");
return PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE;
}

View File

@@ -991,6 +991,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE:
*os << "PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE";
break;
case PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3:
*os << "PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3";
break;
default:
*os << "Unknown CdmResponseType";
break;

View File

@@ -379,6 +379,7 @@ static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) {
case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2:
case wvcdm::PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE:
case wvcdm::PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE:
case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3:
ALOGW("Returns UNKNOWN error for legacy status: %d", res);
return Status::ERROR_DRM_UNKNOWN;