Ignore certain errors on RemoveOfflineLicense().

[ Merge of http://go/wvgerrit/209671 ]

The CDM API RemoveOfflineLicense() is used to remove an offline
license by key set ID.  From the app's perspective, removing the
offline license should not depend on an app to be provisioned, or
the license being loadable.  However, internally, the CDM attempts
to restore the license to lock out its usage entry.

An issue arises when the license is not able to be restored, which
will cause errors related to the restoration to be returned to the
app.  The license is still deleted in case of errors, but certain
partners have experienced GTS failures when using the MediaDRM API
removeOfflineLicense().

This change attempts to catch some of the common errors, but not all.
If certain errors are encountered during the restoration process, the
are not returned to the app.

Additional error cases may be added later, depending on vendor
feedback.

Bug: 319055420
Bug: 357863269
Bug: 370195605
Bug: 288118860
Bug: 302049654
Bug: 346845333
Bug: 312595506
Bug: 345232142
Bug: 303261245
Bug: 287735498
Bug: 372105842
Test: WVTS on Oriole
Change-Id: I020bbea30e5f6e0ae2777d8a1d4858c4f2af107b
This commit is contained in:
Alex Dale
2024-10-18 15:43:56 -07:00
parent 528645f5ab
commit aeae529c10
6 changed files with 250 additions and 41 deletions

View File

@@ -2129,11 +2129,13 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
return result;
}
void Unprovision() {
void Unprovision() { Unprovision(kDefaultCdmIdentifier); }
void Unprovision(const CdmIdentifier& identifier) {
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->Unprovision(kSecurityLevelL1, kDefaultCdmIdentifier));
decryptor_->Unprovision(kSecurityLevelL1, identifier));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->Unprovision(kSecurityLevelL3, kDefaultCdmIdentifier));
decryptor_->Unprovision(kSecurityLevelL3, identifier));
}
bool IsProvisioned(const CdmIdentifier& identifier,
@@ -2231,16 +2233,22 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
CdmSecurityLevel GetDefaultSecurityLevel() {
std::string level = GetSecurityLevel(nullptr).c_str();
CdmSecurityLevel security_level = kSecurityLevelUninitialized;
if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) == 0) {
security_level = kSecurityLevelL1;
} else if (level.compare(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0) {
security_level = kSecurityLevelL3;
} else {
EXPECT_TRUE(false) << "Default Security level is undefined: " << level;
std::string security_level;
const CdmResponseType status = decryptor_->QueryStatus(
kLevelDefault, wvcdm::QUERY_KEY_SECURITY_LEVEL, &security_level);
if (status != NO_ERROR) {
ADD_FAILURE() << "Failed to obtain default security level: "
<< status.ToString();
return kSecurityLevelUninitialized;
}
return security_level;
if (security_level == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) {
return kSecurityLevelL1;
}
if (security_level == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) {
return kSecurityLevelL3;
}
ADD_FAILURE() << "Undefined security level: " << security_level;
return kSecurityLevelUninitialized;
}
uint32_t QueryStatus(RequestedSecurityLevel security_level,
@@ -6546,9 +6554,12 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_DecryptPathTest) {
// not match the license's key set ID (possible for entry to have
// been overwritten).
TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseWithMissingUsageEntry) {
Unprovision();
Provision();
const CdmSecurityLevel security_level = GetDefaultSecurityLevel();
const RequestedSecurityLevel requested_security_level =
(security_level == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
Unprovision(kExampleIdentifier);
Provision(kExampleIdentifier, requested_security_level);
FileSystem file_system;
DeviceFiles handle(&file_system);
@@ -6562,9 +6573,9 @@ TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseWithMissingUsageEntry) {
// This license will be used to test how the CDM handles request to
// remove it when its entry has been deleted.
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
GenerateKeyRequest(key_id, kLicenseTypeOffline, kExampleIdentifier);
VerifyKeyRequestResponse(config_.license_server(), client_auth);
// Save the key set ID for check below.
const std::string original_key_set_id(key_set_id_);
@@ -6578,9 +6589,9 @@ TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseWithMissingUsageEntry) {
EXPECT_EQ(DeviceFiles::kNoError, sub_result);
// Re-provision.
Unprovision();
Unprovision(kExampleIdentifier);
handle.DeleteAllFiles();
Provision();
Provision(kExampleIdentifier, requested_security_level);
// Part 1: Test when usage entry is out of range of the table.
@@ -6591,26 +6602,26 @@ TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseWithMissingUsageEntry) {
std::vector<CdmKeySetId> key_set_ids;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(
security_level, kDefaultCdmIdentifier, &key_set_ids));
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
// Note: It is possible that future changes to the CDM will cause this
// check to fail (such by filtering results from ListStoreLicenses).
EXPECT_THAT(key_set_ids, Contains(original_key_set_id));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->RemoveOfflineLicense(
original_key_set_id, security_level, kDefaultCdmIdentifier));
original_key_set_id, security_level, kExampleIdentifier));
// Verify license has been removed.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(
security_level, kDefaultCdmIdentifier, &key_set_ids));
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
EXPECT_THAT(key_set_ids, Not(Contains(original_key_set_id)));
// Re-provision.
Unprovision();
Unprovision(kExampleIdentifier);
handle.DeleteAllFiles();
Provision();
Provision(kExampleIdentifier, requested_security_level);
// Part 2: Test when the entry does not match the license's key set ID.
@@ -6618,26 +6629,183 @@ TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseWithMissingUsageEntry) {
EXPECT_EQ(DeviceFiles::kNoError, sub_result);
// Request another license so that the usage table is not empty.
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
GenerateKeyRequest(key_id, kLicenseTypeOffline, kExampleIdentifier);
VerifyKeyRequestResponse(config_.license_server(), client_auth);
decryptor_->CloseSession(session_id_);
// Get list of existing offline licenses.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(
security_level, kDefaultCdmIdentifier, &key_set_ids));
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
EXPECT_THAT(key_set_ids, Contains(original_key_set_id));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->RemoveOfflineLicense(
original_key_set_id, security_level, kDefaultCdmIdentifier));
original_key_set_id, security_level, kExampleIdentifier));
// Verify license has been removed.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(
security_level, kDefaultCdmIdentifier, &key_set_ids));
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
EXPECT_THAT(key_set_ids, Not(Contains(original_key_set_id)));
}
TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseAfterUnprovisioning) {
const CdmSecurityLevel security_level = GetDefaultSecurityLevel();
const RequestedSecurityLevel requested_security_level =
(security_level == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
Unprovision(kExampleIdentifier);
Provision(kExampleIdentifier, requested_security_level);
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
// Setup: Request an offline license to create a valid license file.
// This license will be used to test how the CDM handles request to
// remove when the device has been unprovisioned.
decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline, kExampleIdentifier);
VerifyKeyRequestResponse(config_.license_server(), client_auth);
// Save the key set ID for check below.
const std::string original_key_set_id(key_set_id_);
decryptor_->CloseSession(session_id_);
// Unprovision, making the old DRM certificate unavailable.
Unprovision(kExampleIdentifier);
std::vector<CdmKeySetId> key_set_ids;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
// Note: It is possible that future changes to the CDM will cause this
// check to fail (such by filtering results from ListStoreLicenses).
EXPECT_THAT(key_set_ids, Contains(original_key_set_id));
// Remove offline license, without causing a provisioning error.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->RemoveOfflineLicense(
original_key_set_id, security_level, kExampleIdentifier));
// Verify license has been removed.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
EXPECT_THAT(key_set_ids, Not(Contains(original_key_set_id)));
}
TEST_F(WvCdmRequestLicenseTest, RemoveOfflineLicenseAfterReprovisioning) {
const CdmSecurityLevel security_level = GetDefaultSecurityLevel();
const RequestedSecurityLevel requested_security_level =
(security_level == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
Unprovision(kExampleIdentifier);
Provision(kExampleIdentifier, requested_security_level);
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
// Setup: Request an offline license to create a valid license file.
// This license will be used to test how the CDM handles request to
// remove when the device has been unprovisioned.
decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline, kExampleIdentifier);
VerifyKeyRequestResponse(config_.license_server(), client_auth);
// Save the key set ID for check below.
const std::string original_key_set_id(key_set_id_);
decryptor_->CloseSession(session_id_);
// Reprovision, making the old DRM certificate unavailable.
Unprovision(kExampleIdentifier);
Provision(kExampleIdentifier, requested_security_level);
std::vector<CdmKeySetId> key_set_ids;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
// Note: It is possible that future changes to the CDM will cause this
// check to fail (such by filtering results from ListStoreLicenses).
EXPECT_THAT(key_set_ids, Contains(original_key_set_id));
// Remove offline license, without causing a license load error.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->RemoveOfflineLicense(
original_key_set_id, security_level, kExampleIdentifier));
// Verify license has been removed.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
EXPECT_THAT(key_set_ids, Not(Contains(original_key_set_id)));
}
TEST_F(WvCdmRequestLicenseTest, RemoveUnlimitedOfflineLicense) {
const CdmSecurityLevel security_level = GetDefaultSecurityLevel();
const RequestedSecurityLevel requested_security_level =
(security_level == kSecurityLevelL3) ? kLevel3 : kLevelDefault;
Unprovision(kExampleIdentifier);
Provision(kExampleIdentifier, requested_security_level);
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
// Override content ID.
key_id = wvutil::a2bs_hex(
"0000004d" // size = 77
"70737368" // type = "pssh"
"00000000" // flags = None
"edef8ba979d64acea3c827dcd51d21ed" // system_id = Widevine
"0000002d" // pssh_data_size = 45
// WidevinePsshData(
// algorithm = AESCTR,
// provider = "widevine_test"
// content_id = b"GTS_CAN_PERSIST_LICENSE_0S")
"08011a0d7769646576696e655f7465"
"7374221a4754535f43414e5f504552"
"534953545f4c4943454e53455f3053");
// Setup: Request an offline license to create a valid license file.
// This license will be used to test how the CDM handles request to
// remove when the device has been unprovisioned.
decryptor_->OpenSession(config_.key_system(), nullptr, kExampleIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline, kExampleIdentifier);
VerifyKeyRequestResponse(config_.license_server(), client_auth);
// Save the key set ID for check below.
const std::string original_key_set_id(key_set_id_);
decryptor_->CloseSession(session_id_);
std::vector<CdmKeySetId> key_set_ids;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
// Note: It is possible that future changes to the CDM will cause this
// check to fail (such by filtering results from ListStoreLicenses).
EXPECT_THAT(key_set_ids, Contains(original_key_set_id));
// Remove offline license, without causing a generate signature error.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->RemoveOfflineLicense(
original_key_set_id, security_level, kExampleIdentifier));
// Verify license has been removed.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_->ListStoredLicenses(security_level, kExampleIdentifier,
&key_set_ids));
EXPECT_THAT(key_set_ids, Not(Contains(original_key_set_id)));
}