Disallow the ability to load offline licenses more than once

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

In b/65839890 we discovered that an android app loaded an offline
license more than once in a session. We did not intend to allow
this behavior but did not prohibit it. OEMCrypto v16 disallowed
this behavior at the OEMCrypto level but we worked around it
within the CDM to maintain the bad behavior. Now that we have confirmed
that the app no longer relies on that behavior, we are reverting
the CDM workaround.

Bug: 161865160
Test: WV unit/integration test, GtsMediaTestCases
      Amazon, Netflix, Google TV streaming and offline playback.
Change-Id: I31254e4c13b81587f88c6c684d08d5aa5c18e39d
This commit is contained in:
Rahul Frias
2021-04-25 01:17:27 -07:00
parent 0579fe805e
commit 0921b04e41
7 changed files with 1 additions and 99 deletions

View File

@@ -253,12 +253,6 @@ class CdmSession {
// true otherwise.
bool VerifyOfflineUsageEntry();
// On android, we previously permitted a license to be loaded and restored
// in the same session. This method releases resources so that
// CdmSession::Init can safely be invoked before a new license is restored.
// TODO(b/161865160): Investigate whether we can dispense with this scenario.
virtual CdmResponseType ReleaseOfflineResources();
// These setters are for testing only. Takes ownership of the pointers.
void set_license_parser(CdmLicense* license_parser);
void set_crypto_session(CryptoSession* crypto_session);
@@ -318,21 +312,6 @@ class CdmSession {
// license type release and offline related information
CdmKeySetId key_set_id_;
// TODO(b/161865160): Use these variables to cache Init parameters. Remove
// when b/ has been addressed.
// |cdm_client_property_set_| and |event_listener_| point to a data
// member of WVDrmPlugin or WVDrmPlugin itself. It is safe for CdmSession
// to make use of these objects without taking ownership since WVDrmPlugin
// lifetime exceeds CdmSession (WVDrmPlugin indirectly owns CdmSession
// objects). These pointers if set, should be valid till CdmSession
// destruction.
CdmClientPropertySet* cdm_client_property_set_ = nullptr;
CdmSessionId* forced_session_id_ = nullptr;
CdmSessionId forced_session_id_value_;
WvCdmEventListener* event_listener_ = nullptr;
bool has_license_been_loaded_ = false;
bool has_license_been_restored_ = false;
bool mock_license_parser_in_use_;
bool mock_policy_engine_in_use_;

View File

@@ -414,7 +414,7 @@ enum CdmResponseType : int32_t {
SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE = 359,
LICENSE_USAGE_ENTRY_MISSING = 360,
LOAD_USAGE_ENTRY_INVALID_SESSION = 361,
RESTORE_OFFLINE_LICENSE_ERROR_3 = 362,
// previously RESTORE_OFFLINE_LICENSE_ERROR_3 = 362,
NO_SRM_VERSION = 363,
SESSION_NOT_FOUND_23 = 364,
CERT_PROVISIONING_RESPONSE_ERROR_9 = 365,

View File

@@ -122,18 +122,6 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
return REINIT_ERROR;
}
// Save parameters in case Init needs to be called again (load and restore
// offline license)
if (cdm_client_property_set)
cdm_client_property_set_ = cdm_client_property_set;
if (forced_session_id) {
forced_session_id_value_ = *forced_session_id;
forced_session_id_ = &forced_session_id_value_;
}
if (event_listener) event_listener_ = event_listener;
if (cdm_client_property_set && cdm_client_property_set->security_level() ==
QUERY_VALUE_SECURITY_LEVEL_L3) {
requested_security_level_ = kLevel3;
@@ -217,22 +205,6 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
return NO_ERROR;
}
CdmResponseType CdmSession::ReleaseOfflineResources() {
// |license_parser_| and |policy_engine_| are reset in Init. No need to
// deallocate here.
if (has_provider_session_token() && supports_usage_info() && !is_release_) {
UpdateUsageEntryInformation();
}
if (!key_set_id_.empty()) {
// Unreserve the license ID.
file_handle_->UnreserveLicenseId(key_set_id_);
}
crypto_session_.reset(CryptoSession::MakeCryptoSession(crypto_metrics_));
initialized_ = false;
return NO_ERROR;
}
CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
CdmLicenseType license_type,
int* error_detail) {
@@ -244,30 +216,6 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
file_handle_->UnreserveLicenseId(key_set_id_);
}
// On android, we previously permitted an offline license to be loaded and
// restored in the same session. OEMCrypto v16+ disallows it so we need to
// release and initialize an OEMCrypto session. We will still prohibit
// multiple restore attempts on the same session.
// TODO(b/161865160): reevalute this scenario. Should we also
// (a) only allow a restore for the same key set ID that was loaded
// (b) if (a) is true, indicate success and do nothing else rather than
// release resources and reinitialize.
// We need to investigate the conditions that caused an app failure and
// led us to add a test to support this use case as there were multiple
// related issues.
if (!has_license_been_loaded_ && has_license_been_restored_) {
LOGE("Disallow multiple offline license restores");
return RESTORE_OFFLINE_LICENSE_ERROR_3;
}
if (has_license_been_loaded_) {
CdmResponseType status = ReleaseOfflineResources();
if (status != NO_ERROR) return status;
status =
Init(cdm_client_property_set_, forced_session_id_, event_listener_);
if (status != NO_ERROR) return status;
}
has_license_been_restored_ = true;
key_set_id_ = key_set_id;
DeviceFiles::CdmLicenseData license_data;
@@ -633,7 +581,6 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
sts = StoreLicense();
if (sts != NO_ERROR) return sts;
}
has_license_been_loaded_ = true;
return KEY_ADDED;
}

