From 85da7bdb98d15af88c88702e2c751fcbcd548c80 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Wed, 30 Sep 2015 09:48:07 -0700 Subject: [PATCH] Refactoring to cache service certs and initialization data * Extend CdmLicense's stored_init_data_ [ Merge of http://go/wvgerrit/14661 ] CdmLicense will store init data when a server cert must be provisioned. After provisioning, the original init data can be used to generate the originally-intended license request. To do this before, the caller had to call CdmSession's GenerateKeyRequest with an empty InitializationData object. However, the init data's type still had to be set, as did the license type. This CL allows the caller to use a truly empty InitializationData without a type. To permit this, CdmLicense now stores a full InitializationData object, rather than just a copy of it's data field. With this CL, the caller also avoid storing the original license type. To accomplish this, CdmSession uses the already-set is_offline_ and is_release_ flags from the original call to reconstruct the intended license type. The caller uses the new type kLicenseTypeDeferred. To facilitate storing whole InitializationData objects, they are now copyable. This ultimately simplifies server cert code for the new CE CDM. * Store service certs in Properties [ Merge of http://go/wvgerrit/14664 ] This allows CE devices to mimic the Chrome CDM's behavior of sharing server certs between sessions. This also affects Android behavior. Previously, provisioned service certificates were per-session, while explicitly-set service certs were per-DRM-plugin. Now, both are per-DRM-plugin. A DRM plugin is associated with a mediaDrm object. Content providers will still be able to retrieve and use different certificates. The change here requires an app, that wishes to use different provisioned service certificates will have to use multiple mediaDrm objects. This is an unlikely scenario. Change-Id: If2586932784ed046ecab72b5720ff30547e84b97 --- .../core/include/cdm_client_property_set.h | 1 + libwvdrmengine/cdm/core/include/cdm_engine.h | 4 +- libwvdrmengine/cdm/core/include/cdm_session.h | 4 +- .../cdm/core/include/initialization_data.h | 1 - libwvdrmengine/cdm/core/include/license.h | 21 ++--- libwvdrmengine/cdm/core/include/properties.h | 9 +- .../cdm/core/include/wv_cdm_types.h | 11 ++- libwvdrmengine/cdm/core/src/cdm_engine.cpp | 10 +- libwvdrmengine/cdm/core/src/cdm_session.cpp | 51 ++++++++--- libwvdrmengine/cdm/core/src/license.cpp | 91 +++++++++++-------- libwvdrmengine/cdm/core/src/properties.cpp | 19 +++- .../cdm/core/test/cdm_session_unittest.cpp | 5 +- .../cdm/core/test/license_unittest.cpp | 6 +- .../cdm/core/test/test_printers.cpp | 5 +- .../cdm/test/cdm_extended_duration_test.cpp | 6 +- .../cdm/test/request_license_test.cpp | 6 +- libwvdrmengine/include/WVErrors.h | 5 +- libwvdrmengine/include/mapErrors-inl.h | 8 +- libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 3 +- 19 files changed, 162 insertions(+), 104 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h index 74d7421e..589a60cc 100644 --- a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h +++ b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h @@ -16,6 +16,7 @@ class CdmClientPropertySet { virtual const std::string& security_level() const = 0; virtual bool use_privacy_mode() const = 0; virtual const std::string& service_certificate() const = 0; + virtual void set_service_certificate(const std::string& cert) = 0; virtual bool is_session_sharing_enabled() const = 0; virtual uint32_t session_sharing_id() const = 0; virtual void set_session_sharing_id(uint32_t id) = 0; diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index 1de4090d..ce6ec57e 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -31,7 +31,7 @@ class CdmEngine { // Session related methods virtual CdmResponseType OpenSession(const CdmKeySystem& key_system, - const CdmClientPropertySet* property_set, + CdmClientPropertySet* property_set, const std::string& origin, WvCdmEventListener* event_listener, const CdmSessionId* forced_session_id, @@ -40,7 +40,7 @@ class CdmEngine { virtual bool IsOpenSession(const CdmSessionId& session_id); virtual CdmResponseType OpenKeySetSession( - const CdmKeySetId& key_set_id, const CdmClientPropertySet* property_set, + const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set, const std::string& origin, WvCdmEventListener* event_listener); virtual CdmResponseType CloseKeySetSession(const CdmKeySetId& key_set_id); diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 0f7c50ec..24d61319 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -22,7 +22,7 @@ class WvCdmEventListener; class CdmSession { public: - CdmSession(const CdmClientPropertySet* cdm_client_property_set, + CdmSession(CdmClientPropertySet* cdm_client_property_set, const std::string& origin, WvCdmEventListener* event_listener, const CdmSessionId* forced_session_id); virtual ~CdmSession(); @@ -37,7 +37,7 @@ class CdmSession { virtual const CdmSessionId& session_id() { return session_id_; } virtual CdmResponseType GenerateKeyRequest( - const InitializationData& init_data, const CdmLicenseType license_type, + const InitializationData& init_data, CdmLicenseType license_type, const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request, CdmKeyRequestType* key_request_type, std::string* server_url, CdmKeySetId* key_set_id); diff --git a/libwvdrmengine/cdm/core/include/initialization_data.h b/libwvdrmengine/cdm/core/include/initialization_data.h index af33b6b4..80803c7b 100644 --- a/libwvdrmengine/cdm/core/include/initialization_data.h +++ b/libwvdrmengine/cdm/core/include/initialization_data.h @@ -34,7 +34,6 @@ class InitializationData { CdmInitData data_; bool is_cenc_; bool is_webm_; - CORE_DISALLOW_COPY_AND_ASSIGN(InitializationData); }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 7bf6b0aa..7e7912e6 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -24,7 +24,7 @@ class PolicyEngine; class CdmLicense { public: - CdmLicense(); + CdmLicense(const CdmSessionId& session_id); virtual ~CdmLicense(); virtual bool Init(const std::string& token, CryptoSession* session, @@ -32,12 +32,11 @@ class CdmLicense { virtual CdmResponseType PrepareKeyRequest( const InitializationData& init_data, const CdmLicenseType license_type, - const CdmAppParameterMap& app_parameters, const CdmSessionId& session_id, - CdmKeyMessage* signed_request, std::string* server_url); + const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request, + std::string* server_url); virtual CdmResponseType PrepareKeyUpdateRequest( bool is_renewal, const CdmAppParameterMap& app_parameters, - const CdmSessionId& session_id, CdmKeyMessage* signed_request, - std::string* server_url); + CdmKeyMessage* signed_request, std::string* server_url); virtual CdmResponseType HandleKeyResponse( const CdmKeyResponse& license_response); virtual CdmResponseType HandleKeyUpdateResponse( @@ -50,7 +49,7 @@ class CdmLicense { int64_t playback_start_time, int64_t last_playback_time); virtual bool RestoreLicenseForRelease(const CdmKeyMessage& license_request, const CdmKeyResponse& license_response); - virtual bool HasInitData() { return !stored_init_data_.empty(); } + virtual bool HasInitData() { return stored_init_data_.get(); } virtual bool IsKeyLoaded(const KeyId& key_id); virtual std::string provider_session_token() { @@ -78,15 +77,14 @@ class CdmLicense { static CdmResponseType VerifyAndExtractSignedServiceCertificate( const std::string& signed_service_certificate, std::string* service_certificate); - bool GetServiceCertificate(const CdmSessionId& session_id, - std::string* service_certificate); + bool GetServiceCertificate(std::string* service_certificate); CryptoSession* session_; PolicyEngine* policy_engine_; std::string server_url_; std::string token_; - std::string service_certificate_; - std::string stored_init_data_; + const CdmSessionId session_id_; + scoped_ptr stored_init_data_; bool initialized_; std::set loaded_keys_; std::string provider_session_token_; @@ -98,7 +96,8 @@ class CdmLicense { scoped_ptr clock_; // For testing - CdmLicense(Clock* clock); // CdmLicense takes ownership of the clock. + // CdmLicense takes ownership of the clock. + CdmLicense(const CdmSessionId& session_id, Clock* clock); #if defined(UNIT_TEST) friend class CdmLicenseTest; #endif diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index cc8f7ee3..bf4da706 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -17,7 +17,7 @@ namespace wvcdm { -typedef std::map +typedef std::map CdmClientPropertySetMap; // This class saves information about features and properties enabled @@ -55,20 +55,23 @@ class Properties { static bool GetFactoryKeyboxPath(std::string* keybox); static bool GetOEMCryptoPath(std::string* library_name); static bool AlwaysUseKeySetIds(); + static bool GetSecurityLevelDirectories(std::vector* dirs); static bool GetApplicationId(const CdmSessionId& session_id, std::string* app_id); static bool GetServiceCertificate(const CdmSessionId& session_id, std::string* service_certificate); + static bool SetServiceCertificate(const CdmSessionId& session_id, + const std::string& service_certificate); static bool UsePrivacyMode(const CdmSessionId& session_id); static uint32_t GetSessionSharingId(const CdmSessionId& session_id); static bool AddSessionPropertySet(const CdmSessionId& session_id, - const CdmClientPropertySet* property_set); + CdmClientPropertySet* property_set); static bool RemoveSessionPropertySet(const CdmSessionId& session_id); private: - static const CdmClientPropertySet* GetCdmClientPropertySet( + static CdmClientPropertySet* GetCdmClientPropertySet( const CdmSessionId& session_id); static void set_oem_crypto_use_secure_buffers(bool flag) { oem_crypto_use_secure_buffers_ = flag; diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 78001a6f..4de2d9c1 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -186,11 +186,12 @@ enum CdmResponseType { CLIENT_ID_RSA_INIT_ERROR, CLIENT_ID_RSA_ENCRYPT_ERROR, INVALID_QUERY_STATUS, - EMPTY_PROVISIONING_CERTIFICATE_2, + UNUSED_3, /* previously EMPTY_PROVISIONING_CERTIFICATE_2 on mnc-dev, */ + /* DUPLICATE_SESSION_ID_SPECIFIED on master */ LICENSE_PARSER_NOT_INITIALIZED_4, INVALID_PARAMETERS_LIC_3, INVALID_PARAMETERS_LIC_4, - INVALID_PARAMETERS_LIC_5, + UNUSED_2, /* previously INVALID_PARAMETERS_LIC_5 */ INVALID_PARAMETERS_LIC_6, INVALID_PARAMETERS_LIC_7, LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR, @@ -205,6 +206,7 @@ enum CdmResponseType { SECURE_BUFFER_REQUIRED, DUPLICATE_SESSION_ID_SPECIFIED, LICENSE_RENEWAL_PROHIBITED, + EMPTY_PROVISIONING_CERTIFICATE_2, }; enum CdmKeyStatus { @@ -223,7 +225,10 @@ typedef std::map CdmKeyStatusMap; enum CdmLicenseType { kLicenseTypeOffline, kLicenseTypeStreaming, - kLicenseTypeRelease + kLicenseTypeRelease, + // If the original request was saved to make a service certificate request, + // use Deferred for the license type in the subsequent request. + kLicenseTypeDeferred, }; enum SecurityLevel { diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 14fb673e..85f307ce 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -38,6 +38,7 @@ class UsagePropertySet : public CdmClientPropertySet { virtual const std::string& security_level() const { return security_level_; } virtual bool use_privacy_mode() const { return false; } virtual const std::string& service_certificate() const { return empty_; } + virtual void set_service_certificate(const std::string&) {} virtual bool is_session_sharing_enabled() const { return false; } virtual uint32_t session_sharing_id() const { return 0; } virtual void set_session_sharing_id(uint32_t /* id */) {} @@ -75,7 +76,7 @@ CdmEngine::~CdmEngine() { } CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, - const CdmClientPropertySet* property_set, + CdmClientPropertySet* property_set, const std::string& origin, WvCdmEventListener* event_listener, const CdmSessionId* forced_session_id, @@ -122,7 +123,7 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, } CdmResponseType CdmEngine::OpenKeySetSession( - const CdmKeySetId& key_set_id, const CdmClientPropertySet* property_set, + const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set, const std::string& origin, WvCdmEventListener* event_listener) { LOGI("CdmEngine::OpenKeySetSession"); @@ -630,7 +631,6 @@ CdmResponseType CdmEngine::HandleProvisioningResponse( "missing."); return EMPTY_PROVISIONING_CERTIFICATE_1; } - return NO_ERROR; } CdmResponseType ret = cert_provisioning_->HandleProvisioningResponse( @@ -865,8 +865,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) { : kLevelDefault; usage_property_set_->set_security_level(security_level); usage_session_.reset( - new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, - NULL)); + new CdmSession(usage_property_set_.get(), + EMPTY_ORIGIN, NULL, NULL)); CdmResponseType status2 = usage_session_-> DeleteMultipleUsageInformation(provider_session_tokens); if (status2 != NO_ERROR) { diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index e2aedd9a..a5b4da0e 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -2,7 +2,9 @@ #include "cdm_session.h" +#include #include + #include #include @@ -23,14 +25,13 @@ const size_t kKeySetIdLength = 14; namespace wvcdm { -CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, +CdmSession::CdmSession(CdmClientPropertySet* cdm_client_property_set, const std::string& origin, WvCdmEventListener* event_listener, const CdmSessionId* forced_session_id) : initialized_(false), session_id_(GenerateSessionId()), origin_(origin), - license_parser_(new CdmLicense), crypto_session_(new CryptoSession), file_handle_(new DeviceFiles), license_received_(false), @@ -51,6 +52,7 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, } session_id_ = key_set_id_; } + license_parser_.reset(new CdmLicense(session_id_)); policy_engine_.reset(new PolicyEngine( session_id_, event_listener, crypto_session_.get())); if (cdm_client_property_set) { @@ -166,7 +168,7 @@ CdmResponseType CdmSession::RestoreUsageSession( } CdmResponseType CdmSession::GenerateKeyRequest( - const InitializationData& init_data, const CdmLicenseType license_type, + const InitializationData& init_data, CdmLicenseType license_type, const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request, CdmKeyRequestType* key_request_type, std::string* server_url, CdmKeySetId* key_set_id) { @@ -190,6 +192,24 @@ CdmResponseType CdmSession::GenerateKeyRequest( case kLicenseTypeRelease: is_release_ = true; break; + case kLicenseTypeDeferred: + // If you're going to pass Deferred, you must have empty init data in + // this call and stored init data from the previous call. + if (!init_data.IsEmpty() || !license_parser_->HasInitData()) { + return INVALID_LICENSE_TYPE; + } + // The arguments check out. + // The is_release_ and is_offline_ flags were already set last time based + // on the original license type. Do not change them, and use them to + // re-derive the original license type. + if (is_release_) { + license_type = kLicenseTypeRelease; + } else if (is_offline_) { + license_type = kLicenseTypeOffline; + } else { + license_type = kLicenseTypeStreaming; + } + break; default: LOGE("CdmSession::GenerateKeyRequest: unrecognized license type: %ld", license_type); @@ -204,14 +224,16 @@ CdmResponseType CdmSession::GenerateKeyRequest( return GenerateRenewalRequest(key_request, server_url); } else { if (key_request_type) *key_request_type = kKeyRequestTypeInitial; - if (!init_data.is_supported()) { - LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)", - init_data.type().c_str()); - return UNSUPPORTED_INIT_DATA; - } - if (init_data.IsEmpty() && !license_parser_->HasInitData()) { - LOGW("CdmSession::GenerateKeyRequest: init data absent"); - return INIT_DATA_NOT_FOUND; + if (!license_parser_->HasInitData()) { + if (!init_data.is_supported()) { + LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)", + init_data.type().c_str()); + return UNSUPPORTED_INIT_DATA; + } + if (init_data.IsEmpty()) { + LOGW("CdmSession::GenerateKeyRequest: init data absent"); + return INIT_DATA_NOT_FOUND; + } } if (is_offline_ && key_set_id_.empty() && !GenerateKeySetId(&key_set_id_)) { @@ -222,8 +244,7 @@ CdmResponseType CdmSession::GenerateKeyRequest( app_parameters_ = app_parameters; CdmResponseType status = license_parser_->PrepareKeyRequest( init_data, license_type, - app_parameters, session_id_, - key_request, server_url); + app_parameters, key_request, server_url); if (KEY_MESSAGE != status) return status; @@ -374,7 +395,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) { CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request, std::string* server_url) { CdmResponseType status = license_parser_->PrepareKeyUpdateRequest( - true, app_parameters_, session_id_, key_request, server_url); + true, app_parameters_, key_request, server_url); if (KEY_MESSAGE != status) return status; @@ -402,7 +423,7 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request, std::string* server_url) { is_release_ = true; CdmResponseType status = license_parser_->PrepareKeyUpdateRequest( - false, app_parameters_, session_id_, key_request, server_url); + false, app_parameters_, key_request, server_url); if (KEY_MESSAGE != status) return status; diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 54962d6b..a789a6e8 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -126,13 +126,20 @@ static std::vector ExtractContentKeys(const License& license) { return key_array; } -CdmLicense::CdmLicense() +CdmLicense::CdmLicense(const CdmSessionId& session_id) : session_(NULL), + policy_engine_(NULL), + session_id_(session_id), initialized_(false), renew_with_client_id_(false), clock_(new Clock()) {} -CdmLicense::CdmLicense(Clock* clock) : session_(NULL), initialized_(false) { +CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock) + : session_(NULL), + policy_engine_(NULL), + session_id_(session_id), + initialized_(false), + renew_with_client_id_(false) { if (NULL == clock) { LOGE("CdmLicense::CdmLicense: clock parameter not provided"); return; @@ -144,6 +151,14 @@ CdmLicense::~CdmLicense() {} bool CdmLicense::Init(const std::string& token, CryptoSession* session, PolicyEngine* policy_engine) { + if (clock_.get() == NULL) { + LOGE("CdmLicense::Init: clock parameter not provided"); + return false; + } + if (session_id_.empty()) { + LOGE("CdmLicense::Init: empty session id provided"); + return false; + } if (token.size() == 0) { LOGE("CdmLicense::Init: empty token provided"); return false; @@ -165,25 +180,27 @@ bool CdmLicense::Init(const std::string& token, CryptoSession* session, CdmResponseType CdmLicense::PrepareKeyRequest( const InitializationData& init_data, const CdmLicenseType license_type, - const CdmAppParameterMap& app_parameters, const CdmSessionId& session_id, - CdmKeyMessage* signed_request, std::string* server_url) { + const CdmAppParameterMap& app_parameters, CdmKeyMessage* signed_request, + std::string* server_url) { if (!initialized_) { LOGE("CdmLicense::PrepareKeyRequest: not initialized"); return LICENSE_PARSER_NOT_INITIALIZED_4; } + if (init_data.IsEmpty() && stored_init_data_.get()) { + InitializationData restored_init_data = *stored_init_data_; + stored_init_data_.reset(); + return PrepareKeyRequest(restored_init_data, license_type, app_parameters, + signed_request, server_url); + } if (!init_data.is_supported()) { LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)", init_data.type().c_str()); return INVALID_PARAMETERS_LIC_3; } - if (init_data.IsEmpty() && stored_init_data_.empty()) { + if (init_data.IsEmpty()) { LOGE("CdmLicense::PrepareKeyRequest: empty init data provided"); return INVALID_PARAMETERS_LIC_4; } - if (session_id.empty()) { - LOGE("CdmLicense::PrepareKeyRequest: empty session id provided"); - return INVALID_PARAMETERS_LIC_5; - } if (!signed_request) { LOGE("CdmLicense::PrepareKeyRequest: no signed request provided"); return INVALID_PARAMETERS_LIC_6; @@ -194,10 +211,10 @@ CdmResponseType CdmLicense::PrepareKeyRequest( } std::string service_certificate; - bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id); + bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id_); if (privacy_mode_enabled) { - if (!GetServiceCertificate(session_id, &service_certificate)) { - stored_init_data_ = init_data.data(); + if (!GetServiceCertificate(&service_certificate)) { + stored_init_data_.reset(new InitializationData(init_data)); return PrepareServiceCertificateRequest(signed_request, server_url) ? KEY_MESSAGE : LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR; @@ -223,8 +240,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest( if (!init_data.IsEmpty()) { cenc_content_id->add_pssh(init_data.data()); - } else if (privacy_mode_enabled && !stored_init_data_.empty()) { - cenc_content_id->add_pssh(stored_init_data_); } else { LOGE("CdmLicense::PrepareKeyRequest: ISO-CENC init data not available"); return CENC_INIT_DATA_UNAVAILABLE; @@ -239,8 +254,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest( if (!init_data.IsEmpty()) { webm_content_id->set_header(init_data.data()); - } else if (privacy_mode_enabled && !stored_init_data_.empty()) { - webm_content_id->set_header(stored_init_data_); } else { LOGE("CdmLicense::PrepareKeyRequest: WebM init data not available"); return WEBM_INIT_DATA_UNAVAILABLE; @@ -304,8 +317,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest( CdmResponseType CdmLicense::PrepareKeyUpdateRequest( bool is_renewal, const CdmAppParameterMap& app_parameters, - const CdmSessionId& session_id, CdmKeyMessage* signed_request, - std::string* server_url) { + CdmKeyMessage* signed_request, std::string* server_url) { if (!initialized_) { LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized"); return LICENSE_PARSER_NOT_INITIALIZED_1; @@ -334,9 +346,9 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( if (renew_with_client_id_) { std::string service_certificate; - bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id); + bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id_); if (privacy_mode_enabled) { - if (!GetServiceCertificate(session_id, &service_certificate)) { + if (!GetServiceCertificate(&service_certificate)) { return PrepareServiceCertificateRequest(signed_request, server_url) ? KEY_MESSAGE : LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR; @@ -447,9 +459,13 @@ CdmResponseType CdmLicense::HandleKeyResponse( case SignedMessage::LICENSE: break; case SignedMessage::SERVICE_CERTIFICATE: { - CdmResponseType status = VerifyAndExtractSignedServiceCertificate( - signed_response.msg(), &service_certificate_); - return status == NO_ERROR ? NEED_KEY : status; + CdmResponseType status = + VerifySignedServiceCertificate(signed_response.msg()); + if (status != NO_ERROR) { + return status; + } + Properties::SetServiceCertificate(session_id_, signed_response.msg()); + return NEED_KEY; } case SignedMessage::ERROR_RESPONSE: return HandleKeyErrorResponse(signed_response); @@ -558,9 +574,13 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse( case SignedMessage::LICENSE: break; case SignedMessage::SERVICE_CERTIFICATE: { - CdmResponseType status = VerifyAndExtractSignedServiceCertificate( - signed_response.msg(), &service_certificate_); - return status == NO_ERROR ? NEED_KEY : status; + CdmResponseType status = + VerifySignedServiceCertificate(signed_response.msg()); + if (status != NO_ERROR) { + return status; + } + Properties::SetServiceCertificate(session_id_, signed_response.msg()); + return NEED_KEY; } case SignedMessage::ERROR_RESPONSE: return HandleKeyErrorResponse(signed_response); @@ -1067,19 +1087,14 @@ CdmResponseType CdmLicense::PrepareClientId( return NO_ERROR; } -bool CdmLicense::GetServiceCertificate(const CdmSessionId& session_id, - std::string* service_certificate) { +bool CdmLicense::GetServiceCertificate(std::string* service_certificate) { std::string signed_service_certificate; - if (!Properties::GetServiceCertificate(session_id, - &signed_service_certificate) || - signed_service_certificate.empty() || - NO_ERROR != VerifyAndExtractSignedServiceCertificate( - signed_service_certificate, service_certificate)) { - *service_certificate = service_certificate_; - } - - if (service_certificate->size() > 0) return true; - return false; + return Properties::GetServiceCertificate(session_id_, + &signed_service_certificate) && + !signed_service_certificate.empty() && + NO_ERROR == VerifyAndExtractSignedServiceCertificate( + signed_service_certificate, service_certificate) && + !service_certificate->empty(); } template diff --git a/libwvdrmengine/cdm/core/src/properties.cpp b/libwvdrmengine/cdm/core/src/properties.cpp index 3983bf16..0363b61e 100644 --- a/libwvdrmengine/cdm/core/src/properties.cpp +++ b/libwvdrmengine/cdm/core/src/properties.cpp @@ -17,13 +17,13 @@ bool Properties::security_level_path_backward_compatibility_support_; scoped_ptr Properties::session_property_set_; bool Properties::AddSessionPropertySet( - const CdmSessionId& session_id, const CdmClientPropertySet* property_set) { + const CdmSessionId& session_id, CdmClientPropertySet* property_set) { if (NULL == session_property_set_.get()) { return false; } std::pair result = session_property_set_->insert( - std::pair( + std::pair( session_id, property_set)); return result.second; } @@ -35,10 +35,10 @@ bool Properties::RemoveSessionPropertySet(const CdmSessionId& session_id) { return (1 == session_property_set_->erase(session_id)); } -const CdmClientPropertySet* Properties::GetCdmClientPropertySet( +CdmClientPropertySet* Properties::GetCdmClientPropertySet( const CdmSessionId& session_id) { if (NULL != session_property_set_.get()) { - CdmClientPropertySetMap::const_iterator it = + CdmClientPropertySetMap::iterator it = session_property_set_->find(session_id); if (it != session_property_set_->end()) { return it->second; @@ -69,6 +69,17 @@ bool Properties::GetServiceCertificate(const CdmSessionId& session_id, return true; } +bool Properties::SetServiceCertificate(const CdmSessionId& session_id, + const std::string& service_certificate) { + CdmClientPropertySet* property_set = + GetCdmClientPropertySet(session_id); + if (NULL == property_set) { + return false; + } + property_set->set_service_certificate(service_certificate); + return true; +} + bool Properties::UsePrivacyMode(const CdmSessionId& session_id) { const CdmClientPropertySet* property_set = GetCdmClientPropertySet(session_id); diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index 58b97a14..785cb0d6 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -116,6 +116,9 @@ class MockPolicyEngine : public PolicyEngine { class MockCdmLicense : public CdmLicense { public: + MockCdmLicense(const CdmSessionId& session_id) + : CdmLicense(session_id) {} + MOCK_METHOD3(Init, bool(const std::string&, CryptoSession*, PolicyEngine*)); }; @@ -135,7 +138,7 @@ class CdmSessionTest : public ::testing::Test { virtual void SetUp() { cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL, NULL)); // Inject testing mocks. - license_parser_ = new MockCdmLicense(); + license_parser_ = new MockCdmLicense(cdm_session_->session_id()); cdm_session_->set_license_parser(license_parser_); crypto_session_ = new MockCryptoSession(); cdm_session_->set_crypto_session(crypto_session_); diff --git a/libwvdrmengine/cdm/core/test/license_unittest.cpp b/libwvdrmengine/cdm/core/test/license_unittest.cpp index 0227a234..ababf2a5 100644 --- a/libwvdrmengine/cdm/core/test/license_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_unittest.cpp @@ -142,7 +142,7 @@ class CdmLicenseTest : public ::testing::Test { } void CreateCdmLicense() { - cdm_license_ = new CdmLicense(clock_); + cdm_license_ = new CdmLicense(kCdmSessionId, clock_); clock_ = NULL; } @@ -157,7 +157,7 @@ TEST_F(CdmLicenseTest, InitSuccess) { EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); CreateCdmLicense(); - ASSERT_TRUE(cdm_license_->Init(kToken, crypto_session_, policy_engine_)); + EXPECT_TRUE(cdm_license_->Init(kToken, crypto_session_, policy_engine_)); } TEST_F(CdmLicenseTest, InitFail_EmptyToken) { @@ -210,7 +210,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { Properties::set_use_certificates_as_identification(true); std::string server_url; EXPECT_TRUE(cdm_license_->PrepareKeyRequest( - *init_data_, kLicenseTypeStreaming, app_parameters, kCdmSessionId, + *init_data_, kLicenseTypeStreaming, app_parameters, &signed_request, &server_url)); EXPECT_TRUE(!signed_request.empty()); diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 3c573c99..d77d984a 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -314,8 +314,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case INVALID_PARAMETERS_LIC_4: *os << "INVALID_PARAMETERS_LIC_4"; break; - case INVALID_PARAMETERS_LIC_5: *os << "INVALID_PARAMETERS_LIC_5"; - break; case INVALID_PARAMETERS_LIC_6: *os << "INVALID_PARAMETERS_LIC_6"; break; case INVALID_PARAMETERS_LIC_7: *os << "INVALID_PARAMETERS_LIC_7"; @@ -339,6 +337,7 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case EMPTY_LICENSE_REQUEST: *os << "EMPTY_LICENSE_REQUEST"; break; + case DUPLICATE_SESSION_ID_SPECIFIED: *os << "DUPLICATE_SESSION_ID_SPECIFIED"; case LICENSE_RENEWAL_PROHIBITED: *os << "LICENSE_RENEWAL_PROHIBITED"; break; default: @@ -355,6 +354,8 @@ void PrintTo(const enum CdmLicenseType& value, ::std::ostream* os) { break; case kLicenseTypeRelease: *os << "kLicenseTypeRelease"; break; + case kLicenseTypeDeferred: *os << "kLicenseTypeDeferred"; + break; default: *os << "Unknown CdmLicenseType"; break; diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 968d8812..68993bb4 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -198,6 +198,9 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { virtual const std::string& service_certificate() const { return service_certificate_; } + virtual void set_service_certificate(const std::string& cert) { + service_certificate_ = cert; + } virtual bool use_privacy_mode() const { return use_privacy_mode_; } virtual bool is_session_sharing_enabled() const { return is_session_sharing_enabled_; @@ -211,9 +214,6 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { security_level_ = security_level; } } - void set_service_certificate(const std::string& service_certificate) { - service_certificate_ = service_certificate; - } void set_use_privacy_mode(bool use_privacy_mode) { use_privacy_mode_ = use_privacy_mode; } diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 844d635c..377bc082 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -457,6 +457,9 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { virtual const std::string& service_certificate() const { return service_certificate_; } + virtual void set_service_certificate(const std::string& service_certificate) { + service_certificate_ = service_certificate; + } virtual bool use_privacy_mode() const { return use_privacy_mode_; } virtual bool is_session_sharing_enabled() const { return is_session_sharing_enabled_; @@ -470,9 +473,6 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { security_level_ = security_level; } } - void set_service_certificate(const std::string& service_certificate) { - service_certificate_ = service_certificate; - } void set_use_privacy_mode(bool use_privacy_mode) { use_privacy_mode_ = use_privacy_mode; } diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index c13e1c55..ac1b3a7e 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -164,9 +164,8 @@ enum { kLicenseParserNotInitialized4 = ERROR_DRM_VENDOR_MIN + 149, kInvalidParametersLic3 = ERROR_DRM_VENDOR_MIN + 150, kInvalidParametersLic4 = ERROR_DRM_VENDOR_MIN + 151, - kInvalidParametersLic5 = ERROR_DRM_VENDOR_MIN + 152, - kInvalidParametersLic6 = ERROR_DRM_VENDOR_MIN + 153, - kInvalidParametersLic7 = ERROR_DRM_VENDOR_MIN + 154, + kInvalidParametersLic6 = ERROR_DRM_VENDOR_MIN + 152, + kInvalidParametersLic7 = ERROR_DRM_VENDOR_MIN + 153, kLicenseRequestServiceCertificateGenerationError = ERROR_DRM_VENDOR_MIN + 155, kCencInitDataUnavailable = ERROR_DRM_VENDOR_MIN + 156, kPrepareCencContentIdFailed = ERROR_DRM_VENDOR_MIN + 157, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index 546e2cce..8ef2d041 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -317,8 +317,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kInvalidParametersLic3; case wvcdm::INVALID_PARAMETERS_LIC_4: return kInvalidParametersLic4; - case wvcdm::INVALID_PARAMETERS_LIC_5: - return kInvalidParametersLic5; case wvcdm::INVALID_PARAMETERS_LIC_6: return kInvalidParametersLic6; case wvcdm::INVALID_PARAMETERS_LIC_7: @@ -347,10 +345,12 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kLicenseRenewalProhibited; case wvcdm::UNKNOWN_ERROR: return android::ERROR_DRM_UNKNOWN; - case wvcdm::UNUSED_1: - return android::UNKNOWN_ERROR; case wvcdm::SECURE_BUFFER_REQUIRED: return android::ERROR_DRM_CANNOT_HANDLE; + case wvcdm::UNUSED_1: + case wvcdm::UNUSED_2: + case wvcdm::UNUSED_3: + return android::UNKNOWN_ERROR; } // Return here instead of as a default case so that the compiler will warn diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index b880b442..bd56be53 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -210,7 +210,8 @@ class WVDrmPlugin : public android::DrmPlugin, return mServiceCertificate; } - void set_service_certificate(const std::string& serviceCertificate) { + virtual void set_service_certificate( + const std::string& serviceCertificate) { mServiceCertificate = serviceCertificate; }