diff --git a/libwvdrmengine/cdm/core/include/client_identification.h b/libwvdrmengine/cdm/core/include/client_identification.h index 76fcde5e..dd9d3e57 100644 --- a/libwvdrmengine/cdm/core/include/client_identification.h +++ b/libwvdrmengine/cdm/core/include/client_identification.h @@ -37,10 +37,14 @@ class ClientIdentification { // |app_parameters| parameters provided by client/app to be included in // provisioning/license request. optional, only used // if |is_license_request| is true + // |provider_client_token| optional parameter specified by the content + // and included in the license. Only used if + // specified and if |is_license_request| is true // |client_id| Portion of license/provisioning request that needs to be // populated. virtual CdmResponseType Prepare( const CdmAppParameterMap& app_parameters, + const std::string& provider_client_token, video_widevine::ClientIdentification* client_id); private: diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 5807aa4d..f28b5f71 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -84,6 +84,7 @@ class CdmLicense { CdmResponseType PrepareClientId( const CdmAppParameterMap& app_parameters, + const std::string& provider_client_token, video_widevine::LicenseRequest* license_request); CdmResponseType PrepareContentId( @@ -148,6 +149,9 @@ class CdmLicense { CdmLicenseKeyType license_key_type_; RepeatedPtrField entitlement_keys_; + + std::string provider_client_token_; + #if defined(UNIT_TEST) friend class CdmLicenseTestPeer; #endif diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index f9cefd58..300b8b0f 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -15,6 +15,8 @@ namespace { +const std::string kEmptyString; + // URL for Google Provisioning Server. // The provisioning server supplies the certificate that is needed // to communicate with the License Server. @@ -200,7 +202,7 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest( provisioning_request.mutable_client_id(); CdmAppParameterMap app_parameter; - status = id.Prepare(app_parameter, client_id); + status = id.Prepare(app_parameter, kEmptyString, client_id); if (status != NO_ERROR) return status; if (!service_certificate_->has_certificate()) { diff --git a/libwvdrmengine/cdm/core/src/client_identification.cpp b/libwvdrmengine/cdm/core/src/client_identification.cpp index 250d5194..447a276c 100644 --- a/libwvdrmengine/cdm/core/src/client_identification.cpp +++ b/libwvdrmengine/cdm/core/src/client_identification.cpp @@ -73,6 +73,7 @@ CdmResponseType ClientIdentification::Init(const std::string& client_token, */ CdmResponseType ClientIdentification::Prepare( const CdmAppParameterMap& app_parameters, + const std::string& provider_client_token, video_widevine::ClientIdentification* client_id) { if (is_license_request_) { @@ -147,6 +148,10 @@ CdmResponseType ClientIdentification::Prepare( ss << (uint32_t)crypto_session_->GetSecurityPatchLevel(); client_info->set_value(ss.str()); + if (!provider_client_token.empty()) { + client_id->set_provider_client_token(provider_client_token); + } + ClientIdentification_ClientCapabilities* client_capabilities = client_id->mutable_client_capabilities(); diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 58268ad1..d4c21ec8 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -23,12 +23,15 @@ #include "wv_cdm_constants.h" namespace { + const uint32_t kFourCcCbc1 = 0x63626331; const uint32_t kFourCcCbcs = 0x63626373; const uint32_t kFourCcLittleEndianCbc1 = 0x31636263; const uint32_t kFourCcLittleEndianCbcs = 0x73636263; const uint32_t kFourCcCenc = 0x63656e63; +const std::string kEmptyString; + } // namespace namespace wvcdm { @@ -304,7 +307,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest( LicenseRequest license_request; CdmResponseType status; - status = PrepareClientId(app_parameters, &license_request); + status = PrepareClientId(app_parameters, kEmptyString, &license_request); if (NO_ERROR != status) return status; status = @@ -398,7 +401,9 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( license_request.set_request_time(clock_->GetCurrentTime()); if (renew_with_client_id_) { - CdmResponseType status = PrepareClientId(app_parameters, &license_request); + CdmResponseType status = + PrepareClientId(app_parameters, provider_client_token_, + &license_request); if (NO_ERROR != status) return status; } @@ -577,6 +582,7 @@ CdmResponseType CdmLicense::HandleKeyResponse( return NO_CONTENT_KEY; } license_key_type_ = key_type; + provider_client_token_ = license.provider_client_token(); if (license.has_srm_update()) crypto_session_->LoadSrm(license.srm_update()); @@ -930,14 +936,16 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse( } CdmResponseType CdmLicense::PrepareClientId( - const CdmAppParameterMap& app_parameters, LicenseRequest* license_request) { + const CdmAppParameterMap& app_parameters, + const std::string& provider_client_token, + LicenseRequest* license_request) { wvcdm::ClientIdentification id; CdmResponseType status = id.Init(client_token_, device_id_, crypto_session_); if (status != NO_ERROR) return status; video_widevine::ClientIdentification* client_id = license_request->mutable_client_id(); - status = id.Prepare(app_parameters, client_id); + status = id.Prepare(app_parameters, provider_client_token, client_id); if (status != NO_ERROR) return status; if (Properties::UsePrivacyMode(session_id_)) { diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 7295b731..310d17c5 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -3981,6 +3981,115 @@ TEST_F(WvCdmRequestLicenseTest, UsageRemoveSecureStopTest) { EXPECT_TRUE(secure_stop_ids.empty()); } +// TODO(rfrias): Enable when b/123370099 has been addressed +TEST_F(WvCdmRequestLicenseTest, DISABLED_VerifyProviderClientToken) { + Unprovision(); + Provision(kLevelDefault); + + // The default offline asset "offline_clip2" does not include a + // provider session token but "offline_clip5" does, so replace the last + // char in init data with '5' + std::string key_id; + std::string client_auth; + GetOfflineConfiguration(&key_id, &client_auth); + key_id[key_id.size()-1] = '5'; + + // Acquire license + decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, + NULL, &session_id_); + GenerateKeyRequest(key_id, kLicenseTypeOffline); + EXPECT_TRUE(!key_msg_.empty()); + std::string key_msg = key_msg_; + std::string key_response; + VerifyKeyRequestResponse(config_.license_server(), client_auth, false, + &key_response); + + CdmKeySetId key_set_id = key_set_id_; + EXPECT_TRUE(!key_set_id_.empty()); + EXPECT_TRUE(!key_response.empty()); + + // Validate signed license request + SignedMessage signed_message; + EXPECT_TRUE(signed_message.ParseFromString(key_msg)); + EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type()); + EXPECT_TRUE(signed_message.has_signature()); + EXPECT_TRUE(!signed_message.msg().empty()); + + // Verify license request + video_widevine::LicenseRequest license_request; + EXPECT_TRUE(license_request.ParseFromString(signed_message.msg())); + + // Verify that the provider client token is absent in the license request + EXPECT_FALSE(license_request.client_id().has_provider_client_token()); + EXPECT_TRUE(license_request.client_id().provider_client_token().empty()); + + // Validate signed license response + EXPECT_TRUE(signed_message.ParseFromString(key_response)); + EXPECT_EQ(SignedMessage::LICENSE, signed_message.type()); + EXPECT_TRUE(signed_message.has_signature()); + EXPECT_TRUE(!signed_message.msg().empty()); + + // Verify license + video_widevine::License license; + EXPECT_TRUE(license.ParseFromString(signed_message.msg())); + + // Verify that the provider client token is present in the license + EXPECT_TRUE(license.has_provider_client_token()); + EXPECT_TRUE(!license.provider_client_token().empty()); + + decryptor_.CloseSession(session_id_); + session_id_.clear(); + + // Restore offline license and renew it + decryptor_.OpenSession(config_.key_system(), NULL, kDefaultCdmIdentifier, + NULL, &session_id_); + EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); + + std::string license_server; + GenerateRenewalRequest(kLicenseTypeOffline, &license_server); + EXPECT_TRUE(!key_msg_.empty()); + key_msg = key_msg_; + EXPECT_FALSE(license_server.empty()); + VerifyKeyRequestResponse(license_server, client_auth); + + // Validate signed license renewal request + EXPECT_TRUE(signed_message.ParseFromString(key_msg)); + EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type()); + EXPECT_TRUE(signed_message.has_signature()); + EXPECT_TRUE(!signed_message.msg().empty()); + + // Verify license renewal request + EXPECT_TRUE(license_request.ParseFromString(signed_message.msg())); + + // Verify provider client token is present in the license renewal request + EXPECT_TRUE(license_request.client_id().has_provider_client_token()); + EXPECT_TRUE(!license_request.client_id().provider_client_token().empty()); + + decryptor_.CloseSession(session_id_); + session_id_.clear(); + + // Restore and release offline license + key_set_id_.clear(); + GenerateKeyRelease(key_set_id); + key_set_id_ = key_set_id; + EXPECT_TRUE(!key_msg_.empty()); + key_msg = key_msg_; + VerifyKeyRequestResponse(config_.license_server(), client_auth); + + // Validate signed license release request + EXPECT_TRUE(signed_message.ParseFromString(key_msg)); + EXPECT_EQ(SignedMessage::LICENSE_REQUEST, signed_message.type()); + EXPECT_TRUE(signed_message.has_signature()); + EXPECT_TRUE(!signed_message.msg().empty()); + + // Verify license release request + EXPECT_TRUE(license_request.ParseFromString(signed_message.msg())); + + // Verify provider client token is present in the license release request + EXPECT_TRUE(license_request.client_id().has_provider_client_token()); + EXPECT_TRUE(!license_request.client_id().provider_client_token().empty()); +} + TEST_F(WvCdmRequestLicenseTest, QueryUnmodifiedSessionStatus) { // Test that the global value is returned when no properties are modifying it. std::string security_level;