diff --git a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h index 7e9aca48..589a60cc 100644 --- a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h +++ b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h @@ -17,10 +17,6 @@ class CdmClientPropertySet { 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 const std::string& device_provisioning_service_certificate() const - = 0; - virtual void set_device_provisioning_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 1d841f39..ed56566c 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -16,6 +16,7 @@ #include "oemcrypto_adapter.h" #include "scoped_ptr.h" #include "timer_metric.h" +#include "service_certificate.h" #include "wv_cdm_constants.h" #include "wv_cdm_types.h" @@ -38,21 +39,31 @@ class CdmEngine { CdmEngine(FileSystem* file_system, const std::string& spoid = EMPTY_SPOID); virtual ~CdmEngine(); + // Set service certificate for all sessions under this CDM/CdmEngine. + // Setting to the empty string is OK. If the License Service certificate is + // empty and privacy mode is true, the certificate will be fetched from + // the server before the first license request. + virtual CdmResponseType SetServiceCertificate( + const std::string& certificate); + // Session related methods - virtual CdmResponseType OpenSession(const CdmKeySystem& key_system, - CdmClientPropertySet* property_set, - const CdmSessionId& forced_session_id, - WvCdmEventListener* event_listener); - virtual CdmResponseType OpenSession(const CdmKeySystem& key_system, - CdmClientPropertySet* property_set, - WvCdmEventListener* event_listener, - CdmSessionId* session_id); + virtual CdmResponseType OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + const CdmSessionId& forced_session_id, + WvCdmEventListener* event_listener); + + virtual CdmResponseType OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener, CdmSessionId* session_id); + virtual CdmResponseType CloseSession(const CdmSessionId& session_id); + virtual bool IsOpenSession(const CdmSessionId& session_id); - virtual CdmResponseType OpenKeySetSession(const CdmKeySetId& key_set_id, - CdmClientPropertySet* property_set, - WvCdmEventListener* event_listener); + virtual CdmResponseType OpenKeySetSession( + const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener); + virtual CdmResponseType CloseKeySetSession(const CdmKeySetId& key_set_id); // License related methods @@ -249,11 +260,10 @@ class CdmEngine { private: // private methods - CdmResponseType OpenSession(const CdmKeySystem& key_system, - CdmClientPropertySet* property_set, - WvCdmEventListener* event_listener, - const CdmSessionId* forced_session_id, - CdmSessionId* session_id); + CdmResponseType OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener, const CdmSessionId* forced_session_id, + CdmSessionId* session_id); void DeleteAllUsageReportsUponFactoryReset(); bool ValidateKeySystem(const CdmKeySystem& key_system); @@ -290,6 +300,12 @@ class CdmEngine { static bool seeded_; + // Service certificate for license server and provisioning server. + // It is initially empty. If left empty, the operations that + // require them (getting provider_id, encrypting ClientIdentification) + // are not performed. + ServiceCertificate service_certificate_; + // usage related variables scoped_ptr usage_session_; scoped_ptr usage_property_set_; diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 0b3c97ee..8b46c298 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -22,6 +22,7 @@ namespace wvcdm { class CdmClientPropertySet; +class ServiceCertificate; class WvCdmEventListener; class UsageTableHeader; @@ -45,7 +46,8 @@ class CdmSession { // |forced_session_id| is caller owned and may be null. // |event_listener| is caller owned, may be null, but must be in scope // as long as the session is in scope. - virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set, + virtual CdmResponseType Init(ServiceCertificate* service_certificate, + CdmClientPropertySet* cdm_client_property_set, const CdmSessionId* forced_session_id, WvCdmEventListener* event_listener); diff --git a/libwvdrmengine/cdm/core/include/certificate_provisioning.h b/libwvdrmengine/cdm/core/include/certificate_provisioning.h index 8ccfca6e..141cb7dc 100644 --- a/libwvdrmengine/cdm/core/include/certificate_provisioning.h +++ b/libwvdrmengine/cdm/core/include/certificate_provisioning.h @@ -7,31 +7,37 @@ #include "crypto_session.h" #include "metrics_collections.h" +#include "license_protocol.pb.h" #include "oemcrypto_adapter.h" -#include "service_certificate.h" +#include "scoped_ptr.h" #include "wv_cdm_types.h" namespace wvcdm { +class CdmClientPropertySet; class CdmSession; class FileSystem; +class ServiceCertificate; class CertificateProvisioning { public: - CertificateProvisioning(metrics::CryptoMetrics* metrics) : + explicit CertificateProvisioning(metrics::CryptoMetrics* metrics, + ServiceCertificate* service_certificate) : crypto_session_(metrics), cert_type_(kCertificateWidevine), - service_certificate_(NULL) {}; + service_certificate_(service_certificate) {} + ~CertificateProvisioning() {}; - // Provisioning related methods - CdmResponseType GetProvisioningRequest(SecurityLevel requested_security_level, - CdmCertificateType cert_type, - const std::string& cert_authority, - const std::string& origin, - const std::string& spoid, - CdmProvisioningRequest* request, - std::string* default_url); + // Construct a valid provisioning request. + // The request will be sent to the provisioning server. + CdmResponseType GetProvisioningRequest( + SecurityLevel requested_security_level, CdmCertificateType cert_type, + const std::string& cert_authority, const std::string& origin, + const std::string& spoid, CdmProvisioningRequest* request, + std::string* default_url); + + // Process the provisioning response. CdmResponseType HandleProvisioningResponse( FileSystem* file_system, const CdmProvisioningResponse& response, @@ -53,6 +59,7 @@ class CertificateProvisioning { bool ParseJsonResponse(const CdmProvisioningResponse& json_str, const std::string& start_substr, const std::string& end_substr, std::string* result); + CryptoSession crypto_session_; CdmCertificateType cert_type_; ServiceCertificate* service_certificate_; diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 0cb57748..5f8afb11 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -8,7 +8,6 @@ #include "initialization_data.h" #include "license_protocol.pb.h" #include "scoped_ptr.h" -#include "service_certificate.h" #include "wv_cdm_types.h" namespace video_widevine { @@ -22,6 +21,7 @@ class Clock; class CryptoSession; class PolicyEngine; class CdmSession; +class ServiceCertificate; class CdmLicense { public: @@ -29,8 +29,9 @@ class CdmLicense { virtual ~CdmLicense(); virtual bool Init( - const std::string& client_token, CdmClientTokenType client_token_type, - CryptoSession* session, PolicyEngine* policy_engine); + ServiceCertificate* service_certificate, const std::string& client_token, + CdmClientTokenType client_token_type, CryptoSession* session, + PolicyEngine* policy_engine); virtual CdmResponseType PrepareKeyRequest( const InitializationData& init_data, CdmLicenseType license_type, @@ -103,7 +104,7 @@ class CdmLicense { bool is_offline_; // Used to encrypt ClientIdentification message - scoped_ptr service_certificate_; + ServiceCertificate* service_certificate_; // Used for certificate based licensing CdmKeyMessage key_request_; diff --git a/libwvdrmengine/cdm/core/include/service_certificate.h b/libwvdrmengine/cdm/core/include/service_certificate.h index 43e95a3c..1aa2193d 100644 --- a/libwvdrmengine/cdm/core/include/service_certificate.h +++ b/libwvdrmengine/cdm/core/include/service_certificate.h @@ -5,12 +5,11 @@ // Service Certificates are used to encrypt the ClientIdentification message // that is part of Device Provisioning, License, Renewal, and Release requests. -// They may be supplied by the application, or a default certificate may be -// configured into the CDM, or the CDM may send a Service Certificate Request -// to the target server to get one. Separate certificates are maintained for -// the License and Provisioning Servers (the default service certificates -// are currently identical for both servers). Once the Service Certificates are -// established for the session, they should not change. +// It also supplies a provider_id setting used in device provisioning. +// Service Certificates are typically supplied by the application. If one +// is not supplied and privacy mode is enabled, the CDM will send a Service +// Certificate Request to the target server to get one. Once the Service +// Certificate is established for the session, it should not change. #include "license_protocol.pb.h" #include "wv_cdm_types.h" @@ -26,51 +25,56 @@ class CryptoSession; class ServiceCertificate { public: - ServiceCertificate(); - virtual ~ServiceCertificate(); + ServiceCertificate() {} + virtual ~ServiceCertificate() {} - virtual bool Init(const CdmSessionId& session_id, CryptoSession* session); + // Set up a new service certificate. + // Accept a serialized video_widevine::SignedDrmDeviceCertificate message. + virtual CdmResponseType Init(const std::string& signed_certificate); - virtual bool IsRequired(); - virtual bool IsAvailable(); - virtual bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request); + // Initialize the service certificate. + // Set the certificate with no certificate and provider ID. + virtual void Clear(); - virtual CdmResponseType VerifyAndSet( - const std::string& signed_service_certificate); + // Current state of certificate. + // If !HasCertificate() and privacy mode is enabled, then should call + // PrepareRequest() and pass the request to the license server. + virtual bool HasCertificate() { return !certificate_.empty(); } + virtual bool HasProviderId() { return !provider_id_.empty(); } + virtual const std::string& provider_id() { return provider_id_; } + // Encrypt the ClientIdentification message for a provisioning or + // licensing request. Encryption is performed using the current + // service certificate. Return a failure if the service certificate is + // not present, not valid, or if some other error occurs. + // The routine should not be called if privacy mode is off or if the + // certificate is empty. virtual CdmResponseType EncryptClientId( + CryptoSession* crypto_session, const video_widevine::ClientIdentification* clear_client_id, video_widevine::EncryptedClientIdentification* encrypted_client_id); - static CdmResponseType VerifySignedServiceCertificate( - const std::string& signed_certificate) { - bool has_provider_id; - return VerifyAndExtractFromSignedCertificate(signed_certificate, NULL, - &has_provider_id, NULL); - } + // Construct service certificate request. + virtual bool PrepareRequest(CdmKeyMessage* signed_request); + + // Parse service certificate response and make it usable. + virtual CdmResponseType HandleResponse( + const std::string& signed_respnse); private: - // Take a signed certificate, parse it, and verify it. - // If a pointer to a string object is passed in, the certificate - // will be copied to it. - static CdmResponseType VerifyAndExtractFromSignedCertificate( - const std::string& signed_service_certificate, - std::string* service_certificate, bool* has_provider_id, - std::string* provider_id); + // Verify the signature on the signed service certificate. + // Extract and save the certificate and provider_id. + // Expected format: serialized video_widevine::SignedDrmDeviceCertificate. + virtual CdmResponseType VerifyAndExtract( + const std::string& raw_certificate); - virtual bool SetupServiceCertificate(); - - CryptoSession* crypto_session_; - CdmSessionId session_id_; - bool privacy_mode_enabled_; - bool valid_; - bool initialized_; + // True while waiting for response to service certificate request. + bool fetch_in_progress_; // Certificate, verified and extracted from signed message. std::string certificate_; // Provider ID, extracted from certificate message. - bool has_provider_id_; std::string provider_id_; CORE_DISALLOW_COPY_AND_ASSIGN(ServiceCertificate); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 8179b1c8..7165b0cb 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -247,7 +247,7 @@ enum CdmResponseType { INVALID_PARAMETERS_ENG_14, INVALID_PARAMETERS_ENG_15, /* 205 */ INVALID_PARAMETERS_ENG_16, - DEVICE_CERTIFICATE_ERROR_5, + UNUSED_7, /* previously DEVICE_CERTIFICATE_ERROR_5 */ CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1, CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2, LICENSING_CLIENT_TOKEN_ERROR_1, /* 210 */ diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 48b784ab..80d66dd4 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -42,11 +42,6 @@ class UsagePropertySet : public CdmClientPropertySet { 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 const std::string& device_provisioning_service_certificate() const { - return empty_; - } - virtual void set_device_provisioning_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 */) {} @@ -102,27 +97,28 @@ CdmEngine::~CdmEngine() { M_RECORD(&metrics_, cdm_engine_life_span_, life_span_.AsMs()); } -CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, - CdmClientPropertySet* property_set, - const CdmSessionId& forced_session_id, - WvCdmEventListener* event_listener) { +CdmResponseType CdmEngine::SetServiceCertificate( + const std::string& certificate) { + return service_certificate_.Init(certificate); +} + +CdmResponseType CdmEngine::OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + const CdmSessionId& forced_session_id, WvCdmEventListener* event_listener) { return OpenSession(key_system, property_set, event_listener, &forced_session_id, NULL); } -CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, - CdmClientPropertySet* property_set, - WvCdmEventListener* event_listener, - CdmSessionId* session_id) { - return OpenSession(key_system, property_set, event_listener, NULL, - session_id); +CdmResponseType CdmEngine::OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener, CdmSessionId* session_id) { + return OpenSession(key_system, property_set, event_listener, NULL, session_id); } -CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, - CdmClientPropertySet* property_set, - WvCdmEventListener* event_listener, - const CdmSessionId* forced_session_id, - CdmSessionId* session_id) { +CdmResponseType CdmEngine::OpenSession( + const CdmKeySystem& key_system, CdmClientPropertySet* property_set, + WvCdmEventListener* event_listener, const CdmSessionId* forced_session_id, + CdmSessionId* session_id) { LOGI("CdmEngine::OpenSession"); if (!ValidateKeySystem(key_system)) { @@ -145,8 +141,8 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system, scoped_ptr new_session(new CdmSession(file_system_, metrics_.AddSession())); - CdmResponseType sts = new_session->Init(property_set, forced_session_id, - event_listener); + CdmResponseType sts = new_session->Init(&service_certificate_, property_set, + forced_session_id, event_listener); if (sts != NO_ERROR) { if (sts == NEED_PROVISIONING) { cert_provisioning_requested_security_level_ = @@ -547,6 +543,8 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, return UNKNOWN_ERROR; } } else if (query_token == QUERY_KEY_DEVICE_ID) { + // TODO(gmorgan): this should not be performed before device is provisioned + // (except if keybox provisioned). std::string deviceId; bool got_id = crypto_session.GetExternalDeviceUniqueId(&deviceId); metrics_.GetCryptoMetrics()->crypto_session_get_device_unique_id_ @@ -558,6 +556,8 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, *query_response = deviceId; } else if (query_token == QUERY_KEY_SYSTEM_ID) { + // TODO(gmorgan): this should not be performed before device is provisioned + // (except if keybox provisioned). uint32_t system_id; bool got_id = crypto_session.GetSystemId(&system_id); if (!got_id) { @@ -569,6 +569,8 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, system_id_stream << system_id; *query_response = system_id_stream.str(); } else if (query_token == QUERY_KEY_PROVISIONING_ID) { + // TODO(gmorgan): this should not be performed before device is provisioned + // (except if keybox provisioned). std::string provisioning_id; if (!crypto_session.GetProvisioningId(&provisioning_id)) { LOGW("CdmEngine::QueryStatus: GetProvisioningId failed"); @@ -798,7 +800,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest( if (NULL == cert_provisioning_.get()) { cert_provisioning_.reset( - new CertificateProvisioning(metrics_.GetCryptoMetrics())); + new CertificateProvisioning(metrics_.GetCryptoMetrics(), + &service_certificate_)); } CdmResponseType ret = cert_provisioning_->GetProvisioningRequest( cert_provisioning_requested_security_level_, cert_type, cert_authority, @@ -824,14 +827,14 @@ CdmResponseType CdmEngine::HandleProvisioningResponse( cert_provisioning_.reset(NULL); return EMPTY_PROVISIONING_RESPONSE; } - if (NULL == cert) { + if (cert == NULL) { LOGE( "CdmEngine::HandleProvisioningResponse: invalid certificate " "destination"); cert_provisioning_.reset(NULL); return INVALID_PROVISIONING_PARAMETERS_1; } - if (NULL == wrapped_key) { + if (wrapped_key == NULL) { LOGE("CdmEngine::HandleProvisioningResponse: invalid wrapped key " "destination"); cert_provisioning_.reset(NULL); diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 18020498..7954cfcd 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -65,12 +65,13 @@ CdmSession::~CdmSession() { CdmResponseType CdmSession::Init( CdmClientPropertySet* cdm_client_property_set) { - return Init(cdm_client_property_set, NULL, NULL); + return Init(NULL, cdm_client_property_set, NULL, NULL); } -CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, - const CdmSessionId* forced_session_id, - WvCdmEventListener* event_listener) { +CdmResponseType CdmSession::Init( + ServiceCertificate* service_certificate, + CdmClientPropertySet* cdm_client_property_set, + const CdmSessionId* forced_session_id, WvCdmEventListener* event_listener) { if (initialized_) { LOGE("CdmSession::Init: Failed due to previous initialization"); return SESSION_INIT_ERROR_2; @@ -112,11 +113,13 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, // Otherwise, try to fetch device certificate. If not successful and // provisioning is supported, return NEED_PROVISIONING. Otherwise, return // an error. + // client_token and client_token_type are determined here; they are needed + // to initialize the license parser. std::string client_token; CdmClientTokenType client_token_type = crypto_session_->GetPreProvisionTokenType(); if ((client_token_type == kClientTokenKeybox) && - (!Properties::use_certificates_as_identification())) { + !Properties::use_certificates_as_identification()) { // Keybox is client token. LOGW("CdmSession::Init: Properties::use_certificates_as_identification() " "is not set - using Keybox for license requests (not recommended)."); @@ -147,6 +150,9 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, client_token_type = kClientTokenDrmCert; } + // Session is provisioned with certificate needed to construct + // license request (or with keybox). + if (forced_session_id) { key_set_id_ = *forced_session_id; } else { @@ -172,8 +178,9 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, policy_engine_.reset(new PolicyEngine( session_id_, event_listener, crypto_session_.get())); - if (!license_parser_->Init(client_token, client_token_type, - crypto_session_.get(), policy_engine_.get())) + if (!license_parser_->Init( + service_certificate, client_token, client_token_type, + crypto_session_.get(), policy_engine_.get())) return LICENSE_PARSER_INIT_ERROR; license_received_ = false; diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index 0deb8bdc..bcd5868a 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -6,6 +6,7 @@ #include "license_protocol.pb.h" #include "log.h" #include "properties.h" +#include "service_certificate.h" #include "string_conversions.h" #include "wv_cdm_constants.h" @@ -86,16 +87,17 @@ bool CertificateProvisioning::SetSpoidParameter( "passed to method."); return false; } - if (!spoid.empty()) { // Use the SPOID that has been pre-provided request->set_spoid(spoid); - } else if (Properties::UseProviderIdInProvisioningRequest() && - false /* TODO(gmorgan): use provider ID. */) { - // Use the provider ID from the service certificate - - // TODO(gmorgan): use provider ID. - // request->set_provider_id(???); + } else if (Properties::UseProviderIdInProvisioningRequest()) { + if (service_certificate_->HasProviderId()) { + request->set_provider_id(service_certificate_->provider_id()); + } else { + LOGE("CertificateProvisioning::SetSpoidParameter: Failure getting " + "provider ID"); + return false; + } } else if (origin != EMPTY_ORIGIN) { // Legacy behavior - Concatenate Unique ID with Origin std::string device_unique_id; @@ -130,8 +132,8 @@ SignedProvisioningMessage::ProtocolVersion CdmResponseType CertificateProvisioning::GetProvisioningRequest( SecurityLevel requested_security_level, CdmCertificateType cert_type, const std::string& cert_authority, const std::string& origin, - const std::string& spoid, - CdmProvisioningRequest* request, std::string* default_url) { + const std::string& spoid, CdmProvisioningRequest* request, + std::string* default_url) { if (!default_url) { LOGE("GetProvisioningRequest: pointer for returning URL is NULL"); return CERT_PROVISIONING_REQUEST_ERROR_1; @@ -139,13 +141,13 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest( default_url->assign(kProvisioningServerUrl); - CdmResponseType sts = crypto_session_.Open(requested_security_level); - if (NO_ERROR != sts) { + CdmResponseType status = crypto_session_.Open(requested_security_level); + if (NO_ERROR != status) { LOGE("GetProvisioningRequest: fails to create a crypto session"); - return sts; + return status; } - // Prepares device provisioning request. + // Prepare device provisioning request. ProvisioningRequest provisioning_request; std::string token; ClientIdentification* client_id = provisioning_request.mutable_client_id(); diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index d86778bc..4ceaf957 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -292,6 +292,8 @@ bool CryptoSession::GetInternalDeviceUniqueId(std::string* device_id) { if (pre_provision_token_type_ == kClientTokenOemCert) { return GetTokenFromOemCert(device_id); } else { + // Device's authentication root is a keybox. + // Or not. If no keybox, let the OEMCrypto call fail. std::vector id; size_t id_length = 32; id.resize(id_length); @@ -348,6 +350,8 @@ bool CryptoSession::GetApiVersion(uint32_t* version) { } bool CryptoSession::GetSystemId(uint32_t* system_id) { + // TODO(gmorgan): if Prov 3.0, get system ID from DRM Device Cert. If + // DRM Device Cert is not available (e.g., not yet provisioned), return false. if (!system_id) { LOGE("CryptoSession::GetSystemId: No buffer passed to method."); return false; @@ -496,6 +500,7 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert, bool CryptoSession::GetProvisioningId(std::string* provisioning_id) { + // TODO(gmorgan): if Prov 3.0, return false (no "provisioning ID" available). if (!provisioning_id) { LOGE("CryptoSession::GetProvisioningId : No buffer passed to method."); return false; diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index ec18da19..771f97ef 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -15,6 +15,7 @@ #include "policy_engine.h" #include "privacy_crypto.h" #include "properties.h" +#include "service_certificate.h" #include "string_conversions.h" #include "wv_cdm_constants.h" @@ -145,8 +146,9 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock) CdmLicense::~CdmLicense() {} bool CdmLicense::Init( - const std::string& client_token, CdmClientTokenType client_token_type, - CryptoSession* session, PolicyEngine* policy_engine) { + ServiceCertificate* service_certificate, const std::string& client_token, + CdmClientTokenType client_token_type, CryptoSession* session, + PolicyEngine* policy_engine) { if (clock_.get() == NULL) { LOGE("CdmLicense::Init: clock parameter not provided"); return false; @@ -168,19 +170,11 @@ bool CdmLicense::Init( return false; } + service_certificate_ = service_certificate; client_token_ = client_token; client_token_type_ = client_token_type; crypto_session_ = session; policy_engine_ = policy_engine; - service_certificate_.reset(new ServiceCertificate()); - if (service_certificate_.get() == NULL) { - LOGE("CdmLicense::Init: creation of service_certificate failed"); - return false; - } - if (!service_certificate_->Init(session_id_, crypto_session_)) { - LOGE("CdmLicense::Init: init of service_certificate failed"); - return false; - } initialized_ = true; return true; } @@ -217,14 +211,16 @@ CdmResponseType CdmLicense::PrepareKeyRequest( return INVALID_PARAMETERS_LIC_7; } - if (service_certificate_->IsRequired() && - !service_certificate_->IsAvailable()) { + // If privacy mode and no service certificate, initiate a + // service certificate request. + if (Properties::UsePrivacyMode(session_id_) && + !service_certificate_->HasCertificate()) { stored_init_data_.reset(new InitializationData(init_data)); *server_url = server_url_; - if (service_certificate_->PrepareServiceCertificateRequest(signed_request)) + if (service_certificate_->PrepareRequest(signed_request)) { return KEY_MESSAGE; - else - return LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR; + } + return LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR; } std::string request_id; @@ -309,14 +305,13 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( } if (renew_with_client_id_) { - if (service_certificate_->IsRequired() && - !service_certificate_->IsAvailable()) { + if (Properties::UsePrivacyMode(session_id_) && + !service_certificate_->HasCertificate()) { *server_url = server_url_; - if (service_certificate_-> - PrepareServiceCertificateRequest(signed_request)) + if (service_certificate_->PrepareRequest(signed_request)) { return KEY_MESSAGE; - else - return LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR; + } + return LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR; } } @@ -439,8 +434,8 @@ CdmResponseType CdmLicense::HandleKeyResponse( case SignedMessage::LICENSE: break; case SignedMessage::SERVICE_CERTIFICATE: { - CdmResponseType status = - service_certificate_->VerifyAndSet(signed_response.msg()); + CdmResponseType status; + status = service_certificate_->HandleResponse(signed_response.msg()); if (status != NO_ERROR) { return status; } @@ -558,8 +553,8 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse( case SignedMessage::LICENSE: break; case SignedMessage::SERVICE_CERTIFICATE: { - CdmResponseType status = - service_certificate_->VerifyAndSet(signed_response.msg()); + CdmResponseType status; + status = service_certificate_->HandleResponse(signed_response.msg()); if (status != NO_ERROR) { return status; } @@ -1027,16 +1022,15 @@ CdmResponseType CdmLicense::PrepareClientId( if (crypto_session_->GetSrmVersion(&srm_version)) client_capabilities->set_srm_version(srm_version); - if (service_certificate_->IsRequired()) { - if (!service_certificate_->IsAvailable()) { + if (Properties::UsePrivacyMode(session_id_)) { + if (!service_certificate_->HasCertificate()) { LOGE("CdmLicense::PrepareClientId: Service Certificate not staged"); return LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR; } - EncryptedClientIdentification* encrypted_client_id = license_request->mutable_encrypted_client_id(); CdmResponseType status; - status = service_certificate_->EncryptClientId(client_id, + status = service_certificate_->EncryptClientId(crypto_session_, client_id, encrypted_client_id); if (NO_ERROR == status) { license_request->clear_client_id(); diff --git a/libwvdrmengine/cdm/core/src/properties.cpp b/libwvdrmengine/cdm/core/src/properties.cpp index ca3fe0ca..1ba25630 100644 --- a/libwvdrmengine/cdm/core/src/properties.cpp +++ b/libwvdrmengine/cdm/core/src/properties.cpp @@ -62,7 +62,7 @@ bool Properties::GetServiceCertificate(const CdmSessionId& session_id, std::string* service_certificate) { const CdmClientPropertySet* property_set = GetCdmClientPropertySet(session_id); - if (NULL == property_set) { + if (property_set == NULL) { return false; } *service_certificate = property_set->service_certificate(); @@ -73,35 +73,13 @@ bool Properties::SetServiceCertificate(const CdmSessionId& session_id, const std::string& service_certificate) { CdmClientPropertySet* property_set = GetCdmClientPropertySet(session_id); - if (NULL == property_set) { + if (property_set == NULL) { return false; } property_set->set_service_certificate(service_certificate); return true; } -bool Properties::GetDeviceProvisioningServiceCertificate( - const CdmSessionId& session_id, std::string* service_certificate) { - const CdmClientPropertySet* property_set = - GetCdmClientPropertySet(session_id); - if (NULL == property_set) { - return false; - } - *service_certificate = property_set->device_provisioning_service_certificate(); - return true; -} - -bool Properties::SetDeviceProvisioningServiceCertificate( - const CdmSessionId& session_id, const std::string& service_certificate) { - CdmClientPropertySet* property_set = - GetCdmClientPropertySet(session_id); - if (NULL == property_set) { - return false; - } - property_set->set_device_provisioning_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/src/service_certificate.cpp b/libwvdrmengine/cdm/core/src/service_certificate.cpp index bc8d9837..784841b5 100644 --- a/libwvdrmengine/cdm/core/src/service_certificate.cpp +++ b/libwvdrmengine/cdm/core/src/service_certificate.cpp @@ -57,148 +57,26 @@ using video_widevine::EncryptedClientIdentification; using video_widevine::SignedDrmDeviceCertificate; using video_widevine::SignedMessage; -ServiceCertificate::ServiceCertificate() - : crypto_session_(NULL), - valid_(false), - initialized_(false) { +void ServiceCertificate::Clear() { + fetch_in_progress_ = false; certificate_.clear(); + provider_id_.clear(); } -ServiceCertificate::~ServiceCertificate() {} - -bool ServiceCertificate::Init(const CdmSessionId& session_id, - CryptoSession* session) { - if (session_id.empty()) { - LOGE("ServiceCertificate::Init: empty session id provided"); - return false; - } - if (session == NULL) { - LOGE("ServiceCertificate::Init: crypto session not provided"); - return false; - } - session_id_.assign(session_id); - crypto_session_ = session; - privacy_mode_enabled_ = Properties::UsePrivacyMode(session_id_); - SetupServiceCertificate(); - initialized_ = true; - return true; -} - -bool ServiceCertificate::IsRequired() { - return privacy_mode_enabled_; -} - -bool ServiceCertificate::IsAvailable() { - return valid_; -} - -CdmResponseType ServiceCertificate::VerifyAndSet( - const std::string& signed_service_certificate) { - CdmResponseType status; - bool has_provider_id; - status = VerifyAndExtractFromSignedCertificate(signed_service_certificate, - &certificate_, - &has_provider_id, - NULL); - if (status != NO_ERROR) { - LOGE("ServiceCertificate::VerifyAndSet: verify and extract failed with " - "status %d", status); - return status; - } - - Properties::SetServiceCertificate(session_id_, signed_service_certificate); - valid_ = true; - return NO_ERROR; -} - -bool ServiceCertificate::PrepareServiceCertificateRequest( - CdmKeyMessage* signed_request) { - if (!initialized_) { - LOGE("ServiceCertificate::PrepareServiceCertificateRequest: " - "not initialized"); - return false; - } - if (!signed_request) { - LOGE("ServiceCertificate::PrepareServiceCertificateRequest: " - "no signed request provided"); - return false; - } - SignedMessage signed_message; - signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST); - signed_message.SerializeToString(signed_request); - - return true; -} - -CdmResponseType ServiceCertificate::VerifyAndExtractFromSignedCertificate( - const std::string& signed_certificate, std::string* certificate, - bool* /* has_provider_id */, std::string* /* provider_id */) { - SignedDrmDeviceCertificate signed_service_certificate; - if (!signed_service_certificate.ParseFromString(signed_certificate)) { - LOGE( - "ServiceCertificate::VerifyAndExtractFromSignedCertificate: " - "unable to parse signed service certificate"); - return DEVICE_CERTIFICATE_ERROR_1; - } - - RsaPublicKey root_ca_key; - std::string ca_public_key( - reinterpret_cast(&kServiceCertificateCAPublicKey[0]), - sizeof(kServiceCertificateCAPublicKey)); - if (!root_ca_key.Init(ca_public_key)) { - LOGE( - "ServiceCertificate::VerifyAndExtractFromSignedCertificate: public key " - "initialization failed"); - return DEVICE_CERTIFICATE_ERROR_2; - } - - if (!root_ca_key.VerifySignature( - signed_service_certificate.drm_certificate(), - signed_service_certificate.signature())) { - LOGE( - "ServiceCertificate::VerifyAndExtractFromSignedCertificate: service " - "certificate verification failed"); - return DEVICE_CERTIFICATE_ERROR_3; - } - - DrmDeviceCertificate service_certificate; - if (!service_certificate.ParseFromString( - signed_service_certificate.drm_certificate())) { - LOGE( - "ServiceCertificate::VerifyAndExtractFromSignedCertificate: unable to " - "parse retrieved service certificate"); - return DEVICE_CERTIFICATE_ERROR_4; - } - - if (service_certificate.type() != - video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) { - LOGE( - "ServiceCertificate::VerifyAndExtractFromSignedCertificate: " - "certificate not of type service, %d", service_certificate.type()); - return INVALID_DEVICE_CERTIFICATE_TYPE; - } - -#if 0 // TODO(gmorgan): service cert has no provider_id - *has_provider_id = service_certificate.has_provider_id(); - if (*has_provider_id && provider_id != NULL) { - *provider_id = service_certificate.provider_id(); - } else { - return DEVICE_CERTIFICATE_ERROR_5; - } -#endif - - if (certificate != NULL && - !signed_service_certificate.drm_certificate().empty()) { - *certificate = signed_service_certificate.drm_certificate(); - } - return NO_ERROR; +CdmResponseType ServiceCertificate::Init(const std::string& raw_certificate) { + return VerifyAndExtract(raw_certificate); } CdmResponseType ServiceCertificate::EncryptClientId( - const ClientIdentification* clear_client_id, + CryptoSession* crypto_session, const ClientIdentification* clear_client_id, EncryptedClientIdentification* encrypted_client_id) { DrmDeviceCertificate service_certificate; + if (certificate_.empty()) { + LOGE("ServiceCertificate::EncryptClientId: " + "service certificate is not properly initialized"); + return UNKNOWN_ERROR; + } if (!service_certificate.ParseFromString(certificate_)) { LOGE("ServiceCertificate::EncryptClientId: unable to parse retrieved " "service certificate"); @@ -215,14 +93,14 @@ CdmResponseType ServiceCertificate::EncryptClientId( encrypted_client_id->set_service_certificate_serial_number( service_certificate.serial_number()); - std::string iv(KEY_IV_SIZE, 0); // TODO(gmorgan) randomize + std::string iv(KEY_IV_SIZE, 0); std::string key(KEY_SIZE, 0); - if (!crypto_session_->GetRandom(key.size(), - reinterpret_cast(&key[0]))) + if (!crypto_session->GetRandom(key.size(), + reinterpret_cast(&key[0]))) return CLIENT_ID_GENERATE_RANDOM_ERROR; - if (!crypto_session_->GetRandom(iv.size(), - reinterpret_cast(&iv[0]))) + if (!crypto_session->GetRandom(iv.size(), + reinterpret_cast(&iv[0]))) return CLIENT_ID_GENERATE_RANDOM_ERROR; std::string id, enc_id, enc_key; clear_client_id->SerializeToString(&id); @@ -242,38 +120,97 @@ CdmResponseType ServiceCertificate::EncryptClientId( return NO_ERROR; } -bool ServiceCertificate::SetupServiceCertificate() { - std::string signed_certificate; - - valid_ = false; - certificate_.clear(); - - if (!Properties::GetServiceCertificate(session_id_, &signed_certificate)) { - LOGV("ServiceCertificate::SetupServiceCertificate: no signed service " - "certificate set"); - return false; - } - if (signed_certificate.empty()) { - LOGV("ServiceCertificate::SetupServiceCertificate: service certificate " - "empty"); +bool ServiceCertificate::PrepareRequest(CdmKeyMessage* signed_request) { + if (!signed_request) { + LOGE("ServiceCertificate::PrepareRequest: no signed request provided"); return false; } + SignedMessage signed_message; + signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST); + signed_message.SerializeToString(signed_request); - std::string extracted_certificate; - std::string extracted_provider_id; - bool has_provider_id; - if (NO_ERROR != VerifyAndExtractFromSignedCertificate( - signed_certificate, &extracted_certificate, - &has_provider_id, &extracted_provider_id)) { - return false; - } - has_provider_id_ = has_provider_id; - if (has_provider_id_) { - provider_id_ = extracted_provider_id; - } - certificate_ = extracted_certificate; - valid_ = true; + fetch_in_progress_ = true; return true; } +CdmResponseType ServiceCertificate::HandleResponse( + const std::string& signed_response) { + if (!fetch_in_progress_) { + LOGE("ServiceCertificate::HandleResponse: unexpected service " + "certificate response."); + return UNKNOWN_ERROR; + } + + fetch_in_progress_ = false; + CdmResponseType status = VerifyAndExtract(signed_response); + if (status != NO_ERROR) { + return status; + } + return NO_ERROR; +} + +CdmResponseType ServiceCertificate::VerifyAndExtract( + const std::string& raw_certificate) { + if (raw_certificate.empty()) { + Clear(); + return NO_ERROR; + } + // Deserialize and parse raw certificate. + SignedDrmDeviceCertificate signed_service_certificate; + if (!signed_service_certificate.ParseFromString(raw_certificate)) { + LOGE( + "ServiceCertificate::VerifyAndExtract: unable to parse signed " + "service certificate"); + return DEVICE_CERTIFICATE_ERROR_1; + } + + // Set up root key (for verifying signature). + RsaPublicKey root_ca_key; + std::string ca_public_key( + reinterpret_cast(&kServiceCertificateCAPublicKey[0]), + sizeof(kServiceCertificateCAPublicKey)); + if (!root_ca_key.Init(ca_public_key)) { + LOGE( + "ServiceCertificate::VerifyAndExtract: public key initialization " + "failed"); + return DEVICE_CERTIFICATE_ERROR_2; + } + + // Verify the signature. + if (!root_ca_key.VerifySignature( + signed_service_certificate.drm_certificate(), + signed_service_certificate.signature())) { + LOGE( + "ServiceCertificate::VerifyAndExtract: service certificate " + "verification failed"); + return DEVICE_CERTIFICATE_ERROR_3; + } + + // Deserialize and parse actual certificate. + DrmDeviceCertificate service_certificate; + if (!service_certificate.ParseFromString( + signed_service_certificate.drm_certificate())) { + LOGE( + "ServiceCertificate::VerifyAndExtract: unable to parse retrieved " + "service certificate"); + return DEVICE_CERTIFICATE_ERROR_4; + } + + // Verify, extract needed fields. + if (service_certificate.type() != + video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) { + LOGE( + "ServiceCertificate::VerifyAndExtract: certificate not of type " + "service, %d", service_certificate.type()); + return INVALID_DEVICE_CERTIFICATE_TYPE; + } + if (service_certificate.has_provider_id()) { + provider_id_.assign(service_certificate.provider_id()); + } else { + provider_id_.clear(); + } + certificate_.assign(signed_service_certificate.drm_certificate()); + return NO_ERROR; +} + } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp index 5fac4718..ea6ef4ae 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_test.cpp @@ -11,6 +11,7 @@ #include "cdm_engine.h" #include "config_test_env.h" +#include "default_service_certificate.h" #include "initialization_data.h" #include "license_request.h" #include "log.h" @@ -80,6 +81,8 @@ class WvCdmEngineTest : public testing::Test { CdmCertificateType cert_type = kCertificateWidevine; std::string cert_authority; std::string cert, wrapped_key; + ASSERT_EQ(NO_ERROR, cdm_engine_.SetServiceCertificate( + kDefaultServiceCertificate)); CdmResponseType result = NO_ERROR; for (int i = 0; i < 2; i++) { // Retry once if there is a nonce problem. result = cdm_engine_.GetProvisioningRequest( diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index 39875a70..2eafe3a9 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -6,6 +6,7 @@ #include "crypto_key.h" #include "properties.h" #include "scoped_ptr.h" +#include "service_certificate.h" #include "string_conversions.h" #include "test_printers.h" #include "wv_cdm_constants.h" @@ -122,8 +123,8 @@ class MockCdmLicense : public CdmLicense { MockCdmLicense(const CdmSessionId& session_id) : CdmLicense(session_id) {} - MOCK_METHOD4(Init, bool(const std::string&, CdmClientTokenType, - CryptoSession*, PolicyEngine*)); + MOCK_METHOD5(Init, bool(ServiceCertificate*, const std::string&, + CdmClientTokenType, CryptoSession*, PolicyEngine*)); }; } // namespace @@ -140,6 +141,7 @@ using ::testing::StrEq; class CdmSessionTest : public ::testing::Test { protected: virtual void SetUp() { + service_cert_ = new ServiceCertificate; cdm_session_.reset(new CdmSession(NULL, &metrics_)); // Inject testing mocks. license_parser_ = new MockCdmLicense(cdm_session_->session_id()); @@ -165,6 +167,7 @@ class CdmSessionTest : public ::testing::Test { MockCryptoSession* crypto_session_; MockPolicyEngine* policy_engine_; MockDeviceFiles* file_handle_; + ServiceCertificate* service_cert_; }; TEST_F(CdmSessionTest, InitWithBuiltInCertificate) { @@ -186,7 +189,7 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) { .WillOnce(Return(true)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); EXPECT_CALL(*license_parser_, - Init(Eq(kToken), Eq(kClientTokenDrmCert), + Init(NULL, Eq(kToken), Eq(kClientTokenDrmCert), Eq(crypto_session_), Eq(policy_engine_))) .WillOnce(Return(true)); @@ -214,7 +217,7 @@ TEST_F(CdmSessionTest, InitWithCertificate) { .InSequence(crypto_session_seq) .WillOnce(Return(true)); EXPECT_CALL(*license_parser_, - Init(Eq(kToken), Eq(kClientTokenDrmCert), + Init(NULL, Eq(kToken), Eq(kClientTokenDrmCert), Eq(crypto_session_), Eq(policy_engine_))) .WillOnce(Return(true)); @@ -239,7 +242,7 @@ TEST_F(CdmSessionTest, InitWithKeybox) { .WillOnce(Return(kClientTokenKeybox)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); EXPECT_CALL(*license_parser_, - Init(Eq(kToken), Eq(kClientTokenKeybox), + Init(NULL, Eq(kToken), Eq(kClientTokenKeybox), Eq(crypto_session_), Eq(policy_engine_))) .WillOnce(Return(true)); @@ -267,7 +270,7 @@ TEST_F(CdmSessionTest, ReInitFail) { .InSequence(crypto_session_seq) .WillOnce(Return(true)); EXPECT_CALL(*license_parser_, - Init(Eq(kToken), Eq(kClientTokenDrmCert), + Init(NULL, Eq(kToken), Eq(kClientTokenDrmCert), Eq(crypto_session_), Eq(policy_engine_))) .WillOnce(Return(true)); diff --git a/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp b/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp index 2fac894a..b1a57a12 100644 --- a/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp @@ -11,6 +11,7 @@ #include "cdm_engine.h" +#include "default_service_certificate.h" #include "license_request.h" #include "log.h" #include "oec_session_util.h" @@ -163,6 +164,7 @@ class WvGenericOperationsTest : public testing::Test { CdmCertificateType cert_type = kCertificateWidevine; std::string cert_authority; std::string cert, wrapped_key; + cdm_engine_->SetServiceCertificate(kDefaultServiceCertificate); ASSERT_EQ(NO_ERROR, cdm_engine_->GetProvisioningRequest( cert_type, cert_authority, &prov_request, diff --git a/libwvdrmengine/cdm/core/test/license_unittest.cpp b/libwvdrmengine/cdm/core/test/license_unittest.cpp index f2f51d53..158d1a93 100644 --- a/libwvdrmengine/cdm/core/test/license_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_unittest.cpp @@ -5,10 +5,12 @@ #include "clock.h" #include "crypto_session.h" +#include "default_service_certificate.h" #include "initialization_data.h" #include "license.h" #include "policy_engine.h" #include "properties.h" +#include "service_certificate.h" #include "string_conversions.h" #include "wv_cdm_constants.h" @@ -155,25 +157,26 @@ class CdmLicenseTest : public ::testing::Test { MockCryptoSession* crypto_session_; MockInitializationData* init_data_; MockPolicyEngine* policy_engine_; + ServiceCertificate service_cert_; }; TEST_F(CdmLicenseTest, InitSuccess) { EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); CreateCdmLicense(); - EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, + EXPECT_TRUE(cdm_license_->Init(&service_cert_, kToken, kClientTokenDrmCert, crypto_session_, policy_engine_)); } TEST_F(CdmLicenseTest, InitFail_EmptyToken) { CreateCdmLicense(); - EXPECT_FALSE(cdm_license_->Init("", kClientTokenDrmCert, + EXPECT_FALSE(cdm_license_->Init(&service_cert_, "", kClientTokenDrmCert, crypto_session_, policy_engine_)); } TEST_F(CdmLicenseTest, InitFail_CryptoSessionNull) { CreateCdmLicense(); - EXPECT_FALSE(cdm_license_->Init(kToken, kClientTokenDrmCert, + EXPECT_FALSE(cdm_license_->Init(&service_cert_, kToken, kClientTokenDrmCert, NULL, policy_engine_)); } @@ -181,10 +184,18 @@ TEST_F(CdmLicenseTest, InitFail_PolicyEngineNull) { EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); CreateCdmLicense(); - EXPECT_FALSE(cdm_license_->Init(kToken, kClientTokenDrmCert, + EXPECT_FALSE(cdm_license_->Init(&service_cert_, kToken, kClientTokenDrmCert, crypto_session_, NULL)); } +TEST_F(CdmLicenseTest, InitWithNullServiceCert) { + EXPECT_CALL(*crypto_session_, IsOpen()).WillOnce(Return(true)); + + CreateCdmLicense(); + EXPECT_TRUE(cdm_license_->Init(NULL, kToken, kClientTokenDrmCert, + crypto_session_, policy_engine_)); +} + TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { bool usage_information_support = true; CryptoSession::HdcpCapability current_hdcp_version = HDCP_NO_DIGITAL_OUTPUT; @@ -219,16 +230,17 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { DoAll(SetArgPointee<2>(kLicenseRequestSignature), Return(true))); CreateCdmLicense(); - EXPECT_TRUE(cdm_license_->Init(kToken, kClientTokenDrmCert, + service_cert_.Init(kDefaultServiceCertificate); + EXPECT_TRUE(cdm_license_->Init(&service_cert_, kToken, kClientTokenDrmCert, crypto_session_, policy_engine_)); CdmAppParameterMap app_parameters; CdmKeyMessage signed_request; Properties::set_use_certificates_as_identification(true); std::string server_url; - EXPECT_TRUE(cdm_license_->PrepareKeyRequest( + EXPECT_EQ(cdm_license_->PrepareKeyRequest( *init_data_, kLicenseTypeStreaming, app_parameters, - &signed_request, &server_url)); + &signed_request, &server_url), KEY_MESSAGE); EXPECT_TRUE(!signed_request.empty()); @@ -287,7 +299,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_request.content_id(); - EXPECT_TRUE(content_id.has_cenc_id_deprecated()); + ASSERT_TRUE(content_id.has_cenc_id_deprecated()); EXPECT_FALSE(content_id.has_webm_id_deprecated()); EXPECT_FALSE(content_id.has_existing_license()); diff --git a/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp b/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp index 3a9581c2..f6de7718 100644 --- a/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp @@ -89,14 +89,6 @@ class StubCdmClientPropertySet : public CdmClientPropertySet { service_certificate_ = cert; } - virtual const std::string& device_provisioning_service_certificate() const { - return device_provisioning_service_certificate_; - } - - virtual void set_device_provisioning_service_certificate( - const std::string& cert) { - device_provisioning_service_certificate_ = cert; - } virtual bool is_session_sharing_enabled() const { return is_session_sharing_enabled_; } @@ -112,7 +104,6 @@ class StubCdmClientPropertySet : public CdmClientPropertySet { private: std::string security_level_; std::string service_certificate_; - std::string device_provisioning_service_certificate_; bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; @@ -123,9 +114,8 @@ TEST_F(ServiceCertificateTest, InitSuccess) { MockCryptoSession crypto_session(&crypto_metrics_); CreateServiceCertificate(); - service_certificate_->Init(kTestSessionId1, &crypto_session); - EXPECT_FALSE(service_certificate_->IsRequired()); - EXPECT_FALSE(service_certificate_->IsAvailable()); + service_certificate_->Init(kTestSessionId1); + EXPECT_FALSE(service_certificate_->HasCertificate()); } TEST_F(ServiceCertificateTest, InitPrivacyModeRequired) { @@ -138,9 +128,8 @@ TEST_F(ServiceCertificateTest, InitPrivacyModeRequired) { Properties::AddSessionPropertySet(kTestSessionId1, &property_set); CreateServiceCertificate(); - service_certificate_->Init(kTestSessionId1, &crypto_session); - EXPECT_TRUE(service_certificate_->IsRequired()); - EXPECT_FALSE(service_certificate_->IsAvailable()); + service_certificate_->Init(kTestSessionId1); + EXPECT_FALSE(service_certificate_->HasCertificate()); } TEST_F(ServiceCertificateTest, InitServiceCertificatePresent) { @@ -154,9 +143,12 @@ TEST_F(ServiceCertificateTest, InitServiceCertificatePresent) { Properties::AddSessionPropertySet(kTestSessionId1, &property_set); CreateServiceCertificate(); - service_certificate_->Init(kTestSessionId1, &crypto_session); - EXPECT_TRUE(service_certificate_->IsRequired()); - EXPECT_TRUE(service_certificate_->IsAvailable()); + std::string raw_service_certificate; + EXPECT_TRUE(Properties::GetServiceCertificate(kTestSessionId1, + &raw_service_certificate)); + EXPECT_EQ(NO_ERROR, + service_certificate_->Init(raw_service_certificate)); + EXPECT_TRUE(service_certificate_->HasCertificate()); } TEST_F(ServiceCertificateTest, SetServiceCertificate) { @@ -169,13 +161,8 @@ TEST_F(ServiceCertificateTest, SetServiceCertificate) { Properties::AddSessionPropertySet(kTestSessionId1, &property_set); CreateServiceCertificate(); - service_certificate_->Init(kTestSessionId1, &crypto_session); - EXPECT_TRUE(service_certificate_->IsRequired()); - EXPECT_FALSE(service_certificate_->IsAvailable()); + EXPECT_EQ(NO_ERROR, service_certificate_->Init(kTestSignedCertificate)); + EXPECT_TRUE(service_certificate_->HasCertificate()); +} - EXPECT_EQ(NO_ERROR, - service_certificate_->VerifyAndSet(kTestSignedCertificate)); - EXPECT_TRUE(service_certificate_->IsRequired()); - EXPECT_TRUE(service_certificate_->IsAvailable()); -} } diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 016fa74f..5b6af622 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -95,8 +95,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { break; case DEVICE_CERTIFICATE_ERROR_4: *os << "DEVICE_CERTIFICATE_ERROR_4"; break; - case DEVICE_CERTIFICATE_ERROR_5: *os << "DEVICE_CERTIFICATE_ERROR_5"; - break; case EMPTY_KEY_DATA_1: *os << "EMPTY_KEY_DATA_1"; break; case EMPTY_KEY_DATA_2: *os << "EMPTY_KEY_DATA_2"; diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 263b84d1..982b71b0 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -353,8 +353,10 @@ void WvContentDecryptionModule::NotifyResolution(const CdmSessionId& session_id, bool WvContentDecryptionModule::IsValidServiceCertificate( const std::string& certificate) { - return ServiceCertificate::VerifySignedServiceCertificate(certificate) == - NO_ERROR; + ServiceCertificate cert; + CdmResponseType status = cert.Init(certificate); + if (status != NO_ERROR) return false; + return cert.HasCertificate(); } void WvContentDecryptionModule::GetSerializedMetrics( diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 4824a970..d8cb2aa3 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -213,13 +213,6 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { virtual void set_service_certificate(const std::string& cert) { service_certificate_ = cert; } - virtual const std::string& device_provisioning_service_certificate() const { - return device_provisioning_service_certificate_; - } - virtual void set_device_provisioning_service_certificate( - const std::string& cert) { - device_provisioning_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_; @@ -245,7 +238,6 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { std::string app_id_; std::string security_level_; std::string service_certificate_; - std::string device_provisioning_service_certificate_; bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index fe95d396..f54346b8 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -894,13 +894,6 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { virtual void set_service_certificate(const std::string& cert) { service_certificate_ = cert; } - virtual const std::string& device_provisioning_service_certificate() const { - return device_provisioning_service_certificate_; - } - virtual void set_device_provisioning_service_certificate( - const std::string& cert) { - device_provisioning_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_; @@ -926,7 +919,6 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { std::string app_id_; std::string security_level_; std::string service_certificate_; - std::string device_provisioning_service_certificate_; bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; @@ -1652,6 +1644,7 @@ TEST_F(WvCdmRequestLicenseTest, PrivacyModeWithServiceCertificateTest) { property_set.set_use_privacy_mode(true); property_set.set_service_certificate(a2bs_hex(g_service_certificate)); + // TODO: pass g_service_certificate into CdmEngine::SetServiceCertificate() decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); @@ -2181,6 +2174,7 @@ TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) { if (config->specify_service_certificate) property_set.set_service_certificate(a2bs_hex(g_service_certificate)); } + // TODO: pass g_service_certificate into CdmEngine::SetServiceCertificate() decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, app_parameters, kLicenseTypeStreaming, @@ -2311,6 +2305,7 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) { if (config->specify_service_certificate) property_set.set_service_certificate(a2bs_hex(g_service_certificate)); } + // TODO: pass g_service_certificate into CdmEngine::SetServiceCertificate() decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, app_parameters, kLicenseTypeOffline, NULL); diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index d6b79dfc..77c2bddd 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -212,7 +212,6 @@ enum { kInvalidParametersEng14 = ERROR_DRM_VENDOR_MIN + 199, kInvalidParametersEng15 = ERROR_DRM_VENDOR_MIN + 200, kInvalidParametersEng16 = ERROR_DRM_VENDOR_MIN + 201, - kDeviceCertificateError5 = ERROR_DRM_VENDOR_MIN + 202, kCertProvisioningClientTokenError1 = ERROR_DRM_VENDOR_MIN + 203, kCertProvisioningClientTokenError2 = ERROR_DRM_VENDOR_MIN + 204, kLicensingClientTokenError1 = ERROR_DRM_VENDOR_MIN + 205, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index 56225b94..5a84ad33 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -81,8 +81,6 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kDeviceCertificateError3; case wvcdm::DEVICE_CERTIFICATE_ERROR_4: return kDeviceCertificateError4; - case wvcdm::DEVICE_CERTIFICATE_ERROR_5: - return kDeviceCertificateError5; case wvcdm::EMPTY_KEY_DATA_1: return kEmptyKeyData1; case wvcdm::EMPTY_KEY_DATA_2: @@ -542,6 +540,7 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { case wvcdm::UNUSED_4: case wvcdm::UNUSED_5: case wvcdm::UNUSED_6: + case wvcdm::UNUSED_7: return android::UNKNOWN_ERROR; } diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index a752a2a5..75b2a504 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -242,7 +242,6 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) { case wvcdm::INVALID_PARAMETERS_ENG_14: case wvcdm::INVALID_PARAMETERS_ENG_15: case wvcdm::INVALID_PARAMETERS_ENG_16: - case wvcdm::DEVICE_CERTIFICATE_ERROR_5: case wvcdm::CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1: case wvcdm::CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2: case wvcdm::LICENSING_CLIENT_TOKEN_ERROR_1: diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 6a4d5f0d..59a71cd0 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -217,16 +217,6 @@ class WVDrmPlugin : public android::DrmPlugin, mServiceCertificate = serviceCertificate; } - virtual const std::string& device_provisioning_service_certificate() const { - // Android does not support service certificates for provisioning. - return mEmptyString; - } - - virtual void set_device_provisioning_service_certificate( - const std::string& ) { - // Ignore. Android does not support service certificates for provisioning - } - virtual bool is_session_sharing_enabled() const { return mShareKeys; } diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.h index 4ec70bec..51d21320 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_usage_table_mock.h @@ -81,8 +81,11 @@ class UsageTableEntry { class UsageTable { public: - explicit UsageTable(CryptoEngine* ce) - : ce_(ce), header_loaded_(false), old_table_(NULL){}; + UsageTable(CryptoEngine* ce, wvcdm::FileSystem* /* file_system */) + : ce_(ce), + /* TODO: unused: file_system_(file_system), */ + header_loaded_(false), + old_table_(NULL){}; ~UsageTable(); OEMCryptoResult CreateNewUsageEntry(SessionContext* session, @@ -125,6 +128,7 @@ class UsageTable { bool LoadGenerationNumber(bool or_make_new_one); CryptoEngine* ce_; + /* TODO: unused: wvcdm::FileSystem* file_system_; */ bool header_loaded_; int64_t master_generation_number_; std::vector generation_numbers_;