From e4513f4a5976f93f98c7bdaf76fbc9f8a52809a7 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Mon, 7 Dec 2015 14:12:46 -0800 Subject: [PATCH] Merge CE Device Changes This is a merge of the following changes made for CE devices in the widevine share repo: http://go/wvgerrit/16211 Only load offline session if needed in GKR http://go/wvgerrit/16245 Unreserve IDs in reservation test http://go/wvgerrit/16242 Re-enable WebM tests http://go/wvgerrit/16240 Un-reserve reserved license IDs http://go/wvgerrit/16190 Add temporary session type http://go/wvgerrit/16189 Enforce license type and can_persist for storage Change-Id: I592416f66c0d1286844266c01cc9b4906c7b6b05 --- libwvdrmengine/cdm/core/include/cdm_session.h | 3 +++ .../cdm/core/include/device_files.h | 1 + libwvdrmengine/cdm/core/include/license.h | 5 ++++ .../cdm/core/include/wv_cdm_types.h | 5 ++++ libwvdrmengine/cdm/core/src/cdm_engine.cpp | 3 ++- libwvdrmengine/cdm/core/src/cdm_session.cpp | 26 +++++++++++++++++-- libwvdrmengine/cdm/core/src/device_files.cpp | 9 +++++++ libwvdrmengine/cdm/core/src/license.cpp | 9 ++++++- .../cdm/core/test/cdm_engine_test.cpp | 4 +-- .../cdm/core/test/device_files_unittest.cpp | 2 ++ libwvdrmengine/include/WVErrors.h | 4 ++- libwvdrmengine/include/mapErrors-inl.h | 4 +++ 12 files changed, 68 insertions(+), 7 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 24d61319..d473d16b 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -104,6 +104,8 @@ class CdmSession { virtual bool is_release() { return is_release_; } virtual bool is_offline() { return is_offline_; } + virtual bool is_temporary() { return is_temporary_; } + virtual bool license_received() { return license_received_; } // ReleaseCrypto() - Closes the underlying crypto session but leaves this // object alive. It is invalid to call any method that requires a crypto @@ -141,6 +143,7 @@ class CdmSession { bool license_received_; bool is_offline_; bool is_release_; + bool is_temporary_; CdmSecurityLevel security_level_; SecurityLevel requested_security_level_; CdmAppParameterMap app_parameters_; diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index f7cc0636..ee029ccc 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -67,6 +67,7 @@ class DeviceFiles { virtual bool DeleteAllLicenses(); virtual bool LicenseExists(const std::string& key_set_id); virtual bool ReserveLicenseId(const std::string& key_set_id); + virtual bool UnreserveLicenseId(const std::string& key_set_id); virtual bool StoreUsageInfo(const std::string& provider_session_token, const CdmKeyMessage& key_request, diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 7e7912e6..a6a9a82a 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -56,6 +56,10 @@ class CdmLicense { return provider_session_token_; } + virtual bool is_offline() { + return is_offline_; + } + static CdmResponseType VerifySignedServiceCertificate( const std::string& signed_service_certificate); @@ -89,6 +93,7 @@ class CdmLicense { std::set loaded_keys_; std::string provider_session_token_; bool renew_with_client_id_; + bool is_offline_; // Used for certificate based licensing CdmKeyMessage key_request_; diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 4de2d9c1..40f8b055 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -207,6 +207,8 @@ enum CdmResponseType { DUPLICATE_SESSION_ID_SPECIFIED, LICENSE_RENEWAL_PROHIBITED, EMPTY_PROVISIONING_CERTIFICATE_2, + OFFLINE_LICENSE_PROHIBITED, + STORAGE_PROHIBITED, }; enum CdmKeyStatus { @@ -229,6 +231,9 @@ enum CdmLicenseType { // If the original request was saved to make a service certificate request, // use Deferred for the license type in the subsequent request. kLicenseTypeDeferred, + // Like Streaming, but stricter. Does not permit storage of any kind. + // Named after the 'temporary' session type in EME, which has this behavior. + kLicenseTypeTemporary, }; enum SecurityLevel { diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 00900293..2c1e1b2e 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -228,7 +228,8 @@ CdmResponseType CdmEngine::GenerateKeyRequest( key_request->clear(); - if (license_type == kLicenseTypeRelease) { + if (license_type == kLicenseTypeRelease && + !iter->second->license_received()) { sts = iter->second->RestoreOfflineSession(key_set_id, kLicenseTypeRelease); if (sts != KEY_ADDED) { LOGE("CdmEngine::GenerateKeyRequest: key release restoration failed," diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 050cfdba..9b386afe 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -37,6 +37,7 @@ CdmSession::CdmSession(CdmClientPropertySet* cdm_client_property_set, license_received_(false), is_offline_(false), is_release_(false), + is_temporary_(false), security_level_(kSecurityLevelUninitialized), requested_security_level_(kLevelDefault), is_initial_decryption_(true), @@ -66,7 +67,13 @@ CdmSession::CdmSession(CdmClientPropertySet* cdm_client_property_set, } } -CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); } +CdmSession::~CdmSession() { + if (!key_set_id_.empty()) { + // Unreserve the license ID. + file_handle_->UnreserveLicenseId(key_set_id_); + } + Properties::RemoveSessionPropertySet(session_id_); +} CdmResponseType CdmSession::Init() { if (session_id_.empty()) { @@ -184,6 +191,9 @@ CdmResponseType CdmSession::GenerateKeyRequest( } switch (license_type) { + case kLicenseTypeTemporary: + is_temporary_ = true; + break; case kLicenseTypeStreaming: is_offline_ = false; break; @@ -207,6 +217,8 @@ CdmResponseType CdmSession::GenerateKeyRequest( license_type = kLicenseTypeRelease; } else if (is_offline_) { license_type = kLicenseTypeOffline; + } else if (is_temporary_) { + license_type = kLicenseTypeTemporary; } else { license_type = kLicenseTypeStreaming; } @@ -484,12 +496,22 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) { } CdmResponseType CdmSession::StoreLicense() { + if (is_temporary_) { + LOGE("CdmSession::StoreLicense: Session type prohibits storage."); + return STORAGE_PROHIBITED; + } + if (is_offline_) { if (key_set_id_.empty()) { LOGE("CdmSession::StoreLicense: No key set ID"); return EMPTY_KEYSET_ID; } + if (!license_parser_->is_offline()) { + LOGE("CdmSession::StoreLicense: License policy prohibits storage."); + return OFFLINE_LICENSE_PROHIBITED; + } + if (!StoreLicense(DeviceFiles::kLicenseStateActive)) { LOGE("CdmSession::StoreLicense: Unable to store license"); CdmResponseType sts = Init(); @@ -502,7 +524,7 @@ CdmResponseType CdmSession::StoreLicense() { return STORE_LICENSE_ERROR_1; } return NO_ERROR; - } + } // if (is_offline_) std::string provider_session_token = license_parser_->provider_session_token(); diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 4eda0f46..aaaef2b0 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -343,6 +343,15 @@ bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) { return true; } +bool DeviceFiles::UnreserveLicenseId(const std::string& key_set_id) { + if (!initialized_) { + LOGW("DeviceFiles::UnreserveLicenseId: not initialized"); + return false; + } + reserved_license_ids_.erase(key_set_id); + return true; +} + bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, const CdmKeyMessage& key_request, const CdmKeyResponse& key_response, diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index a2a5d297..72af4db7 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -132,6 +132,7 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id) session_id_(session_id), initialized_(false), renew_with_client_id_(false), + is_offline_(false), clock_(new Clock()) {} CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock) @@ -139,7 +140,8 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock) policy_engine_(NULL), session_id_(session_id), initialized_(false), - renew_with_client_id_(false) { + renew_with_client_id_(false), + is_offline_(false) { clock_.reset(clock); } @@ -522,6 +524,10 @@ CdmResponseType CdmLicense::HandleKeyResponse( return NO_CONTENT_KEY; } + if (license.id().type() == video_widevine_server::sdk::OFFLINE && + license.policy().can_persist()) + is_offline_ = true; + if (license.id().has_provider_session_token()) provider_session_token_ = license.id().provider_session_token(); @@ -1102,6 +1108,7 @@ bool CdmLicense::PrepareContentId(const CdmLicenseType license_type, content_id->set_license_type(video_widevine_server::sdk::OFFLINE); break; case kLicenseTypeStreaming: + case kLicenseTypeTemporary: content_id->set_license_type(video_widevine_server::sdk::STREAMING); break; default: diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp index 0418728a..84e6e71b 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp @@ -200,7 +200,7 @@ TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) { } // TODO(juce): Set up with correct test data. -TEST_F(WvCdmEngineTest, DISABLED_BaseWebmMessageTest) { +TEST_F(WvCdmEngineTest, BaseWebmMessageTest) { GenerateKeyRequest(g_key_id_unwrapped, kWebmMimeType); GetKeyRequestResponse(g_license_server, g_client_auth); } @@ -220,7 +220,7 @@ TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) { } // TODO(juce): Set up with correct test data. -TEST_F(WvCdmEngineTest, DISABLED_NormalDecryptionWebm) { +TEST_F(WvCdmEngineTest, NormalDecryptionWebm) { GenerateKeyRequest(g_key_id_unwrapped, kWebmMimeType); VerifyNewKeyResponse(g_license_server, g_client_auth); } diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 4c757932..416e6274 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -2140,6 +2140,8 @@ TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) { EXPECT_TRUE(device_files.ReserveLicenseId(license_test_data[i].key_set_id)); // Validate that the license IDs are actually reserved. EXPECT_TRUE(device_files.LicenseExists(license_test_data[i].key_set_id)); + // Unreserve these IDs to avoid polluting other tests. + EXPECT_TRUE(device_files.UnreserveLicenseId(license_test_data[i].key_set_id)); } } diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index ac1b3a7e..9e2ca991 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -177,7 +177,9 @@ enum { kEmptyLicenseRequest = ERROR_DRM_VENDOR_MIN + 163, kDuplicateSessionIdSpecified = ERROR_DRM_VENDOR_MIN + 164, kLicenseRenewalProhibited = ERROR_DRM_VENDOR_MIN + 165, - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 165, + kOfflineLicenseProhibited = ERROR_DRM_VENDOR_MIN + 166, + kStorageProhibited = ERROR_DRM_VENDOR_MIN + 167, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 167, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index 8ef2d041..64711323 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -343,6 +343,10 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kDuplicateSessionIdSpecified; case wvcdm::LICENSE_RENEWAL_PROHIBITED: return kLicenseRenewalProhibited; + case wvcdm::OFFLINE_LICENSE_PROHIBITED: + return kOfflineLicenseProhibited; + case wvcdm::STORAGE_PROHIBITED: + return kStorageProhibited; case wvcdm::UNKNOWN_ERROR: return android::ERROR_DRM_UNKNOWN; case wvcdm::SECURE_BUFFER_REQUIRED: