Add support for Widevine ECM v3

Widevine ECM v3 is redesigned mainly based on protobuf, and supports new features including carrying fingerprinting and service blocking information. Existing clients must upgrade the Widevine CAS plugin to use the new ECM v3.
This commit is contained in:
Widevine Buildbot
2020-12-14 18:02:09 +00:00
parent 9caa71483c
commit 810ceaf1a1
18 changed files with 367 additions and 96 deletions

View File

@@ -1,39 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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<std::string>* default_profile_strings) const;
};
} // namespace widevine
#endif // COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_

18
common/hash_algorithm.h Normal file
View File

@@ -0,0 +1,18 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_HASH_ALGORITHM_H_
#define COMMON_HASH_ALGORITHM_H_
namespace widevine {
enum class HashAlgorithm { kUnspecified, kSha1, kSha256 };
} // namespace widevine
#endif // COMMON_HASH_ALGORITHM_H_

View File

@@ -15,25 +15,32 @@
#define COMMON_SECURITY_PROFILE_LIST_H_
#include "absl/synchronization/mutex.h"
#include "common/hash_algorithm.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_security_profile_data.pb.h"
#include "protos/public/device_security_profile_list.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
using ClientCapabilities = ClientIdentification::ClientCapabilities;
const char kDefaultProfileOwnerName[] = "Widevine";
// 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.
// TODO(user): Clean up the virtual/protected functions once subclass
// default_device_security_profile_list gets removed.
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.
// Initialize the security profile list with Widevine default profiles. The
// size of the profile list is returned.
virtual int Init();
// Add the specified profile to the existing list of profiles. Returns true
@@ -45,7 +52,7 @@ class SecurityProfileList {
// The number of profiles is returned.
virtual int GetQualifiedProfilesFromSpecifiedProfiles(
const std::vector<std::string>& profiles_to_check,
const ClientIdentification& client_id,
const std::string& owner, const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* qualified_profiles) const;
@@ -53,14 +60,28 @@ class SecurityProfileList {
// requirements for the this device. The number of profiles is returned.
virtual int GetQualifiedProfiles(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
const ProvisionedDeviceInfo& device_info, const std::string& owner,
std::vector<std::string>* 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 true if a profile exist matching the specified parameters {|name|,
// |owner|}. |security_profiles| is owned by the caller and is populated if
// one or more profile exist. For default DSP, the output profiles should
// 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(
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;
// 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;
// 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.
@@ -74,10 +95,33 @@ class SecurityProfileList {
// Return a list of profile names.
virtual void GetProfileNames(std::vector<std::string>* profile_names) const;
// Deserialized SignedDeviceSecurityProfiles for custom DSPs.
static Status DeserializeSignedDeviceSecurityProfiles(
const std::string& serialized_signed_device_security_profiles,
std::string* serialized_device_security_profiles,
HashAlgorithm* hash_algorithm, std::string* signature);
// Validate signature and update security profile list for custom dsps.
Status ValidateAndUpdateProfileList(
const std::string& root_certificate_public_key,
const std::string& serialized_device_security_profiles,
HashAlgorithm hash_algorithm, const std::string& signature,
int* added_profile_num);
protected:
void ClearAllProfiles();
private:
// Add Widevine default profiles into profile_list. The number of added
// default profiles will be returned.
virtual int AddDefaultProfiles();
// Add Widevine custom profiles into profile_list. The number of added custom
// profiles will be returned.
virtual int AddCustomProfiles(
const DeviceSecurityProfileList& device_security_profile_list);
virtual int GetDefaultProfileStrings(
std::vector<std::string>* default_profile_strings) const;
bool DoesProfileQualify(const SecurityProfile& profile,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info) const;
@@ -87,9 +131,19 @@ class SecurityProfileList {
bool IsProfileActive(const SecurityProfile& profile,
int64_t current_time_seconds) const;
bool InsertProfileLocked(const SecurityProfile& profile_to_insert)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Return true if a profile already exists in the profile_list.
bool DoesProfileExistLocked(const SecurityProfile& profile) const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void ClearAllDefaultProfilesLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void ClearAllCustomProfilesLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable absl::Mutex mutex_;
// Security profiles
std::string profile_namespace_;
// TODO(user): Modify as Map<owner, DSPs>.
std::vector<SecurityProfile> security_profiles_ ABSL_GUARDED_BY(mutex_);
};

View File

@@ -104,7 +104,7 @@ constexpr char kTestEcmgChannelStatus[] = {
constexpr char kTestEcmgStreamSetupWithPrivateParameters[] = {
'\x03', // protocol_version
'\x01', '\x01', // message_type - Stream_setup
'\x00', '\xae', // message_length
'\x00', '\xa8', // message_length
'\x00', '\x0e', // parameter_type - ECM_channel_id
'\x00', '\x02', // parameter_length
'\x00', '\x01', // parameter_value
@@ -117,9 +117,6 @@ constexpr char kTestEcmgStreamSetupWithPrivateParameters[] = {
'\x00', '\x10', // parameter_type - nominal_CP_duration
'\x00', '\x02', // parameter_length
'\x00', '\x64', // parameter_value
'\x80', '\x02', // parameter_type - STREAM_TRACK_TYPE
'\x00', '\x02', // parameter_length
'S', 'D', // parameter_value
'\x80', '\x03', // parameter_type - CONTENT_IV
'\x00', '\x10', // parameter_length
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', //
@@ -245,7 +242,7 @@ constexpr char kTestEcmgCwProvision[] = {
constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = {
'\x03', // protocol_version
'\x02', '\x01', // message_type - CW_provision
'\x00', '\xee', // message_length
'\x00', '\xe8', // message_length
'\x00', '\x0e', // parameter_type - ECM_channel_id
'\x00', '\x02', // parameter_length
'\x00', '\x01', // parameter_value
@@ -269,16 +266,13 @@ constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = {
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', //
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', //
'\x00', '\x0d', // parameter_type - access_criteria
'\x00', '\xa6', // parameter_length
'\x00', '\xa0', // parameter_length
'\x80', '\x00', // access_criteria parameter_type - AGE_RESTRICTION
'\x00', '\x01', // parameter_length
'\x00', // parameter_value
'\x80', '\x01', // access_criteria parameter_type - CRYPTO_MODE
'\x00', '\x07', // parameter_length
'A', 'e', 's', 'S', 'c', 't', 'e', // parameter_value
'\x80', '\x02', // access_criteria parameter_type - STREAM_TRACK_TYPE
'\x00', '\x02', // parameter_length
'S', 'D', // parameter_value
'\x80', '\x03', // access_criteria parameter_type - CONTENT_IV
'\x00', '\x10', // parameter_length
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', //

Binary file not shown.

View File

@@ -21,37 +21,60 @@
#include "media_cas_packager_sdk/public/wv_cas_ecm.h"
#include "media_cas_packager_sdk/public/wv_cas_types.h"
const size_t kContentIvSize = 16; // 8 or 16
const bool kKeyRotation = true; // whether key rotation is enabled
const char kCryptoMode[] =
namespace {
constexpr int kEcmVersion = 3; // Choices are 2 and 3.
constexpr size_t kContentIvSize = 16; // 8 or 16
constexpr bool kKeyRotation = true; // whether key rotation is enabled
constexpr char kCryptoMode[] =
"AesScte"; // "AesCbc", "AesCtr", "DvbCsa2", "DvbCsa3", "AesOfb", "AesScte"
const int kEcmPid = 149; // PID for the ECM packet
const int kAgeRestriction = 0; // Age restriction for the ECM
const char kOutputFile[] =
"/tmp/ecm.ts"; // ECM TS packet will be output to here
const uint8_t kTableId = 0x80; // 0x80 or 0x81
const char kDefaultTrackTypeSd[] = "SD";
constexpr int kEcmPid = 149; // PID for the ECM packet
constexpr int kAgeRestriction = 0; // Age restriction for the ECM
constexpr char kOutputFile[] =
"/tmp/ecm.ts"; // ECM TS packet will be output to here
constexpr uint8_t kTableId = 0x80; // 0x80 or 0x81
constexpr char kDefaultTrackTypeSd[] = "SD";
const char kEvenKey[] = "even_key........"; // 16 bytes
const char kEvenKeyId[] = "even_key_id....."; // 16 bytes
const char kEvenContentIv8Bytes[] = "even_iv."; // 8 bytes
const char kEvenContentIv16Bytes[] = "even_iv.even_iv."; // 16 bytes
const char kEvenEntitlementKeyId[] = "fake_key_id1...."; // 16 bytes
const char kEvenEntitlementKey[] =
"fakefakefakefakefakefakefake1..."; // 32 bytes
const char kEvenWrapIv[] = "even_warp_iv...."; // 16 bytes
constexpr char kEvenKey[] = "even_key........"; // 16 bytes
constexpr char kEvenKeyId[] = "even_key_id....."; // 16 bytes
constexpr char kEvenContentIv8Bytes[] = "even_iv."; // 8 bytes
constexpr char kEvenContentIv16Bytes[] = "even_iv.even_iv."; // 16 bytes
constexpr char kEvenEntitlementKeyId[] = "fake_key_id1...."; // 16 bytes
constexpr char kEvenEntitlementKey[] =
"fakefakefakefakefakefakefake1..."; // 32 bytes
constexpr char kEvenWrapIv[] = "even_warp_iv...."; // 16 bytes
const char kOddKey[] = "odd_key........."; // 16 bytes
const char kOddKeyId[] = "odd_key_id......"; // 16 bytes
const char kOddContentIv8Bytes[] = "odd_iv.."; // 8 bytes
const char kOddContentIv16Bytes[] = "odd_iv..odd_iv.."; // 16 bytes
const char kOddEntitlementKeyId[] = "fake_key_id2...."; // 16 bytes
const char kOddEntitlementKey[] =
"fakefakefakefakefakefakefake2..."; // 32 bytes
const char kOddWrapIv[] = "odd_warp_iv....."; // 16 bytes
constexpr char kOddKey[] = "odd_key........."; // 16 bytes
constexpr char kOddKeyId[] = "odd_key_id......"; // 16 bytes
constexpr char kOddContentIv8Bytes[] = "odd_iv.."; // 8 bytes
constexpr char kOddContentIv16Bytes[] = "odd_iv..odd_iv.."; // 16 bytes
constexpr char kOddEntitlementKeyId[] = "fake_key_id2...."; // 16 bytes
constexpr char kOddEntitlementKey[] =
"fakefakefakefakefakefakefake2..."; // 32 bytes
constexpr char kOddWrapIv[] = "odd_warp_iv....."; // 16 bytes
// Fingerprinting and service blocking are only available with ECM v3+.
constexpr char kFingerprintingControl[] = "ctr";
constexpr char kServiceBlockingDeviceGroup1[] = "group";
constexpr char kServiceBlockingDeviceGroup2[] = "g2";
constexpr unsigned char kTestECPrivateKey2Secp256r1[] = {
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x34, 0x9a, 0xf2, 0x95,
0x94, 0xd4, 0xca, 0xb9, 0xa0, 0x81, 0xe4, 0x1c, 0xf5, 0xde, 0x8d,
0x23, 0xf6, 0x79, 0xba, 0x3c, 0x6e, 0xc9, 0x0b, 0x56, 0x0f, 0x07,
0x5e, 0x9f, 0xe9, 0x38, 0x18, 0xfc, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42,
0x00, 0x04, 0x7b, 0x2a, 0x61, 0x59, 0xe5, 0x1b, 0xb6, 0x30, 0x7b,
0x59, 0x98, 0x42, 0x59, 0x37, 0xfb, 0x46, 0xfe, 0x53, 0xfe, 0x32,
0xa1, 0x5c, 0x93, 0x36, 0x11, 0xb0, 0x5a, 0xae, 0xa4, 0x48, 0xe3,
0x20, 0x12, 0xce, 0x78, 0xa7, 0x7f, 0xfd, 0x73, 0x5e, 0x09, 0x77,
0x53, 0x77, 0x8f, 0xd6, 0x1b, 0x26, 0xfa, 0xc4, 0x2c, 0xc4, 0x11,
0xfa, 0x72, 0x6a, 0xbe, 0x94, 0x78, 0x4d, 0x74, 0x20, 0x27, 0x86};
const size_t kTsPacketSize = 188;
const size_t kMaxPossibleTsPacketsSizeBytes = 6 * kTsPacketSize;
using widevine::cas::EcmVersion;
using widevine::cas::EntitlementKeyInfo;
using widevine::cas::WvCasContentKeyInfo;
using widevine::cas::WvCasEcmParameters;
@@ -68,6 +91,9 @@ WvCasEcmParameters CreateWvCasEcmParameters(bool key_rotation,
std::cerr << "Unsupported crypto mode " << kCryptoMode << std::endl;
}
params.age_restriction = kAgeRestriction;
params.ecm_version = kEcmVersion <= 2 ? EcmVersion::kV2 : EcmVersion::kV3;
params.ecc_private_signing_key.assign(std::begin(kTestECPrivateKey2Secp256r1),
std::end(kTestECPrivateKey2Secp256r1));
return params;
}
@@ -115,6 +141,8 @@ std::vector<WvCasContentKeyInfo> CreateContentKeyInfo(bool key_rotation,
return content_keys;
}
} // namespace
int main(int argc, char** argv) {
WvCasEcmParameters params =
CreateWvCasEcmParameters(kKeyRotation, kContentIvSize);
@@ -122,6 +150,17 @@ int main(int argc, char** argv) {
CreateInjectedEntitlements(kKeyRotation);
widevine::cas::WvCasEcm wv_cas_ecm(params, entitlements);
if (params.ecm_version == EcmVersion::kV3) {
widevine::cas::EcmFingerprintingParams fingerprinting_params;
fingerprinting_params.control = kFingerprintingControl;
wv_cas_ecm.SetFingerprinting(&fingerprinting_params);
widevine::cas::EcmServiceBlockingParams service_blocking_params;
service_blocking_params.device_groups = {kServiceBlockingDeviceGroup1,
kServiceBlockingDeviceGroup2};
wv_cas_ecm.SetServiceBlocking(&service_blocking_params);
}
std::vector<WvCasContentKeyInfo> content_keys =
CreateContentKeyInfo(kKeyRotation, kContentIvSize);
std::string ecm;
@@ -147,16 +186,17 @@ int main(int argc, char** argv) {
std::cout << std::endl;
}
// Generate ECM TS Packet.
uint8_t packet[kTsPacketSize];
uint8_t packet[kMaxPossibleTsPacketsSizeBytes];
ssize_t packet_size = kMaxPossibleTsPacketsSizeBytes;
uint8_t continuity_counter; // not used.
status = wv_cas_ecm.GenerateTsPacket(ecm, kEcmPid, kTableId,
&continuity_counter, packet);
status = wv_cas_ecm.GenerateTsPacket(
ecm, kEcmPid, kTableId, &continuity_counter, packet, &packet_size);
if (!status.ok()) {
std::cerr << "Failed to create ECM TS packet: " << status << std::endl;
return -1;
} else {
std::cout << "TS packet bytes: ";
for (size_t i = 0; i < kTsPacketSize; i++) {
for (size_t i = 0; i < packet_size; i++) {
printf("'\\x%02x', ", static_cast<uint16_t>(packet[i]));
}
std::cout << std::endl;
@@ -165,7 +205,7 @@ int main(int argc, char** argv) {
std::ofstream file;
file.open(kOutputFile, std::ios_base::binary);
assert(file.is_open());
file.write(reinterpret_cast<char*>(packet), kTsPacketSize);
file.write(reinterpret_cast<char*>(packet), packet_size);
file.close();
return 0;

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -34,6 +34,18 @@ using widevine::cas::WvCasEcmgClientHandler;
constexpr int kServerPortNumber = 1234;
constexpr int kListenQueueSize = 20;
constexpr int kBufferSizeBytes = 2048;
constexpr unsigned char kTestECPrivateKey2Secp256r1[] = {
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x34, 0x9a, 0xf2, 0x95,
0x94, 0xd4, 0xca, 0xb9, 0xa0, 0x81, 0xe4, 0x1c, 0xf5, 0xde, 0x8d,
0x23, 0xf6, 0x79, 0xba, 0x3c, 0x6e, 0xc9, 0x0b, 0x56, 0x0f, 0x07,
0x5e, 0x9f, 0xe9, 0x38, 0x18, 0xfc, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42,
0x00, 0x04, 0x7b, 0x2a, 0x61, 0x59, 0xe5, 0x1b, 0xb6, 0x30, 0x7b,
0x59, 0x98, 0x42, 0x59, 0x37, 0xfb, 0x46, 0xfe, 0x53, 0xfe, 0x32,
0xa1, 0x5c, 0x93, 0x36, 0x11, 0xb0, 0x5a, 0xae, 0xa4, 0x48, 0xe3,
0x20, 0x12, 0xce, 0x78, 0xa7, 0x7f, 0xfd, 0x73, 0x5e, 0x09, 0x77,
0x53, 0x77, 0x8f, 0xd6, 0x1b, 0x26, 0xfa, 0xc4, 0x2c, 0xc4, 0x11,
0xfa, 0x72, 0x6a, 0xbe, 0x94, 0x78, 0x4d, 0x74, 0x20, 0x27, 0x86};
void BuildEcmgConfig(EcmgConfig* config) {
config->delay_start = 200; // in milliseconds.
@@ -43,6 +55,9 @@ void BuildEcmgConfig(EcmgConfig* config) {
config->access_criteria_transfer_mode = 0;
config->number_of_content_keys = 2;
config->crypto_mode = widevine::cas::CryptoMode::kAesCtr;
config->ecc_private_signing_key.assign(
std::begin(kTestECPrivateKey2Secp256r1),
std::end(kTestECPrivateKey2Secp256r1));
}
void PrintMessage(const std::string& description, const char* const message,

Binary file not shown.

View File

@@ -9,6 +9,7 @@
#ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_
#include <memory>
#include <string>
#include <vector>
@@ -19,6 +20,8 @@
namespace widevine {
namespace cas {
class Ecm;
// Information needed to generate content key portion of ECM.
// Fields:
// |key_id| key ID for the content key, must be 16 bytes.
@@ -44,11 +47,19 @@ struct WvCasContentKeyInfo {
// |crypto_mode| the encryption mode used for the content stream.
// A constant of type CryptoMode.
// |age_restriction| minimum age required; the value represents actual age.
// |cas_id| CA system id that is in the ECM. Must be 0x4AD4 or 0x56C0~0x56C9
// (all inclusive).
// |ecm_version| version of generated ECM.
// |ecc_private_signing_key| Private signing key used to sign ECM data. Must
// be an elliptic-curve cryptography key.
struct WvCasEcmParameters {
EcmIvSize content_iv_size = kIvSize8;
bool key_rotation_enabled = true;
CryptoMode crypto_mode = CryptoMode::kAesCtr;
uint8_t age_restriction = 0;
uint16_t cas_id = 0x4AD4;
EcmVersion ecm_version = EcmVersion::kV2;
std::string ecc_private_signing_key;
};
// Class for generating Widevine CAS ECMs.
@@ -66,10 +77,23 @@ class WvCasEcm {
const std::vector<EntitlementKeyInfo>& injected_entitlements);
WvCasEcm(const WvCasEcm&) = delete;
WvCasEcm& operator=(const WvCasEcm&) = delete;
virtual ~WvCasEcm() = default;
virtual ~WvCasEcm();
// Accept keys and IVs and construct an ECM that will fit into a Transport
// Stream packet payload (184 bytes).
// Set fingerprinting info that will be embedded into the generated ECM. The
// configuration will be used in all following ECMs generated by calling
// GenerateEcm() or GenerateSingleKeyEcm().
// |fingerprinting| may be set to nullptr to clear the fingerprinting info.
virtual void SetFingerprinting(const EcmFingerprintingParams* fingerprinting);
// Set service blocking info that will be embedded into the generated ECM. The
// configuration will be used in all following ECMs generated by calling
// GenerateEcm() or GenerateSingleKeyEcm().
// |service_blocking| may be set to nullptr to clear the service blocking
// info.
virtual void SetServiceBlocking(
const EcmServiceBlockingParams* service_blocking);
// Constructs a Widevine ECM using the provided key info.
// Args:
// |even_key| information for even key to be encoded into ECM.
// |odd_key| information for odd key to be encoded into ECM.
@@ -78,15 +102,14 @@ class WvCasEcm {
// The |even_key| and |odd_key| contents (specifically IV sizes) must be
// consistent with the initialized settings.
// The even_key and odd_key will be wrapped using the appropriate
// entitlement key. Wrapping modifies the original structure.
// entitlement key.
virtual Status GenerateEcm(const WvCasContentKeyInfo& even_key,
const WvCasContentKeyInfo& odd_key,
const std::string& track_type,
std::string* serialized_ecm) const;
// Accept a key and IV and construct an ECM that will fit into a Transport
// Stream packet payload (184 bytes). This call is specifically for the case
// where key rotation is disabled.
// Constructs a Widevine ECM using the provided key info. This call is
// specifically for the case where key rotation is disabled.
// Args:
// |key| information for key to be encoded into ECM.
// |track_type| the track that the key is being used to encrypt.
@@ -112,16 +135,18 @@ class WvCasEcm {
// it will be incremented, only last 4 bits are used
// - |packet| a buffer of size at least 188 bytes to be used to return
// the generated TS packet
// - |packet_size| is the size of the allocated |packet|. It will be updated
// as the number of bytes actually used.
//
// Returns:
// - A status indicating whether there was any error during processing
static Status GenerateTsPacket(const std::string& ecm, uint16_t pid,
uint8_t table_id, uint8_t* continuity_counter,
uint8_t* packet);
uint8_t* packet, ssize_t* packet_size);
private:
std::unique_ptr<Ecm> ecm_;
WvCasEcmParameters ecm_param_;
std::vector<EntitlementKeyInfo> injected_entitlements_;
};
} // namespace cas

View File

@@ -36,6 +36,27 @@ class WvCasEcmgClientHandler {
// Calling this function is optional.
void SetCustomEntitlementKeyFetcherFunc(EntitlementKeyFetcherFunc fetcher);
// Sets the custom access criteria processing function used by ECMG to get
// information including entitlement keys, content iv, crypto mode, etc.
// Calling this function is optional: If the function is set, access criteria
// received in the CwProvision message from SCS will be processed by this
// callback function (SDK will no longer process the access criteria). If not
// set, access criteria will be processed by the SDK.
void SetCustomAccessCriteriaProcessFunc(
CustomAccessCriteriaProcessFunc ac_processor);
// Sets the fingerprinting setting function, which will be called upon each
// CwProvisioning request. It controls the fingerprinting information carried
// in ECMs.
void SetFingerprintingSettingFunc(
FingerprintingSettingFunc fingerprinting_func);
// Sets the service blocking setting function, which will be called upon each
// CwProvisioning request. It controls the service blocking information
// carried in ECMs.
void SetServiceBlockingSettingFunc(
ServiceBlockingSettingFunc service_blocking_func);
// Handles a |request| from the SCS client. If any response is generated, it
// will return the response via |response_buffer| and |response_length|.
// Args:

View File

@@ -9,6 +9,7 @@
#ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_TYPES_H_
#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_TYPES_H_
#include <functional>
#include <string>
#include <vector>
@@ -65,6 +66,8 @@ struct EntitlementKeyInfo {
std::string key_value; // must be 32 bytes.
};
enum class EcmVersion : int { kV2 = 0, kV3 = 1 };
// 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).
@@ -109,6 +112,11 @@ struct EcmgConfig {
// will be included in the ECM. If new crypto_mode is received from SCS, ECM
// will use the new one.
CryptoMode crypto_mode;
// Version of generated ECM.
EcmVersion ecm_version = EcmVersion::kV2;
// Private signing key used to sign ECM data. Must be an elliptic-curve
// cryptography key.
std::string ecc_private_signing_key;
};
// A custom entitlement key fetching function used by ECMG to fetch entitlement
@@ -127,6 +135,82 @@ struct EcmgConfig {
using EntitlementKeyFetcherFunc = std::vector<EntitlementKeyInfo> (*)(
uint16_t channel_id, uint16_t stream_id, uint16_t ecm_id);
struct EcmgCustomParameters {
// Minimum age required for the content. The value represents actual age.
// A negative value means the field is not set.
int age_restriction = -1;
// The encryption mode used for the content stream.
std::string crypto_mode;
// Initial vector used in the content encryption, must be 8 (DvbCsa2) or 16
// bytes (all other crypto modes). The size of the vector must not exceed 2.
// The first entry is for the even key slot, the second entry is for the odd
// key slot. It is suggested that the same IV used for both even and odd key
// slot for better decrypting performance.
std::vector<std::string> content_ivs;
// Entitlement keys used to encrypt the content keys (control words).
// The size of the vector must not exceed 2. When the vector size is 2, one of
// them must be specified as even key and the other must be odd key (sequence
// does not matter).
std::vector<EntitlementKeyInfo> entitlement_keys;
// Fingerprinting control that will be embedded in ECM. The control is opaque
// to Widevine.
std::string fingerprinting_control;
// Devices that should have service blocking enforced. The blocking starts
// when the ECM is received, and stops util the device is no longer in
// |device_groups|.
std::vector<std::string> service_blocking_groups;
};
// A custom access control processing function used by ECMG to get information
// including entitlement keys, content iv, crypto mode, etc. If set, the
// function will be called when an access criteria is received in the
// CwProvision message from SCS. The access criteria will no longer be processed
// by the SDK.
// Args:
// |channel_id| is the channel id received at ECMG from SCS when setting up
// the channel.
// |stream_id| is the stream id received at ECMG from SCS when setting up
// the stream.
// |access_criteria| the received access criteria from SCS.
// Returns EcmgCustomParameters. Negative or empty fields will be ignored.
typedef std::function<EcmgCustomParameters(uint16_t channel_id, uint16_t stream_id,
const std::string& access_criteria)>
CustomAccessCriteriaProcessFunc;
struct EcmFingerprintingParams {
// The |control| is opaque to Widevine.
std::string control;
};
// Function that will be called upon each CwProvisioning request. It controls
// the fingerprinting information carried in ECMs.
// Args:
// |channel_id| is the channel id received at ECMG from SCS when setting up
// the channel.
// |stream_id| is the stream id received at ECMG from SCS when setting up
// the stream.
typedef std::function<EcmFingerprintingParams(uint16_t channel_id,
uint16_t stream_id)>
FingerprintingSettingFunc;
struct EcmServiceBlockingParams {
// Devices that should have service blocking enforced. The blocking starts
// when the ECM is received, and stops util the device is no longer in
// |device_groups|.
std::vector<std::string> device_groups;
};
// Function that will be called upon each CwProvisioning request. It controls
// the service blocking information carried in ECMs.
// Args:
// |channel_id| is the channel id received at ECMG from SCS when setting up
// the channel.
// |stream_id| is the stream id received at ECMG from SCS when setting up
// the stream.
typedef std::function<EcmServiceBlockingParams(uint16_t channel_id,
uint16_t stream_id)>
ServiceBlockingSettingFunc;
struct WvCasEncryptionRequest {
std::string content_id;
std::string provider;

View File

@@ -50,3 +50,62 @@ message EmmPayload {
repeated Fingerprinting fingerprinting = 1;
repeated ServiceBlocking service_blocking = 2;
}
message EcmMetaData {
enum CipherMode {
UNSPECIFIED = 0;
AES_CBC = 1;
AES_CTR = 2;
DVB_CSA2 = 3;
DVB_CSA3 = 4;
AES_OFB = 5;
AES_SCTE52 = 6;
}
// Required. The cipher mode used to encrypt/decrypt the content.
optional CipherMode cipher_mode = 1;
// 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];
}
message EcmKeyData {
// The wrapped content key data (aka control word).
// Required.
optional bytes wrapped_key_data = 1;
// The ID of the entitlement key used to wrap the content key. The secure key
// data associated with this ID is held by the license server. The client gets
// the key from the license server through a license request.
// Required for the even key data, optional for the odd key data if it is the
// same as the even key data.
optional bytes entitlement_key_id = 2;
// IV for decrypting the wrapped_key_data.
// Required for the even key data, optional for the odd key data if it is the
// same as the even key data.
optional bytes wrapped_key_iv = 3;
// IV for decrypting the content stream.
// Optional. If not specified in the even key data, 8 bytes 0x00 will be used;
// If not specified in the odd key data, the same content iv in the even key
// data will be used.
optional bytes content_iv = 4;
}
message EcmPayload {
// Required. Meta info carried by the ECM.
optional EcmMetaData meta_data = 1;
// Required. The key data for the even slot.
optional EcmKeyData even_key_data = 2;
// Optional. The key data for the odd slot if key rotation is enabled.
optional EcmKeyData odd_key_data = 3;
// Optional. Widevine fingerprinting information.
optional Fingerprinting fingerprinting = 4;
// Optional. Widevine service blocking information.
optional ServiceBlocking service_blocking = 5;
}
// The payload field for an ECM with signature.
message SignedEcmPayload {
// Serialized EcmPayload.
optional bytes serialized_payload = 1;
// ECC (Elliptic Curve Cryptography) signature of |serialized_payload|.
optional bytes signature = 2;
}