diff --git a/common/default_device_security_profile_list.h b/common/default_device_security_profile_list.h new file mode 100644 index 0000000..33d96d9 --- /dev/null +++ b/common/default_device_security_profile_list.h @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2020 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// +// +// Description: +// Container of Widevine default security profiless. + +#ifndef COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_ +#define COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_ + +#include "common/security_profile_list.h" + +namespace widevine { + +class DefaultDeviceSecurityProfileList : public SecurityProfileList { + public: + DefaultDeviceSecurityProfileList(); + ~DefaultDeviceSecurityProfileList() override {} + + // Initialize the security profile list. The list is initially empty, this + // function will populate the list with default profiles. The size of the + // list is returned. + int Init() override; + + private: + // Initialize the list with Widevine default profiles. The size of the + // profile list after the additions is returned. + virtual int AddDefaultProfiles(); + virtual int GetDefaultProfileStrings( + std::vector* default_profile_strings) const; +}; + +} // namespace widevine + +#endif // COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_ diff --git a/common/security_profile_list.h b/common/security_profile_list.h new file mode 100644 index 0000000..07b2a3b --- /dev/null +++ b/common/security_profile_list.h @@ -0,0 +1,93 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2020 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// +// +// Description: +// Container of device security profiles. Security profiles indicate rules +// to allow using the profile. The rules are based on DRM capabilities of a +// device. + +#ifndef COMMON_SECURITY_PROFILE_LIST_H_ +#define COMMON_SECURITY_PROFILE_LIST_H_ + +#include "absl/synchronization/mutex.h" +#include "protos/public/client_identification.pb.h" +#include "protos/public/device_security_profile_data.pb.h" +#include "protos/public/provisioned_device_info.pb.h" +#include "protos/public/security_profile.pb.h" + +namespace widevine { +using ClientCapabilities = ClientIdentification::ClientCapabilities; + +// The SecurityProfileList will hold all security profiles. During license +// acquisition, information from the client and information from the server are +// combined to deternmine the device's security profile level. + +class SecurityProfileList { + public: + explicit SecurityProfileList(const std::string& profile_namespace); + virtual ~SecurityProfileList() {} + + // Initialize the security profile list. The size of the profile list is + // returned. + virtual int Init(); + + // Add the specified profile to the existing list of profiles. Returns true + // if successfully inserted, false if unable to insert. + bool InsertProfile(const SecurityProfile& profile_to_insert); + + // Populates |profiles_allow| with a list of profiles from the specified + // |profiles_to_check| list that meet the requirements for the this device. + // The number of profiles is returned. + virtual int GetQualifiedProfilesFromSpecifiedProfiles( + const std::vector& profiles_to_check, + const ClientIdentification& client_id, + const ProvisionedDeviceInfo& device_info, + std::vector* qualified_profiles) const; + + // Populates |profiles_to_allow| with a list of profiles that meet the + // requirements for the this device. The number of profiles is returned. + virtual int GetQualifiedProfiles( + const ClientIdentification& client_id, + const ProvisionedDeviceInfo& device_info, + std::vector* qualified_profiles) const; + + // Return true if a profile exist matching the specified |name|. + // |security_profile| is owned by the caller and is populated if a profile + // exist. + bool GetProfileByName(const std::string& name, + SecurityProfile* security_profile) 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; + + // Return the number of profiles in the list. + int NumProfiles() const; + + // Return a list of profile names. + virtual void GetProfileNames(std::vector* profile_names) const; + + protected: + void ClearAllProfiles(); + + private: + bool DoesProfileQualify(const SecurityProfile& profile, + const ClientIdentification& client_id, + const ProvisionedDeviceInfo& device_info) const; + + + mutable absl::Mutex mutex_; + // Security profiles + std::string profile_namespace_; + std::vector security_profiles_ ABSL_GUARDED_BY(mutex_); +}; + +} // namespace widevine +#endif // COMMON_SECURITY_PROFILE_LIST_H_ diff --git a/example/test_emmg_messages.h b/example/test_emmg_messages.h index aeac11a..cbc53ca 100644 --- a/example/test_emmg_messages.h +++ b/example/test_emmg_messages.h @@ -130,11 +130,11 @@ const char kTestEmmgDataProvision[] = { '\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', '\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', + '\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', '\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', @@ -149,6 +149,26 @@ const char kTestEmmgDataProvision[] = { '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; +const char kTestEmptyEmmgDataProvision[] = { + '\x02', // protocol_version + '\x02', '\x11', // message_type - Data_provision + '\x00', '\x00', // message_length + '\x00', '\x01', // parameter_type - client_id + '\x00', '\x04', // parameter_length + '\x4a', '\xd4', '\x00', '\x00', // parameter_value + '\x00', '\x03', // parameter_type - data_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x04', // parameter_type - data_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x08', // parameter_type - data_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x00', // parameter_type - datagram + '\x00', '\x00', // parameter_length +}; + const char kTestEmmgStreamCloseRequest[] = { '\x02', // protocol_version '\x01', '\x14', // message_type - Stream_close_request diff --git a/example/wv_cas_ecm_example b/example/wv_cas_ecm_example index 8453f79..14e3975 100644 Binary files a/example/wv_cas_ecm_example and b/example/wv_cas_ecm_example differ diff --git a/example/wv_cas_key_fetcher_example b/example/wv_cas_key_fetcher_example index ea45812..6d359a0 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_types_example b/example/wv_cas_types_example index bf937f3..042b8cc 100644 Binary files a/example/wv_cas_types_example and b/example/wv_cas_types_example differ diff --git a/libmedia_cas_packager_sdk.so b/libmedia_cas_packager_sdk.so index b76c295..b8c83e9 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 1a044fc..428457c 100644 --- a/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h +++ b/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h @@ -12,6 +12,7 @@ #include #include +#include #include #include "common/status.h" @@ -48,6 +49,9 @@ 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. // |serialized_ca_desc| a std::string object to receive the encoded descriptor. // // Notes: @@ -55,10 +59,10 @@ 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, - 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& entitlement_key_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 @@ -66,8 +70,9 @@ class WvCasCaDescriptor { virtual size_t CaDescriptorBaseSize() const; // Return private data in the CA descriptor. - virtual std::string GeneratePrivateData(const std::string& provider, - const std::string& content_id) const; + virtual std::string GeneratePrivateData( + const std::string& provider, const std::string& content_id, + const std::vector& entitlement_key_ids) const; }; } // namespace cas diff --git a/media_cas_packager_sdk/public/wv_ecmg b/media_cas_packager_sdk/public/wv_ecmg index f3c5124..314df22 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 1504f78..d419950 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/BUILD b/protos/public/BUILD index cd40ec4..a0b2373 100644 --- a/protos/public/BUILD +++ b/protos/public/BUILD @@ -18,6 +18,7 @@ filegroup( proto_library( name = "media_cas_encryption_proto", srcs = ["media_cas_encryption.proto"], + deps = ["hash_algorithm_proto"], ) cc_proto_library( @@ -34,3 +35,18 @@ cc_proto_library( name = "media_cas_cc_proto", deps = [":media_cas_proto"], ) + +proto_library( + name = "hash_algorithm_proto", + srcs = ["hash_algorithm.proto"], +) + +cc_proto_library( + name = "hash_algorithm_cc_proto", + deps = [":hash_algorithm_proto"], +) + +java_proto_library( + name = "hash_algorithm_java_proto", + deps = [":hash_algorithm_proto"], +) diff --git a/protos/public/hash_algorithm.proto b/protos/public/hash_algorithm.proto new file mode 100644 index 0000000..bcb0751 --- /dev/null +++ b/protos/public/hash_algorithm.proto @@ -0,0 +1,20 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2020 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// + +syntax = "proto3"; + +package widevine; + +// LINT.IfChange +enum HashAlgorithmProto { + // Unspecified hash algorithm: SHA_256 shall be used for ECC based algorithms + // and SHA_1 shall be used otherwise. + HASH_ALGORITHM_UNSPECIFIED = 0; + HASH_ALGORITHM_SHA_1 = 1; + HASH_ALGORITHM_SHA_256 = 2; +} diff --git a/protos/public/media_cas.proto b/protos/public/media_cas.proto index 928c3ce..e9aea06 100644 --- a/protos/public/media_cas.proto +++ b/protos/public/media_cas.proto @@ -18,4 +18,35 @@ 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; +} + +// Widevine fingerprinting. +message Fingerprinting { + // Channels that will be applied with the controls. + repeated bytes channels = 1; + // Fingerprinting controls are opaque to Widevine. + optional bytes control = 2; +} + +// Widevine service blocking. +message ServiceBlocking { + // Channels that will be blocked. + repeated bytes channels = 1; + // Device groups that will be blocked. Group definition is opaque to Widevine. + repeated bytes device_groups = 2; + // Blocking start time in seconds since epoch. Start time is "immediate" if + // this field is not set. + optional int64 start_time_sec = 3; + // Required. Blocking end time in seconds since epoch. + optional int64 end_time_sec = 4; +} + +// The payload field for an EMM. +message EmmPayload { + repeated Fingerprinting fingerprinting = 1; + repeated ServiceBlocking service_blocking = 2; } diff --git a/protos/public/media_cas_encryption.proto b/protos/public/media_cas_encryption.proto index 84f8044..c40712a 100644 --- a/protos/public/media_cas_encryption.proto +++ b/protos/public/media_cas_encryption.proto @@ -12,8 +12,11 @@ syntax = "proto2"; package widevine; +import "protos/public/hash_algorithm.proto"; + option java_package = "com.google.video.widevine.mediacasencryption"; + message CasEncryptionRequest { optional bytes content_id = 1; optional string provider = 2; @@ -23,6 +26,10 @@ message CasEncryptionRequest { // return one key for EVEN and one key for ODD, otherwise only a single key is // returned. optional bool key_rotation = 4; + // Optional value which can be used to indicate a group. + // If present the CasEncryptionResponse will return key based on the group + // id. + optional bytes group_id = 5; } message CasEncryptionResponse { @@ -54,6 +61,8 @@ message CasEncryptionResponse { optional string status_message = 2; optional bytes content_id = 3; repeated KeyInfo entitlement_keys = 4; + // If this is a group key license, this is the group identifier. + optional bytes group_id = 5; } message SignedCasEncryptionRequest { @@ -61,6 +70,8 @@ message SignedCasEncryptionRequest { optional bytes signature = 2; // Identifies the entity sending / signing the request. optional string signer = 3; + // Optional field that indicates the hash algorithm used in signature scheme. + optional HashAlgorithmProto hash_algorithm = 4; } message SignedCasEncryptionResponse { diff --git a/util/error_space.h b/util/error_space.h index 2e66a39..ce63880 100644 --- a/util/error_space.h +++ b/util/error_space.h @@ -17,7 +17,9 @@ namespace util { class ErrorSpace { public: std::string SpaceName() const { return space_name_func_(this); } - std::string String(int code) const { return code_to_string_func_(this, code); } + std::string String(int code) const { + return code_to_string_func_(this, code); + } protected: // typedef instead of using statements for SWIG compatibility.