Entitlement rotation support

Updates also include:
- Add APIs to query current Simulcrypt channel & stream status;
- EMM format change (used only to carry fingerprinting and service
blocking info);
- Key fetcher example to use curl key fetcher.
This commit is contained in:
Widevine Buildbot
2021-06-29 22:07:00 +00:00
parent 8a07605f56
commit 8818d7d026
16 changed files with 142 additions and 66 deletions

View File

@@ -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<SecurityProfile>* security_profiles) const;
// Populates |security_profiles| owned by the content owner.
int GetProfilesByOwner(const std::string& owner,
std::vector<SecurityProfile>* security_profiles) const;
virtual int GetProfilesByOwner(
const std::string& owner,
std::vector<SecurityProfile>* 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<std::string>* owner_list) const;
virtual int GetProfilesOwnerList(const bool is_default_dsp,
std::vector<std::string>* 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();

View File

@@ -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',

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -12,8 +12,11 @@
#include <vector>
#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;

Binary file not shown.

Binary file not shown.

View File

@@ -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<std::string>& 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<std::string>& 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<std::string>& entitlement_key_ids) const;
const std::vector<std::string>& group_ids) const;
};
} // namespace cas

View File

@@ -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<std::string>& group_ids,

View File

@@ -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<WvEcmgStreamStatus> GetStreamStatus() const;
protected:
// For unit test only.
explicit WvCasEcmgClientHandler(

View File

@@ -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<std::string> 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

View File

@@ -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<std::string> 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<EcmServiceBlockingParams(uint16_t channel_id,
uint16_t stream_id)>
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;

View File

@@ -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 {