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

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