diff --git a/common/security_profile_list.h b/common/security_profile_list.h index e1c91c1..10a4e5b 100644 --- a/common/security_profile_list.h +++ b/common/security_profile_list.h @@ -71,25 +71,26 @@ class SecurityProfileList { // contain single record. For custom DSP, it may contain multiple records // since active dsp and inactive dsp could share the same dsp_name under the // same owner. - bool GetProfileByNameAndOwner( + virtual bool GetProfileByNameAndOwner( const std::string& name, const std::string& owner, std::vector* security_profiles) const; // Populates |security_profiles| owned by the content owner. - int GetProfilesByOwner(const std::string& owner, - std::vector* security_profiles) const; + virtual int GetProfilesByOwner( + const std::string& owner, + std::vector* security_profiles) const; // Populates |owner_list| for security profiles. |is_default_dsp| boolean // indicates the owner_list for default dsp or custom dsp. - int GetProfilesOwnerList(const bool is_default_dsp, - std::vector* owner_list) const; + virtual int GetProfilesOwnerList(const bool is_default_dsp, + std::vector* owner_list) const; // Return the device security capabilities. |drm_info| is populated with // data from |client_id| and |device_info|. |drm_info| must not be null and // is owned by the caller. - bool GetDrmInfo(const ClientIdentification& client_id, - const ProvisionedDeviceInfo& device_info, - SecurityProfile::DrmInfo* drm_info) const; + virtual bool GetDrmInfo(const ClientIdentification& client_id, + const ProvisionedDeviceInfo& device_info, + SecurityProfile::DrmInfo* drm_info) const; // Return the number of profiles in the list. int NumProfiles() const; @@ -110,6 +111,12 @@ class SecurityProfileList { HashAlgorithm hash_algorithm, const std::string& signature, int* added_profile_num); + // Returns an instance of the Security profile list for default security + // profiles. Default security profiles are owned by Widevine. + // TODO (b/187073516): This singleton can be moved to the "Environment" class + // as a non-static API. + static SecurityProfileList* GetInstanceForDefaultSecurityProfiles(); + protected: void ClearAllProfiles(); diff --git a/example/test_emmg_messages.h b/example/test_emmg_messages.h index 44b68ef..1d67b72 100644 --- a/example/test_emmg_messages.h +++ b/example/test_emmg_messages.h @@ -151,11 +151,11 @@ const char kTestEmmgPrivateDataProvision[] = { '\x47', '\x40', '\x00', '\x10', '\x0a', '\x0d', '\x77', '\x69', '\x64', '\x65', '\x76', '\x69', '\x6e', '\x65', '\x5f', '\x74', '\x65', '\x73', '\x74', '\x12', '\x09', '\x43', '\x61', '\x73', '\x54', '\x73', '\x46', - '\x61', '\x6b', '\x65', '\x1a', '\x10', '\x66', '\x61', '\x6b', '\x65', - '\x4b', '\x65', '\x79', '\x49', '\x64', '\x31', '\x4b', '\x65', '\x79', - '\x49', '\x64', '\x31', '\x1a', '\x10', '\x66', '\x61', '\x6b', '\x65', - '\x4b', '\x65', '\x79', '\x49', '\x64', '\x32', '\x4b', '\x65', '\x79', - '\x49', '\x64', '\x32', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x61', '\x6b', '\x65', '\x22', '\x0a', '\x66', '\x61', '\x6b', '\x65', + '\x47', '\x72', '\x6f', '\x75', '\x70', '\x31', '\x22', '\x0c', '\x66', + '\x61', '\x6b', '\x65', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x49', + '\x64', '\x32', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', + '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', @@ -191,22 +191,22 @@ const char kTestEmmgEmmDataProvision[] = { // Start of the first TS packet (188 bytes). '\x47', '\x40', '\x00', '\x10', // TS packet header (4 bytes). '\x00', // Pointer field (1 byte). - '\x82', '\x70', '\xbe', // Secyion header (3 bytes). + '\x82', '\x70', '\xbc', // Section header (3 bytes). // Start of Widevine EMM. - '\x01', '\x08', '\x00', '\x00', '\x00', '\x00', '\x5f', '\x3d', '\xc1', - '\xfb', '\x00', '\x6b', '\x0a', '\x14', '\x0a', '\x03', '\x43', '\x48', - '\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x08', '\x63', - '\x6f', '\x6e', '\x74', '\x72', '\x6f', '\x6c', '\x73', '\x0a', '\x16', - '\x0a', '\x03', '\x43', '\x48', '\x33', '\x12', '\x0f', '\x61', '\x6e', - '\x6f', '\x74', '\x68', '\x65', '\x72', '\x20', '\x63', '\x6f', '\x6e', - '\x74', '\x72', '\x6f', '\x6c', '\x12', '\x18', '\x0a', '\x03', '\x43', - '\x48', '\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x06', - '\x47', '\x72', '\x6f', '\x75', '\x70', '\x31', '\x20', '\xd2', '\x85', - '\xd8', '\xcc', '\x04', '\x12', '\x21', '\x0a', '\x03', '\x43', '\x48', - '\x33', '\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x32', - '\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x33', '\x18', - '\xd2', '\x85', '\xd8', '\xcc', '\x04', '\x20', '\xd3', '\x85', '\xd8', - '\xcc', '\x04', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', + '\x0a', '\x71', '\x0a', '\x14', '\x0a', '\x03', '\x43', '\x48', '\x31', + '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x08', '\x63', '\x6f', + '\x6e', '\x74', '\x72', '\x6f', '\x6c', '\x73', '\x0a', '\x16', '\x0a', + '\x03', '\x43', '\x48', '\x33', '\x12', '\x0f', '\x61', '\x6e', '\x6f', + '\x74', '\x68', '\x65', '\x72', '\x20', '\x63', '\x6f', '\x6e', '\x74', + '\x72', '\x6f', '\x6c', '\x12', '\x18', '\x0a', '\x03', '\x43', '\x48', + '\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x06', '\x47', + '\x72', '\x6f', '\x75', '\x70', '\x31', '\x20', '\xd2', '\x85', '\xd8', + '\xcc', '\x04', '\x12', '\x21', '\x0a', '\x03', '\x43', '\x48', '\x33', + '\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x32', '\x12', + '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x33', '\x18', '\xd2', + '\x85', '\xd8', '\xcc', '\x04', '\x20', '\xd3', '\x85', '\xd8', '\xcc', + '\x04', '\x18', '\xfb', '\x83', '\xf7', '\xf9', '\x05', '\x12', '\x47', + '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', @@ -216,8 +216,8 @@ const char kTestEmmgEmmDataProvision[] = { // Start of the second TS packet (188 bytes). '\x47', '\x00', '\x00', '\x11', // TS packet header (4 bytes). // Continued Widevine EMM. - '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', - '\x78', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', + '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\xff', + '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', diff --git a/example/wv_cas_ecm_example b/example/wv_cas_ecm_example index 103f830..e5991ce 100644 Binary files a/example/wv_cas_ecm_example and b/example/wv_cas_ecm_example differ diff --git a/example/wv_cas_emm_example b/example/wv_cas_emm_example index 8e8b2ee..fbe283b 100644 Binary files a/example/wv_cas_emm_example and b/example/wv_cas_emm_example differ diff --git a/example/wv_cas_key_fetcher_example b/example/wv_cas_key_fetcher_example index d67dbda..2958f0e 100644 Binary files a/example/wv_cas_key_fetcher_example and b/example/wv_cas_key_fetcher_example differ diff --git a/example/wv_cas_key_fetcher_example.cc b/example/wv_cas_key_fetcher_example.cc index 7f1e84a..368a945 100644 --- a/example/wv_cas_key_fetcher_example.cc +++ b/example/wv_cas_key_fetcher_example.cc @@ -12,8 +12,11 @@ #include #include "common/status.h" +#include "media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.h" #include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h" +const char kCasEncryptionServerUrl[] = + "https://license.uat.widevine.com/cas/getcontentkey/widevine_test"; const char kContentId[] = "21140844"; const char kContentProvider[] = "widevine"; const char kTrackType[] = "SD"; @@ -22,36 +25,16 @@ const char kSigningProvider[] = "widevine_test"; const char kSingingKey[] = "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9"; const char kSingingIv[] = "d58ce954203b7c9a9a9d467f59839249"; -const char kHttpResponse[] = - "{\"response\":" - "\"eyJzdGF0dXMiOiJPSyIsImNvbnRlbnRfaWQiOiJNakV4TkRBNE5EUT0iLCJlbnRpdGxlbWVu" - "dF9rZXlzIjpbeyJrZXlfaWQiOiJNUGFndXhNb1hNNkUxUzhEOUF3RkNBPT0iLCJrZXkiOiJoZ1" - "JycmdqeUg4NjQycjY3VHd0OHJ1cU5MUGNMRmtKcWRVSUROdm5GZDBNPSIsInRyYWNrX3R5cGUi" - "OiJTRCIsImtleV9zbG90IjoiU0lOR0xFIn1dfQ==\"}"; using widevine::Status; using widevine::cas::EntitlementKeyInfo; using widevine::cas::EntitlementRequestParams; -using widevine::cas::WvCasKeyFetcher; - -class ExampleKeyFetcher : public WvCasKeyFetcher { - public: - ExampleKeyFetcher(const std::string& signing_provider, - const std::string& signing_key, - const std::string& signing_iv) - : WvCasKeyFetcher(signing_provider, signing_key, signing_iv) {} - - // An example that always returns the same response. - Status MakeHttpRequest(const std::string& signed_request_json, - std::string* http_response_json) const override { - *http_response_json = kHttpResponse; - return widevine::OkStatus(); - } -}; +using widevine::cas::WvCasCurlKeyFetcher; int main(int argc, char** argv) { - // Initialize key fetcher. - ExampleKeyFetcher key_fetcher(kSigningProvider, kSingingKey, kSingingIv); + // Initialize key fetcher with server url. + WvCasCurlKeyFetcher key_fetcher(kCasEncryptionServerUrl, kSigningProvider, + kSingingKey, kSingingIv); // Create request string. std::string request_str; diff --git a/example/wv_ecmg_example b/example/wv_ecmg_example index 34ba88a..ccd465b 100644 Binary files a/example/wv_ecmg_example and b/example/wv_ecmg_example differ diff --git a/libmedia_cas_packager_sdk.so b/libmedia_cas_packager_sdk.so index 0b15f43..7927fc5 100755 Binary files a/libmedia_cas_packager_sdk.so and b/libmedia_cas_packager_sdk.so differ diff --git a/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h b/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h index 540a763..f4b75a5 100644 --- a/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h +++ b/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h @@ -50,9 +50,7 @@ class WvCasCaDescriptor { // |ca_pid| the 13-bit PID of the ECMs // |provider| provider name, put in private data for client to construct pssh // |content_id| content ID, put in private data for client to construct pssh - // |entitlement_key_ids| entitlement key ids, put in private data for client - // to select entitlement keys from single fat license. This field is only used - // when client uses single fat license. + // |group_ids| the groups ids this channel belongs to. Optional. // |serialized_ca_desc| a std::string object to receive the encoded descriptor. // // Notes: @@ -60,11 +58,11 @@ class WvCasCaDescriptor { // section (for an EMM stream) or into a TS Program Map Table section (for an // ECM stream). The descriptor will be 6 bytes plus any bytes added as // (user-defined) private data. - virtual Status GenerateCaDescriptor( - uint16_t ca_pid, const std::string& provider, - const std::string& content_id, - const std::vector& entitlement_key_ids, - std::string* serialized_ca_desc) const; + virtual Status GenerateCaDescriptor(uint16_t ca_pid, + const std::string& provider, + const std::string& content_id, + const std::vector& group_ids, + std::string* serialized_ca_desc) const; // Return the base size (before private data is added) of the CA // descriptor. The user can call this to plan the layout of the Table section @@ -74,7 +72,7 @@ class WvCasCaDescriptor { // Return private data in the CA descriptor. virtual std::string GeneratePrivateData( const std::string& provider, const std::string& content_id, - const std::vector& entitlement_key_ids) const; + const std::vector& group_ids) const; }; } // namespace cas diff --git a/media_cas_packager_sdk/public/wv_cas_ecm.h b/media_cas_packager_sdk/public/wv_cas_ecm.h index 35a5342..2ed1676 100644 --- a/media_cas_packager_sdk/public/wv_cas_ecm.h +++ b/media_cas_packager_sdk/public/wv_cas_ecm.h @@ -61,6 +61,7 @@ struct WvCasEcmParameters { uint16_t cas_id = 0x4AD4; EcmVersion ecm_version = EcmVersion::kV2; std::string ecc_private_signing_key; + EntitlementKeyRotationInfo entitlement_rotation; }; // Class for generating Widevine CAS ECMs. @@ -94,6 +95,20 @@ class WvCasEcm { virtual void SetServiceBlocking( const EcmServiceBlockingParams* service_blocking); + // Sets the current value of the entitlement key rotation window left to + // |entitlement_rotation_window_left|. The value will be used in + // GenerateEcm/GenerateSingleKeyEcm if entitlement rotation is enabled as + // specified at initializing, and is automatically decreased by 1 on each call + // to GenerateEcm/GenerateSingleKeyEcm, until it reaches 1. + virtual Status SetEntitlementRotationWindowLeft( + uint32_t entitlement_rotation_window_left); + + // Gets the current value of the entitlement key rotation window left. The + // value is used in GenerateEcm/GenerateSingleKeyEcm, and is automatically + // decreased by 1 on each call to GenerateEcm/GenerateSingleKeyEcm, until it + // reaches 1. + virtual uint32_t GetEntitlementRotationWindowLeft() const; + // Constructs a Widevine ECM using the provided key info. // Args: // |even_key| information for even key to be encoded into ECM. @@ -106,6 +121,9 @@ class WvCasEcm { // consistent with the initialized settings. // The even_key and odd_key will be wrapped using the appropriate // entitlement key. + // If entitlement rotation is enabled as specified at initializing, the + // entitlement key rotation window left value will be automatically decreased + // by 1, until it reaches 1. virtual Status GenerateEcm(const WvCasContentKeyInfo& even_key, const WvCasContentKeyInfo& odd_key, const std::string& track_type, @@ -122,6 +140,9 @@ class WvCasEcm { // |serialized_ecm| caller-supplied std::string pointer to receive the ECM. // The |key| contents (specifically IV sizes) must be consistent // with the initialized settings. + // If entitlement rotation is enabled as specified at initializing, the + // entitlement key rotation window left value will be automatically decreased + // by 1, until it reaches 1. virtual Status GenerateSingleKeyEcm(const WvCasContentKeyInfo& key, const std::string& track_type, const std::vector& group_ids, diff --git a/media_cas_packager_sdk/public/wv_cas_ecmg_client_handler.h b/media_cas_packager_sdk/public/wv_cas_ecmg_client_handler.h index df27548..ad8e25f 100644 --- a/media_cas_packager_sdk/public/wv_cas_ecmg_client_handler.h +++ b/media_cas_packager_sdk/public/wv_cas_ecmg_client_handler.h @@ -74,6 +74,12 @@ class WvCasEcmgClientHandler { size_t& response_length, size_t& processed_request_length); + // Retrieves the current channel status; + WvEcmgChannelStatus GetChannelStatus() const; + + // Retrieves the status of all open streams; + std::vector GetStreamStatus() const; + protected: // For unit test only. explicit WvCasEcmgClientHandler( diff --git a/media_cas_packager_sdk/public/wv_cas_key_fetcher.h b/media_cas_packager_sdk/public/wv_cas_key_fetcher.h index 8f8213c..7f0f49d 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.h +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.h @@ -29,12 +29,17 @@ namespace cas { // |group_id| optional field indicates if this is a key used for a group of // contents. If this field is not empty, entitlement key would be generated // for the group instead of the single content. +// |entitlement_rotation_enabled| Whether entitlement rotation is enabled. +// |entitlement_period_index| The requested entitlement period index if +// entitlement rotation is enabled. struct EntitlementRequestParams { std::string content_id; std::string content_provider; std::vector track_types; bool key_rotation; std::string group_id; + bool entitlement_rotation_enabled = false; + uint32_t entitlement_period_index; }; // WV CAS KeyFetcher. Performs the communication with the Widevine License diff --git a/media_cas_packager_sdk/public/wv_cas_types.h b/media_cas_packager_sdk/public/wv_cas_types.h index 41d439a..08256f2 100644 --- a/media_cas_packager_sdk/public/wv_cas_types.h +++ b/media_cas_packager_sdk/public/wv_cas_types.h @@ -86,6 +86,23 @@ struct EntitlementKeyInfo { enum class EcmVersion : int { kV2 = 0, kV3 = 1 }; +// Used for generating ECMs if entitlement key rotation is enabled. +struct EntitlementKeyRotationInfo { + // Indicates if entitlement key rotation feature is used. If enabled, + // |period_index| and |rotation_window_left| must also be specified and will + // be carried in generated ECMs. + bool rotation_enabled = false; + // The current entitlement key period index. Only used if |rotation_enabled| + // is set to true. + uint32_t period_index = 0; + // It tells the client how many crypto periods (unique ECMs) left (including + // this ECM) that a new license request must be made. Must be a positive + // value. Only used if |rotation_enabled| is set to true. + // The value will automatically decrease by 1 on each call to GenerateEcm or + // GenerateSingleKeyEcm, until the value reaches 1. + uint32_t rotation_window_left = 0; +}; + // A struct that captures the Simulcrypt ECMG configurations. Most fields are // Simulcrypt standard fields (See ETSI TS 103 197 V1.5.1 (2008-10) // Section 5.3). @@ -177,6 +194,8 @@ struct EcmgCustomParameters { // when the ECM is received, and stops util the device is no longer in // |device_groups|. std::vector service_blocking_groups; + // Used if entitlement key rotation is enabled. + EntitlementKeyRotationInfo entitlement_rotation; }; // A custom access control processing function used by ECMG to get information @@ -233,6 +252,33 @@ typedef std::function ServiceBlockingSettingFunc; +struct WvEcmgChannelStatus { + // If the channel has been set up or not. + bool has_setup; + uint16_t channel_id; + uint16_t ca_system_id; + int num_of_open_streams; + EcmVersion ecm_version; + // Below are Simulcrypt parameters values (see ETSI TS 103 197 V1.5.1 + // (2008-10) Section 5.3). + uint8_t section_tspkt_flag; + uint16_t delay_start; + uint16_t delay_stop; + uint16_t ecm_pep_period; + uint16_t max_streams; + uint16_t min_cp_duration; + uint8_t lead_cw; + uint8_t cw_per_message; + uint16_t max_comp_time; +}; + +struct WvEcmgStreamStatus { + uint16_t stream_id; + uint16_t ecm_id; + CryptoMode crypto_mode; + int age_restriction; +}; + struct WvCasEncryptionRequest { std::string content_id; std::string provider; diff --git a/media_cas_packager_sdk/public/wv_ecmg b/media_cas_packager_sdk/public/wv_ecmg index 2d91d80..e54d05e 100644 Binary files a/media_cas_packager_sdk/public/wv_ecmg and b/media_cas_packager_sdk/public/wv_ecmg differ diff --git a/media_cas_packager_sdk/public/wv_emmg b/media_cas_packager_sdk/public/wv_emmg index c16b65b..4adb93b 100644 Binary files a/media_cas_packager_sdk/public/wv_emmg and b/media_cas_packager_sdk/public/wv_emmg differ diff --git a/protos/public/media_cas.proto b/protos/public/media_cas.proto index 33dfbb3..9427e59 100644 --- a/protos/public/media_cas.proto +++ b/protos/public/media_cas.proto @@ -19,9 +19,8 @@ message CaDescriptorPrivateData { // Content ID. optional bytes content_id = 2; - // Entitlement key IDs for current content per track. Each track will allow up - // to 2 entitlement key ids (odd and even entitlement keys). - repeated bytes entitlement_key_ids = 3; + // Deprecated. + repeated bytes deprecated_entitlement_key_ids = 3; // The groups ids this channel belongs to. repeated bytes group_ids = 4; @@ -78,6 +77,17 @@ message EcmMetaData { // Optional. The minimum age required to watch the content. The value // represents actual age, with 0 means no restriction. optional uint32 age_restriction = 2 [default = 0]; + // If specified, it means entitlement key rotation is enabled. The value will + // be included in the license request. The server is expected to return + // entitlement keys accordingly (e.g., keys for |entitlement_period_index| and + // |entitlement_period_index| + 1). + optional uint32 entitlement_period_index = 3; + // Used only if entitlement key rotation is enabled. This parameter controls + // the probability of requesting a new license by clients upon receiving this + // ECM. The purpose is to spread out requests to avoid request storms. A + // client will request a new license with possibility = 1 / + // |entitlement_rotation_window_left|. + optional uint32 entitlement_rotation_window_left = 4 [default = 1]; } message EcmKeyData {