diff --git a/example/test_ecmg_messages.h b/example/test_ecmg_messages.h index b4c7ae5..77a018e 100644 --- a/example/test_ecmg_messages.h +++ b/example/test_ecmg_messages.h @@ -14,7 +14,7 @@ namespace widevine { namespace cas { -const char kTestEcmgChannelSetup[] = { +constexpr char kTestEcmgChannelSetup[] = { '\x03', // protocol_version '\x00', '\x01', // message_type - Channel_setup '\x00', '\x0e', // message_length @@ -26,7 +26,55 @@ const char kTestEcmgChannelSetup[] = { '\x4a', '\xd4', '\x00', '\x00' // parameter_value }; -const char kTestEcmgChannelStatus[] = { +constexpr char kTestEcmgChannelSetupWithPrivateParameters[] = { + '\x03', // protocol_version + '\x00', '\x01', // message_type - Channel_setup + '\x00', '\x70', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x01', // parameter_type- SUPER_CAS_ID + '\x00', '\x04', // parameter_length + '\x4a', '\xd4', '\x00', '\x00', // parameter_value + '\x80', '\x00', // parameter_type - AGE_RESTRICTION + '\x00', '\x01', // parameter_length + '\x00', // parameter_value + '\x80', '\x01', // parameter_type - CRYPTO_MODE + '\x00', '\x07', // parameter_length + 'A', 'e', 's', 'S', 'c', 't', 'e', // parameter_value + '\x80', '\x04', // parameter_type - TRACK_TYPES + '\x00', '\x02', // parameter_length + 'S', 'D', // parameter_value + '\x80', '\x04', // parameter_type - TRACK_TYPES + '\x00', '\x02', // parameter_length + 'H', 'D', // parameter_value + '\x80', '\x02', // parameter_type - CONTENT_ID + '\x00', '\x09', // parameter_length + 'C', 'a', 's', 'T', 's', 'F', 'a', 'k', + 'e', // parameter_value - CasTsFake + '\x80', '\x03', // parameter_type - CONTENT_PROVIDER + '\x00', '\x0d', // parameter_length + 'w', 'i', 'd', 'e', 'v', 'i', 'n', 'e', + '_', 't', 'e', 's', 't', // parameter_value - widevine_test + '\x80', '\x06', // parameter_type - CONTENT_IV + '\x00', '\x10', // parameter_length + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x80', '\x06', // parameter_type - CONTENT_IV + '\x00', '\x10', // parameter_length + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'}; + +constexpr char kTestEcmgChannelTest[] = { + '\x03', // protocol_version + '\x00', '\x02', // message_type - Channel_test + '\x00', '\x06', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value +}; + +constexpr char kTestEcmgChannelStatus[] = { '\x03', // protocol_version '\x00', '\x03', // message_type - Channel_status '\x00', '\x39', // message_length @@ -62,7 +110,28 @@ const char kTestEcmgChannelStatus[] = { '\x00', '\x64' // parameter_value }; -const char kTestEcmgStreamSetup[] = { +constexpr char kTestEcmgStreamSetupWithPrivateParameters[] = { + '\x03', // protocol_version + '\x01', '\x01', // message_type - Stream_setup + '\x00', '\x1e', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x19', // parameter_type - ECM_id + '\x00', '\x02', // parameter_length + '\x00', '\x02', // parameter_value + '\x00', '\x10', // parameter_type - nominal_CP_duration + '\x00', '\x02', // parameter_length + '\x00', '\x64', // parameter_value + '\x80', '\x05', // parameter_type - STREAM_TRACK_TYPE + '\x00', '\x02', // parameter_length + 'S', 'D', // parameter_value +}; + +constexpr char kTestEcmgStreamSetup[] = { '\x03', // protocol_version '\x01', '\x01', // message_type - Stream_setup '\x00', '\x18', // message_length @@ -80,7 +149,19 @@ const char kTestEcmgStreamSetup[] = { '\x00', '\x64' // parameter_value }; -const char kTestEcmgStreamStatus[] = { +constexpr char kTestEcmgStreamTest[] = { + '\x03', // protocol_version + '\x01', '\x02', // message_type - Stream_test + '\x00', '\x0c', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value +}; + +constexpr char kTestEcmgStreamStatus[] = { '\x03', // protocol_version '\x01', '\x03', // message_type - Stream_status '\x00', '\x17', // message_length @@ -98,7 +179,7 @@ const char kTestEcmgStreamStatus[] = { '\x01' // parameter_value }; -const char kTestEcmgCwProvision[] = { +constexpr char kTestEcmgCwProvision[] = { '\x03', // protocol_version '\x02', '\x01', // message_type - CW_provision '\x00', '\x44', // message_length @@ -125,8 +206,87 @@ const char kTestEcmgCwProvision[] = { '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'}; +constexpr char kTestEcmgCwProvisionWithAccessCriteria[] = { + '\x03', // protocol_version + '\x02', '\x01', // message_type - CW_provision + '\x00', '\xaa', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x12', // parameter_type - CP_number + '\x00', '\x02', // parameter_length + '\x00', '\x00', // parameter_value + '\x00', '\x13', // parameter_type - CP_duration + '\x00', '\x02', // parameter_length + '\x00', '\x64', // parameter_value + '\x00', '\x14', // parameter_type - CP_CW_Combination + '\x00', '\x12', // parameter_length + '\x00', '\x00', // parameter_value - CP (2 bytes) then CW next (16 bytes) + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x00', '\x14', // parameter_type - CP_CW_Combination + '\x00', '\x12', // parameter_length + '\x00', '\x01', // parameter_value - CP (2 bytes) then CW next (16 bytes) + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', + '\x00', '\x0d', // parameter_type - access_criteria + '\x00', '\x62', // 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', '\x04', // access_criteria parameter_type - TRACK_TYPES + '\x00', '\x02', // parameter_length + 'S', 'D', // parameter_value + '\x80', '\x05', // access_criteria parameter_type - STREAM_TRACK_TYPE + '\x00', '\x02', // parameter_length + 'S', 'D', // parameter_value + '\x80', '\x02', // access_criteria parameter_type - CONTENT_ID + '\x00', '\x09', // parameter_length + 'C', 'a', 's', 'T', 's', 'F', 'a', 'k', + 'e', // parameter_value - CasTsFake + '\x80', '\x03', // access_criteria parameter_type - CONTENT_PROVIDER + '\x00', '\x0d', // parameter_length + 'w', 'i', 'd', 'e', 'v', 'i', 'n', 'e', + '_', 't', 'e', 's', 't', // parameter_value - widevine_test + '\x80', '\x06', // access_criteria parameter_type - CONTENT_IV + '\x00', '\x10', // parameter_length + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x80', '\x06', // access_criteria parameter_type - CONTENT_IV + '\x00', '\x10', // parameter_length + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'}; + +constexpr char kTestEcmgCwProvisionSingleKey[] = { + '\x03', // protocol_version + '\x02', '\x01', // message_type - CW_provision + '\x00', '\x2e', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x12', // parameter_type - CP_number + '\x00', '\x02', // parameter_length + '\x00', '\x00', // parameter_value + '\x00', '\x13', // parameter_type - CP_duration + '\x00', '\x02', // parameter_length + '\x00', '\x64', // parameter_value + '\x00', '\x14', // parameter_type - CP_CW_Combination + '\x00', '\x12', // parameter_length + '\x00', '\x00', // parameter_value - CP (2 bytes) then CW next (16 bytes) + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f'}; + // CW is encrypted using hardcoded fixed entitlement key. -const char kTestEcmgEcmResponse[] = { +constexpr char kTestEcmgEcmResponse[] = { '\x03', // protocol_version '\x02', '\x02', // message_type - ECM_response '\x00', '\xd2', // message_length @@ -142,8 +302,8 @@ const char kTestEcmgEcmResponse[] = { '\x00', '\x15', // parameter_type - ECM_datagram '\x00', '\xbc', // parameter_length // parameter_value - ECM_datagram - '\x47', '\x40', '\x02', '\x10', '\x00', '\x80', '\x70', '\x95', '\x4a', - '\xd4', '\x01', '\x05', '\x80', '\x66', '\x61', '\x6b', '\x65', '\x5f', + '\x47', '\x40', '\x00', '\x10', '\x00', '\x80', '\x70', '\xa5', '\x4a', + '\xd4', '\x02', '\x0b', '\xc0', '\x66', '\x61', '\x6b', '\x65', '\x5f', '\x6b', '\x65', '\x79', '\x5f', '\x69', '\x64', '\x31', '\x2e', '\x2e', '\x2e', '\x2e', '\xef', '\x40', '\x57', '\x48', '\xa7', '\xad', '\xdd', '\x34', '\x73', '\xfe', '\x5d', '\x1c', '\x65', '\xa0', '\xbf', '\x93', @@ -164,7 +324,7 @@ const char kTestEcmgEcmResponse[] = { '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff'}; -const char kTestEcmgStreamCloseRequest[] = { +constexpr char kTestEcmgStreamClose[] = { '\x03', // protocol_version '\x01', '\x04', // message_type - Stream_close_request '\x00', '\x0c', // message_length @@ -176,7 +336,7 @@ const char kTestEcmgStreamCloseRequest[] = { '\x00', '\x01' // parameter_value }; -const char kTestEcmgStreamCloseResponse[] = { +constexpr char kTestEcmgStreamCloseResponse[] = { '\x03', // protocol_version '\x01', '\x05', // message_type - Stream_close_response '\x00', '\x0c', // message_length @@ -188,7 +348,7 @@ const char kTestEcmgStreamCloseResponse[] = { '\x00', '\x01' // parameter_value }; -const char kTestEcmgChannelClose[] = { +constexpr char kTestEcmgChannelClose[] = { '\x03', // protocol_version '\x00', '\x04', // message_type - Channel_close '\x00', '\x06', // message_length @@ -197,6 +357,57 @@ const char kTestEcmgChannelClose[] = { '\x00', '\x01' // parameter_value }; +constexpr char kTestChannelErrorResponse[] = { + '\x03', // protocol_version + '\x00', '\x05', // message_type - Channel_error_response + '\x00', '\x0c', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x70', '\x00', // parameter_type - error_status + '\x00', '\x02', // parameter_length + '\x00', '\x00' // parameter_value: actual value varies. +}; + +constexpr char kTestStreamErrorResponse[] = { + '\x03', // protocol_version + '\x01', '\x06', // message_type - Stream_error_response + '\x00', '\x12', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x70', '\x00', // parameter_type - error_status + '\x00', '\x02', // parameter_length + '\x00', '\x00' // parameter_value: actual value varies. +}; + +constexpr char kTestEcmgChannelSetupWrongParameterLength[] = { + '\x03', // protocol_version + '\x00', '\x01', // message_type - Channel_setup + '\x00', '\x0e', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x01', // parameter_type- SUPER_CAS_ID + '\x00', '\x02', // parameter_length -- Should be \x04 + '\x4a', '\xd4', '\x00', '\x00' // parameter_value +}; + +constexpr char kTestEcmgChannelSetupWrongMessageLength[] = { + '\x03', // protocol_version + '\x00', '\x01', // message_type - Channel_setup + '\x00', '\xee', // message_length -- Should be \x0e + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x01', // parameter_type- SUPER_CAS_ID + '\x00', '\x04', // parameter_length -- Should be \x04 + '\x4a', '\xd4', '\x00', '\x00' // parameter_value +}; + } // namespace cas } // namespace widevine diff --git a/example/wv_cas_ecm_example b/example/wv_cas_ecm_example index 1460a89..1507c92 100644 Binary files a/example/wv_cas_ecm_example and b/example/wv_cas_ecm_example differ diff --git a/example/wv_cas_ecm_example.cc b/example/wv_cas_ecm_example.cc index ae97860..9f06fae 100644 --- a/example/wv_cas_ecm_example.cc +++ b/example/wv_cas_ecm_example.cc @@ -8,11 +8,15 @@ // Example of how to use the wv_cas_ecm library. +#include +#include + #include #include #include #include +#include #include "media_cas_packager_sdk/public/wv_cas_ecm.h" #include "media_cas_packager_sdk/public/wv_cas_types.h" @@ -96,11 +100,11 @@ int main(int argc, char** argv) { std::cout << std::endl; } // Write ECM TS Packet to a file. - std::ofstream file; - file.open(kOutputFile, std::ios_base::binary); - assert(file.is_open()); - file.write(reinterpret_cast(packet), kTsPacketSize); - file.close(); + std::ofstream file; + file.open(kOutputFile, std::ios_base::binary); + assert(file.is_open()); + file.write(reinterpret_cast(packet), kTsPacketSize); + file.close(); return 0; } diff --git a/example/wv_cas_key_fetcher_example b/example/wv_cas_key_fetcher_example index 67e1e72..65c4df7 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 40dc653..f79589c 100644 --- a/example/wv_cas_key_fetcher_example.cc +++ b/example/wv_cas_key_fetcher_example.cc @@ -7,36 +7,39 @@ //////////////////////////////////////////////////////////////////////////////// -#include #include -#include "gflags/gflags.h" #include "glog/logging.h" +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" #include "common/status.h" #include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h" #include "protos/public/media_cas_encryption.pb.h" -DEFINE_string(content_id, "21140844", "Content ID"); -DEFINE_bool(key_rotation, true, "Whether key rotation is enabled"); -DEFINE_string(track_type, "SD", "Provider name"); +ABSL_FLAG(std::string, content_id, "21140844", "Content ID"); +ABSL_FLAG(bool, key_rotation, true, "Whether key rotation is enabled"); +ABSL_FLAG(std::string, track_type, "SD", "Provider name"); int main(int argc, char **argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - CHECK(!FLAGS_content_id.empty() && !FLAGS_track_type.empty()) + absl::ParseCommandLine(argc, argv); + CHECK(!absl::GetFlag(FLAGS_content_id).empty() && + !absl::GetFlag(FLAGS_track_type).empty()) << "Flags 'content_id' and 'track_type' are required"; // Required flags in key fetcher. - CHECK(!FLAGS_license_server.empty() && !FLAGS_signing_provider.empty() && - !FLAGS_signing_key.empty() && !FLAGS_signing_iv.empty()) + CHECK(!absl::GetFlag(FLAGS_license_server).empty() && + !absl::GetFlag(FLAGS_signing_provider).empty() && + !absl::GetFlag(FLAGS_signing_key).empty() && + !absl::GetFlag(FLAGS_signing_iv).empty()) << "Flags 'license_server', 'signing_provider', 'signing_key' " "and 'signing_iv' are required"; std::string request_str; widevine::CasEncryptionRequest request; - request.set_provider(FLAGS_signing_provider); - request.set_content_id(FLAGS_content_id); - request.set_key_rotation(FLAGS_key_rotation); + request.set_provider(absl::GetFlag(FLAGS_signing_provider)); + request.set_content_id(absl::GetFlag(FLAGS_content_id)); + request.set_key_rotation(absl::GetFlag(FLAGS_key_rotation)); // Only 1 track in this example. - request.add_track_types(FLAGS_track_type); + request.add_track_types(absl::GetFlag(FLAGS_track_type)); LOG(INFO) << "Request: " << request.ShortDebugString(); if (!request.SerializeToString(&request_str)) { LOG(ERROR) << "Failed to serialize request"; diff --git a/example/wv_cas_types_example b/example/wv_cas_types_example index c37da53..5bcaab7 100644 Binary files a/example/wv_cas_types_example and b/example/wv_cas_types_example differ diff --git a/example/wv_cas_types_example.cc b/example/wv_cas_types_example.cc index c0bddda..239f391 100644 --- a/example/wv_cas_types_example.cc +++ b/example/wv_cas_types_example.cc @@ -10,6 +10,7 @@ #include #include +#include #include "media_cas_packager_sdk/public/wv_cas_types.h" diff --git a/libmedia_cas_packager_sdk.so b/libmedia_cas_packager_sdk.so index f1dfc22..e081ede 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 a26e8cf..7323d56 100644 --- a/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h +++ b/media_cas_packager_sdk/public/wv_cas_ca_descriptor.h @@ -10,8 +10,10 @@ #define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_CA_DESCRIPTOR_H_ #include + #include +#include #include "media_cas_packager_sdk/public/wv_cas_types.h" namespace widevine { @@ -53,10 +55,9 @@ 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 WvCasStatus GenerateCaDescriptor(uint16_t ca_pid, - const std::string& provider, - const std::string& content_id, - std::string* serialized_ca_desc) const; + virtual WvCasStatus GenerateCaDescriptor( + uint16_t ca_pid, const std::string& provider, const std::string& content_id, + 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 @@ -65,7 +66,7 @@ class WvCasCaDescriptor { // Return private data in the CA descriptor. virtual std::string GeneratePrivateData(const std::string& provider, - const std::string& content_id) const; + const std::string& content_id) 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 d85623c..fafc608 100644 --- a/media_cas_packager_sdk/public/wv_cas_ecm.h +++ b/media_cas_packager_sdk/public/wv_cas_ecm.h @@ -9,13 +9,9 @@ #ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_ #define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_ -#include -#include -#include #include -#include -#include +#include #include "media_cas_packager_sdk/public/wv_cas_types.h" namespace widevine { @@ -118,7 +114,7 @@ class WvCasEcm { // - |pid| program ID for the ECM stream // - |table_id| is the table ID byte put in the section header, it should be // either 0x80 or 0x81. Changing table ID from 0x80 or 0x81 or - // 0x81 to 0x80 is used to singal to the client that the key contained + // 0x81 to 0x80 is used to signal to the client that the key contained // in the ECM has changed. In other words, if you are building an ECM // with a new key that was not in any previous ECM, you should flip the // table ID so the client knows this is an important ECM it should process. @@ -132,7 +128,7 @@ class WvCasEcm { virtual WvCasStatus GenerateTsPacket(const std::string& ecm, uint16_t pid, uint8_t table_id, uint8_t* continuity_counter, - uint8_t* packet); + uint8_t* packet) const; private: bool initialized_ = false; diff --git a/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc b/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc index d8efb49..6b9e7fb 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc @@ -10,40 +10,42 @@ #include #include -#include -#include "gflags/gflags.h" +#include #include "glog/logging.h" #include "google/protobuf/util/json_util.h" +#include "absl/flags/flag.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "curl/curl.h" #include "curl/easy.h" #include "common/signature_util.h" +#include "common/status.h" #include "protos/public/media_cas_encryption.pb.h" using google::protobuf::util::JsonPrintOptions; using google::protobuf::util::JsonStringToMessage; using google::protobuf::util::MessageToJsonString; -DEFINE_string( - license_server, "", - "HTTP URL to the license server for making CAS encryption request"); -DEFINE_string(signing_provider, "", - "Name of the provider signing the CAS encryption request"); -DEFINE_string(signing_key, "", - "AES key (in hex) for signing the CAS encryption request"); -DEFINE_string(signing_iv, "", - "AES iv (in hex) for signing the CAS encryption request"); +ABSL_FLAG(std::string, license_server, "", + "HTTP URL to the license server for making CAS encryption request."); +ABSL_FLAG(std::string, signing_provider, "", + "Name of the provider signing the CAS encryption request."); +ABSL_FLAG(std::string, signing_key, "", + "AES key (in hex) for signing the CAS encryption request."); +ABSL_FLAG(std::string, signing_iv, "", + "AES iv (in hex) for signing the CAS encryption request."); namespace widevine { namespace cas { -Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string, - std::string* signed_response_string) { - if (FLAGS_signing_provider.empty() || FLAGS_signing_key.empty() || - FLAGS_signing_iv.empty()) { +Status WvCasKeyFetcher::RequestEntitlementKey( + const std::string& request_string, + std::string* signed_response_string) const { + if (absl::GetFlag(FLAGS_signing_provider).empty() || + absl::GetFlag(FLAGS_signing_key).empty() || + absl::GetFlag(FLAGS_signing_iv).empty()) { return Status( error::INVALID_ARGUMENT, "Flag 'signing_provider', 'signing_key' or 'signing_iv' is empty"); @@ -72,13 +74,14 @@ Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string, signed_request.set_request(request_json); std::string signature; if (!signature_util::GenerateAesSignature( - request_json, absl::HexStringToBytes(FLAGS_signing_key), - absl::HexStringToBytes(FLAGS_signing_iv), &signature) + request_json, + absl::HexStringToBytes(absl::GetFlag(FLAGS_signing_key)), + absl::HexStringToBytes(absl::GetFlag(FLAGS_signing_iv)), &signature) .ok()) { return Status(error::INTERNAL, "Failed to sign the request."); } signed_request.set_signature(signature); - signed_request.set_signer(FLAGS_signing_provider); + signed_request.set_signer(absl::GetFlag(FLAGS_signing_provider)); std::string signed_request_json; // NOTE: MessageToJsonString will automatically converts the 'request' and // 'signature' fields in SignedCasEncryptionRequest to base64, because they @@ -115,7 +118,8 @@ Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string, return OkStatus(); } -size_t AppendToString(void* ptr, size_t size, size_t count, std::string* output) { +size_t AppendToString(void* ptr, size_t size, size_t count, + std::string* output) { const absl::string_view data(static_cast(ptr), size * count); absl::StrAppend(output, data); return data.size(); @@ -124,14 +128,15 @@ size_t AppendToString(void* ptr, size_t size, size_t count, std::string* output) Status WvCasKeyFetcher::MakeHttpRequest(const std::string& signed_request_json, std::string* http_response_json) const { CHECK(http_response_json); - if (FLAGS_license_server.empty()) { + if (absl::GetFlag(FLAGS_license_server).empty()) { return Status(error::INVALID_ARGUMENT, "Flag 'license_server' is empty"); } CURL* curl; CURLcode curl_code; curl = curl_easy_init(); if (curl) { - curl_easy_setopt(curl, CURLOPT_URL, FLAGS_license_server.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, + absl::GetFlag(FLAGS_license_server).c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, signed_request_json.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEDATA, http_response_json); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &AppendToString); @@ -140,8 +145,9 @@ Status WvCasKeyFetcher::MakeHttpRequest(const std::string& signed_request_json, (int64_t)strlen(signed_request_json.c_str())); curl_code = curl_easy_perform(curl); if (curl_code != CURLE_OK) { - return Status(error::INTERNAL, "curl_easy_perform() failed: " + - std::string(curl_easy_strerror(curl_code))); + return Status(error::INTERNAL, + "curl_easy_perform() failed: " + + std::string(curl_easy_strerror(curl_code))); } curl_easy_cleanup(curl); } else { 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 f91dbd6..815c93d 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.h +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.h @@ -11,14 +11,10 @@ #include -#include "gflags/gflags.h" +#include "absl/flags/declare.h" +#include "common/status.h" #include "media_cas_packager_sdk/internal/key_fetcher.h" -DECLARE_string(license_server); -DECLARE_string(signing_provider); -DECLARE_string(signing_key); -DECLARE_string(signing_iv); - namespace widevine { namespace cas { @@ -29,7 +25,7 @@ class WvCasKeyFetcher : public KeyFetcher { WvCasKeyFetcher() = default; WvCasKeyFetcher(const WvCasKeyFetcher&) = delete; WvCasKeyFetcher& operator=(const WvCasKeyFetcher&) = delete; - virtual ~WvCasKeyFetcher() = default; + ~WvCasKeyFetcher() override = default; // Get entitlement keys from the license server. Send a // SignedCasEncryptionRequest message to the license server, receive a @@ -40,8 +36,9 @@ class WvCasKeyFetcher : public KeyFetcher { // |signed_response_string| a serialized SignedCasEncryptionResponse // message. It should be passed into // widevine::cas::Ecm::ProcessCasEncryptionResponse(). - Status RequestEntitlementKey(const std::string& request_string, - std::string* signed_response_string) override; + Status RequestEntitlementKey( + const std::string& request_string, + std::string* signed_response_string) const override; protected: // Makes a HTTP request to License Server for entitlement key(s). @@ -54,4 +51,10 @@ class WvCasKeyFetcher : public KeyFetcher { } // namespace cas } // namespace widevine +// Exposed for testing and example. +ABSL_DECLARE_FLAG(std::string, license_server); +ABSL_DECLARE_FLAG(std::string, signing_provider); +ABSL_DECLARE_FLAG(std::string, signing_key); +ABSL_DECLARE_FLAG(std::string, signing_iv); + #endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_KEY_FETCHER_H_ diff --git a/media_cas_packager_sdk/public/wv_cas_types.cc b/media_cas_packager_sdk/public/wv_cas_types.cc index cd74c90..95694e1 100644 --- a/media_cas_packager_sdk/public/wv_cas_types.cc +++ b/media_cas_packager_sdk/public/wv_cas_types.cc @@ -46,9 +46,13 @@ std::string GetWvCasStatusMessage(WvCasStatus status) { // Numeric value of crypto mode is the index into strings array. static const char* kCrypoModeStrings[] = { - "AesCbc", - "AesCtr", - "DvbCsa2", + "AesCbc", "AesCtr", "DvbCsa2", "DvbCsa3", "AesOfb", "AesScte", +}; + +// Numeric value of scrambling level is the index into strings array. +static const char* kScramblingLevelStrings[] = { + "PES", + "TS", }; bool CryptoModeToString(CryptoMode mode, std::string* str) { @@ -69,7 +73,7 @@ bool StringToCryptoMode(const std::string& str, CryptoMode* mode) { return false; } for (int i = 0; i < arraysize(kCrypoModeStrings); ++i) { - if (str.compare(kCrypoModeStrings[i]) == 0) { + if (str == kCrypoModeStrings[i]) { *mode = static_cast(i); return true; } @@ -78,6 +82,33 @@ bool StringToCryptoMode(const std::string& str, CryptoMode* mode) { return false; } +bool ScramblingLevelToString(ScramblingLevel mode, std::string* str) { + if (str == nullptr) { + return false; + } + int mode_idx = static_cast(mode); + if (mode_idx >= 0 && mode_idx < arraysize(kScramblingLevelStrings)) { + *str = kScramblingLevelStrings[mode_idx]; + return true; + } + LOG(ERROR) << "Invalid scrambling mode: " << mode_idx; + return false; +} + +bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode) { + if (mode == nullptr) { + return false; + } + for (int i = 0; i < arraysize(kScramblingLevelStrings); ++i) { + if (str == kScramblingLevelStrings[i]) { + *mode = static_cast(i); + return true; + } + } + LOG(ERROR) << "Invalid scrambling mode: " << str; + return false; +} + WvCasStatus CreateWvCasEncryptionRequestJson( const WvCasEncryptionRequest& request, std::string* request_json) { CHECK(request_json); diff --git a/media_cas_packager_sdk/public/wv_cas_types.h b/media_cas_packager_sdk/public/wv_cas_types.h index 883fd5a..cbea067 100644 --- a/media_cas_packager_sdk/public/wv_cas_types.h +++ b/media_cas_packager_sdk/public/wv_cas_types.h @@ -52,19 +52,31 @@ enum WvCasStatus { std::string GetWvCasStatusMessage(WvCasStatus status); // Crypto mode for encryption / decryption. ENUM value should be consistent with -// https://docs.google.com/document/d/1A5vflf8tbKyUheV-xsvfxFqB6YyNLNdsGXYx8ZnhjfY/edit#heading=h.ej4ts3lifoio +// ECM V2 definition. Largest supported value for this CryptoMode ENUM is 15. enum class CryptoMode : int { + kInvalid = -1, kAesCbc = 0, kAesCtr = 1, kDvbCsa2 = 2, + kDvbCsa3 = 3, + kAesOfb = 4, + kAesScte = 5, }; +enum class ScramblingLevel : int { kPES = 0, kTS = 1 }; + // Returns false if mode is not a valid CryptoMode. bool CryptoModeToString(CryptoMode mode, std::string* str); // Returns false if str is not a valid CryptoMode. bool StringToCryptoMode(const std::string& str, CryptoMode* mode); +// Returns false if mode is not a valid ScramblingLevel. +bool ScramblingLevelToString(ScramblingLevel mode, std::string* str); + +// Returns false if str is not a valid ScramblingLevel. +bool StringToScramblingLevel(const std::string& str, ScramblingLevel* mode); + struct WvCasEncryptionRequest { std::string content_id; std::string provider; @@ -111,7 +123,7 @@ struct WvCasEncryptionResponse { // This request JSON can be later put into the 'request' field of a signed // request JSON message. // And that signed JSON message can be sent to Widevine license server for -// aquiring entitlement keys. +// acquiring entitlement keys. WvCasStatus CreateWvCasEncryptionRequestJson( const WvCasEncryptionRequest& request, std::string* request_json); diff --git a/media_cas_packager_sdk/public/wv_ecmg b/media_cas_packager_sdk/public/wv_ecmg index 6c36776..9432caf 100644 Binary files a/media_cas_packager_sdk/public/wv_ecmg and b/media_cas_packager_sdk/public/wv_ecmg differ