From b492f7b73bba0f228b11ad1536b3d144c23072f7 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Fri, 13 Jan 2017 14:48:29 -0800 Subject: [PATCH 1/2] Update CDM to newest license protocol definitions. * CDM license protocol updates [ Merge of http://go/wvgerrit/22789 ] No functional changes (yet) - all tests in widevine_ce_cdm_unittest run successfully. * Address android test build failures [ Merge of http://go/wvgerrit/22983 ] Updates to the license_protocol.proto in go/wvgerrit/22789 did not include the integration tests for android. b/34202048 Test: Reran unittests. All tests other than some oemcrypto, request_license_test passed. Those tests failed with or without this CL. Change-Id: Ib9041d397187859b8fcbc1b1f7d275f8c4ef6aba --- libwvdrmengine/cdm/core/include/license.h | 10 +- .../cdm/core/include/license_key_status.h | 6 +- .../cdm/core/include/policy_engine.h | 12 +- .../cdm/core/src/certificate_provisioning.cpp | 15 +- .../cdm/core/src/initialization_data.cpp | 8 +- libwvdrmengine/cdm/core/src/license.cpp | 99 ++++--- .../cdm/core/src/license_key_status.cpp | 4 +- .../cdm/core/src/license_protocol.proto | 263 ++++++++++++------ libwvdrmengine/cdm/core/src/policy_engine.cpp | 4 +- .../test/initialization_data_unittest.cpp | 6 +- .../cdm/core/test/license_keys_unittest.cpp | 10 +- .../cdm/core/test/license_unittest.cpp | 34 +-- .../policy_engine_constraints_unittest.cpp | 14 +- .../cdm/core/test/policy_engine_unittest.cpp | 10 +- .../cdm/test/cdm_extended_duration_test.cpp | 95 +++---- .../cdm/test/request_license_test.cpp | 70 ++--- 16 files changed, 371 insertions(+), 289 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index a6a9a82a..6166dee7 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -9,12 +9,10 @@ #include "scoped_ptr.h" #include "wv_cdm_types.h" -namespace video_widevine_server { -namespace sdk { +namespace video_widevine { class SignedMessage; class LicenseRequest; -} -} // namespace video_widevine_server +} // namespace video_widevine namespace wvcdm { @@ -68,12 +66,12 @@ class CdmLicense { std::string* server_url); CdmResponseType HandleKeyErrorResponse( - const video_widevine_server::sdk::SignedMessage& signed_message); + const video_widevine::SignedMessage& signed_message); CdmResponseType PrepareClientId( bool encrypt, const std::string& certificate, const CdmAppParameterMap& app_parameters, - video_widevine_server::sdk::LicenseRequest* license_request); + video_widevine::LicenseRequest* license_request); template bool PrepareContentId(const CdmLicenseType license_type, const std::string& request_id, T* content_id); diff --git a/libwvdrmengine/cdm/core/include/license_key_status.h b/libwvdrmengine/cdm/core/include/license_key_status.h index cc81dd5a..59689472 100644 --- a/libwvdrmengine/cdm/core/include/license_key_status.h +++ b/libwvdrmengine/cdm/core/include/license_key_status.h @@ -53,10 +53,10 @@ class LicenseKeys { // Extracts the keys from a license and makes them available for // querying usage and constraint settings. virtual void SetFromLicense( - const video_widevine_server::sdk::License& license); + const video_widevine::License& license); private: - typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer; + typedef ::video_widevine::License::KeyContainer KeyContainer; typedef std::map::const_iterator LicenseKeyStatusIterator; @@ -101,7 +101,7 @@ class LicenseKeyStatus { uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level); protected: - typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer; + typedef ::video_widevine::License::KeyContainer KeyContainer; typedef KeyContainer::OperatorSessionKeyPermissions OperatorSessionKeyPermissions; typedef KeyContainer::OutputProtection OutputProtection; diff --git a/libwvdrmengine/cdm/core/include/policy_engine.h b/libwvdrmengine/cdm/core/include/policy_engine.h index 812b84d1..b24a72a6 100644 --- a/libwvdrmengine/cdm/core/include/policy_engine.h +++ b/libwvdrmengine/cdm/core/include/policy_engine.h @@ -13,7 +13,7 @@ namespace wvcdm { -using video_widevine_server::sdk::LicenseIdentification; +using video_widevine::LicenseIdentification; class Clock; class CryptoSession; @@ -43,12 +43,12 @@ class PolicyEngine { // an exact copy of the policy information stored in the license. // The license state transitions to kLicenseStateCanPlay if the license // permits playback. - virtual void SetLicense(const video_widevine_server::sdk::License& license); + virtual void SetLicense(const video_widevine::License& license); // SetLicenseForRelease is used when releasing a license. The keys in this // license will be ignored, and any old keys will be expired. virtual void SetLicenseForRelease( - const video_widevine_server::sdk::License& license); + const video_widevine::License& license); // Call this on first decrypt to set the start of playback. virtual void BeginDecryption(void); @@ -60,7 +60,7 @@ class PolicyEngine { // updated license_start_time from the server. The license will transition to // kLicenseStateCanPlay if the license permits playback. virtual void UpdateLicense( - const video_widevine_server::sdk::License& license); + const video_widevine::License& license); // Used for notifying the Policy Engine of resolution changes virtual void NotifyResolution(uint32_t width, uint32_t height); @@ -146,12 +146,12 @@ class PolicyEngine { // This is the current policy information for this license. This gets updated // as license renewals occur. - video_widevine_server::sdk::License::Policy policy_; + video_widevine::License::Policy policy_; // This is the license id field from server response. This data gets passed // back to the server in each renewal request. When we get a renewal response // from the license server we will get an updated id field. - video_widevine_server::sdk::LicenseIdentification license_id_; + video_widevine::LicenseIdentification license_id_; // The server returns the license start time in the license/license renewal // response based off the request time sent by the client in the diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index a6b2c10a..689f4510 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -21,11 +21,11 @@ const std::string kProvisioningServerUrl = namespace wvcdm { // Protobuf generated classes. -using video_widevine_server::sdk::ClientIdentification; -using video_widevine_server::sdk::ProvisioningOptions; -using video_widevine_server::sdk::ProvisioningRequest; -using video_widevine_server::sdk::ProvisioningResponse; -using video_widevine_server::sdk::SignedProvisioningMessage; +using video_widevine::ClientIdentification; +using video_widevine::ProvisioningOptions; +using video_widevine::ProvisioningRequest; +using video_widevine::ProvisioningResponse; +using video_widevine::SignedProvisioningMessage; /* * This function converts SignedProvisioningRequest into base64 string. It then @@ -98,12 +98,11 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest( switch (cert_type) { case kCertificateWidevine: options->set_certificate_type( - video_widevine_server::sdk:: - ProvisioningOptions_CertificateType_WIDEVINE_DRM); + video_widevine::ProvisioningOptions_CertificateType_WIDEVINE_DRM); break; case kCertificateX509: options->set_certificate_type( - video_widevine_server::sdk::ProvisioningOptions_CertificateType_X509); + video_widevine::ProvisioningOptions_CertificateType_X509); break; default: LOGE("GetProvisioningRequest: unknown certificate type %ld", cert_type); diff --git a/libwvdrmengine/cdm/core/src/initialization_data.cpp b/libwvdrmengine/cdm/core/src/initialization_data.cpp index 2ce009b6..5fa64d84 100644 --- a/libwvdrmengine/cdm/core/src/initialization_data.cpp +++ b/libwvdrmengine/cdm/core/src/initialization_data.cpp @@ -35,9 +35,9 @@ const int kDefaultNumJsonTokens = 128; namespace wvcdm { // Protobuf generated classes. -using video_widevine_server::sdk::WidevineCencHeader; -using video_widevine_server::sdk::WidevineCencHeader_Algorithm; -using video_widevine_server::sdk::WidevineCencHeader_Algorithm_AESCTR; +using video_widevine::WidevineCencHeader; +using video_widevine::WidevineCencHeader_Algorithm; +using video_widevine::WidevineCencHeader_Algorithm_AESCTR; InitializationData::InitializationData(const std::string& type, const CdmInitData& data) @@ -234,7 +234,7 @@ bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data, // "URI=”data:text/plain;base64,eyANCiAgICJwcm92aWRlciI6Im1sYmFtaGJvIiwNCiAg" // "ICJjb250ZW50X2lkIjoiMjAxNV9UZWFycyIsDQogICAia2V5X2lkcyI6DQogICBbDQo" // "gICAgICAiMzcxZTEzNWUxYTk4NWQ3NWQxOThhN2Y0MTAyMGRjMjMiDQogICBdDQp9DQ" -// "o=", \ +// "o=, \" // "IV=0x6df49213a781e338628d0e9c812d328e, \" // "KEYFORMAT=”com.widevine”, \" // "KEYFORMATVERSIONS=”1”" diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index fdc205a2..e2afa55f 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -73,23 +73,22 @@ const uint32_t kFourCcCens = 0x63656e73; namespace wvcdm { // Protobuf generated classes. -using video_widevine_server::sdk::ClientIdentification; -using video_widevine_server::sdk::ClientIdentification_ClientCapabilities; -using video_widevine_server::sdk::ClientIdentification_NameValue; -using video_widevine_server::sdk::DeviceCertificate; -using video_widevine_server::sdk::EncryptedClientIdentification; -using video_widevine_server::sdk::License; -using video_widevine_server::sdk::License_KeyContainer; -using video_widevine_server::sdk::LicenseError; -using video_widevine_server::sdk::LicenseIdentification; -using video_widevine_server::sdk::LicenseRequest; -using video_widevine_server::sdk::LicenseRequest_ContentIdentification; -using video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC; -using video_widevine_server::sdk::LicenseRequest_ContentIdentification_WebM; -using video_widevine_server::sdk:: - LicenseRequest_ContentIdentification_ExistingLicense; -using video_widevine_server::sdk::SignedDeviceCertificate; -using video_widevine_server::sdk::SignedMessage; +using video_widevine::ClientIdentification; +using video_widevine::ClientIdentification_ClientCapabilities; +using video_widevine::ClientIdentification_NameValue; +using video_widevine::DrmDeviceCertificate; +using video_widevine::EncryptedClientIdentification; +using video_widevine::License; +using video_widevine::License_KeyContainer; +using video_widevine::LicenseError; +using video_widevine::LicenseIdentification; +using video_widevine::LicenseRequest; +using video_widevine::LicenseRequest_ContentIdentification; +using video_widevine::LicenseRequest_ContentIdentification_CencDeprecated; +using video_widevine::LicenseRequest_ContentIdentification_WebmDeprecated; +using video_widevine::LicenseRequest_ContentIdentification_ExistingLicense; +using video_widevine::SignedDrmDeviceCertificate; +using video_widevine::SignedMessage; static std::vector ExtractContentKeys(const License& license) { std::vector key_array; @@ -262,8 +261,8 @@ CdmResponseType CdmLicense::PrepareKeyRequest( license_request.mutable_content_id(); if (init_data.is_cenc() || init_data.is_hls()) { - LicenseRequest_ContentIdentification_CENC* cenc_content_id = - content_id->mutable_cenc_id(); + LicenseRequest_ContentIdentification_CencDeprecated* cenc_content_id = + content_id->mutable_cenc_id_deprecated(); if (!init_data.IsEmpty()) { cenc_content_id->add_pssh(init_data.data()); @@ -276,8 +275,8 @@ CdmResponseType CdmLicense::PrepareKeyRequest( return PREPARE_CENC_CONTENT_ID_FAILED; } } else if (init_data.is_webm()) { - LicenseRequest_ContentIdentification_WebM* webm_content_id = - content_id->mutable_webm_id(); + LicenseRequest_ContentIdentification_WebmDeprecated* webm_content_id = + content_id->mutable_webm_id_deprecated(); if (!init_data.IsEmpty()) { webm_content_id->set_header(init_data.data()); @@ -307,7 +306,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest( } license_request.set_key_control_nonce(nonce); LOGD("PrepareKeyRequest: nonce=%u", nonce); - license_request.set_protocol_version(video_widevine_server::sdk::VERSION_2_1); + license_request.set_protocol_version(video_widevine::VERSION_2_1); // License request is complete. Serialize it. std::string serialized_license_req; @@ -388,7 +387,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( } LicenseRequest_ContentIdentification_ExistingLicense* current_license = - license_request.mutable_content_id()->mutable_license(); + license_request.mutable_content_id()->mutable_existing_license(); LicenseIdentification license_id = policy_engine_->license_id(); current_license->mutable_license_id()->CopyFrom(license_id); @@ -433,7 +432,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( } license_request.set_key_control_nonce(nonce); LOGD("PrepareKeyUpdateRequest: nonce=%u", nonce); - license_request.set_protocol_version(video_widevine_server::sdk::VERSION_2_1); + license_request.set_protocol_version(video_widevine::VERSION_2_1); // License request is complete. Serialize it. std::string serialized_license_req; @@ -553,7 +552,7 @@ CdmResponseType CdmLicense::HandleKeyResponse( return NO_CONTENT_KEY; } - if (license.id().type() == video_widevine_server::sdk::OFFLINE && + if (license.id().type() == video_widevine::OFFLINE && license.policy().can_persist()) is_offline_ = true; @@ -564,8 +563,8 @@ CdmResponseType CdmLicense::HandleKeyResponse( server_url_ = license.policy().renewal_server_url(); } - if (license.policy().has_renew_with_client_id()) { - renew_with_client_id_ = license.policy().renew_with_client_id(); + if (license.policy().has_always_include_client_id()) { + renew_with_client_id_ = license.policy().always_include_client_id(); } CdmResponseType resp = session_->LoadKeys( @@ -640,8 +639,8 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse( return LICENSE_ID_NOT_FOUND; } - if (license.policy().has_renew_with_client_id()) { - renew_with_client_id_ = license.policy().renew_with_client_id(); + if (license.policy().has_always_include_client_id()) { + renew_with_client_id_ = license.policy().always_include_client_id(); } if (!is_renewal) { @@ -812,8 +811,8 @@ bool CdmLicense::RestoreLicenseForRelease( if (license.id().has_provider_session_token()) provider_session_token_ = license.id().provider_session_token(); - if (license.policy().has_renew_with_client_id()) - renew_with_client_id_ = license.policy().renew_with_client_id(); + if (license.policy().has_always_include_client_id()) + renew_with_client_id_ = license.policy().always_include_client_id(); if (Properties::use_certificates_as_identification()) { if (!signed_response.has_session_key()) { @@ -877,7 +876,7 @@ bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate( const std::string& signed_certificate, std::string* certificate) { - SignedDeviceCertificate signed_service_certificate; + SignedDrmDeviceCertificate signed_service_certificate; if (!signed_service_certificate.ParseFromString(signed_certificate)) { LOGE( "CdmLicense::VerifyAndExtractSignedServiceCertificate: unable to parse " @@ -897,7 +896,7 @@ CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate( } if (!root_ca_key.VerifySignature( - signed_service_certificate.device_certificate(), + signed_service_certificate.drm_certificate(), signed_service_certificate.signature())) { LOGE( "CdmLicense::VerifyAndExtractSignedServiceCertificate: service " @@ -905,9 +904,9 @@ CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate( return DEVICE_CERTIFICATE_ERROR_3; } - DeviceCertificate service_certificate; + DrmDeviceCertificate service_certificate; if (!service_certificate.ParseFromString( - signed_service_certificate.device_certificate())) { + signed_service_certificate.drm_certificate())) { LOGE( "CdmLicense::VerifyAndExtractSignedServiceCertificate: unable to parse " "retrieved service certificate"); @@ -915,7 +914,7 @@ CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate( } if (service_certificate.type() != - video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) { + video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) { LOGE( "CdmLicense::VerifyAndExtractSignedServiceCertificate: certificate not " "of type service, %d", @@ -924,7 +923,7 @@ CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate( } if (certificate != NULL) { - *certificate = signed_service_certificate.device_certificate(); + *certificate = signed_service_certificate.drm_certificate(); } return NO_ERROR; } @@ -938,9 +937,9 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse( } switch (license_error.error_code()) { - case LicenseError::INVALID_DEVICE_CERTIFICATE: + case LicenseError::INVALID_DRM_DEVICE_CERTIFICATE: return NEED_PROVISIONING; - case LicenseError::REVOKED_DEVICE_CERTIFICATE: + case LicenseError::REVOKED_DRM_DEVICE_CERTIFICATE: return DEVICE_REVOKED; case LicenseError::SERVICE_UNAVAILABLE: default: @@ -956,7 +955,7 @@ CdmResponseType CdmLicense::PrepareClientId( ClientIdentification* client_id = license_request->mutable_client_id(); if (Properties::use_certificates_as_identification()) - client_id->set_type(ClientIdentification::DEVICE_CERTIFICATE); + client_id->set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); else client_id->set_type(ClientIdentification::KEYBOX); client_id->set_token(token_); @@ -1035,32 +1034,32 @@ CdmResponseType CdmLicense::PrepareClientId( switch (max_version) { case HDCP_NONE: client_capabilities->set_max_hdcp_version( - video_widevine_server::sdk:: + video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NONE); break; case HDCP_V1: client_capabilities->set_max_hdcp_version( - video_widevine_server::sdk:: + video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V1); break; case HDCP_V2: client_capabilities->set_max_hdcp_version( - video_widevine_server::sdk:: + video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2); break; case HDCP_V2_1: client_capabilities->set_max_hdcp_version( - video_widevine_server::sdk:: + video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1); break; case HDCP_V2_2: client_capabilities->set_max_hdcp_version( - video_widevine_server::sdk:: + video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_2); break; case HDCP_NO_DIGITAL_OUTPUT: client_capabilities->set_max_hdcp_version( - video_widevine_server::sdk:: + video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_NO_DIGITAL_OUTPUT); break; default: @@ -1074,7 +1073,7 @@ CdmResponseType CdmLicense::PrepareClientId( if (encrypt) { EncryptedClientIdentification* encrypted_client_id = license_request->mutable_encrypted_client_id(); - DeviceCertificate service_certificate; + DrmDeviceCertificate service_certificate; if (!service_certificate.ParseFromString(certificate)) { LOGE( @@ -1084,7 +1083,7 @@ CdmResponseType CdmLicense::PrepareClientId( } if (service_certificate.type() != - video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) { + video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) { LOGE( "CdmLicense::PrepareClientId: retrieved certificate not of type" " service, %d", @@ -1138,11 +1137,11 @@ bool CdmLicense::PrepareContentId(const CdmLicenseType license_type, T* content_id) { switch (license_type) { case kLicenseTypeOffline: - content_id->set_license_type(video_widevine_server::sdk::OFFLINE); + content_id->set_license_type(video_widevine::OFFLINE); break; case kLicenseTypeStreaming: case kLicenseTypeTemporary: - content_id->set_license_type(video_widevine_server::sdk::STREAMING); + content_id->set_license_type(video_widevine::STREAMING); break; default: LOGD("CdmLicense::PrepareKeyRequest: Unknown license type = %d", diff --git a/libwvdrmengine/cdm/core/src/license_key_status.cpp b/libwvdrmengine/cdm/core/src/license_key_status.cpp index d467687f..0fe19363 100644 --- a/libwvdrmengine/cdm/core/src/license_key_status.cpp +++ b/libwvdrmengine/cdm/core/src/license_key_status.cpp @@ -8,7 +8,7 @@ namespace { // License protocol aliases -typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer; +typedef ::video_widevine::License::KeyContainer KeyContainer; typedef KeyContainer::OutputProtection OutputProtection; typedef KeyContainer::VideoResolutionConstraint VideoResolutionConstraint; typedef ::google::protobuf::RepeatedPtrField @@ -130,7 +130,7 @@ void LicenseKeys::ApplyConstraints( } void LicenseKeys::SetFromLicense( - const video_widevine_server::sdk::License& license) { + const video_widevine::License& license) { this->Clear(); for (int32_t key_index = 0; key_index < license.key_size(); ++key_index) { const KeyContainer& key = license.key(key_index); diff --git a/libwvdrmengine/cdm/core/src/license_protocol.proto b/libwvdrmengine/cdm/core/src/license_protocol.proto index 9877430e..46567076 100644 --- a/libwvdrmengine/cdm/core/src/license_protocol.proto +++ b/libwvdrmengine/cdm/core/src/license_protocol.proto @@ -9,11 +9,13 @@ syntax = "proto2"; -package video_widevine_server.sdk; +package video_widevine; // need this if we are using libprotobuf-cpp-2.3.0-lite option optimize_for = LITE_RUNTIME; +option java_package = "com.google.video.widevine.protos"; + enum LicenseType { STREAMING = 1; OFFLINE = 2; @@ -81,7 +83,11 @@ message License { // Indicates to client that license renewal and release requests ought to // include ClientIdentification (client_id). - optional bool renew_with_client_id = 12 [default = false]; + optional bool always_include_client_id = 12 [default = false]; + + // Duration of grace period before playback_duration_seconds (short window) + // goes into effect. Optional. + optional int64 play_start_grace_period_seconds = 13 [default = 0]; // Enables "soft enforcement" of playback_duration_seconds, letting the user // finish playback even if short window expires. Optional. @@ -121,6 +127,8 @@ message License { } message KeyControl { + // |key_control| is documented in: + // Widevine Modular DRM Security Integration Guide for CENC // If present, the key control must be communicated to the secure // environment prior to any usage. This message is automatically generated // by the Widevine License Server SDK. @@ -196,14 +204,19 @@ message License { optional LicenseIdentification id = 1; optional Policy policy = 2; repeated KeyContainer key = 3; + // Time of the request in seconds (UTC) as set in + // LicenseRequest.request_time. If this time is not set in the request, + // the local time at the license service is used in this field. optional int64 license_start_time = 4; optional bool remote_attestation_verified = 5 [default = false]; // Client token generated by the content provider. Optional. optional bytes provider_client_token = 6; - // Protection scheme identifying the encryption algorithm. Represented as one - // of the following 4CC values: 'cenc' (AES-CTR), 'cbc1' (AES-CBC), - // 'cens' (AES-CTR subsample), 'cbcs' (AES-CBC subsample). + // 4cc code specifying the CENC protection scheme as defined in the CENC 3.0 + // specification. Propagated from Widevine PSSH box. Optional. optional uint32 protection_scheme = 7; + // Minimum HDCP SRM version needed for using this key on content sent to + // HDCP enabled outputs. + optional uint32 min_hdcp_srm_version = 8; } enum ProtocolVersion { @@ -213,13 +226,13 @@ enum ProtocolVersion { message LicenseRequest { message ContentIdentification { - message CENC { + message CencDeprecated { repeated bytes pssh = 1; optional LicenseType license_type = 2; optional bytes request_id = 3; // Opaque, client-specified. } - message WebM { + message WebmDeprecated { optional bytes header = 1; optional LicenseType license_type = 2; optional bytes request_id = 3; // Opaque, client-specified. @@ -232,10 +245,25 @@ message LicenseRequest { optional bytes session_usage_table_entry = 4; } - // Exactly one of these must be present. - optional CENC cenc_id = 1; - optional WebM webm_id = 2; - optional ExistingLicense license = 3; + message InitData { + enum InitDataType { + CENC = 1; + WEBM = 2; + } + + optional InitDataType init_data_type = 1 [default = CENC]; + optional bytes init_data = 2; + optional LicenseType license_type = 3; + optional bytes request_id = 4; + } + + //oneof content_id_variant { + // Exactly one of these must be present. + optional CencDeprecated cenc_id_deprecated = 1; + optional WebmDeprecated webm_id_deprecated = 2; + optional ExistingLicense existing_license = 3; + optional InitData init_data = 4; + //} } enum RequestType { @@ -251,6 +279,7 @@ message LicenseRequest { optional ClientIdentification client_id = 1; optional ContentIdentification content_id = 2; optional RequestType type = 3; + // Time of the request in seconds (UTC) as set by the client. optional int64 request_time = 4; // Old-style decimal-encoded string key control nonce. optional bytes key_control_nonce_deprecated = 5; @@ -265,10 +294,10 @@ message LicenseRequest { message LicenseError { enum Error { // The device credentials are invalid. The device must re-provision. - INVALID_DEVICE_CERTIFICATE = 1; + INVALID_DRM_DEVICE_CERTIFICATE = 1; // The device credentials have been revoked. Re-provisioning is not // possible. - REVOKED_DEVICE_CERTIFICATE = 2; + REVOKED_DRM_DEVICE_CERTIFICATE = 2; // The service is currently unavailable due to the backend being down // or similar circumstances. SERVICE_UNAVAILABLE = 3; @@ -330,17 +359,38 @@ message SignedMessage { } message GroupKeys { - repeated License.KeyContainer key = 1; + enum GroupLicenseVersion { + GROUP_LICENSE_VERSION_1 = 0; + GROUP_LICENSE_VERSION_2 = 1; + } + + message GroupKeyData { + // Required track type. This indicates the track type to which this key + // belongs. + optional string track_type = 1; + // A required signed message. The message body contains a serialized group + // msg. + optional bytes key = 2; + } + + // Optional key container array used in group licensing V1. This is not used + // in V2. + repeated License.KeyContainer key = 1 [deprecated = true]; + // Byte string that identifies the group to which this license material // belongs. optional bytes group_id = 2; + + // Required version id beginning with version 2. If not present version 1 + // should be assumed. + optional GroupLicenseVersion version = 3 [default = GROUP_LICENSE_VERSION_1]; + // Optional key container array for group licensing V2. + repeated GroupKeyData key_data = 4; } // ---------------------------------------------------------------------------- // certificate_provisioning.proto // ---------------------------------------------------------------------------- -// Copyright 2013 Google Inc. All Rights Reserved. -// // Description: // Public protocol buffer definitions for Widevine Device Certificate // Provisioning protocol. @@ -353,53 +403,76 @@ message ProvisioningOptions { X509 = 1; // X.509 certificate. } - optional CertificateType certificate_type = 1; + optional CertificateType certificate_type = 1 [default = WIDEVINE_DRM]; - // It is recommended that the certificate_authority specify the X.509 - // Subject of the signing certificate. + // Contains the application-specific name used to identify the certificate + // authority for signing the generated certificate. This is required iff the + // certificate type is X509. optional string certificate_authority = 2; } // Provisioning request sent by client devices to provisioning service. message ProvisioningRequest { - // Device root of trust and other client identification. Required. - optional ClientIdentification client_id = 1; + //oneof clear_or_encrypted_client_id { + // Device root of trust and other client identification. Required. + optional ClientIdentification client_id = 1; + optional EncryptedClientIdentification encrypted_client_id = 5; + //} // Nonce value used to prevent replay attacks. Required. optional bytes nonce = 2; // Options for type of certificate to generate. Optional. optional ProvisioningOptions options = 3; - // Stable identifier, unique for each device + application (or origin). - // Required if doing per-origin provisioning. - optional bytes stable_id = 4; + //oneof origin_id { + // Stable identifier, unique for each device + application (or origin). + // Required if doing per-origin provisioning. + optional bytes stable_id = 4; + // Stable content provider ID. + optional bytes provider_id = 6; + //} } // Provisioning response sent by the provisioning server to client devices. +// This message is used for both regular Widevine DRM certificates and for +// application-specific X.509 certificates. message ProvisioningResponse { // AES-128 encrypted device private RSA key. PKCS#1 ASN.1 DER-encoded. - // Required. + // Required. For X.509 certificates, the private RSA key may also include + // a prefix as specified by private_key_prefix in the X509CertificateMetadata + // proto message. optional bytes device_rsa_key = 1; // Initialization vector used to encrypt device_rsa_key. Required. optional bytes device_rsa_key_iv = 2; - // Serialized SignedDeviceCertificate. Required. + // For Widevine DRM certificates, this contains the serialized + // SignedDrmDeviceCertificate. For X.509 certificates, this contains the PEM + // encoded X.509 certificate. Required. optional bytes device_certificate = 3; // Nonce value matching nonce in ProvisioningRequest. Required. optional bytes nonce = 4; + // Key used to wrap device_rsa_key when DRM provisioning an OEM factory + // provisioned device. Encrypted with the device OEM public key using + // RSA-OAEP. + optional bytes wrapping_key = 5; } // Serialized ProvisioningRequest or ProvisioningResponse signed with // The message authentication key. message SignedProvisioningMessage { + enum ProtocolVersion { + VERSION_2 = 2; // Keybox factory-provisioned devices. + VERSION_3 = 3; // OEM certificate factory-provisioned devices. + } + // Serialized ProvisioningRequest or ProvisioningResponse. Required. optional bytes message = 1; - // HMAC-SHA256 signature of message. Required. + // HMAC-SHA256 (Keybox) or RSASSA-PSS (OEM) signature of message. Required. optional bytes signature = 2; + // Version number of provisioning protocol. + optional ProtocolVersion protocol_version = 3 [default = VERSION_2]; } // ---------------------------------------------------------------------------- // client_identification.proto // ---------------------------------------------------------------------------- -// Copyright 2013 Google Inc. All Rights Reserved. -// // Description: // ClientIdentification messages used by provisioning and license protocols. @@ -407,8 +480,9 @@ message SignedProvisioningMessage { message ClientIdentification { enum TokenType { KEYBOX = 0; - DEVICE_CERTIFICATE = 1; + DRM_DEVICE_CERTIFICATE = 1; REMOTE_ATTESTATION_CERTIFICATE = 2; + OEM_DEVICE_CERTIFICATE = 3; } message NameValue { @@ -433,6 +507,9 @@ message ClientIdentification { optional bool video_resolution_constraints = 3 [default = false]; optional HdcpVersion max_hdcp_version = 4 [default = HDCP_NONE]; optional uint32 oem_crypto_api_version = 5; + // Client has hardware support for protecting the usage table, such as + // storing the generation number in secure memory. For Details, see: + // Widevine Modular DRM Security Integration Guide for CENC optional bool anti_rollback_usage_table = 6 [default = false]; } @@ -449,6 +526,8 @@ message ClientIdentification { optional uint32 license_counter = 5; // List of non-baseline client capabilities. optional ClientCapabilities client_capabilities = 6; + // Serialized VmpData message. Optional. + optional bytes vmp_data = 7; } // EncryptedClientIdentification message used to hold ClientIdentification @@ -460,32 +539,30 @@ message EncryptedClientIdentification { // Serial number for the service certificate for which ClientIdentification is // encrypted. optional bytes service_certificate_serial_number = 2; - // Serialized ClientIdentification message, encrypted with the privacy key using - // AES-128-CBC with PKCS#5 padding. + // Serialized ClientIdentification message, encrypted with the privacy key + // using AES-128-CBC with PKCS#5 padding. optional bytes encrypted_client_id = 3; // Initialization vector needed to decrypt encrypted_client_id. optional bytes encrypted_client_id_iv = 4; - // AES-128 privacy key, encrypted with the service public public key using - // RSA-OAEP. + // AES-128 privacy key, encrypted with the service public key using RSA-OAEP. optional bytes encrypted_privacy_key = 5; } // ---------------------------------------------------------------------------- // device_certificate.proto // ---------------------------------------------------------------------------- -// Copyright 2013 Google Inc. All Rights Reserved. -// // Description: // Device certificate and certificate status list format definitions. -// Certificate definition for user devices, intermediate, service, and root +// DRM certificate definition for user devices, intermediate, service, and root // certificates. -message DeviceCertificate { +message DrmDeviceCertificate { enum CertificateType { ROOT = 0; - INTERMEDIATE = 1; - USER_DEVICE = 2; + DRM_INTERMEDIATE = 1; + DRM_USER_DEVICE = 2; SERVICE = 3; + PROVISIONING_PROVIDER = 4; } // Type of certificate. Required. @@ -509,23 +586,55 @@ message DeviceCertificate { optional string service_id = 7; } -// DeviceCertificate signed with intermediate or root certificate private key. -message SignedDeviceCertificate { - // Serialized DeviceCertificate. Required. - optional bytes device_certificate = 1; - // Signature of device_certificate. Signed with root or intermediate - // certificate private key using RSASSA-PSS. Required. - optional bytes signature = 2; - // Intermediate signing certificate. Present only for user device - // certificates. All others signed with root certificate private key. - optional SignedDeviceCertificate signer = 3; +// Contains DRM and OEM certificate status and device information for a +// specific system ID. +message DeviceCertificateStatus { + enum Status { + VALID = 0; + REVOKED = 1; + }; + + // Serial number of the intermediate DrmDeviceCertificate to which this + // message refers. Required. + optional bytes drm_serial_number = 1; + // Status of the certificate. Optional. + optional Status status = 2 [default = VALID]; + // Device model information about the device to which the intermediate + // certificate(s) correspond. + optional ProvisionedDeviceInfo device_info = 4; + // Serial number of the OEM X.509 intermediate certificate for this type + // of device. Present only if the device is OEM-provisioned. + optional bytes oem_serial_number = 5; } +// List of DeviceCertificateStatus. Used to propagate certificate revocation +// status and device information. +message DeviceCertificateStatusList { + // POSIX time, in seconds, when the list was created. Required. + optional uint32 creation_time_seconds = 1; + // DeviceCertificateStatus for each system ID. + repeated DeviceCertificateStatus certificate_status = 2; +} + +// Signed CertificateStatusList +message SignedCertificateStatusList { + // Serialized DeviceCertificateStatusList. Required. + optional bytes certificate_status_list = 1; + // Signature of certificate_status_list. Signed with root certificate private + // key using RSASSA-PSS. Required. + optional bytes signature = 2; +} + +// ---------------------------------------------------------------------------- +// provisioned_device_info.proto +// ---------------------------------------------------------------------------- +// Description: +// Provisioned device info format definitions. + // Contains device model information for a provisioned device. message ProvisionedDeviceInfo { enum WvSecurityLevel { - // Defined in "WV Modular DRM Security Integration Guide for - // Common Encryption (CENC)" + // Defined in "Widevine Security Integration Guide for DASH on Android" LEVEL_UNSPECIFIED = 0; LEVEL_1 = 1; LEVEL_2 = 2; @@ -551,49 +660,13 @@ message ProvisionedDeviceInfo { optional bool test_device = 8 [default = false]; } -// Contains the status of the root or an intermediate DeviceCertificate. -message DeviceCertificateStatus { - enum CertificateStatus { - VALID = 0; - REVOKED = 1; - }; - - // Serial number of the DeviceCertificate to which this message refers. - // Required. - optional bytes serial_number = 1; - // Status of the certificate. Optional. - optional CertificateStatus status = 2 [default = VALID]; - // Device model information about the device to which the certificate - // corresponds. Required. - optional ProvisionedDeviceInfo device_info = 4; -} - -// List of DeviceCertificateStatus. Used to propagate certificate revocation and -// update list. -message DeviceCertificateStatusList { - // POSIX time, in seconds, when the list was created. Required. - optional uint32 creation_time_seconds = 1; - // DeviceCertificateStatus for each certifificate. - repeated DeviceCertificateStatus certificate_status = 2; -} - -// Signed CertificateStatusList -message SignedCertificateStatusList { - // Serialized DeviceCertificateStatusList. Required. - optional bytes certificate_status_list = 1; - // Signature of certificate_status_list. Signed with root certificate private - // key using RSASSA-PSS. Required. - optional bytes signature = 2; -} - // ---------------------------------------------------------------------------- // widevine_header.proto // ---------------------------------------------------------------------------- -// Copyright 2016 Google Inc. All Rights Reserved. -// // Description: // Public protocol buffer definitions for Widevine Cenc Header // protocol. + message WidevineCencHeader { enum Algorithm { UNENCRYPTED = 0; @@ -630,3 +703,15 @@ message WidevineCencHeader { // 'cens' (AES-CTR subsample), 'cbcs' (AES-CBC subsample). optional uint32 protection_scheme = 9; } + +// Signed device certificate definition. +// DrmDeviceCertificate signed by a higher (CA) DRM certificate. +message SignedDrmDeviceCertificate { + // Serialized certificate. Required. + optional bytes drm_certificate = 1; + // Signature of certificate. Signed with root or intermediate + // certificate specified below. Required. + optional bytes signature = 2; + // SignedDrmDeviceCertificate used to sign this certificate. + optional SignedDrmDeviceCertificate signer = 3; +} diff --git a/libwvdrmengine/cdm/core/src/policy_engine.cpp b/libwvdrmengine/cdm/core/src/policy_engine.cpp index 416ead89..48bc6ad5 100644 --- a/libwvdrmengine/cdm/core/src/policy_engine.cpp +++ b/libwvdrmengine/cdm/core/src/policy_engine.cpp @@ -12,7 +12,7 @@ #include "wv_cdm_constants.h" #include "wv_cdm_event_listener.h" -using video_widevine_server::sdk::License; +using video_widevine::License; namespace { @@ -244,7 +244,7 @@ CdmResponseType PolicyEngine::Query(CdmQueryMap* query_response) { } (*query_response)[QUERY_KEY_LICENSE_TYPE] = - license_id_.type() == video_widevine_server::sdk::STREAMING + license_id_.type() == video_widevine::STREAMING ? QUERY_VALUE_STREAMING : QUERY_VALUE_OFFLINE; (*query_response)[QUERY_KEY_PLAY_ALLOWED] = diff --git a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp index c9836726..d62e300b 100644 --- a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp @@ -17,7 +17,7 @@ namespace wvcdm { // Protobuf generated classes. -using video_widevine_server::sdk::WidevineCencHeader; +using video_widevine::WidevineCencHeader; namespace { @@ -600,7 +600,7 @@ TEST_P(HlsConstructionTest, InitData) { if (param.success_) { WidevineCencHeader cenc_header; EXPECT_TRUE(cenc_header.ParseFromString(value)); - EXPECT_EQ(video_widevine_server::sdk::WidevineCencHeader_Algorithm_AESCTR, + EXPECT_EQ(video_widevine::WidevineCencHeader_Algorithm_AESCTR, cenc_header.algorithm()); for (size_t i = 0; i < param.key_ids_.size(); ++i) { bool key_id_found = false; @@ -701,7 +701,7 @@ TEST_P(HlsParseTest, Parse) { WidevineCencHeader cenc_header; EXPECT_TRUE(cenc_header.ParseFromString(init_data.data())); - EXPECT_EQ(video_widevine_server::sdk::WidevineCencHeader_Algorithm_AESCTR, + EXPECT_EQ(video_widevine::WidevineCencHeader_Algorithm_AESCTR, cenc_header.algorithm()); if (param.key_.compare(kJsonProvider) == 0) { EXPECT_EQ(param.value_, cenc_header.provider()); diff --git a/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp b/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp index 34ecf62b..906994b5 100644 --- a/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_keys_unittest.cpp @@ -54,12 +54,12 @@ static const KeyId ck_NO_HDCP_dual_res = "ck_NO_HDCP_dual_res"; } // namespace // protobuf generated classes. -using video_widevine_server::sdk::License; -using video_widevine_server::sdk::LicenseIdentification; -using video_widevine_server::sdk::STREAMING; -using video_widevine_server::sdk::OFFLINE; +using video_widevine::License; +using video_widevine::LicenseIdentification; +using video_widevine::STREAMING; +using video_widevine::OFFLINE; -typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer; +typedef ::video_widevine::License::KeyContainer KeyContainer; typedef KeyContainer::VideoResolutionConstraint VideoResolutionConstraint; class LicenseKeysTest : public ::testing::Test { diff --git a/libwvdrmengine/cdm/core/test/license_unittest.cpp b/libwvdrmengine/cdm/core/test/license_unittest.cpp index 11f88504..553184ae 100644 --- a/libwvdrmengine/cdm/core/test/license_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/license_unittest.cpp @@ -110,10 +110,10 @@ class MockInitializationData : public InitializationData { } // namespace // Protobuf generated classes -using video_widevine_server::sdk::LicenseRequest_ContentIdentification; -using video_widevine_server::sdk::ClientIdentification; -using video_widevine_server::sdk::LicenseRequest; -using video_widevine_server::sdk::SignedMessage; +using video_widevine::LicenseRequest_ContentIdentification; +using video_widevine::ClientIdentification; +using video_widevine::LicenseRequest; +using video_widevine::SignedMessage; // gmock methods using ::testing::_; @@ -230,15 +230,15 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { // Verify Client Identification const ClientIdentification& client_id = license_request.client_id(); - EXPECT_EQ(video_widevine_server::sdk:: - ClientIdentification_TokenType_DEVICE_CERTIFICATE, + EXPECT_EQ(video_widevine:: + ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE, client_id.type()); EXPECT_TRUE(std::equal(client_id.token().begin(), client_id.token().end(), kToken.begin())); EXPECT_LT(0, client_id.client_info_size()); for (int i = 0; i < client_id.client_info_size(); ++i) { - const ::video_widevine_server::sdk::ClientIdentification_NameValue& + const ::video_widevine::ClientIdentification_NameValue& name_value = client_id.client_info(i); EXPECT_TRUE(!name_value.name().empty()); EXPECT_TRUE(!name_value.value().empty()); @@ -247,12 +247,12 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { EXPECT_FALSE(client_id.has_provider_client_token()); EXPECT_FALSE(client_id.has_license_counter()); - const ::video_widevine_server::sdk::ClientIdentification_ClientCapabilities& + const ::video_widevine::ClientIdentification_ClientCapabilities& client_capabilities = client_id.client_capabilities(); EXPECT_FALSE(client_capabilities.has_client_token()); EXPECT_TRUE(client_capabilities.has_session_token()); EXPECT_FALSE(client_capabilities.video_resolution_constraints()); - EXPECT_EQ(video_widevine_server::sdk:: + EXPECT_EQ(video_widevine:: ClientIdentification_ClientCapabilities_HdcpVersion_HDCP_V2_1, client_capabilities.max_hdcp_version()); EXPECT_EQ(crypto_session_api_version, @@ -261,23 +261,23 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) { // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_request.content_id(); - EXPECT_TRUE(content_id.has_cenc_id()); - EXPECT_FALSE(content_id.has_webm_id()); - EXPECT_FALSE(content_id.has_license()); + EXPECT_TRUE(content_id.has_cenc_id_deprecated()); + EXPECT_FALSE(content_id.has_webm_id_deprecated()); + EXPECT_FALSE(content_id.has_existing_license()); - const ::video_widevine_server::sdk::LicenseRequest_ContentIdentification_CENC& - cenc_id = content_id.cenc_id(); + const ::video_widevine::LicenseRequest_ContentIdentification_CencDeprecated& + cenc_id = content_id.cenc_id_deprecated(); EXPECT_TRUE(std::equal(cenc_id.pssh(0).begin(), cenc_id.pssh(0).end(), kCencPssh.begin())); - EXPECT_EQ(video_widevine_server::sdk::STREAMING, cenc_id.license_type()); + EXPECT_EQ(video_widevine::STREAMING, cenc_id.license_type()); EXPECT_TRUE(std::equal(cenc_id.request_id().begin(), cenc_id.request_id().end(), kCryptoRequestId.begin())); // Verify other license request fields - EXPECT_EQ(::video_widevine_server::sdk::LicenseRequest_RequestType_NEW, + EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_NEW, license_request.type()); EXPECT_EQ(kLicenseStartTime, license_request.request_time()); - EXPECT_EQ(video_widevine_server::sdk::VERSION_2_1, + EXPECT_EQ(video_widevine::VERSION_2_1, license_request.protocol_version()); EXPECT_EQ(kNonce, license_request.key_control_nonce()); } diff --git a/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp b/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp index ac322b18..cd0d0e72 100644 --- a/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/policy_engine_constraints_unittest.cpp @@ -11,17 +11,17 @@ #include "wv_cdm_types.h" // protobuf generated classes. -using video_widevine_server::sdk::License; -using video_widevine_server::sdk::License_Policy; -using video_widevine_server::sdk::STREAMING; +using video_widevine::License; +using video_widevine::License_Policy; +using video_widevine::STREAMING; namespace wvcdm { -typedef ::video_widevine_server::sdk::License License; -typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer; -typedef ::video_widevine_server::sdk::License::KeyContainer::OutputProtection +typedef ::video_widevine::License License; +typedef ::video_widevine::License::KeyContainer KeyContainer; +typedef ::video_widevine::License::KeyContainer::OutputProtection OutputProtection; -typedef ::video_widevine_server::sdk::License::KeyContainer:: +typedef ::video_widevine::License::KeyContainer:: VideoResolutionConstraint VideoResolutionConstraint; typedef ::google::protobuf::RepeatedPtrField KeyList; typedef ::google::protobuf::RepeatedPtrField diff --git a/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp b/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp index 54253a78..2c828cf7 100644 --- a/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp @@ -65,11 +65,11 @@ class MockCdmEventListener : public WvCdmEventListener { } // namespace // protobuf generated classes. -using video_widevine_server::sdk::License; -using video_widevine_server::sdk::License_Policy; -using video_widevine_server::sdk::LicenseIdentification; -using video_widevine_server::sdk::STREAMING; -using video_widevine_server::sdk::OFFLINE; +using video_widevine::License; +using video_widevine::License_Policy; +using video_widevine::LicenseIdentification; +using video_widevine::STREAMING; +using video_widevine::OFFLINE; // gmock methods using ::testing::_; diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 03a08f76..6b2a1b2f 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -188,10 +188,11 @@ using ::testing::StrNe; namespace wvcdm { // Protobuf generated classes -using video_widevine_server::sdk::LicenseIdentification; -using video_widevine_server::sdk::LicenseRequest_ContentIdentification; -using video_widevine_server::sdk::ClientIdentification; -using video_widevine_server::sdk::SignedMessage; +using video_widevine::LicenseIdentification; +using video_widevine::LicenseRequest_ContentIdentification; +using video_widevine::LicenseRequest_ContentIdentification_CencDeprecated; +using video_widevine::ClientIdentification; +using video_widevine::SignedMessage; class TestWvCdmClientPropertySet : public CdmClientPropertySet { public: @@ -460,7 +461,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { return; } - void ValidateResponse(video_widevine_server::sdk::LicenseType license_type, + void ValidateResponse(video_widevine::LicenseType license_type, bool has_provider_session_token) { // Validate signed response SignedMessage signed_message; @@ -470,7 +471,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license - video_widevine_server::sdk::License license; + video_widevine::License license; EXPECT_TRUE(license.ParseFromString(signed_message.msg())); // Verify license identification @@ -491,18 +492,18 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license request - video_widevine_server::sdk::LicenseRequest license_renewal; + video_widevine::LicenseRequest license_renewal; EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg())); // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_renewal.content_id(); - EXPECT_FALSE(content_id.has_cenc_id()); - EXPECT_FALSE(content_id.has_webm_id()); - EXPECT_TRUE(content_id.has_license()); + EXPECT_FALSE(content_id.has_cenc_id_deprecated()); + EXPECT_FALSE(content_id.has_webm_id_deprecated()); + EXPECT_TRUE(content_id.has_existing_license()); const LicenseRequest_ContentIdentification::ExistingLicense& - existing_license = content_id.license(); + existing_license = content_id.existing_license(); const LicenseIdentification& id = existing_license.license_id(); EXPECT_EQ(license_id_.request_id(), id.request_id()); @@ -518,10 +519,10 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { expected_seconds_since_last_played, kClockTolerance); EXPECT_TRUE(existing_license.session_usage_table_entry().empty()); - EXPECT_EQ(::video_widevine_server::sdk::LicenseRequest_RequestType_RENEWAL, + EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_RENEWAL, license_renewal.type()); EXPECT_LT(0, license_renewal.request_time()); - EXPECT_EQ(video_widevine_server::sdk::VERSION_2_1, + EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version()); EXPECT_TRUE(license_renewal.has_key_control_nonce()); } @@ -538,18 +539,18 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license request - video_widevine_server::sdk::LicenseRequest license_renewal; + video_widevine::LicenseRequest license_renewal; EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg())); // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_renewal.content_id(); - EXPECT_FALSE(content_id.has_cenc_id()); - EXPECT_FALSE(content_id.has_webm_id()); - EXPECT_TRUE(content_id.has_license()); + EXPECT_FALSE(content_id.has_cenc_id_deprecated()); + EXPECT_FALSE(content_id.has_webm_id_deprecated()); + EXPECT_TRUE(content_id.has_existing_license()); const LicenseRequest_ContentIdentification::ExistingLicense& - existing_license = content_id.license(); + existing_license = content_id.existing_license(); const LicenseIdentification& id = existing_license.license_id(); EXPECT_EQ(license_id_.request_id(), id.request_id()); @@ -598,10 +599,10 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { EXPECT_NEAR(seconds_since_last_decrypt, expected_seconds_since_last_playback, kClockTolerance); - EXPECT_EQ(::video_widevine_server::sdk::LicenseRequest_RequestType_RELEASE, + EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_RELEASE, license_renewal.type()); EXPECT_LT(0, license_renewal.request_time()); - EXPECT_EQ(video_widevine_server::sdk::VERSION_2_1, + EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version()); EXPECT_TRUE(license_renewal.has_key_control_nonce()); } @@ -678,7 +679,7 @@ class WvCdmExtendedDurationTest : public WvCdmTestBase { CdmKeyResponse key_response_; CdmSessionId session_id_; CdmKeySetId key_set_id_; - video_widevine_server::sdk::LicenseIdentification license_id_; + video_widevine::LicenseIdentification license_id_; }; TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRequestTest) { @@ -696,18 +697,18 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRequestTest) { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license request - video_widevine_server::sdk::LicenseRequest license_request; + video_widevine::LicenseRequest license_request; EXPECT_TRUE(license_request.ParseFromString(signed_message.msg())); // Verify Client Identification const ClientIdentification& client_id = license_request.client_id(); - EXPECT_EQ(video_widevine_server::sdk:: - ClientIdentification_TokenType_DEVICE_CERTIFICATE, + EXPECT_EQ(video_widevine:: + ClientIdentification_TokenType_DRM_DEVICE_CERTIFICATE, client_id.type()); EXPECT_LT(0, client_id.client_info_size()); for (int i = 0; i < client_id.client_info_size(); ++i) { - const ::video_widevine_server::sdk::ClientIdentification_NameValue& + const ::video_widevine::ClientIdentification_NameValue& name_value = client_id.client_info(i); EXPECT_TRUE(!name_value.name().empty()); EXPECT_TRUE(!name_value.value().empty()); @@ -727,22 +728,22 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRequestTest) { // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_request.content_id(); - EXPECT_TRUE(content_id.has_cenc_id()); - EXPECT_FALSE(content_id.has_webm_id()); - EXPECT_FALSE(content_id.has_license()); + EXPECT_TRUE(content_id.has_cenc_id_deprecated()); + EXPECT_FALSE(content_id.has_webm_id_deprecated()); + EXPECT_FALSE(content_id.has_existing_license()); - const LicenseRequest_ContentIdentification::CENC& cenc_id = - content_id.cenc_id(); + const LicenseRequest_ContentIdentification_CencDeprecated& cenc_id = + content_id.cenc_id_deprecated(); EXPECT_TRUE(std::equal(cenc_id.pssh(0).begin(), cenc_id.pssh(0).end(), g_key_id.begin() + 32)); - EXPECT_EQ(video_widevine_server::sdk::STREAMING, cenc_id.license_type()); + EXPECT_EQ(video_widevine::STREAMING, cenc_id.license_type()); EXPECT_TRUE(cenc_id.has_request_id()); // Verify other license request fields - EXPECT_EQ(::video_widevine_server::sdk::LicenseRequest_RequestType_NEW, + EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_NEW, license_request.type()); EXPECT_LT(0, license_request.request_time()); - EXPECT_EQ(video_widevine_server::sdk::VERSION_2_1, + EXPECT_EQ(video_widevine::VERSION_2_1, license_request.protocol_version()); EXPECT_TRUE(license_request.has_key_control_nonce()); @@ -763,14 +764,14 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license - video_widevine_server::sdk::License license; + video_widevine::License license; EXPECT_TRUE(license.ParseFromString(signed_message.msg())); // Verify license identification - video_widevine_server::sdk::LicenseIdentification license_id = license.id(); + video_widevine::LicenseIdentification license_id = license.id(); EXPECT_LT(0u, license_id.request_id().size()); EXPECT_LT(0u, license_id.session_id().size()); - EXPECT_EQ(video_widevine_server::sdk::STREAMING, license_id.type()); + EXPECT_EQ(video_widevine::STREAMING, license_id.type()); EXPECT_FALSE(license_id.has_provider_session_token()); // Create renewal request @@ -787,7 +788,7 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license request - video_widevine_server::sdk::LicenseRequest license_renewal; + video_widevine::LicenseRequest license_renewal; EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg())); // Client Identification not filled in in renewal @@ -795,12 +796,12 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) { // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_renewal.content_id(); - EXPECT_FALSE(content_id.has_cenc_id()); - EXPECT_FALSE(content_id.has_webm_id()); - EXPECT_TRUE(content_id.has_license()); + EXPECT_FALSE(content_id.has_cenc_id_deprecated()); + EXPECT_FALSE(content_id.has_webm_id_deprecated()); + EXPECT_TRUE(content_id.has_existing_license()); const LicenseRequest_ContentIdentification::ExistingLicense& - existing_license = content_id.license(); + existing_license = content_id.existing_license(); const LicenseIdentification& id = existing_license.license_id(); EXPECT_EQ(license_id.request_id(), id.request_id()); @@ -814,10 +815,10 @@ TEST_F(WvCdmExtendedDurationTest, VerifyLicenseRenewalTest) { EXPECT_EQ(0, existing_license.seconds_since_last_played()); EXPECT_TRUE(existing_license.session_usage_table_entry().empty()); - EXPECT_EQ(::video_widevine_server::sdk::LicenseRequest_RequestType_RENEWAL, + EXPECT_EQ(::video_widevine::LicenseRequest_RequestType_RENEWAL, license_renewal.type()); EXPECT_LT(0, license_renewal.request_time()); - EXPECT_EQ(video_widevine_server::sdk::VERSION_2_1, + EXPECT_EQ(video_widevine::VERSION_2_1, license_renewal.protocol_version()); EXPECT_TRUE(license_renewal.has_key_control_nonce()); @@ -959,7 +960,7 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) { GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); VerifyKeyRequestResponse(g_license_server, g_client_auth, false); - ValidateResponse(video_widevine_server::sdk::STREAMING, false); + ValidateResponse(video_widevine::STREAMING, false); int64_t initial_license_duration_remaining = 0; int64_t initial_playback_duration_remaining = 0; @@ -1033,7 +1034,7 @@ TEST_P(WvCdmStreamingPstTest, UsageTest) { GenerateKeyRequest(kStreamingClip1PstInitData, kLicenseTypeStreaming); VerifyKeyRequestResponse(g_license_server, g_client_auth, false); - ValidateResponse(video_widevine_server::sdk::STREAMING, true); + ValidateResponse(video_widevine::STREAMING, true); int64_t initial_license_duration_remaining = 0; int64_t initial_playback_duration_remaining = 0; @@ -1098,7 +1099,7 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) { GenerateKeyRequest(kStreamingClip1PstInitData, kLicenseTypeStreaming); VerifyKeyRequestResponse(g_license_server, g_client_auth, false); - ValidateResponse(video_widevine_server::sdk::STREAMING, true); + ValidateResponse(video_widevine::STREAMING, true); int64_t initial_license_duration_remaining = 0; int64_t initial_playback_duration_remaining = 0; @@ -1194,7 +1195,7 @@ TEST_P(WvCdmOfflineUsageReportTest, UsageTest) { GenerateKeyRequest(kOfflineClip2PstInitData, kLicenseTypeOffline); VerifyKeyRequestResponse(g_license_server, g_client_auth, false); - ValidateResponse(video_widevine_server::sdk::OFFLINE, true); + ValidateResponse(video_widevine::OFFLINE, true); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 019966fe..bc949440 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -51,8 +51,8 @@ const int kHttpInternalServerError = 500; const char kOrigin[] = "com.example"; // Protobuf generated classes -using video_widevine_server::sdk::LicenseIdentification; -using video_widevine_server::sdk::LicenseRequest_ContentIdentification; +using video_widevine::LicenseIdentification; +using video_widevine::LicenseRequest_ContentIdentification; // Default license server, can be configured using --server command line option // Default key id (pssh), can be configured using --keyid command line option @@ -415,7 +415,7 @@ UsageInfoSubSampleInfo usage_info_sub_sample_info[] = { {&usage_info_sub_samples_icp[0], 3, wvcdm::kLevel3, "other app id"}}; struct RenewWithClientIdTestConfiguration { - bool renew_with_client_id; + bool always_include_client_id; bool specify_app_parameters; bool enable_privacy_mode; bool specify_service_certificate; @@ -869,9 +869,9 @@ HlsDecryptionInfo kHlsFourCCBackwardCompatibilityTestVectors[] = { namespace wvcdm { // Protobuf generated classes -using video_widevine_server::sdk::ClientIdentification; -using video_widevine_server::sdk::ClientIdentification_NameValue; -using video_widevine_server::sdk::SignedMessage; +using video_widevine::ClientIdentification; +using video_widevine::ClientIdentification_NameValue; +using video_widevine::SignedMessage; class TestWvCdmClientPropertySet : public CdmClientPropertySet { public: @@ -1761,18 +1761,18 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) { EXPECT_TRUE(!signed_message.msg().empty()); // Verify license request - video_widevine_server::sdk::LicenseRequest license_renewal; + video_widevine::LicenseRequest license_renewal; EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg())); // Verify Content Identification const LicenseRequest_ContentIdentification& content_id = license_renewal.content_id(); - EXPECT_FALSE(content_id.has_cenc_id()); - EXPECT_FALSE(content_id.has_webm_id()); - EXPECT_TRUE(content_id.has_license()); + EXPECT_FALSE(content_id.has_cenc_id_deprecated()); + EXPECT_FALSE(content_id.has_webm_id_deprecated()); + EXPECT_TRUE(content_id.has_existing_license()); const LicenseRequest_ContentIdentification::ExistingLicense& - existing_license = content_id.license(); + existing_license = content_id.existing_license(); EXPECT_TRUE(existing_license.license_id().provider_session_token().empty()); EXPECT_TRUE(existing_license.session_usage_table_entry().empty()); } @@ -2055,7 +2055,7 @@ class WvCdmStreamingLicenseRenewalTest TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) { RenewWithClientIdTestConfiguration* config = GetParam(); std::string key_id; - if (config->renew_with_client_id) { + if (config->always_include_client_id) { key_id = a2bs_hex( "000000427073736800000000" // blob size and pssh "EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id @@ -2105,13 +2105,13 @@ TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) { EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description; // Verify license request - video_widevine_server::sdk::License license; + video_widevine::License license; EXPECT_TRUE(license.ParseFromString(signed_message.msg())) << config->test_description; - // Verify renew_with_client_id - EXPECT_EQ(config->renew_with_client_id, - license.policy().has_renew_with_client_id()); + // Verify always_include_client_id + EXPECT_EQ(config->always_include_client_id, + license.policy().has_always_include_client_id()); std::string license_server; CdmKeyMessage key_msg; @@ -2127,12 +2127,12 @@ TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) { EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description; // Verify license request - video_widevine_server::sdk::LicenseRequest license_renewal; + video_widevine::LicenseRequest license_renewal; EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg())) << config->test_description; // Verify ClientId - EXPECT_EQ(config->renew_with_client_id && !config->enable_privacy_mode, + EXPECT_EQ(config->always_include_client_id && !config->enable_privacy_mode, license_renewal.has_client_id()) << config->test_description; @@ -2153,7 +2153,7 @@ TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) { } if (config->enable_privacy_mode) { - EXPECT_EQ(config->renew_with_client_id, + EXPECT_EQ(config->always_include_client_id, license_renewal.has_encrypted_client_id()) << config->test_description; EXPECT_NE( @@ -2183,7 +2183,7 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) { std::string client_auth; GetOfflineConfiguration(&key_id, &client_auth); - if (config->renew_with_client_id) { + if (config->always_include_client_id) { key_id = a2bs_hex( "00000040" // blob size "70737368" // "pssh" @@ -2233,13 +2233,13 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) { EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description; // Verify license request - video_widevine_server::sdk::License license; + video_widevine::License license; EXPECT_TRUE(license.ParseFromString(signed_message.msg())) << config->test_description; - // Verify renew_with_client_id - EXPECT_EQ(config->renew_with_client_id, - license.policy().has_renew_with_client_id()); + // Verify always_include_client_id + EXPECT_EQ(config->always_include_client_id, + license.policy().has_always_include_client_id()); CdmKeySetId key_set_id = key_set_id_; EXPECT_TRUE(key_set_id_.size() > 0); @@ -2268,12 +2268,12 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) { EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description; // Verify license request - video_widevine_server::sdk::LicenseRequest license_release; + video_widevine::LicenseRequest license_release; EXPECT_TRUE(license_release.ParseFromString(signed_message.msg())) << config->test_description; // Verify ClientId - EXPECT_EQ(config->renew_with_client_id && !config->enable_privacy_mode, + EXPECT_EQ(config->always_include_client_id && !config->enable_privacy_mode, license_release.has_client_id()) << config->test_description; @@ -2294,7 +2294,7 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) { } if (config->enable_privacy_mode) { - EXPECT_EQ(config->renew_with_client_id, + EXPECT_EQ(config->always_include_client_id, license_release.has_encrypted_client_id()) << config->test_description; EXPECT_NE( @@ -2330,7 +2330,7 @@ TEST_P(WvCdmUsageTest, WithClientId) { RenewWithClientIdTestConfiguration* config = GetParam(); std::string key_id; - if (config->renew_with_client_id) { + if (config->always_include_client_id) { key_id = a2bs_hex( // streaming_clip20 "000000427073736800000000" // blob size and pssh "EDEF8BA979D64ACEA3C827DCD51D21ED00000023" // Widevine system id @@ -2367,13 +2367,13 @@ TEST_P(WvCdmUsageTest, WithClientId) { EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description; // Verify license request - video_widevine_server::sdk::License license; + video_widevine::License license; EXPECT_TRUE(license.ParseFromString(signed_message.msg())) << config->test_description; - // Verify renew_with_client_id - EXPECT_EQ(config->renew_with_client_id, - license.policy().has_renew_with_client_id()); + // Verify always_include_client_id + EXPECT_EQ(config->always_include_client_id, + license.policy().has_always_include_client_id()); EXPECT_FALSE(license.id().provider_session_token().empty()); @@ -2406,17 +2406,17 @@ TEST_P(WvCdmUsageTest, WithClientId) { EXPECT_TRUE(!signed_message.msg().empty()) << config->test_description; // Verify license request - video_widevine_server::sdk::LicenseRequest license_renewal; + video_widevine::LicenseRequest license_renewal; EXPECT_TRUE(license_renewal.ParseFromString(signed_message.msg())) << config->test_description; // Verify ClientId - EXPECT_EQ(config->renew_with_client_id && !config->enable_privacy_mode, + EXPECT_EQ(config->always_include_client_id && !config->enable_privacy_mode, license_renewal.has_client_id()) << config->test_description; if (config->enable_privacy_mode) { - EXPECT_EQ(config->renew_with_client_id, + EXPECT_EQ(config->always_include_client_id, license_renewal.has_encrypted_client_id()) << config->test_description; EXPECT_NE( From 826c91ba268e2b2429e4408857eb618cd4ea99ac Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 16 Jan 2017 18:17:01 -0800 Subject: [PATCH 2/2] Add License::Policy::play_start_grace_period_seconds [ Merge of http://go/wvgerrit/22565 ] When using the grace period, the CDM will need to override the values given to use by the TEE (through OEMCrypto). Normally the first (and last) decrypt times are stored securely by the TEE. To avoid extra complexity in OEMCrypto, we will simply ignore the values given to us by the TEE when using this feature. However, the TEE will still enforce the (hard) license duration. So only the rental/playback durations will be affected by malicious editing of files. b/34211676 Test: Reran unittests including newly added tests. All tests other than some oemcrypto, request_license_test passed. Those tests failed with or without this CL. Change-Id: I6d7b5bfb669fd8603b474b68c2f7175b0c30901d --- .../cdm/core/include/device_files.h | 3 +- libwvdrmengine/cdm/core/include/license.h | 3 +- .../cdm/core/include/policy_engine.h | 18 ++- libwvdrmengine/cdm/core/src/cdm_session.cpp | 9 +- libwvdrmengine/cdm/core/src/device_files.cpp | 8 +- .../cdm/core/src/device_files.proto | 4 + libwvdrmengine/cdm/core/src/license.cpp | 5 +- libwvdrmengine/cdm/core/src/policy_engine.cpp | 48 ++++-- .../cdm/core/test/device_files_unittest.cpp | 70 +++++---- .../cdm/core/test/policy_engine_unittest.cpp | 140 +++++++++++++++++- 10 files changed, 252 insertions(+), 56 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 6eef4ee7..40ae4d2b 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -53,6 +53,7 @@ class DeviceFiles { const std::string& release_server_url, int64_t playback_start_time, int64_t last_playback_time, + int64_t grace_period_end_time, const CdmAppParameterMap& app_parameters); virtual bool RetrieveLicense( const std::string& key_set_id, LicenseState* state, @@ -60,7 +61,7 @@ class DeviceFiles { CdmKeyResponse* key_response, CdmKeyMessage* key_renewal_request, CdmKeyResponse* key_renewal_response, std::string* release_server_url, int64_t* playback_start_time, int64_t* last_playback_time, - CdmAppParameterMap* app_parameters); + int64_t* grace_period_end_time, CdmAppParameterMap* app_parameters); virtual bool DeleteLicense(const std::string& key_set_id); virtual bool DeleteAllFiles(); virtual bool DeleteAllLicenses(); diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 6166dee7..486ba8f0 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -44,7 +44,8 @@ class CdmLicense { const CdmKeyMessage& license_request, const CdmKeyResponse& license_response, const CdmKeyResponse& license_renewal_response, - int64_t playback_start_time, int64_t last_playback_time); + int64_t playback_start_time, int64_t last_playback_time, + int64_t grace_period_end_time); virtual bool RestoreLicenseForRelease(const CdmKeyMessage& license_request, const CdmKeyResponse& license_response); virtual bool HasInitData() { return stored_init_data_.get(); } diff --git a/libwvdrmengine/cdm/core/include/policy_engine.h b/libwvdrmengine/cdm/core/include/policy_engine.h index b24a72a6..6cd9aad1 100644 --- a/libwvdrmengine/cdm/core/include/policy_engine.h +++ b/libwvdrmengine/cdm/core/include/policy_engine.h @@ -80,11 +80,19 @@ class PolicyEngine { // for offline save and restore int64_t GetPlaybackStartTime() { return playback_start_time_; } int64_t GetLastPlaybackTime() { return last_playback_time_; } + int64_t GetGracePeriodEndTime() { return grace_period_end_time_; } void RestorePlaybackTimes(int64_t playback_start_time, - int64_t last_playback_time); + int64_t last_playback_time, + int64_t grace_period_end_time); bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; } - bool HasPlaybackStarted() { return playback_start_time_ > 0; } + bool HasPlaybackStarted(int64_t current_time) { + if (playback_start_time_ == 0) + return false; + + const int64_t playback_time = current_time - playback_start_time_; + return playback_time >= policy_.play_start_grace_period_seconds(); + } bool HasLicenseOrPlaybackDurationExpired(int64_t current_time); int64_t GetLicenseOrPlaybackDurationRemaining(); @@ -119,7 +127,8 @@ class PolicyEngine { int64_t GetRentalExpiryTime(); // Gets the clock time that the license expires based on whether we have // started playing. This takes into account GetHardLicenseExpiryTime. - int64_t GetExpiryTime(bool ignore_soft_enforce_playback_duration); + int64_t GetExpiryTime(int64_t current_time, + bool ignore_soft_enforce_playback_duration); int64_t GetLicenseOrRentalDurationRemaining(int64_t current_time); int64_t GetPlaybackDurationRemaining(int64_t current_time); @@ -136,7 +145,7 @@ class PolicyEngine { // Notifies updates in expiry time and fire OnExpirationUpdate event if // expiry time changes. - void NotifyExpirationUpdate(); + void NotifyExpirationUpdate(int64_t current_time); // set_clock() is for testing only. It alters ownership of the // passed-in pointer. @@ -160,6 +169,7 @@ class PolicyEngine { int64_t playback_start_time_; int64_t last_playback_time_; int64_t last_expiry_time_; + int64_t grace_period_end_time_; bool last_expiry_time_set_; bool was_expired_on_load_; diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index d176ec19..0c2bf2a2 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -129,12 +129,14 @@ CdmResponseType CdmSession::RestoreOfflineSession( DeviceFiles::LicenseState license_state; int64_t playback_start_time; int64_t last_playback_time; + int64_t grace_period_end_time; if (!file_handle_->RetrieveLicense( key_set_id, &license_state, &offline_init_data_, &key_request_, &key_response_, &offline_key_renewal_request_, &offline_key_renewal_response_, &offline_release_server_url_, - &playback_start_time, &last_playback_time, &app_parameters_)) { + &playback_start_time, &last_playback_time, &grace_period_end_time, + &app_parameters_)) { LOGE("CdmSession::Init failed to retrieve license. key set id = %s", key_set_id.c_str()); return GET_LICENSE_ERROR; @@ -156,7 +158,7 @@ CdmResponseType CdmSession::RestoreOfflineSession( } else { if (!license_parser_->RestoreOfflineLicense( key_request_, key_response_, offline_key_renewal_response_, - playback_start_time, last_playback_time)) { + playback_start_time, last_playback_time, grace_period_end_time)) { return RESTORE_OFFLINE_LICENSE_ERROR_2; } } @@ -568,7 +570,8 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) { key_set_id_, state, offline_init_data_, key_request_, key_response_, offline_key_renewal_request_, offline_key_renewal_response_, offline_release_server_url_, policy_engine_->GetPlaybackStartTime(), - policy_engine_->GetLastPlaybackTime(), app_parameters_); + policy_engine_->GetLastPlaybackTime(), + policy_engine_->GetGracePeriodEndTime(), app_parameters_); } CdmResponseType CdmSession::ReleaseCrypto() { diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index 76a64148..7f760886 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -168,7 +168,8 @@ bool DeviceFiles::StoreLicense( const CdmKeyMessage& license_renewal_request, const CdmKeyResponse& license_renewal, const std::string& release_server_url, int64_t playback_start_time, - int64_t last_playback_time, const CdmAppParameterMap& app_parameters) { + int64_t last_playback_time, int64_t grace_period_end_time, + const CdmAppParameterMap& app_parameters) { if (!initialized_) { LOGW("DeviceFiles::StoreLicense: not initialized"); return false; @@ -201,6 +202,7 @@ bool DeviceFiles::StoreLicense( license->set_release_server_url(release_server_url); license->set_playback_start_time(playback_start_time); license->set_last_playback_time(last_playback_time); + license->set_grace_period_end_time(grace_period_end_time); NameValue* app_params; for (CdmAppParameterMap::const_iterator iter = app_parameters.begin(); iter != app_parameters.end(); ++iter) { @@ -221,7 +223,8 @@ bool DeviceFiles::RetrieveLicense( CdmKeyMessage* license_request, CdmKeyResponse* license_message, CdmKeyMessage* license_renewal_request, CdmKeyResponse* license_renewal, std::string* release_server_url, int64_t* playback_start_time, - int64_t* last_playback_time, CdmAppParameterMap* app_parameters) { + int64_t* last_playback_time, int64_t* grace_period_end_time, + CdmAppParameterMap* app_parameters) { if (!initialized_) { LOGW("DeviceFiles::RetrieveLicense: not initialized"); return false; @@ -270,6 +273,7 @@ bool DeviceFiles::RetrieveLicense( *release_server_url = license.release_server_url(); *playback_start_time = license.playback_start_time(); *last_playback_time = license.last_playback_time(); + *grace_period_end_time = license.grace_period_end_time(); for (int i = 0; i < license.app_parameters_size(); ++i) { (*app_parameters)[license.app_parameters(i).name()] = license.app_parameters(i).value(); diff --git a/libwvdrmengine/cdm/core/src/device_files.proto b/libwvdrmengine/cdm/core/src/device_files.proto index 89bd0c5e..eef367d6 100644 --- a/libwvdrmengine/cdm/core/src/device_files.proto +++ b/libwvdrmengine/cdm/core/src/device_files.proto @@ -39,6 +39,10 @@ message License { optional int64 playback_start_time = 8 [default = 0]; optional int64 last_playback_time = 9 [default = 0]; repeated NameValue app_parameters = 10; + // This will be 0/missing if the grace period has not expired; otherwise it + // contains the playback_start_time we should use as an override. This is + // ignored if there is no grace period. + optional int64 grace_period_end_time = 11 [default = 0]; } message UsageInfo { diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index e2afa55f..42bc7fcf 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -674,7 +674,7 @@ bool CdmLicense::RestoreOfflineLicense( const CdmKeyMessage& license_request, const CdmKeyResponse& license_response, const CdmKeyResponse& license_renewal_response, int64_t playback_start_time, - int64_t last_playback_time) { + int64_t last_playback_time, int64_t grace_period_end_time) { if (license_request.empty() || license_response.empty()) { LOGE( "CdmLicense::RestoreOfflineLicense: key_request or response empty: " @@ -742,7 +742,8 @@ bool CdmLicense::RestoreOfflineLicense( } } - policy_engine_->RestorePlaybackTimes(playback_start_time, last_playback_time); + policy_engine_->RestorePlaybackTimes(playback_start_time, last_playback_time, + grace_period_end_time); return true; } diff --git a/libwvdrmengine/cdm/core/src/policy_engine.cpp b/libwvdrmengine/cdm/core/src/policy_engine.cpp index 48bc6ad5..d4633b3b 100644 --- a/libwvdrmengine/cdm/core/src/policy_engine.cpp +++ b/libwvdrmengine/cdm/core/src/policy_engine.cpp @@ -31,6 +31,7 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id, playback_start_time_(0), last_playback_time_(0), last_expiry_time_(0), + grace_period_end_time_(0), last_expiry_time_set_(false), was_expired_on_load_(false), next_renewal_time_(0), @@ -78,6 +79,12 @@ void PolicyEngine::CheckDevice(int64_t current_time) { void PolicyEngine::OnTimerEvent() { int64_t current_time = clock_->GetCurrentTime(); + // If we have passed the grace period, the expiration will update. + if (grace_period_end_time_ == 0 && HasPlaybackStarted(current_time)) { + grace_period_end_time_ = playback_start_time_; + NotifyExpirationUpdate(current_time); + } + // License expiration trumps all. if (HasLicenseOrPlaybackDurationExpired(current_time) && license_state_ != kLicenseStateExpired) { @@ -195,7 +202,7 @@ void PolicyEngine::UpdateLicense(const License& license) { license_state_ = kLicenseStatePending; NotifyKeysChange(kKeyStatusPending); } - NotifyExpirationUpdate(); + NotifyExpirationUpdate(current_time); } void PolicyEngine::BeginDecryption() { @@ -206,11 +213,13 @@ void PolicyEngine::BeginDecryption() { case kLicenseStateWaitingLicenseUpdate: playback_start_time_ = clock_->GetCurrentTime(); last_playback_time_ = playback_start_time_; + if (policy_.play_start_grace_period_seconds() == 0) + grace_period_end_time_ = playback_start_time_; if (policy_.renew_with_usage()) { license_state_ = kLicenseStateNeedRenewal; } - NotifyExpirationUpdate(); + NotifyExpirationUpdate(playback_start_time_); break; case kLicenseStateInitial: case kLicenseStatePending: @@ -290,26 +299,38 @@ bool PolicyEngine::GetSecondsSinceLastPlayed( } int64_t PolicyEngine::GetLicenseOrPlaybackDurationRemaining() { - int64_t current_time = clock_->GetCurrentTime(); + const int64_t current_time = clock_->GetCurrentTime(); const int64_t expiry_time = - GetExpiryTime(/* ignore_soft_enforce_playback_duration */ false); + GetExpiryTime(current_time, + /* ignore_soft_enforce_playback_duration */ false); if (expiry_time == NEVER_EXPIRES) return LLONG_MAX; if (expiry_time < current_time) return 0; return expiry_time - current_time; } void PolicyEngine::RestorePlaybackTimes(int64_t playback_start_time, - int64_t last_playback_time) { + int64_t last_playback_time, + int64_t grace_period_end_time) { playback_start_time_ = (playback_start_time > 0) ? playback_start_time : 0; last_playback_time_ = (last_playback_time > 0) ? last_playback_time : 0; + grace_period_end_time_ = grace_period_end_time; + + if (policy_.play_start_grace_period_seconds() != 0) { + // If we are using grace period, we may need to override some of the values + // given to us by OEMCrypto. |grace_period_end_time| will be 0 if the grace + // period has not expired (effectively playback has not begun). Otherwise, + // |grace_period_end_time| contains the playback start time we should use. + playback_start_time_ = grace_period_end_time; + } const int64_t current_time = clock_->GetCurrentTime(); const int64_t expiry_time = - GetExpiryTime(/* ignore_soft_enforce_playback_duration */ true); + GetExpiryTime(current_time, + /* ignore_soft_enforce_playback_duration */ true); was_expired_on_load_ = expiry_time != NEVER_EXPIRES && expiry_time < current_time; - NotifyExpirationUpdate(); + NotifyExpirationUpdate(current_time); } void PolicyEngine::UpdateRenewalRequest(int64_t current_time) { @@ -319,8 +340,9 @@ void PolicyEngine::UpdateRenewalRequest(int64_t current_time) { bool PolicyEngine::HasLicenseOrPlaybackDurationExpired(int64_t current_time) { const int64_t expiry_time = - GetExpiryTime(/* ignore_soft_enforce_playback_duration */ false); - return (expiry_time != NEVER_EXPIRES) && expiry_time <= current_time; + GetExpiryTime(current_time, + /* ignore_soft_enforce_playback_duration */ false); + return expiry_time != NEVER_EXPIRES && expiry_time <= current_time; } // For the policy time fields checked in the following methods, a value of 0 @@ -343,8 +365,9 @@ int64_t PolicyEngine::GetRentalExpiryTime() { } int64_t PolicyEngine::GetExpiryTime( + int64_t current_time, bool ignore_soft_enforce_playback_duration) { - if (!HasPlaybackStarted()) + if (!HasPlaybackStarted(current_time)) return GetRentalExpiryTime(); const int64_t hard_limit = GetHardLicenseExpiryTime(); @@ -418,9 +441,10 @@ void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) { } } -void PolicyEngine::NotifyExpirationUpdate() { +void PolicyEngine::NotifyExpirationUpdate(int64_t current_time) { const int64_t expiry_time = - GetExpiryTime(/* ignore_soft_enforce_playback_duration */ false); + GetExpiryTime(current_time, + /* ignore_soft_enforce_playback_duration */ false); if (!last_expiry_time_set_ || expiry_time != last_expiry_time_) { last_expiry_time_ = expiry_time; if (event_listener_) diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index dacf0882..4b08a553 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -118,6 +118,7 @@ struct LicenseInfo { std::string key_release_url; int64_t playback_start_time; int64_t last_playback_time; + int64_t grace_period_end_time; std::string app_parameters; std::string file_data; }; @@ -225,9 +226,9 @@ LicenseInfo license_test_data[] = { "0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF" "A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0" "BEA6CABACA1C2C"), - "https://test.google.com/license/GetCencLicense", 0x0, 0x0, "", + "https://test.google.com/license/GetCencLicense", 0x0, 0x0, 0x0, "", a2bs_hex( - "0AA8150802100122A1150801121408011210303132333435363738394142434445461" + "0AAA150802100122A3150801121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302" "5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B" @@ -306,8 +307,8 @@ LicenseInfo license_test_data[] = { "106B63746C0000000000ECDCBE0000000020DBDFA68F051A20182F029E35047A3841F" "A176C74E5B387350E8D58DEA6878FF0BEA6CABACA1C2C3A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "365400048001220CD0599C2B85D9F2D573AC7893CE77CB5A10B326828BA8C89047505" - "A8C9B606AC")}, + "365400048005800122066F4FFF1CB2C0F978149A9402F3E4FF8D49B19635E646A0678" + "71AA08E7A8FDC3")}, // license 1 {"ksidC8EAA2579A282EB0", DeviceFiles::kLicenseStateReleasing, @@ -406,9 +407,9 @@ LicenseInfo license_test_data[] = { "A68F051A20BDA6A56F7CBFD0942198F87C23A34AA5CBD64AFEB134277774" "CCF8E789D815DD"), "https://test.google.com/license/GetCencLicense", 0x12345678, 0x12348765, - "Name1 Value1", + 0x0, "Name1 Value1", a2bs_hex( - "0AC1150802100122BA150802121408011210303132333435363738394142434445461" + "0AC3150802100122BC150802121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302" "5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B" @@ -487,8 +488,8 @@ LicenseInfo license_test_data[] = { "106B63746C00000000CA3A6A75000000002083E5A68F051A20BDA6A56F7CBFD094219" "8F87C23A34AA5CBD64AFEB134277774CCF8E789D815DD3A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "36540F8ACD1910148E58ED29101520F0A054E616D6531120656616C7565311220BE69" - "AAB25B481BCAF57B741518D9F9DB8E3A7A6911D10C53D4F4649D78393C65")}, + "36540F8ACD1910148E58ED29101520F0A054E616D6531120656616C75653158001220" + "9C0315FC1812C6A0E5936E36D04ECE2FA56AF4AB544ECDF3C9135D54B4A26167")}, // license 2 {"ksidE8C37662C88DC673", DeviceFiles::kLicenseStateReleasing, @@ -587,9 +588,9 @@ LicenseInfo license_test_data[] = { "A68F051A2041EF0A9267D613D17AA90E1D1DA5BE091860E5E296D41D6D0F" "75E73660C279B3"), "https://test.google.com/license/GetCencLicense", 0x0123456789abcdef, - 0x123456789abfedc, "Name1 Value1 Name2 Param2", + 0x123456789abfedc, 0x0, "Name1 Value1 Name2 Param2", a2bs_hex( - "0AE7150802100122E0150802121408011210303132333435363738394142434445461" + "0AE9150802100122E2150802121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D507618A5D3A68F05228E023082010A0282010100A947904B8DBD55FB685FDB302" "5574517CCCC74EE4FEAF6629D5179A52FF85CE7409528EFFA0E5DFC3DE9A34BA5F08B" @@ -669,9 +670,9 @@ LicenseInfo license_test_data[] = { "90E1D1DA5BE091860E5E296D41D6D0F75E73660C279B33A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910152150A054E616D6531120C5661" - "6C756531204E616D653252160A0C4E616D653220506172616D321206506172616D321" - "2203653BA57F16FE28D66D9F7A76128B7AD7F33680815FF70A3684617DE1FBB0F9" - "F")}}; + "6C756531204E616D653252160A0C4E616D653220506172616D321206506172616D325" + "8001220616E6AC4AF6EB4F7147E98CF7302425E2390B293BBC01F9F8E89B49F653EA3" + "45")}}; // Sample license data and related data for storage and use for offline // playback. The license data and URLs in this test are not real. @@ -774,9 +775,9 @@ LicenseInfo license_update_test_data[] = { "B68F051A2000351030900858FCFD6977B67803ADFD1280AA661E6B0BD30B" "08B2C467355129"), "https://test.google.com/license/GetCencLicense", 0x0123456789abcdef, - 0x123456789abfedc, "Name1 Value1 Name2 Value2 Name3 Value3", + 0x123456789abfedc, 0x0, "Name1 Value1 Name2 Value2 Name3 Value3", a2bs_hex( - "0AB8150802100122B1150801121408011210303132333435363738394142434445461" + "0ABA150802100122B3150801121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D5076189EDFB68F05228E023082010A0282010100CC1715C81AD3F6F279C686F82" "6E6D7C8961EB13318367D06B4061BBC57E3C616A226A10F042CAD54D44C6484C725CD" @@ -855,13 +856,14 @@ LicenseInfo license_update_test_data[] = { "106B63746C0000000071FEF30B0000000020F4DFB68F051A2000351030900858FCFD6" "977B67803ADFD1280AA661E6B0BD30B08B2C4673551293A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD191011220C7ACA00F6877DAAE2E8F50" - "126C3222C2E584A50D08EFA75BC4FC091E7034E1DD")}, + "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD191015800122051F15CDA5B9414919D" + "B67769A781CC4F43138D314DAFFCBFBD620E53167E4AF2")}, // license being released. all fields are identical except for license // state and hashed file data - {"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "", 0, 0, "", + {"", DeviceFiles::kLicenseStateReleasing, "", "", "", "", "", "", 0, 0, 0, + "", a2bs_hex( - "0AB8150802100122B1150802121408011210303132333435363738394142434445461" + "0ABA150802100122B3150802121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" "7A7D5076189EDFB68F05228E023082010A0282010100CC1715C81AD3F6F279C686F82" "6E6D7C8961EB13318367D06B4061BBC57E3C616A226A10F042CAD54D44C6484C725CD" @@ -940,8 +942,8 @@ LicenseInfo license_update_test_data[] = { "106B63746C0000000071FEF30B0000000020F4DFB68F051A2000351030900858FCFD6" "977B67803ADFD1280AA661E6B0BD30B08B2C4673551293A2E68747470733A2F2F7465" "73742E676F6F676C652E636F6D2F6C6963656E73652F47657443656E634C6963656E7" - "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD1910112203D8933A735A22FE27AA956" - "802B597529E8FFCB91A5F3CBBB3CE0C38E4AF3DC88")}}; + "36540EF9BAFCDF8ACD1910148DCFDAFCDF8ACD191015800122093FDE0D42BC60D3932" + "02E0D5A49775E08093BF01560EF72C298321E921716E24")}}; // Application parameters were added to the License message. This data // is used to verify that a License saved without application parameters can @@ -1043,7 +1045,7 @@ LicenseInfo license_app_parameters_backwards_compatibility_test_data = { "0112001A16200342120A106B63746C0000000000ECDCBE0000000020DBDF" "A68F051A20182F029E35047A3841FA176C74E5B387350E8D58DEA6878FF0" "BEA6CABACA1C2C"), - "https://test.google.com/license/GetCencLicense", 0x0, 0x0, "", + "https://test.google.com/license/GetCencLicense", 0x0, 0x0, 0x0, "", a2bs_hex( "0AA8150802100122A1150801121408011210303132333435363738394142434445461" "A9D0E080112950C0AD70B080112EF090AB002080212103E560EC5335E346F591BC4D0" @@ -1489,7 +1491,7 @@ class DeviceFilesTest : public ::testing::Test { return sizeof(DeviceFiles::LicenseState) + data.pssh_data.size() + data.key_request.size() + data.key_response.size() + data.key_renewal_request.size() + data.key_renewal_response.size() + - data.key_release_url.size() + 2 * sizeof(int64_t); + data.key_release_url.size() + 3 * sizeof(int64_t); } CdmAppParameterMap GetAppParameters(std::string str) { @@ -1747,7 +1749,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) { license_test_data[license_num].key_renewal_response, license_test_data[license_num].key_release_url, license_test_data[license_num].playback_start_time, - license_test_data[license_num].last_playback_time, app_parameters)); + license_test_data[license_num].last_playback_time, + license_test_data[license_num].grace_period_end_time, app_parameters)); } INSTANTIATE_TEST_CASE_P(StoreLicense, DeviceFilesStoreTest, ::testing::Bool()); @@ -1794,7 +1797,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) { license_test_data[i].key_renewal_response, license_test_data[i].key_release_url, license_test_data[i].playback_start_time, - license_test_data[i].last_playback_time, app_parameters)); + license_test_data[i].last_playback_time, + license_test_data[i].grace_period_end_time, app_parameters)); } } @@ -1832,6 +1836,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { CdmKeyMessage key_renewal_request; CdmKeyResponse key_renewal_response; int64_t playback_start_time, last_playback_time; + int64_t grace_period_end_time; std::string release_server_url; CdmAppParameterMap app_parameters; @@ -1841,7 +1846,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { license_test_data[i].key_set_id, &license_state, &pssh_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, - &last_playback_time, &app_parameters)); + &last_playback_time, &grace_period_end_time, &app_parameters)); EXPECT_EQ(license_test_data[i].license_state, license_state); EXPECT_EQ(license_test_data[i].pssh_data, pssh_data); EXPECT_EQ(license_test_data[i].key_request, key_request); @@ -1850,6 +1855,8 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) { EXPECT_EQ(license_test_data[i].key_response, key_response); EXPECT_EQ(license_test_data[i].playback_start_time, playback_start_time); EXPECT_EQ(license_test_data[i].last_playback_time, last_playback_time); + EXPECT_EQ(license_test_data[i].grace_period_end_time, + grace_period_end_time); std::map::iterator itr; for (itr = app_parameters.begin(); itr != app_parameters.end(); ++itr) { @@ -1894,6 +1901,7 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) { CdmKeyMessage key_renewal_request; CdmKeyResponse key_renewal_response; int64_t playback_start_time, last_playback_time; + int64_t grace_period_end_time; std::string release_server_url; CdmAppParameterMap app_parameters; @@ -1901,7 +1909,7 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) { test_data->key_set_id, &license_state, &pssh_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, &last_playback_time, - &app_parameters)); + &grace_period_end_time, &app_parameters)); EXPECT_EQ(test_data->license_state, license_state); EXPECT_EQ(test_data->pssh_data, pssh_data); EXPECT_EQ(test_data->key_request, key_request); @@ -1910,6 +1918,7 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) { EXPECT_EQ(test_data->key_response, key_response); EXPECT_EQ(test_data->playback_start_time, playback_start_time); EXPECT_EQ(test_data->last_playback_time, last_playback_time); + EXPECT_EQ(test_data->grace_period_end_time, grace_period_end_time); EXPECT_EQ(0u, app_parameters.size()); } @@ -1945,6 +1954,7 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) { license_update_test_data[0].key_release_url, license_update_test_data[0].playback_start_time, license_update_test_data[0].last_playback_time, + license_update_test_data[0].grace_period_end_time, GetAppParameters(license_test_data[0].app_parameters))); EXPECT_TRUE(device_files.StoreLicense( @@ -1958,6 +1968,7 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) { license_update_test_data[0].key_release_url, license_update_test_data[0].playback_start_time, license_update_test_data[0].last_playback_time, + license_update_test_data[0].grace_period_end_time, GetAppParameters(license_test_data[0].app_parameters))); } @@ -1996,14 +2007,14 @@ TEST_F(DeviceFilesTest, DeleteLicense) { CdmKeyMessage key_renewal_request; CdmKeyResponse key_renewal_response; std::string release_server_url; - int64_t playback_start_time, last_playback_time; + int64_t playback_start_time, last_playback_time, grace_period_end_time; CdmAppParameterMap app_parameters; EXPECT_TRUE(device_files.RetrieveLicense( license_test_data[0].key_set_id, &license_state, &pssh_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, &last_playback_time, - &app_parameters)); + &grace_period_end_time, &app_parameters)); EXPECT_EQ(license_test_data[0].license_state, license_state); EXPECT_EQ(license_test_data[0].pssh_data, pssh_data); EXPECT_EQ(license_test_data[0].key_request, key_request); @@ -2012,6 +2023,7 @@ TEST_F(DeviceFilesTest, DeleteLicense) { EXPECT_EQ(license_test_data[0].key_response, key_response); EXPECT_EQ(license_test_data[0].playback_start_time, playback_start_time); EXPECT_EQ(license_test_data[0].last_playback_time, last_playback_time); + EXPECT_EQ(license_test_data[0].grace_period_end_time, grace_period_end_time); std::map::iterator itr; for (itr = app_parameters.begin(); itr != app_parameters.end(); ++itr) { EXPECT_NE(license_test_data[0].app_parameters.find(itr->first), diff --git a/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp b/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp index 2c828cf7..23b7f3d4 100644 --- a/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/policy_engine_unittest.cpp @@ -1093,7 +1093,8 @@ TEST_F(PolicyEngineTest, LicenseExpired_SoftEnforceLoadBeforeExpire) { OnExpirationUpdate(_, kLicenseStartTime + kLicenseDuration)); policy_engine_->SetLicense(license_); - policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime); + policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime, + kPlaybackStartTime); policy_engine_->OnTimerEvent(); EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId)); @@ -1117,12 +1118,147 @@ TEST_F(PolicyEngineTest, LicenseExpired_SoftEnforceLoadAfterExpire) { ExpectSessionKeysChange(kKeyStatusExpired, false); policy_engine_->SetLicense(license_); - policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime); + policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime, + kPlaybackStartTime); policy_engine_->OnTimerEvent(); EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId)); } +TEST_F(PolicyEngineTest, PlaybackOk_GracePeriod) { + const int64_t kGracePeriod = 300; // 5 minutes + License_Policy* policy = license_.mutable_policy(); + policy->set_play_start_grace_period_seconds(kGracePeriod); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kPlaybackStartTime)) + .WillOnce(Return(kPlaybackStartTime + kGracePeriod - 5)) + .WillOnce(Return(kPlaybackStartTime + kGracePeriod + 5)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 5)) + .WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 5)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(check_, Call(1)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration)); + EXPECT_CALL(check_, Call(2)); + EXPECT_CALL(check_, Call(3)); + ExpectSessionKeysChange(kKeyStatusExpired, false); + EXPECT_CALL(check_, Call(4)); + + policy_engine_->SetLicense(license_); + policy_engine_->BeginDecryption(); + + for (int i = 1; i <= 4; ++i) { + EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId)); + policy_engine_->OnTimerEvent(); + check_.Call(i); + } + + EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId)); +} + +TEST_F(PolicyEngineTest, PlaybackOk_GracePeriodWithLoad) { + const int64_t kGracePeriod = 300; // 5 minutes + const int64_t kNewPlaybackStartTime = kPlaybackStartTime + kPlaybackDuration; + License_Policy* policy = license_.mutable_policy(); + policy->set_play_start_grace_period_seconds(kGracePeriod); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kNewPlaybackStartTime)) + .WillOnce(Return(kNewPlaybackStartTime)) + .WillOnce(Return(kNewPlaybackStartTime + kGracePeriod - 5)) + .WillOnce(Return(kNewPlaybackStartTime + kGracePeriod + 5)) + .WillOnce(Return(kNewPlaybackStartTime + kPlaybackDuration - 5)) + .WillOnce(Return(kNewPlaybackStartTime + kPlaybackDuration + 5)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(check_, Call(1)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kNewPlaybackStartTime + kPlaybackDuration)); + EXPECT_CALL(check_, Call(2)); + EXPECT_CALL(check_, Call(3)); + ExpectSessionKeysChange(kKeyStatusExpired, false); + EXPECT_CALL(check_, Call(4)); + + policy_engine_->SetLicense(license_); + policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime, + 0); + policy_engine_->BeginDecryption(); + + for (int i = 1; i <= 4; ++i) { + EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId)); + policy_engine_->OnTimerEvent(); + check_.Call(i); + } + + EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId)); +} + +TEST_F(PolicyEngineTest, PlaybackOk_GracePeriodWithExpiredLoad) { + const int64_t kGracePeriod = 300; // 5 minutes + const int64_t kNewPlaybackStartTime = + kPlaybackStartTime + kPlaybackDuration + 5; + License_Policy* policy = license_.mutable_policy(); + policy->set_play_start_grace_period_seconds(kGracePeriod); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kNewPlaybackStartTime)) + .WillOnce(Return(kNewPlaybackStartTime)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration)); + ExpectSessionKeysChange(kKeyStatusExpired, false); + + policy_engine_->SetLicense(license_); + policy_engine_->RestorePlaybackTimes(kPlaybackStartTime, kPlaybackStartTime, + kPlaybackStartTime); + + policy_engine_->OnTimerEvent(); + EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId)); +} + +TEST_F(PolicyEngineTest, PlaybackOk_CanStoreGracePeriod) { + const int64_t kGracePeriod = 300; // 5 minutes + License_Policy* policy = license_.mutable_policy(); + policy->set_play_start_grace_period_seconds(kGracePeriod); + + EXPECT_CALL(*mock_clock_, GetCurrentTime()) + .WillOnce(Return(kLicenseStartTime + 1)) + .WillOnce(Return(kPlaybackStartTime)) + .WillOnce(Return(kPlaybackStartTime + 50)) + .WillOnce(Return(kPlaybackStartTime + kGracePeriod + 2)); + + InSequence seq; + ExpectSessionKeysChange(kKeyStatusUsable, true); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kLicenseStartTime + kRentalDuration)); + EXPECT_CALL(mock_event_listener_, + OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration)); + + policy_engine_->SetLicense(license_); + policy_engine_->BeginDecryption(); + + policy_engine_->OnTimerEvent(); + EXPECT_EQ(0, policy_engine_->GetGracePeriodEndTime()); + + policy_engine_->OnTimerEvent(); + EXPECT_EQ(kPlaybackStartTime, policy_engine_->GetGracePeriodEndTime()); +} + class PolicyEngineKeyAllowedUsageTest : public PolicyEngineTest { protected: enum KeyFlag {