Separate OEM unprovisioning from DRM unprovisioing.
[ Cherry-pick of v19 http://go/wvgerrit/219330 ] [ Merge of http://go/wvgerrit/219454 ] For two-staged provisioning devices, the behavior of CdmEngine::Unprovision() varied by platform and context. For production Android, unprovisioning would remove both; for production and testing CE CDM it would only remove DRM provisioning; for testing Android may remove both or remove everything (both certs and licenses). This behavior was not documented, making use of the CdmEngine::Unprovision() API rather unpredictable. This change attempts to document the unpredictable behavior and add a way to explicitly remove the OEM certificate in the core code. The new CdmEngine::UnprovisionOemCert() will remove only the OEM certificate. Bug: 391469176 Test: run_x86_64_tests Test: WvTs on oriole Change-Id: Ib2f6ef61f45b5320c71d7e8e8460f7fe8e0e2248
This commit is contained in:
@@ -212,6 +212,15 @@ class CdmEngine {
|
||||
// system. This will force the device to reprovision itself.
|
||||
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level);
|
||||
|
||||
// Remove the system's REE-side OEM certificate for the specified
|
||||
// |security_level|.
|
||||
// Only effects two-stage provisioning devices which have an OEM cert
|
||||
// in the REE side file system.
|
||||
// Removing the OEM certificate will cause all DRM certificates tied to
|
||||
// the OEM certificate to be invalidated and unloadable to future
|
||||
// sessions.
|
||||
virtual CdmResponseType UnprovisionOemCert(CdmSecurityLevel security_level);
|
||||
|
||||
// Return the list of key_set_ids stored on the current (origin-specific)
|
||||
// file system.
|
||||
virtual CdmResponseType ListStoredLicenses(
|
||||
|
||||
@@ -1332,8 +1332,7 @@ CdmProvisioningStatus CdmEngine::GetProvisioningStatus(
|
||||
return kUnknownProvisionStatus;
|
||||
}
|
||||
|
||||
UsagePropertySet property_set;
|
||||
if (handle.HasCertificate(property_set.use_atsc_mode())) {
|
||||
if (handle.HasCertificate(/* atsc_mode_enabled = */ false)) {
|
||||
return kProvisioned;
|
||||
}
|
||||
if (crypto_session->GetPreProvisionTokenType() == kClientTokenBootCertChain) {
|
||||
@@ -1356,8 +1355,8 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
LOGD("OKP fallback to L3");
|
||||
security_level = kSecurityLevelL3;
|
||||
}
|
||||
// Devices with baked-in DRM certs cannot be reprovisioned and therefore must
|
||||
// not be unprovisioned.
|
||||
// Devices with baked-in DRM certs cannot be reprovisioned
|
||||
// and therefore must not be unprovisioned.
|
||||
std::unique_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
|
||||
CdmClientTokenType token_type = kClientTokenUninitialized;
|
||||
@@ -1376,18 +1375,78 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
LOGE("Unable to initialize device files");
|
||||
return CdmResponseType(UNPROVISION_ERROR_1);
|
||||
}
|
||||
|
||||
// TODO(b/141705730): Remove usage entries during unprovisioning.
|
||||
if (!file_system_->IsGlobal()) {
|
||||
if (!handle.RemoveCertificate() || !handle.RemoveOemCertificate()) {
|
||||
LOGE("Unable to delete certificate");
|
||||
// This if statement is misleading. There is no consistent
|
||||
// concept of "global" vs "per-app/origin" storage in the
|
||||
// core library. Android vs CE CDM behave very different.
|
||||
// On CE device:
|
||||
// file_system_->IsGlobal() is always true, even if app/origin
|
||||
// specific.
|
||||
// On Android:
|
||||
// file_system_->IsGlobal() is always false, except for some C++
|
||||
// test code.
|
||||
// TODO(b/142280599): Refactor this once CE CDM SPOIDs are supported
|
||||
// by the file system. May require moving platform-dependent behavior
|
||||
// to the platform-dependent layer. Only have this remove the
|
||||
// certificate and nothing else.
|
||||
if (!file_system_->IsGlobal()) { // AKA is Android
|
||||
// TODO(b/141705730): Remove usage entries during unprovisioning.
|
||||
// Not considered an error if no certificate exists.
|
||||
if (handle.HasCertificate(/* atsc_mode_enabled = */ false) &&
|
||||
!handle.RemoveCertificate()) {
|
||||
LOGE("Unable to delete DRM certificate");
|
||||
return CdmResponseType(UNPROVISION_ERROR_2);
|
||||
}
|
||||
// Maintaining old behavior expected by Android.
|
||||
const CdmResponseType oem_cert_status = UnprovisionOemCert(security_level);
|
||||
if (oem_cert_status != NO_ERROR) return oem_cert_status;
|
||||
} else { // AKA is CE CDM (or some Android tests)
|
||||
// On CE CDM, deleting all files only deletes the app/origin
|
||||
// specific files.
|
||||
// On Android, this will delete all files (only possible
|
||||
// during testing).
|
||||
if (!handle.DeleteAllFiles()) {
|
||||
LOGE("Unable to delete files");
|
||||
return CdmResponseType(UNPROVISION_ERROR_3);
|
||||
}
|
||||
}
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::UnprovisionOemCert(CdmSecurityLevel security_level) {
|
||||
LOGI("security_level = %s", CdmSecurityLevelToString(security_level));
|
||||
if (security_level == kSecurityLevelL1 && OkpIsInFallbackMode()) {
|
||||
LOGD("OKP fallback to L3");
|
||||
security_level = kSecurityLevelL3;
|
||||
}
|
||||
// Only BCC-based system have an OEM certificate that can
|
||||
// unprovisioned.
|
||||
// Prov 3.0 system's OEM certs are built into the TEE.
|
||||
std::unique_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
|
||||
CdmClientTokenType token_type = kClientTokenUninitialized;
|
||||
const CdmResponseType res = crypto_session->GetProvisioningMethod(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault,
|
||||
&token_type);
|
||||
if (res != NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
if (token_type != kClientTokenBootCertChain) {
|
||||
LOGD("Device does not support OEM certificate unprovisioning");
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
if (!handle.DeleteAllFiles()) {
|
||||
LOGE("Unable to delete files");
|
||||
return CdmResponseType(UNPROVISION_ERROR_3);
|
||||
// For Prov 4.0 devices, this will cause every app/origin client
|
||||
// to lose their offline content for the same TEE security level.
|
||||
wvutil::FileSystem global_file_system;
|
||||
DeviceFiles global_handle(&global_file_system);
|
||||
if (!global_handle.Init(security_level)) {
|
||||
LOGE("Unable to initialize global device files");
|
||||
return CdmResponseType(UNPROVISION_ERROR_1);
|
||||
}
|
||||
// Not considered an error if no certificate exists.
|
||||
if (global_handle.HasOemCertificate() &&
|
||||
!global_handle.RemoveOemCertificate()) {
|
||||
LOGE("Unable to delete OEM certificate");
|
||||
return CdmResponseType(UNPROVISION_ERROR_2);
|
||||
}
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
|
||||
@@ -709,17 +709,26 @@ bool DeviceFiles::RemoveCertificate() {
|
||||
RETURN_FALSE_IF_UNINITIALIZED()
|
||||
|
||||
std::string certificate_file_name;
|
||||
if (GetCertificateFileName(kCertificateLegacy, &certificate_file_name))
|
||||
RemoveFile(certificate_file_name);
|
||||
if (GetCertificateFileName(kCertificateDefault, &certificate_file_name))
|
||||
return RemoveFile(certificate_file_name);
|
||||
return true;
|
||||
// Return true so long as at least one certificate was removed.
|
||||
// This is to compliment the behavior of HasCertificate() which
|
||||
// returns true if at least one certificate exists.
|
||||
bool result = false;
|
||||
if (GetCertificateFileName(kCertificateLegacy, &certificate_file_name)) {
|
||||
LOGI("Removing legacy DRM cert");
|
||||
result |= RemoveFile(certificate_file_name);
|
||||
}
|
||||
if (GetCertificateFileName(kCertificateDefault, &certificate_file_name)) {
|
||||
LOGI("Removing DRM cert");
|
||||
result |= RemoveFile(certificate_file_name);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveOemCertificate() {
|
||||
RETURN_FALSE_IF_UNINITIALIZED()
|
||||
std::string certificate_file_name;
|
||||
if (GetOemCertificateFileName(&certificate_file_name)) {
|
||||
LOGI("Removing OEM certificate");
|
||||
return RemoveFile(certificate_file_name);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -346,6 +346,8 @@ CdmResponseType WvContentDecryptionModule::Unprovision(
|
||||
// Enable immediate OEMCrypto termination and re-initalization on
|
||||
// unprovisioning.
|
||||
CryptoSession::DisableDelayedTermination();
|
||||
// Android unprovisioning has historically allowed for both
|
||||
// DRM (app/origin-specific) and OEM (global) unprovisioning.
|
||||
return cdm_engine->Unprovision(level);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user