View File

@@ -734,9 +734,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case RESTORE_OFFLINE_LICENSE_ERROR_2:
*os << "RESTORE_OFFLINE_LICENSE_ERROR_2";
break;
case RESTORE_OFFLINE_LICENSE_ERROR_3:
*os << "RESTORE_OFFLINE_LICENSE_ERROR_3";
break;
case REWRAP_DEVICE_RSA_KEY_ERROR:
*os << "REWRAP_DEVICE_RSA_KEY_ERROR";
break;

View File

@@ -2939,23 +2939,6 @@ TEST_F(WvCdmRequestLicenseTest, DisallowMultipleRestoreOfflineKeyTest) {
decryptor_->CloseSession(session_id_);
}
TEST_F(WvCdmRequestLicenseTest, AllowLoadAndRestoreOfflineKeyTest) {
Unprovision();
Provision();
std::string key_id;
std::string client_auth;
GetOfflineConfiguration(&key_id, &client_auth);
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(config_.license_server(), client_auth);
EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_->RestoreKey(session_id_, key_set_id_));
decryptor_->CloseSession(session_id_);
}
TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) {
Unprovision();
Provision();

View File

@@ -477,8 +477,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
return kRenewKeyError2;
case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_2:
return kRestoreOfflineLicenseError2;
case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3:
return kRestoreOfflineLicenseError3;
case wvcdm::SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH:
return kSampleAndSubsampleSizeMismatch;
case wvcdm::SESSION_FILE_HANDLE_INIT_ERROR:

View File

@@ -167,7 +167,6 @@ static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) {
case wvcdm::RENEW_KEY_ERROR_1:
case wvcdm::RENEW_KEY_ERROR_2:
case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_2:
case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3:
case wvcdm::NOT_INITIALIZED_ERROR:
case wvcdm::REINIT_ERROR:
case wvcdm::SESSION_KEYS_NOT_FOUND:
@@ -616,7 +615,6 @@ static S mapCdmResponseType(wvcdm::CdmResponseType res) {
err = ::drm::V1_4::Status::LICENSE_RESTORE_ERROR;
break;
case wvcdm::GET_RELEASED_LICENSE_ERROR:
case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3:
err = ::drm::V1_4::Status::LICENSE_STATE_ERROR;
break;
case wvcdm::DEVICE_CERTIFICATE_ERROR_2: