From 1ce468e5ba3a7cfff7d1d9634f7a17c2fa34213f Mon Sep 17 00:00:00 2001 From: Lu Chen Date: Tue, 15 Sep 2020 09:16:59 -0700 Subject: [PATCH] Add EMMG to carry fingerprinting and service blocking info --- common/BUILD | 17 + common/aes_cbc_util_test.cc | 166 ---- common/certificate_client_cert.cc | 280 ------ common/certificate_client_cert.h | 114 --- common/certificate_type.h | 22 - common/client_cert.cc | 130 --- common/client_cert.h | 99 -- common/client_cert_test.cc | 867 ----------------- common/client_id_util.cc | 126 --- common/client_id_util.h | 71 -- common/content_id_util.cc | 83 -- common/content_id_util.h | 37 - common/content_id_util_test.cc | 82 -- common/core_message_util.cc | 78 -- common/core_message_util.h | 40 - common/crypto_util_test.cc | 318 ------ .../default_device_security_profile_list.cc | 135 --- common/default_device_security_profile_list.h | 39 - ...fault_device_security_profile_list_test.cc | 186 ---- common/device_info_util.cc | 42 - common/device_info_util.h | 30 - common/device_status_list.cc | 598 ------------ common/device_status_list.h | 279 ------ common/device_status_list_test.cc | 918 ------------------ common/drm_root_certificate.cc | 574 ----------- common/drm_root_certificate.h | 111 --- common/drm_root_certificate_test.cc | 415 -------- common/drm_service_certificate.cc | 316 ------ common/drm_service_certificate.h | 144 --- common/drm_service_certificate_test.cc | 428 -------- common/dual_certificate_client_cert.cc | 113 --- common/dual_certificate_client_cert.h | 57 -- common/ec_key.cc | 58 -- common/ec_key.h | 25 - common/ec_key_source.h | 43 - common/ec_key_test.cc | 315 ------ common/ec_util_test.cc | 202 ---- common/ecb_util.cc | 117 --- common/ecb_util.h | 63 -- common/ecb_util_test.cc | 90 -- common/ecies_crypto.cc | 239 ----- common/ecies_crypto.h | 82 -- common/ecies_crypto_test.cc | 259 ----- common/error_space.cc | 19 - common/error_space.h | 20 - common/fake_ec_key_source.cc | 78 -- common/fake_ec_key_source.h | 53 - common/file_util.cc | 63 -- common/file_util.h | 27 - common/file_util_test.cc | 31 - common/hash_algorithm_util.cc | 51 - common/hash_algorithm_util.h | 23 - common/hash_algorithm_util_test.cc | 58 -- common/keybox_client_cert.cc | 58 -- common/keybox_client_cert.h | 85 -- common/local_ec_key_source.cc | 50 - common/local_ec_key_source.h | 42 - common/local_ec_key_source_test.cc | 64 -- common/mock_rsa_key.h | 97 -- common/output_protection_util.cc | 54 -- common/output_protection_util.h | 31 - common/output_protection_util_test.cc | 155 --- common/playready_interface.h | 42 - common/playready_sdk_impl.cc | 23 - common/playready_sdk_impl.h | 28 - common/random_util_test.cc | 28 - common/remote_attestation_verifier.cc | 262 ----- common/remote_attestation_verifier.h | 94 -- common/rot_id_generator.cc | 130 --- common/rot_id_generator.h | 103 -- common/rot_id_generator_test.cc | 304 ------ common/rot_id_util.cc | 45 - common/rot_id_util.h | 67 -- common/rot_id_util_test.cc | 85 -- common/rsa_key.cc | 75 -- common/rsa_key.h | 16 - common/rsa_key_test.cc | 268 ----- common/rsa_test_keys.cc | 786 --------------- common/rsa_test_keys.h | 92 -- common/rsa_util_test.cc | 353 ------- common/security_profile_list.cc | 245 ----- common/security_profile_list.h | 93 -- common/security_profile_list_test.cc | 206 ---- common/sha_util_test.cc | 74 -- common/signer_public_key.cc | 70 -- common/signer_public_key.h | 42 - common/signer_public_key_test.cc | 82 -- common/signing_key_util.cc | 44 - common/signing_key_util.h | 54 -- common/signing_key_util_test.cc | 66 -- common/status_test.cc | 61 -- common/test_drm_certificates.cc | 720 -------------- common/test_drm_certificates.h | 91 -- common/test_utils.cc | 72 -- common/test_utils.h | 32 - common/verified_media_pipeline.cc | 43 - common/verified_media_pipeline.h | 28 - common/vmp_checker.cc | 362 ------- common/vmp_checker.h | 57 -- common/vmp_checker_test.cc | 326 ------- common/widevine_system_id.cc | 19 - common/widevine_system_id.h | 22 - common/wvm_test_keys.cc | 87 -- common/wvm_test_keys.h | 58 -- common/wvm_token_handler.cc | 315 ------ common/wvm_token_handler.h | 125 --- common/wvm_token_handler_test.cc | 230 ----- common/x509_cert.cc | 459 --------- common/x509_cert.h | 181 ---- common/x509_cert_test.cc | 531 ---------- example/BUILD | 10 + example/test_emmg_messages.h | 83 +- example/wv_cas_emm_example.cc | 133 +++ media_cas_packager_sdk/internal/BUILD | 18 +- .../internal/ecm_generator_test.cc | 234 ++--- .../internal/ecmg_client_handler.cc | 8 +- .../internal/ecmg_client_handler.h | 4 +- .../internal/ecmg_client_handler_test.cc | 37 +- media_cas_packager_sdk/internal/emm.cc | 149 ++- media_cas_packager_sdk/internal/emm.h | 46 +- media_cas_packager_sdk/internal/emm_test.cc | 505 ++++++++-- media_cas_packager_sdk/internal/emmg.cc | 105 +- media_cas_packager_sdk/internal/emmg.h | 17 +- media_cas_packager_sdk/internal/emmg_test.cc | 136 ++- .../internal/fixed_key_fetcher.cc | 3 + media_cas_packager_sdk/internal/mpeg2ts.h | 4 + media_cas_packager_sdk/internal/util.cc | 147 ++- media_cas_packager_sdk/internal/util.h | 30 +- media_cas_packager_sdk/internal/util_test.cc | 210 +++- media_cas_packager_sdk/public/BUILD | 24 + media_cas_packager_sdk/public/wv_cas_emm.cc | 101 ++ media_cas_packager_sdk/public/wv_cas_emm.h | 91 ++ .../public/wv_cas_emm_test.cc | 260 +++++ .../public/wv_cas_key_fetcher.cc | 3 + .../public/wv_cas_key_fetcher.h | 4 + .../public/wv_cas_key_fetcher_test.cc | 115 ++- media_cas_packager_sdk/public/wv_cas_types.cc | 4 + media_cas_packager_sdk/public/wv_cas_types.h | 2 + .../public/wv_cas_types_test.cc | 15 +- media_cas_packager_sdk/public/wv_emmg.cc | 167 +++- util/endian/BUILD | 10 + util/endian/endian.h | 4 +- .../endian/endian_test.cc | 24 +- 143 files changed, 2316 insertions(+), 17450 deletions(-) delete mode 100644 common/aes_cbc_util_test.cc delete mode 100644 common/certificate_client_cert.cc delete mode 100644 common/certificate_client_cert.h delete mode 100644 common/certificate_type.h delete mode 100644 common/client_cert.cc delete mode 100644 common/client_cert.h delete mode 100644 common/client_cert_test.cc delete mode 100644 common/client_id_util.cc delete mode 100644 common/client_id_util.h delete mode 100644 common/content_id_util.cc delete mode 100644 common/content_id_util.h delete mode 100644 common/content_id_util_test.cc delete mode 100644 common/core_message_util.cc delete mode 100644 common/core_message_util.h delete mode 100644 common/crypto_util_test.cc delete mode 100644 common/default_device_security_profile_list.cc delete mode 100644 common/default_device_security_profile_list.h delete mode 100644 common/default_device_security_profile_list_test.cc delete mode 100644 common/device_info_util.cc delete mode 100644 common/device_info_util.h delete mode 100644 common/device_status_list.cc delete mode 100644 common/device_status_list.h delete mode 100644 common/device_status_list_test.cc delete mode 100644 common/drm_root_certificate.cc delete mode 100644 common/drm_root_certificate.h delete mode 100644 common/drm_root_certificate_test.cc delete mode 100644 common/drm_service_certificate.cc delete mode 100644 common/drm_service_certificate.h delete mode 100644 common/drm_service_certificate_test.cc delete mode 100644 common/dual_certificate_client_cert.cc delete mode 100644 common/dual_certificate_client_cert.h delete mode 100644 common/ec_key_source.h delete mode 100644 common/ec_key_test.cc delete mode 100644 common/ec_util_test.cc delete mode 100644 common/ecb_util.cc delete mode 100644 common/ecb_util.h delete mode 100644 common/ecb_util_test.cc delete mode 100644 common/ecies_crypto.cc delete mode 100644 common/ecies_crypto.h delete mode 100644 common/ecies_crypto_test.cc delete mode 100644 common/error_space.cc delete mode 100644 common/error_space.h delete mode 100644 common/fake_ec_key_source.cc delete mode 100644 common/fake_ec_key_source.h delete mode 100644 common/file_util.cc delete mode 100644 common/file_util.h delete mode 100644 common/file_util_test.cc delete mode 100644 common/hash_algorithm_util.cc delete mode 100644 common/hash_algorithm_util.h delete mode 100644 common/hash_algorithm_util_test.cc delete mode 100644 common/keybox_client_cert.cc delete mode 100644 common/keybox_client_cert.h delete mode 100644 common/local_ec_key_source.cc delete mode 100644 common/local_ec_key_source.h delete mode 100644 common/local_ec_key_source_test.cc delete mode 100644 common/mock_rsa_key.h delete mode 100644 common/output_protection_util.cc delete mode 100644 common/output_protection_util.h delete mode 100644 common/output_protection_util_test.cc delete mode 100644 common/playready_interface.h delete mode 100644 common/playready_sdk_impl.cc delete mode 100644 common/playready_sdk_impl.h delete mode 100644 common/random_util_test.cc delete mode 100644 common/remote_attestation_verifier.cc delete mode 100644 common/remote_attestation_verifier.h delete mode 100644 common/rot_id_generator.cc delete mode 100644 common/rot_id_generator.h delete mode 100644 common/rot_id_generator_test.cc delete mode 100644 common/rot_id_util.cc delete mode 100644 common/rot_id_util.h delete mode 100644 common/rot_id_util_test.cc delete mode 100644 common/rsa_key_test.cc delete mode 100644 common/rsa_test_keys.cc delete mode 100644 common/rsa_test_keys.h delete mode 100644 common/rsa_util_test.cc delete mode 100644 common/security_profile_list.cc delete mode 100644 common/security_profile_list.h delete mode 100644 common/security_profile_list_test.cc delete mode 100644 common/sha_util_test.cc delete mode 100644 common/signer_public_key.cc delete mode 100644 common/signer_public_key.h delete mode 100644 common/signer_public_key_test.cc delete mode 100644 common/signing_key_util.cc delete mode 100644 common/signing_key_util.h delete mode 100644 common/signing_key_util_test.cc delete mode 100644 common/status_test.cc delete mode 100644 common/test_drm_certificates.cc delete mode 100644 common/test_drm_certificates.h delete mode 100644 common/test_utils.cc delete mode 100644 common/test_utils.h delete mode 100644 common/verified_media_pipeline.cc delete mode 100644 common/verified_media_pipeline.h delete mode 100644 common/vmp_checker.cc delete mode 100644 common/vmp_checker.h delete mode 100644 common/vmp_checker_test.cc delete mode 100644 common/widevine_system_id.cc delete mode 100644 common/widevine_system_id.h delete mode 100644 common/wvm_test_keys.cc delete mode 100644 common/wvm_test_keys.h delete mode 100644 common/wvm_token_handler.cc delete mode 100644 common/wvm_token_handler.h delete mode 100644 common/wvm_token_handler_test.cc delete mode 100644 common/x509_cert.cc delete mode 100644 common/x509_cert.h delete mode 100644 common/x509_cert_test.cc create mode 100644 example/wv_cas_emm_example.cc create mode 100644 media_cas_packager_sdk/public/wv_cas_emm.cc create mode 100644 media_cas_packager_sdk/public/wv_cas_emm.h create mode 100644 media_cas_packager_sdk/public/wv_cas_emm_test.cc rename common/string_util_test.cc => util/endian/endian_test.cc (51%) diff --git a/common/BUILD b/common/BUILD index a25bb7d..355a2bd 100644 --- a/common/BUILD +++ b/common/BUILD @@ -113,6 +113,7 @@ cc_test( "//testing:gunit_main", "@abseil_repo//absl/memory", "//protos/public:device_common_cc_proto", + "//protos/public:device_security_profile_data_cc_proto", "//protos/public:security_profile_cc_proto", ], ) @@ -429,6 +430,7 @@ cc_test( timeout = "short", srcs = ["rsa_key_test.cc"], deps = [ + ":hash_algorithm", ":rsa_key", ":rsa_test_keys", ":rsa_util", @@ -515,6 +517,7 @@ cc_test( ":ec_key", ":ec_test_keys", ":ec_util", + ":hash_algorithm", ":random_util", "//testing:gunit", "//testing:gunit_main", @@ -887,6 +890,7 @@ cc_library( "//protos/public:client_identification_cc_proto", "//protos/public:drm_certificate_cc_proto", "//protos/public:errors_cc_proto", + "//protos/public:external_license_cc_proto", "//protos/public:signed_drm_certificate_cc_proto", ], ) @@ -911,6 +915,7 @@ cc_test( "//protos/public:client_identification_cc_proto", "//protos/public:drm_certificate_cc_proto", "//protos/public:errors_cc_proto", + "//protos/public:external_license_cc_proto", "//protos/public:license_server_sdk_cc_proto", "//protos/public:signed_drm_certificate_cc_proto", ], @@ -1130,10 +1135,22 @@ cc_library( hdrs = ["core_message_util.h"], deps = [ ":sha_util", + "//base", + "@abseil_repo//absl/strings", "//common/oemcrypto_core_message/odk:kdo", ], ) +cc_test( + name = "core_message_util_test", + srcs = ["core_message_util_test.cc"], + deps = [ + ":core_message_util", + "//testing:gunit_main", + "@abseil_repo//absl/strings", + ], +) + cc_library( name = "hash_algorithm", hdrs = ["hash_algorithm.h"], diff --git a/common/aes_cbc_util_test.cc b/common/aes_cbc_util_test.cc deleted file mode 100644 index 1713ea9..0000000 --- a/common/aes_cbc_util_test.cc +++ /dev/null @@ -1,166 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/aes_cbc_util.h" - -#include "testing/gmock.h" -#include "testing/gunit.h" - -namespace { - -const uint8_t kKey[] = { - 0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e, - 0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b, -}; - -const uint8_t kIv[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -}; - -} // namespace - -namespace widevine { -namespace crypto_util { - -TEST(CryptoUtilTest, EncryptAndDecryptAesCbc) { - std::string plain_text("Foo"); - std::string ciphertext = - EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), plain_text); - std::string expected_ciphertext( - "\xCF\x1A\x3\x1C\x9C\x8C\xB9Z\xEC\xC0\x17\xDCRxX\xD7"); - ASSERT_EQ(0, ciphertext.size() % 16); - ASSERT_GT(ciphertext.size(), plain_text.size()); - ASSERT_EQ(expected_ciphertext, ciphertext); - - std::string decrypted = - DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), ciphertext); - ASSERT_EQ(plain_text, decrypted); -} - -TEST(CryptoUtilTest, DecryptAesCbcNoPad) { - const uint8_t kKey[] = { - 0xdd, 0x71, 0x39, 0xea, 0xfa, 0xce, 0xed, 0x7c, - 0xda, 0x9f, 0x25, 0xda, 0x8a, 0xa9, 0x15, 0xea, - }; - const uint8_t kIv[] = { - 0x5d, 0x16, 0x44, 0xea, 0xec, 0x11, 0xf9, 0x83, - 0x14, 0x75, 0x41, 0xe4, 0x6e, 0xeb, 0x27, 0x74, - }; - const uint8_t kCiphertext[] = { - 0x6d, 0xa6, 0xda, 0xe4, 0xee, 0x40, 0x09, 0x17, - 0x54, 0x7b, 0xba, 0xa5, 0x27, 0xb8, 0x82, 0x1b, - }; - const uint8_t kExpectedPlaintext[] = { - 0xb3, 0x49, 0xd4, 0x80, 0x9e, 0x91, 0x06, 0x87, - 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10, - }; - const uint8_t kExpectedPlaintextEmptyIv[] = { - 0xee, 0x5f, 0x90, 0x6a, 0x72, 0x80, 0xff, 0x04, - 0x14, 0x75, 0x41, 0xa4, 0x6e, 0xeb, 0x27, 0x64, - }; - - std::string decrypted = DecryptAesCbcNoPad( - std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), - std::string(kCiphertext, kCiphertext + sizeof(kCiphertext))); - ASSERT_EQ(std::string(kExpectedPlaintext, - kExpectedPlaintext + sizeof(kExpectedPlaintext)), - decrypted); - - std::string dummy_iv; - decrypted = DecryptAesCbcNoPad( - std::string(kKey, kKey + sizeof(kKey)), dummy_iv, - std::string(kCiphertext, kCiphertext + sizeof(kCiphertext))); - ASSERT_EQ(std::string( - kExpectedPlaintextEmptyIv, - kExpectedPlaintextEmptyIv + sizeof(kExpectedPlaintextEmptyIv)), - decrypted); -} - -TEST(CryptoUtilTest, TestFailedEncrypt) { - // Test with bogus initialization vector. - std::string plain_text("Foo"); - std::string bogus_iv("bogus"); - std::string ciphertext = EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), - bogus_iv, plain_text); - ASSERT_EQ(ciphertext.size(), 0); - - // Test with bogus key. - std::string bogus_key("bogus"); - ciphertext = - EncryptAesCbc(bogus_key, std::string(kIv, kIv + sizeof(kIv)), plain_text); - ASSERT_EQ(ciphertext.size(), 0); -} - -TEST(CryptoUtilTest, TestFailedEncryptNoPad) { - std::string plaintext("0123456789abcdef"); - std::string key(kKey, kKey + sizeof(kKey)); - std::string iv(kIv, kIv + sizeof(kIv)); - - // Control. - std::string ciphertext = EncryptAesCbcNoPad(key, iv, plaintext); - ASSERT_EQ(plaintext.size(), ciphertext.size()); - - // Bogus key. - std::string bogus_key("bogus"); - ciphertext = EncryptAesCbcNoPad(bogus_key, iv, plaintext); - EXPECT_EQ(ciphertext.size(), 0); - - // Bogus IV. - std::string bogus_iv("bogus"); - ciphertext = EncryptAesCbcNoPad(key, bogus_iv, plaintext); - EXPECT_EQ(ciphertext.size(), 0); - - // Incorrectly-sized plaintext. - std::string bad_plaintext("Foo"); - ciphertext = EncryptAesCbcNoPad(key, iv, bad_plaintext); - EXPECT_EQ(ciphertext.size(), 0); -} - -TEST(CryptoUtilTest, TestFailedDecrypt) { - // First, encrypt the data. - std::string plain_text("Foo"); - std::string ciphertext = - EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), plain_text); - ASSERT_NE(ciphertext.size(), 0); - - // Test Decrypt with bogus iv. - std::string bogus_iv("bogus"); - plain_text = DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), bogus_iv, - ciphertext); - ASSERT_EQ(plain_text.size(), 0); - - // Test Decrypt with bogus key. - std::string bogus_key("bogus"); - plain_text = - DecryptAesCbc(bogus_key, std::string(kIv, kIv + sizeof(kIv)), ciphertext); - ASSERT_EQ(plain_text.size(), 0); -} - -TEST(CryptoUtilTest, TestEmptyEncrypt) { - EXPECT_EQ("\xDBx\xD9\x91\xE8\x1D\xD9\x19\x80r\x12\x89\xD7Kp\xEB", - EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), "")); -} - -TEST(CryptoUtilTest, TestEmptyDecryptAesCbc) { - EXPECT_EQ("", DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), "")); -} - -TEST(CryptoUtilTest, TestEmptyDecryptAesCbcNoPad) { - EXPECT_EQ("", DecryptAesCbcNoPad(std::string(kKey, kKey + sizeof(kKey)), - std::string(kIv, kIv + sizeof(kIv)), "")); -} - -} // namespace crypto_util -} // namespace widevine diff --git a/common/certificate_client_cert.cc b/common/certificate_client_cert.cc deleted file mode 100644 index be44107..0000000 --- a/common/certificate_client_cert.cc +++ /dev/null @@ -1,280 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/certificate_client_cert.h" - -#include "glog/logging.h" -#include "absl/memory/memory.h" -#include "common/crypto_util.h" -#include "common/ec_key.h" -#include "common/ec_util.h" -#include "common/error_space.h" -#include "common/openssl_util.h" -#include "common/random_util.h" -#include "common/rsa_key.h" -#include "common/sha_util.h" -#include "common/signing_key_util.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/license_protocol.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace widevine { - -using EllipticCurve = ECPrivateKey::EllipticCurve; - -ECPrivateKey::EllipticCurve CertificateAlgorithmToCurve( - DrmCertificate::Algorithm algorithm) { - switch (algorithm) { - case DrmCertificate::ECC_SECP256R1: - return ECPrivateKey::SECP256R1; - case DrmCertificate::ECC_SECP384R1: - return ECPrivateKey::SECP384R1; - case DrmCertificate::ECC_SECP521R1: - return ECPrivateKey::SECP521R1; - default: - return ECPrivateKey::UNDEFINED_CURVE; - } -} - -class ClientCertAlgorithmRSA : public ClientCertAlgorithm { - public: - ClientCertAlgorithmRSA() {} - ~ClientCertAlgorithmRSA() override {} - ClientCertAlgorithmRSA(const ClientCertAlgorithmRSA&) = delete; - ClientCertAlgorithmRSA& operator=(const ClientCertAlgorithmRSA&) = delete; - - Status Initialize(const std::string& public_key, - DrmCertificate::Algorithm /*not_used*/) override { - rsa_public_key_ = - std::unique_ptr(RsaPublicKey::Create(public_key)); - if (!rsa_public_key_) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-public-key-failed"); - } - session_key_ = Random16Bytes(); - if (!rsa_public_key_->Encrypt(session_key_, &wrapped_session_key_)) { - return Status(error_space, ENCRYPT_ERROR, - "drm-certificate-failed-encrypt-session-key"); - } - return OkStatus(); - } - - Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature) const override { - CHECK(rsa_public_key_); - - if (!rsa_public_key_->VerifySignature(message, hash_algorithm, signature)) { - return Status(error_space, INVALID_SIGNATURE, ""); - } - return OkStatus(); - } - - const std::string& session_key() const override { return session_key_; } - - const std::string& wrapped_session_key() const override { - return wrapped_session_key_; - } - - SignedMessage::SessionKeyType session_key_type() const override { - return SignedMessage::WRAPPED_AES_KEY; - } - - private: - std::unique_ptr rsa_public_key_; - std::string session_key_; - std::string wrapped_session_key_; -}; - -// ClientCertAlgorithmECC implements the Widevine protocol using ECC. It -// verifies an ECC based request and generates keys for use in building a -// license. The curve type value is contained in |algorithm|. -class ClientCertAlgorithmECC : public ClientCertAlgorithm { - public: - ClientCertAlgorithmECC() = default; - ~ClientCertAlgorithmECC() override = default; - ClientCertAlgorithmECC(const ClientCertAlgorithmECC&) = delete; - ClientCertAlgorithmECC& operator=(const ClientCertAlgorithmECC&) = delete; - - Status Initialize(const std::string& public_key, - DrmCertificate::Algorithm algorithm) override { - ECPrivateKey::EllipticCurve curve_id = - CertificateAlgorithmToCurve(algorithm); - if (curve_id == ECPrivateKey::UNDEFINED_CURVE) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-unknown-curve"); - } - // Parse the certifcate ECC public key. - client_ecc_public_key_ = ECPublicKey::Create(public_key); - if (client_ecc_public_key_ == nullptr) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-public-key-failed"); - } - // Generate an ephemeral ecc key pair with the same curve as used by the - // certificate public key. - ScopedECKEY key = ec_util::GenerateKeyWithCurve(curve_id); - auto new_private_key = absl::make_unique(std::move(key)); - if (new_private_key == nullptr) { - return Status(error_space, DRM_DEVICE_CERTIFICATE_ECC_KEYGEN_FAILED, - "drm-certificate-ephemeral-private-key-failed"); - } - - // Serialize the ephemeral public key for inclusion in a license response. - std::unique_ptr new_public_key = new_private_key->PublicKey(); - if (new_public_key == nullptr || - !new_public_key->SerializedKey(&ephemeral_public_key_)) { - return Status(error_space, DRM_DEVICE_CERTIFICATE_ECC_KEYGEN_FAILED, - "drm-certificate-ephemeral-public-key-failed"); - } - - // Generate the session key from the ephemeral private key and the - // certificate public key. - if (!new_private_key->DeriveSharedSessionKey(*client_ecc_public_key_, - &derived_session_key_)) { - return Status(error_space, DRM_DEVICE_CERTIFICATE_ECC_KEYGEN_FAILED, - "drm-certificate-shared-key-gen-failed"); - } - return OkStatus(); - } - - Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature) const override { - CHECK(client_ecc_public_key_); - - if (!client_ecc_public_key_->VerifySignature(message, hash_algorithm, - signature)) { - return Status(error_space, INVALID_SIGNATURE, ""); - } - return OkStatus(); - } - // Returns an aes key generated from the sha256 hash of the shared ecc secret. - // This key is used for key derivation. - const std::string& session_key() const override { - return derived_session_key_; - } - - // Returns an ephemeral serialized ecc public key. This key is added to a - // license response in the SignedMessage::session_key field. The client will - // use this key to generate the shared secret and derived session key. - const std::string& wrapped_session_key() const override { - return ephemeral_public_key_; - } - - SignedMessage::SessionKeyType session_key_type() const override { - return SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY; - } - - private: - std::unique_ptr client_ecc_public_key_; - std::string ephemeral_public_key_; - std::string derived_session_key_; -}; - -Status CertificateClientCert::Initialize( - const DrmRootCertificate* root_certificate, - const std::string& serialized_certificate) { - CHECK(root_certificate); - - if (is_initialized_) { - return Status(error_space, INVALID_PARAMETER, - "certificate-is-already-initialized"); - } - - SignedDrmCertificate signed_device_cert; - Status status = root_certificate->VerifyCertificate( - serialized_certificate, &signed_device_cert, &device_cert_); - if (!status.ok()) { - return status; - } - if (device_cert_.type() != DrmCertificate::DEVICE || - device_cert_.public_key().empty()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "expected-device-certificate-type"); - } - - const SignedDrmCertificate& device_cert_signer = signed_device_cert.signer(); - - if (!model_certificate_.ParseFromString( - device_cert_signer.drm_certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-invalid-signer"); - } - if (model_certificate_.type() != DrmCertificate::DEVICE_MODEL) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "expected-device-model-certificate-type"); - } - if (!model_certificate_.has_serial_number()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-signer-serial-number"); - } - // Check to see if this model certificate is signed by a - // provisioner (entity using Widevine Provisioning Server SDK). - if (device_cert_signer.has_signer()) { - if (!provisioner_certificate_.ParseFromString( - device_cert_signer.signer().drm_certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "model-certificate-invalid-signer"); - } - if (provisioner_certificate_.type() != DrmCertificate::PROVISIONER) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "expected-provisioning-provider-certificate-type"); - } - if (!provisioner_certificate_.has_provider_id() || - provisioner_certificate_.provider_id().empty()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-provisioning-service-id"); - } - signed_by_provisioner_ = true; - } - if (!model_certificate_.has_system_id()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "model-certificate-missing-system-id"); - } - - switch (device_cert_.algorithm()) { - case DrmCertificate::RSA: - algorithm_ = absl::make_unique(); - break; - case DrmCertificate::ECC_SECP256R1: - case DrmCertificate::ECC_SECP384R1: - case DrmCertificate::ECC_SECP521R1: - algorithm_ = absl::make_unique(); - break; - default: - return Status(error_space, INVALID_DRM_CERTIFICATE, - "unsupported-certificate-algorithm"); - } - - status = algorithm_->Initialize(device_cert_.public_key(), - device_cert_.algorithm()); - if (!status.ok()) { - return status; - } - is_initialized_ = true; - return OkStatus(); -} - -Status CertificateClientCert::VerifySignature( - const std::string& message, HashAlgorithm hash_algorithm, - const std::string& signature, ProtocolVersion protocol_version) const { - return algorithm_->VerifySignature( - protocol_version < VERSION_2_2 ? message : Sha512_Hash(message), - hash_algorithm, signature); -} - -void CertificateClientCert::GenerateSigningKey( - const std::string& message, ProtocolVersion protocol_version) { - signing_key_ = crypto_util::DeriveKey( - key(), crypto_util::kSigningKeyLabel, - protocol_version < VERSION_2_2 ? message : Sha512_Hash(message), - SigningKeyMaterialSizeBits(protocol_version)); -} - -} // namespace widevine diff --git a/common/certificate_client_cert.h b/common/certificate_client_cert.h deleted file mode 100644 index c412fec..0000000 --- a/common/certificate_client_cert.h +++ /dev/null @@ -1,114 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_CERTIFICATE_CLIENT_CERT_H_ -#define COMMON_CERTIFICATE_CLIENT_CERT_H_ - -#include "common/client_cert.h" -#include "common/hash_algorithm.h" -#include "protos/public/drm_certificate.pb.h" - -namespace widevine { - -class ClientCertAlgorithm { - public: - ClientCertAlgorithm() = default; - virtual ~ClientCertAlgorithm() = default; - ClientCertAlgorithm(const ClientCertAlgorithm&) = delete; - ClientCertAlgorithm& operator=(const ClientCertAlgorithm&) = delete; - - // Initialize the algorithm module using the |public_key| from the drm - // certificate. The |algorithm| value provides additional information needed - // by the ECC implementation of this interface. - virtual Status Initialize(const std::string& public_key, - DrmCertificate::Algorithm algorithm) = 0; - - // Verify the |signature| of an incoming request |message| using the public - // key from the drm certificate. - virtual Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature) const = 0; - - // Returns the key to be used in key derivation of the license - // protocol. - virtual const std::string& session_key() const = 0; - - // Returns a byte std::string to be included in the SignedMessage::session_key - // field of a license response. This key may be either an encrypted aes key, - // or the bytes of an ephemeral public key. - virtual const std::string& wrapped_session_key() const = 0; - - // Returns information on the type session key used in this format. This value - // is intended to be included in the SignedMessage::session_key_type field of - // a license response. - virtual SignedMessage::SessionKeyType session_key_type() const = 0; -}; - -class CertificateClientCert : public ClientCert { - public: - CertificateClientCert() {} - ~CertificateClientCert() override {} - CertificateClientCert(const CertificateClientCert&) = delete; - CertificateClientCert& operator=(const CertificateClientCert&) = delete; - Status Initialize(const DrmRootCertificate* root_certificate, - const std::string& serialized_certificate); - - Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature, - ProtocolVersion protocol_version) const override; - - void GenerateSigningKey(const std::string& message, - ProtocolVersion protocol_version) override; - - const std::string& encrypted_key() const override { - return algorithm_->wrapped_session_key(); - } - const std::string& key() const override { return algorithm_->session_key(); } - SignedMessage::SessionKeyType key_type() const override { - return algorithm_->session_key_type(); - } - bool using_dual_certificate() const override { return false; } - const std::string& serial_number() const override { - return device_cert_.serial_number(); - } - const std::string& service_id() const override { - return provisioner_certificate_.provider_id(); - } - const std::string& signing_key() const override { return signing_key_; } - const std::string& signer_serial_number() const override { - return model_certificate_.serial_number(); - } - uint32_t signer_creation_time_seconds() const override { - return model_certificate_.creation_time_seconds(); - } - bool signed_by_provisioner() const override { return signed_by_provisioner_; } - uint32_t system_id() const override { return model_certificate_.system_id(); } - widevine::ClientIdentification::TokenType type() const override { - return ClientIdentification::DRM_DEVICE_CERTIFICATE; - } - const std::string& encrypted_unique_id() const override { - return device_cert_.rot_id().encrypted_unique_id(); - } - const std::string& unique_id_hash() const override { - return device_cert_.rot_id().unique_id_hash(); - } - - private: - std::unique_ptr algorithm_; - bool signed_by_provisioner_ = false; - std::string signing_key_; - DrmCertificate model_certificate_; - DrmCertificate device_cert_; - DrmCertificate provisioner_certificate_; - bool is_initialized_ = false; -}; - -} // namespace widevine - -#endif // COMMON_CERTIFICATE_CLIENT_CERT_H_ diff --git a/common/certificate_type.h b/common/certificate_type.h deleted file mode 100644 index b63a639..0000000 --- a/common/certificate_type.h +++ /dev/null @@ -1,22 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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_CERTIFICATE_TYPE_H_ -#define COMMON_CERTIFICATE_TYPE_H_ - -namespace widevine { - -enum CertificateType { - kCertificateTypeTesting, - kCertificateTypeDevelopment, - kCertificateTypeProduction, -}; - -} // namespace widevine - -#endif // COMMON_CERTIFICATE_TYPE_H_ diff --git a/common/client_cert.cc b/common/client_cert.cc deleted file mode 100644 index ec6d30a..0000000 --- a/common/client_cert.cc +++ /dev/null @@ -1,130 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/client_cert.h" - -#include -#include -#include - -#include "glog/logging.h" -#include "absl/memory/memory.h" -#include "absl/strings/escaping.h" -#include "common/certificate_client_cert.h" -#include "common/crypto_util.h" -#include "common/dual_certificate_client_cert.h" -#include "common/error_space.h" -#include "common/keybox_client_cert.h" -#include "common/random_util.h" -#include "common/rsa_key.h" -#include "common/sha_util.h" -#include "common/signing_key_util.h" -#include "common/status.h" -#include "common/wvm_token_handler.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace widevine { - -void KeyboxClientCert::SetPreProvisioningKeys( - const std::multimap& keymap) { - std::vector keyvector; - keyvector.reserve(keymap.size()); - for (std::multimap::const_iterator it = keymap.begin(); - it != keymap.end(); ++it) { - std::string key = absl::HexStringToBytes(it->second); - DCHECK_EQ(key.size(), 16); - keyvector.push_back(WvmTokenHandler::PreprovKey(it->first, key)); - } - WvmTokenHandler::SetPreprovKeys(keyvector); -} - -bool KeyboxClientCert::IsSystemIdKnown(const uint32_t system_id) { - return WvmTokenHandler::IsSystemIdKnown(system_id); -} - -uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) { - return WvmTokenHandler::GetSystemId(keybox_bytes); -} - -Status ClientCert::Create(const DrmRootCertificate* root_certificate, - const widevine::ClientIdentification& client_id, - std::unique_ptr* client_cert) { - CHECK(client_cert); - - switch (client_id.type()) { - case ClientIdentification::KEYBOX: - return CreateWithKeybox(client_id.token(), client_cert); - case ClientIdentification::DRM_DEVICE_CERTIFICATE: - if (!client_id.has_device_credentials()) { - return CreateWithDrmCertificate(root_certificate, client_id.token(), - client_cert); - } - // Assumes |client_id.token| is the signing cert and - // |client_id.device_credentials().token| is the encryption cert. - if (client_id.device_credentials().type() != - ClientIdentification::DRM_DEVICE_CERTIFICATE) - return Status(error_space, INVALID_DRM_CERTIFICATE, - "unsupported-encryption-certificate"); - - return CreateWithDualDrmCertificates( - root_certificate, client_id.token(), - client_id.device_credentials().token(), client_cert); - default: - return Status(error_space, error::UNIMPLEMENTED, - "client-type-not-implemented"); - } - - return OkStatus(); -} - -// Creates a Device Certificate based ClientCert. The |client_cert| is a -// caller supplied unique_ptr to receive the new ClientCert. -Status ClientCert::CreateWithDrmCertificate( - const DrmRootCertificate* root_certificate, - const std::string& drm_certificate, - std::unique_ptr* client_cert) { - CHECK(root_certificate); - CHECK(client_cert); - auto device_cert = absl::make_unique(); - Status status = device_cert->Initialize(root_certificate, drm_certificate); - if (status.ok()) { - *client_cert = std::move(device_cert); - } - return status; -} - -Status ClientCert::CreateWithDualDrmCertificates( - const DrmRootCertificate* root_certificate, - const std::string& signing_drm_certificate, - const std::string& encryption_drm_certificate, - std::unique_ptr* client_cert) { - CHECK(root_certificate); - CHECK(client_cert); - auto device_cert = absl::make_unique(); - Status status = device_cert->Initialize( - root_certificate, signing_drm_certificate, encryption_drm_certificate); - if (status.ok()) { - *client_cert = std::move(device_cert); - } - return status; -} - -Status ClientCert::CreateWithKeybox(const std::string& keybox_token, - std::unique_ptr* client_cert) { - CHECK(client_cert); - auto kbx_cert = absl::make_unique(); - Status status = kbx_cert->Initialize(keybox_token); - if (status.ok()) { - *client_cert = std::move(kbx_cert); - } - return status; -} - -} // namespace widevine diff --git a/common/client_cert.h b/common/client_cert.h deleted file mode 100644 index 8b458a8..0000000 --- a/common/client_cert.h +++ /dev/null @@ -1,99 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_CLIENT_CERT_H__ -#define COMMON_CLIENT_CERT_H__ - -#include - -#include "common/drm_root_certificate.h" -#include "common/error_space.h" -#include "common/hash_algorithm.h" -#include "common/status.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { - -// Handler class for LicenseRequests; validates requests and encrypts licenses. -class ClientCert { - protected: - ClientCert() = default; - - public: - // Creates a Device Certificate from the supplied |client_id|. - static Status Create(const DrmRootCertificate* root_certificate, - const widevine::ClientIdentification& client_id, - std::unique_ptr* client_cert); - - // Creates a Device Certificate based ClientCert. - static Status CreateWithDrmCertificate( - const DrmRootCertificate* root_certificate, - const std::string& drm_certificate, - std::unique_ptr* client_cert); - - // Creates a Device Certificate using the supplied certificates. - // The|signing_drm_certificate| will be used to verify an incoming request. - // The |encryption_drm_certificate| will be used to define the session key - // used to protect a response message. - static Status CreateWithDualDrmCertificates( - const DrmRootCertificate* root_certificate, - const std::string& signing_drm_certificate, - const std::string& encryption_drm_certificate, - std::unique_ptr* client_cert); - - // Creates a Keybox based ClientCert. The |client_cert| is a caller supplied - // unique_ptr to receive the new ClientCert. - static Status CreateWithKeybox(const std::string& keybox_token, - std::unique_ptr* client_cert); - - virtual ~ClientCert() = default; - ClientCert(const ClientCert&) = delete; - ClientCert& operator=(const ClientCert&) = delete; - - // Checks the passed in signature against a signature created used the - // classes information and the passed in message. Returns OK if signature - // is valid. - virtual Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature, - ProtocolVersion protocol_version) const = 0; - - // Creates a signing_key that is accessible using signing_key(). Signing_key - // is constructed by doing a key derivation using the key() and message. - virtual void GenerateSigningKey(const std::string& message, - ProtocolVersion protocol_version) = 0; - - virtual const std::string& encrypted_key() const = 0; - virtual const std::string& key() const = 0; - virtual SignedMessage::SessionKeyType key_type() const = 0; - virtual bool using_dual_certificate() const = 0; - virtual const std::string& serial_number() const = 0; - virtual const std::string& service_id() const = 0; - virtual const std::string& signing_key() const = 0; - virtual const std::string& signer_serial_number() const = 0; - virtual uint32_t signer_creation_time_seconds() const = 0; - virtual bool signed_by_provisioner() const = 0; - virtual uint32_t system_id() const = 0; - virtual widevine::ClientIdentification::TokenType type() const = 0; - virtual const std::string& encrypted_unique_id() const = 0; - virtual const std::string& unique_id_hash() const = 0; - virtual Status SystemIdUnknownError() const { - return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, - "device-certificate-status-unknown"); - } - virtual Status SystemIdRevokedError() const { - return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, - "device-certificate-revoked"); - } -}; - -} // namespace widevine - -#endif // COMMON_CLIENT_CERT_H__ diff --git a/common/client_cert_test.cc b/common/client_cert_test.cc deleted file mode 100644 index e145f60..0000000 --- a/common/client_cert_test.cc +++ /dev/null @@ -1,867 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/client_cert.h" - -#include -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/ec_key.h" -#include "common/ec_test_keys.h" -#include "common/error_space.h" -#include "common/hash_algorithm.h" -#include "common/hash_algorithm_util.h" -#include "common/keybox_client_cert.h" -#include "common/rsa_key.h" -#include "common/rsa_test_keys.h" -#include "common/sha_util.h" -#include "common/status.h" -#include "common/test_drm_certificates.h" -#include "common/wvm_test_keys.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -using widevine::ClientCert; -using widevine::ClientIdentification; -using widevine::Status; - -namespace widevine { -const DrmCertificate::Type kNoSigner = DrmCertificate::ROOT; -const DrmCertificate::Type kDeviceModelSigner = DrmCertificate::DEVICE_MODEL; -const DrmCertificate::Type kProvisionerSigner = DrmCertificate::PROVISIONER; - -const HashAlgorithm kSha256 = HashAlgorithm::kSha256; - -// TODO(user): Change these tests to use on-the-fly generated intermediate -// and device certificates based on RsaTestKeys. -// TODO(user): Add testcase(s) CreateSignature, -// and GenerateSigningKey. - -class ClientCertTest - : public ::testing::TestWithParam< - std::tuple> { - public: - ~ClientCertTest() override = default; - void SetUp() override { - if (!setup_preprov_keys_) { - KeyboxClientCert::SetPreProvisioningKeys( - wvm_test_keys::GetPreprovKeyMultimap()); - setup_preprov_keys_ = true; - } - ASSERT_OK( - DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); - } - - protected: - // Simple container struct for test value and expected keys. - class TestTokenAndKeys { - public: - const std::string token_; - uint32_t expected_system_id_; - const std::string expected_serial_number_; - const std::string expected_device_key_; - TestTokenAndKeys(const std::string& token, uint32_t expected_system_id, - const std::string& expected_serial_number, - const std::string& expected_device_key) - : token_(token), - expected_system_id_(expected_system_id), - expected_serial_number_(expected_serial_number), - expected_device_key_(expected_device_key) {} - }; - - class TestCertificateAndData { - public: - const std::string certificate_; - const std::string encryption_certificate_; - const std::string expected_serial_number_; - uint32_t expected_system_id_; - Status expected_status_; - SignedMessage::SessionKeyType expected_key_type_; - TestCertificateAndData(const std::string& certificate, - const std::string& expected_serial_number, - uint32_t expected_system_id, Status expected_status) - : certificate_(certificate), - expected_serial_number_(expected_serial_number), - expected_system_id_(expected_system_id), - expected_status_(expected_status), - expected_key_type_(SignedMessage::WRAPPED_AES_KEY) {} - TestCertificateAndData(const std::string& certificate, - const std::string& encryption_certificate, - const std::string& expected_serial_number, - uint32_t expected_system_id, Status expected_status, - SignedMessage::SessionKeyType expected_key_type) - : certificate_(certificate), - encryption_certificate_(encryption_certificate), - expected_serial_number_(expected_serial_number), - expected_system_id_(expected_system_id), - expected_status_(expected_status), - expected_key_type_(expected_key_type) {} - }; - - void TestBasicValidation(const TestTokenAndKeys& expectation, - const bool expect_success, - const bool compare_device_key); - void TestBasicValidationDrmCertificate( - const TestCertificateAndData& expectation, const bool compare_data); - - void GenerateSignature(const std::string& message, - const std::string& private_key, - HashAlgorithm hash_algorithm, std::string* signature); - std::unique_ptr SignCertificate( - const DrmCertificate& certificate, const SignedDrmCertificate* signer, - const std::string& private_key); - std::unique_ptr GenerateProvisionerCertificate( - uint32_t system_id, const std::string& serial_number, - const std::string& provider_id); - std::unique_ptr GenerateSignedProvisionerCertificate( - uint32_t system_id, const std::string& serial_number, - const std::string& service_id); - std::unique_ptr GenerateIntermediateCertificate( - uint32_t system_id, const std::string& serial_number); - std::unique_ptr GenerateSignedIntermediateCertificate( - SignedDrmCertificate* signer, uint32_t system_id, - const std::string& serial_number, DrmCertificate::Type signer_cert_type); - std::unique_ptr GenerateDrmCertificate( - uint32_t system_id, const std::string& serial_number, - DrmCertificate::Algorithm = DrmCertificate::RSA); - std::unique_ptr GenerateSignedDrmCertificate( - SignedDrmCertificate* signer, uint32_t system_id, - const std::string& serial_number, - DrmCertificate::Algorithm = DrmCertificate::RSA); - - std::string GetPublicKeyByCertType(DrmCertificate::Type cert_type); - std::string GetPrivateKeyByCertType(DrmCertificate::Type cert_type); - std::string GetECCPrivateKey(DrmCertificate::Algorithm algorithm); - std::string GetECCPublicKey(DrmCertificate::Algorithm algorithm); - - RsaTestKeys test_rsa_keys_; - TestDrmCertificates test_drm_certs_; - std::unique_ptr root_cert_; - static bool setup_preprov_keys_; -}; - -bool ClientCertTest::setup_preprov_keys_(false); - -void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation, - const bool expect_success, - const bool compare_device_key) { - // Test validation of a valid request. - Status status; - std::unique_ptr keybox_cert; - - ClientIdentification client_id; - client_id.set_type(ClientIdentification::KEYBOX); - client_id.set_token(expectation.token_); - - status = ClientCert::Create(root_cert_.get(), client_id, &keybox_cert); - if (expect_success) { - ASSERT_EQ(OkStatus(), status); - ASSERT_TRUE(keybox_cert.get()); - EXPECT_EQ(expectation.expected_system_id_, keybox_cert->system_id()); - EXPECT_EQ(expectation.expected_serial_number_, - keybox_cert->serial_number()); - if (compare_device_key) { - EXPECT_EQ(expectation.expected_device_key_, keybox_cert->key()); - } - } else { - EXPECT_NE(OkStatus(), status); - EXPECT_FALSE(keybox_cert); - } -} - -void ClientCertTest::TestBasicValidationDrmCertificate( - const TestCertificateAndData& expectation, const bool compare_data) { - // Reset DRM certificate signature cache since some certificates get - // re-generated. - ASSERT_OK( - DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); - - // Test validation of a valid request. - Status status; - std::unique_ptr drm_certificate_cert; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(expectation.certificate_); - if (!expectation.encryption_certificate_.empty()) { - client_id.mutable_device_credentials()->set_token( - expectation.encryption_certificate_); - client_id.mutable_device_credentials()->set_type( - ClientIdentification::DRM_DEVICE_CERTIFICATE); - } - - status = - ClientCert::Create(root_cert_.get(), client_id, &drm_certificate_cert); - ASSERT_EQ(expectation.expected_status_, status); - if (expectation.expected_status_.ok()) { - ASSERT_TRUE(drm_certificate_cert.get()); - if (!expectation.encryption_certificate_.empty()) { - ASSERT_TRUE(drm_certificate_cert->using_dual_certificate()); - } - ASSERT_EQ(expectation.expected_key_type_, drm_certificate_cert->key_type()); - if (compare_data) { - ASSERT_EQ(expectation.expected_serial_number_, - drm_certificate_cert->signer_serial_number()); - ASSERT_EQ(expectation.expected_system_id_, - drm_certificate_cert->system_id()); - } - } else { - ASSERT_FALSE(drm_certificate_cert.get()); - } -} - -void ClientCertTest::GenerateSignature(const std::string& message, - const std::string& private_key, - HashAlgorithm hash_algorithm, - std::string* signature) { - std::unique_ptr rsa_private_key( - RsaPrivateKey::Create(private_key)); - ASSERT_TRUE(rsa_private_key != nullptr); - rsa_private_key->GenerateSignature(message, hash_algorithm, signature); -} - -// The caller retains ownership of |signer|, which may also be nullptr. -std::unique_ptr ClientCertTest::SignCertificate( - const DrmCertificate& certificate, const SignedDrmCertificate* signer, - const std::string& private_key) { - std::unique_ptr signed_certificate( - new SignedDrmCertificate); - signed_certificate->set_drm_certificate(certificate.SerializeAsString()); - GenerateSignature( - signed_certificate->drm_certificate(), private_key, - HashAlgorithmProtoToEnum(signed_certificate->hash_algorithm()), - signed_certificate->mutable_signature()); - if (signer != nullptr) { - *(signed_certificate->mutable_signer()) = *signer; - } - return signed_certificate; -} - -std::string ClientCertTest::GetPublicKeyByCertType( - DrmCertificate::Type cert_type) { - if (cert_type == DrmCertificate::DEVICE) { - return test_rsa_keys_.public_test_key_3_2048_bits(); - } else if (cert_type == DrmCertificate::DEVICE_MODEL) { - return test_rsa_keys_.public_test_key_2_2048_bits(); - } - return test_rsa_keys_.public_test_key_1_3072_bits(); -} - -std::string ClientCertTest::GetPrivateKeyByCertType( - DrmCertificate::Type cert_type) { - if (cert_type == DrmCertificate::DEVICE) { - return test_rsa_keys_.private_test_key_3_2048_bits(); - } else if (cert_type == DrmCertificate::DEVICE_MODEL) { - return test_rsa_keys_.private_test_key_2_2048_bits(); - } - return test_rsa_keys_.private_test_key_1_3072_bits(); -} - -std::string ClientCertTest::GetECCPrivateKey( - DrmCertificate::Algorithm algorithm) { - ECTestKeys keys; - switch (algorithm) { - case DrmCertificate::ECC_SECP256R1: - return keys.private_test_key_1_secp256r1(); - case DrmCertificate::ECC_SECP384R1: - return keys.private_test_key_1_secp384r1(); - case DrmCertificate::ECC_SECP521R1: - return keys.private_test_key_1_secp521r1(); - default: - return ""; - } -} - -std::string ClientCertTest::GetECCPublicKey( - DrmCertificate::Algorithm algorithm) { - ECTestKeys keys; - switch (algorithm) { - case DrmCertificate::ECC_SECP256R1: - return keys.public_test_key_1_secp256r1(); - case DrmCertificate::ECC_SECP384R1: - return keys.public_test_key_1_secp384r1(); - case DrmCertificate::ECC_SECP521R1: - return keys.public_test_key_1_secp521r1(); - default: - return ""; - } -} - -std::unique_ptr ClientCertTest::GenerateIntermediateCertificate( - uint32_t system_id, const std::string& serial_number) { - std::unique_ptr intermediate_certificate(new DrmCertificate); - intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL); - intermediate_certificate->set_serial_number(serial_number); - intermediate_certificate->set_public_key( - GetPublicKeyByCertType(DrmCertificate::DEVICE_MODEL)); - intermediate_certificate->set_system_id(system_id); - intermediate_certificate->set_creation_time_seconds(1234); - return intermediate_certificate; -} - -std::unique_ptr -ClientCertTest::GenerateSignedIntermediateCertificate( - SignedDrmCertificate* signer, uint32_t system_id, - const std::string& serial_number, DrmCertificate::Type signer_cert_type) { - std::unique_ptr intermediate_certificate( - GenerateIntermediateCertificate(system_id, serial_number)); - // Must use the same key pair used by GenerateIntermediateCertificate(). - return SignCertificate(*intermediate_certificate, signer, - GetPrivateKeyByCertType(signer_cert_type)); -} - -std::unique_ptr ClientCertTest::GenerateDrmCertificate( - uint32_t system_id, const std::string& serial_number, - DrmCertificate::Algorithm algorithm) { - std::unique_ptr drm_certificate(new DrmCertificate); - drm_certificate->set_type(DrmCertificate::DEVICE); - drm_certificate->set_serial_number(serial_number); - drm_certificate->set_system_id(system_id); - drm_certificate->set_public_key( - algorithm == DrmCertificate::RSA - ? GetPublicKeyByCertType(DrmCertificate::DEVICE) - : GetECCPublicKey(algorithm)); - drm_certificate->set_creation_time_seconds(4321); - drm_certificate->set_algorithm(algorithm); - return drm_certificate; -} - -std::unique_ptr -ClientCertTest::GenerateSignedDrmCertificate( - SignedDrmCertificate* signer, uint32_t system_id, - const std::string& serial_number, DrmCertificate::Algorithm algorithm) { - std::unique_ptr drm_certificate( - GenerateDrmCertificate(system_id, serial_number, algorithm)); - std::unique_ptr signed_drm_certificate( - SignCertificate(*drm_certificate, signer, - GetPrivateKeyByCertType(DrmCertificate::DEVICE_MODEL))); - return signed_drm_certificate; -} - -std::unique_ptr ClientCertTest::GenerateProvisionerCertificate( - uint32_t system_id, const std::string& serial_number, - const std::string& provider_id) { - std::unique_ptr provisioner_certificate(new DrmCertificate); - provisioner_certificate->set_type(DrmCertificate::PROVISIONER); - provisioner_certificate->set_serial_number(serial_number); - provisioner_certificate->set_public_key( - GetPublicKeyByCertType(DrmCertificate::DrmCertificate::PROVISIONER)); - provisioner_certificate->set_system_id(system_id); - provisioner_certificate->set_provider_id(provider_id); - provisioner_certificate->set_creation_time_seconds(1234); - return provisioner_certificate; -} - -std::unique_ptr -ClientCertTest::GenerateSignedProvisionerCertificate( - uint32_t system_id, const std::string& serial_number, - const std::string& service_id) { - std::unique_ptr provisioner_certificate( - GenerateProvisionerCertificate(system_id, serial_number, service_id)); - return SignCertificate(*provisioner_certificate, nullptr, - GetPrivateKeyByCertType(DrmCertificate::ROOT)); -} - -TEST_F(ClientCertTest, BasicValidation) { - const TestTokenAndKeys kValidTokenAndExpectedKeys[] = { - TestTokenAndKeys( - absl::HexStringToBytes( - "00000002000001128e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"), - 274, absl::HexStringToBytes("8e1ebfe037828096ca6538b4f6f4bcb5"), - absl::HexStringToBytes("4071197f1f8910d9bf10c6bc4c987638")), - TestTokenAndKeys( - absl::HexStringToBytes( - "0000000200000112d906feebe1750c5886ff77c2dfa31bb40e002f3adbc0fa5b" - "eb2486cf5f419549cdaa23230e5165ac2ffab56d53b692b7ba0c1857400c6add" - "3af3ff3d5cb24985"), - 274, absl::HexStringToBytes("d906feebe1750c5886ff77c2dfa31bb4"), - absl::HexStringToBytes("42cfb1765201042302a404d1e0fac8ed"))}; - - for (size_t i = 0; i < ABSL_ARRAYSIZE(kValidTokenAndExpectedKeys); ++i) { - SCOPED_TRACE("Test data: " + absl::StrCat(i)); - TestBasicValidation(kValidTokenAndExpectedKeys[i], true, true); - } - - EXPECT_EQ( - wvm_test_keys::kTestSystemId, - KeyboxClientCert::GetSystemId(kValidTokenAndExpectedKeys[0].token_)); -} - -TEST_P(ClientCertTest, BasicCertValidation) { - const uint32_t system_id = 1234; - const std::string serial_number("serial_number"); - std::unique_ptr intermediate_certificate = - GenerateSignedIntermediateCertificate(nullptr, system_id, serial_number, - kNoSigner); - std::unique_ptr signed_cert = - GenerateSignedDrmCertificate(intermediate_certificate.get(), system_id, - serial_number + "-device1", - std::get<0>(GetParam())); - SignedMessage::SessionKeyType expected_key_type = - std::get<0>(GetParam()) != DrmCertificate::RSA - ? SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY - : SignedMessage::WRAPPED_AES_KEY; - std::unique_ptr encryption_certificate; - if (std::get<1>(GetParam()) != DrmCertificate::UNKNOWN_ALGORITHM) { - encryption_certificate = GenerateSignedDrmCertificate( - intermediate_certificate.get(), system_id, serial_number + "-device2", - std::get<1>(GetParam())); - expected_key_type = std::get<1>(GetParam()) != DrmCertificate::RSA - ? SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY - : SignedMessage::WRAPPED_AES_KEY; - } - const TestCertificateAndData kValidCertificateAndExpectedData( - signed_cert->SerializeAsString(), - encryption_certificate == nullptr - ? std::string() - : encryption_certificate->SerializeAsString(), - serial_number, system_id, OkStatus(), expected_key_type); - const bool compare_data = true; - TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData, - compare_data); -} - -INSTANTIATE_TEST_SUITE_P( - BasicCertValidation, ClientCertTest, - testing::Combine(testing::Values(DrmCertificate::RSA, - DrmCertificate::ECC_SECP256R1, - DrmCertificate::ECC_SECP384R1, - DrmCertificate::ECC_SECP521R1), - testing::Values(DrmCertificate::UNKNOWN_ALGORITHM, - DrmCertificate::RSA, - DrmCertificate::ECC_SECP256R1, - DrmCertificate::ECC_SECP384R1, - DrmCertificate::ECC_SECP521R1))); - -TEST_F(ClientCertTest, InvalidKeybox) { - const TestTokenAndKeys kInvalidTokenAndExpectedKeys[] = { - // This tests a malformed, but appropriately sized keybox. - TestTokenAndKeys( - absl::HexStringToBytes( - "00000002000001129e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"), - 0, absl::HexStringToBytes(""), absl::HexStringToBytes("")), - // This has a length and system_id, but nothing else. - TestTokenAndKeys(absl::HexStringToBytes("0000000200000112"), 0, - absl::HexStringToBytes(""), absl::HexStringToBytes("")), - // This has only a byte. - TestTokenAndKeys(absl::HexStringToBytes(""), 0, - absl::HexStringToBytes(""), absl::HexStringToBytes("")), - // This has an emptry std::string for the keybox. - TestTokenAndKeys(absl::HexStringToBytes(""), 0, - absl::HexStringToBytes(""), absl::HexStringToBytes(""))}; - - for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidTokenAndExpectedKeys); ++i) { - SCOPED_TRACE("Test data: " + absl::StrCat(i)); - TestBasicValidation(kInvalidTokenAndExpectedKeys[i], false, false); - } -} - -TEST_F(ClientCertTest, InvalidCertificate) { - const uint32_t system_id(1234); - const std::string device_sn("device-serial-number"); - const std::string signer_sn("signer-serial-number"); - std::unique_ptr dev_cert; - std::unique_ptr signer_cert; - std::unique_ptr signed_signer; - - // Invalid serialized device certificate. - std::unique_ptr invalid_drm_cert( - new SignedDrmCertificate); - invalid_drm_cert->set_drm_certificate("bad-serialized-cert"); - GenerateSignature( - invalid_drm_cert->drm_certificate(), - test_rsa_keys_.private_test_key_2_2048_bits(), - HashAlgorithmProtoToEnum(invalid_drm_cert->hash_algorithm()), - invalid_drm_cert->mutable_signature()); - invalid_drm_cert->set_allocated_signer( - GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn, - kNoSigner) - .release()); - // Invalid device public key. - dev_cert = GenerateDrmCertificate(system_id, device_sn); - dev_cert->set_public_key("bad-device-public-key"); - std::unique_ptr bad_device_public_key = - SignCertificate(*dev_cert, - GenerateSignedIntermediateCertificate( - nullptr, system_id, signer_sn, kNoSigner) - .get(), - test_rsa_keys_.private_test_key_2_2048_bits()); - // Invalid serialized intermediate certificate. - signed_signer = GenerateSignedIntermediateCertificate(nullptr, system_id, - signer_sn, kNoSigner); - signed_signer->set_drm_certificate("bad-serialized-cert"); - GenerateSignature(signed_signer->drm_certificate(), - test_rsa_keys_.private_test_key_1_3072_bits(), - HashAlgorithmProtoToEnum(signed_signer->hash_algorithm()), - signed_signer->mutable_signature()); - dev_cert = GenerateDrmCertificate(system_id, device_sn); - std::unique_ptr invalid_signer( - SignCertificate(*dev_cert, signed_signer.get(), - test_rsa_keys_.private_test_key_2_2048_bits())); - // Invalid signer public key. - dev_cert = GenerateDrmCertificate(system_id, device_sn); - signer_cert = GenerateIntermediateCertificate(system_id, signer_sn); - signer_cert->set_public_key("bad-signer-public-key"); - std::unique_ptr bad_signer_public_key(SignCertificate( - *dev_cert, - SignCertificate(*signer_cert, nullptr, - test_rsa_keys_.private_test_key_1_3072_bits()) - .get(), - test_rsa_keys_.private_test_key_2_2048_bits())); - // Invalid device certificate signature. - std::unique_ptr bad_device_signature( - GenerateSignedDrmCertificate(GenerateSignedIntermediateCertificate( - nullptr, system_id, signer_sn, kNoSigner) - .get(), - system_id, device_sn)); - bad_device_signature->set_signature("bad-signature"); - // Missing model system ID. - dev_cert = GenerateDrmCertificate(system_id, device_sn); - signer_cert = GenerateIntermediateCertificate(system_id, signer_sn); - signer_cert->clear_system_id(); - std::unique_ptr missing_model_sn(SignCertificate( - *dev_cert, - SignCertificate(*signer_cert, nullptr, - test_rsa_keys_.private_test_key_1_3072_bits()) - .get(), - test_rsa_keys_.private_test_key_2_2048_bits())); - // Missing signer serial number. - dev_cert = GenerateDrmCertificate(system_id, device_sn); - signer_cert = GenerateIntermediateCertificate(system_id, signer_sn); - signer_cert->clear_serial_number(); - std::unique_ptr missing_signer_sn(SignCertificate( - *dev_cert, - SignCertificate(*signer_cert, nullptr, - test_rsa_keys_.private_test_key_1_3072_bits()) - .get(), - test_rsa_keys_.private_test_key_2_2048_bits())); - // Invalid serialized intermediate certificate. - dev_cert = GenerateDrmCertificate(system_id, device_sn); - signed_signer = GenerateSignedIntermediateCertificate(nullptr, system_id, - signer_sn, kNoSigner); - signed_signer->set_signature("bad-signature"); - std::unique_ptr bad_signer_signature( - SignCertificate(*dev_cert, signed_signer.get(), - test_rsa_keys_.private_test_key_2_2048_bits())); - - const TestCertificateAndData kInvalidCertificate[] = { - TestCertificateAndData("f", "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signed-drm-certificate")), - TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-drm-certificate")), - TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-public-key-failed")), - TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-certificate")), - TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-leaf-signer-public-key")), - TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0, - Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature")), - TestCertificateAndData(missing_model_sn->SerializeAsString(), "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "model-certificate-missing-system-id")), - TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0, - Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-signer-serial-number")), - TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0, - Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature")), - }; - - for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) { - TestBasicValidationDrmCertificate(kInvalidCertificate[i], false); - } -} - -TEST_F(ClientCertTest, MissingPreProvKey) { - // system ID in token is 0x01234567 - const std::string token(absl::HexStringToBytes( - "00000002012345678e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e")); - std::unique_ptr client_cert_ptr; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::KEYBOX); - client_id.set_token(token); - Status status = - ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr); - ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code()); -} - -TEST_F(ClientCertTest, ValidProvisionerDeviceCert) { - const uint32_t system_id = 5000; - const std::string service_id("widevine_test.com"); - const std::string device_serial_number("device-serial-number"); - const std::string intermediate_serial_number("intermediate-serial-number"); - const std::string provisioner_serial_number("provisioner-serial-number"); - - std::unique_ptr signed_provisioner_cert = - GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, - service_id); - - std::unique_ptr signed_intermediate_cert = - GenerateSignedIntermediateCertificate( - signed_provisioner_cert.get(), system_id, intermediate_serial_number, - kProvisionerSigner); - - std::unique_ptr signed_device_cert = - GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id, - device_serial_number); - - std::string serialized_cert; - signed_device_cert->SerializeToString(&serialized_cert); - std::unique_ptr drm_cert; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(serialized_cert); - - EXPECT_OK(ClientCert::Create(root_cert_.get(), client_id, &drm_cert)); - ASSERT_TRUE(drm_cert); - - EXPECT_EQ(service_id, drm_cert->service_id()); - EXPECT_EQ(device_serial_number, drm_cert->serial_number()); - EXPECT_EQ(intermediate_serial_number, drm_cert->signer_serial_number()); - EXPECT_EQ(system_id, drm_cert->system_id()); -} - -TEST_F(ClientCertTest, InvalidProvisionerDeviceCertEmptyServiceId) { - const uint32_t system_id = 4890; - const std::string service_id(""); - const std::string device_serial_number("device-serial-number"); - const std::string intermediate_serial_number("intermediate-serial-number"); - const std::string provisioner_serial_number("provisioner-serial-number"); - - std::unique_ptr signed_provisioner_cert = - GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, - service_id); - - std::unique_ptr signed_intermediate_cert( - GenerateSignedIntermediateCertificate( - signed_provisioner_cert.get(), system_id, intermediate_serial_number, - kProvisionerSigner)); - - std::unique_ptr signed_device_cert = - GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id, - device_serial_number); - - std::string serialized_cert; - signed_device_cert->SerializeToString(&serialized_cert); - std::unique_ptr client_cert_ptr; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(serialized_cert); - - EXPECT_EQ("missing-provisioning-service-id", - ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr) - .error_message()); - EXPECT_FALSE(client_cert_ptr); -} - -TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) { - const uint32_t system_id = 4890; - const uint32_t system_id2 = 4892; - const std::string service_id("widevine_test.com"); - const std::string device_serial_number("device-serial-number"); - const std::string intermediate_serial_number("intermediate-serial-number"); - const std::string intermediate_serial_number2("intermediate-serial-number-2"); - - std::unique_ptr signed_intermediate_cert2 = - GenerateSignedIntermediateCertificate( - nullptr, system_id2, intermediate_serial_number2, kNoSigner); - - // Instead of using a provisioner certificate to sign this intermediate - // certificate, use another intermediate certificate. This is an invalid - // chain and should generate an error when trying to create a client - // certificate. - std::unique_ptr signed_intermediate_cert = - GenerateSignedIntermediateCertificate( - signed_intermediate_cert2.get(), system_id, - intermediate_serial_number, kDeviceModelSigner); - std::unique_ptr signed_device_cert = - GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id, - device_serial_number); - std::string serialized_cert; - signed_device_cert->SerializeToString(&serialized_cert); - std::unique_ptr client_cert_ptr; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(serialized_cert); - - ASSERT_EQ("expected-provisioning-provider-certificate-type", - ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr) - .error_message()); - EXPECT_FALSE(client_cert_ptr); -} - -TEST_F(ClientCertTest, InvalidDeviceCertChainSize_TooLong) { - const uint32_t system_id = 5000; - const std::string service_id("widevine_test.com"); - const std::string device_serial_number("device-serial-number"); - const std::string intermediate_serial_number1("intermediate-serial-number-1"); - const std::string intermediate_serial_number2("intermediate-serial-number-2"); - const std::string provisioner_serial_number("provisioner-serial-number"); - - std::unique_ptr signed_provisioner_cert = - GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, - service_id); - - std::unique_ptr signed_intermediate_cert1 = - GenerateSignedIntermediateCertificate( - signed_provisioner_cert.get(), system_id, intermediate_serial_number1, - kProvisionerSigner); - - std::unique_ptr signed_intermediate_cert2 = - GenerateSignedIntermediateCertificate( - signed_intermediate_cert1.get(), system_id, - intermediate_serial_number2, kDeviceModelSigner); - - std::unique_ptr signed_device_cert = - GenerateSignedDrmCertificate(signed_intermediate_cert2.get(), system_id, - device_serial_number); - - std::string serialized_cert; - signed_device_cert->SerializeToString(&serialized_cert); - std::unique_ptr client_cert_ptr = nullptr; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(serialized_cert); - - ASSERT_EQ("certificate-chain-size-exceeded", - ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr) - .error_message()); - EXPECT_FALSE(client_cert_ptr); -} - -TEST_F(ClientCertTest, DeviceCertTypeNotLeaf) { - const uint32_t system_id = 5000; - const std::string service_id("widevine_test.com"); - const std::string intermediate_serial_number("intermediate-serial-number"); - const std::string provisioner_serial_number("provisioner-serial-number"); - const std::string drm_serial_number("drm-serial-number"); - - std::unique_ptr signed_provisioner_cert = - GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, - service_id); - - // Use a DEVICE certificate as the intermediate certificate. - std::unique_ptr signed_intermediate_cert = - GenerateSignedDrmCertificate(signed_provisioner_cert.get(), system_id, - intermediate_serial_number); - - std::unique_ptr signed_drm_cert = - GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id, - drm_serial_number); - std::string serialized_cert; - signed_drm_cert->SerializeToString(&serialized_cert); - std::unique_ptr client_cert_ptr; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(serialized_cert); - - EXPECT_EQ("device-cert-must-be-leaf", - ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr) - .error_message()); - EXPECT_FALSE(client_cert_ptr); -} - -TEST_F(ClientCertTest, InvalidLeafCertificateType) { - const uint32_t system_id = 5000; - const std::string service_id("widevine_test.com"); - const std::string intermediate_serial_number("intermediate-serial-number"); - const std::string provisioner_serial_number("provisioner-serial-number"); - - std::unique_ptr signed_provisioner_cert = - GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, - service_id); - std::unique_ptr signed_intermediate_cert = - GenerateSignedIntermediateCertificate( - signed_provisioner_cert.get(), system_id, intermediate_serial_number, - kProvisionerSigner); - std::string serialized_cert; - signed_intermediate_cert->SerializeToString(&serialized_cert); - std::unique_ptr client_cert_ptr; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(serialized_cert); - // Leaf certificate must be a device certificate. - EXPECT_EQ("expected-device-certificate-type", - ClientCert::Create(root_cert_.get(), client_id, &client_cert_ptr) - .error_message()); - EXPECT_FALSE(client_cert_ptr); -} - -TEST_F(ClientCertTest, Protocol21WithDrmCert) { - const char message[] = "A weekend wasted is a weekend well spent."; - - std::unique_ptr client_cert; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(test_drm_certs_.test_user_device_certificate()); - ASSERT_OK(ClientCert::Create(root_cert_.get(), client_id, &client_cert)); - - std::unique_ptr private_key( - RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits())); - ASSERT_TRUE(private_key); - - // Success - std::string signature; - ASSERT_TRUE(private_key->GenerateSignature(message, kSha256, &signature)); - EXPECT_OK( - client_cert->VerifySignature(message, kSha256, signature, VERSION_2_1)); - - // Failure - ASSERT_EQ(256, signature.size()); - ++signature[127]; - EXPECT_FALSE( - client_cert->VerifySignature(message, kSha256, signature, VERSION_2_1) - .ok()); -} - -TEST_F(ClientCertTest, Protocol22WithDrmCert) { - const char message[] = "There is nothing permanent except change."; - const std::string message_hash(Sha512_Hash(message)); - - std::unique_ptr client_cert; - ClientIdentification client_id; - client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id.set_token(test_drm_certs_.test_user_device_certificate()); - ASSERT_OK(ClientCert::Create(root_cert_.get(), client_id, &client_cert)); - - std::unique_ptr private_key( - RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits())); - ASSERT_TRUE(private_key); - - // Success - std::string signature; - ASSERT_TRUE( - private_key->GenerateSignature(message_hash, kSha256, &signature)); - EXPECT_OK( - client_cert->VerifySignature(message, kSha256, signature, VERSION_2_2)); - - // Failure - ASSERT_EQ(256, signature.size()); - ++signature[127]; - EXPECT_FALSE( - client_cert->VerifySignature(message, kSha256, signature, VERSION_2_2) - .ok()); -} - -} // namespace widevine diff --git a/common/client_id_util.cc b/common/client_id_util.cc deleted file mode 100644 index cb25df8..0000000 --- a/common/client_id_util.cc +++ /dev/null @@ -1,126 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/client_id_util.h" - -#include "glog/logging.h" -#include "common/aes_cbc_util.h" -#include "common/client_cert.h" -#include "common/drm_service_certificate.h" -#include "common/error_space.h" -#include "common/keybox_client_cert.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace widevine { - -const char kModDrmMake[] = "company_name"; -const char kModDrmModel[] = "model_name"; -const char kModDrmDeviceName[] = "device_name"; -const char kModDrmProductName[] = "product_name"; -const char kModDrmBuildInfo[] = "build_info"; -const char kModDrmOemCryptoSecurityPatchLevel[] = - "oem_crypto_security_patch_level"; - -void AddClientInfo(ClientIdentification* client_id, absl::string_view name, - absl::string_view value) { - ClientIdentification_NameValue* nv = client_id->add_client_info(); - nv->set_name(std::string(name)); - nv->set_value(std::string(value)); -} - -bool SetClientInfo(ClientIdentification* client_id, absl::string_view name, - absl::string_view value) { - int n = client_id->client_info_size(); - for (int i = 0; i < n; i++) { - if (client_id->client_info(i).name() == name) { - client_id->mutable_client_info(i)->set_value(std::string(value)); - return true; - } - } - AddClientInfo(client_id, name, value); - return false; -} - -std::string GetClientInfo(const ClientIdentification& client_id, - absl::string_view name) { - return GetClientInfo(client_id, name, std::string()); -} - -std::string GetClientInfo(const ClientIdentification& client_id, - absl::string_view name, - const std::string& default_value) { - for (const auto& nv : client_id.client_info()) { - if (nv.name() == name) { - return nv.value(); - } - } - return default_value; -} - -Status DecryptEncryptedClientIdentification( - const EncryptedClientIdentification& encrypted_client_id, - ClientIdentification* client_id) { - return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id, - client_id); -} - -Status DecryptEncryptedClientIdentification( - const EncryptedClientIdentification& encrypted_client_id, - const std::string& privacy_key, ClientIdentification* client_id) { - DCHECK(client_id); - if (!encrypted_client_id.has_encrypted_client_id() || - encrypted_client_id.encrypted_client_id().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id"); - } - if (!encrypted_client_id.has_encrypted_client_id_iv() || - encrypted_client_id.encrypted_client_id_iv().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id-iv"); - } - std::string serialized_client_id(crypto_util::DecryptAesCbc( - privacy_key, encrypted_client_id.encrypted_client_id_iv(), - encrypted_client_id.encrypted_client_id())); - if (serialized_client_id.empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-decryption-failed"); - } - if (!client_id->ParseFromString(serialized_client_id)) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-parse-failed"); - } - return OkStatus(); -} - -uint32_t GetSystemId(const ClientIdentification& client_id) { - uint32_t system_id = 0; - if (client_id.has_token()) { - switch (client_id.type()) { - case ClientIdentification::KEYBOX: - system_id = KeyboxClientCert::GetSystemId(client_id.token()); - break; - case ClientIdentification::DRM_DEVICE_CERTIFICATE: { - SignedDrmCertificate signed_drm_certificate; - if (signed_drm_certificate.ParseFromString(client_id.token())) { - DrmCertificate drm_certificate; - if (drm_certificate.ParseFromString( - signed_drm_certificate.drm_certificate())) { - system_id = drm_certificate.system_id(); - } - } - } break; - default: - break; - } - } - return system_id; -} - -} // namespace widevine diff --git a/common/client_id_util.h b/common/client_id_util.h deleted file mode 100644 index 025b158..0000000 --- a/common/client_id_util.h +++ /dev/null @@ -1,71 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Utilities for manipulating the ClientIdentification proto. -// ClientIdentification.client_info() contains a sequence of -// arbitrary name-value pairs; this code consolidates the -// accessors for them in one place. -#ifndef COMMON_CLIENT_ID_UTIL_H_ -#define COMMON_CLIENT_ID_UTIL_H_ - -#include "absl/strings/string_view.h" -#include "common/status.h" -#include "protos/public/client_identification.pb.h" - -namespace widevine { - -extern const char kModDrmMake[]; -extern const char kModDrmModel[]; -extern const char kModDrmDeviceName[]; -extern const char kModDrmProductName[]; -extern const char kModDrmBuildInfo[]; -extern const char kModDrmOemCryptoSecurityPatchLevel[]; - -// Append the given name/value pair to client_id->client_info(). Does not -// check for duplicates. -void AddClientInfo(ClientIdentification* client_id, absl::string_view name, - absl::string_view value); - -// Append the given name/value pair to client_id->client_info(). If the -// given name already had a value, replaces it and returns true. -bool SetClientInfo(ClientIdentification* client_id, absl::string_view name, - absl::string_view value); - -// Return the value from client_id.client_info() matching the given name, -// or the empty std::string if not found. -std::string GetClientInfo(const ClientIdentification& client_id, - absl::string_view name); - -// Return the value from client_id.client_info() matching the given name, -// or the given default value if not found. -std::string GetClientInfo(const ClientIdentification& client_id, - absl::string_view name, - const std::string& default_value); - -// Decrypts the encrypted client identification in |encrypted_client_id| into -// |client_id| using the private key for the service certificate which was -// used to encrypt the information. -// |client_id| is owned by caller. -// Returns Status::OK, if successful, else an error. -Status DecryptEncryptedClientIdentification( - const EncryptedClientIdentification& encrypted_client_id, - ClientIdentification* client_id); - -// Decrypts the encrypted client identification in |encrypted_client_id| into -// |client_id| using |privacy_key|. -// |client_id| is owned by caller. -// Returns Status::OK, if successful, else an error. -Status DecryptEncryptedClientIdentification( - const EncryptedClientIdentification& encrypted_client_id, - const std::string& privacy_key, ClientIdentification* client_id); - -uint32_t GetSystemId(const ClientIdentification& client_id); - -} // namespace widevine - -#endif // COMMON_CLIENT_ID_UTIL_H_ diff --git a/common/content_id_util.cc b/common/content_id_util.cc deleted file mode 100644 index 40c755e..0000000 --- a/common/content_id_util.cc +++ /dev/null @@ -1,83 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// -#include "common/content_id_util.h" - -#include "glog/logging.h" -#include "common/error_space.h" -#include "common/status.h" -#include "license_server_sdk/internal/parse_content_id.h" -#include "protos/public/errors.pb.h" -#include "protos/public/external_license.pb.h" -#include "protos/public/license_protocol.pb.h" -#include "protos/public/license_server_sdk.pb.h" -#include "protos/public/widevine_pssh.pb.h" - -namespace widevine { - -Status GetContentIdFromExternalLicenseRequest( - const ExternalLicenseRequest& external_license_request, - std::string* content_id) { - WidevinePsshData pssh_data; - Status status = ParsePsshData(external_license_request, &pssh_data); - *content_id = pssh_data.content_id(); - return OkStatus(); -} -Status GetContentIdFromSignedExternalLicenseRequest( - const SignedMessage& signed_message, std::string* content_id) { - if (signed_message.type() != SignedMessage::EXTERNAL_LICENSE_REQUEST) { - return Status( - error_space, error::INVALID_ARGUMENT, - "Unexpected SignedMessage Type. EXTERNAL_LICENSE_REQUEST expected"); - } - ExternalLicenseRequest external_license_request; - if (!external_license_request.ParseFromString(signed_message.msg())) { - return Status(error_space, EXTERNAL_LICENSE_REQUEST_PARSE_ERROR, - "Unable to parse into External License Request"); - } - return GetContentIdFromExternalLicenseRequest(external_license_request, - content_id); -} - -Status ParsePsshData(ExternalLicenseRequest external_license_request, - WidevinePsshData* widevine_pssh_data) { - if (!external_license_request.has_content_id()) { - std::string error = "ExternalLicenseRequest does not include ContentId"; - LOG(ERROR) << error - << ", request = " << external_license_request.ShortDebugString(); - return Status(error_space, MISSING_CONTENT_ID, error); - } - ContentInfo content_info; - Status status = - ParseContentId(external_license_request.content_id(), &content_info); - if (!status.ok()) { - std::string error = - "Unable to retrieve ContentId from ExternalLicenseRequest"; - LOG(ERROR) << error << ", status = " << status - << ", request = " << external_license_request.ShortDebugString(); - return Status(error_space, MISSING_CONTENT_ID, error); - } - switch (external_license_request.content_id().init_data().init_data_type()) { - case LicenseRequest::ContentIdentification::InitData::WEBM: - widevine_pssh_data->ParseFromString( - content_info.content_info_entry(0).key_ids(0)); - break; - default: - *widevine_pssh_data = - content_info.content_info_entry(0).pssh().widevine_data(); - break; - } - if (widevine_pssh_data->content_id().empty()) { - std::string error = - "Missing ContentId within Pssh data for ExternalLicenseRequest"; - LOG(ERROR) << error - << ", request = " << external_license_request.ShortDebugString(); - return Status(error_space, MISSING_CONTENT_ID, error); - } - return OkStatus(); -} -} // namespace widevine diff --git a/common/content_id_util.h b/common/content_id_util.h deleted file mode 100644 index 3775cb3..0000000 --- a/common/content_id_util.h +++ /dev/null @@ -1,37 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_CONTENT_ID_UTIL_H_ -#define COMMON_CONTENT_ID_UTIL_H_ - -#include "common/status.h" -#include "protos/public/external_license.pb.h" -#include "protos/public/license_protocol.pb.h" -#include "protos/public/widevine_pssh.pb.h" - -namespace widevine { - -// Get content identifier as a std::string from a SignedMessage that includes a -// serialized ExternalLicenseRequest. -Status GetContentIdFromSignedExternalLicenseRequest( - const SignedMessage& signed_message, std::string* content_id); - -// Get content identifier as a std::string from an ExternalLicenseRequest. -Status GetContentIdFromExternalLicenseRequest( - const ExternalLicenseRequest& external_license_request, - std::string* content_id); - -// Returns OK if successful and |widevine_pssh_data| will be populated by -// parsing |external_license_request|. Else, error and |widevine_pssh_data| -// will not be set within this method. -Status ParsePsshData(ExternalLicenseRequest external_license_request, - WidevinePsshData* widevine_pssh_data); - -} // namespace widevine - -#endif // COMMON_CONTENT_ID_UTIL_H_ diff --git a/common/content_id_util_test.cc b/common/content_id_util_test.cc deleted file mode 100644 index ca0ea31..0000000 --- a/common/content_id_util_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/content_id_util.h" - -#include - -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "protos/public/errors.pb.h" -#include "protos/public/external_license.pb.h" -#include "protos/public/license_protocol.pb.h" -#include "protos/public/widevine_pssh.pb.h" - -namespace { -const char kContentId[] = "TestContentId"; -const char kPlayReadyChallenge[] = ""; -} // namespace - -namespace widevine { - -// Builds a SignedMessage that includes an ExternalLicenseRequest. -SignedMessage BuildSignedExternalLicenseRequest(const ExternalLicenseType type, - const std::string& request, - const std::string& content_id) { - ExternalLicenseRequest external_license_request; - external_license_request.set_request_type(type); - external_license_request.set_request(request); - LicenseRequest::ContentIdentification::WidevinePsshData* cenc_id = - external_license_request.mutable_content_id() - ->mutable_widevine_pssh_data(); - WidevinePsshData widevine_pssh_data; - widevine_pssh_data.set_content_id(content_id); - std::string widevine_pssh_string; - widevine_pssh_data.SerializeToString(&widevine_pssh_string); - cenc_id->add_pssh_data(widevine_pssh_string); - SignedMessage signed_message; - signed_message.set_type(SignedMessage::EXTERNAL_LICENSE_REQUEST); - EXPECT_TRUE( - external_license_request.SerializeToString(signed_message.mutable_msg())); - return signed_message; -} - -TEST(ContentIdUtil, GetContentId) { - std::string content_id; - EXPECT_OK(GetContentIdFromSignedExternalLicenseRequest( - BuildSignedExternalLicenseRequest(PLAYREADY_LICENSE_NEW, - kPlayReadyChallenge, kContentId), - &content_id)); - EXPECT_EQ(kContentId, content_id); -} - -TEST(ContentIdUtil, GetContentIdFailureWithIncorrectType) { - std::string content_id; - SignedMessage signed_message = BuildSignedExternalLicenseRequest( - PLAYREADY_LICENSE_NEW, kPlayReadyChallenge, kContentId); - signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST); - Status status = - GetContentIdFromSignedExternalLicenseRequest(signed_message, &content_id); - EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code()); - EXPECT_TRUE(content_id.empty()); -} - -TEST(ContentIdUtil, GetContentIdFailureWithInvalidExternalLicenseRequest) { - std::string content_id; - SignedMessage signed_message = BuildSignedExternalLicenseRequest( - PLAYREADY_LICENSE_NEW, kPlayReadyChallenge, kContentId); - signed_message.set_msg("Invalid payload"); - Status status = - GetContentIdFromSignedExternalLicenseRequest(signed_message, &content_id); - EXPECT_EQ(EXTERNAL_LICENSE_REQUEST_PARSE_ERROR, status.error_code()); - EXPECT_TRUE(content_id.empty()); -} - -} // namespace widevine diff --git a/common/core_message_util.cc b/common/core_message_util.cc deleted file mode 100644 index 90837c0..0000000 --- a/common/core_message_util.cc +++ /dev/null @@ -1,78 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/core_message_util.h" - -#include "common/oemcrypto_core_message/odk/include/core_message_deserialize.h" -#include "common/oemcrypto_core_message/odk/include/core_message_serialize.h" -#include "common/oemcrypto_core_message/odk/include/core_message_serialize_proto.h" -#include "common/sha_util.h" - -using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; -using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; -using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; -using oemcrypto_core_message::serialize::CreateCoreLicenseResponseFromProto; -using oemcrypto_core_message::serialize:: - CreateCoreProvisioningResponseFromProto; -using oemcrypto_core_message::serialize::CreateCoreRenewalResponse; -using widevine::Sha256_Hash; - -namespace widevine { -namespace core_message_util { -bool GetCoreProvisioningResponse( - const std::string& serialized_provisioning_response, - const std::string& request_core_message, - std::string* response_core_message) { - if (request_core_message.empty()) { - return false; - } - oemcrypto_core_message::ODK_ProvisioningRequest odk_provisioning_request; - if (CoreProvisioningRequestFromMessage(request_core_message, - &odk_provisioning_request)) { - return CreateCoreProvisioningResponseFromProto( - serialized_provisioning_response, odk_provisioning_request, - response_core_message); - } - return false; -} - -bool GetCoreRenewalOrReleaseLicenseResponse( - uint64_t renewal_duration_seconds, const std::string& request_core_message, - std::string* response_core_message) { - oemcrypto_core_message::ODK_RenewalRequest odk_renewal_request; - if (request_core_message.empty()) { - return false; - } - if (!CoreRenewalRequestFromMessage(request_core_message, - &odk_renewal_request)) { - return false; - } - return CreateCoreRenewalResponse( - odk_renewal_request, renewal_duration_seconds, response_core_message); -} - -bool GetCoreNewLicenseResponse(const std::string& license, - const std::string& request_core_message, - const bool nonce_required, - std::string* response_core_message) { - if (request_core_message.empty()) { - return false; - } - oemcrypto_core_message::ODK_LicenseRequest odk_license_request; - if (!CoreLicenseRequestFromMessage(request_core_message, - &odk_license_request)) { - return false; - } - std::string core_request_sha256 = Sha256_Hash(request_core_message); - return CreateCoreLicenseResponseFromProto(license, odk_license_request, - core_request_sha256, nonce_required, - response_core_message); -} - -} // namespace core_message_util -} // namespace widevine diff --git a/common/core_message_util.h b/common/core_message_util.h deleted file mode 100644 index 7c88dee..0000000 --- a/common/core_message_util.h +++ /dev/null @@ -1,40 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_CORE_MESSAGE_UTIL_H_ -#define COMMON_CORE_MESSAGE_UTIL_H_ - -#include - -namespace widevine { -namespace core_message_util { -// Gets the |response_core_message| by parsing |request_core_message| and -// |serialized_provisioning_response|. The output is held in -// |response_core_message|. -bool GetCoreProvisioningResponse( - const std::string& serialized_provisioning_response, - const std::string& request_core_message, - std::string* response_core_message); - -// Gets the |response_core_message| by parsing |request_core_message| for -// release and renewal response. The output is held in |response_core_message|. -bool GetCoreRenewalOrReleaseLicenseResponse( - uint64_t renewal_duration_seconds, const std::string& request_core_message, - std::string* response_core_message); - -// Gets the |response_core_message| by parsing |request_core_message| and -// |license| for new license response. The output is held in -// |response_core_message|. -bool GetCoreNewLicenseResponse(const std::string& license, - const std::string& request_core_message, - const bool nonce_required, - std::string* response_core_message); - -} // namespace core_message_util -} // namespace widevine -#endif // COMMON_CORE_MESSAGE_UTIL_H_ diff --git a/common/crypto_util_test.cc b/common/crypto_util_test.cc deleted file mode 100644 index c7613c1..0000000 --- a/common/crypto_util_test.cc +++ /dev/null @@ -1,318 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Unit tests for the crypto_util helper functions. - -#include "common/crypto_util.h" - -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "openssl/aes.h" - -namespace widevine { -namespace crypto_util { - -const char kCENCStr[] = "cenc"; -const char kCBC1Str[] = "cbc1"; -const char kCENSStr[] = "cens"; -const char kCBCSStr[] = "cbcs"; - -static unsigned char kAes128KeyData[] = {0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, - 0x32, 0x9e, 0x6b, 0x3b, 0x4e, 0x29, - 0xfa, 0x3b, 0x00, 0x4b}; - -static unsigned char kAes256KeyData[] = { - 0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e, 0x6b, 0x3b, 0x4e, - 0x29, 0xfa, 0x3b, 0x00, 0x4b, 0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, - 0x32, 0x9e, 0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b}; - -static unsigned char kAes128IvData[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, - 0x0c, 0x0d, 0x0e, 0x0f}; - -class CryptoUtilTest : public ::testing::Test { - public: - CryptoUtilTest() - : aes_128_key_(kAes128KeyData, kAes128KeyData + sizeof(kAes128KeyData)), - aes_256_key_(kAes256KeyData, kAes256KeyData + sizeof(kAes256KeyData)), - iv_128_(kAes128IvData, kAes128IvData + sizeof(kAes128IvData)) {} - - protected: - std::string aes_128_key_; - std::string aes_256_key_; - std::string iv_128_; -}; - -TEST_F(CryptoUtilTest, DeriveAes128MasterKeyTest) { - unsigned char label[] = { 0x16, 0xf1, 0xa4, 0x32, 0x9f, 0x94, 0x55, 0xc1, - 0x92, 0xa0, 0x34, 0x8a, 0x8b, 0x6b, 0x77, 0x08, - 0xbc, 0x23, 0x70, 0x16, 0xbc, 0xda, 0xfb, 0x60, - 0xd1, 0xcf, 0x6a, 0x4d, 0x40, 0xa1, 0xe3, 0xfe, - 0xd3, 0xe9, 0xa6, 0x58, 0x4c, 0xd4, 0xad, 0xa4, - 0xa2 }; - - unsigned char context[] = { 0x4c, 0x53, 0xc0, 0xe9, 0x9e, 0x7f, 0x7d, 0x6d, - 0x0a, 0x76, 0x7c, 0xc7, 0x25, 0xb5, 0x5b, 0x80, - 0x81, 0x91, 0xff }; - - unsigned char output0[] = { 0xd5, 0xad, 0x2d, 0xb1, 0x5a, 0x06, 0xcb, 0x50, - 0xf2, 0x59, 0x5a, 0xb2, 0xb2, 0x0d, 0x44, 0x4e }; - - unsigned char output1[] = { 0xdf, 0x38, 0x45, 0x97, 0x5d, 0x7a, 0x81, 0xb4, - 0x94, 0x86, 0xaf, 0x0c, 0xdc, 0x4d, 0xeb, 0x62, - 0x31, 0x39, 0x67, 0x8f, 0xff, 0x5d, 0x68, 0x35, - 0xdc, 0x89, 0x5f, 0x47, 0xca, 0xe0, 0x2d, 0x3a, - 0x10, 0x24, 0xf8, 0x7e, 0x5b, 0x70, 0xe1, 0xa3, - 0x4a, 0x47, 0x2f, 0x04, 0xe0, 0x34, 0x75, 0x22 }; - - std::string label_str(label, label + sizeof(label)); - std::string context_str(context, context + sizeof(context)); - std::string result = DeriveKey(aes_128_key_, label_str, context_str, 128); - - std::string output_128(output0, output0 + sizeof(output0)); - - ASSERT_EQ(result, output_128); - - result = DeriveKey(aes_128_key_, label_str, context_str, 384); - - std::string output_384(output1, output1 + sizeof(output1)); - - ASSERT_EQ(result, output_384); -} - -TEST_F(CryptoUtilTest, DeriveAes256MasterKeyTest) { - const unsigned char label[] = { - 0x16, 0xf1, 0xa4, 0x32, 0x9f, 0x94, 0x55, 0xc1, 0x92, 0xa0, 0x34, - 0x8a, 0x8b, 0x6b, 0x77, 0x08, 0xbc, 0x23, 0x70, 0x16, 0xbc, 0xda, - 0xfb, 0x60, 0xd1, 0xcf, 0x6a, 0x4d, 0x40, 0xa1, 0xe3, 0xfe, 0xd3, - 0xe9, 0xa6, 0x58, 0x4c, 0xd4, 0xad, 0xa4, 0xa2}; - - const unsigned char context[] = {0x4c, 0x53, 0xc0, 0xe9, 0x9e, 0x7f, 0x7d, - 0x6d, 0x0a, 0x76, 0x7c, 0xc7, 0x25, 0xb5, - 0x5b, 0x80, 0x81, 0x91, 0xff}; - - const unsigned char expected_128[] = {0x76, 0x36, 0x33, 0x0e, 0x0b, 0x2c, - 0x38, 0xc2, 0x9e, 0x53, 0x23, 0x8d, - 0x2e, 0xc6, 0x3a, 0x46}; - - const std::string label_str(label, label + sizeof(label)); - const std::string context_str(context, context + sizeof(context)); - std::string result = DeriveKey(aes_256_key_, label_str, context_str, 128); - EXPECT_EQ(std::string(expected_128, expected_128 + sizeof(expected_128)), - result) - << absl::BytesToHexString(result); - - const unsigned char expected_256[] = { - 0xfb, 0x8f, 0xdf, 0x0e, 0x22, 0xfe, 0xf7, 0x2b, 0xd1, 0x9a, 0x1d, - 0xd2, 0xcb, 0xb0, 0x11, 0x5c, 0x6c, 0xa7, 0xe1, 0x7f, 0x72, 0xce, - 0x3a, 0x60, 0x34, 0x89, 0x6d, 0x08, 0xef, 0xde, 0x19, 0x45}; - result = DeriveKey(aes_256_key_, label_str, context_str, 256); - EXPECT_EQ(std::string(expected_256, expected_256 + sizeof(expected_256)), - result) - << absl::BytesToHexString(result); - - const unsigned char expected_384[] = { - 0x65, 0xbc, 0xe3, 0xf3, 0xfb, 0xfa, 0xce, 0x1d, 0x24, 0x63, 0x9c, 0x8f, - 0x48, 0x0e, 0xbd, 0x76, 0xd1, 0x14, 0x0b, 0xb1, 0x3a, 0x3d, 0x6e, 0x30, - 0xa9, 0xf4, 0x40, 0x35, 0x0d, 0x6b, 0xc5, 0x1e, 0x9c, 0xa9, 0x5f, 0xf9, - 0xde, 0x96, 0xa0, 0xa4, 0x22, 0x62, 0x21, 0xc5, 0xd6, 0xd4, 0xf4, 0x6f}; - result = DeriveKey(aes_256_key_, label_str, context_str, 384); - EXPECT_EQ(std::string(expected_384, expected_384 + sizeof(expected_384)), - result) - << absl::BytesToHexString(result); -} - -TEST_F(CryptoUtilTest, DeriveAesInvalidSizeModulus) { - // This is the control case that we correctly derive 128 bits. - EXPECT_NE("", DeriveKey(aes_128_key_, "foo", "bar", 128)); - EXPECT_EQ("", DeriveKey(aes_128_key_, "foo", "bar", 127)); -} - -TEST_F(CryptoUtilTest, DeriveAesMaxBlocks) { - EXPECT_EQ( - 255 * AES_BLOCK_SIZE, - DeriveKey(aes_128_key_, "foo", "bar", AES_BLOCK_SIZE * 8 * 255).size()); -} - -TEST_F(CryptoUtilTest, DeriveAesTooManyBlocks) { - EXPECT_EQ("", - DeriveKey(aes_128_key_, "foo", "bar", AES_BLOCK_SIZE * 8 * 256)); -} - -TEST_F(CryptoUtilTest, DeriveAes128InvalidKeySize) { - EXPECT_EQ("", DeriveKey(aes_128_key_.substr(0, 15), "foo", "bar", 128)); -} - -TEST_F(CryptoUtilTest, DeriveAes256InvalidKeySize) { - EXPECT_EQ("", DeriveKey(aes_256_key_.substr(0, 31), "foo", "bar", 128)); -} - -TEST_F(CryptoUtilTest, DeriveGroupSesionKey) { - unsigned char output[] = { 0x92, 0x6c, 0x2f, 0x5, 0xa6, 0x4f, 0xff, 0xb1, - 0x86, 0x4a, 0x1a, 0x14, 0x95, 0xeb, 0xb0, 0xf1 }; - std::string group_session_key = DeriveGroupSessionKey("test_group_id", 128); - EXPECT_EQ(crypto_util::kAes128KeySizeBytes, group_session_key.size()); - const std::string output_128(output, output + sizeof(output)); - ASSERT_EQ(output_128, group_session_key); -} - -TEST_F(CryptoUtilTest, TestCreateAndVerifySignatureHmacSha256) { - unsigned char message_data[] = { - 0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, - 0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2, - 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91, - 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, - 0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, - 0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5, - 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54, - 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda }; - - std::string message(message_data, message_data + sizeof(message_data)); - std::string signature(CreateSignatureHmacSha256(aes_128_key_, message)); - - ASSERT_EQ(signature.size(), 32); - - ASSERT_TRUE(VerifySignatureHmacSha256(aes_128_key_, signature, message)); -} - -TEST_F(CryptoUtilTest, TestFailCreateAndVerifyHmacSha256) { - unsigned char message_data[] = { - 0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, - 0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2, - 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91, - 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, - 0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, - 0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5, - 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54, - 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda }; - - std::string message(message_data, message_data + sizeof(message_data)); - // Test with bogus key; - std::string bogus_key("bogus"); - std::string signature(CreateSignatureHmacSha256(bogus_key, message)); - - // This should still produce an hmac signature. - ASSERT_EQ(signature.size(), 32); - - // Create valid signature to compare. - signature = CreateSignatureHmacSha256(aes_128_key_, message); - - // Test with bogus key. - ASSERT_FALSE(VerifySignatureHmacSha256(bogus_key, signature, message)); - - // Test with munged signature. - signature[0] = 0xFF; - ASSERT_FALSE(VerifySignatureHmacSha256(aes_128_key_, signature, message)); - - // Test with bogus signature. - ASSERT_FALSE(VerifySignatureHmacSha256(aes_128_key_, "bogus", message)); -} - -TEST_F(CryptoUtilTest, TestCreateAndVerifySignatureHmacSha1) { - unsigned char message_data[] = { - 0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, - 0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2, - 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91, - 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, - 0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, - 0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5, - 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54, - 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda }; - - std::string message(message_data, message_data + sizeof(message_data)); - std::string signature(CreateSignatureHmacSha1(aes_128_key_, message)); - - ASSERT_EQ(20, signature.size()); - ASSERT_TRUE(VerifySignatureHmacSha1(aes_128_key_, signature, message)); -} - -TEST_F(CryptoUtilTest, TestFailCreateAndVerifyHmacSha1) { - unsigned char message_data[] = { - 0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53, - 0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2, - 0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91, - 0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde, - 0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f, - 0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5, - 0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54, - 0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda }; - - std::string message(message_data, message_data + sizeof(message_data)); - // Test with bogus key; - std::string bogus_key("bogus"); - std::string signature(CreateSignatureHmacSha1(bogus_key, message)); - - // This should still produce an hmac signature. - ASSERT_EQ(20, signature.size()); - // Create valid signature to compare. - signature = CreateSignatureHmacSha1(aes_128_key_, message); - // Test with bogus key. - ASSERT_FALSE(VerifySignatureHmacSha1(bogus_key, signature, message)); - // Test with munged signature. - signature[0] = 0xFF; - ASSERT_FALSE(VerifySignatureHmacSha1(aes_128_key_, signature, message)); - // Test with bogus signature. - ASSERT_FALSE(VerifySignatureHmacSha1(aes_128_key_, "bogus", message)); -} - -TEST_F(CryptoUtilTest, DeriveIv) { - // First value in the pair is the key_id, second value is the expected IV. - std::pair id_iv_pairs[] = { - {"1234567890123456", "3278234c7682d1a2e153af4912975f5f"}, - {"0987654321098765", "cf09abd30f04b60544910791a6b904cf"}}; - for (const auto& id_iv_pair : id_iv_pairs) { - SCOPED_TRACE(absl::StrCat("test case:", id_iv_pair.first)); - EXPECT_EQ(id_iv_pair.second, - absl::BytesToHexString(DeriveIv(id_iv_pair.first))); - // Repeat same call to verify derivied result is repeatable. - EXPECT_EQ(id_iv_pair.second, - absl::BytesToHexString(DeriveIv(id_iv_pair.first))); - } -} - -TEST_F(CryptoUtilTest, DeriveKeyId) { - // First value in the pair is the context, second value is the expected id. - std::pair context_id_pairs[] = { - {"1234567890123456", "a3c4a8c0d0e24e96f38f492254186a9d"}, - {"0987654321098765", "084fc6bece9688ccce6b1672d9b47e22"}}; - for (const auto& context_id_pair : context_id_pairs) { - SCOPED_TRACE(absl::StrCat("test case:", context_id_pair.first)); - EXPECT_EQ(context_id_pair.second, - absl::BytesToHexString(DeriveKeyId(context_id_pair.first))); - // Repeat same call to verify derivied result is repeatable. - EXPECT_EQ(context_id_pair.second, - absl::BytesToHexString(DeriveKeyId(context_id_pair.first))); - } -} - -TEST_F(CryptoUtilTest, Verify4CCEncryptionIDFromBadString) { - uint32_t cc_code; - ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("garbage", &cc_code)); - ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("junk", &cc_code)); - ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("cencc", &cc_code)); -} - -TEST_F(CryptoUtilTest, Verify4CCEncryptionIDFromString) { - uint32_t cc_code = 0; - ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENCStr, &cc_code)); - ASSERT_EQ(kCENCSchemeID, cc_code); - ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBC1Str, &cc_code)); - ASSERT_EQ(kCBC1SchemeID, cc_code); - ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENSStr, &cc_code)); - ASSERT_EQ(kCENSSchemeID, cc_code); - ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBCSStr, &cc_code)); - ASSERT_EQ(kCBCSSchemeID, cc_code); -} - -} // namespace crypto_util -} // namespace widevine diff --git a/common/default_device_security_profile_list.cc b/common/default_device_security_profile_list.cc deleted file mode 100644 index 9aa625e..0000000 --- a/common/default_device_security_profile_list.cc +++ /dev/null @@ -1,135 +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. -//////////////////////////////////////////////////////////////////////////////// -// Implementation of the DefaultDeviceSecurityProfileList class. - -#include "common/default_device_security_profile_list.h" - -#include - -#include "glog/logging.h" -#include "google/protobuf/text_format.h" -#include "common/client_id_util.h" -#include "common/device_status_list.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/device_certificate_status.pb.h" -#include "protos/public/device_common.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 kWidevine[] = "widevine"; - -// Definition of Widevine default device security profiles. -// TODO(user): Add an OWNER file with per-file access to restrict changes to the -// profile definition. -const char kWidevineProfileMin[] = - (" name: \"minimum\"" - " min_output_requirements {" - " hdcp_version: HDCP_NONE" - " analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN" - " }" - " min_security_requirements {" - " oemcrypto_api_version: 0" - " security_level: LEVEL_3" - " resource_rating_tier: 0" - " vulnerability_level: VULNERABILITY_HIGH" - " }" - " owner: \"Widevine\""); - -const char kWidevineProfileLow[] = - (" name: \"low\"" - " min_output_requirements {" - " hdcp_version: HDCP_NONE" - " analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN" - " }" - " min_security_requirements {" - " oemcrypto_api_version: 8" - " security_level: LEVEL_3" - " resource_rating_tier: 1" - " vulnerability_level: VULNERABILITY_MEDIUM" - " }" - " owner: \"Widevine\""); - -const char kWidevineProfileMed[] = - (" name: \"medium\"" - " min_output_requirements {" - " hdcp_version: HDCP_V1" - " analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN" - " }" - " min_security_requirements {" - " oemcrypto_api_version: 12" - " security_level: LEVEL_3" - " resource_rating_tier: 1" - " vulnerability_level: VULNERABILITY_LOW" - " }" - " owner: \"Widevine\""); - -const char kWidevineProfileHigh[] = - (" name: \"high\"" - " min_output_requirements {" - " hdcp_version: HDCP_V1" - " analog_output_capabilities: ANALOG_OUTPUT_SUPPORTS_CGMS_A" - " }" - " min_security_requirements {" - " oemcrypto_api_version: 12" - " security_level: LEVEL_1" - " resource_rating_tier: 2" - " vulnerability_level: VULNERABILITY_NONE" - " }" - " owner: \"Widevine\""); - -const char kWidevineProfileStrict[] = - (" name: \"strict\"" - " min_output_requirements {" - " hdcp_version: HDCP_V2_2" - " analog_output_capabilities: ANALOG_OUTPUT_SUPPORTS_CGMS_A" - " }" - " min_security_requirements {" - " oemcrypto_api_version: 12" - " security_level: LEVEL_1" - " resource_rating_tier: 3" - " vulnerability_level: VULNERABILITY_NONE" - " }" - " owner: \"Widevine\""); - -DefaultDeviceSecurityProfileList::DefaultDeviceSecurityProfileList() - : SecurityProfileList(kWidevine) {} - -int DefaultDeviceSecurityProfileList::Init() { return AddDefaultProfiles(); } - -int DefaultDeviceSecurityProfileList::AddDefaultProfiles() { - std::vector default_profile_strings; - GetDefaultProfileStrings(&default_profile_strings); - for (auto& profile_string : default_profile_strings) { - SecurityProfile profile; - if (!google::protobuf::TextFormat::ParseFromString(profile_string, &profile)) { - LOG(ERROR) << "Unable to load default profile: " << profile.name(); - ClearAllProfiles(); - return 0; - } - InsertProfile(profile); - } - return NumProfiles(); -} - -int DefaultDeviceSecurityProfileList::GetDefaultProfileStrings( - std::vector* default_profile_strings) const { - if (default_profile_strings == nullptr) { - return 0; - } - default_profile_strings->push_back(kWidevineProfileMin); - default_profile_strings->push_back(kWidevineProfileLow); - default_profile_strings->push_back(kWidevineProfileMed); - default_profile_strings->push_back(kWidevineProfileHigh); - default_profile_strings->push_back(kWidevineProfileStrict); - return default_profile_strings->size(); -} - -} // namespace widevine diff --git a/common/default_device_security_profile_list.h b/common/default_device_security_profile_list.h deleted file mode 100644 index 33d96d9..0000000 --- a/common/default_device_security_profile_list.h +++ /dev/null @@ -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* default_profile_strings) const; -}; - -} // namespace widevine - -#endif // COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_ diff --git a/common/default_device_security_profile_list_test.cc b/common/default_device_security_profile_list_test.cc deleted file mode 100644 index 958836c..0000000 --- a/common/default_device_security_profile_list_test.cc +++ /dev/null @@ -1,186 +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. -//////////////////////////////////////////////////////////////////////////////// -// - -#include "common/default_device_security_profile_list.h" - -#include "glog/logging.h" -#include "google/protobuf/util/message_differencer.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/memory/memory.h" -#include "common/client_id_util.h" -#include "protos/public/device_common.pb.h" -#include "protos/public/security_profile.pb.h" - -namespace widevine { -namespace security_profile { - -const uint32_t kResourceTierLow = 1; -const uint32_t kResourceTierMed = 2; -const uint32_t kResourceTierHigh = 3; -const char kMinProfileName[] = "minimum"; -const char kLowProfileName[] = "low"; -const char kMedProfileName[] = "medium"; -const char kHighProfileName[] = "high"; -const char kStrictProfileName[] = "strict"; - -class DefaultDeviceSecurityProfileListTest : public ::testing::Test { - public: - DefaultDeviceSecurityProfileListTest() {} - ~DefaultDeviceSecurityProfileListTest() override {} - - void SetUp() override { - SecurityProfile profile; - std::string profile_namespace = "widevine"; - profile_list_ = absl::make_unique(); - const int kNumWidevineProfiles = 5; - ASSERT_EQ(kNumWidevineProfiles, profile_list_->Init()); - } - - // Configure |client_id| and |device_info| with minimum settings. - void SetupMinDrmParams(ClientIdentification* client_id, - ProvisionedDeviceInfo* device_info) { - client_id->mutable_client_capabilities()->set_max_hdcp_version( - ClientCapabilities::HDCP_NONE); - client_id->mutable_client_capabilities()->set_analog_output_capabilities( - ClientCapabilities::ANALOG_OUTPUT_UNKNOWN); - client_id->mutable_client_capabilities()->set_oem_crypto_api_version(0); - client_id->mutable_client_capabilities()->set_resource_rating_tier( - kResourceTierLow); - device_info->set_security_level(ProvisionedDeviceInfo::LEVEL_3); - } - - // Configure |client_id| and |device_info| with maximum settings. - void SetupMaxDrmParams(ClientIdentification* client_id, - ProvisionedDeviceInfo* device_info) { - client_id->mutable_client_capabilities()->set_max_hdcp_version( - ClientCapabilities::HDCP_V2_3); - client_id->mutable_client_capabilities()->set_analog_output_capabilities( - ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A); - client_id->mutable_client_capabilities()->set_oem_crypto_api_version(16); - client_id->mutable_client_capabilities()->set_resource_rating_tier( - kResourceTierHigh); - device_info->set_security_level(ProvisionedDeviceInfo::LEVEL_1); - } - - std::unique_ptr profile_list_; -}; - -TEST_F(DefaultDeviceSecurityProfileListTest, QualifiedProfiles) { - ClientIdentification client_id; - ProvisionedDeviceInfo device_info; - SetupMinDrmParams(&client_id, &device_info); - - std::vector qualified_profiles; - // Should only return the minimum profile. - ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMinProfileName) != qualified_profiles.end()); - - // Increase the device capabilities to include the low profile. - client_id.mutable_client_capabilities()->set_oem_crypto_api_version(8); - ASSERT_EQ(2, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); - - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMinProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kLowProfileName) != qualified_profiles.end()); - - // Increase the device capabilities to include the med profile. - client_id.mutable_client_capabilities()->set_max_hdcp_version( - ClientCapabilities::HDCP_V1); - client_id.mutable_client_capabilities()->set_oem_crypto_api_version(12); - ASSERT_EQ(3, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMinProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kLowProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMedProfileName) != qualified_profiles.end()); - - // Increase the device capabilities to include the high profile. - device_info.set_security_level(ProvisionedDeviceInfo::LEVEL_1); - client_id.mutable_client_capabilities()->set_analog_output_capabilities( - ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A); - client_id.mutable_client_capabilities()->set_resource_rating_tier( - kResourceTierMed); - ASSERT_EQ(4, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMinProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kLowProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMedProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kHighProfileName) != qualified_profiles.end()); - - // Increase the device capabilities to include the strict profile. - client_id.mutable_client_capabilities()->set_max_hdcp_version( - ClientCapabilities::HDCP_V2_2); - client_id.mutable_client_capabilities()->set_resource_rating_tier( - kResourceTierHigh); - ASSERT_EQ(5, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMinProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kLowProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMedProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kHighProfileName) != qualified_profiles.end()); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kStrictProfileName) != qualified_profiles.end()); -} - -TEST_F(DefaultDeviceSecurityProfileListTest, - DeviceQualifiedProfilesForLowEndDevice) { - ClientIdentification client_id; - ProvisionedDeviceInfo device_info; - SetupMinDrmParams(&client_id, &device_info); - - // Only 1 profile should qualify for this device. - std::vector qualified_profiles; - ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); - EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(), - kMinProfileName) != qualified_profiles.end()); -} - -TEST_F(DefaultDeviceSecurityProfileListTest, - QualifiedProfilesForHighEndDevice) { - ClientIdentification client_id; - ProvisionedDeviceInfo device_info; - SetupMaxDrmParams(&client_id, &device_info); - - // All 5 default profiles should qualify for this device. - std::vector qualified_profiles; - ASSERT_EQ(5, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); -} - -// TODO(b/160019477): Add test once provisioned device info supports known -// vulnerability. -TEST_F(DefaultDeviceSecurityProfileListTest, - DISABLED_QualifiedProfilesByVunerabilityLevel) { - ClientIdentification client_id; - ProvisionedDeviceInfo device_info; - SetupMaxDrmParams(&client_id, &device_info); - - std::vector qualified_profiles; - ASSERT_EQ(0, profile_list_->GetQualifiedProfiles(client_id, device_info, - &qualified_profiles)); -} - -} // namespace security_profile -} // namespace widevine diff --git a/common/device_info_util.cc b/common/device_info_util.cc deleted file mode 100644 index 1579e91..0000000 --- a/common/device_info_util.cc +++ /dev/null @@ -1,42 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -// Implements the device info helper function. -#include "common/device_info_util.h" - -#include "absl/strings/ascii.h" -#include "protos/public/device_common.pb.h" - -namespace widevine { -bool IsMatchedMakeModel(const std::string& expected_make, - const std::string& expected_model, - const std::string& make_from_client, - const std::string& model_from_client) { - return absl::AsciiStrToLower(expected_make) == - absl::AsciiStrToLower(make_from_client) && - absl::AsciiStrToLower(expected_model) == - absl::AsciiStrToLower(model_from_client); -} - -bool VerifyMakeModel(const ProvisionedDeviceInfo& device_info, - const std::string& make_from_client, - const std::string& model_from_client) { - if (IsMatchedMakeModel(device_info.manufacturer(), device_info.model(), - make_from_client, model_from_client)) { - return true; - } - for (const DeviceModel& product_info : device_info.model_info()) { - if (IsMatchedMakeModel(product_info.manufacturer(), - product_info.model_name(), make_from_client, - model_from_client)) { - return true; - } - } - return false; -} -} // namespace widevine diff --git a/common/device_info_util.h b/common/device_info_util.h deleted file mode 100644 index b202519..0000000 --- a/common/device_info_util.h +++ /dev/null @@ -1,30 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_DEVICE_INFO_UTIL_H_ -#define COMMON_DEVICE_INFO_UTIL_H_ - -#include - -#include "protos/public/provisioned_device_info.pb.h" - -namespace widevine { - -// Helpers function to compare the expected and actual make model field. -bool IsMatchedMakeModel(const std::string& expected_make, - const std::string& expected_model, - const std::string& make_from_client, - const std::string& model_from_client); -/** - * Return true if make/model from client in device_info matches any of the - * registered makes/models. - */ -bool VerifyMakeModel(const ProvisionedDeviceInfo& device_info, - const std::string& make_from_client, - const std::string& model_from_client); -} // namespace widevine -#endif // COMMON_DEVICE_INFO_UTIL_H_ diff --git a/common/device_status_list.cc b/common/device_status_list.cc deleted file mode 100644 index 5cfe9ec..0000000 --- a/common/device_status_list.cc +++ /dev/null @@ -1,598 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -// Implements the DeviceStatusList class. - -#include "common/device_status_list.h" - -#include - -#include -#include - -#include -#include "glog/logging.h" -#include "absl/strings/ascii.h" -#include "absl/strings/escaping.h" -#include "absl/strings/numbers.h" -#include "absl/strings/str_split.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" -#include "util/gtl/map_util.h" -#include "common/client_cert.h" -#include "common/drm_service_certificate.h" -#include "common/error_space.h" -#include "common/hash_algorithm_util.h" -#include "common/keybox_client_cert.h" -#include "common/rsa_key.h" -#include "common/status.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/device_certificate_status.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_device_info.pb.h" - -using ::widevine::DeviceCertificateStatusListRequest; -using ::widevine::SignedDeviceInfo; -using ::widevine::SignedDeviceInfoRequest; - -namespace widevine { - -namespace { -const char kSignedListTerminator[] = "}"; -const char kSignedList[] = "signedList\":"; -const std::size_t kSignedListLen = strlen(kSignedList); -} // namespace - -DeviceStatusList* DeviceStatusList::Instance() { - // TODO(user): This is "ok" according to Google's Coding for Dummies, but - // we should inject the status list into the sessions. This will require - // exposing additional objects in the public interface. - static DeviceStatusList* device_status_list(nullptr); - if (!device_status_list) device_status_list = new DeviceStatusList; - return device_status_list; -} - -DeviceStatusList::DeviceStatusList() {} - -DeviceStatusList::~DeviceStatusList() {} - -Status DeviceStatusList::UpdateStatusList( - const std::string& root_certificate_public_key, - const std::string& serialized_device_certificate_status_list, - HashAlgorithm hash_algorithm, const std::string& signature, - uint32_t expiration_period_seconds) { - if (serialized_device_certificate_status_list.empty()) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list"); - } - if (signature.empty()) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list-signature"); - } - std::unique_ptr root_key( - RsaPublicKey::Create(root_certificate_public_key)); - if (root_key == nullptr) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-root-public-key"); - } - if (!root_key->VerifySignature(serialized_device_certificate_status_list, - hash_algorithm, signature)) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "invalid-status-list-signature"); - } - DeviceCertificateStatusList certificate_status_list; - if (!certificate_status_list.ParseFromString( - serialized_device_certificate_status_list)) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "signed-certificate-status-list-parse-error"); - } - if (expiration_period_seconds && - (GetCurrentTime() > (certificate_status_list.creation_time_seconds() + - expiration_period_seconds))) { - return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, - "certificate-status-list-expired"); - } - - absl::WriterMutexLock lock(&status_map_lock_); - device_status_map_.clear(); - for (int i = 0, n = certificate_status_list.certificate_status_size(); i < n; - i++) { - const DeviceCertificateStatus& cert_status = - certificate_status_list.certificate_status(i); - if (cert_status.has_device_info()) { - const ProvisionedDeviceInfo& device_info = cert_status.device_info(); - if (device_info.has_system_id()) { - device_status_map_[device_info.system_id()] = cert_status; - } else { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "device-info-missing-system-id"); - } - } - } - creation_time_seconds_ = certificate_status_list.creation_time_seconds(); - expiration_period_seconds_ = expiration_period_seconds; - return OkStatus(); -} - -Status DeviceStatusList::GetCertStatus( - const ClientCert& client_cert, const std::string& make, - const std::string& provider, bool allow_revoked_system_id, - DeviceCertificateStatus* device_certificate_status) { - CHECK(device_certificate_status); - absl::ReaderMutexLock lock(&status_map_lock_); - if (expiration_period_seconds_ && - (GetCurrentTime() > - (creation_time_seconds_ + expiration_period_seconds_))) { - return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, - "certificate-status-list-expired"); - } - DeviceCertificateStatus* device_cert_status = - gtl::FindOrNull(device_status_map_, client_cert.system_id()); - - if (device_cert_status == nullptr) { - if (allow_unknown_devices_) { - return OkStatus(); - } - return client_cert.SystemIdUnknownError(); - } - *device_certificate_status = *device_cert_status; - - if (device_cert_status->status() == DeviceCertificateStatus::STATUS_REVOKED) { - if (IsRevokedSystemIdAllowed(client_cert.system_id()) || - allow_revoked_system_id) { - LOG(WARNING) << "Allowing REVOKED device: " - << device_cert_status->device_info().ShortDebugString(); - } else { - return client_cert.SystemIdRevokedError(); - } - } - - // The remainder of this function is for DRM certificates. - if (client_cert.type() == ClientIdentification::KEYBOX) { - return OkStatus(); - } - // DRM certificate checks. - if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "device-certificate-unsupported-token-type"); - } - if ((device_cert_status->status() == - DeviceCertificateStatus::STATUS_TEST_ONLY) && - !allow_test_only_devices_) { - if (IsTestOnlyDeviceAllowedByMake(client_cert.system_id(), make) && - IsTestOnlyDeviceAllowedByProvider(client_cert.system_id(), provider)) { - LOG(WARNING) << "Allowing TEST_ONLY device with systemId = " - << client_cert.system_id() << ", make = " << make - << ", provider = " << provider << ", device info = " - << device_cert_status->device_info().ShortDebugString(); - } else { - VLOG(2) << "Not allowing TEST ONLY device with systemId = " - << client_cert.system_id() << ", provider = " << provider - << ", device info = " - << device_cert_status->device_info().ShortDebugString(); - return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, - "test-only-drm-certificate-not-allowed"); - } - } - if (!client_cert.signed_by_provisioner() && - (client_cert.signer_serial_number() != - device_cert_status->drm_serial_number())) { - // Widevine-provisioned device, and the intermediate certificate serial - // number does not match that in the status list. If the status list is - // newer than the certificate, indicate an invalid certificate, so that - // the device re-provisions. If, on the other hand, the certificate status - // list is older than the certificate, the certificate is for all purposes - // unknown. - if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "intermediate-certificate-serial-number-mismatch"); - } - return client_cert.SystemIdUnknownError(); - } - return OkStatus(); -} - -bool DeviceStatusList::GetDeviceInfo(const ClientCert& client_cert, - ProvisionedDeviceInfo* device_info) { - CHECK(device_info); - absl::ReaderMutexLock lock(&status_map_lock_); - DeviceCertificateStatus* device_cert_status = - gtl::FindOrNull(device_status_map_, client_cert.system_id()); - if (device_cert_status != nullptr) { - *device_info = device_cert_status->device_info(); - return true; - } - return false; -} - -bool DeviceStatusList::GetRevokedIdentifiers( - uint32_t system_id, - DeviceCertificateStatus::RevokedIdentifiers* revoked_identifiers) { - CHECK(revoked_identifiers); - absl::ReaderMutexLock lock(&status_map_lock_); - DeviceCertificateStatus* device_cert_status = - gtl::FindOrNull(device_status_map_, system_id); - if (device_cert_status) { - *revoked_identifiers = device_cert_status->revoked_identifiers(); - return true; - } - return false; -} - -bool DeviceStatusList::IsSystemIdActive(uint32_t system_id) { - absl::ReaderMutexLock lock(&status_map_lock_); - DeviceCertificateStatus* device_cert_status = - gtl::FindOrNull(device_status_map_, system_id); - if (!device_cert_status) { - return allow_unknown_devices_ || - KeyboxClientCert::IsSystemIdKnown(system_id); - } - if (device_cert_status->status() == - DeviceCertificateStatus::STATUS_TEST_ONLY) { - return allow_test_only_devices_; - } - if (device_cert_status) { - ProvisionedDeviceInfo device_info = device_cert_status->device_info(); - if (device_cert_status->status() == - DeviceCertificateStatus::STATUS_REVOKED) { - if (IsRevokedSystemIdAllowed(system_id)) { - LOG(WARNING) << "REVOKED system_id: " << system_id - << " is allowed to be active"; - return true; - } - } - } - return device_cert_status->status() != - DeviceCertificateStatus::STATUS_REVOKED; -} - -uint32_t DeviceStatusList::GetCurrentTime() const { return time(nullptr); } - -void DeviceStatusList::AllowRevokedDevices(const std::string& system_id_list) { - for (absl::string_view sp : absl::StrSplit(system_id_list, ',')) { - allowed_revoked_devices_.push_back(std::stoi(std::string(sp))); - } - std::sort(allowed_revoked_devices_.begin(), allowed_revoked_devices_.end()); -} - -void DeviceStatusList::AllowTestOnlyDevicesByMake( - const std::string& device_list_by_make) { - absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_); - if (device_list_by_make.empty()) { - allowed_test_only_devices_by_make_.clear(); - return; - } - for (absl::string_view device : absl::StrSplit(device_list_by_make, ',')) { - const std::pair device_split = - absl::StrSplit(device, ':'); - if (device_split.second.empty() || device_split.second == "*") { - allowed_test_only_devices_by_make_.emplace( - std::stoi(std::string(device_split.first)), "*"); - VLOG(2) << "Allowing TEST_ONLY device: systemId = " - << std::stoi(std::string(device_split.first)) << ", make *"; - } else { - allowed_test_only_devices_by_make_.emplace( - std::stoi(std::string(device_split.first)), - absl::AsciiStrToUpper(device_split.second)); - VLOG(2) << "Allowing TEST_ONLY device: systemId = " - << std::stoi(std::string(device_split.first)) - << ", make = " << absl::AsciiStrToUpper(device_split.second); - } - } -} - -void DeviceStatusList::AllowTestOnlyDevicesByProvider( - const std::string& device_list_by_provider) { - absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_); - if (device_list_by_provider.empty()) { - allowed_test_only_devices_by_provider_.clear(); - return; - } - for (absl::string_view device : - absl::StrSplit(device_list_by_provider, ',')) { - const std::pair device_split = - absl::StrSplit(device, ':'); - if (device_split.second.empty() || device_split.second == "*") { - allowed_test_only_devices_by_provider_.emplace( - std::stoi(std::string(device_split.first)), "*"); - VLOG(2) << "Allowing TEST_ONLY device: systemId = " - << std::stoi(std::string(device_split.first)) << ", provider *"; - } else { - allowed_test_only_devices_by_provider_.emplace( - std::stoi(std::string(device_split.first)), - absl::AsciiStrToUpper(device_split.second)); - VLOG(2) << "Allowing TEST_ONLY device: systemId = " - << std::stoi(std::string(device_split.first)) - << ", provider = " << absl::AsciiStrToUpper(device_split.second); - } - } -} - -bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) { - auto it = std::binary_search(allowed_revoked_devices_.begin(), - allowed_revoked_devices_.end(), system_id); - return it; -} - -bool DeviceStatusList::IsTestOnlyDeviceAllowedByMake( - uint32_t system_id, const std::string& manufacturer) { - absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_); - std::pair::iterator, - std::multimap::iterator> - allowed_makes = allowed_test_only_devices_by_make_.equal_range(system_id); - for (auto it = allowed_makes.first; it != allowed_makes.second; ++it) { - std::string allowed_makes = (*it).second; - if (allowed_makes == "*" || - allowed_makes == absl::AsciiStrToUpper(manufacturer)) { - return true; - } - } - return false; -} - -bool DeviceStatusList::IsTestOnlyDeviceAllowedByProvider( - uint32_t system_id, const std::string& provider) { - absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_); - std::pair::iterator, - std::multimap::iterator> - allowed_providers = - allowed_test_only_devices_by_provider_.equal_range(system_id); - for (auto it = allowed_providers.first; it != allowed_providers.second; - ++it) { - std::string allowed_provider = (*it).second; - if (allowed_provider == "*" || - allowed_provider == absl::AsciiStrToUpper(provider)) { - return true; - } - } - return false; -} - -Status DeviceStatusList::DetermineAndDeserializeServiceResponse( - const std::string& service_response, - DeviceCertificateStatusList* certificate_status_list, - std::string* serialized_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature) { - if (certificate_status_list == nullptr) { - return Status(error_space, error::INVALID_ARGUMENT, - "certificate_status_list is empty"); - } else if (serialized_certificate_status_list == nullptr) { - return Status(error_space, error::INVALID_ARGUMENT, - "serialized_certificate_status_list is empty"); - } else if (signature == nullptr) { - return Status(error_space, error::INVALID_ARGUMENT, "signature is empty"); - } - - // We support three types of payload parsing. The legacy path checks for a - // JSON encoded payload as well as just a plain base64 (web safe or normal) - // payload. If that doesn't match, then the method will try to parse the - // serialized PublishedDeviceInfo proto. - Status status = ExtractPublishedDevicesInfo( - service_response, serialized_certificate_status_list, hash_algorithm, - signature); - - // If the payload was not correctly parsed as a PublishedDevices proto. - // then attempt to parse it as a legacy payload. - if (!status.ok()) { - status = ExtractLegacyDeviceList(service_response, - serialized_certificate_status_list, - hash_algorithm, signature); - // The payload could not be parsed in either format, return the failure - // information. - if (!status.ok()) { - return status; - } - } - - if (!certificate_status_list->ParseFromString( - *serialized_certificate_status_list)) { - return Status(error_space, widevine::INVALID_CERTIFICATE_STATUS_LIST, - "certificate-status-list-parse-error"); - } - return OkStatus(); -} - -Status DeviceStatusList::ExtractLegacyDeviceList( - const std::string& raw_certificate_provisioning_service_response, - std::string* serialized_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature) { - // First, attempt to extract the legacy JSON response. Example legacy format. - // "signedList":"" - // where the b64 encoded data is a DeviceCertificateStatusListResponse. - size_t b64_list_response_start = - raw_certificate_provisioning_service_response.find(kSignedList); - std::string serialized_signed_certificate_status_list; - if (b64_list_response_start != std::string::npos) { - size_t b64_list_response_end = - raw_certificate_provisioning_service_response.find( - kSignedListTerminator, b64_list_response_start); - if (b64_list_response_end == std::string::npos) { - return Status( - error_space, error::INVALID_ARGUMENT, - "Unable to parse the certificate_provisioning_service_response. " - "SignedList not terminated."); - } - std::string signed_list( - raw_certificate_provisioning_service_response.begin() + - b64_list_response_start + kSignedListLen, - raw_certificate_provisioning_service_response.begin() + - b64_list_response_end); - - // Strip off quotes. - signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\"'), - signed_list.end()); - // Strip off spaces. - signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), ' '), - signed_list.end()); - - // Strip off newlines. - signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\n'), - signed_list.end()); - - // Strip off carriage return (the control-M character) - signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\r'), - signed_list.end()); - if (!absl::WebSafeBase64Unescape( - signed_list, &serialized_signed_certificate_status_list)) { - if (!absl::Base64Unescape(signed_list, - &serialized_signed_certificate_status_list)) { - return Status(error_space, error::INVALID_ARGUMENT, - "Base64 decode of signedlist failed."); - } - } - } else { - // If this was not a legacy JSON response, attempt to deserialize the base64 - // response. - if (!absl::WebSafeBase64Unescape( - raw_certificate_provisioning_service_response, - &serialized_signed_certificate_status_list)) { - if (!absl::Base64Unescape(raw_certificate_provisioning_service_response, - &serialized_signed_certificate_status_list)) { - return Status(error_space, error::INVALID_ARGUMENT, - "Base64 decode of certList failed."); - } - } - } - - // Attempt to parse the legacy serialized signed status list into the proto - // and extract the serialized status list and signature. - return ParseLegacySignedDeviceCertificateStatusList( - serialized_signed_certificate_status_list, - serialized_certificate_status_list, hash_algorithm, signature); -} - -Status DeviceStatusList::ExtractPublishedDevicesInfo( - const std::string& serialized_published_devices, - std::string* serialized_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature) { - // TODO(b/139067045): Change from using the SignedDeviceInfo proto - // to using the correct proto from the API. This duplicate, wire-compatible - // proto was a temporary way to workaround Proto2/Proto3 compatibility issues. - SignedDeviceInfo devices_info; - if (!devices_info.ParseFromString(serialized_published_devices)) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "published-devices-info-parse-error"); - } - *serialized_certificate_status_list = - devices_info.device_certificate_status_list(); - *hash_algorithm = HashAlgorithmProtoToEnum(devices_info.hash_algorithm()); - *signature = devices_info.signature(); - return OkStatus(); -} - -Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( - const std::string& version, - const std::string& serialized_service_certificate, - std::string* signed_device_certificate_status_list_request) { - if (version.empty()) { - return Status(error_space, error::INVALID_ARGUMENT, "SDK version is empty"); - } - DCHECK(signed_device_certificate_status_list_request); - if (signed_device_certificate_status_list_request == nullptr) { - return Status(error_space, error::INVALID_ARGUMENT, - "Signed_device_certificate_status_list_request is empty"); - } - // Construct SignedDeviceCertificateStatusListRequest. - DeviceCertificateStatusListRequest request; - request.set_sdk_version(version); - request.set_sdk_time_seconds(DeviceStatusList::Instance()->GetCurrentTime()); - request.set_service_certificate(serialized_service_certificate); - std::string device_certificate_status_list_request; - request.SerializeToString(&device_certificate_status_list_request); - SignedDeviceInfoRequest signed_request; - signed_request.set_device_certificate_status_list_request( - device_certificate_status_list_request); - const DrmServiceCertificate* sc = - DrmServiceCertificate::GetDefaultDrmServiceCertificate(); - if (sc == nullptr) { - signed_device_certificate_status_list_request->clear(); - return Status(error_space, widevine::SERVICE_CERTIFICATE_NOT_FOUND, - "Drm service certificate is not loaded."); - } - const RsaPrivateKey* private_key = sc->private_key(); - if (private_key == nullptr) { - return Status(error_space, widevine::INVALID_SERVICE_PRIVATE_KEY, - "Private key in the service certificate is null."); - } - std::string signature; - private_key->GenerateSignature(device_certificate_status_list_request, - &signature); - signed_request.set_signature(signature); - signed_request.SerializeToString( - signed_device_certificate_status_list_request); - return OkStatus(); -} - -Status DeviceStatusList::ParseLegacySignedDeviceCertificateStatusList( - const std::string& serialized_signed_device_certificate_status_list, - std::string* serialized_device_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature) { - // Parse the serialized_signed_device_certificate_status_list to extract the - // serialized_device_certificate_status_list - SignedDeviceCertificateStatusList signed_device_list; - if (!signed_device_list.ParseFromString( - serialized_signed_device_certificate_status_list)) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "signed-certificate-status-list-parse-error"); - } - if (signed_device_list.certificate_status_list().empty()) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list"); - } - if (signed_device_list.signature().empty()) { - return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list-signature"); - } - *serialized_device_certificate_status_list = - signed_device_list.certificate_status_list(); - *hash_algorithm = - HashAlgorithmProtoToEnum(signed_device_list.hash_algorithm()); - *signature = signed_device_list.signature(); - return OkStatus(); -} - -void DeviceStatusList::RevokedDrmCertificateSerialNumbers( - const std::string& drm_certificate_serial_numbers) { - for (absl::string_view drm_certificate_serial_number : - absl::StrSplit(drm_certificate_serial_numbers, ',')) { - revoked_drm_certificate_serial_numbers_.insert( - std::string(drm_certificate_serial_number)); - } -} - -bool DeviceStatusList::IsDrmCertificateRevoked( - const std::string& device_certificate_serial_number) { - if (revoked_drm_certificate_serial_numbers_.find( - device_certificate_serial_number) != - revoked_drm_certificate_serial_numbers_.end()) { - return true; - } - return false; -} - -Status DeviceStatusList::GetDeviceCertificateStatusBySystemId( - uint32_t system_id, DeviceCertificateStatus* device_certificate_status) { - absl::ReaderMutexLock lock(&status_map_lock_); - if (expiration_period_seconds_ && - (GetCurrentTime() > - (creation_time_seconds_ + expiration_period_seconds_))) { - return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, - "certificate-status-list-expired"); - } - DeviceCertificateStatus* device_cert_status = - gtl::FindOrNull(device_status_map_, system_id); - if (device_cert_status == nullptr) { - return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, - "device-certificate-status-unknown"); - } else { - *device_certificate_status = *device_cert_status; - } - return OkStatus(); -} - -} // namespace widevine diff --git a/common/device_status_list.h b/common/device_status_list.h deleted file mode 100644 index 7607d7f..0000000 --- a/common/device_status_list.h +++ /dev/null @@ -1,279 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -// DeviceStatusList class header. - -#ifndef COMMON_DEVICE_STATUS_LIST_H__ -#define COMMON_DEVICE_STATUS_LIST_H__ - -#include -#include -#include - -#include "absl/synchronization/mutex.h" -#include "common/hash_algorithm.h" -#include "common/status.h" -#include "protos/public/device_certificate_status.pb.h" -#include "protos/public/provisioned_device_info.pb.h" - -namespace widevine { - -class ClientCert; -// Manages the certificate status of devices. The list of -// DeviceCertificateStatus is provided by the DRM server. Each license -// request is checked to ensure the certificate in the request is valid and -// not revoked. Also checks to see if the intermediate certificates were -// updated where the system Id is the same, but the serial number changes. -// This case should cause the clients to re-provision. -class DeviceStatusList { - public: - // Returns a pointer to a singleton DeviceStatusList. - static DeviceStatusList* Instance(); - - DeviceStatusList(); - - DeviceStatusList(const DeviceStatusList&) = delete; - DeviceStatusList& operator=(const DeviceStatusList&) = delete; - - virtual ~DeviceStatusList(); - - // Takes |serialized_device_certificate_status_list| and copies to an - // internal map of device certificate status list. The internal map is used - // to verify a device was not revoked. Returns true is the list was - // successfully parsed. - Status UpdateStatusList( - const std::string& root_certificate_public_key, - const std::string& serialized_device_certificate_status_list, - HashAlgorithm hash_algorithm, const std::string& signature, - uint32_t expiration_period_seconds); - void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; } - bool allow_unknown_devices() const { return allow_unknown_devices_; } - void set_allow_test_only_devices(bool allow) { - allow_test_only_devices_ = allow; - } - bool allow_test_only_devices() const { return allow_test_only_devices_; } - - // Checks the device status list and handles the case when a TEST_ONLY device - // made the request. Returns one of - // OK - // UNSUPPORTED_SYSTEM_ID - // INVALID_DRM_CERTIFICATE - // DRM_DEVICE_CERTIFICATE_REVOKED - // DRM_DEVICE_CERTIFICATE_UNKNOWN - // DEVELOPMENT_CERTIFICATE_NOT_ALLOWED - // |provider| is the service provider making the license request. - // If status is OK, a copy of the device certificate status is copied - // into |device_certificate_status|. Caller owns |device_certificate_status| - // and it must not be null. - Status GetCertStatus( - const ClientCert& client_cert, const std::string& make, - const std::string& provider, bool allow_revoked_system_id, - widevine::DeviceCertificateStatus* device_certificate_status); - // Returns true if the pre-provisioning key or certificate for the specified - // system ID are active (not disallowed or revoked). - bool IsSystemIdActive(uint32_t system_id); - - // Returns true if the system ID - // Returns true is a ProvisionedDeviceInfo exist based on . - // Caller owns and it must not be null. - bool GetDeviceInfo(const ClientCert& client_cert, - widevine::ProvisionedDeviceInfo* device_info); - - // Returns true if device certificate status list contains revoked_identifiers - // with specific |system_id|. - // Caller owns and it must not be null. - bool GetRevokedIdentifiers( - uint32_t system_id, - DeviceCertificateStatus::RevokedIdentifiers* revoked_identifiers); - - // Returns the current POSIX time. - virtual uint32_t GetCurrentTime() const; - - // Enable delivery of licenses to revoked client devices. |system_id_list| is - // a comma separated list of systems Ids to allow even if revoked. - virtual void AllowRevokedDevices(const std::string& system_id_list); - - // Enable delivery of licenses to TEST_ONLY client devices. |device_list| is - // a comma separated list of devices to allow even if the device state is - // TEST_ONLY. Each device is specified by a colon separated system_id and - // manufacturer. If the manufacturer is not specified, all manufacturers for - // that system_id are allowed. - // 'device_list' is expected to be of the format ,..., and - // each 'device' will contain a 'system_id' and 'manufacturer' OR will contain - // only a 'system_id'. - // 'device' is expected to be of the format : OR - // of the format : - // Example usage: - // const std::string device_list = "4121:LG,7912:*" - // AllowTestOnlyDevicesByMake(device_list_by_make); - virtual void AllowTestOnlyDevicesByMake( - const std::string& device_list_by_make); - - // Same as above, except by providers instead of by manufacturers. - // Example usage: - // const std::string device_list = "4121:YouTube,4121:AndroidVideo" - // AllowTestOnlyDevicesByProvider(device_list); - virtual void AllowTestOnlyDevicesByProvider( - const std::string& device_list_by_provider); - - // A comma separated list of DRM Certificate Serial Numbers that are revoked. - virtual void RevokedDrmCertificateSerialNumbers( - const std::string& drm_certificate_serial_numbers); - - // Return true, if the specified |device_certificate_serial_number| was - // revoked ... else, false. - bool IsDrmCertificateRevoked( - const std::string& device_certificate_serial_number); - - // Returns OK if |system_id| was found in the device certificate status list - // and |device_certificate_status| is populated. If |system_id| is not found, - // this call returns an error. - virtual Status GetDeviceCertificateStatusBySystemId( - uint32_t system_id, DeviceCertificateStatus* device_certificate_status); - - // Parses the serialized certificate status list and the signature from the - // service_response. The service_response is the JSON payload that comes - // in the response to a certificate status list request. Both the legacy - // format and the newer SignedDeviceInfo format are supported. - // - // |service_response| is the response provided from the Widevine API that - // produces the certificate list. The response can be in one of a few - // formats: - // 1) The JSON response from the legacy API. - // 2) The Base 64 encoded payload within the JSON response that contains - // the serialized certificate list (Web safe or regular base64). - // 3) The raw bytes of the serialized PublishedDevices proto returned from - // the new Widevine API that generates the serialized certificate list. - // The |certificate_status_list| is the deserialized list from the - // service_response. - // The |serialized_certificate_status_list| is the binary serialized status - // list. This is an out parameter which allows the caller to verify the - // serialized proto against the |signature|. - // The |signature| is the signature of the serialized_certificate_status_list - // using RSASSA-PSS signed with the root certificate private key. - // The |hash_algorithm| is the hash algorithm used in signature. - // Returns WvPLStatus - Status::OK if success, else error. - static Status DetermineAndDeserializeServiceResponse( - const std::string& service_response, - DeviceCertificateStatusList* certificate_status_list, - std::string* serialized_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature); - - /** - * Constructs signed device certificate status list request string. - * - * @param signed_device_certificate_status_list_request - * @param version - * @return Status - Status::OK if success, else error. - */ - static Status GenerateSignedDeviceCertificateStatusListRequest( - const std::string& version, - const std::string& serialized_service_certificate, - std::string* signed_device_certificate_status_list_request); - - // Returns true if the system ID is allowed to be revoked. - // Caller owns |system_id|. They must not be null. - bool IsRevokedSystemIdAllowed(uint32_t system_id); - - // Returns true if the device, which is identified by system_id and - // device_manufacturer, is present in |allowed_test_only_devices_by_make_|. - bool IsTestOnlyDeviceAllowedByMake(uint32_t system_id, - const std::string& device_manufacturer); - - // Returns true if the device, which is identified by system_id and - // provider, is present in |allowed_test_only_devices_by_provider_|. - bool IsTestOnlyDeviceAllowedByProvider(uint32_t system_id, - const std::string& provider); - - private: - friend class DeviceStatusListTest; - - /** - * Parses the serialized legacy device certificate status list and signature. - * The certificate_provisioning_service_response is the JSON payload that - * comes in the response to a certificate status list request. - * - * @param legacy_certificate_provisioning_service_response - * @param serialized_certificate_status_list - * @param hash_algorithm - * @param signature - * @return WvPLStatus - Status::OK if success, else error. - */ - static Status ExtractLegacyDeviceList( - const std::string& raw_certificate_provisioning_service_response, - std::string* serialized_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature); - - /** - * Parses the serialized published devices response. - * The published_devices_info_response is the JSON payload that comes in the - * response to a PublishedDevices request. - * - * @param published_devices_response the serialized PublishedDevices proto - * containing the certificate status list. - * @param serialized_certificate_status_list - * @param hash_algorithm - * @param signature - * @return WvPLStatus - Status::OK if success, else error. - */ - static Status ExtractPublishedDevicesInfo( - const std::string& serialized_published_devices, - std::string* serialized_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature); - - /** - * Returns a |serialized_device_certificate_status_list| in its output - * parameter by parsing |serialized_signed_device_certificate_status_list| - * returned from Widevine Certificate Provisioning Server. - * - * @param serialized_signed_device_certificate_status_list - * @param serialized_device_certificate_status_list - * @param hash_algorithm - * @return Status - Status::OK if success, else error. - */ - static Status ParseLegacySignedDeviceCertificateStatusList( - const std::string& serialized_signed_device_certificate_status_list, - std::string* serialized_device_certificate_status_list, - HashAlgorithm* hash_algorithm, std::string* signature); - - virtual size_t allowed_test_only_devices_by_make_size() { - absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_); - return allowed_test_only_devices_by_make_.size(); - } - - virtual size_t allowed_test_only_devices_by_provider_size() { - absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_); - return allowed_test_only_devices_by_provider_.size(); - } - - mutable absl::Mutex status_map_lock_; - // Key is the system id for the device. - std::map device_status_map_ - ABSL_GUARDED_BY(status_map_lock_); - uint32_t creation_time_seconds_ = 0; - uint32_t expiration_period_seconds_ = 0; - bool allow_unknown_devices_ = false; - bool allow_test_only_devices_ = false; - // Contains the list of system_id values that are allowed to succeed even if - // revoked. - std::vector allowed_revoked_devices_; - mutable absl::Mutex allowed_test_only_devices_mutex_; - // Contains a map of 'system_id' to 'manufacturer'. If manufacturer value is - // "*", any manufacturer using that system_id is allowed. - std::multimap allowed_test_only_devices_by_make_ - ABSL_GUARDED_BY(allowed_test_only_devices_mutex_); - // Contains a map of 'system_id' to 'provider'. If provider value is "*", any - // provider using that system_id is allowed. - std::multimap allowed_test_only_devices_by_provider_ - ABSL_GUARDED_BY(allowed_test_only_devices_mutex_); - // Revoked DRM certificate serial numbers. - std::set revoked_drm_certificate_serial_numbers_; -}; - -} // namespace widevine -#endif // COMMON_DEVICE_STATUS_LIST_H__ diff --git a/common/device_status_list_test.cc b/common/device_status_list_test.cc deleted file mode 100644 index 6ab8032..0000000 --- a/common/device_status_list_test.cc +++ /dev/null @@ -1,918 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/device_status_list.h" - -#include - -#include -#include -#include - -#include "glog/logging.h" -#include "google/protobuf/util/message_differencer.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "common/client_cert.h" -#include "common/hash_algorithm.h" -#include "common/hash_algorithm_util.h" -#include "common/keybox_client_cert.h" -#include "common/rsa_key.h" -#include "common/rsa_test_keys.h" -#include "common/status.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/device_certificate_status.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/provisioned_device_info.pb.h" -#include "protos/public/signed_device_info.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace { -const char kTestSystemId_1[] = "4121"; -const char kTestSystemId_2[] = "8242"; -const char kTestSystemId_3[] = "6556"; -const char kTestManufacturer[] = "TestManufacturer"; -const char kTestProvider[] = "TestProvider"; -const char kRevokedManufacturer[] = "RevokedManufacturer"; -const widevine::HashAlgorithm kHashAlgorithm = - widevine::HashAlgorithm::kSha256; -} // namespace - -namespace widevine { - -using ::testing::Return; -using ::testing::ReturnRef; - -const uint32_t kValidCertSystemId = 100; -const uint32_t kRevokedCertSystemId = 101; -const uint32_t kValidPpkSystemId = 102; -const uint32_t kTestOnlyCertSystemId = 103; -const uint32_t kRevokedAllowedDeviceCertSystemId = 104; -const uint32_t kUnknownSystemId = 666; -const char kValidSerialNumber[] = "valid-serial-number"; -const char kRevokedSerialNumber[] = "revoked-serial-number"; -const char kRevokedAllowDeviceSerialNumber[] = - "revoked-allow-device-serial-number"; -const char kRevokedDeviceCertificateSerialNumber1[] = "revoked-serial-number_1"; -const char kRevokedDeviceCertificateSerialNumber2[] = "revoked-serial-number_2"; -const char kRevokedDeviceCertificateSerialNumber3[] = "revoked-serial-number_3"; -const char kRevokedUniqueIdentifiers[] = "revoked-unique-identifiers"; -const char kTestOnlySerialNumber[] = "test_only-serial-number"; -const char kMismatchSerialNumber[] = "mismatch-serial-number"; -const char kDeviceModel[] = "device-model-x"; -const char kRevokedDeviceModel[] = "device-model-revoked"; -const char kTestPreprovKey[] = "00112233445566778899aabbccddeeff"; -const uint32_t kStatusListCreationTime = 17798001; -const uint32_t kDefaultExpirePeriod = 0; -const bool kDenyRevokedDevice = false; -const bool kAllowRevokedDevice = true; - -class MockClientCert : public ClientCert { - public: - MockClientCert() {} - ~MockClientCert() override {} - MOCK_METHOD(uint32_t, system_id, (), (const, override)); - MOCK_METHOD(std::string &, signer_serial_number, (), (const, override)); - MOCK_METHOD(uint32_t, signer_creation_time_seconds, (), (const, override)); - MOCK_METHOD(ClientIdentification::TokenType, type, (), (const, override)); - MOCK_METHOD(const std::string &, encrypted_unique_id, (), (const, override)); - MOCK_METHOD(const std::string &, unique_id_hash, (), (const, override)); - MOCK_METHOD(bool, signed_by_provisioner, (), (const, override)); - MOCK_METHOD(Status, VerifySignature, - (const std::string &message, HashAlgorithm hash_algorithm, - const std::string &signature, ProtocolVersion protocol_version), - (const, override)); - MOCK_METHOD(void, GenerateSigningKey, - (const std::string &message, ProtocolVersion protocol_version), - (override)); - MOCK_METHOD(const std::string &, serial_number, (), (const, override)); - MOCK_METHOD(const std::string &, key, (), (const, override)); - MOCK_METHOD(SignedMessage::SessionKeyType, key_type, (), (const, override)); - MOCK_METHOD(bool, using_dual_certificate, (), (const override)); - MOCK_METHOD(const std::string &, service_id, (), (const, override)); - MOCK_METHOD(const std::string &, encrypted_key, (), (const, override)); - MOCK_METHOD(const std::string &, signing_key, (), (const, override)); - MOCK_METHOD(Status, SystemIdUnknownError, (), (const, override)); - MOCK_METHOD(Status, SystemIdRevokedError, (), (const, override)); -}; - -class DeviceStatusListTest : public ::testing::Test { - public: - ~DeviceStatusListTest() override {} - - void SetUp() override { - DeviceCertificateStatus *cert_status; - - // Device cert with status RELEASED. - cert_status = cert_status_list_.add_certificate_status(); - cert_status->mutable_device_info()->set_system_id(kValidCertSystemId); - cert_status->set_drm_serial_number(kValidSerialNumber); - cert_status->mutable_device_info()->set_model(kDeviceModel); - cert_status->set_status(DeviceCertificateStatus::STATUS_RELEASED); - cert_status->mutable_revoked_identifiers()->add_revoked_unique_id_hashes( - kRevokedUniqueIdentifiers); - cert_status->mutable_revoked_identifiers() - ->add_revoked_certificate_serial_numbers(kRevokedSerialNumber); - - // Device cert with status REVOKED. - cert_status = cert_status_list_.add_certificate_status(); - cert_status->mutable_device_info()->set_system_id(kRevokedCertSystemId); - cert_status->set_drm_serial_number(kRevokedSerialNumber); - cert_status->mutable_device_info()->set_model(kRevokedDeviceModel); - cert_status->set_status(DeviceCertificateStatus::STATUS_REVOKED); - - // Device cert with status REVOKED ALLOWED DEVICE. - cert_status = cert_status_list_.add_certificate_status(); - cert_status->mutable_device_info()->set_system_id( - kRevokedAllowedDeviceCertSystemId); - cert_status->set_drm_serial_number(kRevokedAllowDeviceSerialNumber); - cert_status->set_status(DeviceCertificateStatus::STATUS_REVOKED); - device_status_list_.AllowRevokedDevices( - absl::StrCat(kRevokedAllowedDeviceCertSystemId)); - - // Device cert with status TEST_ONLY. - cert_status = cert_status_list_.add_certificate_status(); - cert_status->mutable_device_info()->set_system_id(kTestOnlyCertSystemId); - cert_status->set_drm_serial_number(kTestOnlySerialNumber); - cert_status->set_status(DeviceCertificateStatus::STATUS_TEST_ONLY); - - cert_status_list_.set_creation_time_seconds(kStatusListCreationTime); - - // Generate the serialized list and signature. - std::unique_ptr root_key( - RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())); - ASSERT_TRUE(root_key); - cert_status_list_.SerializeToString(&serialized_cert_status_list_); - ASSERT_TRUE(root_key->GenerateSignature(serialized_cert_status_list_, - kHashAlgorithm, - &cert_status_list_signature_)); - - // Update the device_status_list_ with the serialized status list - // and signature. - ASSERT_EQ(OkStatus(), - device_status_list_.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, kDefaultExpirePeriod)); - } - - void GenerateTrivialValidStatusList(std::string *serialized_cert_status_list, - HashAlgorithm hash_algorithm, - std::string *signature) { - DeviceCertificateStatusList cert_status_list; - DeviceCertificateStatus *cert_status; - - // Device cert with status RELEASED. - cert_status = cert_status_list.add_certificate_status(); - cert_status->mutable_device_info()->set_system_id(kValidCertSystemId); - cert_status->set_drm_serial_number(kValidSerialNumber); - cert_status->mutable_device_info()->set_model(kDeviceModel); - cert_status->set_status(DeviceCertificateStatus::STATUS_RELEASED); - - cert_status_list.set_creation_time_seconds(kStatusListCreationTime); - - // Generate the serialized list and signature. - std::unique_ptr root_key( - RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())); - ASSERT_TRUE(root_key); - cert_status_list.SerializeToString(serialized_cert_status_list); - ASSERT_TRUE(root_key->GenerateSignature(*serialized_cert_status_list, - hash_algorithm, signature)); - } - - int AllowedTestOnlyDevicesByMakeSize() { - return device_status_list_.allowed_test_only_devices_by_make_size(); - } - - int AllowedTestOnlyDevicesByProviderSize() { - return device_status_list_.allowed_test_only_devices_by_provider_size(); - } - - bool IsTestOnlyDeviceAllowedByMake(uint32_t system_id, - const std::string &make) { - return device_status_list_.IsTestOnlyDeviceAllowedByMake(system_id, make); - } - - bool IsTestOnlyDeviceAllowedByProvider(uint32_t system_id, - const std::string &provider) { - return device_status_list_.IsTestOnlyDeviceAllowedByProvider(system_id, - provider); - } - - int VerifyRevokedDeviceCertificatesCount() { - return device_status_list_.revoked_drm_certificate_serial_numbers_.size(); - } - - bool VerifyIsDeviceCertificateRevoked( - std::string device_certificate_serial_number) { - return device_status_list_.IsDrmCertificateRevoked( - device_certificate_serial_number); - } - - DeviceStatusList device_status_list_; - RsaTestKeys test_keys_; - DeviceCertificateStatusList cert_status_list_; - std::string serialized_cert_status_list_; - std::string cert_status_list_signature_; -}; - -TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) { - // Test case where the Certificate status is set to Valid. - DeviceCertificateStatus device_certificate_status; - MockClientCert valid_client_cert; - std::string valid_drm_serial_number(kValidSerialNumber); - EXPECT_CALL(valid_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(valid_client_cert, system_id()) - .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_CALL(valid_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(valid_drm_serial_number)); - EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus( - valid_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status)); - ProvisionedDeviceInfo device_info = device_certificate_status.device_info(); - EXPECT_TRUE(device_info.has_model()); - EXPECT_EQ(kDeviceModel, device_info.model()); - - // Test case where the Certificate status is Revoked. - MockClientCert revoked_client_cert; - std::string revoked_drm_serial_number(kRevokedSerialNumber); - EXPECT_CALL(revoked_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(revoked_client_cert, system_id()) - .WillRepeatedly(Return(kRevokedCertSystemId)); - EXPECT_CALL(revoked_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(revoked_drm_serial_number)); - EXPECT_CALL(revoked_client_cert, SystemIdRevokedError()) - .WillRepeatedly( - Return(Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, ""))); - EXPECT_EQ( - DRM_DEVICE_CERTIFICATE_REVOKED, - device_status_list_ - .GetCertStatus(revoked_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status) - .error_code()); - - // Test case where the revoked cert is allowed. - device_status_list_.AllowRevokedDevices(absl::StrCat(kRevokedCertSystemId)); - EXPECT_OK(device_status_list_.GetCertStatus( - revoked_client_cert, kTestManufacturer, kTestProvider, kDenyRevokedDevice, - &device_certificate_status)); -} - -TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) { - DeviceCertificateStatus device_certificate_status; - MockClientCert test_only_client_cert; - std::string test_only_drm_serial_number(kTestOnlySerialNumber); - EXPECT_CALL(test_only_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(test_only_client_cert, system_id()) - .WillRepeatedly(Return(kTestOnlyCertSystemId)); - EXPECT_CALL(test_only_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(test_only_drm_serial_number)); - EXPECT_EQ(DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, - device_status_list_ - .GetCertStatus(test_only_client_cert, kTestManufacturer, - kTestProvider, kDenyRevokedDevice, - &device_certificate_status) - .error_code()); -} - -TEST_F(DeviceStatusListTest, GetRevokedIfentifiers) { - DeviceCertificateStatus::RevokedIdentifiers revoked_identifiers; - ASSERT_TRUE(device_status_list_.GetRevokedIdentifiers(kValidCertSystemId, - &revoked_identifiers)); - EXPECT_EQ(kRevokedSerialNumber, - revoked_identifiers.revoked_certificate_serial_numbers(0)); - EXPECT_EQ(kRevokedUniqueIdentifiers, - revoked_identifiers.revoked_unique_id_hashes(0)); - ASSERT_FALSE(device_status_list_.GetRevokedIdentifiers(kUnknownSystemId, - &revoked_identifiers)); -} - -TEST_F(DeviceStatusListTest, TestOnlyCertAllowed) { - DeviceCertificateStatus device_certificate_status; - MockClientCert test_only_client_cert; - std::string test_only_drm_serial_number(kTestOnlySerialNumber); - device_status_list_.set_allow_test_only_devices(true); - EXPECT_CALL(test_only_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(test_only_client_cert, system_id()) - .WillRepeatedly(Return(kTestOnlyCertSystemId)); - EXPECT_CALL(test_only_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(test_only_drm_serial_number)); - EXPECT_EQ(OkStatus(), - device_status_list_.GetCertStatus( - test_only_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status)); -} - -TEST_F(DeviceStatusListTest, RevokedSystemIdAllowed) { - DeviceCertificateStatus device_certificate_status; - MockClientCert revoked_client_cert; - std::string revoked_drm_serial_number(kRevokedSerialNumber); - EXPECT_CALL(revoked_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(revoked_client_cert, system_id()) - .WillRepeatedly(Return(kRevokedCertSystemId)); - EXPECT_CALL(revoked_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(revoked_drm_serial_number)); - EXPECT_EQ(OkStatus(), - device_status_list_.GetCertStatus( - revoked_client_cert, kRevokedManufacturer, kTestProvider, - kAllowRevokedDevice, &device_certificate_status)); -} - -// Test case where the Certificate status is set to Valid. -TEST_F(DeviceStatusListTest, ValidKeybox) { - std::multimap preprov_keys; - preprov_keys.insert(std::make_pair(kValidCertSystemId, kTestPreprovKey)); - KeyboxClientCert::SetPreProvisioningKeys(preprov_keys); - DeviceCertificateStatus device_certificate_status; - MockClientCert valid_client_keybox; - - std::string valid_drm_serial_number(kValidSerialNumber); - EXPECT_CALL(valid_client_keybox, type()) - .WillRepeatedly(Return(ClientIdentification::KEYBOX)); - EXPECT_CALL(valid_client_keybox, system_id()) - .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_EQ(OkStatus(), - device_status_list_.GetCertStatus( - valid_client_keybox, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status)); - ProvisionedDeviceInfo device_info = device_certificate_status.device_info(); - ASSERT_TRUE(device_info.has_model()); - EXPECT_EQ(kDeviceModel, device_info.model()); -} - -// Test case where the keybox was not loaded into the pre-prov list. -TEST_F(DeviceStatusListTest, UnknownKeybox) { - std::multimap preprov_keys; - preprov_keys.insert(std::make_pair(kValidCertSystemId, kTestPreprovKey)); - KeyboxClientCert::SetPreProvisioningKeys(preprov_keys); - DeviceCertificateStatus device_certificate_status; - MockClientCert unknown_client_keybox; - - EXPECT_CALL(unknown_client_keybox, type()) - .WillRepeatedly(Return(ClientIdentification::KEYBOX)); - EXPECT_CALL(unknown_client_keybox, system_id()) - .WillRepeatedly(Return(kUnknownSystemId)); - EXPECT_CALL(unknown_client_keybox, SystemIdUnknownError()) - .WillRepeatedly(Return(Status(error_space, UNSUPPORTED_SYSTEM_ID, ""))); - EXPECT_EQ(UNSUPPORTED_SYSTEM_ID, - device_status_list_ - .GetCertStatus(unknown_client_keybox, kTestManufacturer, - kTestProvider, kDenyRevokedDevice, - &device_certificate_status) - .error_code()); - ProvisionedDeviceInfo device_info = device_certificate_status.device_info(); - ASSERT_FALSE(device_info.has_model()); -} - -// Test case where the keybox was loaded into the pre-prov list but it's -// certificate status is REVOKED. -TEST_F(DeviceStatusListTest, RevokedKeybox) { - std::multimap preprov_keys; - preprov_keys.insert(std::make_pair(kRevokedCertSystemId, kTestPreprovKey)); - KeyboxClientCert::SetPreProvisioningKeys(preprov_keys); - DeviceCertificateStatus device_certificate_status; - MockClientCert revoked_client_keybox; - - EXPECT_CALL(revoked_client_keybox, type()) - .WillRepeatedly(Return(ClientIdentification::KEYBOX)); - EXPECT_CALL(revoked_client_keybox, system_id()) - .WillRepeatedly(Return(kRevokedCertSystemId)); - EXPECT_CALL(revoked_client_keybox, SystemIdRevokedError()) - .WillRepeatedly( - Return(Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, ""))); - EXPECT_EQ(DRM_DEVICE_CERTIFICATE_REVOKED, - device_status_list_ - .GetCertStatus(revoked_client_keybox, kTestManufacturer, - kTestProvider, kDenyRevokedDevice, - &device_certificate_status) - .error_code()); - ProvisionedDeviceInfo device_info = device_certificate_status.device_info(); - ASSERT_TRUE(device_info.has_model()); - EXPECT_EQ(kRevokedDeviceModel, device_info.model()); -} - -TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) { - device_status_list_.set_allow_unknown_devices(true); - - // Test case where the signer certificate is older than the current status - // list. - MockClientCert older_client_cert; - DeviceCertificateStatus device_certificate_status; - std::string mismatch_drm_serial_number(kMismatchSerialNumber); - EXPECT_CALL(older_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(older_client_cert, system_id()) - .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_CALL(older_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(mismatch_drm_serial_number)); - EXPECT_CALL(older_client_cert, signer_creation_time_seconds()) - .WillRepeatedly(Return(kStatusListCreationTime - 1)); - EXPECT_EQ( - INVALID_DRM_CERTIFICATE, - device_status_list_ - .GetCertStatus(older_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status) - .error_code()); - - // We allow this case only for certs signed by a provisioner cert. - EXPECT_CALL(older_client_cert, signed_by_provisioner()) - .WillOnce(Return(true)); - EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus( - older_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status)); - ProvisionedDeviceInfo device_info = device_certificate_status.device_info(); - EXPECT_TRUE(device_info.has_system_id()); - EXPECT_EQ(kValidCertSystemId, device_info.system_id()); - - // Test case where the signer certificate is newer than the current status - // list, and unknown devices are allowed. - device_certificate_status.Clear(); - MockClientCert newer_client_cert1; - EXPECT_CALL(newer_client_cert1, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(newer_client_cert1, system_id()) - .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_CALL(newer_client_cert1, signer_serial_number()) - .WillRepeatedly(ReturnRef(mismatch_drm_serial_number)); - EXPECT_CALL(newer_client_cert1, signer_creation_time_seconds()) - .WillRepeatedly(Return(kStatusListCreationTime)); - EXPECT_CALL(newer_client_cert1, SystemIdUnknownError()) - .WillRepeatedly( - Return(Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, ""))); - EXPECT_EQ( - DRM_DEVICE_CERTIFICATE_UNKNOWN, - device_status_list_ - .GetCertStatus(newer_client_cert1, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status) - .error_code()); - - // Test case where the signer certificate is newer than the current status - // list, and unknown devices are not allowed. - device_certificate_status.Clear(); - device_status_list_.set_allow_unknown_devices(false); - MockClientCert newer_client_cert2; - EXPECT_CALL(newer_client_cert2, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(newer_client_cert2, system_id()) - .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_CALL(newer_client_cert2, signer_serial_number()) - .WillRepeatedly(ReturnRef(mismatch_drm_serial_number)); - EXPECT_CALL(newer_client_cert2, signer_creation_time_seconds()) - .WillRepeatedly(Return(kStatusListCreationTime + 1)); - EXPECT_CALL(newer_client_cert2, SystemIdUnknownError()) - .WillRepeatedly( - Return(Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, ""))); - EXPECT_EQ( - DRM_DEVICE_CERTIFICATE_UNKNOWN, - device_status_list_ - .GetCertStatus(newer_client_cert2, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status) - .error_code()); -} - -TEST_F(DeviceStatusListTest, InvalidStatusList) { - EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST, - device_status_list_ - .UpdateStatusList(test_keys_.public_test_key_2_2048_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, 0) - .error_code()); - - ++(serialized_cert_status_list_)[4]; - EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST, - device_status_list_ - .UpdateStatusList(test_keys_.public_test_key_1_3072_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, 0) - .error_code()); -} - -class MockDeviceStatusList : public DeviceStatusList { - public: - MOCK_METHOD(uint32_t, GetCurrentTime, (), (const, override)); -}; - -TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) { - MockDeviceStatusList mock_device_status_list; - EXPECT_CALL(mock_device_status_list, GetCurrentTime()) - .Times(2) - .WillOnce(Return(kStatusListCreationTime + 100)) - .WillOnce(Return(kStatusListCreationTime + 101)); - EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, 100)); - EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST, - mock_device_status_list - .UpdateStatusList(test_keys_.public_test_key_1_3072_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, 100) - .error_code()); -} - -TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) { - MockDeviceStatusList mock_device_status_list; - EXPECT_CALL(mock_device_status_list, GetCurrentTime()) - .Times(3) - .WillOnce(Return(kStatusListCreationTime + 100)) - .WillOnce(Return(kStatusListCreationTime + 100)) - .WillOnce(Return(kStatusListCreationTime + 101)); - EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, 100)); - - DeviceCertificateStatus device_certificate_status; - MockClientCert valid_client_cert; - std::string valid_drm_serial_number(kValidSerialNumber); - EXPECT_CALL(valid_client_cert, type()) - .WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE)); - EXPECT_CALL(valid_client_cert, system_id()) - .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_CALL(valid_client_cert, signer_serial_number()) - .WillRepeatedly(ReturnRef(valid_drm_serial_number)); - EXPECT_CALL(valid_client_cert, signer_creation_time_seconds()) - .WillRepeatedly(Return(kStatusListCreationTime - 1)); - EXPECT_EQ(OkStatus(), mock_device_status_list.GetCertStatus( - valid_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status)); - - EXPECT_EQ( - EXPIRED_CERTIFICATE_STATUS_LIST, - mock_device_status_list - .GetCertStatus(valid_client_cert, kTestManufacturer, kTestProvider, - kDenyRevokedDevice, &device_certificate_status) - .error_code()); -} - -TEST_F(DeviceStatusListTest, IsSystemIdActive) { - std::multimap preprov_keys; - preprov_keys.insert( - std::make_pair(kValidPpkSystemId, "00112233445566778899aabbccddeeff")); - KeyboxClientCert::SetPreProvisioningKeys(preprov_keys); - device_status_list_.set_allow_unknown_devices(false); - EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidCertSystemId)); - EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidPpkSystemId)); - EXPECT_FALSE(device_status_list_.IsSystemIdActive(kRevokedCertSystemId)); - EXPECT_FALSE(device_status_list_.IsSystemIdActive(kUnknownSystemId)); - device_status_list_.set_allow_unknown_devices(true); - EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidCertSystemId)); - EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidPpkSystemId)); - EXPECT_FALSE(device_status_list_.IsSystemIdActive(kRevokedCertSystemId)); - EXPECT_TRUE(device_status_list_.IsSystemIdActive(kUnknownSystemId)); - EXPECT_TRUE( - device_status_list_.IsSystemIdActive(kRevokedAllowedDeviceCertSystemId)); -} - -TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowedByMake) { - const char kTestManufacturer_AA[] = "AA"; - const char kTestManufacturer_AAA[] = "AAA"; - const char kTestManufacturer_BBB[] = "BBB"; - const char kTestManufacturer_BbB[] = "BbB"; - const char kTestManufacturer_bbb[] = "bbb"; - const char kTestManufacturer_CCC[] = "CCC"; - const char kTestManufacturer_DDD[] = "AAA"; - std::string allowed_device_list = - std::string(kTestSystemId_1) + ":" + std::string(kTestManufacturer_AA); - allowed_device_list += "," + std::string(kTestSystemId_2) + ":" + - std::string(kTestManufacturer_BBB); - allowed_device_list += "," + std::string(kTestSystemId_3) + ":"; - allowed_device_list += ", " + std::string(kTestSystemId_1) + ":" + - std::string(kTestManufacturer_AAA); - device_status_list_.AllowTestOnlyDevicesByMake(allowed_device_list); - EXPECT_EQ(4, AllowedTestOnlyDevicesByMakeSize()); - // Verify that device with system_id = kTestSystemId_1 and - // manufacturer AA is allowed. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_1), - kTestManufacturer_AA)); - // Verify that device with system_id = kTestSystemId_1 and - // manufacturer AAA is allowed. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_1), - kTestManufacturer_AAA)); - // Verify that device with system_id = kTestSystemId_2 and - // manufacturer AAA is not allowed. - // This is because this combination is not in the allowed list. - EXPECT_FALSE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2), - kTestManufacturer_AAA)); - // Verify that device with system_id = kTestSystemId_2 and - // manufacturer BBB is allowed. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2), - kTestManufacturer_BBB)); - // Verifes that device with mixed case succeeds. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2), - kTestManufacturer_BbB)); - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2), - kTestManufacturer_bbb)); - // Verify that device with system_id = kTestSystemId_3 and - // any manufacturer is allowed. This checks that any manufacturer is - // allowed for this system_id. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_3), - kTestManufacturer_CCC)); - EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_3), - kTestManufacturer_DDD)); - uint32_t unknown_system_id = 7890; - // Verify that device with system_id = unknown_system_id and - // manufacturer CCC is not allowed. - EXPECT_FALSE( - IsTestOnlyDeviceAllowedByMake(unknown_system_id, kTestManufacturer_CCC)); -} - -TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowedByProvider) { - const char kTestProvider_AA[] = "AA"; - const char kTestProvider_AAA[] = "AAA"; - const char kTestProvider_BBB[] = "BBB"; - const char kTestProvider_BbB[] = "BbB"; - const char kTestProvider_bbb[] = "bbb"; - const char kTestProvider_CCC[] = "CCC"; - std::string allowed_device_list = - std::string(kTestSystemId_1) + ":" + std::string(kTestProvider_AA); - allowed_device_list += - "," + std::string(kTestSystemId_2) + ":" + std::string(kTestProvider_BBB); - allowed_device_list += "," + std::string(kTestSystemId_3) + ":"; - allowed_device_list += ", " + std::string(kTestSystemId_1) + ":" + - std::string(kTestProvider_AAA); - device_status_list_.AllowTestOnlyDevicesByProvider(allowed_device_list); - EXPECT_EQ(4, AllowedTestOnlyDevicesByProviderSize()); - // Verify that device with system_id = kTestSystemId_1 and - // provider AA is allowed. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_1), - kTestProvider_AA)); - // Verify that device with system_id = kTestSystemId_1 and - // provider AAA is allowed. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_1), - kTestProvider_AAA)); - // Verify that device with system_id = kTestSystemId_2 and - // provider AAA is not allowed. - // This is because this combination is not 'whitelisted'. - EXPECT_FALSE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2), - kTestProvider_AAA)); - // Verify that device with system_id = kTestSystemId_2 and - // provider BBB is allowed. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2), - kTestProvider_BBB)); - // Verifes that device with mixed case succeeds. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2), - kTestProvider_BbB)); - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2), - kTestProvider_bbb)); - // Verify that device with system_id = kTestSystemId_3 and - // any provider is allowed. This checks that any provider is - // allowed for this system_id. - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_3), - kTestProvider_CCC)); - EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_3), - kTestProvider_AAA)); - uint32_t unknown_system_id = 7890; - // Verify that device with system_id = unknown_system_id and - // provider CCC is not allowed. - EXPECT_FALSE( - IsTestOnlyDeviceAllowedByProvider(unknown_system_id, kTestProvider_CCC)); -} - -TEST_F(DeviceStatusListTest, IsDrmDeviceCertificateRevoked) { - std::string revoked_device_certificate_serial_numbers = - std::string(kRevokedDeviceCertificateSerialNumber1); - revoked_device_certificate_serial_numbers += - "," + std::string(kRevokedDeviceCertificateSerialNumber2); - revoked_device_certificate_serial_numbers += - "," + std::string(kRevokedDeviceCertificateSerialNumber3); - device_status_list_.RevokedDrmCertificateSerialNumbers( - revoked_device_certificate_serial_numbers); - EXPECT_EQ(3, VerifyRevokedDeviceCertificatesCount()); - // Verify that device certificates with serial number, - // 'kRevokedDeviceCertificateSerialNumber1', - // 'kRevokedDeviceCertificateSerialNumber2', - // 'kRevokedDeviceCertificateSerialNumber3' are revoked. - EXPECT_TRUE( - VerifyIsDeviceCertificateRevoked(kRevokedDeviceCertificateSerialNumber1)); - EXPECT_TRUE( - VerifyIsDeviceCertificateRevoked(kRevokedDeviceCertificateSerialNumber2)); - EXPECT_TRUE( - VerifyIsDeviceCertificateRevoked(kRevokedDeviceCertificateSerialNumber3)); - const std::string unrevoked_device_certificate_serial_number = - "unrevoked_device_certificate_serial_number"; - EXPECT_FALSE(VerifyIsDeviceCertificateRevoked( - unrevoked_device_certificate_serial_number)); -} - -TEST_F(DeviceStatusListTest, DetermineAndDeserializeServiceResponseSuccess) { - SignedDeviceInfo published_devices; - GenerateTrivialValidStatusList( - published_devices.mutable_device_certificate_status_list(), - HashAlgorithmProtoToEnum(published_devices.hash_algorithm()), - published_devices.mutable_signature()); - - std::string serialized_published_devices; - ASSERT_TRUE( - published_devices.SerializeToString(&serialized_published_devices)); - - DeviceCertificateStatusList actual_cert_status_list; - std::string actual_serialized_cert_status_list; - std::string actual_signature; - HashAlgorithm hash_algorithm; - ASSERT_EQ(OkStatus(), - DeviceStatusList::DetermineAndDeserializeServiceResponse( - serialized_published_devices, &actual_cert_status_list, - &actual_serialized_cert_status_list, &hash_algorithm, - &actual_signature)); - EXPECT_EQ(published_devices.device_certificate_status_list(), - actual_serialized_cert_status_list); - EXPECT_EQ(published_devices.signature(), actual_signature); - EXPECT_EQ(HashAlgorithmProtoToEnum(published_devices.hash_algorithm()), - hash_algorithm); - - DeviceCertificateStatusList expected_cert_status_list; - ASSERT_TRUE(expected_cert_status_list.ParseFromString( - published_devices.device_certificate_status_list())); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_cert_status_list, actual_cert_status_list)); -} - -TEST_F(DeviceStatusListTest, - DetermineAndDeserializeServiceResponseLegacySuccess) { - std::string serialized_cert_status_list; - std::string signature; - SignedDeviceCertificateStatusList legacy_signed_cert_status_list; - GenerateTrivialValidStatusList( - &serialized_cert_status_list, - HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()), - &signature); - *(legacy_signed_cert_status_list.mutable_certificate_status_list()) = - serialized_cert_status_list; - *(legacy_signed_cert_status_list.mutable_signature()) = signature; - - std::string serialized_signed_cert_status_list; - ASSERT_TRUE(legacy_signed_cert_status_list.SerializeToString( - &serialized_signed_cert_status_list)); - - std::string websafe_b64_serialized_signed_cert_status_list; - absl::WebSafeBase64Escape(serialized_signed_cert_status_list, - &websafe_b64_serialized_signed_cert_status_list); - - std::string server_response = absl::StrCat( - "{\n" - " \"kind\": \"certificateprovisioning#certificateStatusListResponse\"\n" - " \"signedList\": \"", - websafe_b64_serialized_signed_cert_status_list, "\"\n}\n"); - - std::string actual_serialized_cert_status_list; - std::string actual_signature; - DeviceCertificateStatusList actual_cert_status_list; - HashAlgorithm hash_algorithm; - ASSERT_EQ(OkStatus(), - DeviceStatusList::DetermineAndDeserializeServiceResponse( - server_response, &actual_cert_status_list, - &actual_serialized_cert_status_list, &hash_algorithm, - &actual_signature)); - EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list); - EXPECT_EQ(signature, actual_signature); - EXPECT_EQ( - HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()), - hash_algorithm); - - DeviceCertificateStatusList expected_cert_status_list; - ASSERT_TRUE( - expected_cert_status_list.ParseFromString(serialized_cert_status_list)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_cert_status_list, actual_cert_status_list)); -} - -TEST_F(DeviceStatusListTest, - DetermineAndDeserializeServiceResponseLegacyWebSafeBase64Success) { - std::string serialized_cert_status_list; - std::string signature; - SignedDeviceCertificateStatusList legacy_signed_cert_status_list; - GenerateTrivialValidStatusList( - &serialized_cert_status_list, - HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()), - &signature); - *(legacy_signed_cert_status_list.mutable_certificate_status_list()) = - serialized_cert_status_list; - *(legacy_signed_cert_status_list.mutable_signature()) = signature; - - std::string serialized_signed_cert_status_list; - ASSERT_TRUE(legacy_signed_cert_status_list.SerializeToString( - &serialized_signed_cert_status_list)); - - std::string websafe_b64_serialized_signed_cert_status_list; - absl::WebSafeBase64Escape(serialized_signed_cert_status_list, - &websafe_b64_serialized_signed_cert_status_list); - - std::string actual_serialized_cert_status_list; - std::string actual_signature; - HashAlgorithm hash_algorithm; - DeviceCertificateStatusList actual_cert_status_list; - ASSERT_EQ(OkStatus(), - DeviceStatusList::DetermineAndDeserializeServiceResponse( - websafe_b64_serialized_signed_cert_status_list, - &actual_cert_status_list, &actual_serialized_cert_status_list, - &hash_algorithm, &actual_signature)); - EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list); - EXPECT_EQ(signature, actual_signature); - EXPECT_EQ( - HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()), - hash_algorithm); - - DeviceCertificateStatusList expected_cert_status_list; - ASSERT_TRUE( - expected_cert_status_list.ParseFromString(serialized_cert_status_list)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_cert_status_list, actual_cert_status_list)); -} - -TEST_F(DeviceStatusListTest, - DetermineAndDeserializeServiceResponseLegacyBase64Success) { - std::string serialized_cert_status_list; - std::string signature; - SignedDeviceCertificateStatusList legacy_signed_cert_status_list; - GenerateTrivialValidStatusList( - &serialized_cert_status_list, - HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()), - &signature); - *(legacy_signed_cert_status_list.mutable_certificate_status_list()) = - serialized_cert_status_list; - *(legacy_signed_cert_status_list.mutable_signature()) = signature; - - std::string serialized_signed_cert_status_list; - ASSERT_TRUE(legacy_signed_cert_status_list.SerializeToString( - &serialized_signed_cert_status_list)); - - std::string websafe_b64_serialized_signed_cert_status_list; - absl::WebSafeBase64Escape(serialized_signed_cert_status_list, - &websafe_b64_serialized_signed_cert_status_list); - - std::string actual_serialized_cert_status_list; - std::string actual_signature; - HashAlgorithm hash_algorithm; - DeviceCertificateStatusList actual_cert_status_list; - ASSERT_EQ(OkStatus(), - DeviceStatusList::DetermineAndDeserializeServiceResponse( - websafe_b64_serialized_signed_cert_status_list, - &actual_cert_status_list, &actual_serialized_cert_status_list, - &hash_algorithm, &actual_signature)); - EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list); - EXPECT_EQ(signature, actual_signature); - EXPECT_EQ( - HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()), - hash_algorithm); - - DeviceCertificateStatusList expected_cert_status_list; - ASSERT_TRUE( - expected_cert_status_list.ParseFromString(serialized_cert_status_list)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_cert_status_list, actual_cert_status_list)); -} - -TEST_F(DeviceStatusListTest, - GetDeviceCertificateStatusBySystemIdExpiredDeviceCertificateStatusList) { - MockDeviceStatusList mock_device_status_list; - EXPECT_CALL(mock_device_status_list, GetCurrentTime()) - .Times(3) - .WillOnce(Return(kStatusListCreationTime + 100)) - .WillOnce(Return(kStatusListCreationTime + 100)) - .WillOnce(Return(kStatusListCreationTime + 101)); - EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_cert_status_list_, kHashAlgorithm, - cert_status_list_signature_, 100)); - DeviceCertificateStatus device_certificate_status; - EXPECT_EQ(OkStatus(), - mock_device_status_list.GetDeviceCertificateStatusBySystemId( - kValidCertSystemId, &device_certificate_status)); - EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST, - mock_device_status_list - .GetDeviceCertificateStatusBySystemId( - kValidCertSystemId, &device_certificate_status) - .error_code()); -} - -TEST_F(DeviceStatusListTest, - GetDeviceCertificateStatusBySystemIdUnknownDevice) { - DeviceCertificateStatus device_certificate_status; - uint32_t unknown_system_id = 2000; - EXPECT_EQ(DRM_DEVICE_CERTIFICATE_UNKNOWN, - device_status_list_ - .GetDeviceCertificateStatusBySystemId( - unknown_system_id, &device_certificate_status) - .error_code()); -} - -TEST_F(DeviceStatusListTest, GetDeviceCertificateStatusBySystemIdOk) { - DeviceCertificateStatus device_certificate_status; - EXPECT_OK(device_status_list_.GetDeviceCertificateStatusBySystemId( - kValidCertSystemId, &device_certificate_status)); -} - -} // namespace widevine diff --git a/common/drm_root_certificate.cc b/common/drm_root_certificate.cc deleted file mode 100644 index eac92c6..0000000 --- a/common/drm_root_certificate.cc +++ /dev/null @@ -1,574 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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. -//////////////////////////////////////////////////////////////////////////////// - -// common_typos_disable. Successful / successfull. - -#include "common/drm_root_certificate.h" - -#include - -#include "glog/logging.h" -#include "absl/memory/memory.h" -#include "absl/strings/escaping.h" -#include "absl/synchronization/mutex.h" -#include "common/ec_key.h" -#include "common/error_space.h" -#include "common/hash_algorithm.h" -#include "common/hash_algorithm_util.h" -#include "common/rsa_key.h" -#include "common/sha_util.h" -#include "common/signer_public_key.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace widevine { - -namespace { - -const char kDevelopmentString[] = "dev"; // QA systems. -const char kProductionString[] = "prod"; // Production. -const char kTestingString[] = "test"; // Code development / unit tests. - -const bool kUseCache = true; - -// Restrict the certificate chain size. All leaf DRM certificates must be a -// DEVICE certificate. The DEVICE certificate must be signed by a MODEL -// certificate. The MODEL certificate can be signed by Widevine or by a -// PROVISIONER certificate which is signed by Widevine. Do not allow any -// additional links. -const uint32_t kMaxCertificateChainSize = 3; - -// From common::TestDrmCertificates. -// TODO(user): common::test_certificates is a testonly target, consider -// how to use instead of dupliciating the test cert here. -static const unsigned char kTestRootCertificate[] = { - 0x0a, 0x99, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xb9, 0x60, 0x22, - 0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5, - 0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78, - 0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f, - 0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca, - 0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b, - 0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46, - 0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01, - 0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c, - 0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14, - 0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd, - 0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6, - 0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde, - 0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31, - 0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a, - 0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90, - 0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49, - 0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f, - 0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda, - 0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17, - 0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30, - 0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf, - 0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16, - 0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42, - 0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9, - 0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4, - 0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a, - 0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72, - 0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde, - 0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04, - 0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b, - 0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33, - 0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67, - 0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02, - 0x03, 0x01, 0x00, 0x01, 0x12, 0x80, 0x03, 0x7f, 0x83, 0xde, 0xf0, 0x6a, - 0x07, 0x2b, 0x8c, 0xd7, 0x0c, 0xb8, 0x75, 0x50, 0xce, 0xe8, 0xa9, 0x35, - 0xcb, 0x9d, 0xe3, 0x83, 0x89, 0xe6, 0x78, 0xb2, 0x12, 0x12, 0x16, 0xfe, - 0x62, 0xf9, 0xed, 0x1d, 0x1d, 0xda, 0x82, 0x67, 0x82, 0x30, 0xf8, 0x49, - 0xc2, 0x49, 0x65, 0x3b, 0xa3, 0x69, 0xaa, 0xd4, 0xaa, 0xfa, 0x74, 0xa6, - 0xf1, 0xc3, 0xd8, 0xd0, 0x84, 0x27, 0x00, 0xa2, 0xec, 0xbd, 0xcf, 0x58, - 0xf2, 0xf6, 0x60, 0x00, 0xeb, 0x50, 0xae, 0x06, 0x9e, 0x5c, 0xd2, 0xce, - 0xc0, 0xbc, 0x73, 0xdb, 0x66, 0xc4, 0x93, 0x39, 0x22, 0x92, 0x92, 0x27, - 0x71, 0x3c, 0x25, 0x66, 0x96, 0x2e, 0xda, 0x66, 0x65, 0xbc, 0x38, 0xf5, - 0x4e, 0x8e, 0x68, 0x4d, 0x5f, 0x8f, 0xf5, 0x90, 0xcc, 0xfb, 0xf3, 0x8c, - 0x63, 0x3f, 0xe2, 0xf9, 0x4a, 0x37, 0xec, 0x68, 0x0b, 0x00, 0xcd, 0x0e, - 0x13, 0x66, 0x06, 0x2f, 0x37, 0xc7, 0x3a, 0xa3, 0x7a, 0x1e, 0xb8, 0x12, - 0x1d, 0xf4, 0x09, 0xba, 0xfc, 0x55, 0x1d, 0xa8, 0x54, 0x4a, 0x4c, 0x54, - 0xda, 0x32, 0xe3, 0x4c, 0xa2, 0x03, 0xae, 0x65, 0xf0, 0x81, 0x4a, 0xe8, - 0xc7, 0x93, 0x78, 0xdf, 0xc0, 0x3d, 0xc5, 0x24, 0xdc, 0x45, 0x27, 0xe1, - 0xba, 0xc8, 0xe2, 0x1f, 0x27, 0x7c, 0x61, 0xba, 0x1b, 0x31, 0xc0, 0xf1, - 0xad, 0x13, 0xdd, 0x61, 0x31, 0xf4, 0xc0, 0xe9, 0x0e, 0x8c, 0x8e, 0xe8, - 0xd1, 0xf8, 0xdb, 0x76, 0xdf, 0x3f, 0x1a, 0x25, 0x28, 0x46, 0xc4, 0xf4, - 0xdb, 0x8a, 0x3b, 0x03, 0x16, 0x96, 0x6b, 0x28, 0x0f, 0x05, 0xe6, 0xa9, - 0xcb, 0x0d, 0x95, 0x57, 0x89, 0x3e, 0x4c, 0x70, 0xed, 0x84, 0x45, 0xdd, - 0x88, 0x43, 0x4b, 0xc1, 0x9e, 0x52, 0xb3, 0x3a, 0xa1, 0xd9, 0xd4, 0xf9, - 0x68, 0x08, 0x0b, 0x83, 0x35, 0x75, 0xf1, 0x2a, 0xa7, 0xce, 0xf6, 0x3f, - 0x4a, 0x84, 0xd0, 0x0c, 0xfa, 0xf2, 0x0f, 0x42, 0x28, 0x1a, 0x1a, 0x92, - 0xa7, 0x7d, 0x6f, 0xad, 0x57, 0x82, 0x44, 0x1a, 0x6d, 0x35, 0x85, 0x15, - 0x2c, 0xd4, 0x28, 0xb4, 0x7c, 0xde, 0x66, 0x3b, 0xeb, 0x6d, 0x32, 0xc0, - 0x30, 0xdf, 0x16, 0x99, 0x2e, 0xce, 0x8d, 0x23, 0x43, 0x06, 0x00, 0xe9, - 0xb1, 0x94, 0x20, 0x42, 0x2a, 0xf5, 0xf1, 0x79, 0x4f, 0x2c, 0xd9, 0xe1, - 0xc7, 0x2e, 0xd4, 0x8a, 0x31, 0x5a, 0x80, 0x27, 0x57, 0xa6, 0xfc, 0xb2, - 0x47, 0x4c, 0x5b, 0x05, 0x22, 0x82, 0x77, 0x76, 0xbe, 0xd4, 0x23, 0x8c, - 0xdf, 0xfc, 0xe9, 0xbc, 0x01, 0xc0, 0x16, 0x60, 0xff, 0x00, 0x45, 0x36, - 0x2f, 0x29, 0x5f, 0x5f, 0xa8, 0x83, 0x8a, 0x55, 0xc2, 0x39, 0x72, 0x35, - 0xc2, 0xb4, 0x81, 0xf7, 0xd7, 0x40, 0x15, 0x0c, 0xf1, 0xef, 0x58, 0xe7, - 0xc4, 0xc1, 0x23, 0x47, 0x92, 0x29, 0x44}; - -static const unsigned char kDevRootCertificate[] = { - 0x0a, 0x9c, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xc3, 0x94, 0x88, - 0x8b, 0x05, 0x22, 0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, - 0x81, 0x00, 0xc0, 0x00, 0x36, 0x6f, 0x8e, 0xe9, 0xcf, 0x86, 0xdb, 0xcd, - 0xdd, 0x4e, 0xfd, 0xcd, 0x45, 0xbf, 0x6d, 0x96, 0x05, 0x00, 0xb8, 0x72, - 0xff, 0x9c, 0xb4, 0x39, 0xa8, 0xd8, 0xc0, 0x09, 0x73, 0xc0, 0x24, 0x6a, - 0x39, 0x4d, 0x36, 0x3f, 0x9a, 0xe4, 0xb8, 0x76, 0xdc, 0x34, 0xe3, 0xee, - 0x5f, 0xdd, 0x13, 0x20, 0x08, 0xdc, 0x4e, 0x6f, 0x4e, 0x9f, 0xc0, 0x36, - 0xf9, 0xce, 0xc6, 0xb7, 0xdb, 0xe0, 0x51, 0x2d, 0x30, 0x0b, 0xae, 0x0a, - 0x20, 0xd2, 0x29, 0x3c, 0x2c, 0x1d, 0x87, 0x65, 0xeb, 0x5f, 0x93, 0xd7, - 0x3f, 0x12, 0x08, 0x50, 0x0e, 0x55, 0xf3, 0xf1, 0x19, 0xee, 0x18, 0x21, - 0x6e, 0xea, 0xb6, 0x0a, 0x4a, 0x0b, 0x9c, 0x72, 0x37, 0xeb, 0x0b, 0x68, - 0xfc, 0x52, 0x46, 0x62, 0xd0, 0xa2, 0x99, 0x66, 0xe2, 0x2b, 0x74, 0xdd, - 0x5c, 0xaf, 0x9a, 0x03, 0xc4, 0x5d, 0x93, 0xfb, 0xcd, 0x45, 0x9a, 0xee, - 0xfb, 0x7b, 0x18, 0x94, 0xc1, 0x8c, 0x82, 0x34, 0x7f, 0x02, 0x12, 0x21, - 0xfc, 0x40, 0xc1, 0x50, 0xc9, 0xf4, 0x7c, 0xd5, 0x96, 0xbe, 0x55, 0x7f, - 0x3c, 0x1d, 0x70, 0x34, 0xb4, 0xa2, 0x03, 0xc4, 0x3f, 0x89, 0x60, 0xe4, - 0x24, 0x09, 0x1a, 0x74, 0xc4, 0xb6, 0x39, 0xf0, 0x34, 0x60, 0x8e, 0xa7, - 0x5f, 0x02, 0x7f, 0xb9, 0x2a, 0xc5, 0xaa, 0xb2, 0x4c, 0x34, 0xd3, 0x5a, - 0x5d, 0xfa, 0x07, 0xf2, 0xb9, 0xb3, 0xc1, 0xba, 0xab, 0xbe, 0x89, 0x99, - 0xe3, 0x6d, 0x9b, 0xa9, 0xd3, 0xaf, 0x2a, 0x08, 0x76, 0xf3, 0x0e, 0xc9, - 0xe0, 0xb3, 0xbf, 0x51, 0x0c, 0xc5, 0xf4, 0xf3, 0x15, 0x7b, 0x08, 0x11, - 0x8f, 0x61, 0x1f, 0x61, 0x64, 0xdb, 0x15, 0x84, 0x5b, 0x8a, 0xd1, 0x28, - 0x40, 0xde, 0xc5, 0x32, 0xb5, 0xad, 0xad, 0x65, 0x4c, 0xf5, 0xf7, 0xd1, - 0x90, 0x14, 0x5d, 0xc2, 0x85, 0x98, 0xcc, 0xe9, 0xe6, 0x95, 0x42, 0xe1, - 0x3e, 0xfc, 0x7f, 0xc4, 0x49, 0xed, 0x9c, 0xe4, 0x49, 0x3f, 0x03, 0x1b, - 0x0d, 0xa0, 0xfb, 0xf5, 0x38, 0x49, 0xd2, 0xdf, 0xa3, 0x88, 0xb2, 0x76, - 0x93, 0x08, 0x20, 0x18, 0xfe, 0xdc, 0x72, 0x6c, 0x6e, 0xbf, 0x61, 0x37, - 0x03, 0xdb, 0xe5, 0x72, 0x68, 0xe0, 0x99, 0x2f, 0xb9, 0xe0, 0x2e, 0xbb, - 0x9f, 0x96, 0x36, 0x61, 0xaa, 0x2d, 0xa4, 0x93, 0xe8, 0x50, 0x58, 0xe6, - 0x61, 0xe1, 0x14, 0xcf, 0xac, 0x86, 0x98, 0x7f, 0x3c, 0x67, 0x16, 0xce, - 0xb8, 0x70, 0x90, 0x3a, 0x5a, 0xd4, 0xe1, 0xe2, 0x35, 0x98, 0xbf, 0x93, - 0x41, 0x11, 0xb2, 0x44, 0xb2, 0x64, 0xc2, 0xe7, 0x09, 0x45, 0xb7, 0x6f, - 0xb0, 0xbd, 0x6e, 0xe8, 0x67, 0xfa, 0x8d, 0xd4, 0xfa, 0x4b, 0xef, 0xa8, - 0x9d, 0x8a, 0x0a, 0xd9, 0x14, 0x77, 0x09, 0x11, 0x9e, 0xc3, 0x50, 0x14, - 0x6c, 0x45, 0x02, 0x03, 0x01, 0x00, 0x01, 0x12, 0x80, 0x03, 0x17, 0x01, - 0x60, 0x24, 0xe1, 0xfd, 0x75, 0x60, 0x17, 0x5c, 0x5e, 0x6f, 0x9f, 0x7f, - 0xdf, 0xee, 0xf0, 0xf7, 0x7d, 0xb2, 0x50, 0x65, 0x36, 0x26, 0x14, 0x19, - 0x01, 0x5e, 0x98, 0x94, 0x65, 0x97, 0x83, 0xaa, 0x4a, 0x2b, 0x98, 0x2e, - 0x02, 0xf3, 0xb2, 0xc9, 0xb2, 0xed, 0xd3, 0x1b, 0x20, 0x27, 0x9e, 0xe1, - 0x25, 0xc7, 0x86, 0xf0, 0x66, 0x68, 0x5d, 0xd2, 0x3d, 0xa7, 0xbb, 0xbc, - 0x22, 0xfc, 0x29, 0xfa, 0x17, 0x16, 0xf4, 0xa2, 0x00, 0x10, 0x87, 0xb4, - 0x5d, 0x51, 0x45, 0x6b, 0xc8, 0xf4, 0x6b, 0xcc, 0x92, 0x91, 0xe7, 0xa7, - 0x93, 0xbc, 0xc7, 0x2e, 0xdc, 0xac, 0x82, 0x2b, 0x85, 0x56, 0x7b, 0xae, - 0xf2, 0xd8, 0xda, 0xa6, 0xd7, 0xfa, 0x6d, 0x70, 0x2a, 0x2e, 0xcf, 0x69, - 0xef, 0x57, 0x91, 0xa7, 0xaa, 0x40, 0x15, 0x4a, 0x49, 0x1b, 0xbc, 0x36, - 0xbb, 0x1c, 0x94, 0x33, 0x36, 0x61, 0x22, 0x9d, 0x22, 0x66, 0xf0, 0x88, - 0x5e, 0x7c, 0x3c, 0xa5, 0xff, 0x81, 0xcf, 0x1a, 0x44, 0xa1, 0x2b, 0xdf, - 0xc9, 0x3d, 0xd5, 0xc7, 0xc7, 0x3a, 0x75, 0xac, 0x29, 0xfa, 0xfd, 0x5b, - 0xda, 0xf5, 0x8f, 0xd9, 0xdf, 0x08, 0xa4, 0x8d, 0x19, 0x4a, 0xa4, 0x79, - 0x6e, 0x47, 0xf6, 0x07, 0xe0, 0xbd, 0xbf, 0x30, 0x3a, 0xf9, 0xf5, 0xc0, - 0x90, 0x6d, 0x70, 0x27, 0x44, 0xa8, 0x5e, 0x70, 0xcd, 0x43, 0x3e, 0xaf, - 0xf0, 0xd7, 0x20, 0xd3, 0x5e, 0x97, 0x2d, 0x32, 0x1a, 0x3d, 0x2d, 0x0f, - 0x0f, 0xcf, 0xac, 0x4e, 0x88, 0x75, 0x98, 0x6c, 0xfa, 0xe8, 0x42, 0x58, - 0x99, 0xaa, 0x45, 0x0c, 0x41, 0x0c, 0x6e, 0x27, 0x58, 0x57, 0xd2, 0x5b, - 0x82, 0x3d, 0x75, 0x2f, 0x9e, 0xf3, 0xe4, 0x00, 0xcf, 0x91, 0x48, 0x25, - 0xca, 0x98, 0xf2, 0x91, 0x6b, 0x41, 0xa5, 0xe8, 0xcd, 0x64, 0xa7, 0x2e, - 0x78, 0xc7, 0x76, 0x82, 0x3f, 0xf8, 0x57, 0x8a, 0x9d, 0x78, 0x25, 0xad, - 0xf3, 0x1a, 0x8b, 0xfc, 0x83, 0x9a, 0x98, 0x87, 0xe4, 0x55, 0x3e, 0x1c, - 0xa7, 0x80, 0x8f, 0xd6, 0x76, 0xab, 0x03, 0xc7, 0x05, 0x66, 0xc3, 0xa0, - 0x4c, 0x33, 0x1f, 0x39, 0x74, 0x1b, 0x2a, 0xbf, 0xe6, 0xb0, 0x9f, 0x6b, - 0xc1, 0xd6, 0xd3, 0xf4, 0x46, 0x9b, 0xf3, 0xab, 0xca, 0x2e, 0x88, 0x3d, - 0x84, 0x5f, 0xc9, 0x9b, 0x47, 0xbb, 0x57, 0x64, 0x08, 0x0e, 0x18, 0x74, - 0x83, 0x44, 0xd4, 0xc3, 0x18, 0x97, 0xcf, 0x89, 0x6a, 0x49, 0x51, 0xc6, - 0xff, 0x8d, 0x39, 0xc5, 0x23, 0xf9, 0xd5, 0x01, 0xd7, 0x2f, 0xa9, 0xa5, - 0x5d, 0xa9, 0xf3, 0xc9, 0xfd, 0xc4, 0x52, 0x19, 0x7d, 0xf6, 0xa4, 0x2c, - 0x0c, 0xa0, 0x07, 0xdf, 0x7b, 0x44, 0xd7, 0xe5, 0xbf, 0x57, 0x87, 0xc9, - 0x8c, 0xfe, 0x30, 0xb2, 0x89, 0x5d, 0x00, 0x03, 0x3b, 0xe5}; - -static const unsigned char kProdRootCertificate[] = { - 0x0a, 0x9c, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xdd, 0x94, 0x88, - 0x8b, 0x05, 0x22, 0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, - 0x81, 0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90, 0x03, 0xdb, 0x3c, 0x11, - 0x97, 0x09, 0xe8, 0x68, 0xcd, 0xf2, 0xc3, 0x5e, 0x9b, 0xf2, 0xe7, 0x4d, - 0x23, 0xb1, 0x10, 0xdb, 0x87, 0x65, 0xdf, 0xdc, 0xfb, 0x9f, 0x35, 0xa0, - 0x57, 0x03, 0x53, 0x4c, 0xf6, 0x6d, 0x35, 0x7d, 0xa6, 0x78, 0xdb, 0xb3, - 0x36, 0xd2, 0x3f, 0x9c, 0x40, 0xa9, 0x95, 0x26, 0x72, 0x7f, 0xb8, 0xbe, - 0x66, 0xdf, 0xc5, 0x21, 0x98, 0x78, 0x15, 0x16, 0x68, 0x5d, 0x2f, 0x46, - 0x0e, 0x43, 0xcb, 0x8a, 0x84, 0x39, 0xab, 0xfb, 0xb0, 0x35, 0x80, 0x22, - 0xbe, 0x34, 0x23, 0x8b, 0xab, 0x53, 0x5b, 0x72, 0xec, 0x4b, 0xb5, 0x48, - 0x69, 0x53, 0x3e, 0x47, 0x5f, 0xfd, 0x09, 0xfd, 0xa7, 0x76, 0x13, 0x8f, - 0x0f, 0x92, 0xd6, 0x4c, 0xdf, 0xae, 0x76, 0xa9, 0xba, 0xd9, 0x22, 0x10, - 0xa9, 0x9d, 0x71, 0x45, 0xd6, 0xd7, 0xe1, 0x19, 0x25, 0x85, 0x9c, 0x53, - 0x9a, 0x97, 0xeb, 0x84, 0xd7, 0xcc, 0xa8, 0x88, 0x82, 0x20, 0x70, 0x26, - 0x20, 0xfd, 0x7e, 0x40, 0x50, 0x27, 0xe2, 0x25, 0x93, 0x6f, 0xbc, 0x3e, - 0x72, 0xa0, 0xfa, 0xc1, 0xbd, 0x29, 0xb4, 0x4d, 0x82, 0x5c, 0xc1, 0xb4, - 0xcb, 0x9c, 0x72, 0x7e, 0xb0, 0xe9, 0x8a, 0x17, 0x3e, 0x19, 0x63, 0xfc, - 0xfd, 0x82, 0x48, 0x2b, 0xb7, 0xb2, 0x33, 0xb9, 0x7d, 0xec, 0x4b, 0xba, - 0x89, 0x1f, 0x27, 0xb8, 0x9b, 0x88, 0x48, 0x84, 0xaa, 0x18, 0x92, 0x0e, - 0x65, 0xf5, 0xc8, 0x6c, 0x11, 0xff, 0x6b, 0x36, 0xe4, 0x74, 0x34, 0xca, - 0x8c, 0x33, 0xb1, 0xf9, 0xb8, 0x8e, 0xb4, 0xe6, 0x12, 0xe0, 0x02, 0x98, - 0x79, 0x52, 0x5e, 0x45, 0x33, 0xff, 0x11, 0xdc, 0xeb, 0xc3, 0x53, 0xba, - 0x7c, 0x60, 0x1a, 0x11, 0x3d, 0x00, 0xfb, 0xd2, 0xb7, 0xaa, 0x30, 0xfa, - 0x4f, 0x5e, 0x48, 0x77, 0x5b, 0x17, 0xdc, 0x75, 0xef, 0x6f, 0xd2, 0x19, - 0x6d, 0xdc, 0xbe, 0x7f, 0xb0, 0x78, 0x8f, 0xdc, 0x82, 0x60, 0x4c, 0xbf, - 0xe4, 0x29, 0x06, 0x5e, 0x69, 0x8c, 0x39, 0x13, 0xad, 0x14, 0x25, 0xed, - 0x19, 0xb2, 0xf2, 0x9f, 0x01, 0x82, 0x0d, 0x56, 0x44, 0x88, 0xc8, 0x35, - 0xec, 0x1f, 0x11, 0xb3, 0x24, 0xe0, 0x59, 0x0d, 0x37, 0xe4, 0x47, 0x3c, - 0xea, 0x4b, 0x7f, 0x97, 0x31, 0x1c, 0x81, 0x7c, 0x94, 0x8a, 0x4c, 0x7d, - 0x68, 0x15, 0x84, 0xff, 0xa5, 0x08, 0xfd, 0x18, 0xe7, 0xe7, 0x2b, 0xe4, - 0x47, 0x27, 0x12, 0x11, 0xb8, 0x23, 0xec, 0x58, 0x93, 0x3c, 0xac, 0x12, - 0xd2, 0x88, 0x6d, 0x41, 0x3d, 0xc5, 0xfe, 0x1c, 0xdc, 0xb9, 0xf8, 0xd4, - 0x51, 0x3e, 0x07, 0xe5, 0x03, 0x6f, 0xa7, 0x12, 0xe8, 0x12, 0xf7, 0xb5, - 0xce, 0xa6, 0x96, 0x55, 0x3f, 0x78, 0xb4, 0x64, 0x82, 0x50, 0xd2, 0x33, - 0x5f, 0x91, 0x02, 0x03, 0x01, 0x00, 0x01, 0x12, 0x80, 0x03, 0x58, 0xf1, - 0xd6, 0x4d, 0x04, 0x09, 0x7b, 0xdf, 0xd7, 0xef, 0x5d, 0x3b, 0x02, 0x39, - 0x17, 0xfa, 0x14, 0x36, 0x75, 0x4a, 0x38, 0x67, 0x85, 0x57, 0x12, 0xa7, - 0x14, 0xee, 0x35, 0x16, 0xd5, 0x3d, 0xbf, 0x42, 0x86, 0xf6, 0x69, 0x00, - 0x76, 0xcd, 0x93, 0xf4, 0x7c, 0xb2, 0xdf, 0x9e, 0x44, 0xcd, 0x4c, 0xd4, - 0xae, 0x09, 0x18, 0x53, 0x44, 0x32, 0xec, 0xe0, 0x61, 0x1b, 0xe5, 0xda, - 0x13, 0xd3, 0x55, 0xc5, 0xdd, 0x1a, 0xcb, 0x90, 0x1e, 0x7e, 0x5b, 0xc6, - 0xe9, 0x0f, 0x22, 0x9f, 0xbe, 0x85, 0x02, 0xfe, 0x90, 0x31, 0xcc, 0x6b, - 0x03, 0x84, 0xbd, 0x22, 0xc4, 0x55, 0xfa, 0xf5, 0xf2, 0x08, 0xcd, 0x65, - 0x41, 0x58, 0xe8, 0x7d, 0x29, 0xda, 0x04, 0x58, 0x82, 0xf5, 0x37, 0x69, - 0xbc, 0xf3, 0x5a, 0x57, 0x84, 0x17, 0x7b, 0x32, 0x87, 0x70, 0xb2, 0xb0, - 0x76, 0x9c, 0xb2, 0xc3, 0x15, 0xd1, 0x11, 0x26, 0x2a, 0x23, 0x75, 0x99, - 0x3e, 0xb9, 0x77, 0x22, 0x32, 0x0d, 0xbc, 0x1a, 0x19, 0xc1, 0xd5, 0x65, - 0x90, 0x76, 0x55, 0x74, 0x0f, 0x0e, 0x69, 0x4d, 0x5f, 0x4d, 0x8f, 0x19, - 0xaf, 0xdf, 0xd6, 0x16, 0x31, 0x94, 0xa8, 0x92, 0x5f, 0x4f, 0xbc, 0x7a, - 0x31, 0xf8, 0xae, 0x8e, 0xad, 0x33, 0xb7, 0xe9, 0x30, 0xd0, 0x8c, 0x0a, - 0x8a, 0x6c, 0x83, 0x35, 0xf8, 0x8a, 0x81, 0xb2, 0xfe, 0x1c, 0x88, 0xac, - 0x2a, 0x66, 0xc5, 0xff, 0xbd, 0xe6, 0x17, 0xd0, 0x62, 0x0b, 0xdc, 0x8a, - 0x45, 0xf7, 0xb0, 0x3e, 0x5a, 0xc8, 0x1e, 0x4a, 0x24, 0x2f, 0x6c, 0xa5, - 0xe3, 0x1c, 0x88, 0x14, 0x83, 0xd5, 0xc5, 0xef, 0x5e, 0x9f, 0x3d, 0x85, - 0x45, 0x73, 0xe2, 0x6b, 0x50, 0x52, 0x57, 0x4c, 0xfb, 0x92, 0x6c, 0x66, - 0x75, 0x8a, 0xd6, 0x0d, 0x1b, 0xae, 0xf3, 0xec, 0xaf, 0x51, 0x22, 0x03, - 0x5d, 0x0a, 0x2e, 0x63, 0x93, 0x9c, 0x0b, 0x01, 0x20, 0xa8, 0xa9, 0x84, - 0x2e, 0x17, 0xca, 0xae, 0x73, 0xec, 0x22, 0x1b, 0x79, 0xae, 0xf6, 0xa0, - 0x72, 0x2c, 0xdf, 0x07, 0x47, 0xdb, 0x88, 0x86, 0x30, 0x14, 0x78, 0x21, - 0x11, 0x22, 0x88, 0xac, 0xd7, 0x54, 0x74, 0xf9, 0xf3, 0x26, 0xc2, 0xa5, - 0x56, 0xc8, 0x56, 0x4f, 0x00, 0x29, 0x1d, 0x08, 0x7b, 0x7a, 0xfb, 0x95, - 0x89, 0xc3, 0xee, 0x98, 0x54, 0x9e, 0x3c, 0x6b, 0x94, 0x05, 0x13, 0x12, - 0xf6, 0x71, 0xb9, 0xab, 0x13, 0xc3, 0x0c, 0x9b, 0x46, 0x08, 0x7b, 0x3d, - 0x32, 0x6a, 0x68, 0xca, 0x1e, 0x9c, 0x90, 0x62, 0xc5, 0xed, 0x10, 0xb9, - 0x1f, 0x17, 0x25, 0xce, 0x90, 0xb9, 0x6d, 0xcd, 0xc4, 0x46, 0xf5, 0xa3, - 0x62, 0x13, 0x74, 0x02, 0xa7, 0x62, 0xa4, 0xfa, 0x55, 0xd9, 0xde, 0xcf, - 0xa2, 0xe6, 0x80, 0x74, 0x55, 0x06, 0x49, 0xd5, 0x02, 0x0c}; -} // namespace - -// Caches an individual signature for a certificate with a specific serial -// number (signer). -struct VerifiedCertSignature { - VerifiedCertSignature(const std::string& cert, const std::string& sig, - const std::string& signer_sn, - const std::string& signer_pub_key) - : signed_cert(cert), - signature(sig), - signer_serial(signer_sn), - signer_public_key(signer_pub_key) {} - - std::string signed_cert; - std::string signature; - std::string signer_serial; - std::string signer_public_key; -}; - -// Map of certificate serial number to its signature. -typedef std::map VerifiedCertSignatures; -class VerifiedCertSignatureCache { - public: - explicit VerifiedCertSignatureCache(const RsaKeyFactory* key_factory) - : key_factory_(key_factory) {} - - // Checks cache, on miss, uses public key. If successful, adds to - // cache. - Status VerifySignature(const std::string& cert, - const std::string& serial_number, - HashAlgorithm hash_algorithm, - const std::string& signature, - const DrmCertificate& signer) { - { - VerifiedCertSignatures::iterator cached_signature; - absl::ReaderMutexLock read_lock(&signature_cache_mutex_); - cached_signature = signature_cache_.find(serial_number); - if (cached_signature != signature_cache_.end()) { - if (cert != cached_signature->second.signed_cert) { - return Status(error_space, INVALID_SIGNATURE, "cached-cert-mismatch"); - } - if (signature != cached_signature->second.signature) { - return Status(error_space, INVALID_SIGNATURE, - "cached-signature-mismatch"); - } - if (signer.serial_number() != cached_signature->second.signer_serial) { - return Status(error_space, INVALID_SIGNATURE, - "cached-serial-number-mismatch"); - } - if (signer.public_key() != cached_signature->second.signer_public_key) { - return Status(error_space, INVALID_SIGNATURE, - "cached-signer-public-key-mismatch"); - } - return OkStatus(); - } - } - - // Cache miss. Verify signature. - std::unique_ptr signer_public_key = - SignerPublicKey::Create(signer.public_key(), signer.algorithm()); - if (signer_public_key == nullptr) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-public-key"); - } - if (!signer_public_key->VerifySignature(cert, hash_algorithm, signature)) { - return Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature"); - } - // Add signature to cache. - absl::WriterMutexLock write_lock(&signature_cache_mutex_); - signature_cache_.emplace( - serial_number, - VerifiedCertSignature(cert, signature, signer.serial_number(), - signer.public_key())); - return OkStatus(); - } - - private: - VerifiedCertSignatures signature_cache_ - ABSL_GUARDED_BY(&signature_cache_mutex_); - absl::Mutex signature_cache_mutex_; - const RsaKeyFactory* key_factory_; -}; - -Status DrmRootCertificate::CreateByType( - CertificateType cert_type, std::unique_ptr* cert) { - CHECK(cert); - - return Create(cert_type, absl::make_unique(), cert); -} - -std::unique_ptr DrmRootCertificate::CreateByType( - CertificateType cert_type, Status* status) { - CHECK(status); - - std::unique_ptr new_root_cert; - *status = CreateByType(cert_type, &new_root_cert); - return new_root_cert; -} - -Status DrmRootCertificate::CreateByTypeString( - const std::string& cert_type_string, - std::unique_ptr* cert) { - CHECK(cert); - - CertificateType cert_type; - if (cert_type_string == kDevelopmentString) { - cert_type = kCertificateTypeDevelopment; - } else if (cert_type_string == kProductionString) { - cert_type = kCertificateTypeProduction; - } else if (cert_type_string == kTestingString) { - cert_type = kCertificateTypeTesting; - } else { - return Status(error_space, INVALID_PARAMETER, - absl::StrCat("invalid-certificate-type ", cert_type_string)); - } - - return CreateByType(cert_type, cert); -} - -Status DrmRootCertificate::Create(CertificateType cert_type, - std::unique_ptr key_factory, - std::unique_ptr* cert) { - DCHECK(cert); - - std::string serialized_certificate; - switch (cert_type) { - case kCertificateTypeProduction: { - serialized_certificate.assign( - kProdRootCertificate, - kProdRootCertificate + sizeof(kProdRootCertificate)); - break; - } - case kCertificateTypeDevelopment: { - serialized_certificate.assign( - kDevRootCertificate, - kDevRootCertificate + sizeof(kDevRootCertificate)); - break; - } - case kCertificateTypeTesting: { - serialized_certificate.assign( - kTestRootCertificate, - kTestRootCertificate + sizeof(kTestRootCertificate)); - break; - } - default: - return Status(error_space, INVALID_PARAMETER, "invalid-certificate-type"); - } - - SignedDrmCertificate signed_root_cert; - if (!signed_root_cert.ParseFromString(serialized_certificate)) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "signed-root-cert-deserialize-fail"); - } - DrmCertificate root_cert; - if (!signed_root_cert.has_drm_certificate()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-root-device-certificate"); - } - if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "root-cert-deserialize-fail"); - } - if (!root_cert.has_public_key()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-root-cert-public-key"); - } - if (!signed_root_cert.has_signature()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-root-certificate-signature"); - } - - std::unique_ptr public_key = - SignerPublicKey::Create(root_cert.public_key(), root_cert.algorithm()); - if (public_key == nullptr) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-root-public-key"); - } - if (!public_key->VerifySignature( - signed_root_cert.drm_certificate(), - HashAlgorithmProtoToEnum(signed_root_cert.hash_algorithm()), - signed_root_cert.signature())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-root-certificate-signature"); - } - - cert->reset(new DrmRootCertificate( - cert_type, serialized_certificate, root_cert.serial_number(), - root_cert.public_key(), std::move(key_factory))); - return OkStatus(); -} - -DrmRootCertificate::DrmRootCertificate( - CertificateType type, const std::string& serialized_certificate, - const std::string& serial_number, const std::string& public_key, - std::unique_ptr key_factory) - : type_(type), - serialized_certificate_(serialized_certificate), - key_factory_(std::move(key_factory)), - signature_cache_(new VerifiedCertSignatureCache(key_factory_.get())) { - root_cert_.set_public_key(public_key); - root_cert_.set_serial_number(serial_number); -} - -DrmRootCertificate::~DrmRootCertificate() {} - -std::string DrmRootCertificate::GetDigest() const { - return absl::BytesToHexString(Sha256_Hash(serialized_certificate_)); -} - -Status DrmRootCertificate::VerifyCertificate( - const std::string& serialized_certificate, - SignedDrmCertificate* signed_certificate, - DrmCertificate* certificate) const { - std::unique_ptr local_signed_certificate; - if (!signed_certificate) { - local_signed_certificate = absl::make_unique(); - signed_certificate = local_signed_certificate.get(); - } - if (!signed_certificate->ParseFromString(serialized_certificate)) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signed-drm-certificate"); - } - - std::unique_ptr local_certificate; - if (!certificate) { - local_certificate = absl::make_unique(); - certificate = local_certificate.get(); - } - if (signed_certificate->drm_certificate().empty() || - !certificate->ParseFromString(signed_certificate->drm_certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-drm-certificate"); - } - if (certificate->serial_number().empty()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-serial-number"); - } - if (!certificate->has_creation_time_seconds()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-creation-time"); - } - if (certificate->public_key().empty()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"); - } - - // Verify signature chain, but do not use cache for leaf certificates. - uint32_t certs_in_chain = 0; - return VerifySignatures(*signed_certificate, certificate->serial_number(), - !kUseCache, &certs_in_chain); -} - -// Recursively verifies certificates with their signing certs or the root. -// use_cache should be false when initially called so that signatures do not -// cached leaf certificates not signed with the root certificate, such as for -// the case of device-unique device certificates. -// Signatures for root-signed certificates are always cached, even if they are -// leaf certificates. For example service, and provisioner certificates. -Status DrmRootCertificate::VerifySignatures( - const SignedDrmCertificate& signed_cert, - const std::string& cert_serial_number, bool use_cache, - uint32_t* certs_in_chain) const { - CHECK(certs_in_chain); - if (++(*certs_in_chain) > kMaxCertificateChainSize) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "certificate-chain-size-exceeded"); - } - if (!signed_cert.has_signer()) { - // Always use cache for root-signed certificates. - return signature_cache_->VerifySignature( - signed_cert.drm_certificate(), cert_serial_number, - HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()), - signed_cert.signature(), root_cert_); - } - DrmCertificate signer; - if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-certificate"); - } - // Signer cannot be a device certificate. - if (signer.type() == DrmCertificate::DEVICE) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "device-cert-must-be-leaf"); - } - // Verify the signer before verifying signed_cert. - Status status = VerifySignatures(signed_cert.signer(), signer.serial_number(), - kUseCache, certs_in_chain); - if (!status.ok()) { - return status; - } - - if (use_cache) { - status = signature_cache_->VerifySignature( - signed_cert.drm_certificate(), cert_serial_number, - HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()), - signed_cert.signature(), signer); - if (!status.ok()) { - return status; - } - } else { - std::unique_ptr signer_public_key = - SignerPublicKey::Create(signer.public_key(), signer.algorithm()); - if (signer_public_key == nullptr) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-leaf-signer-public-key"); - } - if (!signer_public_key->VerifySignature( - signed_cert.drm_certificate(), - HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()), - signed_cert.signature())) { - return Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature"); - } - } - - return OkStatus(); -} - -} // namespace widevine diff --git a/common/drm_root_certificate.h b/common/drm_root_certificate.h deleted file mode 100644 index 630f28c..0000000 --- a/common/drm_root_certificate.h +++ /dev/null @@ -1,111 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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: -// Root device certificate holder class which deserializes, validates, -// and extracts the root certificate public key. - -#ifndef COMMON_DRM_ROOT_CERTIFICATE_H_ -#define COMMON_DRM_ROOT_CERTIFICATE_H_ - -// common_typos_disable. Successful / successfull. - -#include -#include - -#include "common/certificate_type.h" -#include "common/signer_public_key.h" -#include "common/status.h" -#include "protos/public/drm_certificate.pb.h" - -namespace widevine { - -class DrmCertificate; -class RsaKeyFactory; -class RsaPublicKey; -class SignedDrmCertificate; -class VerifiedCertSignatureCache; - -// Root certificate and certificate chain verifier with internal caching. -// This object is thread-safe. -class DrmRootCertificate { - public: - DrmRootCertificate(const DrmRootCertificate&) = delete; - DrmRootCertificate& operator=(const DrmRootCertificate&) = delete; - - virtual ~DrmRootCertificate(); - - // Creates a DrmRootCertificate object given a certificate type. - // |cert| may not be nullptr, and it points to a - // std::unique_ptr which will be used to return a newly - // created const DrmRootCertificate* if successful. The caller assumes - // ownership of the new DrmRootCertificate. This method returns - // Status::OK on success, or appropriate error status otherwise. - static Status CreateByType(CertificateType cert_type, - std::unique_ptr* cert); - - // Variant on the method above to make CLIF happy until b/110539622 is fixed. - static std::unique_ptr CreateByType( - CertificateType cert_type, Status* status); - - // Creates a DrmRootCertificate object given a certificate type std::string, which - // must be one of "prod", "qa", or "test". - // |cert| may not be nullptr, and it points to a - // std::unique_ptr which will be used to return a newly - // created const DrmRootCertificate* if successful. The caller assumes - // ownership of the new DrmRootCertificate. This method returns - // Status::OK on success, or appropriate error status otherwise. - static Status CreateByTypeString(const std::string& cert_type_string, - std::unique_ptr* cert); - - // |certificate| will contgain the DRM certificate upon successful return. - // May be null. - // Returns Status::OK if successful, or an appropriate error code otherwise. - virtual Status VerifyCertificate(const std::string& serialized_certificate, - SignedDrmCertificate* signed_certificate, - DrmCertificate* certificate) const; - - // Returns the hex-encoded SHA-256 digest for this certificate. - virtual std::string GetDigest() const; - - const CertificateType type() const { return type_; } - - virtual const std::string& public_key() const { - return root_cert_.public_key(); - } - - protected: - DrmRootCertificate(CertificateType cert_type, - const std::string& serialized_certificate, - const std::string& serial_number, - const std::string& public_key, - std::unique_ptr key_factory); - - private: - friend class DrmRootCertificateTest; - - static Status Create(CertificateType cert_type, - std::unique_ptr key_factory, - std::unique_ptr* cert); - - Status VerifySignatures(const SignedDrmCertificate& signed_cert, - const std::string& cert_serial_number, bool use_cache, - uint32_t* certs_in_chain) const; - - CertificateType type_; - std::string serialized_certificate_; - DrmCertificate root_cert_; - // TODO(b/143309971): Either add an ec key_factory object, or drop the rsa - // |key_factory_|. - std::unique_ptr key_factory_; - mutable std::unique_ptr signature_cache_; -}; - -} // namespace widevine - -#endif // COMMON_DRM_ROOT_CERTIFICATE_H_ diff --git a/common/drm_root_certificate_test.cc b/common/drm_root_certificate_test.cc deleted file mode 100644 index a671885..0000000 --- a/common/drm_root_certificate_test.cc +++ /dev/null @@ -1,415 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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: -// Unit tests for drm_root_certificate.cc - -#include "common/drm_root_certificate.h" - -#include - -#include "glog/logging.h" -#include "google/protobuf/util/message_differencer.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/memory/memory.h" -#include "common/ec_key.h" -#include "common/ec_test_keys.h" -#include "common/error_space.h" -#include "common/hash_algorithm.h" -#include "common/hash_algorithm_util.h" -#include "common/rsa_key.h" -#include "common/rsa_test_keys.h" -#include "common/test_drm_certificates.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -using google::protobuf::util::MessageDifferencer; -using ::testing::Values; - -namespace widevine { - -TEST(DrmRootCertificateCreateTest, TestCertificate) { - const std::string kTestCertificateHash( - "49f917b1bdfed78002a58e799a58e940" - "1fffaaed9d8d80752782b066757e2c8c"); - std::unique_ptr root_cert; - ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeTesting, &root_cert)); - ASSERT_TRUE(root_cert != nullptr); - EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest()); -} - -TEST(DrmRootCertificateCreateTest, DevCertificate) { - const std::string kDevelopmentCertificateHash( - "0e25ee95476a770f30b98ac5ef778b3f" - "137b66c29385b84f547a361b4724b17d"); - std::unique_ptr root_cert; - ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeDevelopment, &root_cert)); - ASSERT_TRUE(root_cert != nullptr); - EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest()); -} - -TEST(DrmRootCertificateCreateTest, ProdCertificate) { - const std::string kProductionCertificateHash( - "d62fdabc9286648a81f7d3bedaf2f5a5" - "27bbad39bc38da034ba98a21569adb9b"); - std::unique_ptr root_cert; - ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeProduction, &root_cert)); - ASSERT_TRUE(root_cert != nullptr); - EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest()); -} - -TEST(DrmRootCertificateTestCertificatesTest, Success) { - TestDrmCertificates test_certs; - std::unique_ptr root_cert; - ASSERT_TRUE( - DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert) - .ok()); - EXPECT_TRUE(root_cert - ->VerifyCertificate(test_certs.test_root_certificate(), - nullptr, nullptr) - .ok()); - EXPECT_TRUE( - root_cert - ->VerifyCertificate(test_certs.test_intermediate_certificate(), - nullptr, nullptr) - .ok()); - EXPECT_TRUE(root_cert - ->VerifyCertificate(test_certs.test_user_device_certificate(), - nullptr, nullptr) - .ok()); - EXPECT_TRUE( - root_cert - ->VerifyCertificate(test_certs.test_service_certificate_no_type(), - nullptr, nullptr) - .ok()); -} - -TEST(DrmRootCertificateTestCertificatesTest, NonWidevineRootSigner) { - // TODO(b/138929855): Add test to verify certificate chain is signed by - // Widevine. -} - -class SignerPrivateKey { - public: - virtual ~SignerPrivateKey() {} - virtual bool GenerateSignature(const std::string& message, - HashAlgorithm hash_algorithm, - std::string* signature) const = 0; - virtual DrmCertificate::Algorithm algorithm() const = 0; - static std::unique_ptr Create( - const std::string& private_key, - widevine::DrmCertificate::Algorithm algorithm); - - protected: - SignerPrivateKey() {} -}; - -template -class SignerPrivateKeyImpl : public SignerPrivateKey { - public: - SignerPrivateKeyImpl(std::unique_ptr private_key, - DrmCertificate::Algorithm algorithm) - : private_key_(std::move(private_key)), algorithm_(algorithm) {} - ~SignerPrivateKeyImpl() override {} - bool GenerateSignature(const std::string& message, - HashAlgorithm hash_algorithm, - std::string* signature) const override { - return private_key_->GenerateSignature(message, hash_algorithm, signature); - } - DrmCertificate::Algorithm algorithm() const override { return algorithm_; } - - private: - std::unique_ptr private_key_; - DrmCertificate::Algorithm algorithm_; -}; - -std::unique_ptr SignerPrivateKey::Create( - const std::string& private_key, - widevine::DrmCertificate::Algorithm algorithm) { - DCHECK(algorithm != DrmCertificate::UNKNOWN_ALGORITHM); - switch (algorithm) { - case DrmCertificate::RSA: { - auto rsa_key = - std::unique_ptr(RsaPrivateKey::Create(private_key)); - CHECK(rsa_key); - std::unique_ptr new_rsa_signer_private_key = - absl::make_unique>( - std::move(rsa_key), algorithm); - CHECK(new_rsa_signer_private_key); - return new_rsa_signer_private_key; - } - case DrmCertificate::ECC_SECP256R1: - case DrmCertificate::ECC_SECP384R1: - case DrmCertificate::ECC_SECP521R1: { - auto ec_key = ECPrivateKey::Create(private_key); - CHECK(ec_key); - std::unique_ptr new_ec_signer_private_key = - absl::make_unique>( - std::move(ec_key), algorithm); - CHECK(new_ec_signer_private_key); - return new_ec_signer_private_key; - } - default: - break; - } - return nullptr; -} - -static const int kDrmRootKey = 0; -static const int kInterMediateKey = 1; -static const int kClientKey = 2; - -class DrmRootCertificateTest : public testing::TestWithParam { - protected: - DrmRootCertificateTest() {} - - void SetUp() override { - bool algorithm_status = false; - std::string algorithm(GetParam()); - if (algorithm == "RSA") { - RsaTestSetup(); - algorithm_status = true; - } - if (algorithm == "ECC") { - EcTestSetup(); - algorithm_status = true; - } - - CHECK(algorithm_status); - - ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeTesting, &root_cert_)); - } - - void RsaTestSetup() { - private_keys_.resize(3); - private_keys_[kDrmRootKey] = - SignerPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits(), - widevine::DrmCertificate::RSA); - drm_certificates_[kDrmRootKey].set_serial_number("level 0"); - drm_certificates_[kDrmRootKey].set_creation_time_seconds(0); - drm_certificates_[kDrmRootKey].set_public_key( - rsa_test_keys_.public_test_key_1_3072_bits()); - - private_keys_[kInterMediateKey] = - SignerPrivateKey::Create(rsa_test_keys_.private_test_key_2_2048_bits(), - widevine::DrmCertificate::RSA); - drm_certificates_[kInterMediateKey].set_serial_number("level 1"); - drm_certificates_[kInterMediateKey].set_creation_time_seconds(1); - drm_certificates_[kInterMediateKey].set_public_key( - rsa_test_keys_.public_test_key_2_2048_bits()); - - private_keys_[kClientKey] = - SignerPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits(), - widevine::DrmCertificate::RSA); - drm_certificates_[kClientKey].set_serial_number("level 2"); - drm_certificates_[kClientKey].set_creation_time_seconds(2); - drm_certificates_[kClientKey].set_public_key( - rsa_test_keys_.public_test_key_3_2048_bits()); - } - - void EcTestSetup() { - private_keys_.resize(3); - private_keys_[kDrmRootKey] = - SignerPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits(), - widevine::DrmCertificate::RSA); - drm_certificates_[kDrmRootKey].set_serial_number("level 0"); - drm_certificates_[kDrmRootKey].set_creation_time_seconds(0); - drm_certificates_[kDrmRootKey].set_public_key( - rsa_test_keys_.public_test_key_1_3072_bits()); - - private_keys_[kInterMediateKey] = - SignerPrivateKey::Create(ec_test_keys_.private_test_key_1_secp521r1(), - DrmCertificate::ECC_SECP521R1); - drm_certificates_[kInterMediateKey].set_serial_number("level 1"); - drm_certificates_[kInterMediateKey].set_creation_time_seconds(1); - drm_certificates_[kInterMediateKey].set_public_key( - ec_test_keys_.public_test_key_1_secp521r1()); - drm_certificates_[kInterMediateKey].set_algorithm( - DrmCertificate::ECC_SECP521R1); - - private_keys_[kClientKey] = - SignerPrivateKey::Create(ec_test_keys_.private_test_key_1_secp256r1(), - DrmCertificate::ECC_SECP256R1); - drm_certificates_[kClientKey].set_serial_number("level 2"); - drm_certificates_[kClientKey].set_creation_time_seconds(2); - drm_certificates_[kClientKey].set_public_key( - ec_test_keys_.public_test_key_1_secp256r1()); - drm_certificates_[kClientKey].set_algorithm(DrmCertificate::ECC_SECP256R1); - - // Client certificate. - - // Intermediate certificate. - } - - void GenerateSignedDrmCertificate() { - SignedDrmCertificate* current_sc(&signed_drm_certificate_); - drm_certificates_[kClientKey].set_algorithm( - private_keys_[kClientKey]->algorithm()); - ASSERT_TRUE(drm_certificates_[kClientKey].SerializeToString( - current_sc->mutable_drm_certificate())); - ASSERT_TRUE(private_keys_[kInterMediateKey]->GenerateSignature( - current_sc->drm_certificate(), - HashAlgorithmProtoToEnum(current_sc->hash_algorithm()), - current_sc->mutable_signature())); - - current_sc = current_sc->mutable_signer(); - drm_certificates_[kInterMediateKey].set_algorithm( - private_keys_[kInterMediateKey]->algorithm()); - ASSERT_TRUE(drm_certificates_[kInterMediateKey].SerializeToString( - current_sc->mutable_drm_certificate())); - ASSERT_TRUE(private_keys_[kDrmRootKey]->GenerateSignature( - current_sc->drm_certificate(), - HashAlgorithmProtoToEnum(current_sc->hash_algorithm()), - current_sc->mutable_signature())); - - current_sc = current_sc->mutable_signer(); - drm_certificates_[kDrmRootKey].set_algorithm( - private_keys_[kDrmRootKey]->algorithm()); - ASSERT_TRUE(drm_certificates_[kDrmRootKey].SerializeToString( - current_sc->mutable_drm_certificate())); - ASSERT_TRUE(private_keys_[kDrmRootKey]->GenerateSignature( - current_sc->drm_certificate(), - HashAlgorithmProtoToEnum(current_sc->hash_algorithm()), - current_sc->mutable_signature())); - } - - RsaTestKeys rsa_test_keys_; - ECTestKeys ec_test_keys_; - std::vector> private_keys_; - SignedDrmCertificate signed_drm_certificate_; - DrmCertificate drm_certificates_[3]; - std::unique_ptr root_cert_; -}; - -INSTANTIATE_TEST_SUITE_P(SuccessNoOutput, DrmRootCertificateTest, - Values("RSA", "ECC")); - -TEST_P(DrmRootCertificateTest, SuccessNoOutput) { - GenerateSignedDrmCertificate(); - ASSERT_EQ(OkStatus(), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, SuccessWithOutput) { - GenerateSignedDrmCertificate(); - SignedDrmCertificate out_signed_cert; - DrmCertificate out_cert; - ASSERT_EQ(OkStatus(), root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), - &out_signed_cert, &out_cert)); - EXPECT_TRUE( - MessageDifferencer::Equals(out_signed_cert, signed_drm_certificate_)); - EXPECT_TRUE(MessageDifferencer::Equals(out_cert, drm_certificates_[2])); -} - -TEST_P(DrmRootCertificateTest, InvalidSignedDrmCertificate) { - EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signed-drm-certificate"), - root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, InvalidSignerCertificate) { - GenerateSignedDrmCertificate(); - signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage"); - EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-certificate"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, MissingDrmCertificate) { - GenerateSignedDrmCertificate(); - signed_drm_certificate_.clear_drm_certificate(); - EXPECT_EQ( - Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, InvalidDrmCertificate) { - GenerateSignedDrmCertificate(); - signed_drm_certificate_.set_drm_certificate("junk"); - EXPECT_EQ( - Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, InvalidPublicKey) { - drm_certificates_[0].set_public_key("rubbish"); - GenerateSignedDrmCertificate(); - EXPECT_EQ( - Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signer-public-key"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, MissingPublicKey) { - drm_certificates_[2].clear_public_key(); - GenerateSignedDrmCertificate(); - EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, MissingCreationTime) { - drm_certificates_[2].clear_creation_time_seconds(); - GenerateSignedDrmCertificate(); - EXPECT_EQ( - Status(error_space, INVALID_DRM_CERTIFICATE, "missing-creation-time"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, MissingSerialNumber) { - drm_certificates_[2].set_serial_number(""); - GenerateSignedDrmCertificate(); - EXPECT_EQ( - Status(error_space, INVALID_DRM_CERTIFICATE, "missing-serial-number"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, InvalidSignatureWithNoCache) { - GenerateSignedDrmCertificate(); - signed_drm_certificate_.mutable_signer()->set_signature( - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - EXPECT_EQ( - Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); -} - -TEST_P(DrmRootCertificateTest, InvalidSignatureWithCache) { - GenerateSignedDrmCertificate(); - // Verify and cache. - ASSERT_EQ(OkStatus(), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); - - // Verify success using cache. - ASSERT_EQ(OkStatus(), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); - - // Verify failure using cache. - signed_drm_certificate_.mutable_signer()->set_signature( - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - EXPECT_EQ(Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); -} - -} // namespace widevine diff --git a/common/drm_service_certificate.cc b/common/drm_service_certificate.cc deleted file mode 100644 index 1cc77eb..0000000 --- a/common/drm_service_certificate.cc +++ /dev/null @@ -1,316 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/drm_service_certificate.h" - -#include -#include -#include - -#include "glog/logging.h" -#include "absl/base/thread_annotations.h" -#include "absl/strings/escaping.h" -#include "absl/synchronization/mutex.h" -#include "util/gtl/map_util.h" -#include "common/aes_cbc_util.h" -#include "common/certificate_type.h" -#include "common/drm_root_certificate.h" -#include "common/error_space.h" -#include "common/rsa_util.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace widevine { - -namespace { - -// Class used to hold global service certificate map. -class DrmServiceCertificateMap { - public: - DrmServiceCertificateMap(); - ~DrmServiceCertificateMap(); - - DrmServiceCertificateMap(const DrmServiceCertificateMap&) = delete; - DrmServiceCertificateMap& operator=(const DrmServiceCertificateMap&) = delete; - - void Reset(); - void AddCert(std::unique_ptr new_cert); - void ClearDefaultDrmServiceCertificate(); - const DrmServiceCertificate* GetDefaultCert(); - const DrmServiceCertificate* GetCertBySerialNumber( - const std::string& serial_number); - const DrmServiceCertificate* GetCertByProvider( - const std::string& provider_id); - static DrmServiceCertificateMap* GetInstance(); - - private: - absl::Mutex mutex_; - // Certificate serial number to certificate map. - std::map> map_ - ABSL_GUARDED_BY(mutex_); - DrmServiceCertificate* default_cert_ ABSL_GUARDED_BY(mutex_); -}; - -DrmServiceCertificateMap::DrmServiceCertificateMap() : default_cert_(nullptr) {} -DrmServiceCertificateMap::~DrmServiceCertificateMap() { Reset(); } - -void DrmServiceCertificateMap::Reset() { - absl::WriterMutexLock lock(&mutex_); - map_.clear(); - default_cert_ = nullptr; -} - -void DrmServiceCertificateMap::AddCert( - std::unique_ptr new_cert) { - absl::WriterMutexLock lock(&mutex_); - - std::unique_ptr* previous_cert = - gtl::FindOrNull(map_, new_cert->serial_number()); - if (previous_cert != nullptr) { - if (default_cert_ == previous_cert->get()) { - default_cert_ = nullptr; - } - } - - if (default_cert_ == nullptr) { - default_cert_ = new_cert.get(); - } - const std::string& serial_number = new_cert->serial_number(); - map_[serial_number] = std::move(new_cert); -} - -void DrmServiceCertificateMap::ClearDefaultDrmServiceCertificate() { - absl::WriterMutexLock lock(&mutex_); - default_cert_ = nullptr; -} - -const DrmServiceCertificate* DrmServiceCertificateMap::GetDefaultCert() { - absl::ReaderMutexLock lock(&mutex_); - return default_cert_; -} - -const DrmServiceCertificate* DrmServiceCertificateMap::GetCertBySerialNumber( - const std::string& serial_number) { - absl::ReaderMutexLock lock(&mutex_); - return map_[serial_number].get(); -} - -const DrmServiceCertificate* DrmServiceCertificateMap::GetCertByProvider( - const std::string& provider_id) { - absl::ReaderMutexLock lock(&mutex_); - DrmServiceCertificate* provider_drm_cert = nullptr; - for (const auto& drm_cert : map_) { - if (drm_cert.second->provider_id() == provider_id) { - if (provider_drm_cert == nullptr) { - provider_drm_cert = drm_cert.second.get(); - } else if (drm_cert.second->creation_time_seconds() > - provider_drm_cert->creation_time_seconds()) { - // Use the newest cert. - provider_drm_cert = drm_cert.second.get(); - } - } - } - return provider_drm_cert; -} - -DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() { - static auto* const kInstance = new DrmServiceCertificateMap(); - return kInstance; -} - -} // namespace - -Status DrmServiceCertificate::AddDrmServiceCertificate( - const DrmRootCertificate* root_drm_cert, - const std::string& service_certificate, - const std::string& service_private_key, - const std::string& service_private_key_passphrase) { - DrmCertificate drm_cert; - Status status = - root_drm_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert); - if (!status.ok()) { - return status; - } - - if (drm_cert.type() != DrmCertificate::SERVICE) { - return Status(error_space, INVALID_SERVICE_CERTIFICATE, - "not-service-certificate"); - } - if (drm_cert.provider_id().empty()) { - return Status(error_space, INVALID_SERVICE_CERTIFICATE, - "missing-certificate-service-id"); - } - std::unique_ptr public_key( - RsaPublicKey::Create(drm_cert.public_key())); - if (!public_key) { - return Status(error_space, INVALID_SERVICE_CERTIFICATE, - "invalid-certificate-public-key"); - } - std::string pkcs1_key; - if (!rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey( - service_private_key, service_private_key_passphrase, &pkcs1_key)) { - return Status(error_space, INVALID_SERVICE_PRIVATE_KEY, - "key-decryption-failed"); - } - std::unique_ptr private_key(RsaPrivateKey::Create(pkcs1_key)); - if (private_key == nullptr) { - return Status(error_space, INVALID_SERVICE_PRIVATE_KEY, - "invalid-private-key"); - } - - std::unique_ptr new_cert(new DrmServiceCertificate( - service_certificate, drm_cert.provider_id(), drm_cert.serial_number(), - drm_cert.creation_time_seconds(), std::move(public_key), - std::move(private_key))); - DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert)); - - return OkStatus(); -} - -const DrmServiceCertificate* -DrmServiceCertificate::GetDefaultDrmServiceCertificate() { - return DrmServiceCertificateMap::GetInstance()->GetDefaultCert(); -} - -const DrmServiceCertificate* -DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie() { - const DrmServiceCertificate* default_cert = - DrmServiceCertificateMap::GetInstance()->GetDefaultCert(); - CHECK(default_cert) << "Service Certificate not set!"; - return default_cert; -} - -const DrmServiceCertificate* -DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber( - const std::string& serial_number) { - return DrmServiceCertificateMap::GetInstance()->GetCertBySerialNumber( - serial_number); -} - -const DrmServiceCertificate* -DrmServiceCertificate::GetDrmServiceCertificateByProvider( - const std::string& provider) { - return DrmServiceCertificateMap::GetInstance()->GetCertByProvider(provider); -} - -Status DrmServiceCertificate::SetDefaultDrmServiceCertificate( - const DrmRootCertificate* root_drm_cert, - const std::string& service_certificate, - const std::string& service_private_key, - const std::string& service_private_key_passphrase) { - DrmServiceCertificateMap::GetInstance()->ClearDefaultDrmServiceCertificate(); - return AddDrmServiceCertificate(root_drm_cert, service_certificate, - service_private_key, - service_private_key_passphrase); -} - -Status DrmServiceCertificate::DecryptClientIdentification( - const EncryptedClientIdentification& encrypted_client_id, - ClientIdentification* client_id) { - DCHECK(client_id); - if (encrypted_client_id.service_certificate_serial_number().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-service-certificate-serial-number"); - } - if (encrypted_client_id.provider_id().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-service-id"); - } - if (encrypted_client_id.encrypted_client_id().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id"); - } - if (encrypted_client_id.encrypted_client_id_iv().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id-iv"); - } - if (encrypted_client_id.encrypted_privacy_key().empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-privacy-key"); - } - std::string privacy_key; - std::string provider_id; - const DrmServiceCertificate* cert = GetDrmServiceCertificateBySerialNumber( - encrypted_client_id.service_certificate_serial_number()); - if (!cert) { - return Status( - error_space, SERVICE_CERTIFICATE_NOT_FOUND, - "service-certificate-not-found (SN " + - absl::BytesToHexString( - encrypted_client_id.service_certificate_serial_number()) + - ")"); - } - if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(), - &privacy_key)) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "privacy-key-decryption-failed"); - } - if (cert->provider_id() != encrypted_client_id.provider_id()) { - return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, - std::string("provider-id-mismatch (") + cert->provider_id() + - " / " + encrypted_client_id.provider_id() + ")"); - } - std::string serialized_client_id(crypto_util::DecryptAesCbc( - privacy_key, encrypted_client_id.encrypted_client_id_iv(), - encrypted_client_id.encrypted_client_id())); - if (serialized_client_id.empty()) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-decryption-failed"); - } - if (!client_id->ParseFromString(serialized_client_id)) { - return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-parse-failed"); - } - return OkStatus(); -} - -void DrmServiceCertificate::ResetServiceCertificates() { - DrmServiceCertificateMap::GetInstance()->Reset(); -} - -Status DrmServiceCertificate::ValidateDrmServiceCertificate() { - const DrmServiceCertificate* service_certificate = - GetDefaultDrmServiceCertificate(); - if (!service_certificate) { - return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, - "drm service certificate is not found."); - } - SignedDrmCertificate signed_cert; - if (!signed_cert.ParseFromString(service_certificate->certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "signed drm service certificate is failed to parse."); - } - DrmCertificate drm_cert; - if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "Drm service certificate is failed to parse."); - } - if (!drm_cert.has_creation_time_seconds()) { - return Status(error_space, INVALID_SERVICE_CERTIFICATE, - "missing certificate creation time"); - } - // TODO(user): Check creation_time_seconds field in DrmCertificate and also - // export the absl/time dependency through moe. - return OkStatus(); -} - -DrmServiceCertificate::DrmServiceCertificate( - const std::string& service_certificate, const std::string& provider_id, - const std::string& serial_number, const uint32_t creation_time_seconds, - std::unique_ptr public_key, - std::unique_ptr private_key) - : certificate_(service_certificate), - provider_id_(provider_id), - serial_number_(serial_number), - creation_time_seconds_(creation_time_seconds), - public_key_(std::move(public_key)), - private_key_(std::move(private_key)) {} - -} // namespace widevine diff --git a/common/drm_service_certificate.h b/common/drm_service_certificate.h deleted file mode 100644 index 7d4e33f..0000000 --- a/common/drm_service_certificate.h +++ /dev/null @@ -1,144 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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: -// Service certificate holder used to decrypt encrypted client credentials. - -#ifndef COMMON_DRM_SERVICE_CERTIFICATE_H_ -#define COMMON_DRM_SERVICE_CERTIFICATE_H_ - -#include -#include -#include - -#include -#include "common/certificate_type.h" -#include "common/rsa_key.h" -#include "common/status.h" - -namespace widevine { -class RequestInspectorTest; -} // namespace widevine - -namespace widevine { - -class ClientIdentification; -class DrmRootCertificate; -class EncryptedClientIdentification; - -// TODO(user): Add a DrmCertificateList class to provide the static method -// functionality. -class DrmServiceCertificate { - public: - DrmServiceCertificate(const DrmServiceCertificate&) = delete; - DrmServiceCertificate& operator=(const DrmServiceCertificate&) = delete; - - // Create a new DrmServiceCertificate object and add it to the list of valid - // service certificates. |drm_root_cert| is the root certificate for the type - // of certifiate being added. |service_certificate| is a - // Google-generated certificate used to authenticate the service provider for - // purposes of device privacy, |service_private_key| is the encrypted PKCS#8 - // private RSA key corresponding to the service certificate, - // |service_private_key_passphrase| is the password required to decrypt - // |service_private_key|. - // Returns status::OK if successful, or appropriate error code otherwise. - // If the default service certificate is not set, this certificate will be - // used as the default service certificate. - // This method is thread-safe. - static Status AddDrmServiceCertificate( - const DrmRootCertificate* root_drm_cert, - const std::string& service_certificate, - const std::string& service_private_key, - const std::string& service_private_key_passphrase); - - // Same as AddDrmServiceCertificate(), but will clear the default service - // certificate if it's set. This will result in this service certificate - // being set as the default service certificate. - static Status SetDefaultDrmServiceCertificate( - const DrmRootCertificate* root_drm_cert, - const std::string& service_certificate, - const std::string& service_private_key, - const std::string& service_private_key_passphrase); - - // Returns the default service certificate. Will return null if no default - // Service Certificate is set. This method is thread-safe. - static const DrmServiceCertificate* GetDefaultDrmServiceCertificate(); - - // Returns the default service certificate. Will abort if no default Service - // Certificate is set. This method is thread-safe. - static const DrmServiceCertificate* GetDefaultDrmServiceCertificateOrDie(); - - // Returns the service certificate with the given |cert_serial_number|, or - // null otherwise. - static const DrmServiceCertificate* GetDrmServiceCertificateBySerialNumber( - const std::string& cert_serial_number); - - // Returns the service certificate with the given |provider_id|, or - // null otherwise. If multple certificates exist for the provider, the - // newest certificate is returned. - static const DrmServiceCertificate* GetDrmServiceCertificateByProvider( - const std::string& provider_id); - - // Decrypts the EncryptedClientIdentification message passed in - // |encrypted_client_id| into |client_id| using the private key for the - // certificate which was used to encrypt the information. |client_id| must - // not be NULL. Returns status::OK if successful, or an appropriate error - // otherwise. This method is thread-safe. - static Status DecryptClientIdentification( - const EncryptedClientIdentification& encrypted_client_id, - ClientIdentification* client_id); - - const std::string& certificate() const { return certificate_; } - const std::string& provider_id() const { return provider_id_; } - const std::string& serial_number() const { return serial_number_; } - uint32_t creation_time_seconds() const { return creation_time_seconds_; } - const RsaPrivateKey* const private_key() const { return private_key_.get(); } - const RsaPublicKey* const public_key() const { return public_key_.get(); } - - // Returns the validation result of drm service certificate. Returns - // status::OK if successful, or in case of error, contact - // widevine-tam@google.com to get the next valid service certificate renewed - // via get deviceCertificate StatusList. - static Status ValidateDrmServiceCertificate(); - - private: - friend class DrmServiceCertificateTest; - friend class widevine::RequestInspectorTest; - - static Status AddDrmServiceCertificate( - const std::string& root_public_key, - const std::string& service_certificate, - const std::string& service_private_key, - const std::string& service_private_key_passphrase); - - static Status SetDefaultDrmServiceCertificate( - const std::string& root_public_key, - const std::string& service_certificate, - const std::string& service_private_key, - const std::string& service_private_key_passphrase); - - DrmServiceCertificate(const std::string& service_certificate, - const std::string& provider_id, - const std::string& serial_number, - const uint32_t creation_time_seconds, - std::unique_ptr public_key, - std::unique_ptr private_key); - - static void ResetServiceCertificates(); - - std::string certificate_; - std::string provider_id_; - std::string serial_number_; - uint32_t creation_time_seconds_; - std::unique_ptr public_key_; - std::unique_ptr private_key_; -}; - -} // namespace widevine - -#endif // COMMON_DRM_SERVICE_CERTIFICATE_H_ diff --git a/common/drm_service_certificate_test.cc b/common/drm_service_certificate_test.cc deleted file mode 100644 index a978990..0000000 --- a/common/drm_service_certificate_test.cc +++ /dev/null @@ -1,428 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/drm_service_certificate.h" - -#include - -#include "glog/logging.h" -#include "google/protobuf/util/message_differencer.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/aes_cbc_util.h" -#include "common/drm_root_certificate.h" -#include "common/hash_algorithm_util.h" -#include "common/rsa_key.h" -#include "common/rsa_test_keys.h" -#include "common/rsa_util.h" -#include "common/test_drm_certificates.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/drm_certificate.pb.h" -#include "protos/public/errors.pb.h" // IWYU pragma: keep -#include "protos/public/license_server_sdk.pb.h" -#include "protos/public/signed_drm_certificate.pb.h" - -namespace widevine { - -const char kPrivacyKey[] = "f7538b38acc78ec68c732ac665c55c65"; -const char kIv[] = "09e9cda133ff5140bd2793173a04b5a3"; -const char kPassphrase[] = "passphrase"; - -class DrmServiceCertificateTest : public ::testing::Test { - public: - DrmServiceCertificateTest() - : privacy_key_(absl::HexStringToBytes(kPrivacyKey)), - iv_(absl::HexStringToBytes(kIv)), - root_private_key_( - RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())) { - EXPECT_TRUE(root_private_key_); - EXPECT_OK( - DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); - client_id_.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); - client_id_.set_token(test_certs_.test_user_device_certificate()); - } - - void SetUp() override { DrmServiceCertificate::ResetServiceCertificates(); } - - protected: - std::string GenerateDrmServiceCertificate(const std::string& serial_number, - const std::string& provider_id, - uint32_t creation_time_seconds, - const std::string& public_key) { - DrmCertificate cert; - cert.set_type(DrmCertificate::SERVICE); - cert.set_serial_number(serial_number); - cert.set_provider_id(provider_id); - cert.set_public_key(public_key); - cert.set_creation_time_seconds(creation_time_seconds); - SignedDrmCertificate signed_cert; - cert.SerializeToString(signed_cert.mutable_drm_certificate()); - root_private_key_->GenerateSignature( - signed_cert.drm_certificate(), - HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()), - signed_cert.mutable_signature()); - std::string serialized_cert; - signed_cert.SerializeToString(&serialized_cert); - return serialized_cert; - } - - Status SetDefaultDrmServiceCertificate(const std::string& serial_number, - const std::string& provider_id, - uint32_t creation_time_seconds) { - std::string signed_cert(GenerateDrmServiceCertificate( - serial_number, provider_id, creation_time_seconds, - test_keys_.public_test_key_2_2048_bits())); - std::string encrypted_private_key; - if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( - test_keys_.private_test_key_2_2048_bits(), kPassphrase, - &encrypted_private_key)) { - return Status(error::INTERNAL, ""); - } - return DrmServiceCertificate::SetDefaultDrmServiceCertificate( - root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase); - } - - Status AddDrmServiceCertificate(const std::string& serial_number, - const std::string& provider_id, - uint32_t creation_time_seconds) { - std::string signed_cert(GenerateDrmServiceCertificate( - serial_number, provider_id, creation_time_seconds, - test_keys_.public_test_key_2_2048_bits())); - std::string encrypted_private_key; - if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( - test_keys_.private_test_key_2_2048_bits(), kPassphrase, - &encrypted_private_key)) { - return Status(error::INTERNAL, ""); - } - return DrmServiceCertificate::AddDrmServiceCertificate( - root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase); - } - - void EncryptClientIdentification( - const std::string& serial_number, const std::string& provider_id, - const std::string& public_key, - EncryptedClientIdentification* encrypted_client_id) { - CHECK(encrypted_client_id); - encrypted_client_id->set_provider_id(provider_id); - encrypted_client_id->set_service_certificate_serial_number(serial_number); - std::string serial_client_id; - client_id_.SerializeToString(&serial_client_id); - encrypted_client_id->set_encrypted_client_id( - crypto_util::EncryptAesCbc(privacy_key_, iv_, serial_client_id)); - encrypted_client_id->set_encrypted_client_id_iv(iv_); - std::unique_ptr rsa_key(RsaPublicKey::Create(public_key)); - ASSERT_TRUE(rsa_key.get()); - rsa_key->Encrypt(privacy_key_, - encrypted_client_id->mutable_encrypted_privacy_key()); - } - - RsaTestKeys test_keys_; - TestDrmCertificates test_certs_; - std::string privacy_key_; - std::string iv_; - std::unique_ptr root_private_key_; - std::unique_ptr root_cert_; - ClientIdentification client_id_; -}; - -TEST_F(DrmServiceCertificateTest, BasicClientIdDecrypt) { - std::string serial_number("serial_number"); - std::string provider_id("someservice.com"); - uint32_t creation_time_seconds(1234); - - EXPECT_OK(AddDrmServiceCertificate(serial_number, provider_id, - creation_time_seconds)); - EncryptedClientIdentification encrypted_client_id; - EncryptClientIdentification(serial_number, provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - ClientIdentification decrypted_client_id; - EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); -} - -TEST_F(DrmServiceCertificateTest, NoDefaultDrmServiceCertificate) { - ASSERT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate()); - const auto& get_default_sc_or_die = []() { - DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie(); - }; - EXPECT_DEATH(get_default_sc_or_die(), "Service Certificate not set!"); -} - -TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificates) { - std::string serial_number1("serial_number1"); - std::string provider_id1("someservice.com"); - uint32_t creation_time_seconds1(1234); - std::string serial_number2("serial_number2"); - uint32_t creation_time_seconds2(1234); - std::string serial_number3("serial_number3"); - std::string provider_id3("service3.com"); - uint32_t creation_time_seconds3(1235); - std::string bogus_serial_number("bogus-serial-number2"); - - EXPECT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate()); - - EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id1, - creation_time_seconds1)); - - // Expect this to pass because the serial number is allowed to change as long - // as the service Id is the same as before. - EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id1, - creation_time_seconds2)); - - EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id3, - creation_time_seconds3)); - - EncryptedClientIdentification encrypted_client_id; - EncryptClientIdentification(serial_number1, provider_id1, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - ClientIdentification decrypted_client_id; - EXPECT_OK(DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - EncryptClientIdentification(serial_number2, provider_id1, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - EXPECT_OK(DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - EncryptClientIdentification(bogus_serial_number, provider_id1, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - EXPECT_EQ(SERVICE_CERTIFICATE_NOT_FOUND, - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id) - .error_code()); -} - -TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificatesLookup) { - std::string serial_number1("serial_number1"); - std::string provider_id1("service1.com"); - uint32_t creation_time_seconds1(1231); - std::string serial_number2("serial_number2"); - std::string provider_id2("service2.com"); - uint32_t creation_time_seconds2(1232); - std::string serial_number3("serial_number3"); - std::string provider_id3("service3.com"); - uint32_t creation_time_seconds3(1234); - std::string serial_number4("serial_number4"); - std::string bogus_serial_number("bogus-serial-number"); - - EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id1, - creation_time_seconds1)); - EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id2, - creation_time_seconds2)); - EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id3, - creation_time_seconds3)); - - EXPECT_EQ(provider_id1, - DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber( - serial_number1) - ->provider_id()); - EXPECT_EQ(provider_id2, - DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber( - serial_number2) - ->provider_id()); - EXPECT_EQ(provider_id3, - DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber( - serial_number3) - ->provider_id()); - - EXPECT_EQ( - serial_number1, - DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id1) - ->serial_number()); - EXPECT_EQ( - serial_number2, - DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id2) - ->serial_number()); - EXPECT_EQ( - serial_number3, - DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id3) - ->serial_number()); - - // Add a second cert for provider 3. - EXPECT_OK(AddDrmServiceCertificate(serial_number4, provider_id3, - creation_time_seconds3 + 60)); - EXPECT_EQ( - serial_number4, - DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id3) - ->serial_number()); -} - -TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) { - std::string serial_number1("serial_number1"); - std::string serial_number2("serial_number2"); - std::string serial_number3("serial_number3"); - std::string serial_number4("serial_number4"); - std::string provider_id("someservice.com"); - uint32_t creation_time_seconds(1234); - - EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id, - creation_time_seconds)); - EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id, - creation_time_seconds + 1)); - EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id, - creation_time_seconds - 1)); - - EncryptedClientIdentification encrypted_client_id; - EncryptClientIdentification(serial_number1, provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - ClientIdentification decrypted_client_id; - EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - EncryptClientIdentification(serial_number2, provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - EncryptClientIdentification(serial_number3, provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - const DrmServiceCertificate* default_cert( - DrmServiceCertificate::GetDefaultDrmServiceCertificate()); - ASSERT_TRUE(default_cert); - SignedDrmCertificate signed_cert; - ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate())); - DrmCertificate drm_cert; - ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate())); - EXPECT_EQ(serial_number1, drm_cert.serial_number()); - - EXPECT_OK(SetDefaultDrmServiceCertificate(serial_number4, provider_id, - creation_time_seconds)); - default_cert = DrmServiceCertificate::GetDefaultDrmServiceCertificate(); - ASSERT_TRUE(default_cert); - ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate())); - ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate())); - EXPECT_EQ(serial_number4, drm_cert.serial_number()); -} - -TEST_F(DrmServiceCertificateTest, DrmServiceCertificateNotFound) { - std::string serial_number("serial_number"); - std::string provider_id("someservice.com"); - uint32_t creation_time_seconds(1234); - - EXPECT_OK(AddDrmServiceCertificate(serial_number, provider_id, - creation_time_seconds)); - EncryptedClientIdentification encrypted_client_id; - EncryptClientIdentification("invalid_serial_number", provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - ClientIdentification decrypted_client_id; - EXPECT_EQ(SERVICE_CERTIFICATE_NOT_FOUND, - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id) - .error_code()); -} - -TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) { - std::string serial_number("serial_number"); - std::string provider_id("someservice.com"); - uint32_t creation_time_seconds(1234); - - ASSERT_OK(AddDrmServiceCertificate(serial_number, provider_id, - creation_time_seconds)); - EncryptedClientIdentification encrypted_client_id; - EncryptClientIdentification(serial_number, provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - ClientIdentification decrypted_client_id; - ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - EncryptedClientIdentification invalid; - invalid = encrypted_client_id; - invalid.clear_encrypted_privacy_key(); - EXPECT_EQ( - "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " - "missing-encrypted-privacy-key", - DrmServiceCertificate::DecryptClientIdentification(invalid, - &decrypted_client_id) - .ToString()); - - invalid = encrypted_client_id; - ++(*invalid.mutable_encrypted_client_id_iv())[4]; - EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - invalid, &decrypted_client_id)); - - invalid.clear_encrypted_client_id_iv(); - EXPECT_EQ( - "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " - "missing-encrypted-client-id-iv", - DrmServiceCertificate::DecryptClientIdentification(invalid, - &decrypted_client_id) - .ToString()); - - invalid = encrypted_client_id; - ++(*invalid.mutable_encrypted_client_id())[0]; - EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - invalid, &decrypted_client_id)); - - invalid.clear_encrypted_client_id(); - EXPECT_EQ( - "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " - "missing-encrypted-client-id", - DrmServiceCertificate::DecryptClientIdentification(invalid, - &decrypted_client_id) - .ToString()); -} - -TEST_F(DrmServiceCertificateTest, PrivateKeyDecryptError) { - std::string serial_number("serial_number"); - std::string provider_id("someservice.com"); - uint32_t creation_time_seconds(1234); - - ASSERT_OK(AddDrmServiceCertificate(serial_number, provider_id, - creation_time_seconds)); - EncryptedClientIdentification encrypted_client_id; - EncryptClientIdentification(serial_number, provider_id, - test_keys_.public_test_key_2_2048_bits(), - &encrypted_client_id); - ClientIdentification decrypted_client_id; - ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &decrypted_client_id)); - ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, - decrypted_client_id)); - - EncryptedClientIdentification corrupted; - corrupted = encrypted_client_id; - ++(*corrupted.mutable_encrypted_privacy_key())[20]; - EXPECT_EQ( - "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " - "privacy-key-decryption-failed", - DrmServiceCertificate::DecryptClientIdentification(corrupted, - &decrypted_client_id) - .ToString()); -} - -// TODO(user): Add more unit tests for various fail cases (bad keys having -// to do with bad keys and bad certs). - -} // namespace widevine diff --git a/common/dual_certificate_client_cert.cc b/common/dual_certificate_client_cert.cc deleted file mode 100644 index ac7d7cd..0000000 --- a/common/dual_certificate_client_cert.cc +++ /dev/null @@ -1,113 +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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/dual_certificate_client_cert.h" - -#include "common/error_space.h" -#include "common/status.h" -#include "protos/public/errors.pb.h" - -namespace widevine { - -Status DualCertificateClientCert::Initialize( - const DrmRootCertificate* root_certificate, - const std::string& serialized_signing_certificate, - const std::string& serialized_encryption_certificate) { - Status status = signing_certificate_.Initialize( - root_certificate, serialized_signing_certificate); - if (!status.ok()) { - return status; - } - status = encryption_certificate_.Initialize( - root_certificate, serialized_encryption_certificate); - if (!status.ok()) { - return status; - } - if (encryption_certificate_.signer_serial_number() != - signing_certificate_.signer_serial_number()) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "certificate_signer_mismatch"); - } - if ((encryption_certificate_.system_id() != - signing_certificate_.system_id()) || - (encryption_certificate_.service_id() != - signing_certificate_.service_id()) || - (encryption_certificate_.signer_creation_time_seconds() != - signing_certificate_.signer_creation_time_seconds()) || - (encryption_certificate_.signed_by_provisioner() != - signing_certificate_.signed_by_provisioner())) { - return Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid_certificate_pair"); - } - return OkStatus(); -} - -Status DualCertificateClientCert::VerifySignature( - const std::string& message, HashAlgorithm hash_algorithm, - const std::string& signature, ProtocolVersion protocol_version) const { - return signing_certificate_.VerifySignature(message, hash_algorithm, - signature, protocol_version); -} - -void DualCertificateClientCert::GenerateSigningKey( - const std::string& message, ProtocolVersion protocol_version) { - encryption_certificate_.GenerateSigningKey(message, protocol_version); -} - -const std::string& DualCertificateClientCert::encrypted_key() const { - return encryption_certificate_.encrypted_key(); -} - -const std::string& DualCertificateClientCert::key() const { - return encryption_certificate_.key(); -} - -SignedMessage::SessionKeyType DualCertificateClientCert::key_type() const { - return encryption_certificate_.key_type(); -} - -// TODO(b/155979840): Support revocation check for the encryption certificate. -const std::string& DualCertificateClientCert::serial_number() const { - return signing_certificate_.serial_number(); -} - -const std::string& DualCertificateClientCert::service_id() const { - return signing_certificate_.service_id(); -} - -const std::string& DualCertificateClientCert::signing_key() const { - return encryption_certificate_.signing_key(); -} - -const std::string& DualCertificateClientCert::signer_serial_number() const { - return signing_certificate_.signer_serial_number(); -} - -uint32_t DualCertificateClientCert::signer_creation_time_seconds() const { - return signing_certificate_.signer_creation_time_seconds(); -} - -bool DualCertificateClientCert::signed_by_provisioner() const { - return signing_certificate_.signed_by_provisioner(); -} - -uint32_t DualCertificateClientCert::system_id() const { - return signing_certificate_.system_id(); -} - -// TODO(b/155979840): Support revocation check for the encryption certificate. -const std::string& DualCertificateClientCert::encrypted_unique_id() const { - return signing_certificate_.encrypted_unique_id(); -} - -// TODO(b/155979840): Support revocation check for the encryption certificate. -const std::string& DualCertificateClientCert::unique_id_hash() const { - return signing_certificate_.unique_id_hash(); -} - -} // namespace widevine diff --git a/common/dual_certificate_client_cert.h b/common/dual_certificate_client_cert.h deleted file mode 100644 index 306c2d2..0000000 --- a/common/dual_certificate_client_cert.h +++ /dev/null @@ -1,57 +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. -//////////////////////////////////////////////////////////////////////////////// - -#ifndef COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_ -#define COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_ - -#include "common/certificate_client_cert.h" - -namespace widevine { - -class DualCertificateClientCert : public ClientCert { - public: - DualCertificateClientCert() = default; - ~DualCertificateClientCert() override = default; - DualCertificateClientCert(const DualCertificateClientCert&) = delete; - DualCertificateClientCert& operator=(const DualCertificateClientCert&) = - delete; - - Status Initialize(const DrmRootCertificate* root_certificate, - const std::string& serialized_signing_certificate, - const std::string& serialized_encryption_certificate); - Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature, - ProtocolVersion protocol_version) const override; - void GenerateSigningKey(const std::string& message, - ProtocolVersion protocol_version) override; - - const std::string& encrypted_key() const override; - const std::string& key() const override; - SignedMessage::SessionKeyType key_type() const override; - bool using_dual_certificate() const override { return true; } - const std::string& serial_number() const override; - const std::string& service_id() const override; - const std::string& signing_key() const override; - const std::string& signer_serial_number() const override; - uint32_t signer_creation_time_seconds() const override; - bool signed_by_provisioner() const override; - uint32_t system_id() const override; - widevine::ClientIdentification::TokenType type() const override { - return ClientIdentification::DRM_DEVICE_CERTIFICATE; - } - const std::string& encrypted_unique_id() const override; - const std::string& unique_id_hash() const override; - - private: - CertificateClientCert signing_certificate_; - CertificateClientCert encryption_certificate_; -}; - -} // namespace widevine -#endif // COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_ diff --git a/common/ec_key.cc b/common/ec_key.cc index 0b16c75..b5b4684 100644 --- a/common/ec_key.cc +++ b/common/ec_key.cc @@ -143,39 +143,6 @@ bool ECPrivateKey::DeriveSharedSessionKey( return true; } -bool ECPrivateKey::GenerateSignature(const std::string& message, - std::string* signature) const { - if (message.empty()) { - LOG(ERROR) << "|message| cannot be empty"; - return false; - } - if (signature == nullptr) { - LOG(ERROR) << "|signature| cannot be nullptr"; - return false; - } - std::string message_digest = Sha256_Hash(message); - size_t max_signature_size = ECDSA_size(key()); - if (max_signature_size == 0) { - LOG(ERROR) << "key_ does not have a group set"; - return false; - } - signature->resize(max_signature_size); - unsigned int bytes_written = 0; - int result = ECDSA_sign( - 0 /* unused type */, - reinterpret_cast(message_digest.data()), - message_digest.size(), - reinterpret_cast(const_cast(signature->data())), - &bytes_written, key()); - if (result != 1) { - LOG(ERROR) << "Could not calculate signature: " - << OpenSSLErrorString(ERR_get_error()); - return false; - } - signature->resize(bytes_written); - return true; -} - bool ECPrivateKey::GenerateSignature(const std::string& message, HashAlgorithm hash_algorithm, std::string* signature) const { @@ -287,31 +254,6 @@ std::unique_ptr ECPublicKey::CreateFromKeyPoint( return absl::make_unique(scoped_ec_key.release()); } -bool ECPublicKey::VerifySignature(const std::string& message, - const std::string& signature) const { - if (message.empty()) { - LOG(ERROR) << "|message| cannot be empty"; - return false; - } - if (signature.empty()) { - LOG(ERROR) << "|signature| cannot be empty"; - return false; - } - std::string message_digest = Sha256_Hash(message); - int result = ECDSA_verify( - 0 /* unused type */, - reinterpret_cast(message_digest.data()), - message_digest.size(), - reinterpret_cast(const_cast(signature.data())), - signature.size(), key()); - if (result != 1) { - LOG(ERROR) << "Could not verify signature: " - << OpenSSLErrorString(ERR_get_error()); - return false; - } - return true; -} - bool ECPublicKey::VerifySignature(const std::string& message, HashAlgorithm hash_algorithm, const std::string& signature) const { diff --git a/common/ec_key.h b/common/ec_key.h index e000f53..57a74ea 100644 --- a/common/ec_key.h +++ b/common/ec_key.h @@ -61,19 +61,6 @@ class ECPrivateKey { const ECPublicKey& public_key, std::string* derived_shared_session_key) const; - // Given a message, calculates a signature using ECDSA with the key_. - // |message| is the message to be signed. - // |signature| will contain the resulting signature. This will be an ASN.1 - // DER-encoded signature. - // Caller retains ownership of all pointers. - // Returns true on success and false on error. - // TODO(b/155438325): remove this function after the below function is fully - // propagated. - ABSL_DEPRECATED( - "Use the below function with |hash_algorithm| argument instead.") - virtual bool GenerateSignature(const std::string& message, - std::string* signature) const; - // Given a message, calculates a signature using ECDSA with the key_. // |message| is the message to be signed. // |hash_algorithm| specifies the hash algorithm. @@ -122,18 +109,6 @@ class ECPublicKey { static std::unique_ptr CreateFromKeyPoint( ECPrivateKey::EllipticCurve curve, const std::string& key_point); - // Given a message and a signature, verifies that the signature was created - // using the private key associated with key_. - // |message| is the message that was signed. - // |signature| is an ASN.1 DER-encoded signature. - // Returns true on success and false on error. - // TODO(b/155438325): remove this function after the below function is fully - // propagated. - ABSL_DEPRECATED( - "Use the below function with |hash_algorithm| argument instead.") - virtual bool VerifySignature(const std::string& message, - const std::string& signature) const; - // Given a message and a signature, verifies that the signature was created // using the private key associated with key_. // |message| is the message that was signed. diff --git a/common/ec_key_source.h b/common/ec_key_source.h deleted file mode 100644 index e0333a3..0000000 --- a/common/ec_key_source.h +++ /dev/null @@ -1,43 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Declaration for abstract EC key generation class. - -#ifndef COMMON_EC_KEY_SOURCE_H_ -#define COMMON_EC_KEY_SOURCE_H_ - -#include - -#include "common/ec_key.h" - -namespace widevine { - -class ECKeySource { - public: - ECKeySource() = default; - virtual ~ECKeySource() = default; - - // Get an EC key pair given a specific curve defined by EllipticCurve. - // Parameter |curve| is a standard curve which defines the parameters of the - // key generation. - // Parameter |private_key| is the serialized EC private key. - // Parameter |public_key| is the serialized EC public key. - // Caller retains ownership of all pointers and they cannot be nullptr. - // Returns true if successful, false otherwise. - virtual bool GetECKey(ECPrivateKey::EllipticCurve curve, - std::string* private_key, std::string* public_key) = 0; - - private: - ECKeySource(const ECKeySource&) = delete; - ECKeySource& operator=(const ECKeySource&) = delete; -}; - -} // namespace widevine - -#endif // COMMON_EC_KEY_SOURCE_H_ diff --git a/common/ec_key_test.cc b/common/ec_key_test.cc deleted file mode 100644 index ec6fcdc..0000000 --- a/common/ec_key_test.cc +++ /dev/null @@ -1,315 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Unit tests for the ECPrivateKey and ECPublicKey classes. - -#include "common/ec_key.h" - -#include -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "openssl/sha.h" -#include "common/ec_test_keys.h" -#include "common/ec_util.h" -#include "common/random_util.h" - -using ::testing::IsNull; - -namespace widevine { - -class ECKeyTest : public ::testing::Test { - public: - static std::vector > GetTestKeyList() { - std::vector > test_key_list; - ECTestKeys test_keys; - test_key_list.push_back( - std::make_tuple(test_keys.private_test_key_1_secp521r1(), - test_keys.public_test_key_1_secp521r1())); - test_key_list.push_back( - std::make_tuple(test_keys.private_test_key_1_secp384r1(), - test_keys.public_test_key_1_secp384r1())); - test_key_list.push_back( - std::make_tuple(test_keys.private_test_key_1_secp256r1(), - test_keys.public_test_key_1_secp256r1())); - return test_key_list; - } - - protected: - ECKeyTest() { plaintext_message_ = "This is a plaintext message."; } - - void GenerateEphemeralKeyPair(ECPrivateKey::EllipticCurve curve) { - ASSERT_NE(curve, ECPrivateKey::UNDEFINED_CURVE); - bssl::UniquePtr ephemeral_key_pair( - EC_KEY_new_by_curve_name(ec_util::CurveToNid(curve))); - ASSERT_TRUE(ephemeral_key_pair != nullptr); - ASSERT_TRUE(EC_KEY_generate_key(ephemeral_key_pair.get())); - // Separate them out into their private and public parts. - std::string private_key; - std::string public_key; - ASSERT_TRUE( - ec_util::SerializeECPrivateKey(ephemeral_key_pair.get(), &private_key)); - ASSERT_TRUE( - ec_util::SerializeECPublicKey(ephemeral_key_pair.get(), &public_key)); - ephemeral_private_key_ = ECPrivateKey::Create(private_key); - ephemeral_public_key_ = ECPublicKey::Create(public_key); - } - - std::unique_ptr ephemeral_private_key_; - std::unique_ptr ephemeral_public_key_; - std::string plaintext_message_; -}; - -TEST_F(ECKeyTest, KeyCurve) { - ECTestKeys test_keys; - EXPECT_EQ( - ECPrivateKey::Create(test_keys.private_test_key_1_secp521r1())->Curve(), - ECPrivateKey::SECP521R1); - EXPECT_EQ( - ECPrivateKey::Create(test_keys.private_test_key_1_secp384r1())->Curve(), - ECPrivateKey::SECP384R1); - EXPECT_EQ( - ECPrivateKey::Create(test_keys.private_test_key_1_secp256r1())->Curve(), - ECPrivateKey::SECP256R1); - - EXPECT_EQ( - ECPublicKey::Create(test_keys.public_test_key_1_secp521r1())->Curve(), - ECPrivateKey::SECP521R1); - EXPECT_EQ( - ECPublicKey::Create(test_keys.public_test_key_1_secp384r1())->Curve(), - ECPrivateKey::SECP384R1); - EXPECT_EQ( - ECPublicKey::Create(test_keys.public_test_key_1_secp256r1())->Curve(), - ECPrivateKey::SECP256R1); -} - -TEST_F(ECKeyTest, KeyPointEncodingNullDeath) { - EXPECT_DEATH(ephemeral_public_key_->GetPointEncodedKey(nullptr), ""); -} - -class ECKeyTestKeyPairs : public ECKeyTest, - public ::testing::WithParamInterface< - std::tuple > { - protected: - ECKeyTestKeyPairs() { - test_private_key_ = std::get<0>(GetParam()); - test_public_key_ = std::get<1>(GetParam()); - private_key_ = ECPrivateKey::Create(test_private_key_); - public_key_ = ECPublicKey::Create(test_public_key_); - } - - std::string test_private_key_; - std::string test_public_key_; - std::unique_ptr private_key_; - std::unique_ptr public_key_; -}; - -// Death test naming convention. See below link for details: -// go/gunitadvanced#death-test-naming -using ECKeyTestKeyPairsDeathTest = ECKeyTestKeyPairs; - -TEST_P(ECKeyTestKeyPairs, CreateWrongKey) { - EXPECT_EQ(ECPrivateKey::Create(test_public_key_), nullptr); - EXPECT_EQ(ECPublicKey::Create(test_private_key_), nullptr); -} - -TEST_P(ECKeyTestKeyPairs, InvalidKeyConstructorParameters) { - EXPECT_DEATH(ECPrivateKey(nullptr), ""); - EXPECT_DEATH(ECPublicKey(nullptr), ""); - - EC_KEY* key; - ASSERT_TRUE(ec_util::DeserializeECPrivateKey(test_private_key_, &key)); - // Brace initialization to avoid most vexing parse. - EXPECT_DEATH(ECPublicKey{key}, ""); - EC_KEY_free(key); - - ASSERT_TRUE(ec_util::DeserializeECPublicKey(test_public_key_, &key)); - EXPECT_DEATH(ECPrivateKey{key}, ""); - EC_KEY_free(key); -} - -TEST_P(ECKeyTestKeyPairs, KeyMatch) { - EXPECT_TRUE(private_key_->MatchesPrivateKey(*private_key_)); - EXPECT_TRUE(private_key_->MatchesPublicKey(*public_key_)); - EXPECT_TRUE(public_key_->MatchesPrivateKey(*private_key_)); - EXPECT_TRUE(public_key_->MatchesPublicKey(*public_key_)); -} - -TEST_P(ECKeyTestKeyPairs, DeriveSharedSessionKey) { - std::string derived_shared_session_key_1; - // Generate a temporary key pair as part of ECDH. - GenerateEphemeralKeyPair(private_key_->Curve()); - EXPECT_TRUE(private_key_->DeriveSharedSessionKey( - *ephemeral_public_key_, &derived_shared_session_key_1)); - EXPECT_EQ(derived_shared_session_key_1.size(), SHA256_DIGEST_LENGTH); - std::string derived_shared_session_key_2; - EXPECT_TRUE(ephemeral_private_key_->DeriveSharedSessionKey( - *public_key_, &derived_shared_session_key_2)); - EXPECT_EQ(derived_shared_session_key_1, derived_shared_session_key_2); -} - -TEST_P(ECKeyTestKeyPairs, InvalidDeriveSharedSessionKeyParameters) { - GenerateEphemeralKeyPair(private_key_->Curve()); - EXPECT_FALSE( - private_key_->DeriveSharedSessionKey(*ephemeral_public_key_, nullptr)); - EXPECT_FALSE( - ephemeral_private_key_->DeriveSharedSessionKey(*public_key_, nullptr)); -} - -TEST_P(ECKeyTestKeyPairs, SignVerify) { - std::string signature; - EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature)); - EXPECT_TRUE(public_key_->VerifySignature(plaintext_message_, signature)); -} - -TEST_P(ECKeyTestKeyPairs, SignVerifySha1) { - std::string signature; - EXPECT_FALSE(private_key_->GenerateSignature( - plaintext_message_, HashAlgorithm::kSha1, &signature)); - EXPECT_FALSE(public_key_->VerifySignature(plaintext_message_, - HashAlgorithm::kSha1, signature)); -} - -TEST_P(ECKeyTestKeyPairs, SignVerifySha256) { - std::string signature; - ASSERT_TRUE(private_key_->GenerateSignature( - plaintext_message_, HashAlgorithm::kSha256, &signature)); - ASSERT_TRUE(public_key_->VerifySignature(plaintext_message_, - HashAlgorithm::kSha256, signature)); -} - -TEST_P(ECKeyTestKeyPairs, SignVerifyUnspecified) { - std::string signature; - ASSERT_TRUE(private_key_->GenerateSignature( - plaintext_message_, HashAlgorithm::kUnspecified, &signature)); - ASSERT_TRUE(public_key_->VerifySignature( - plaintext_message_, HashAlgorithm::kUnspecified, signature)); -} - -TEST_P(ECKeyTestKeyPairsDeathTest, SignVerifyUnexpected) { - std::string signature; - HashAlgorithm unexpected_hash_algorithm = static_cast(1234); - EXPECT_DEATH(private_key_->GenerateSignature( - plaintext_message_, unexpected_hash_algorithm, &signature), - "Unexpected hash algorithm: 1234"); - EXPECT_FALSE(public_key_->VerifySignature( - plaintext_message_, unexpected_hash_algorithm, signature)); -} - -TEST_P(ECKeyTestKeyPairs, InvalidSignVerifyParameters) { - std::string signature; - EXPECT_FALSE(private_key_->GenerateSignature("", &signature)); - EXPECT_FALSE(public_key_->VerifySignature("", "signature")); - EXPECT_FALSE(private_key_->GenerateSignature(plaintext_message_, nullptr)); - EXPECT_FALSE(public_key_->VerifySignature(plaintext_message_, "")); -} - -TEST_P(ECKeyTestKeyPairs, KeyMismatch) { - GenerateEphemeralKeyPair(private_key_->Curve()); - EXPECT_FALSE(private_key_->MatchesPrivateKey(*ephemeral_private_key_)); - EXPECT_FALSE(private_key_->MatchesPublicKey(*ephemeral_public_key_)); - EXPECT_FALSE(public_key_->MatchesPrivateKey(*ephemeral_private_key_)); - EXPECT_FALSE(public_key_->MatchesPublicKey(*ephemeral_public_key_)); -} - -TEST_P(ECKeyTestKeyPairs, SignVerifyKeyMismatch) { - std::string signature; - GenerateEphemeralKeyPair(private_key_->Curve()); - EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature)); - EXPECT_FALSE( - ephemeral_public_key_->VerifySignature(plaintext_message_, signature)); -} - -TEST_P(ECKeyTestKeyPairs, KeyPointEncodingCreateBadKeyPoint) { - ASSERT_THAT(ECPublicKey::CreateFromKeyPoint(public_key_->Curve(), ""), - IsNull()); -} - -TEST_P(ECKeyTestKeyPairs, KeyPointEncodingCreateBadCurve) { - std::string serialized_key_point; - ASSERT_TRUE(public_key_->GetPointEncodedKey(&serialized_key_point)); - ASSERT_THAT(ECPublicKey::CreateFromKeyPoint(ECPrivateKey::UNDEFINED_CURVE, - serialized_key_point), - IsNull()); -} - -TEST_P(ECKeyTestKeyPairs, KeyPointEncodingSuccess) { - std::string serialized_key_point; - ASSERT_TRUE(public_key_->GetPointEncodedKey(&serialized_key_point)); - ASSERT_EQ(ec_util::GetPublicKeyPointSize(public_key_->Curve()), - serialized_key_point.size()); - // Check that the leading byte indicates uncompressed. - ASSERT_EQ(4, serialized_key_point[0]); - - std::unique_ptr new_public_key = ECPublicKey::CreateFromKeyPoint( - public_key_->Curve(), serialized_key_point); - ASSERT_THAT(new_public_key, testing::NotNull()); - EXPECT_TRUE(new_public_key->MatchesPublicKey(*public_key_)); - EXPECT_TRUE(new_public_key->MatchesPrivateKey(*private_key_)); -}; - -INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairs, ECKeyTestKeyPairs, - ::testing::ValuesIn(ECKeyTest::GetTestKeyList())); - -INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairsDeathTest, ECKeyTestKeyPairsDeathTest, - ::testing::ValuesIn(ECKeyTest::GetTestKeyList())); - -class ECKeyTestCurveMismatch - : public ECKeyTest, - public ::testing::WithParamInterface< - std::tuple, - std::tuple > > { - protected: - ECKeyTestCurveMismatch() { - private_key_ = ECPrivateKey::Create(std::get<0>(std::get<0>(GetParam()))); - public_key_ = ECPublicKey::Create(std::get<1>(std::get<0>(GetParam()))); - wrong_curve_private_key_ = - ECPrivateKey::Create(std::get<0>(std::get<1>(GetParam()))); - wrong_curve_public_key_ = - ECPublicKey::Create(std::get<1>(std::get<1>(GetParam()))); - } - - void SetUp() override { - // Only run combinations where the two curves differ. - if (std::get<0>(GetParam()) == std::get<1>(GetParam())) GTEST_SKIP(); - } - - std::unique_ptr private_key_; - std::unique_ptr public_key_; - std::unique_ptr wrong_curve_private_key_; - std::unique_ptr wrong_curve_public_key_; -}; - -TEST_P(ECKeyTestCurveMismatch, CurveMismatch) { - EXPECT_FALSE(private_key_->MatchesPrivateKey(*wrong_curve_private_key_)); - EXPECT_FALSE(private_key_->MatchesPublicKey(*wrong_curve_public_key_)); - EXPECT_FALSE(public_key_->MatchesPrivateKey(*wrong_curve_private_key_)); - EXPECT_FALSE(public_key_->MatchesPublicKey(*wrong_curve_public_key_)); -} - -TEST_P(ECKeyTestCurveMismatch, DeriveSharedSessionKeyCurveMismatch) { - std::string derived_shared_session_key; - EXPECT_FALSE(private_key_->DeriveSharedSessionKey( - *wrong_curve_public_key_, &derived_shared_session_key)); -} - -TEST_P(ECKeyTestCurveMismatch, SignVerifyCurveMismatch) { - std::string signature; - EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature)); - EXPECT_FALSE( - wrong_curve_public_key_->VerifySignature(plaintext_message_, signature)); -} - -INSTANTIATE_TEST_SUITE_P( - ECKeyTestCurveMismatch, ECKeyTestCurveMismatch, - ::testing::Combine(::testing::ValuesIn(ECKeyTest::GetTestKeyList()), - ::testing::ValuesIn(ECKeyTest::GetTestKeyList()))); - -} // namespace widevine diff --git a/common/ec_util_test.cc b/common/ec_util_test.cc deleted file mode 100644 index e19ea0f..0000000 --- a/common/ec_util_test.cc +++ /dev/null @@ -1,202 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Unit tests for ec_util. - -#include "common/ec_util.h" - -#include - -#include - -#include "glog/logging.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "common/ec_test_keys.h" -#include "common/openssl_util.h" - -namespace widevine { -namespace ec_util { - -class ECUtilTest : public ::testing::Test { - protected: - ECTestKeys test_keys_; - - // Given serialization and deserialization methods for an EC_KEY and a test - // key, this checks that that those methods can deserialize to a valid EC_KEY - // and serialize to the same test key. - template - void SerializeDeserializeECKeyCheck(const std::string& test_key) { - EC_KEY* key = nullptr; - std::string serialized_key; - EXPECT_TRUE(DeserializeECKey(test_key, &key)); - ASSERT_TRUE(key != nullptr); - EXPECT_TRUE(SerializeECKey(key, &serialized_key)); - EXPECT_EQ(serialized_key, test_key); - EXPECT_EQ(EC_KEY_check_key(key), 1); - EC_KEY_free(key); - } - - // Given serialization and deserialization methods for an EC_KEY and a test - // key, this method checks that deserialization fails for a bad input std::string - // and both serialization and deserialization fail on nullptrs. - template - void SerializeDeserializeECKeyValidateInput(const std::string& test_key) { - EC_KEY* key = nullptr; - // Invalid key - EXPECT_FALSE(DeserializeECKey("this is a bad key", &key)); - EXPECT_EQ(key, nullptr); - // Invalid pointers - EXPECT_TRUE(DeserializeECKey(test_key, &key)); - EXPECT_FALSE(SerializeECKey(key, nullptr)); - EC_KEY_free(key); - EXPECT_FALSE(DeserializeECKey(test_key, nullptr)); - } -}; - -TEST_F(ECUtilTest, SerializeDeserializePrivateKey) { - SerializeDeserializeECKeyCheck( - test_keys_.private_test_key_1_secp521r1()); - SerializeDeserializeECKeyCheck( - test_keys_.private_test_key_1_secp384r1()); - SerializeDeserializeECKeyCheck( - test_keys_.private_test_key_1_secp256r1()); - SerializeDeserializeECKeyValidateInput( - test_keys_.private_test_key_1_secp521r1()); -} - -TEST_F(ECUtilTest, SerializeDeserializePublicKey) { - SerializeDeserializeECKeyCheck( - test_keys_.public_test_key_1_secp521r1()); - SerializeDeserializeECKeyCheck( - test_keys_.public_test_key_1_secp384r1()); - SerializeDeserializeECKeyCheck( - test_keys_.public_test_key_1_secp256r1()); - SerializeDeserializeECKeyValidateInput( - test_keys_.public_test_key_1_secp521r1()); -} - -TEST_F(ECUtilTest, PublicKeyExtraction) { - EC_KEY* private_key = nullptr; - std::string serialized_public_key; - // Key 1 - EXPECT_TRUE(DeserializeECPrivateKey(test_keys_.private_test_key_1_secp521r1(), - &private_key)); - ASSERT_TRUE(private_key != nullptr); - EXPECT_TRUE(SerializeECPublicKey(private_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_secp521r1()); - EC_KEY_free(private_key); - private_key = nullptr; - // Key 2 - EXPECT_TRUE(DeserializeECPrivateKey(test_keys_.private_test_key_1_secp384r1(), - &private_key)); - ASSERT_TRUE(private_key != nullptr); - EXPECT_TRUE(SerializeECPublicKey(private_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_secp384r1()); - EC_KEY_free(private_key); - private_key = nullptr; - // Key 3 - EXPECT_TRUE(DeserializeECPrivateKey(test_keys_.private_test_key_1_secp256r1(), - &private_key)); - ASSERT_TRUE(private_key != nullptr); - EXPECT_TRUE(SerializeECPublicKey(private_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_secp256r1()); - EC_KEY_free(private_key); -} - -TEST_F(ECUtilTest, GetPublicKeyPointSizeAll) { - ASSERT_GT(ec_util::GetPublicKeyPointSize(ECPrivateKey::SECP256R1), 0); - ASSERT_GT(ec_util::GetPublicKeyPointSize(ECPrivateKey::SECP384R1), 0); - ASSERT_GT(ec_util::GetPublicKeyPointSize(ECPrivateKey::SECP521R1), 0); - - ASSERT_EQ(0, ec_util::GetPublicKeyPointSize(ECPrivateKey::UNDEFINED_CURVE)); -} - -TEST_F(ECUtilTest, GetPublicKeyFromKeyPointDeath) { - EXPECT_DEATH(GetPublicKeyFromKeyPoint(ECPrivateKey::SECP256R1, "", nullptr), - ""); -} - -class ECKeyPointTest : public ::testing::Test, - public ::testing::WithParamInterface { - public: - static std::vector GetTestKeyList() { - ECTestKeys test_keys; - return {test_keys.public_test_key_1_secp256r1(), - test_keys.public_test_key_1_secp384r1(), - test_keys.public_test_key_1_secp521r1()}; - } - - void SetUp() override { - serialized_public_key_ = GetParam(); - - EC_KEY* public_key = nullptr; - ASSERT_TRUE(DeserializeECPublicKey(serialized_public_key_, &public_key)); - ASSERT_TRUE(public_key != nullptr); - ec_public_key_.reset(public_key); - - curve_ = NidToCurve( - EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_public_key_.get()))); - } - - protected: - std::string serialized_public_key_; - ScopedECKEY ec_public_key_; - ECPrivateKey::EllipticCurve curve_; -}; - -INSTANTIATE_TEST_SUITE_P(ECUtilKeyPointTest, ECKeyPointTest, - ::testing::ValuesIn(ECKeyPointTest::GetTestKeyList())); - -TEST_P(ECKeyPointTest, GetPublicKeyPointDeath) { - EXPECT_DEATH(GetPublicKeyPoint(ec_public_key_.get(), nullptr), ""); -} - -TEST_P(ECKeyPointTest, GetPublicKeyFromKeyPointInvalidCurve) { - std::string encoded_key; - ASSERT_TRUE(GetPublicKeyPoint(ec_public_key_.get(), &encoded_key)); - EC_KEY* new_public_key = nullptr; - EXPECT_FALSE(GetPublicKeyFromKeyPoint(ECPrivateKey::UNDEFINED_CURVE, - encoded_key, &new_public_key)); -} - -TEST_P(ECKeyPointTest, GetPublicKeyFromKeyPointInvalidSize) { - EC_KEY* new_public_key = nullptr; - EXPECT_FALSE(GetPublicKeyFromKeyPoint(curve_, "", &new_public_key)); -} - -TEST_P(ECKeyPointTest, PublicKeyPointFormatTest) { - std::string encoded_key; - ASSERT_TRUE(GetPublicKeyPoint(ec_public_key_.get(), &encoded_key)); - ASSERT_FALSE(encoded_key.empty()); - EXPECT_EQ(4, encoded_key[0]); - EXPECT_EQ(GetPublicKeyPointSize(curve_), encoded_key.size()); - - // Create a new EC key from the key point. - EC_KEY* ec_key = nullptr; - ASSERT_TRUE(GetPublicKeyFromKeyPoint(curve_, encoded_key, &ec_key)); - ASSERT_TRUE(ec_key != nullptr); - ScopedECKEY new_public_key(ec_key); - - // EC_POINT_cmp returns 0 if the keys match. - ASSERT_EQ( - 0, EC_POINT_cmp(EC_KEY_get0_group(ec_public_key_.get()), - EC_KEY_get0_public_key(ec_public_key_.get()), - EC_KEY_get0_public_key(new_public_key.get()), nullptr)); -} - -} // namespace ec_util -} // namespace widevine diff --git a/common/ecb_util.cc b/common/ecb_util.cc deleted file mode 100644 index 799b9c3..0000000 --- a/common/ecb_util.cc +++ /dev/null @@ -1,117 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Implementation of ecb crypto routines used by Widevine services. - -#include "common/ecb_util.h" - -#include "glog/logging.h" -#include "absl/strings/string_view.h" -#include "openssl/aes.h" -#include "openssl/des.h" - -namespace widevine { -namespace crypto_util { - -const int kWvmDESKeySizeBytes = 16; - -static bool EncryptOrDecrypt3DesCbc(absl::string_view key, - absl::string_view src, std::string* dst, - bool encrypt) { - CHECK(dst); - if (key.size() != kWvmDESKeySizeBytes) { - LOG(WARNING) << "Invalid 3DES key size (" << key.size() << "!=16)."; - dst->clear(); - return false; - } - const int data_size = src.size(); - if (data_size % DES_KEY_SZ != 0) { - // Data must be a multiple of block size - LOG(WARNING) << "3DES data is not a multiple of 8 bytes."; - dst->clear(); - return false; - } - const int data_size_blocks = data_size / DES_KEY_SZ; - DES_key_schedule schedule[2]; - // const_DES_cblock (the type of the first argument to DES_ecb3_encrypt) isn't - // actually const, so we have to cast away const. - DES_cblock* keyblock = - const_cast(reinterpret_cast(key.data())); - DES_set_key(keyblock + 0, schedule + 1); - DES_set_key(keyblock + 1, schedule + 0); - DES_cblock* srcblock = - const_cast(reinterpret_cast(src.data())); - dst->resize(data_size); - DES_cblock* dstblock = reinterpret_cast(&*dst->begin()); - for (int i = 0; i < data_size_blocks; i++) { - DES_ecb3_encrypt(srcblock + i, dstblock + i, schedule + 0, schedule + 1, - schedule + 0, encrypt); - } - return true; -} - -bool Encrypt3DesEcb(absl::string_view key, absl::string_view src, - std::string* dst) { - return EncryptOrDecrypt3DesCbc(key, src, dst, DES_ENCRYPT); -} - -bool Decrypt3DesEcb(absl::string_view key, absl::string_view src, - std::string* dst) { - return EncryptOrDecrypt3DesCbc(key, src, dst, DES_DECRYPT); -} - -bool EncryptAesEcb(absl::string_view key, absl::string_view src, - std::string* dst) { - CHECK(dst); - dst->clear(); - if (src.size() % 16 != 0) { - LOG(WARNING) << "AES-ECB data is not a multiple of 16 bytes."; - return false; - } - int num_bits = key.size() * 8; - AES_KEY aes_key; - int aes_result = AES_set_encrypt_key( - reinterpret_cast(key.data()), num_bits, &aes_key); - if (aes_result != 0) { - LOG(WARNING) << "AES result is not zero."; - return false; - } - dst->resize(src.size()); - for (int i = 0; i < src.size(); i += AES_BLOCK_SIZE) { - AES_encrypt(reinterpret_cast(src.data() + i), - reinterpret_cast(&(*dst)[i]), &aes_key); - } - return true; -} - -bool DecryptAesEcb(absl::string_view key, absl::string_view src, - std::string* dst) { - CHECK(dst); - dst->clear(); - if (src.size() % 16 != 0) { - LOG(WARNING) << "AES-ECB data is not a multiple of 16 bytes."; - return false; - } - int num_bits = key.size() * 8; - AES_KEY aes_key; - int aes_result = AES_set_decrypt_key( - reinterpret_cast(key.data()), num_bits, &aes_key); - if (aes_result != 0) { - LOG(WARNING) << "AES result is not zero."; - return false; - } - dst->resize(src.size()); - for (int i = 0; i < src.size(); i += AES_BLOCK_SIZE) { - AES_decrypt(reinterpret_cast(src.data() + i), - reinterpret_cast(&(*dst)[i]), &aes_key); - } - return true; -} - -} // namespace crypto_util -} // namespace widevine diff --git a/common/ecb_util.h b/common/ecb_util.h deleted file mode 100644 index ecbbbd4..0000000 --- a/common/ecb_util.h +++ /dev/null @@ -1,63 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Contains ecb crypto routines for widevine protocols. These routines are used -// as part of licensing and provisioning request handling. - -#ifndef COMMON_ECB_UTIL_H_ -#define COMMON_ECB_UTIL_H_ - -#include - -#include "absl/strings/string_view.h" - -namespace widevine { -namespace crypto_util { - -// Encrypts |src| into |dst| using 3DES ECB2 mode with the given key. This is -// used for protecting content keys on some older Widevine keyboxes, and is not -// intended for any other purpose. Returns false and sets *|dst|="" if -// unsuccessful. Key should be 16 bytes. The first 8 are key2 of the 3DES key -// bundle, and the last 8 bytes are key1 and key3. |src| must be a multiple of -// 8 bytes. -bool Encrypt3DesEcb(absl::string_view key, absl::string_view src, - std::string* dst); - -// Decrypts |src| into |dst| using 3DES ECB2 mode with the given (16-byte) -// key. This is used for protecting content keys on some older Widevine -// keyboxes, and is not intended for any other purpose. -// Returns false and sets *|dst|="" if unsuccessful. Note that it can only -// fail if invalid key or data sizes are passed in. -// Key should be 16 bytes. The first 8 are key2 of the 3DES key bundle, -// and the last 8 bytes are key1 and key3. |src| must be a multiple of -// 8 bytes. -bool Decrypt3DesEcb(absl::string_view key, absl::string_view src, - std::string* dst); - -// Encrypts |src| into |dst| using AES ECB mode with the given -// key. This is used for protecting content keys on Widevine devices, -// and is not intended for any other purpose. -// Returns false and sets *|dst|="" if unsuccessful. Note that it can only -// fail if invalid key or data sizes are passed in. -// Key must be 16 bytes, and src must be a multiple of 16 bytes. -bool EncryptAesEcb(absl::string_view key, absl::string_view src, - std::string* dst); - -// Decrypts |src| into |dst| using AES ECB mode with the given -// key. This is used for protecting content keys on Widevine devices, -// and is not intended for any other purpose. -// Returns false and sets *|dst|="" if unsuccessful. Note that it can only -// fail if invalid key or data sizes are passed in. -// Key must be 16 bytes, and src must be a multiple of 16 bytes. -bool DecryptAesEcb(absl::string_view key, absl::string_view src, - std::string* dst); - -} // namespace crypto_util -} // namespace widevine - -#endif // COMMON_ECB_UTIL_H_ diff --git a/common/ecb_util_test.cc b/common/ecb_util_test.cc deleted file mode 100644 index 40285b8..0000000 --- a/common/ecb_util_test.cc +++ /dev/null @@ -1,90 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Unit tests for the ecb_util functions. - -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "common/ecb_util.h" - -namespace widevine { -namespace crypto_util { - -TEST(CryptoUtilTest, TestEncrypt3DesEcb) { - // Test vector generated by (Python): - // c = M2Crypto.EVP.Cipher('des_ede3_ecb', '89abcdef0123456789abcdef', - // iv='', op=1, padding=False) - // (c.update('This is a test message. ')+c.final()).encode('hex') - // TODO(user): find some Widevine test vectors and use those - std::string key = "0123456789abcdef"; - std::string plain = "This is a test message. "; - std::string cipher; - std::string decrypted; - EXPECT_TRUE(Encrypt3DesEcb(key, plain, &cipher)); - EXPECT_EQ("ae7c7accaf99a973e7f89bb7f6dc61a9aa9e226a5ba17376", - absl::BytesToHexString(cipher)); - EXPECT_TRUE(Decrypt3DesEcb(key, cipher, &decrypted)); - EXPECT_EQ(plain, decrypted); -} - -TEST(CryptoUtilTest, TestEncrypt3DesEcbFail) { - // Verify that 3DES fails with invalid key or data size - std::string badkey = "0123456789abcde"; // 15 bytes - std::string badplain = "This is a test message."; // 23 bytes - std::string goodkey = "0123456789abcdef"; // 16 bytes - std::string goodplain = "This is a test message. "; // 24 bytes - - // Encryption failure should leave 'decrypted' as empty std::string - std::string out = "Not empty"; - EXPECT_FALSE(Encrypt3DesEcb(badkey, goodplain, &out)); - EXPECT_TRUE(out.empty()); - - out = "Not empty"; - EXPECT_FALSE(Decrypt3DesEcb(goodkey, badplain, &out)); - EXPECT_TRUE(out.empty()); -} - -TEST(CryptoUtilTest, TestEncryptAesEcb) { - // Test vector generated by (Python): - // c = M2Crypto.EVP.Cipher('aes_128_ecb', key, '', 1, padding=False) - // encrypted = c.update(data) + c.final(); - // TODO(user): find some Widevine test vectors and use those - std::string key = "0123456789abcdef"; - std::string plaintext = "This message has 32 bytes in it."; - std::string encrypted; - std::string decrypted; - EXPECT_TRUE(EncryptAesEcb(key, plaintext, &encrypted)); - EXPECT_EQ("1f6a7d63e0645de25c56c6b39ba7723d640129d65f41e96b87be812bc94ad8a9", - absl::BytesToHexString(encrypted)); - EXPECT_TRUE(DecryptAesEcb(key, encrypted, &decrypted)); - EXPECT_EQ(plaintext, decrypted); -} - -TEST(CryptoUtilTest, TestEncryptAesEcbFail) { - // Verify that EncryptAesEcb fails with invalid key or data size - std::string badkey = "0123456789abcde"; // 15 bytes - std::string badplain = "This message has 31 bytes in it"; - std::string goodkey = "0123456789abcdef"; // 16 bytes - std::string goodplain = "This message has 32 bytes in it."; - - // Encryption failure should leave 'decrypted' as empty std::string - std::string out = "Not empty"; - EXPECT_FALSE(EncryptAesEcb(badkey, goodplain, &out)); - EXPECT_TRUE(out.empty()); - - out = "Not empty"; - EXPECT_FALSE(EncryptAesEcb(goodkey, badplain, &out)); - EXPECT_TRUE(out.empty()); -} - -} // namespace crypto_util -} // namespace widevine diff --git a/common/ecies_crypto.cc b/common/ecies_crypto.cc deleted file mode 100644 index 5e61036..0000000 --- a/common/ecies_crypto.cc +++ /dev/null @@ -1,239 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/ecies_crypto.h" - -#include - -#include "glog/logging.h" -#include "absl/strings/escaping.h" -#include "openssl/ec.h" -#include "common/aes_cbc_util.h" -#include "common/crypto_util.h" -#include "common/ec_key.h" -#include "common/ec_util.h" -#include "common/openssl_util.h" - -namespace { - -const char kZeroIv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -const size_t kMacSizeBytes = 32; -const size_t kMasterKeySizeBytes = 32; -const size_t kEncryptionKeySizeBytes = kMasterKeySizeBytes; -const size_t kSigningKeySizeBytes = kMasterKeySizeBytes; -const size_t kEncryptionKeySizeBits = kEncryptionKeySizeBytes * 8; -const size_t kSigningKeySizeBits = kSigningKeySizeBytes * 8; - -const char kWrappingKeyLabel[] = "ECIESEncryptionLabel"; -const char kSigningKeyLabel[] = "ECIESSigningLabel"; - -bool DeriveWrappingAndSigningKeys(const std::string& key, - const std::string& context, - std::string* wrapping_key, - std::string* signing_key) { - if (wrapping_key == nullptr || signing_key == nullptr) return false; - if (key.size() != kMasterKeySizeBytes) { - LOG(ERROR) << "Invalid master key size"; - return false; - } - - *wrapping_key = widevine::crypto_util::DeriveKey( - key, kWrappingKeyLabel, context, kEncryptionKeySizeBits); - if (wrapping_key->empty()) { - LOG(WARNING) << "Failed to derive encryption key."; - return false; - } - - *signing_key = widevine::crypto_util::DeriveKey( - key, kSigningKeyLabel, context, kSigningKeySizeBits); - if (signing_key->empty()) { - LOG(WARNING) << "Failed to derive sigining key."; - return false; - } - return true; -} - -} // anonymous namespace - -namespace widevine { - -EciesEncryptor::EciesEncryptor(std::unique_ptr public_key, - ECKeySource* key_source) - : public_key_(std::move(public_key)), key_source_(key_source) {} - -std::unique_ptr EciesEncryptor::Create( - const std::string& serialized_public_key, ECKeySource* key_source) { - if (key_source == nullptr) { - return nullptr; - } - std::unique_ptr ec_key = - ECPublicKey::Create(serialized_public_key); - if (ec_key == nullptr) { - return nullptr; - } - std::unique_ptr encryptor( - new EciesEncryptor(std::move(ec_key), key_source)); - return encryptor; -} - -bool EciesEncryptor::Encrypt(const std::string& plaintext, - const std::string& context, - std::string* ecies_message) const { - if (ecies_message == nullptr) { - LOG(ERROR) << "ecies_message cannot be null"; - return false; - } - - std::string serialized_private_key; - std::string serialized_public_key; - if (!key_source_->GetECKey(public_key_->Curve(), &serialized_private_key, - &serialized_public_key)) { - LOG(WARNING) << "Failed to get key pair from key source."; - return false; - } - - // Convert the ephemeral public key to an encoded EC point. - std::unique_ptr ephemeral_public_key = - ECPublicKey::Create(serialized_public_key); - std::string encoded_public_key; - if (!ephemeral_public_key->GetPointEncodedKey(&encoded_public_key)) { - LOG(ERROR) << "Could not encode the public key. "; - return false; - } - - // This condition is just an indication that the serialized_public_key doesn't - // match our size expectations. It shouldn't block the encryption operation. - size_t expected_size = ec_util::GetPublicKeyPointSize(public_key_->Curve()); - if (encoded_public_key.size() != expected_size) { - LOG(WARNING) << "Unexpected key size for public key. " - << "Curve " << public_key_->Curve() << ". Expected " - << expected_size << ". Found " << encoded_public_key.size() - << "."; - } - - std::unique_ptr ephemeral_private_key = - ECPrivateKey::Create(serialized_private_key); - - std::string session_key; - if (!ephemeral_private_key->DeriveSharedSessionKey(*public_key_, - &session_key)) { - LOG(WARNING) << "Failed to derive shared session key."; - return false; - } - - std::string encryption_key; - std::string signing_key; - if (!DeriveWrappingAndSigningKeys(session_key, context, &encryption_key, - &signing_key)) { - return false; - } - - std::string zero_iv(kZeroIv, sizeof(kZeroIv)); - std::string ciphertext = - crypto_util::EncryptAesCbc(encryption_key, zero_iv, plaintext); - if (ciphertext.empty()) { - LOG(WARNING) << "Failed to encrypt plaintext."; - return false; - } - - std::string signature = - crypto_util::CreateSignatureHmacSha256(signing_key, ciphertext); - if (signature.empty()) { - LOG(WARNING) << "Failed to sign plaintext."; - return false; - } - - *ecies_message = encoded_public_key + ciphertext + signature; - - return true; -} - -std::unique_ptr EciesDecryptor::Create( - const std::string& serialized_private_key) { - std::unique_ptr ec_key = - ECPrivateKey::Create(serialized_private_key); - if (ec_key == nullptr) { - return nullptr; - } - std::unique_ptr decryptor( - new EciesDecryptor(std::move(ec_key))); - if (decryptor == nullptr) { - LOG(ERROR) << "Failed to create EciesDecryptor."; - } - return decryptor; -} - -EciesDecryptor::EciesDecryptor(std::unique_ptr private_key) - : private_key_(std::move(private_key)) {} - -bool EciesDecryptor::Decrypt(const std::string& ecies_message, - const std::string& context, - std::string* plaintext) const { - if (plaintext == nullptr) { - LOG(ERROR) << "plaintext cannot be null"; - return false; - } - - // Check the minimum std::string size. - size_t key_size = ec_util::GetPublicKeyPointSize(private_key_->Curve()); - if (key_size + kMacSizeBytes > ecies_message.size()) { - LOG(ERROR) << "The size of the message is too small. Expected > " - << key_size + kMacSizeBytes << ". found " - << ecies_message.size(); - return false; - } - - std::string ciphertext = ecies_message.substr( - key_size, ecies_message.size() - kMacSizeBytes - key_size); - std::string signature = - ecies_message.substr(ecies_message.size() - kMacSizeBytes, kMacSizeBytes); - - std::unique_ptr public_key = ECPublicKey::CreateFromKeyPoint( - private_key_->Curve(), ecies_message.substr(0, key_size)); - if (public_key == nullptr) { - LOG(WARNING) << "Failed to deserialize public key."; - return false; - } - - std::string session_key; - if (!private_key_->DeriveSharedSessionKey(*public_key, &session_key)) { - LOG(WARNING) << "Failed to derive shared session key."; - return false; - } - - std::string encryption_key; - std::string signing_key; - if (!DeriveWrappingAndSigningKeys(session_key, context, &encryption_key, - &signing_key)) { - LOG(WARNING) << "Failed to derive shared wrapping and signing keys."; - return false; - } - - if (!crypto_util::VerifySignatureHmacSha256(signing_key, signature, - ciphertext)) { - LOG(WARNING) << "Failed to verify signature on ciphertext."; - return false; - } - - std::string zero_iv(kZeroIv, sizeof(kZeroIv)); - // In theory, we should be able to decrypt a cipher block that was originally - // the empty string. But DecryptAesCbc uses an empty std::string to indicate an - // error. This means that we can't distinguish between an error and correctly - // decrypted empty string. - *plaintext = crypto_util::DecryptAesCbc(encryption_key, zero_iv, ciphertext); - if (plaintext->empty()) { - LOG(WARNING) << "Failed to decrypt plaintext."; - return false; - } - - return true; -} - -} // namespace widevine. diff --git a/common/ecies_crypto.h b/common/ecies_crypto.h deleted file mode 100644 index f7207ee..0000000 --- a/common/ecies_crypto.h +++ /dev/null @@ -1,82 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_ECIES_CRYPTO_H_ -#define COMMON_ECIES_CRYPTO_H_ - -#include -#include - -#include "common/ec_key.h" -#include "common/ec_key_source.h" - -namespace widevine { - -class EciesEncryptor { - public: - static std::unique_ptr Create(const std::string& public_key, - ECKeySource* key_source); - virtual ~EciesEncryptor() = default; - EciesEncryptor(const EciesEncryptor&) = delete; - EciesEncryptor& operator=(const EciesEncryptor&) = delete; - - // Generates an encrypted EC-IES message using the public key, an ephemeral - // private key and context. This function uses AES 256 bit encryption with a - // master key derived from EC shared key generated from the public key and - // ephemeral private key. - // |plaintext| is the value to be encrypted. - // |context| is used as part of the key derivation. - // |ecies_message| is the concatenation of - // 1) the ephemeral public key. - // 2) the plaintext encrypted with the derived AES key using AES CBC, - // PKCS7 padding and a zerio iv. - // 3) The HMAC SHA256 of the cipher text. - // Returns false if there is a problem encrypting the content, true otherwise. - virtual bool Encrypt(const std::string& plaintext, const std::string& context, - std::string* ecies_message) const; - - protected: - // Creates the EciesEncryptor with a given ECKey. This is protected in order - // to support mock tests. - EciesEncryptor(std::unique_ptr public_key, - ECKeySource* key_source); - - private: - std::unique_ptr public_key_; - ECKeySource* key_source_; -}; - -class EciesDecryptor { - public: - static std::unique_ptr Create( - const std::string& serialized_private_key); - - virtual ~EciesDecryptor() = default; - EciesDecryptor(const EciesDecryptor&) = delete; - EciesDecryptor& operator=(const EciesDecryptor&) = delete; - - // Decrypts and verifies an EC-IES message using the private key, the - // ephemeral public key embedded in |ecies_message| and the |context|. - // This function uses a master AES key to decrypt the content and validate the - // signature. The content is encrypted with AES CBC, PKCS7 padded with a - // zero iv. - // |plaintext| will be populated iff decryption is successful and the - // signature is valid. - // Returns false if there is a problem decrypting the content, true otherwise. - virtual bool Decrypt(const std::string& ecies_message, - const std::string& context, - std::string* plaintext) const; - - private: - explicit EciesDecryptor(std::unique_ptr private_key); - std::unique_ptr private_key_; -}; - -} // namespace widevine - -#endif // COMMON_ECIES_CRYPTO_H_ diff --git a/common/ecies_crypto_test.cc b/common/ecies_crypto_test.cc deleted file mode 100644 index f3e2ff8..0000000 --- a/common/ecies_crypto_test.cc +++ /dev/null @@ -1,259 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/ecies_crypto.h" - -#include -#include -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/ec_key.h" -#include "common/ec_key_source.h" -#include "common/ec_test_keys.h" -#include "common/ec_util.h" -#include "common/fake_ec_key_source.h" - -using ::testing::_; -using ::testing::Return; - -namespace { -const size_t kMacSizeBytes = 32; -} // anonymous namespace - -namespace widevine { - -class EciesCryptoTest - : public ::testing::Test, - public ::testing::WithParamInterface< - std::tuple > { - public: - static std::vector< - std::tuple > - GetTestKeyList() { - ECTestKeys test_keys; - - std::vector > - keys({std::make_tuple(test_keys.private_test_key_1_secp521r1(), - test_keys.public_test_key_1_secp521r1(), - test_keys.private_test_key_2_secp521r1(), - test_keys.public_test_key_2_secp521r1()), - std::make_tuple(test_keys.private_test_key_1_secp384r1(), - test_keys.public_test_key_1_secp384r1(), - test_keys.private_test_key_2_secp384r1(), - test_keys.public_test_key_2_secp384r1()), - std::make_tuple(test_keys.private_test_key_1_secp256r1(), - test_keys.public_test_key_1_secp256r1(), - test_keys.private_test_key_2_secp256r1(), - test_keys.public_test_key_2_secp256r1())}); - return keys; - } - - protected: - EciesCryptoTest() { - test_private_key_ = std::get<0>(GetParam()); - test_public_key_ = std::get<1>(GetParam()); - test_ephemeral_private_key_ = std::get<2>(GetParam()); - test_ephemeral_public_key_ = std::get<3>(GetParam()); - private_key_ = ECPrivateKey::Create(test_private_key_); - public_key_ = ECPublicKey::Create(test_public_key_); - ephemeral_private_key_ = ECPrivateKey::Create(test_ephemeral_private_key_); - ephemeral_public_key_ = ECPublicKey::Create(test_ephemeral_public_key_); - } - - std::string test_private_key_; - std::string test_public_key_; - std::string test_ephemeral_private_key_; - std::string test_ephemeral_public_key_; - std::unique_ptr private_key_; - std::unique_ptr public_key_; - std::unique_ptr ephemeral_private_key_; - std::unique_ptr ephemeral_public_key_; -}; - -TEST_P(EciesCryptoTest, EciesEncryptSuccess) { - std::string serialized_public_key; - - const std::string context = "test context"; - const std::string plaintext = "test plaintext"; - - std::string ecies_message; - - // Use the test ephemeral key in the key source. - FakeECKeySource fake_key_source; - ASSERT_TRUE(fake_key_source.SetKey(ephemeral_public_key_->Curve(), - test_ephemeral_private_key_, - test_ephemeral_public_key_)); - std::unique_ptr encryptor = - EciesEncryptor::Create(test_public_key_, &fake_key_source); - - ASSERT_TRUE(encryptor->Encrypt(plaintext, context, &ecies_message)); - EXPECT_TRUE(ecies_message.find(plaintext) == std::string::npos); - - // Verify the decrypted_message. - std::string decrypted_message; - std::unique_ptr decryptor = - EciesDecryptor::Create(test_private_key_); - ASSERT_TRUE(decryptor != nullptr); - ASSERT_TRUE(decryptor->Decrypt(ecies_message, context, &decrypted_message)); - EXPECT_EQ(plaintext, decrypted_message); -} - -TEST_P(EciesCryptoTest, EciesDecryptShortEciesMessage) { - std::unique_ptr decryptor = - EciesDecryptor::Create(test_private_key_); - ASSERT_NE(nullptr, decryptor.get()); - std::string decrypted_message; - std::string short_message( - ec_util::GetPublicKeyPointSize(private_key_->Curve()) + kMacSizeBytes - 1, - 'a'); - - ASSERT_FALSE( - decryptor->Decrypt(short_message, "test context", &decrypted_message)); -} - -TEST_P(EciesCryptoTest, EciesDecryptBadSignature) { - std::string serialized_public_key; - - const std::string context = "test context"; - const std::string plaintext = "test plaintext"; - - std::string ecies_message; - - // Use the test ephemeral key in the key source. - FakeECKeySource fake_key_source; - ASSERT_TRUE(fake_key_source.SetKey(ephemeral_public_key_->Curve(), - test_ephemeral_private_key_, - test_ephemeral_public_key_)); - std::unique_ptr encryptor = - EciesEncryptor::Create(test_public_key_, &fake_key_source); - - ASSERT_TRUE(encryptor->Encrypt(plaintext, context, &ecies_message)); - - // Corrupt the signature (at end of message) and verify that decryption fails. - ecies_message[ecies_message.size() - 1]++; - std::string decrypted_message; - std::unique_ptr decryptor = - EciesDecryptor::Create(test_private_key_); - ASSERT_TRUE(decryptor != nullptr); - ASSERT_FALSE(decryptor->Decrypt(ecies_message, context, &decrypted_message)); - EXPECT_EQ("", decrypted_message); -} - -TEST_P(EciesCryptoTest, EciesEncryptMismatchContext) { - std::string serialized_public_key; - - const std::string context = "test context"; - const std::string bogus_context = "bogus_context"; - const std::string plaintext = "test plaintext"; - - std::string ecies_message; - - // Use the test ephemeral key in the key source. - FakeECKeySource fake_key_source; - ASSERT_TRUE(fake_key_source.SetKey(ephemeral_public_key_->Curve(), - test_ephemeral_private_key_, - test_ephemeral_public_key_)); - std::unique_ptr encryptor = - EciesEncryptor::Create(test_public_key_, &fake_key_source); - ASSERT_TRUE(encryptor != nullptr); - ASSERT_TRUE(encryptor->Encrypt(plaintext, context, &ecies_message)); - EXPECT_GT( - ecies_message.size(), - kMacSizeBytes + ec_util::GetPublicKeyPointSize(public_key_->Curve())); - - // Verify the decrypted_message using the invalid context. - std::string decrypted_message; - std::unique_ptr decryptor = - EciesDecryptor::Create(test_private_key_); - ASSERT_TRUE(decryptor != nullptr); - ASSERT_FALSE( - decryptor->Decrypt(ecies_message, bogus_context, &decrypted_message)); - EXPECT_TRUE(decrypted_message.empty()); -} - -INSTANTIATE_TEST_SUITE_P( - EciesCryptoTest, EciesCryptoTest, - ::testing::ValuesIn(EciesCryptoTest::GetTestKeyList())); - -TEST(EciesEncryptorTest, EciesEncryptBadPublicKey) { - // Use the test ephemeral key in the key source. - FakeECKeySource fake_key_source; - std::unique_ptr encryptor = - EciesEncryptor::Create("bad public key.", &fake_key_source); - ASSERT_TRUE(encryptor == nullptr); -} - -TEST(EciesEncryptorTest, EciesEncryptNullKeySource) { - std::unique_ptr encryptor = - EciesEncryptor::Create("bad public key.", nullptr); - ASSERT_TRUE(encryptor == nullptr); -} - -class MockEcKeySource : public ECKeySource { - public: - MockEcKeySource() = default; - MOCK_METHOD(bool, GetECKey, - (ECPrivateKey::EllipticCurve curve, std::string* private_key, - std::string* public_key), - (override)); -}; - -TEST(EciesEncryptorTest, EciesEncryptKeysourceFail) { - MockEcKeySource mock_ec_key_source; - EXPECT_CALL(mock_ec_key_source, GetECKey(_, _, _)).WillOnce(Return(false)); - - ECTestKeys test_keys; - std::unique_ptr encryptor = EciesEncryptor::Create( - test_keys.public_test_key_1_secp256r1(), &mock_ec_key_source); - ASSERT_TRUE(encryptor != nullptr); - std::string ecies_message; - ASSERT_FALSE( - encryptor->Encrypt("test plaintext", "test context", &ecies_message)); -} - -TEST(EciesEncryptorTest, EciesEncryptNullEciesMessage) { - FakeECKeySource fake_key_source; - ECTestKeys test_keys; - std::unique_ptr encryptor = EciesEncryptor::Create( - test_keys.public_test_key_1_secp256r1(), &fake_key_source); - ASSERT_TRUE(encryptor != nullptr); - ASSERT_FALSE(encryptor->Encrypt("test plaintext", "test context", nullptr)); -} - -TEST(EciesDecryptorTest, EciesDecryptBadPrivateKey) { - ECTestKeys test_keys; - std::string invalid_private_key(test_keys.private_test_key_1_secp521r1()); - invalid_private_key[0]++; - - std::unique_ptr decryptor = - EciesDecryptor::Create(invalid_private_key); - ASSERT_TRUE(decryptor == nullptr); -} - -TEST(EciesDecryptorTest, EciesDecryptEmptyEciesMessage) { - ECTestKeys test_keys; - std::unique_ptr decryptor = - EciesDecryptor::Create(test_keys.private_test_key_1_secp521r1()); - ASSERT_NE(nullptr, decryptor); - std::string decrypted_message; - ASSERT_FALSE(decryptor->Decrypt("", "test context", &decrypted_message)); -} - -TEST(EciesDecryptorTest, EciesDecryptNullPlaintext) { - ECTestKeys test_keys; - std::unique_ptr decryptor = - EciesDecryptor::Create(test_keys.private_test_key_1_secp521r1()); - ASSERT_NE(nullptr, decryptor); - std::string decrypted_message; - ASSERT_FALSE(decryptor->Decrypt("foo", "test context", nullptr)); -} - -} // namespace widevine diff --git a/common/error_space.cc b/common/error_space.cc deleted file mode 100644 index 2e9742b..0000000 --- a/common/error_space.cc +++ /dev/null @@ -1,19 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/error_space.h" - -#include "util/proto_status.h" -#include "protos/public/errors.pb.h" - -namespace widevine { - -const util::ErrorSpace* error_space = - util::ProtoEnumErrorSpace::Get(); - -} // namespace widevine diff --git a/common/error_space.h b/common/error_space.h deleted file mode 100644 index 1a4ab78..0000000 --- a/common/error_space.h +++ /dev/null @@ -1,20 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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_ERROR_SPACE_H_ -#define COMMON_ERROR_SPACE_H_ - -#include "util/error_space.h" - -namespace widevine { - -extern const util::ErrorSpace* error_space; - -} // namespace widevine - -#endif // COMMON_ERROR_SPACE_H_ diff --git a/common/fake_ec_key_source.cc b/common/fake_ec_key_source.cc deleted file mode 100644 index 16a551f..0000000 --- a/common/fake_ec_key_source.cc +++ /dev/null @@ -1,78 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Implementation of fake EC key generator. Returns precomputed test keys. - -#include "common/fake_ec_key_source.h" - -#include -#include -#include - -#include "glog/logging.h" -#include "common/ec_key.h" -#include "common/ec_test_keys.h" - -namespace widevine { - -FakeECKeySource::FakeECKeySource() { - ECTestKeys ec_test_keys; - CHECK(SetKey(ECPrivateKey::SECP256R1, - ec_test_keys.private_test_key_1_secp256r1(), - ec_test_keys.public_test_key_1_secp256r1())); - - CHECK(SetKey(ECPrivateKey::SECP384R1, - ec_test_keys.private_test_key_1_secp384r1(), - ec_test_keys.public_test_key_1_secp384r1())); - - CHECK(SetKey(ECPrivateKey::SECP521R1, - ec_test_keys.private_test_key_1_secp521r1(), - ec_test_keys.public_test_key_1_secp521r1())); -} - -bool FakeECKeySource::SetKey(ECPrivateKey::EllipticCurve curve, - const std::string& private_key, - const std::string& public_key) { - std::unique_ptr pri_key = ECPrivateKey::Create(private_key); - std::unique_ptr pub_key = ECPublicKey::Create(public_key); - if (pub_key == nullptr || pri_key == nullptr) { - LOG(ERROR) << "public key or private key was null."; - return false; - } - if (!pri_key->MatchesPublicKey(*pub_key)) { - LOG(ERROR) << "Public and private keys do not match."; - return false; - } - if (pri_key->Curve() != curve) { - LOG(ERROR) << "Curve does not match specified curve."; - return false; - } - - test_keys_[curve] = std::make_pair(private_key, public_key); - - return true; -} - -bool FakeECKeySource::GetECKey(ECPrivateKey::EllipticCurve curve, - std::string* private_key, - std::string* public_key) { - CHECK(private_key); - CHECK(public_key); - - const auto keys = test_keys_.find(curve); - if (keys == test_keys_.end()) { - return false; - } - - std::tie(*private_key, *public_key) = keys->second; - - return true; -} - -} // namespace widevine diff --git a/common/fake_ec_key_source.h b/common/fake_ec_key_source.h deleted file mode 100644 index da6f8fe..0000000 --- a/common/fake_ec_key_source.h +++ /dev/null @@ -1,53 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Declaration for fake EC key source used for testing. - -#ifndef COMMON_FAKE_EC_KEY_SOURCE_H_ -#define COMMON_FAKE_EC_KEY_SOURCE_H_ - -#include -#include - -#include "common/ec_key_source.h" -#include "common/ec_test_keys.h" - -namespace widevine { - -// This is a fake implementation of the ECKeySource. It returns the values -// specified in ec_test_keys.h. -class FakeECKeySource : public ECKeySource { - public: - FakeECKeySource(); - FakeECKeySource(const FakeECKeySource&) = delete; - FakeECKeySource& operator=(const FakeECKeySource&) = delete; - - // This method allows a caller to specify which keys to return from GetKeys. - // This overrides the default test keys. - bool SetKey(ECPrivateKey::EllipticCurve curve, const std::string& private_key, - const std::string& public_key); - - // Gets precomputed test keys based on |curve|. - // Parameter |curve| is a standard curve which defines the parameters of the - // key generation. - // Parameter |private_key| is the serialized EC private key. - // Parameter |public_key| is the serialized EC public key. - // Caller retains ownership of all pointers and they cannot be nullptr. - // Returns true if successful, false otherwise. - bool GetECKey(ECPrivateKey::EllipticCurve curve, std::string* private_key, - std::string* public_key) override; - - private: - std::map> - test_keys_; -}; - -} // namespace widevine - -#endif // COMMON_FAKE_EC_KEY_SOURCE_H_ diff --git a/common/file_util.cc b/common/file_util.cc deleted file mode 100644 index 49147f4..0000000 --- a/common/file_util.cc +++ /dev/null @@ -1,63 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/file_util.h" - -#include -#include - -#include "glog/logging.h" - -namespace widevine { - -bool GetContents(const std::string& file_name, std::string* contents) { - if (file_name.empty()) { - LOG(WARNING) << "File name is empty."; - return false; - } - FILE* file = fopen(file_name.c_str(), "r"); - if (!file) { - LOG(WARNING) << "Unable to open file " << file_name; - return false; - } - contents->clear(); - const size_t kReadSize = 0x1000; - char buffer[kReadSize]; - while (true) { - size_t size_read = fread(buffer, sizeof(char), kReadSize, file); - if (size_read == 0) break; - contents->append(buffer, size_read); - } - const bool eof = feof(file); - fclose(file); - if (!eof) { - LOG(WARNING) << "Failed to read all file contents."; - return false; - } - return true; -} - -bool SetContents(const std::string& file_name, const std::string& contents) { - if (file_name.empty()) { - LOG(WARNING) << "File name is empty."; - return false; - } - FILE* file = fopen(file_name.c_str(), "w"); - if (!file) { - LOG(WARNING) << "Unable to open file " << file_name; - return false; - } - const size_t size_written = - fwrite(contents.data(), sizeof(char), contents.size(), file); - if (size_written != contents.size()) - LOG(WARNING) << "Failed to write to " << file_name; - fclose(file); - return size_written == contents.size(); -} - -} // namespace widevine diff --git a/common/file_util.h b/common/file_util.h deleted file mode 100644 index 42c03aa..0000000 --- a/common/file_util.h +++ /dev/null @@ -1,27 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// File util wrapper to be used in partner sdks. Implemented using generic file -// apis. - -#ifndef COMMON_FILE_UTIL_H_ -#define COMMON_FILE_UTIL_H_ - -#include - -namespace widevine { - -// Read file to string. -bool GetContents(const std::string& file_name, std::string* contents); - -// Write file. -bool SetContents(const std::string& file_name, const std::string& contents); - -} // namespace widevine - -#endif // COMMON_FILE_UTIL_H_ diff --git a/common/file_util_test.cc b/common/file_util_test.cc deleted file mode 100644 index e07669e..0000000 --- a/common/file_util_test.cc +++ /dev/null @@ -1,31 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/file_util.h" - -#include "testing/gunit.h" -#include "absl/strings/str_cat.h" - -namespace widevine { - -TEST(FileUtilTest, EmptyFileName) { - std::string contents; - EXPECT_FALSE(GetContents("", &contents)); - EXPECT_FALSE(SetContents("", "test content")); -} - -TEST(FileUtilTest, BasicTest) { - const std::string file_path = - absl::StrCat("/tmp", "/file_util_test"); - EXPECT_TRUE(SetContents(file_path, "test content")); - std::string contents; - EXPECT_TRUE(GetContents(file_path, &contents)); - EXPECT_EQ("test content", contents); -} - -} // namespace widevine diff --git a/common/hash_algorithm_util.cc b/common/hash_algorithm_util.cc deleted file mode 100644 index d52e7af..0000000 --- a/common/hash_algorithm_util.cc +++ /dev/null @@ -1,51 +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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/hash_algorithm_util.h" - -#include "glog/logging.h" -#include "protos/public/hash_algorithm.pb.h" - -namespace widevine { - -HashAlgorithm HashAlgorithmProtoToEnum( - HashAlgorithmProto hash_algorithm_proto) { - switch (hash_algorithm_proto) { - case HASH_ALGORITHM_UNSPECIFIED: - return HashAlgorithm::kUnspecified; - case HASH_ALGORITHM_SHA_1: - return HashAlgorithm::kSha1; - case HASH_ALGORITHM_SHA_256: - return HashAlgorithm::kSha256; - default: - // See below link for using proto3 enum in switch statement: - // http://shortn/_ma9MY7V9wh - if (HashAlgorithmProto_IsValid(hash_algorithm_proto)) { - LOG(ERROR) << "Unsupported value " << hash_algorithm_proto; - } else { - LOG(WARNING) << "Unexpected value " << hash_algorithm_proto; - } - return HashAlgorithm::kUnspecified; - } -} - -HashAlgorithmProto HashAlgorithmEnumToProto(HashAlgorithm hash_algorithm) { - switch (hash_algorithm) { - case HashAlgorithm::kUnspecified: - return HASH_ALGORITHM_UNSPECIFIED; - case HashAlgorithm::kSha1: - return HASH_ALGORITHM_SHA_1; - case HashAlgorithm::kSha256: - return HASH_ALGORITHM_SHA_256; - } - LOG(WARNING) << "Unexpected hash algorithm " - << static_cast(hash_algorithm); - return HASH_ALGORITHM_UNSPECIFIED; -} - -} // namespace widevine diff --git a/common/hash_algorithm_util.h b/common/hash_algorithm_util.h deleted file mode 100644 index 5541544..0000000 --- a/common/hash_algorithm_util.h +++ /dev/null @@ -1,23 +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. -//////////////////////////////////////////////////////////////////////////////// - -#ifndef COMMON_HASH_ALGORITHM_UTIL_H_ -#define COMMON_HASH_ALGORITHM_UTIL_H_ - -#include "common/hash_algorithm.h" -#include "protos/public/hash_algorithm.pb.h" - -namespace widevine { - -HashAlgorithm HashAlgorithmProtoToEnum(HashAlgorithmProto hash_algorithm_proto); - -HashAlgorithmProto HashAlgorithmEnumToProto(HashAlgorithm hash_algorithm); - -} // namespace widevine - -#endif // COMMON_HASH_ALGORITHM_UTIL_H_ diff --git a/common/hash_algorithm_util_test.cc b/common/hash_algorithm_util_test.cc deleted file mode 100644 index f5fbfdd..0000000 --- a/common/hash_algorithm_util_test.cc +++ /dev/null @@ -1,58 +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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/hash_algorithm_util.h" - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "common/hash_algorithm.h" - -namespace widevine { - -TEST(HashAlgorithmTest, ProtoToEnumUnspecified) { - EXPECT_EQ(HashAlgorithm::kUnspecified, - HashAlgorithmProtoToEnum(HASH_ALGORITHM_UNSPECIFIED)); -} - -TEST(HashAlgorithmTest, ProtoToEnumSha1) { - EXPECT_EQ(HashAlgorithm::kSha1, - HashAlgorithmProtoToEnum(HASH_ALGORITHM_SHA_1)); -} - -TEST(HashAlgorithmTest, ProtoToEnumSha256) { - EXPECT_EQ(HashAlgorithm::kSha256, - HashAlgorithmProtoToEnum(HASH_ALGORITHM_SHA_256)); -} - -TEST(HashAlgorithmTest, ProtoToEnumUnsupported) { - EXPECT_EQ(HashAlgorithm::kUnspecified, - HashAlgorithmProtoToEnum(static_cast(1234))); -} - -TEST(HashAlgorithmTest, EnumToProtoUnspecified) { - EXPECT_EQ(HASH_ALGORITHM_UNSPECIFIED, - HashAlgorithmEnumToProto(HashAlgorithm::kUnspecified)); -} - -TEST(HashAlgorithmTest, EnumToProtoSha1) { - EXPECT_EQ(HASH_ALGORITHM_SHA_1, - HashAlgorithmEnumToProto(HashAlgorithm::kSha1)); -} - -TEST(HashAlgorithmTest, EnumToProtoSha256) { - EXPECT_EQ(HASH_ALGORITHM_SHA_256, - HashAlgorithmEnumToProto(HashAlgorithm::kSha256)); -} - -TEST(HashAlgorithmTest, EnumToProtoUnexpected) { - int some_value = 1234; - EXPECT_EQ(HASH_ALGORITHM_UNSPECIFIED, - HashAlgorithmEnumToProto(static_cast(some_value))); -} - -} // namespace widevine diff --git a/common/keybox_client_cert.cc b/common/keybox_client_cert.cc deleted file mode 100644 index bd8e748..0000000 --- a/common/keybox_client_cert.cc +++ /dev/null @@ -1,58 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/keybox_client_cert.h" - -#include "glog/logging.h" -#include "common/crypto_util.h" -#include "common/error_space.h" -#include "common/sha_util.h" -#include "common/signing_key_util.h" -#include "common/wvm_token_handler.h" -#include "protos/public/errors.pb.h" - -namespace widevine { - -Status KeyboxClientCert::Initialize(const std::string& keybox_token) { - system_id_ = WvmTokenHandler::GetSystemId(keybox_token); - serial_number_ = WvmTokenHandler::GetEncryptedUniqueId(keybox_token); - bool insecure_keybox = false; - Status status = WvmTokenHandler::DecryptDeviceKey(keybox_token, &device_key_, - nullptr, &insecure_keybox); - if (!status.ok()) { - Errors new_code = status.error_code() == error::NOT_FOUND - ? MISSING_PRE_PROV_KEY - : KEYBOX_DECRYPT_ERROR; - return Status(error_space, new_code, status.error_message()); - } - return OkStatus(); -} - -// |hash_algorithm| is needed for function inheritance. -// For KeyBoxClientCert, we always use HMAC-SHA256 in signature verification. -Status KeyboxClientCert::VerifySignature( - const std::string& message, HashAlgorithm hash_algorithm, - const std::string& signature, ProtocolVersion protocol_version) const { - DCHECK(!signing_key_.empty()); - using crypto_util::VerifySignatureHmacSha256; - if (!VerifySignatureHmacSha256( - GetClientSigningKey(signing_key_, protocol_version), signature, - message)) { - return Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac"); - } - return OkStatus(); -} - -void KeyboxClientCert::GenerateSigningKey(const std::string& message, - ProtocolVersion protocol_version) { - signing_key_ = crypto_util::DeriveKey( - key(), crypto_util::kSigningKeyLabel, - protocol_version < VERSION_2_2 ? message : Sha512_Hash(message), - SigningKeyMaterialSizeBits(protocol_version)); -} -} // namespace widevine diff --git a/common/keybox_client_cert.h b/common/keybox_client_cert.h deleted file mode 100644 index 98fb111..0000000 --- a/common/keybox_client_cert.h +++ /dev/null @@ -1,85 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_KEYBOX_CLIENT_CERT_H_ -#define COMMON_KEYBOX_CLIENT_CERT_H_ - -#include "common/client_cert.h" -#include "common/error_space.h" -#include "common/hash_algorithm.h" -#include "protos/public/errors.pb.h" - -namespace widevine { - -class KeyboxClientCert : public ClientCert { - public: - KeyboxClientCert() {} - ~KeyboxClientCert() override {} - KeyboxClientCert(const KeyboxClientCert&) = delete; - KeyboxClientCert& operator=(const KeyboxClientCert&) = delete; - Status Initialize(const std::string& keybox_token); - - Status VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature, - ProtocolVersion protocol_version) const override; - - void GenerateSigningKey(const std::string& message, - ProtocolVersion protocol_version) override; - - const std::string& encrypted_key() const override { return unimplemented_; } - const std::string& key() const override { return device_key_; } - SignedMessage::SessionKeyType key_type() const override { - return SignedMessage::WRAPPED_AES_KEY; - } - bool using_dual_certificate() const override { return false; } - const std::string& serial_number() const override { return serial_number_; } - const std::string& service_id() const override { return unimplemented_; } - const std::string& signing_key() const override { return signing_key_; } - const std::string& signer_serial_number() const override { - return unimplemented_; - } - uint32_t signer_creation_time_seconds() const override { return 0; } - bool signed_by_provisioner() const override { return false; } - uint32_t system_id() const override { return system_id_; } - widevine::ClientIdentification::TokenType type() const override { - return ClientIdentification::KEYBOX; - } - const std::string& encrypted_unique_id() const override { - return unimplemented_; - } - const std::string& unique_id_hash() const override { return unimplemented_; } - - // Set the system-wide pre-provisioning keys; argument must be human-readable - // hex digits. - // Must be called before any other method of this class is called, unless - // created by ClientCert::CreateWithPreProvisioningKey(...). - static void SetPreProvisioningKeys( - const std::multimap& keymap); - static bool IsSystemIdKnown(const uint32_t system_id); - static uint32_t GetSystemId(const std::string& keybox_bytes); - Status SystemIdUnknownError() const override { - return Status(error_space, UNSUPPORTED_SYSTEM_ID, - "keybox-unsupported-system-id"); - } - Status SystemIdRevokedError() const override { - return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, - "keybox-system-id-revoked"); - } - - private: - std::string unimplemented_; - std::string device_key_; - uint32_t system_id_; - std::string serial_number_; - std::string signing_key_; -}; - -} // namespace widevine - -#endif // COMMON_KEYBOX_CLIENT_CERT_H_ diff --git a/common/local_ec_key_source.cc b/common/local_ec_key_source.cc deleted file mode 100644 index 46517d6..0000000 --- a/common/local_ec_key_source.cc +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Implementation of local EC key generator. - -#include "common/local_ec_key_source.h" - -#include -#include - -#include "glog/logging.h" -#include "openssl/ec.h" -#include "openssl/nid.h" -#include "common/ec_key.h" -#include "common/ec_util.h" - -using widevine::ec_util::SerializeECPrivateKey; -using widevine::ec_util::SerializeECPublicKey; - -namespace widevine { - -bool LocalECKeySource::GetECKey(ECPrivateKey::EllipticCurve curve, - std::string* private_key, - std::string* public_key) { - DCHECK(private_key); - DCHECK(public_key); - - int nid = ec_util::CurveToNid(curve); - if (nid <= 0) { - return false; - } - bssl::UniquePtr key_pair(EC_KEY_new_by_curve_name(nid)); - if (key_pair == nullptr || !EC_KEY_generate_key(key_pair.get())) { - return false; - } - if (!SerializeECPrivateKey(key_pair.get(), private_key) || - !SerializeECPublicKey(key_pair.get(), public_key)) { - return false; - } - - return true; -} - -} // namespace widevine diff --git a/common/local_ec_key_source.h b/common/local_ec_key_source.h deleted file mode 100644 index e6022e2..0000000 --- a/common/local_ec_key_source.h +++ /dev/null @@ -1,42 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Class to generate EC keys locally. - -#ifndef COMMON_LOCAL_EC_KEY_SOURCE_H_ -#define COMMON_LOCAL_EC_KEY_SOURCE_H_ - -#include "common/ec_key.h" -#include "common/ec_key_source.h" - -namespace widevine { - -// Class which generates new EC keys. -class LocalECKeySource : public ECKeySource { - public: - LocalECKeySource() = default; - - // Creates an EC key pair using openssl and |curve|. - // Parameter |curve| is a standard curve which defines the parameters of the - // key generation. - // Parameter |private_key| is the serialized EC private key. - // Parameter |public_key| is the serialized EC public key. - // Caller retains ownership of all pointers and they cannot be nullptr. - // Returns true if successful, false otherwise. - bool GetECKey(ECPrivateKey::EllipticCurve curve, std::string* private_key, - std::string* public_key) override; - - private: - LocalECKeySource(const LocalECKeySource&) = delete; - LocalECKeySource& operator=(const LocalECKeySource&) = delete; -}; - -} // namespace widevine - -#endif // COMMON_LOCAL_EC_KEY_SOURCE_H_ diff --git a/common/local_ec_key_source_test.cc b/common/local_ec_key_source_test.cc deleted file mode 100644 index 0f23bd3..0000000 --- a/common/local_ec_key_source_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Unit tests for LocalECKeySource. - -#include "common/local_ec_key_source.h" - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "common/ec_test_keys.h" -#include "common/ec_util.h" - -namespace widevine { - -using ec_util::DeserializeECPrivateKey; -using ec_util::DeserializeECPublicKey; -using ec_util::SerializeECPublicKey; - -class LocalECKeySourceTest : public ::testing::Test { - public: - void ValidateKeyPair(ECPrivateKey::EllipticCurve curve, - const std::string& private_key, - const std::string& public_key) { - EC_KEY* ec_key; - std::string expected_public_key; - - int nid = ec_util::CurveToNid(curve); - ASSERT_GT(nid, 0); - - EXPECT_TRUE(DeserializeECPrivateKey(private_key, &ec_key)); - ASSERT_TRUE(ec_key != nullptr); - EXPECT_EQ(nid, EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key))); - EXPECT_TRUE(SerializeECPublicKey(ec_key, &expected_public_key)); - EXPECT_EQ(expected_public_key, public_key); - EC_KEY_free(ec_key); - ec_key = nullptr; - EXPECT_TRUE(DeserializeECPublicKey(public_key, &ec_key)); - ASSERT_TRUE(ec_key != nullptr); - EC_KEY_free(ec_key); - } -}; - -TEST_F(LocalECKeySourceTest, GenerateKeys) { - LocalECKeySource key_source; - std::string private_key; - std::string public_key; - - std::vector curves = {ECPrivateKey::SECP256R1, - ECPrivateKey::SECP384R1, - ECPrivateKey::SECP521R1}; - - for (auto curve : curves) { - ASSERT_TRUE(key_source.GetECKey(curve, &private_key, &public_key)); - ValidateKeyPair(curve, private_key, public_key); - } -} - -} // namespace widevine diff --git a/common/mock_rsa_key.h b/common/mock_rsa_key.h deleted file mode 100644 index a241e1d..0000000 --- a/common/mock_rsa_key.h +++ /dev/null @@ -1,97 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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_MOCK_RSA_KEY_H_ -#define COMMON_MOCK_RSA_KEY_H_ - -#include - -#include "testing/gmock.h" -#include "common/hash_algorithm.h" -#include "common/rsa_key.h" - -namespace widevine { - -class MockRsaPrivateKey : public RsaPrivateKey { - public: - MockRsaPrivateKey() : RsaPrivateKey(RSA_new()) {} - ~MockRsaPrivateKey() override {} - - MOCK_METHOD(bool, Decrypt, - (const std::string& encrypted_message, - std::string* decrypted_message), - (const, override)); - // TODO(b/155438325): remove this function after the below function is fully - // propagated. - MOCK_METHOD(bool, GenerateSignature, - (const std::string& message, std::string* signature), - (const, override)); - MOCK_METHOD(bool, GenerateSignature, - (const std::string& message, HashAlgorithm hash_algorithm, - std::string* signature), - (const, override)); - MOCK_METHOD(bool, MatchesPrivateKey, (const RsaPrivateKey& private_key), - (const, override)); - MOCK_METHOD(bool, MatchesPublicKey, (const RsaPublicKey& public_key), - (const, override)); - - private: - MockRsaPrivateKey(const MockRsaPrivateKey&) = delete; - MockRsaPrivateKey& operator=(const MockRsaPrivateKey&) = delete; -}; - -class MockRsaPublicKey : public RsaPublicKey { - public: - MockRsaPublicKey() : RsaPublicKey(RSA_new()) {} - ~MockRsaPublicKey() override {} - - MOCK_METHOD(bool, Encrypt, - (const std::string& clear_message, - std::string* encrypted_message), - (const, override)); - // TODO(b/155438325): remove this function after the below function is fully - // propagated. - MOCK_METHOD(bool, VerifySignature, - (const std::string& message, const std::string& signature), - (const, override)); - MOCK_METHOD(bool, VerifySignature, - (const std::string& message, HashAlgorithm hash_algorithm, - const std::string& signature), - (const, override)); - MOCK_METHOD(bool, MatchesPrivateKey, (const RsaPrivateKey& private_key), - (const, override)); - MOCK_METHOD(bool, MatchesPublicKey, (const RsaPublicKey& public_key), - (const, override)); - - private: - MockRsaPublicKey(const MockRsaPublicKey&) = delete; - MockRsaPublicKey& operator=(const MockRsaPublicKey&) = delete; -}; - -class MockRsaKeyFactory : public RsaKeyFactory { - public: - MockRsaKeyFactory() {} - ~MockRsaKeyFactory() override {} - - MOCK_METHOD(std::unique_ptr, CreateFromPkcs1PrivateKey, - (const std::string& private_key), (const, override)); - MOCK_METHOD(std::unique_ptr, CreateFromPkcs8PrivateKey, - (const std::string& private_key, - const std::string& private_key_passphrase), - (const, override)); - MOCK_METHOD(std::unique_ptr, CreateFromPkcs1PublicKey, - (const std::string& public_key), (const, override)); - - private: - MockRsaKeyFactory(const MockRsaKeyFactory&) = delete; - MockRsaKeyFactory& operator=(const MockRsaKeyFactory&) = delete; -}; - -} // namespace widevine - -#endif // COMMON_MOCK_RSA_KEY_H_ diff --git a/common/output_protection_util.cc b/common/output_protection_util.cc deleted file mode 100644 index d677d92..0000000 --- a/common/output_protection_util.cc +++ /dev/null @@ -1,54 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/output_protection_util.h" - -namespace widevine { -namespace op_util { - -Status VerifyDeviceCapabilities( - const ClientIdentification::ClientCapabilities& device_capabilities, - const License::KeyContainer::OutputProtection& output_protection, - bool* should_disable_analog_output) { - bool device_has_analog_output = - device_capabilities.analog_output_capabilities() != - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE && - device_capabilities.analog_output_capabilities() != - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_UNKNOWN; - - if (should_disable_analog_output != nullptr) { - *should_disable_analog_output = false; - } - if (device_has_analog_output) { - if (output_protection.disable_analog_output() && - !device_capabilities.can_disable_analog_output()) { - return Status(error::PERMISSION_DENIED, - "Analog out cannot be disabled on this device."); - } - if (output_protection.cgms_flags() != - License::KeyContainer::OutputProtection::CGMS_NONE) { - if (device_capabilities.analog_output_capabilities() != - ClientIdentification::ClientCapabilities:: - ANALOG_OUTPUT_SUPPORTS_CGMS_A) { - if (!device_capabilities.can_disable_analog_output()) { - return Status( - error::PERMISSION_DENIED, - "Analog out cannot be disabled on this device, no CGMS."); - } - // This device does not have support for CGMS protections. - if (should_disable_analog_output != nullptr) { - *should_disable_analog_output = true; - } - } - } - } - return OkStatus(); -} - -} // namespace op_util -} // namespace widevine diff --git a/common/output_protection_util.h b/common/output_protection_util.h deleted file mode 100644 index 568e8ec..0000000 --- a/common/output_protection_util.h +++ /dev/null @@ -1,31 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_OUTPUT_PROTECTION_UTIL_H_ -#define COMMON_OUTPUT_PROTECTION_UTIL_H_ - -#include "common/status.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { -namespace op_util { - -// Verify the device meets the provider's output requirements. Set -// |should_disable_analog_output| to true if device does not meet analog output -// requirements, otherwise |should_disable_analog_error| is false including -// error cases. -Status VerifyDeviceCapabilities( - const ClientIdentification::ClientCapabilities& device_capabilities, - const License::KeyContainer::OutputProtection& output_protection, - bool* should_disable_analog_output); - -} // namespace op_util -} // namespace widevine - -#endif // COMMON_OUTPUT_PROTECTION_UTIL_H_ diff --git a/common/output_protection_util_test.cc b/common/output_protection_util_test.cc deleted file mode 100644 index 68e0702..0000000 --- a/common/output_protection_util_test.cc +++ /dev/null @@ -1,155 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/output_protection_util.h" - -#include "testing/gmock.h" -#include "testing/gunit.h" - -namespace widevine { -namespace op_util { - -TEST(OutputProtectionUtilTest, AnalogOutputAllowed_DeviceWithoutAnalogOutput) { - License::KeyContainer::OutputProtection output_protection; - output_protection.set_disable_analog_output(false); - ClientIdentification::ClientCapabilities client_capabilities; - client_capabilities.set_analog_output_capabilities( - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_UNKNOWN); - bool should_disable_output_protection = true; - ASSERT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection, - &should_disable_output_protection)); - EXPECT_FALSE(should_disable_output_protection); -} - -TEST(OutputProtectionUtilTest, - AnalogOutputNotAllowed_DeviceWithoutAnalogOutput) { - License::KeyContainer::OutputProtection output_protection; - output_protection.set_disable_analog_output(true); - ClientIdentification::ClientCapabilities client_capabilities; - client_capabilities.set_analog_output_capabilities( - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE); - bool should_disable_output_protection = true; - ASSERT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection, - &should_disable_output_protection)); - EXPECT_FALSE(should_disable_output_protection); -} - -TEST(OutputProtectionUtilTest, AnalogOutputNotAllowed_DeviceWithAnalogOutput) { - License::KeyContainer::OutputProtection output_protection; - output_protection.set_disable_analog_output(true); - ClientIdentification::ClientCapabilities client_capabilities; - client_capabilities.set_analog_output_capabilities( - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED); - client_capabilities.set_can_disable_analog_output(false); - bool should_disable_output_protection = true; - ASSERT_EQ(error::PERMISSION_DENIED, - VerifyDeviceCapabilities(client_capabilities, output_protection, - &should_disable_output_protection) - .error_code()); - EXPECT_FALSE(should_disable_output_protection); - // Client has the ability to disable it's analog output. - client_capabilities.set_can_disable_analog_output(true); - EXPECT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection, - &should_disable_output_protection)); -} - -TEST(OutputProtectionUtilTest, CGMSRequired) { - License::KeyContainer::OutputProtection output_protection; - output_protection.set_disable_analog_output(false); - output_protection.set_cgms_flags( - License::KeyContainer::OutputProtection::COPY_NEVER); - ClientIdentification::ClientCapabilities client_capabilities; - client_capabilities.set_analog_output_capabilities( - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED); - bool should_disable_output_protection = true; - EXPECT_EQ(error::PERMISSION_DENIED, - VerifyDeviceCapabilities(client_capabilities, output_protection, - &should_disable_output_protection) - .error_code()); - client_capabilities.set_analog_output_capabilities( - ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A); - ASSERT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection, - &should_disable_output_protection)); - EXPECT_FALSE(should_disable_output_protection); -} -// TODO(user): enable this test. -TEST(OutputProtectionUtilTest, DISABLED_VerifyDeviceHdcpCapabilities) { - ClientIdentification::ClientCapabilities device_capabilities; - License::KeyContainer::OutputProtection required; - - // Device capabilities was not specified by the client. - device_capabilities.clear_max_hdcp_version(); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_NONE); - bool should_disable_output_protection; - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V1); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_1); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_2); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp( - License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - - // Device capabilities are too low for any HDCP. Only fail if the required - // protection is HDCP_NO_DIGITAL_OUTPUT. - device_capabilities.set_max_hdcp_version( - ClientIdentification::ClientCapabilities::HDCP_NONE); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_NONE); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V1); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp( - License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT); - EXPECT_EQ(error::PERMISSION_DENIED, - VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection) - .error_code()); - - // Device does not have any digital output ports. In this case, the CDM - // cannot enforce this situation. For now, allow all HDCP requests, the KCB - // will enforce the HDCP settings. - device_capabilities.set_max_hdcp_version( - ClientIdentification::ClientCapabilities::HDCP_NO_DIGITAL_OUTPUT); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_NONE); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V1); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_1); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_2); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); - required.set_hdcp( - License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT); - EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required, - &should_disable_output_protection)); -} - -} // namespace op_util -} // namespace widevine diff --git a/common/playready_interface.h b/common/playready_interface.h deleted file mode 100644 index caa7d30..0000000 --- a/common/playready_interface.h +++ /dev/null @@ -1,42 +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. -//////////////////////////////////////////////////////////////////////////////// -#ifndef COMMON_PLAYREADY_INTERFACE_H_ -#define COMMON_PLAYREADY_INTERFACE_H_ - -#include - -#include "util/error_space.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { - -class PlayReadyInterface { - public: - PlayReadyInterface() {} - virtual ~PlayReadyInterface() {} - - // Sends to a PlayReady Service running the PlayReady license server on - // Windows . - // Args: - // - |challenge| is a std::string which contains PlayReadyLicenseRequest. - // - |policy| is a std::string which contains the PlayReady Policy Setting. - // - |license| is a std::string of PlayReadyLicenseResponse returned from PlayReady - // Service. - - // Returns: - // - status code from downstream components. - virtual util::Status SendToPlayReady( - const std::string& playready_challenge, const std::string& provider, - const std::string& content_id, - const std::list& keys, - const License::Policy& policy, std::string* playready_license) = 0; -}; - -} // namespace widevine - -#endif // COMMON_PLAYREADY_INTERFACE_H_ diff --git a/common/playready_sdk_impl.cc b/common/playready_sdk_impl.cc deleted file mode 100644 index 0540ed0..0000000 --- a/common/playready_sdk_impl.cc +++ /dev/null @@ -1,23 +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. -//////////////////////////////////////////////////////////////////////////////// -#include "common/playready_sdk_impl.h" - -#include "absl/status/status.h" -#include "absl/strings/escaping.h" -#include "util/task/codes.pb.h" - -namespace widevine { - -// TODO(user): fill in SendToPlayReady function. -util::Status PlayReadySdkImpl::SendToPlayReady( - const std::string& playready_challenge, const std::string& provider, - const std::string& content_id, const std::list& keys, - const License::Policy& policy, std::string* playready_license) { - return OkStatus; -} -} // namespace widevine diff --git a/common/playready_sdk_impl.h b/common/playready_sdk_impl.h deleted file mode 100644 index 8595487..0000000 --- a/common/playready_sdk_impl.h +++ /dev/null @@ -1,28 +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. -//////////////////////////////////////////////////////////////////////////////// -#ifndef COMMON_PLAYREADY_SDK_IMPL_H_ -#define COMMON_PLAYREADY_SDK_IMPL_H_ - -#include "common/playready_interface.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { -class PlayReadySdkImpl : public PlayReadyInterface { - public: - PlayReadySdkImpl() : PlayReadyInterface() {} - ~PlayReadySdkImpl() override {} - - util::Status SendToPlayReady(const std::string& playready_challenge, - const std::string& provider, - const std::string& content_id, - const std::list& keys, - const License::Policy& policy, - std::string* playready_license) override; -}; -} // namespace widevine -#endif // COMMON_PLAYREADY_SDK_IMPL_H_ diff --git a/common/random_util_test.cc b/common/random_util_test.cc deleted file mode 100644 index 1a52d6f..0000000 --- a/common/random_util_test.cc +++ /dev/null @@ -1,28 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/random_util.h" -#include "testing/gunit.h" - -namespace widevine { - -TEST(RandomUtilTest, Test) { - std::string output; - ASSERT_TRUE(RandomBytes(16u, &output)); - EXPECT_EQ(16u, output.size()); - - std::string output2; - ASSERT_TRUE(RandomBytes(16u, &output2)); - EXPECT_EQ(16u, output2.size()); - EXPECT_NE(output, output2); - - ASSERT_TRUE(RandomBytes(10u, &output2)); - EXPECT_EQ(10u, output2.size()); -} - -} // namespace widevine diff --git a/common/remote_attestation_verifier.cc b/common/remote_attestation_verifier.cc deleted file mode 100644 index a9daa9d..0000000 --- a/common/remote_attestation_verifier.cc +++ /dev/null @@ -1,262 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/remote_attestation_verifier.h" - -#include -#include - -#include "glog/logging.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "absl/synchronization/mutex.h" -#include "common/client_id_util.h" -#include "common/drm_service_certificate.h" -#include "common/error_space.h" -#include "common/rsa_key.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/errors.pb.h" - -namespace widevine { - -const char kTestRootCaDerCert[] = - "30820403308202eba003020102020900a24f94af7ae6831f300d06092a86" - "4886f70d0101050500308197310b30090603550406130255533113301106" - "035504080c0a57617368696e67746f6e3111300f06035504070c084b6972" - "6b6c616e6431133011060355040a0c0a476f6f676c6520496e633111300f" - "060355040b0c085769646576696e653115301306035504030c0c54657374" - "20526f6f742043413121301f06092a864886f70d010901161274696e736b" - "697040676f6f676c652e636f6d301e170d3133303831363030353731305a" - "170d3333303831353030353731305a308197310b30090603550406130255" - "533113301106035504080c0a57617368696e67746f6e3111300f06035504" - "070c084b69726b6c616e6431133011060355040a0c0a476f6f676c652049" - "6e633111300f060355040b0c085769646576696e65311530130603550403" - "0c0c5465737420526f6f742043413121301f06092a864886f70d01090116" - "1274696e736b697040676f6f676c652e636f6d30820122300d06092a8648" - "86f70d01010105000382010f003082010a0282010100c6eee629d99f7736" - "2db5545ed1d6dfb3616c742c617d5fd48f2fbfcb3f2ec40a080bd04d551c" - "e519471a8bb4ec5c2c75bf8a2d2caf3f85d90e9e39391dfbdaae68051319" - "0da71b1b2ae4829a15c44bc1b19b17134844b94c6f06d9216333236574f3" - "f11b0d10c3c621410e42630c57ce9e901057eda5c3c2203ee2ad805a0d93" - "52fa91da45a6f4875b4524c193c42fd9048a10204e5b2c8203402ba760e7" - "e1b4126c3e2ab4258f2bf28cd3170de8c738a6a1f4cfcc0649fa95f1414f" - "d9d09dd4f511bc0a9bf3a5844a334d9e0a4b9525d2789be6abafe2d0cc20" - "79dcf030ffa9be8ae3fe2cab4ebdfa494d48aa8c63264d31e2208a9c28f7" - "3e0103ce164683bf0203010001a350304e301d0603551d0e041604144d30" - "ff181ac4f10da99e6a12c01e02accadf840a301f0603551d230418301680" - "144d30ff181ac4f10da99e6a12c01e02accadf840a300c0603551d130405" - "30030101ff300d06092a864886f70d01010505000382010100779e9b98d3" - "ec066f29862903a00e9c98259d987c04b9e6a2e6c3381ee59ec1dd0d7dee" - "79da612e4dfaa3465c8916993ed7adebb27340de20ca101067f8342b2124" - "ec0d5db531277b4653c3bc72b2a8daeae120e5348e1a338f6e68e7129436" - "026e78024f04d766b132252ec152402dcec28174346aa0ba997d7f1af140" - "ff025bec841f8039ba10d7cc098cf24554f8cbb2aa31875205c67df2f053" - "0d8784faf63c4f945e62da374cad6155e6ae44f597bcff4566ea2aac4258" - "e4ae81569c0eddd1df6929532b4538bd204b2ff5847cb46ac7383c96fe82" - "d22de9a13c5092c92c297021c51a2a0a5250cf26c271ff262f25a7738ae4" - "c270d87191c13aefdd177b"; - -const char kProdRootCaDerCert[] = - "30820408308202f0a003020102020101300d06092a864886f70d01010505" - "00307d311830160603550403130f5072697661637920434120526f6f7431" - "123010060355040b13094368726f6d65204f5331133011060355040a130a" - "476f6f676c6520496e63311630140603550407130d4d6f756e7461696e20" - "56696577311330110603550408130a43616c69666f726e6961310b300906" - "0355040613025553301e170d3133303231383130313334325a170d333330" - "3231333130313334325a307d311830160603550403130f50726976616379" - "20434120526f6f7431123010060355040b13094368726f6d65204f533113" - "3011060355040a130a476f6f676c6520496e63311630140603550407130d" - "4d6f756e7461696e2056696577311330110603550408130a43616c69666f" - "726e6961310b300906035504061302555330820122300d06092a864886f7" - "0d01010105000382010f003082010a0282010100e10ea6819d3d066b421d" - "d7612de3eef9599f5d9a2a24bfd09caab543511cf22f615e29f989425a65" - "7396bf33603747719cfb0b4240cd682c7c558fec0176b4793be440752246" - "83648f5b12d02a838a2a8e55a4b645ed0a4a52b19252a23d34bf64a17ac7" - "11fe93a889086d943211b17d670f96442c9f367d38026000da79664e600e" - "e9259348f4fd74108e973d561e624e9f5eda77a085a6eb15fadb2cc7787c" - "7f30ef3b196f2a416a76fa9eb30d65753f5039d97bea70e82431d2962396" - "a34864f33b74d60707fea794c03c82e547abc2407fa7bad67bd09cdab49b" - "26e68754994d12a3845dbeceffe18de0d51fc6fa78676d89ea1e0fcff931" - "59bfb809519b0203010001a3819230818f30290603551d0e042204204b1d" - "148aa5380938812ed6a763f5dc2c318610d5fa9604d609cb2e0d8cec3289" - "302b0603551d230424302280204b1d148aa5380938812ed6a763f5dc2c31" - "8610d5fa9604d609cb2e0d8cec3289300e0603551d0f0101ff0404030201" - "06300f0603551d130101ff040530030101ff30140603551d200101ff040a" - "300830060604551d2000300d06092a864886f70d01010505000382010100" - "c40d84bc8d609b1b68b3caa7e841021838d7e392557d40debab3e0685e72" - "80541092dc913b0aa6150228d8fe5ab08cceefbac56952fa00ba614294d1" - "ba4fa170c86b27f9bf58666c46940f740c4be2795501b25e40b9702af07c" - "884926bd8beed036c503e5e42a223ff36271404ca4360a93dec92a02fd8d" - "ae8f756fc68aaa647e2159f0a7a95d1446e92362bd512f59daec02c5d152" - "c301b9807db998ba70c616364762a0a497aaa92eb7d92f3635169d3f74c6" - "40c738941759a8ab43677b80329d015bdcf8922b779a80f85f1e4a677659" - "c60de80152e8c526a7de46cac143a75af58f0806de81e15c97f616e1bffa" - "1c1c6b0d2438543bdfb2a21bd9bc7ae4"; - -const char kServiceIdFieldName[] = "OU"; -const char kDeviceModeFieldName[] = "O"; -const char kExpectedDeviceMode[] = "Chrome Device Content Protection"; - -RemoteAttestationVerifier& RemoteAttestationVerifier::get() { - static RemoteAttestationVerifier instance; - return instance; -} - -void RemoteAttestationVerifier::EnableTestDrmCertificates(bool enable) { - absl::WriterMutexLock lock(&ca_mutex_); - enable_test_certificates_ = enable; - ca_.reset(); -} - -Status RemoteAttestationVerifier::VerifyRemoteAttestation( - const std::string& message, const RemoteAttestation& remote_attestation, - std::string* remote_attestation_cert_sn) { - DCHECK(remote_attestation_cert_sn); - - // Sanity check RemoteAttestation. - if (!remote_attestation.has_certificate()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-certificate-missing")); - } - if (!remote_attestation.has_salt()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-salt-missing")); - } - if (!remote_attestation.has_signature()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-signature-missing")); - } - // Decrypt ClientIdentification containing remote attestation certificate. - // A service cert would be looked up first, then that cert will be used - // to decrypt the ClientIdentification. - ClientIdentification client_id; - Status status = DrmServiceCertificate::DecryptClientIdentification( - remote_attestation.certificate(), &client_id); - if (!status.ok()) return status; - - if (client_id.type() != - ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) { - return (Status(error_space, INVALID_MESSAGE, - std::string("remote-attestation-invalid-client-id-type (") + - absl::StrCat(client_id.type()) + ")")); - } - return VerifyRemoteAttestation(message, remote_attestation, client_id, - remote_attestation_cert_sn); -} - -Status RemoteAttestationVerifier::VerifyRemoteAttestation( - const std::string& message, const RemoteAttestation& remote_attestation, - const std::string& privacy_key) { - // Sanity check RemoteAttestation. - if (!remote_attestation.has_certificate()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-certificate-missing")); - } - if (!remote_attestation.has_salt()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-salt-missing")); - } - if (!remote_attestation.has_signature()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-signature-missing")); - } - // Decrypt ClientIdentification containing remote attestation certificate, - // directly using an explicitly provided key |privacy_key|. - ClientIdentification client_id; - Status status = DecryptEncryptedClientIdentification( - remote_attestation.certificate(), privacy_key, &client_id); - if (!status.ok()) return status; - - if (client_id.type() != - ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) { - return (Status(error_space, INVALID_MESSAGE, - std::string("remote-attestation-invalid-client-id-type (") + - absl::StrCat(client_id.type()) + ")")); - } - std::string remote_attestation_cert_sn; - return VerifyRemoteAttestation(message, remote_attestation, client_id, - &remote_attestation_cert_sn); -} - -Status RemoteAttestationVerifier::VerifyRemoteAttestation( - const std::string& message, const RemoteAttestation& remote_attestation, - const ClientIdentification& client_id, - std::string* remote_attestation_cert_sn) { - if (!client_id.has_token()) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-token-missing")); - } - // Load and verify the certificate chain. - std::unique_ptr cert_chain(new X509CertChain); - Status status = cert_chain->LoadPem(client_id.token()); - if (!status.ok()) return status; - - if (cert_chain->GetNumCerts() < 1) { - return (Status(error_space, INVALID_MESSAGE, - "remote-attestation-empty-certificate-chain")); - } - std::string device_mode_string = - cert_chain->GetCert(0)->GetSubjectNameField(kDeviceModeFieldName); - if (device_mode_string != kExpectedDeviceMode) { - return (Status(error_space, REMOTE_ATTESTATION_FAILED, - std::string("remote-attestation-device-not-verified (") + - device_mode_string + " / " + kDeviceModeFieldName + - ")")); - } - ca_mutex_.ReaderLock(); - if (ca_ == NULL) { - ca_mutex_.ReaderUnlock(); - status = LoadCa(); - if (!status.ok()) return status; - ca_mutex_.ReaderLock(); - } - status = ca_->VerifyCertChain(*cert_chain); - ca_mutex_.ReaderUnlock(); - if (!status.ok()) { - return (Status( - error_space, REMOTE_ATTESTATION_FAILED, - std::string("remote-attestation-cert-chain-validation-failed: ") + - status.error_message())); - } - // Verify the remote attestation signature. - std::unique_ptr leaf_key; - std::string message_with_salt = message + remote_attestation.salt(); - for (size_t idx = 0; idx < cert_chain->GetNumCerts(); ++idx) { - if (!cert_chain->GetCert(idx)->IsCaCertificate()) { - leaf_key = cert_chain->GetCert(idx)->GetRsaPublicKey(); - break; - } - } - if (!leaf_key) { - return Status(error_space, REMOTE_ATTESTATION_FAILED, - "remote-attestation-cert-chain-no-leaf"); - } - - if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt, - remote_attestation.signature())) { - return (Status(error_space, REMOTE_ATTESTATION_FAILED, - "remote-attestation-signature-verification-failed: ")); - } - - *remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber(); - return OkStatus(); -} - -Status RemoteAttestationVerifier::LoadCa() { - absl::WriterMutexLock lock(&ca_mutex_); - std::unique_ptr ca_cert(new X509Cert); - Status status = ca_cert->LoadDer(absl::HexStringToBytes( - enable_test_certificates_ ? kTestRootCaDerCert : kProdRootCaDerCert)); - if (!status.ok()) { - return status; - } - ca_.reset(new X509CA(ca_cert.release())); - return OkStatus(); -} - -} // namespace widevine diff --git a/common/remote_attestation_verifier.h b/common/remote_attestation_verifier.h deleted file mode 100644 index 7ae9ed7..0000000 --- a/common/remote_attestation_verifier.h +++ /dev/null @@ -1,94 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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: -// Functionality used to verifier ChromeOS remote attestation. - -#ifndef COMMON_REMOTE_ATTESTATION_VERIFIER_H_ -#define COMMON_REMOTE_ATTESTATION_VERIFIER_H_ - -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/synchronization/mutex.h" -#include "common/status.h" -#include "common/x509_cert.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/remote_attestation.pb.h" - -namespace widevine { - -// Singleton class used to do remote attestation. Access singleton instance via -// the get() method. -// TODO(user): This class is tested as part of the Session unit tests, but -// finer unit tests should be implemented for the failure cases. -class RemoteAttestationVerifier { - public: - RemoteAttestationVerifier() : enable_test_certificates_(false) {} - - RemoteAttestationVerifier(const RemoteAttestationVerifier&) = delete; - RemoteAttestationVerifier& operator=(const RemoteAttestationVerifier&) = - delete; - - virtual ~RemoteAttestationVerifier() {} - - // Singleton accessor. - static RemoteAttestationVerifier& get(); - - // Call to use the test (non-production) remote attestation root certificate. - // This method is thread-safe. - void EnableTestDrmCertificates(bool enable); - - // Call to verify a RemoteAttestation challenge response, used in licensing - // protocol. - // |message| is the challenge message, - // |remote_attestation| is the remote attestation response to verify, - // |remote_attestation_cert_sn| is a pointer to a std::string which on successful - // return will contain the serial number for the client's remote attestation - // certificate. - // This method is thread-safe. - Status VerifyRemoteAttestation(const std::string& message, - const RemoteAttestation& remote_attestation, - std::string* remote_attestation_cert_sn); - - // Call to verify a RemoteAttestation challenge response, used in certificate - // provisioning protocol. - // |message| is the challenge message, - // |remote_attestation| is the remote attestation response to verify, - // |privacy_key| is used to decrypt the EncryptedClientIdentification within - // the |remote_attestation| message. - // This method is thread-safe. - Status VerifyRemoteAttestation(const std::string& message, - const RemoteAttestation& remote_attestation, - const std::string& privacy_key); - - private: - // Common subroutine to perform the verification. - // |message| is the challenge message, - // |remote_attestation| is the remote attestation response to verify, - // |client_id| is the decrypted client identification carrying the token, - // |remote_attestation_cert_sn| is a pointer to a std::string which on successful - // return will contain the serial number for the client's remote attestation - // certificate. - Status VerifyRemoteAttestation(const std::string& message, - const RemoteAttestation& remote_attestation, - const ClientIdentification& client_id, - std::string* remote_attestation_cert_sn); - - Status LoadCa(); - - bool enable_test_certificates_; - absl::Mutex ca_mutex_; - std::unique_ptr ca_ ABSL_GUARDED_BY(ca_mutex_); -}; - -} // namespace widevine - -#endif // COMMON_REMOTE_ATTESTATION_VERIFIER_H_ diff --git a/common/rot_id_generator.cc b/common/rot_id_generator.cc deleted file mode 100644 index 58c89fe..0000000 --- a/common/rot_id_generator.cc +++ /dev/null @@ -1,130 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Classes for generating and decrypting the root of trust id which is -// included in generated DRM Certificates. - -#include "common/rot_id_generator.h" - -#include - -#include "glog/logging.h" -#include "absl/strings/escaping.h" -#include "absl/strings/str_cat.h" -#include "common/crypto_util.h" -#include "common/ec_key.h" -#include "common/rot_id_util.h" -#include "common/sha_util.h" -#include "common/status.h" -#include "protos/public/drm_certificate.pb.h" - -namespace { - -constexpr char kRotIdLabel[] = "ROOT_OF_TRUST_ID ENCRYPTION LABEL"; -constexpr int32_t kKeyId = 0; - -std::string GenerateContext(uint32_t system_id) { - return absl::StrCat(kRotIdLabel, system_id); -} - -} // anonymous namespace - -namespace widevine { - -Status RootOfTrustIdGenerator::Generate(uint32_t system_id, - const std::string& unique_id, - RootOfTrustId* root_of_trust_id) const { - CHECK(root_of_trust_id != nullptr) << "root_of_trust_id was null."; - - if (system_id == 0) { - return Status(error::INVALID_ARGUMENT, "system id should not be 0."); - } - if (unique_id.empty()) { - return Status(error::INVALID_ARGUMENT, - "The unique id should not be empty."); - } - - root_of_trust_id->set_version( - widevine::RootOfTrustId::ROOT_OF_TRUST_ID_VERSION_1); - root_of_trust_id->set_key_id(kKeyId); - if (!ecies_encryptor_->Encrypt( - unique_id, GenerateContext(system_id), - root_of_trust_id->mutable_encrypted_unique_id())) { - root_of_trust_id->Clear(); - return Status(error::INTERNAL, "Encrypt failed."); - } - - std::string unique_id_hash = GenerateUniqueIdHash(unique_id); - if (unique_id_hash.empty()) { - root_of_trust_id->Clear(); - return Status(error::INTERNAL, "Could not generate unique id hash."); - } - - root_of_trust_id->set_unique_id_hash(GenerateRotIdHash( - root_of_trust_id->encrypted_unique_id(), system_id, unique_id_hash)); - if (root_of_trust_id->unique_id_hash().empty()) { - root_of_trust_id->Clear(); - return Status(error::INTERNAL, "Failed to generate revoked id hash."); - } - - return OkStatus(); -} - -std::string RootOfTrustIdGenerator::GenerateUniqueIdHash( - const std::string& unique_id) const { - return widevine::GenerateUniqueIdHash(unique_id, wv_shared_salt_); -} - -Status RootOfTrustIdDecryptor::DecryptUniqueId( - uint32_t system_id, const std::string& rot_encrypted_id, - std::string* unique_id) const { - CHECK(unique_id != nullptr) << "unique_id was null."; - if (system_id == 0) { - return Status(error::INVALID_ARGUMENT, "system id should not be 0."); - } - if (rot_encrypted_id.empty()) { - return Status(error::INVALID_ARGUMENT, - "The rot_encrypted_id should not be empty."); - } - - if (!ecies_decryptor_->Decrypt(rot_encrypted_id, GenerateContext(system_id), - unique_id)) { - return Status(error::INTERNAL, "Failed to decrypt rot_encrypted_id"); - } - - return OkStatus(); -} - -Status RootOfTrustIdDecryptor::VerifyAndExtractAllValues( - uint32_t system_id, const RootOfTrustId& root_of_trust_id, - std::string* device_unique_id, std::string* device_unique_id_hash) const { - CHECK(device_unique_id != nullptr) << "device_unique_id was null."; - CHECK(device_unique_id_hash != nullptr) << "device_unique_id_hash was null."; - - Status status = DecryptUniqueId( - system_id, root_of_trust_id.encrypted_unique_id(), device_unique_id); - if (!status.ok()) { - return status; - } - *device_unique_id_hash = - widevine::GenerateUniqueIdHash(*device_unique_id, wv_shared_salt_); - std::string revocation_hash = - GenerateRotIdHash(root_of_trust_id.encrypted_unique_id(), system_id, - *device_unique_id_hash); - // This should not happen unless there's a bug in the way we issue root of - // trust ids. - if (revocation_hash != root_of_trust_id.unique_id_hash()) { - return Status(error::INVALID_ARGUMENT, - "The generated revocation hash did not match the one in the " - "root_of_trust_id"); - } - return OkStatus(); -} - -} // namespace widevine diff --git a/common/rot_id_generator.h b/common/rot_id_generator.h deleted file mode 100644 index b6ae69a..0000000 --- a/common/rot_id_generator.h +++ /dev/null @@ -1,103 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Classes for generating and decrypting the root of trust id which is -// included in generated DRM Certificates. - -#ifndef COMMON_ROT_ID_GENERATOR_H_ -#define COMMON_ROT_ID_GENERATOR_H_ - -#include -#include - -#include -#include "common/ecies_crypto.h" -#include "common/rot_id_util.h" -#include "common/status.h" -#include "protos/public/drm_certificate.pb.h" - -namespace widevine { - -// The RootOfTrustIdGenerator is used to create a root of trust id that is -// associated with the keybox or OEM X.509 certificate that was used as -// authentication during provisioning. -class RootOfTrustIdGenerator { - public: - // The constructor for creating the RootOfTrustIdGenerator. |ecies_encryptor| - // is used to encrypt the unique identifier. It must not be null. The - // |wv_shared_salt| is a secret salt used in creating the hash - // component of the Root of Trust Id. The secret salt is stored securely. The - // same value is used as part of generating all Root of Trust Ids. - // The |wv_shared_salt| is also used for creating the unique id hash - // values. The unique id hash values identify revoked devices and are - // published in the DCSL and consumed by the License SDK. - RootOfTrustIdGenerator(std::unique_ptr ecies_encryptor, - const std::string& wv_shared_salt) - : ecies_encryptor_(std::move(ecies_encryptor)), - wv_shared_salt_(std::move(wv_shared_salt)) {} - - virtual ~RootOfTrustIdGenerator() {} - - // Creates the root of trust identifier. This fills the fields of the - // |root_of_trust_id|. The fields are generated per the spec at go/wv-kb-id. - // The |system_id| is required and must match the system id to which the - // |unique_id| belongs. - // Returns INVALID_ARGUMENT if |system_id| is 0, |unique_id| is empty. - // |roof_of_trust_id| is owned by the caller and must not be null. - virtual Status Generate(uint32_t system_id, const std::string& unique_id, - RootOfTrustId* root_of_trust_id) const; - - // Generates the hash of the |unique_id| per the spec in go/wv-kb-id. This - // unique id hash (aka inner hash) is the identifier used when revoking an - // individual device. The result of this hash is one of the values used to - // generate Root of Trust Id Hash. - // |unique_id| should not be empty. If it is, an empty hash - // is returned. - std::string GenerateUniqueIdHash(const std::string& unique_id) const; - - private: - std::unique_ptr ecies_encryptor_; - std::string wv_shared_salt_; -}; - -// The RootOfTrustIdDecryptor is used to decrypt the root of trust id. It -// requires an |ecies_decryptor| which must use the private key that matches -// the public key used with the RootOfTrustIdGenerator. |ecies_decryptor| -// must not be null. The RootOfTrustIdDecryptor will take ownership. -class RootOfTrustIdDecryptor { - public: - explicit RootOfTrustIdDecryptor( - std::unique_ptr ecies_decryptor, - const std::string& wv_shared_salt) - : ecies_decryptor_(std::move(ecies_decryptor)), - wv_shared_salt_(wv_shared_salt) {} - - // Decrypts the |rot_encrypted_id| using the |system_id| as part of the - // context. |unique_id| contains the decrypted value on success. - // |rot_encrypted_id| must not be empty. |unique_id| must not be null. - // Returns true on success, false on failure. - Status DecryptUniqueId(uint32_t system_id, const std::string& rot_encrypted_id, - std::string* unique_id) const; - - // Decrypts the encrypted id within the |root_of_trust_id|, extacting the - // |device_unique_id|, and generating the |device_unique_id_hash|. It then - // generates the rot id revocation hash and verifies that it matches the - // unique_id_hash from the root_of_trust_id. - Status VerifyAndExtractAllValues(uint32_t system_id, - const RootOfTrustId& root_of_trust_id, - std::string* device_unique_id, - std::string* device_unique_id_hash) const; - - private: - std::unique_ptr ecies_decryptor_; - std::string wv_shared_salt_; -}; - -} // namespace widevine -#endif // COMMON_ROT_ID_GENERATOR_H_ diff --git a/common/rot_id_generator_test.cc b/common/rot_id_generator_test.cc deleted file mode 100644 index e8b9bc1..0000000 --- a/common/rot_id_generator_test.cc +++ /dev/null @@ -1,304 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Unit tests for RootOfTrustIdGenerator and RootO -#include "common/rot_id_generator.h" - -#include -#include - -#include "google/protobuf/util/message_differencer.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/ec_key.h" -#include "common/ec_test_keys.h" -#include "common/ecies_crypto.h" -#include "common/fake_ec_key_source.h" -#include "common/rot_id_util.h" -#include "common/status.h" -#include "protos/public/drm_certificate.pb.h" - -using ::testing::_; -using ::testing::NotNull; -using ::testing::Return; - -namespace { -constexpr char kTestSharedSalt[] = "test shared salt"; -constexpr char kTestUniqueId[] = "test unique id"; -constexpr uint32_t kTestSystemId = 1234; -constexpr char kExpectedRotIdEncryptedIdHex[] = - "048aea3f16ff24a9bf03283015ee52509a551c60c7a7cc4b995b4055ce4619d4d45efde068" - "27ea78f3071f024a785244d3dfbeac5fa51c8a498da65aaca1252bd1f174166d9645b6ecd6" - "669aa0afb7b766682c02f794d67050f779ebd104a767bedef288be13d321ae79d7209b5cd3" - "4698"; - -constexpr char kExpectedRotIdHashHex[] = - "2c4dbc37092ab3e55897639d4f0dd3c824001d07eb69a3f9e6db3b846bf31828"; - -} // anonymous namespace - -namespace widevine { - -class RootOfTrustIdGeneratorTest : public ::testing::Test { - public: - RootOfTrustIdGeneratorTest() { - expected_root_of_trust_id_.set_encrypted_unique_id( - absl::HexStringToBytes(kExpectedRotIdEncryptedIdHex)); - expected_root_of_trust_id_.set_unique_id_hash( - absl::HexStringToBytes(kExpectedRotIdHashHex)); - expected_root_of_trust_id_.set_key_id(0); - expected_root_of_trust_id_.set_version( - RootOfTrustId::ROOT_OF_TRUST_ID_VERSION_1); - } - - std::unique_ptr CreateEncryptor() { - return EciesEncryptor::Create(test_keys_.public_test_key_2_secp256r1(), - &fake_ec_key_source_); - } - std::unique_ptr CreateDecryptor() { - return EciesDecryptor::Create(test_keys_.private_test_key_2_secp256r1()); - } - - protected: - ECTestKeys test_keys_; - FakeECKeySource fake_ec_key_source_; - RootOfTrustId expected_root_of_trust_id_; -}; - -class MockEciesEncryptor : public EciesEncryptor { - public: - static MockEciesEncryptor* Create() { - ECTestKeys test_keys; - std::unique_ptr ec_key = - ECPublicKey::Create(test_keys.public_test_key_1_secp256r1()); - return new MockEciesEncryptor(std::move(ec_key)); - } - MOCK_METHOD(bool, Encrypt, - (const std::string&, const std::string&, std::string*), - (const, override)); - - private: - explicit MockEciesEncryptor(std::unique_ptr ec_key) - : EciesEncryptor(std::move(ec_key), &fake_ec_key_source_) {} - - FakeECKeySource fake_ec_key_source_; -}; - -TEST_F(RootOfTrustIdGeneratorTest, GenerateIdSuccess) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - // Generate the root of trust id. - RootOfTrustId root_of_trust_id; - ASSERT_OK( - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_root_of_trust_id_, root_of_trust_id)); - - // Verify decrypted unique id. - std::string decrypted_unique_id; - EXPECT_OK(decryptor.DecryptUniqueId(kTestSystemId, - root_of_trust_id.encrypted_unique_id(), - &decrypted_unique_id)); - EXPECT_EQ(kTestUniqueId, decrypted_unique_id); - - // Verify hashed unique id matches. - std::string unique_id_hash = generator.GenerateUniqueIdHash(kTestUniqueId); - EXPECT_TRUE(IsRotIdRevoked>( - root_of_trust_id.encrypted_unique_id(), kTestSystemId, - root_of_trust_id.unique_id_hash(), {unique_id_hash})); -} - -TEST_F(RootOfTrustIdGeneratorTest, GenerateIdUniqueSuccess) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - std::string rot_encrypted_id; - std::string rot_id_hash; - - // Generate the root of trust id. - RootOfTrustId root_of_trust_id; - ASSERT_OK( - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_root_of_trust_id_, root_of_trust_id)); - - // Generate a second root of trust id for the same unique id. - // This must generate a different looking id. - // First, assign a new ephemeral to the fake key source. - fake_ec_key_source_.SetKey(ECPrivateKey::SECP256R1, - test_keys_.private_test_key_2_secp256r1(), - test_keys_.public_test_key_2_secp256r1()); - RootOfTrustId second_root_of_trust_id; - ASSERT_OK(generator.Generate(kTestSystemId, kTestUniqueId, - &second_root_of_trust_id)); - EXPECT_FALSE(second_root_of_trust_id.encrypted_unique_id().empty()); - EXPECT_NE(kTestUniqueId, second_root_of_trust_id.encrypted_unique_id()); - EXPECT_FALSE(second_root_of_trust_id.unique_id_hash().empty()); - - // Verify that the second id does not equal the first. - EXPECT_NE(root_of_trust_id.encrypted_unique_id(), - second_root_of_trust_id.encrypted_unique_id()); - EXPECT_NE(root_of_trust_id.unique_id_hash(), - second_root_of_trust_id.unique_id_hash()); - - // Verify second decrypted unique id. - std::string decrypted_unique_id; - EXPECT_OK(decryptor.DecryptUniqueId( - kTestSystemId, second_root_of_trust_id.encrypted_unique_id(), - &decrypted_unique_id)); - EXPECT_EQ(kTestUniqueId, decrypted_unique_id); - - // Verify hashed unique id matches. - std::string unique_id_hash = generator.GenerateUniqueIdHash(kTestUniqueId); - EXPECT_TRUE(IsRotIdRevoked>( - second_root_of_trust_id.encrypted_unique_id(), kTestSystemId, - second_root_of_trust_id.unique_id_hash(), {unique_id_hash})); -} - -TEST_F(RootOfTrustIdGeneratorTest, GenerateIdFailedEncryption) { - MockEciesEncryptor* mock_encryptor = MockEciesEncryptor::Create(); - ASSERT_THAT(mock_encryptor, NotNull()); - RootOfTrustIdGenerator generator( - std::unique_ptr(mock_encryptor), kTestSharedSalt); - - EXPECT_CALL(*mock_encryptor, Encrypt(_, _, _)) - .Times(1) - .WillOnce(Return(false)) - .RetiresOnSaturation(); - - std::string rot_encrypted_id; - std::string rot_id_hash; - - // Attempt to generate the root of trust id. - RootOfTrustId root_of_trust_id; - EXPECT_EQ(error::INTERNAL, - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id) - .error_code()); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - RootOfTrustId::default_instance(), root_of_trust_id)); -} - -TEST_F(RootOfTrustIdGeneratorTest, GenerateIdEmptyIdFail) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustId root_of_trust_id; - - // Should fail because the id is blank. - EXPECT_EQ( - error::INVALID_ARGUMENT, - generator.Generate(kTestSystemId, "", &root_of_trust_id).error_code()); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - RootOfTrustId::default_instance(), root_of_trust_id)); -} - -TEST_F(RootOfTrustIdGeneratorTest, GenerateIdNullRotIdFail) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - - // Should fail because the id is blank. - EXPECT_DEATH(generator.Generate(kTestSystemId, kTestUniqueId, - nullptr /* root of trust id*/), - "root_of_trust_id"); -} - -TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdMismatchFails) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - // Generate the root of trust id. - RootOfTrustId root_of_trust_id; - ASSERT_OK( - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_root_of_trust_id_, root_of_trust_id)); - - // Attempt to decrypt with different system id. Should fail. - std::string decrypted_unique_id; - EXPECT_EQ(error::INTERNAL, - decryptor - .DecryptUniqueId(kTestSystemId + 1, - root_of_trust_id.encrypted_unique_id(), - &decrypted_unique_id) - .error_code()); -} - -TEST_F(RootOfTrustIdGeneratorTest, DecryptorBlankUniqueId) { - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - // Attempt to decrypt empty encrypted id. - std::string decrypted_unique_id; - EXPECT_EQ(error::INVALID_ARGUMENT, - decryptor.DecryptUniqueId(kTestSystemId, "", &decrypted_unique_id) - .error_code()); -} - -TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdNullDecryptedIdFails) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - // Generate the root of trust id. - RootOfTrustId root_of_trust_id; - ASSERT_OK( - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_root_of_trust_id_, root_of_trust_id)); - - // Attempt to decrypt with a nullptr for the decrypted id. - std::string decrypted_unique_id; - EXPECT_DEATH( - decryptor.DecryptUniqueId( - kTestSystemId, root_of_trust_id.encrypted_unique_id(), nullptr), - "unique_id"); -} - -TEST_F(RootOfTrustIdGeneratorTest, VerifyAndExtractAllValuesSuccess) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - // Generate the root of trust id. - RootOfTrustId root_of_trust_id; - ASSERT_OK( - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_root_of_trust_id_, root_of_trust_id)); - - // Verify decrypted unique id. - std::string decrypted_unique_id; - std::string decrypted_unique_id_hash; - EXPECT_OK(decryptor.VerifyAndExtractAllValues(kTestSystemId, root_of_trust_id, - &decrypted_unique_id, - &decrypted_unique_id_hash)); - EXPECT_EQ(kTestUniqueId, decrypted_unique_id); - EXPECT_EQ(generator.GenerateUniqueIdHash(kTestUniqueId), - decrypted_unique_id_hash); -} - -TEST_F(RootOfTrustIdGeneratorTest, VerifyAndExtractAllValuesSystemIdMismatch) { - RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt); - RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt); - - // Generate the root of trust id. - RootOfTrustId root_of_trust_id; - ASSERT_OK( - generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)); - EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals( - expected_root_of_trust_id_, root_of_trust_id)); - - // Verify decrypted unique id. - std::string decrypted_unique_id; - std::string decrypted_unique_id_hash; - EXPECT_EQ(error::INTERNAL, - decryptor - .VerifyAndExtractAllValues(kTestSystemId + 1, root_of_trust_id, - &decrypted_unique_id, - &decrypted_unique_id_hash) - .error_code()); -} - -} // namespace widevine diff --git a/common/rot_id_util.cc b/common/rot_id_util.cc deleted file mode 100644 index a43e942..0000000 --- a/common/rot_id_util.cc +++ /dev/null @@ -1,45 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Helper methods for the Root of Trust Id. - -#include "common/rot_id_util.h" - -#include - -#include "glog/logging.h" -#include "absl/strings/str_cat.h" -#include "common/crypto_util.h" -#include "common/ec_key.h" -#include "common/sha_util.h" - -namespace widevine { - -std::string GenerateRotIdHash(const std::string& salt, uint32_t system_id, - const std::string& unique_id_hash) { - if (salt.empty() || unique_id_hash.empty()) { - return ""; - } - return Sha256_Hash(absl::StrCat(salt, system_id, unique_id_hash)); -} - -std::string GenerateUniqueIdHash(const std::string& unique_id, - const std::string& salt) { - if (unique_id.empty()) { - LOG(WARNING) << "unique_id should not be empty."; - return ""; - } - if (salt.empty()) { - LOG(WARNING) << "salt should not be empty."; - return ""; - } - return widevine::Sha256_Hash(absl::StrCat(unique_id, salt)); -} - -} // namespace widevine diff --git a/common/rot_id_util.h b/common/rot_id_util.h deleted file mode 100644 index 835985e..0000000 --- a/common/rot_id_util.h +++ /dev/null @@ -1,67 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Helper methods for the Root of Trust Id. - -#ifndef COMMON_ROT_ID_UTIL_H_ -#define COMMON_ROT_ID_UTIL_H_ - -#include -#include - -#include -#include "common/ec_key.h" -#include "common/local_ec_key_source.h" - -namespace widevine { - -// Helper function that generates the unique id hash from the |unique_id| and -// the |salt|. |salt| is an internal secret. -// -// Returns the hash value on success. -// If |salt| or |unique_id| are empty, this will return an empty string. -std::string GenerateUniqueIdHash(const std::string& unique_id, - const std::string& salt); - -// Helper function that generates the hash for the ROT id from the -// |unique_id_hash|, the |system_id| and the |salt|. |salt| is typically an -// encrypted unique id. Since we use an ephemeral eliptic curve key as part of -// the encrypted unique id, the value is effectively random can be used as a -// salt. -// Returns the hash value on success. -// If |salt| or |unique_id_hash| are empty, this will return an empty -// string. -std::string GenerateRotIdHash(const std::string& salt, uint32_t system_id, - const std::string& unique_id_hash); - -// Helper function that compares the |rot_id_hash| to a hash of each of the -// |revoked_ids|. The |revoked_ids| are the unique id hash (aka inner hash) -// values as defined in the spec at go/wv-kb-id. The |encrypted_unique_id| and -// |system_id| are used to compute the hash of each of the |revoked_ids|. -// Returns true if any of the revoked_ids match. -template -bool IsRotIdRevoked(const std::string& encrypted_unique_id, uint32_t system_id, - const std::string& rot_id_hash, const V& revoked_ids) { - // This could conceivably happen for legacy DRM certificates without a ROT id. - // No need to match if there's nothing to match against. - if (encrypted_unique_id.empty() || rot_id_hash.empty()) { - return false; - } - - for (const auto& revoked_id : revoked_ids) { - if (GenerateRotIdHash(encrypted_unique_id, system_id, revoked_id) == - rot_id_hash) { - return true; - } - } - return false; -} - -} // namespace widevine -#endif // COMMON_ROT_ID_UTIL_H_ diff --git a/common/rot_id_util_test.cc b/common/rot_id_util_test.cc deleted file mode 100644 index 9b89d98..0000000 --- a/common/rot_id_util_test.cc +++ /dev/null @@ -1,85 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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: -// Unit tests for the rot_id_util helper methods. - -#include "common/rot_id_util.h" - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" - -namespace { -constexpr char kFakeEncryptedId[] = "fake encrypted id"; -constexpr char kFakeUniqueIdHash[] = "fake unique_id hash"; - -constexpr char kFakeUniqueId[] = "fake unique_id"; -constexpr char kFakeSecretSalt[] = "fake secret salt"; - -// This is the ROT ID Hash generated from the fake values. -constexpr char kRotIdHashHex[] = - "0a757dde0f1080b60f34bf8e46af573ce987b5ed1c831b44952e2feed5243a95"; -// This is the unique id hash generated from the fake unique id value. -constexpr char kUniqueIdHashHex[] = - "da20922e84b48e52223496f44b07632a4db19d488cd71cf813de300b9d244e06"; - -constexpr uint32_t kFakeSystemId = 1234; -constexpr uint32_t kOtherFakeSystemId = 9876; - -} // anonymous namespace - -namespace widevine { - -TEST(RotIdUtilTest, IsRotIdRevokedMatches) { - ASSERT_TRUE(IsRotIdRevoked>( - kFakeEncryptedId, kFakeSystemId, absl::HexStringToBytes(kRotIdHashHex), - {"NO MATCH UNIQUE ID HASH 1", kFakeUniqueIdHash})); -} - -TEST(RotIdUtilTest, IsRotIdRevokedNoMatchSystemId) { - ASSERT_FALSE(IsRotIdRevoked>( - kFakeEncryptedId, kOtherFakeSystemId, - absl::HexStringToBytes(kRotIdHashHex), - {"NO MATCH UNIQUE ID HASH 1", kFakeUniqueIdHash})); -} - -TEST(RotIdUtilTest, IsRotIdRevokedNoMatch) { - ASSERT_FALSE(IsRotIdRevoked>( - kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash, - {"NO MATCH UNIQUE ID HASH 1", "NO MATCH UNIQUE ID HASH 2"})); -} - -TEST(RotIdUtilTest, IsRotIdRevokedEmptyList) { - ASSERT_FALSE(IsRotIdRevoked>( - kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash, - {/* Intentionally empty vector */})); -} - -// This test really only ensures the stability of the implementation. If the -// hash ever changes, then it will introduce problems into the ecosystem. -TEST(RotIdUtilTest, GenerateRotIdHashSuccess) { - ASSERT_EQ( - absl::HexStringToBytes(kRotIdHashHex), - GenerateRotIdHash(kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash)); -} - -// This test really only ensures the stability of the GenerateUniqueIdHash -// implementation. If the hash ever changes, then it will introduce problems -// into the ecosystem. -TEST(RotIdUtilTest, GenerateUniqueIdHashSuccess) { - ASSERT_EQ(absl::HexStringToBytes(kUniqueIdHashHex), - GenerateUniqueIdHash(kFakeUniqueId, kFakeSecretSalt)); -} - -TEST(RotIdUtilTest, GenerateUniqueIdHashEmptyValues) { - ASSERT_EQ("", GenerateUniqueIdHash(kFakeUniqueId, "")); - ASSERT_EQ("", GenerateUniqueIdHash("", kFakeSecretSalt)); -} - -} // namespace widevine diff --git a/common/rsa_key.cc b/common/rsa_key.cc index 809ae03..d788986 100644 --- a/common/rsa_key.cc +++ b/common/rsa_key.cc @@ -117,41 +117,6 @@ bool RsaPrivateKey::Decrypt(const std::string& encrypted_message, return true; } -bool RsaPrivateKey::GenerateSignature(const std::string& message, - std::string* signature) const { - DCHECK(signature); - - if (message.empty()) { - LOG(ERROR) << "Message to be signed is empty"; - return false; - } - // Hash the message using SHA1. - std::string message_digest = Sha1_Hash(message); - - // Add PSS padding. - size_t rsa_size = RSA_size(key_); - std::string padded_digest(rsa_size, 0); - if (!RSA_padding_add_PKCS1_PSS_mgf1( - key_, reinterpret_cast(&padded_digest[0]), - reinterpret_cast(&message_digest[0]), EVP_sha1(), - EVP_sha1(), kPssSaltLength)) { - LOG(ERROR) << "RSA padding failure: " - << OpenSSLErrorString(ERR_get_error()); - return false; - } - // Encrypt PSS padded digest. - signature->assign(rsa_size, 0); - if (RSA_private_encrypt(padded_digest.size(), - reinterpret_cast(&padded_digest[0]), - reinterpret_cast(&(*signature)[0]), - key_, RSA_NO_PADDING) != - static_cast(signature->size())) { - LOG(ERROR) << "RSA private encrypt failure: " - << OpenSSLErrorString(ERR_get_error()); - return false; - } - return true; -} bool RsaPrivateKey::GenerateSignature(const std::string& message, HashAlgorithm hash_algorithm, @@ -270,46 +235,6 @@ bool RsaPublicKey::Encrypt(const std::string& clear_message, return true; } -bool RsaPublicKey::VerifySignature(const std::string& message, - const std::string& signature) const { - if (message.empty()) { - LOG(ERROR) << "Signed message is empty"; - return false; - } - size_t rsa_size = RSA_size(key_); - if (signature.size() != rsa_size) { - LOG(ERROR) << "Message signature is of the wrong size (expected " - << rsa_size << ", actual " << signature.size() << ")"; - return false; - } - // Decrypt the signature. - std::string padded_digest(signature.size(), 0); - if (RSA_public_decrypt( - signature.size(), - const_cast( - reinterpret_cast(signature.data())), - reinterpret_cast(&padded_digest[0]), key_, - RSA_NO_PADDING) != static_cast(rsa_size)) { - LOG(ERROR) << "RSA public decrypt failure: " - << OpenSSLErrorString(ERR_get_error()); - return false; - } - // Hash the message using SHA1. - std::string message_digest = Sha1_Hash(message); - - // Verify PSS padding. - if (RSA_verify_PKCS1_PSS_mgf1( - key_, reinterpret_cast(&message_digest[0]), - EVP_sha1(), EVP_sha1(), - reinterpret_cast(&padded_digest[0]), - kPssSaltLength) == 0) { - LOG(ERROR) << "RSA Verify PSS padding failure: " - << OpenSSLErrorString(ERR_get_error()); - return false; - } - return true; -} - bool RsaPublicKey::VerifySignature(const std::string& message, HashAlgorithm hash_algorithm, const std::string& signature) const { diff --git a/common/rsa_key.h b/common/rsa_key.h index 9c4c212..0a8f9ba 100644 --- a/common/rsa_key.h +++ b/common/rsa_key.h @@ -41,14 +41,6 @@ class RsaPrivateKey { virtual bool Decrypt(const std::string& encrypted_message, std::string* decrypted_message) const; - // Generate RSSASSA-PSS signature. Caller retains ownership of all parameters. - // Returns true if successful, false otherwise. - // TODO(b/155438325): remove this function after the below function is fully - // propagated. - ABSL_DEPRECATED( - "Use the below function with |hash_algorithm| argument instead.") - virtual bool GenerateSignature(const std::string& message, - std::string* signature) const; // Generate RSSASSA-PSS signature. Caller retains ownership of all parameters. // |hash_algorithm| indicates the hash algorithm used. Returns true if @@ -109,14 +101,6 @@ class RsaPublicKey { virtual bool Encrypt(const std::string& clear_message, std::string* encrypted_message) const; - // Verify RSSASSA-PSS signature. Caller retains ownership of all parameters. - // Returns true if validation succeeds, false otherwise. - // TODO(b/155438325): remove this function after the below function is fully - // propagated. - ABSL_DEPRECATED( - "Use the below function with |hash_algorithm| argument instead.") - virtual bool VerifySignature(const std::string& message, - const std::string& signature) const; // Verify RSSASSA-PSS signature. Caller retains ownership of all parameters. // |hash_algorithm| indicates the hash algorithm used. Returns true if diff --git a/common/rsa_key_test.cc b/common/rsa_key_test.cc deleted file mode 100644 index e0822fd..0000000 --- a/common/rsa_key_test.cc +++ /dev/null @@ -1,268 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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: -// Unit test for rsa_key RSA encryption and signing. - -#include "common/rsa_key.h" - -#include - -#include "testing/gunit.h" -#include "common/rsa_test_keys.h" -#include "common/rsa_util.h" - -namespace widevine { - -static const char kTestMessage[] = - "A fool thinks himself to be wise, but a wise man knows himself to be a " - "fool."; - -class RsaKeyTest : public ::testing::Test { - protected: - void TestEncryption(std::unique_ptr private_key, - std::unique_ptr public_key); - - void TestSigning(std::unique_ptr private_key, - std::unique_ptr public_key); - - void TestSigningSha256Pkcs7(std::unique_ptr private_key, - std::unique_ptr public_key); - - RsaTestKeys test_keys_; - RsaKeyFactory factory_; -}; - -TEST_F(RsaKeyTest, CopyConstructor) { - std::unique_ptr private_key( - RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits())); - std::unique_ptr public_key( - RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits())); - - std::unique_ptr private_key_copy( - new RsaPrivateKey(*private_key)); - std::unique_ptr public_key_copy(new RsaPublicKey(*public_key)); - - EXPECT_TRUE(public_key_copy->MatchesPublicKey(*public_key)); - EXPECT_TRUE(public_key_copy->MatchesPrivateKey(*private_key)); - - EXPECT_TRUE(private_key_copy->MatchesPublicKey(*public_key)); - EXPECT_TRUE(private_key_copy->MatchesPrivateKey(*private_key)); -} - -void RsaKeyTest::TestEncryption(std::unique_ptr private_key, - std::unique_ptr public_key) { - ASSERT_TRUE(private_key); - ASSERT_TRUE(public_key); - std::string encrypted_message; - EXPECT_TRUE(public_key->Encrypt(kTestMessage, &encrypted_message)); - std::string decrypted_message; - EXPECT_TRUE(private_key->Decrypt(encrypted_message, &decrypted_message)); - EXPECT_EQ(kTestMessage, decrypted_message); - // Add a byte to the encrypted message. - std::string bad_enc_message(encrypted_message); - bad_enc_message += '\0'; - EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message)); - // Remove a byte from the encrypted message. - bad_enc_message = encrypted_message.substr(0, encrypted_message.size() - 1); - EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message)); - // Change a byte in the encrypted message. - bad_enc_message = encrypted_message; - bad_enc_message[128] ^= 0x55; - EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message)); -} - -void RsaKeyTest::TestSigning(std::unique_ptr private_key, - std::unique_ptr public_key) { - ASSERT_TRUE(private_key); - ASSERT_TRUE(public_key); - std::string signature; - EXPECT_TRUE(private_key->GenerateSignature(kTestMessage, &signature)); - EXPECT_TRUE(public_key->VerifySignature(kTestMessage, signature)); - // Add a byte to the signature. - std::string bad_signature(signature); - bad_signature += '\0'; - EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature)); - // Remove a byte from the signature. - bad_signature = signature.substr(0, signature.size() - 1); - EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature)); - // Change a byte in the signature. - bad_signature = signature; - bad_signature[32] ^= 0x55; - EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature)); -} - -void RsaKeyTest::TestSigningSha256Pkcs7( - std::unique_ptr private_key, - std::unique_ptr public_key) { - ASSERT_TRUE(private_key); - ASSERT_TRUE(public_key); - std::string signature; - EXPECT_TRUE( - private_key->GenerateSignatureSha256Pkcs7(kTestMessage, &signature)); - EXPECT_TRUE(public_key->VerifySignatureSha256Pkcs7(kTestMessage, signature)); - // Add a byte to the signature. - std::string bad_signature(signature); - bad_signature += '\0'; - EXPECT_FALSE( - public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature)); - // Remove a byte from the signature. - bad_signature = signature.substr(0, signature.size() - 1); - EXPECT_FALSE( - public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature)); - // Change a byte in the signature. - bad_signature = signature; - bad_signature[32] ^= 0x55; - EXPECT_FALSE( - public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature)); -} - -TEST_F(RsaKeyTest, BadKey) { - std::unique_ptr private_key( - RsaPrivateKey::Create("bad_private_key")); - EXPECT_TRUE(!private_key); - std::unique_ptr public_key( - RsaPublicKey::Create("bad_public_key")); - EXPECT_TRUE(!public_key); -} - -TEST_F(RsaKeyTest, EncryptAndDecrypt_3072) { - const std::string& private_key = test_keys_.private_test_key_1_3072_bits(); - const std::string& public_key = test_keys_.public_test_key_1_3072_bits(); - TestEncryption( - std::unique_ptr(RsaPrivateKey::Create(private_key)), - std::unique_ptr(RsaPublicKey::Create(public_key))); - TestEncryption(factory_.CreateFromPkcs1PrivateKey(private_key), - factory_.CreateFromPkcs1PublicKey(public_key)); -} - -TEST_F(RsaKeyTest, EncryptAndDecrypt_2048) { - const std::string& private_key = test_keys_.private_test_key_2_2048_bits(); - const std::string& public_key = test_keys_.public_test_key_2_2048_bits(); - TestEncryption( - std::unique_ptr(RsaPrivateKey::Create(private_key)), - std::unique_ptr(RsaPublicKey::Create(public_key))); - - std::string pkcs8_key; - std::string passphrase("passphrase"); - ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( - private_key, passphrase, &pkcs8_key)); - TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase), - factory_.CreateFromPkcs1PublicKey(public_key)); - - ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key)); - TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()), - factory_.CreateFromPkcs1PublicKey(public_key)); -} - -TEST_F(RsaKeyTest, RsaPublicKeyFromPrivateKey) { - std::unique_ptr private_key( - RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits())); - ASSERT_TRUE(private_key); - std::unique_ptr public_key(new RsaPublicKey(*private_key)); - ASSERT_TRUE(public_key); - - EXPECT_TRUE(private_key->MatchesPublicKey(*public_key)); - EXPECT_TRUE(public_key->MatchesPrivateKey(*private_key)); - - TestEncryption(std::move(private_key), std::move(public_key)); -} - -TEST_F(RsaKeyTest, SignAndVerify_3072) { - const std::string& private_key = test_keys_.private_test_key_1_3072_bits(); - const std::string& public_key = test_keys_.public_test_key_1_3072_bits(); - TestSigning( - std::unique_ptr(RsaPrivateKey::Create(private_key)), - std::unique_ptr(RsaPublicKey::Create(public_key))); - TestSigning(factory_.CreateFromPkcs1PrivateKey(private_key), - factory_.CreateFromPkcs1PublicKey(public_key)); -} - -TEST_F(RsaKeyTest, SignAndVerify_2048) { - const std::string& private_key = test_keys_.private_test_key_2_2048_bits(); - const std::string& public_key = test_keys_.public_test_key_2_2048_bits(); - TestSigning( - std::unique_ptr(RsaPrivateKey::Create(private_key)), - std::unique_ptr(RsaPublicKey::Create(public_key))); - - std::string pkcs8_key; - std::string passphrase("passphrase"); - ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( - private_key, passphrase, &pkcs8_key)); - TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase), - factory_.CreateFromPkcs1PublicKey(public_key)); - - ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key)); - TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()), - factory_.CreateFromPkcs1PublicKey(public_key)); -} - -TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_3072) { - const std::string& private_key = test_keys_.private_test_key_1_3072_bits(); - const std::string& public_key = test_keys_.public_test_key_1_3072_bits(); - TestSigningSha256Pkcs7( - std::unique_ptr(RsaPrivateKey::Create(private_key)), - std::unique_ptr(RsaPublicKey::Create(public_key))); - TestSigningSha256Pkcs7(factory_.CreateFromPkcs1PrivateKey(private_key), - factory_.CreateFromPkcs1PublicKey(public_key)); -} - -TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_2048) { - const std::string& private_key = test_keys_.private_test_key_2_2048_bits(); - const std::string& public_key = test_keys_.public_test_key_2_2048_bits(); - TestSigningSha256Pkcs7( - std::unique_ptr(RsaPrivateKey::Create(private_key)), - std::unique_ptr(RsaPublicKey::Create(public_key))); - - std::string pkcs8_key; - std::string passphrase("passphrase"); - ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( - private_key, passphrase, &pkcs8_key)); - TestSigningSha256Pkcs7( - factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase), - factory_.CreateFromPkcs1PublicKey(public_key)); - - ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key)); - TestSigningSha256Pkcs7( - factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()), - factory_.CreateFromPkcs1PublicKey(public_key)); -} - -TEST_F(RsaKeyTest, KeySize) { - std::unique_ptr private_key( - RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits())); - std::unique_ptr public_key( - RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits())); - - EXPECT_EQ(256, private_key->KeySize()); - EXPECT_EQ(256, public_key->KeySize()); -} - -TEST_F(RsaKeyTest, RsaKeyMatch) { - std::unique_ptr private_key2( - RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits())); - std::unique_ptr private_key3( - RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits())); - std::unique_ptr public_key2( - RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits())); - std::unique_ptr public_key3( - RsaPublicKey::Create(test_keys_.public_test_key_3_2048_bits())); - - EXPECT_TRUE(public_key2->MatchesPublicKey(*public_key2)); - EXPECT_FALSE(public_key2->MatchesPublicKey(*public_key3)); - EXPECT_TRUE(public_key2->MatchesPrivateKey(*private_key2)); - EXPECT_FALSE(public_key2->MatchesPrivateKey(*private_key3)); - - EXPECT_TRUE(private_key2->MatchesPublicKey(*public_key2)); - EXPECT_FALSE(private_key2->MatchesPublicKey(*public_key3)); - EXPECT_TRUE(private_key2->MatchesPrivateKey(*private_key2)); - EXPECT_FALSE(private_key2->MatchesPrivateKey(*private_key3)); -} - -} // namespace widevine diff --git a/common/rsa_test_keys.cc b/common/rsa_test_keys.cc deleted file mode 100644 index 315ae45..0000000 --- a/common/rsa_test_keys.cc +++ /dev/null @@ -1,786 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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: -// RSA keys generated using fake_prng for purposes of testing. - -#include "common/rsa_test_keys.h" - -namespace widevine { - -static const unsigned char kTestRsaPrivateKey1_3072[] = { - 0x30, 0x82, 0x06, 0xe3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x81, 0x00, - 0xa5, 0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, - 0x78, 0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, - 0x0f, 0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, - 0xca, 0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, - 0x1b, 0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, - 0x46, 0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, - 0x01, 0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, - 0x5c, 0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, - 0x14, 0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, - 0xcd, 0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, - 0xb6, 0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, - 0xde, 0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, - 0x31, 0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, - 0x3a, 0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, - 0x90, 0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, - 0x49, 0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, - 0x5f, 0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, - 0xda, 0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, - 0x17, 0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, - 0x30, 0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, - 0xaf, 0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, - 0x16, 0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, - 0x42, 0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, - 0xf9, 0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, - 0xe4, 0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, - 0x4a, 0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, - 0x72, 0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, - 0xde, 0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, - 0x04, 0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, - 0x1b, 0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, - 0x33, 0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, - 0x67, 0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, - 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x80, 0x5a, 0x09, 0x3f, - 0x9e, 0x2e, 0x4d, 0x26, 0x50, 0x7b, 0x70, 0x21, 0xb0, 0x0c, 0x25, 0x21, - 0x1f, 0xd9, 0x89, 0x5a, 0xca, 0x35, 0x23, 0x0b, 0x58, 0xa9, 0x7d, 0xf6, - 0x19, 0xc4, 0x29, 0x87, 0xc7, 0xd4, 0x94, 0x85, 0xb4, 0x2c, 0xaf, 0x62, - 0xb1, 0xe8, 0x62, 0x5b, 0xda, 0xdb, 0x70, 0x40, 0x37, 0xb1, 0x4e, 0x0c, - 0xc8, 0x62, 0xee, 0xa2, 0xfc, 0x3c, 0xd2, 0x39, 0x90, 0x15, 0x2c, 0xba, - 0x20, 0x50, 0xb7, 0x82, 0x2a, 0xa0, 0x76, 0x83, 0x20, 0x7f, 0x56, 0x73, - 0x43, 0x8a, 0x9b, 0xa7, 0x6c, 0x63, 0xb6, 0xad, 0x56, 0xb2, 0x8a, 0xb2, - 0xbc, 0x8f, 0xe2, 0xef, 0x83, 0x9d, 0x98, 0x0b, 0xc7, 0x62, 0x0e, 0x51, - 0x6e, 0x57, 0x1d, 0x1b, 0x0e, 0x3a, 0xea, 0x3b, 0x76, 0x63, 0x35, 0xd0, - 0xd1, 0xcf, 0xbe, 0xad, 0xbb, 0x1d, 0xde, 0x0f, 0x05, 0x48, 0x55, 0x29, - 0xc1, 0xbc, 0x21, 0xc7, 0x87, 0xf2, 0x75, 0x12, 0x7d, 0x92, 0x9e, 0xbf, - 0xad, 0x04, 0x68, 0xc4, 0xc9, 0x9d, 0x35, 0xd6, 0xa8, 0x62, 0xc1, 0x69, - 0x6a, 0xb6, 0x41, 0xb7, 0x37, 0x66, 0xdf, 0xb2, 0xb9, 0x8c, 0x8b, 0x15, - 0x08, 0x4c, 0x3d, 0xf1, 0xed, 0x82, 0x0f, 0xe3, 0xd5, 0xff, 0x46, 0xbd, - 0xf7, 0x85, 0x43, 0xc0, 0x8b, 0xba, 0x47, 0xf1, 0x41, 0x57, 0xc3, 0x7f, - 0x8b, 0x0d, 0x48, 0xea, 0xc2, 0xed, 0xc0, 0x69, 0x84, 0xb6, 0x32, 0x08, - 0x49, 0x74, 0x14, 0x84, 0xa4, 0x1b, 0x48, 0x5b, 0xec, 0xd3, 0x0b, 0x12, - 0x2b, 0x4c, 0x9e, 0x5c, 0x01, 0x60, 0xad, 0xef, 0xcb, 0x2b, 0x56, 0x84, - 0x07, 0xfa, 0x62, 0xc6, 0x08, 0x92, 0x98, 0x70, 0xc9, 0x5b, 0x18, 0xc8, - 0xfa, 0x27, 0x0c, 0xe2, 0xbd, 0xfb, 0x3e, 0x43, 0xa5, 0xb7, 0x06, 0x2c, - 0x4e, 0xf1, 0x07, 0x5d, 0x8d, 0xdd, 0x53, 0xc5, 0x8c, 0x4a, 0xf2, 0x2f, - 0x8e, 0x80, 0x96, 0x16, 0xc0, 0xfc, 0xf9, 0x20, 0x4f, 0x35, 0xc7, 0x53, - 0x8b, 0x2d, 0x37, 0x43, 0x93, 0x3d, 0x74, 0x3f, 0x63, 0xf7, 0x0b, 0xbd, - 0x46, 0xe4, 0x51, 0x67, 0x33, 0x57, 0x15, 0xf5, 0x59, 0x27, 0x66, 0xe8, - 0xe2, 0x4b, 0xa3, 0x93, 0x03, 0x8a, 0x9c, 0x05, 0x13, 0xf2, 0xcb, 0xf7, - 0x9c, 0x68, 0xe7, 0x16, 0x4b, 0x8e, 0x59, 0x71, 0x2b, 0x73, 0x9b, 0xb9, - 0xae, 0x50, 0xfa, 0xd7, 0xd3, 0x34, 0x17, 0x1d, 0x62, 0x88, 0xbd, 0x8c, - 0xba, 0x5a, 0x6b, 0x6a, 0x5e, 0xb3, 0xa5, 0x80, 0xca, 0xbb, 0xb9, 0xb5, - 0xa8, 0x2e, 0xb1, 0x61, 0x6e, 0xd5, 0xd6, 0x62, 0x98, 0x4a, 0xb0, 0xb8, - 0x76, 0xa9, 0x19, 0x5c, 0xe2, 0xbe, 0xb3, 0x9b, 0x4a, 0x39, 0xf5, 0xe6, - 0xbb, 0x11, 0x6e, 0x13, 0x13, 0x38, 0xb8, 0x1f, 0x21, 0x19, 0xf5, 0xa7, - 0x76, 0x93, 0xb3, 0x56, 0xfa, 0xcc, 0x74, 0xbc, 0x19, 0x02, 0x81, 0xc1, - 0x00, 0xd1, 0xd1, 0x72, 0x57, 0xe5, 0xb0, 0x1c, 0x09, 0x05, 0xbb, 0x55, - 0x89, 0x3c, 0x4a, 0x81, 0x90, 0x9a, 0xf9, 0x32, 0x63, 0x41, 0xad, 0x6a, - 0x5f, 0x65, 0x94, 0x92, 0xcc, 0xf7, 0xc7, 0x53, 0x93, 0xa0, 0xf7, 0xbe, - 0x48, 0x82, 0x63, 0x31, 0x7b, 0xd0, 0x82, 0x09, 0xbb, 0x0a, 0xbc, 0x60, - 0xc9, 0x4d, 0x83, 0xe4, 0x5d, 0x50, 0xe6, 0x5f, 0x8b, 0x47, 0x07, 0xa3, - 0x3a, 0x36, 0x97, 0xaa, 0x21, 0x70, 0x7f, 0xd5, 0x6c, 0xb0, 0x56, 0xf5, - 0x5c, 0x48, 0x74, 0x2a, 0xdd, 0xfe, 0x94, 0x83, 0x05, 0xe0, 0x3d, 0x5d, - 0xdd, 0x5a, 0x05, 0xcb, 0x47, 0xd7, 0xf9, 0x89, 0x55, 0xaa, 0x0b, 0x21, - 0xc0, 0x71, 0x5d, 0xe1, 0x4c, 0x6a, 0x45, 0x86, 0x86, 0xf2, 0xb9, 0x38, - 0x6a, 0x56, 0x51, 0x0d, 0x7d, 0xac, 0x30, 0x31, 0xca, 0x2d, 0xaa, 0xaa, - 0xba, 0xcc, 0x12, 0x40, 0xc1, 0x0d, 0xa6, 0xc1, 0x7d, 0x22, 0xec, 0xb6, - 0x51, 0x45, 0xfe, 0x4e, 0xbb, 0x4a, 0xd2, 0xba, 0x9b, 0xa2, 0xcc, 0x28, - 0x2b, 0x01, 0x53, 0x53, 0xf3, 0xa9, 0x5a, 0x8f, 0xeb, 0xb7, 0xb8, 0x62, - 0x6b, 0x8a, 0x79, 0x24, 0xcc, 0x86, 0x34, 0x45, 0xe2, 0xad, 0x1d, 0xd0, - 0x4c, 0xc9, 0x77, 0x2a, 0xf9, 0x1a, 0xe8, 0x58, 0x78, 0x51, 0x8a, 0xea, - 0x3f, 0x90, 0x36, 0x46, 0x2a, 0xc0, 0x71, 0x41, 0x83, 0x2c, 0x48, 0xee, - 0xc5, 0x02, 0x81, 0xc1, 0x00, 0xc9, 0xc8, 0xce, 0xc4, 0x50, 0xb2, 0x26, - 0xcb, 0x35, 0x78, 0x55, 0x3c, 0xcc, 0xf0, 0x7e, 0xba, 0xad, 0xeb, 0x58, - 0xe9, 0xb5, 0x78, 0x2f, 0x43, 0x5f, 0x07, 0x47, 0x56, 0x05, 0x41, 0x38, - 0x71, 0xe1, 0x58, 0x62, 0xb1, 0x8e, 0xbc, 0xf9, 0x80, 0x04, 0x22, 0x39, - 0x22, 0x24, 0x28, 0x86, 0x9c, 0x00, 0x44, 0x5f, 0xc4, 0x97, 0xe6, 0x71, - 0x5f, 0x1f, 0x58, 0xea, 0x75, 0x18, 0x0c, 0x23, 0x63, 0x09, 0xc5, 0x98, - 0xc4, 0x6d, 0x23, 0xc2, 0x2c, 0x93, 0x6a, 0x26, 0xe4, 0x3d, 0x8d, 0xa1, - 0x39, 0x70, 0x34, 0x25, 0xcd, 0xbc, 0x82, 0x78, 0x2b, 0xf3, 0x7e, 0x81, - 0xb6, 0x5f, 0xc5, 0x69, 0xd0, 0x81, 0x69, 0x50, 0x2f, 0x17, 0x0c, 0x17, - 0x3c, 0x0b, 0x45, 0x38, 0xce, 0xe3, 0xbf, 0x8a, 0x50, 0x0a, 0x00, 0x74, - 0x7e, 0x7a, 0xd8, 0x55, 0x52, 0x6b, 0x82, 0xfb, 0x34, 0x15, 0x73, 0x6a, - 0xf4, 0x51, 0x9b, 0x9f, 0xa0, 0x45, 0xb9, 0x76, 0xe5, 0xd3, 0xd5, 0xf4, - 0xa9, 0xa4, 0xcd, 0x42, 0x2f, 0x29, 0x89, 0xec, 0x28, 0x5f, 0x03, 0x45, - 0x27, 0xaf, 0x8c, 0x39, 0x3e, 0x59, 0x9d, 0xaf, 0x27, 0x5d, 0x17, 0x53, - 0x17, 0xeb, 0x8d, 0x7f, 0x3d, 0xb8, 0x2a, 0x50, 0x1e, 0xb5, 0xc5, 0x04, - 0xab, 0x9c, 0xa7, 0xaa, 0x86, 0x41, 0xb9, 0x36, 0x29, 0x9e, 0xd2, 0xd8, - 0xde, 0x5f, 0xde, 0x80, 0xdb, 0x02, 0x81, 0xc0, 0x03, 0xf3, 0x5f, 0xa5, - 0xcc, 0x0b, 0x5e, 0xdb, 0xc4, 0xa1, 0xdc, 0x60, 0x73, 0x24, 0x2c, 0x00, - 0x5f, 0x0a, 0xa6, 0x2a, 0x3c, 0x48, 0x59, 0xa2, 0x66, 0x35, 0x3f, 0xf6, - 0x60, 0x0b, 0xfe, 0xc4, 0xde, 0xd9, 0x0b, 0x5a, 0x2e, 0x2a, 0x53, 0xfa, - 0x32, 0xd8, 0xdf, 0xfa, 0x07, 0x9f, 0xb8, 0x6a, 0xd1, 0xec, 0xd3, 0xd5, - 0xf5, 0xfa, 0x00, 0x7e, 0x8c, 0xdd, 0xd5, 0xf2, 0xf8, 0xa8, 0x2e, 0x69, - 0xe6, 0xc6, 0x61, 0x6c, 0x64, 0x7d, 0x9e, 0xad, 0x18, 0x28, 0x27, 0xce, - 0x7a, 0x46, 0xad, 0x98, 0xe4, 0xba, 0x03, 0x14, 0x71, 0xe7, 0x7e, 0x06, - 0x62, 0x48, 0xae, 0x8f, 0x50, 0x5e, 0x59, 0x4a, 0x58, 0x58, 0x1e, 0x2f, - 0xe4, 0x28, 0x5e, 0xfa, 0x17, 0x83, 0xe9, 0x4e, 0x07, 0x46, 0x0b, 0x6c, - 0xfc, 0x5b, 0x03, 0xf4, 0xfc, 0x9b, 0x24, 0x0f, 0xd4, 0x5b, 0xdb, 0xa0, - 0x46, 0xf3, 0x86, 0xdd, 0x26, 0x55, 0x32, 0xb1, 0xa1, 0x11, 0xc2, 0xc5, - 0xc0, 0x08, 0xeb, 0xbe, 0x96, 0x78, 0x25, 0xa1, 0x79, 0xaa, 0xe9, 0xff, - 0xc2, 0x86, 0x94, 0x03, 0x2a, 0x38, 0x6c, 0x91, 0xfd, 0xcf, 0x7e, 0x23, - 0xe3, 0xbb, 0x04, 0x3d, 0xda, 0x68, 0x9f, 0x4d, 0x72, 0xd5, 0xad, 0x97, - 0x77, 0x2c, 0x3c, 0xce, 0x37, 0x2a, 0xd8, 0x72, 0x4d, 0xf2, 0xd7, 0xab, - 0x62, 0x68, 0x3f, 0x85, 0x8a, 0xc5, 0xec, 0xc9, 0x02, 0x81, 0xc1, 0x00, - 0x92, 0x43, 0x0c, 0x1d, 0x20, 0xa1, 0x01, 0x9d, 0xaa, 0x54, 0x5e, 0xf4, - 0x83, 0x58, 0x8f, 0x83, 0xa1, 0x2d, 0x46, 0x75, 0xa1, 0x24, 0x4c, 0x9d, - 0xf8, 0xf3, 0xbd, 0xb1, 0x8c, 0x7d, 0x89, 0xfc, 0x81, 0xeb, 0x1f, 0x1e, - 0xb4, 0xe8, 0x25, 0xb1, 0xb5, 0x4d, 0x59, 0x3c, 0x76, 0x19, 0x29, 0xf9, - 0x49, 0xf8, 0x45, 0xb2, 0xaa, 0xa8, 0x4e, 0xe5, 0x34, 0x43, 0xaf, 0x2e, - 0xd1, 0x0f, 0x7b, 0x56, 0xfe, 0x6e, 0x4c, 0x1d, 0x95, 0x3e, 0xa6, 0x30, - 0xc9, 0x69, 0xd8, 0x66, 0xf8, 0x77, 0x00, 0xb6, 0x31, 0xae, 0x9a, 0xf8, - 0x55, 0xfb, 0xfc, 0x3f, 0x5f, 0x70, 0x03, 0x75, 0xbe, 0x55, 0xca, 0x2d, - 0x68, 0xa0, 0x7d, 0x8e, 0xa4, 0x96, 0x0f, 0x01, 0x66, 0xe9, 0xf6, 0x13, - 0x80, 0xe2, 0x05, 0xcf, 0x9e, 0x70, 0x56, 0x00, 0x97, 0xea, 0xd7, 0x6d, - 0xb6, 0xa0, 0x6a, 0x95, 0x86, 0x36, 0xf2, 0xff, 0xc5, 0x67, 0x98, 0x7d, - 0x04, 0x0d, 0x3b, 0x31, 0xbc, 0x2b, 0x09, 0xfd, 0x2d, 0x87, 0xda, 0xc1, - 0x74, 0xca, 0x94, 0x73, 0x6e, 0xeb, 0x5f, 0xe5, 0x34, 0x49, 0xdf, 0xf4, - 0x61, 0xe0, 0xfa, 0x64, 0xfe, 0x05, 0x3a, 0x25, 0xcc, 0x87, 0xf4, 0x03, - 0x38, 0xca, 0xf2, 0xe8, 0x4f, 0xb9, 0x4f, 0x79, 0x55, 0x43, 0xf3, 0x46, - 0xfd, 0xbc, 0xd2, 0x95, 0xb8, 0x99, 0xfc, 0xb8, 0xb3, 0xa5, 0x04, 0xa1, - 0x02, 0x81, 0xc0, 0x47, 0xc6, 0x9c, 0x18, 0x54, 0xe5, 0xbb, 0xf9, 0xf4, - 0x38, 0xd2, 0xc0, 0xd1, 0x1a, 0xcc, 0xdb, 0x06, 0x87, 0x75, 0x1f, 0x13, - 0xa2, 0x7f, 0x8b, 0x45, 0x54, 0xcb, 0x43, 0xf8, 0xbb, 0x94, 0xd6, 0x2e, - 0x56, 0x5c, 0x69, 0x6d, 0x83, 0xb5, 0x45, 0x46, 0x68, 0x5c, 0x76, 0x1e, - 0x6c, 0x0c, 0x53, 0x59, 0xcc, 0x19, 0xc7, 0x81, 0x62, 0x66, 0x92, 0x02, - 0x8f, 0xa6, 0xdb, 0x50, 0x1c, 0x67, 0xfc, 0x82, 0x56, 0x2b, 0x4b, 0x1f, - 0x97, 0x87, 0xc4, 0x7d, 0x20, 0xda, 0xd3, 0x3f, 0x28, 0xf9, 0x55, 0xfe, - 0x84, 0x50, 0xc5, 0x3b, 0xd4, 0xaf, 0xf5, 0x3d, 0x43, 0xce, 0xdc, 0x55, - 0x11, 0x87, 0xdb, 0x72, 0x66, 0xcc, 0x83, 0xc4, 0x8b, 0x20, 0xae, 0x59, - 0x4d, 0xeb, 0xac, 0xb5, 0x4a, 0xec, 0x66, 0x09, 0x37, 0x55, 0x14, 0x21, - 0x57, 0xff, 0x0a, 0xac, 0xda, 0xb1, 0xae, 0x31, 0xab, 0x41, 0x30, 0x65, - 0x02, 0x83, 0xd1, 0xdb, 0x65, 0xb7, 0x52, 0xa7, 0x21, 0x9f, 0x1f, 0x8f, - 0x69, 0x23, 0x3b, 0xb8, 0xf9, 0x6d, 0xe7, 0xc1, 0x53, 0x9f, 0x8f, 0x67, - 0xfc, 0x6e, 0x20, 0x18, 0x31, 0x89, 0xe7, 0xbb, 0xd4, 0xc1, 0x03, 0x67, - 0xd6, 0xa5, 0x76, 0xc9, 0xea, 0x97, 0x93, 0x02, 0xca, 0x44, 0x52, 0x55, - 0x0f, 0xed, 0x55, 0xb5, 0x49, 0xd6, 0x94, 0x59, 0xee, 0xcc, 0x1b, 0x5a, - 0x00, 0x3d, 0xcd}; - -static const unsigned char kTestRsaPublicKey1_3072[] = { - 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5, 0x62, 0x07, - 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78, 0x76, 0xbe, - 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f, 0xe9, 0x61, - 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca, 0xe4, 0xdd, - 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b, 0x83, 0xbe, - 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46, 0xc2, 0x65, - 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01, 0xb5, 0x11, - 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c, 0xb4, 0x7a, - 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14, 0xf1, 0x22, - 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd, 0xa0, 0x0a, - 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6, 0x0e, 0x85, - 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde, 0xf2, 0x59, - 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31, 0xa0, 0xee, - 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a, 0xae, 0xb2, - 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90, 0x97, 0x2c, - 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49, 0x94, 0x53, - 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f, 0x07, 0x53, - 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda, 0xea, 0x1e, - 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17, 0xe8, 0xc9, - 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30, 0xb7, 0xf5, - 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf, 0x39, 0xf3, - 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16, 0x9c, 0xee, - 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42, 0x72, 0x85, - 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9, 0xa6, 0x82, - 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4, 0x3a, 0x3b, - 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a, 0xe9, 0x4c, - 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72, 0x71, 0x04, - 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde, 0x8f, 0xe1, - 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04, 0xb5, 0xd7, - 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b, 0x38, 0xff, - 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33, 0x61, 0x53, - 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67, 0xd5, 0xf0, - 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02, 0x03, 0x01, - 0x00, 0x01}; - -static const unsigned char kTestRsaPrivateKey2_2048[] = { - 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4, - 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, - 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e, - 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, - 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7, - 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, - 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68, - 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, - 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2, - 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, - 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e, - 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, - 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88, - 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, - 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8, - 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, - 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e, - 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, - 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29, - 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, - 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f, - 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, - 0x00, 0x5e, 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05, 0x45, 0x0f, - 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, 0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, - 0xac, 0x97, 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7, 0x3b, 0x5c, - 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, 0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, - 0x7e, 0xdc, 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c, 0x5e, 0x79, - 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, 0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, - 0x79, 0xf9, 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3, 0x68, 0x7b, - 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, 0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, - 0x71, 0xe7, 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75, 0xbe, 0x09, - 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, 0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, - 0xe8, 0x88, 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78, 0x25, 0x0b, - 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, 0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, - 0x37, 0x14, 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47, 0xde, 0x00, - 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, 0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, - 0x87, 0x27, 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d, 0x6f, 0x35, - 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, 0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, - 0xb6, 0x64, 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53, 0x1f, 0x51, - 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, 0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, - 0x07, 0x5f, 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29, 0xf6, 0x06, - 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, 0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, - 0xc9, 0x21, 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81, 0xb2, 0x51, - 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, - 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, 0x78, 0xcc, - 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, - 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, 0x84, 0x68, - 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, - 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, 0x3a, 0x83, - 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, - 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, 0x18, 0x6c, - 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, - 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, 0x3c, 0x2d, - 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, 0x48, 0x16, - 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, 0x15, 0x43, - 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, - 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, 0xcb, 0x43, - 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, - 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, 0xa7, 0x5b, - 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, - 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, 0xc1, 0xee, - 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, - 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, 0x0d, 0x6c, - 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, - 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, 0x53, 0xa8, - 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, - 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, 0x0a, 0x2d, - 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, - 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, 0xeb, 0xdb, - 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, - 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, 0x37, 0x43, - 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, - 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, 0xf9, 0xca, - 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, - 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, 0xb1, 0x31, - 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, 0x40, 0x19, - 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, 0xcc, 0x3b, - 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, - 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, 0x6a, 0xab, - 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, - 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, 0x5f, 0xdf, - 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, - 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, 0x77, 0xe6, - 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, - 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, 0xd9, 0xbe, - 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, - 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, 0xac, 0x21, - 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, - 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, 0x28, 0x66, - 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, - 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, 0x70, 0xcf, - 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, - 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, 0x50, 0xcb, - 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, - 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, 0xa2, 0x0d, - 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, - 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, 0x72, 0x2c, - 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, - 0xdb, 0x03}; - -static const unsigned char kTestRsaPublicKey2_2048[] = { - 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, - 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, - 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, - 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, - 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, - 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, - 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, - 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, - 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, - 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, - 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, - 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, - 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, - 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, - 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, - 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, - 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, - 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, - 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, - 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, - 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, - 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, - 0x05, 0x02, 0x03, 0x01, 0x00, 0x01}; - -static const unsigned char kTestRsaPrivateKey3_2048[] = { - 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40, - 0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7, - 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44, - 0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91, - 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08, - 0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10, - 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d, - 0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94, - 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d, - 0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68, - 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55, - 0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8, - 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7, - 0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35, - 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06, - 0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21, - 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae, - 0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c, - 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84, - 0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87, - 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b, - 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, - 0x00, 0x43, 0x8f, 0x19, 0x83, 0xb1, 0x27, 0x4e, 0xee, 0x98, 0xba, 0xcb, - 0x54, 0xa0, 0x77, 0x11, 0x6d, 0xd4, 0x25, 0x31, 0x8c, 0xb0, 0x01, 0xcf, - 0xe6, 0x80, 0x83, 0x14, 0x40, 0x67, 0x39, 0x33, 0x67, 0x03, 0x1e, 0xa0, - 0x8b, 0xd1, 0x1d, 0xfd, 0x80, 0xa4, 0xb9, 0xe7, 0x57, 0x5e, 0xc8, 0x8e, - 0x79, 0x71, 0xd5, 0x6b, 0x09, 0xe9, 0x2b, 0x41, 0xa0, 0x33, 0x64, 0xc9, - 0x66, 0x33, 0xa1, 0xb1, 0x55, 0x07, 0x55, 0x98, 0x53, 0x10, 0xe6, 0xc0, - 0x39, 0x6d, 0x61, 0xd9, 0xe8, 0x16, 0x52, 0x28, 0xe4, 0x2b, 0xda, 0x27, - 0x01, 0xaf, 0x21, 0x4a, 0xe8, 0x55, 0x1d, 0x0b, 0xd1, 0x1c, 0xdc, 0xfd, - 0xb3, 0x0b, 0xa6, 0x5c, 0xcc, 0x6e, 0x77, 0xb8, 0xe0, 0xd1, 0x4e, 0x0a, - 0xd7, 0x7a, 0x5e, 0x18, 0xc3, 0xfb, 0xe9, 0xa1, 0x9c, 0xc3, 0x9c, 0xd4, - 0x4a, 0x7e, 0x70, 0x72, 0x11, 0x18, 0x24, 0x56, 0x24, 0xdf, 0xf8, 0xba, - 0xac, 0x5b, 0x54, 0xd3, 0xc4, 0x65, 0x69, 0xc8, 0x79, 0x94, 0x16, 0x88, - 0x9a, 0x68, 0x1c, 0xbc, 0xd4, 0xca, 0xec, 0x5e, 0x07, 0x4a, 0xc9, 0x54, - 0x7a, 0x4b, 0xdb, 0x19, 0x88, 0xf6, 0xbe, 0x50, 0x9d, 0x9e, 0x9d, 0x88, - 0x5b, 0x4a, 0x23, 0x86, 0x2b, 0xa9, 0xa6, 0x6c, 0x70, 0x7d, 0xe1, 0x11, - 0xba, 0xbf, 0x03, 0x2e, 0xf1, 0x46, 0x7e, 0x1b, 0xed, 0x06, 0x11, 0x57, - 0xad, 0x4a, 0xcb, 0xe5, 0xb1, 0x11, 0x05, 0x0a, 0x30, 0xb1, 0x73, 0x79, - 0xcd, 0x7a, 0x04, 0xcc, 0x70, 0xe9, 0x95, 0xe4, 0x27, 0xc2, 0xd5, 0x2d, - 0x92, 0x44, 0xdf, 0xb4, 0x94, 0xa8, 0x73, 0xa1, 0x4a, 0xc3, 0xcc, 0xc4, - 0x0e, 0x8d, 0xa1, 0x6a, 0xc2, 0xd8, 0x03, 0x7f, 0xfa, 0xa7, 0x76, 0x0d, - 0xad, 0x87, 0x88, 0xa0, 0x77, 0xaf, 0x3b, 0x23, 0xd1, 0x66, 0x0b, 0x31, - 0x2b, 0xaf, 0xef, 0xd5, 0x41, 0x02, 0x81, 0x81, 0x00, 0xdb, 0xc1, 0xe7, - 0xdd, 0xba, 0x3c, 0x1f, 0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47, - 0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2, 0x25, 0x64, 0x0a, 0x02, - 0xbc, 0x7d, 0x7f, 0x50, 0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d, - 0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9, 0x53, 0x0b, 0x5c, 0xa2, - 0x71, 0x14, 0x02, 0xfd, 0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e, - 0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8, 0x3d, 0xcf, 0x8c, 0x89, - 0x65, 0x6c, 0x35, 0x19, 0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d, - 0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43, 0xe5, 0xdd, 0x39, 0x3a, - 0x78, 0x8f, 0x07, 0xb8, 0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02, - 0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01, 0x90, 0x81, 0x29, 0x94, - 0xad, 0x77, 0xeb, 0x86, 0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88, - 0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32, 0x12, 0x5e, 0xdf, 0x28, - 0x0c, 0x96, 0x0d, 0xa8, 0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb, - 0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2, 0xf3, 0xf2, 0x95, 0xff, - 0xd8, 0x33, 0x3f, 0x8c, 0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66, - 0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1, 0xbc, 0xbe, 0x44, 0x09, - 0xb4, 0xfe, 0x95, 0x06, 0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0, - 0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8, 0xcc, 0xeb, 0x10, 0x4d, - 0xa7, 0xd0, 0x4b, 0x46, 0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3, - 0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b, 0x7b, 0xae, 0x6d, 0x08, - 0x9f, 0x0c, 0x2a, 0xe1, 0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d, - 0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80, 0x61, 0x73, 0x3d, 0x64, - 0xff, 0xdf, 0x05, 0x8d, 0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53, - 0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f, 0xae, 0x2b, 0x1a, 0x47, - 0x87, 0xc7, 0x5b, 0x78, 0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c, - 0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d, 0x40, 0xfe, 0x95, 0x32, - 0x5b, 0xd3, 0x6f, 0x90, 0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7, - 0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78, 0xad, 0x7e, 0xfe, 0xb6, - 0xb1, 0x23, 0x63, 0x01, 0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1, - 0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec, 0xcb, 0x0b, 0x43, 0xb8, - 0x8e, 0x84, 0xb8, 0x09, 0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95, - 0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f, 0x91, 0x17, 0x65, 0x4c, - 0xff, 0x6e, 0xbc, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8, - 0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7, 0xce, 0x72, 0x02, 0x38, - 0xf2, 0x0f, 0x9c, 0x27, 0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19, - 0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e, 0xe6, 0xb8, 0xfc, 0x07, - 0x3c, 0xd1, 0x1b, 0x16, 0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd, - 0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd, 0xf9, 0xdb, 0x4e, 0x48, - 0x52, 0xd8, 0xe6, 0x4b, 0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3, - 0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71, 0xd3, 0xcd, 0x6b, 0x8f, - 0x79, 0x22, 0x83, 0x02, 0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8, - 0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e, 0xa4, 0x89, 0xdc, 0xbf, - 0xf9, 0x0d, 0x32, 0xc8, 0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e, - 0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x35, 0x1b, 0x19, - 0x75, 0x3f, 0x61, 0xf2, 0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a, - 0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d, 0x1f, 0x86, 0x58, 0x4f, - 0xd8, 0xee, 0xfa, 0x76, 0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62, - 0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83, 0x07, 0xac, 0x8c, 0xa3, - 0x7e, 0x18, 0xc0, 0x1c, 0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3, - 0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43, 0x04, 0x36, 0xc8, 0x19, - 0xbe, 0xdc, 0xa6, 0xe5, 0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3, - 0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31, 0x44, 0x74, 0xfa, 0x7c, - 0xb4, 0xea, 0xfc, 0x15, 0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b, - 0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b, 0x21, 0xdc, 0x86, 0x17, - 0x6e, 0xc8, 0xee, 0x24}; - -static const unsigned char kTestRsaPublicKey3_2048[] = { - 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7, - 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89, - 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41, - 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44, 0xb3, 0x08, 0x05, - 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8, - 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10, - 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1, - 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b, - 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94, 0x40, 0x70, 0xac, - 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95, - 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68, 0x16, 0x31, 0xaa, - 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4, - 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf, - 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b, - 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66, - 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06, 0xd9, 0x84, 0x51, - 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd, - 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee, - 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89, - 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a, - 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1, - 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69, - 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01}; - -unsigned char kTestRsaPrivateKey2CarmichaelTotient_2048[] = { - 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4, - 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, - 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e, - 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, - 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7, - 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, - 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68, - 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, - 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2, - 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, - 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e, - 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, - 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88, - 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, - 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8, - 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, - 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e, - 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, - 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29, - 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, - 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f, - 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, - 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8, 0x2f, 0xef, - 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4, 0xe9, 0x65, - 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33, 0x8c, 0x30, - 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde, 0xb1, 0x13, - 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc, 0x6c, 0xdf, - 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4, 0x67, 0x75, - 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b, 0x6a, 0xdc, - 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40, 0xb2, 0xb4, - 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a, 0xeb, 0x90, - 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f, 0xa9, 0x47, - 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f, 0xfc, 0x19, - 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff, 0x45, 0xa2, - 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c, 0x37, 0x99, - 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8, 0xfa, 0x2d, - 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71, 0xbd, 0xff, - 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85, 0xfd, 0xd0, - 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a, 0x3f, 0xbf, - 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e, 0x51, 0x9f, - 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5, 0x97, 0x5f, - 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c, 0x94, 0x4b, - 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf, 0xa2, 0x9a, - 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, - 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, 0x78, 0xcc, - 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, - 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, 0x84, 0x68, - 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, - 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, 0x3a, 0x83, - 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, - 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, 0x18, 0x6c, - 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, - 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, 0x3c, 0x2d, - 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, 0x48, 0x16, - 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, 0x15, 0x43, - 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, - 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, 0xcb, 0x43, - 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, - 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, 0xa7, 0x5b, - 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, - 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, 0xc1, 0xee, - 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, - 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, 0x0d, 0x6c, - 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, - 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, 0x53, 0xa8, - 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, - 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, 0x0a, 0x2d, - 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, - 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, 0xeb, 0xdb, - 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, - 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, 0x37, 0x43, - 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, - 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, 0xf9, 0xca, - 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, - 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, 0xb1, 0x31, - 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, 0x40, 0x19, - 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, 0xcc, 0x3b, - 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, - 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, 0x6a, 0xab, - 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, - 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, 0x5f, 0xdf, - 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, - 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, 0x77, 0xe6, - 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, - 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, 0xd9, 0xbe, - 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, - 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, 0xac, 0x21, - 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, - 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, 0x28, 0x66, - 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, - 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, 0x70, 0xcf, - 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, - 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, 0x50, 0xcb, - 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, - 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, 0xa2, 0x0d, - 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, - 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, 0x72, 0x2c, - 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, - 0xdb, 0x03}; - -static const unsigned char kTestRsaPrivateKey3CarmichaelTotient_2048[] = { - 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40, - 0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7, - 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44, - 0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91, - 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08, - 0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10, - 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d, - 0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94, - 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d, - 0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68, - 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55, - 0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8, - 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7, - 0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35, - 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06, - 0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21, - 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae, - 0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c, - 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84, - 0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87, - 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b, - 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, - 0x00, 0x1a, 0x1a, 0xe3, 0xb4, 0x2d, 0x9b, 0xd0, 0x1d, 0xc4, 0x54, 0x50, - 0xc4, 0x98, 0xeb, 0xae, 0xf4, 0xab, 0x95, 0x72, 0x78, 0x60, 0xbe, 0x2e, - 0xfc, 0x88, 0x59, 0xc3, 0xff, 0x5f, 0xb4, 0x01, 0xfd, 0x2c, 0x06, 0x52, - 0xfa, 0xa4, 0x5b, 0xfc, 0x29, 0xdf, 0x82, 0x67, 0x14, 0x52, 0x39, 0x67, - 0xd5, 0x31, 0xc1, 0x41, 0x02, 0x76, 0x03, 0x5d, 0xd2, 0xc5, 0x74, 0x2c, - 0x24, 0x26, 0xfe, 0xed, 0x46, 0x65, 0x97, 0x22, 0x74, 0xe7, 0xff, 0x63, - 0x35, 0x3b, 0xd8, 0xad, 0x88, 0x2c, 0xe2, 0x50, 0xf3, 0x76, 0x14, 0xbe, - 0x3a, 0x37, 0x1b, 0xf0, 0x21, 0x91, 0x8e, 0xdd, 0x43, 0xed, 0xb7, 0xab, - 0xcd, 0xfb, 0x8a, 0x31, 0xa6, 0x26, 0xb4, 0xd5, 0x4b, 0x2c, 0x80, 0x7f, - 0xfc, 0x39, 0x24, 0x33, 0x7d, 0x6d, 0xf3, 0x1c, 0x06, 0xdd, 0x21, 0x53, - 0x70, 0x78, 0xe4, 0x07, 0x60, 0x2a, 0x3f, 0xb8, 0xd0, 0x47, 0xf6, 0x0e, - 0xbd, 0xde, 0x31, 0xf3, 0x66, 0xfe, 0x6e, 0x4b, 0x50, 0x75, 0x0b, 0x49, - 0x3a, 0x96, 0xeb, 0x63, 0xb9, 0x24, 0xbb, 0xfc, 0xcd, 0xf5, 0x49, 0x12, - 0xa9, 0x6d, 0x39, 0xd4, 0x18, 0x15, 0x14, 0x50, 0x82, 0xa9, 0x75, 0xeb, - 0x9f, 0x1a, 0xaa, 0x52, 0x1d, 0x0d, 0x55, 0x74, 0x30, 0x45, 0x3b, 0xd2, - 0xd3, 0xe1, 0xdb, 0x8d, 0xec, 0x38, 0x2b, 0xb0, 0xdd, 0xda, 0x10, 0xe3, - 0x40, 0x87, 0x27, 0xbe, 0x0b, 0xbf, 0x08, 0x9e, 0x25, 0x95, 0x14, 0xf4, - 0xd7, 0xfe, 0x8c, 0x4f, 0x23, 0xfd, 0x1b, 0xad, 0x83, 0x6b, 0x05, 0x3a, - 0x83, 0xfa, 0x65, 0x1e, 0x65, 0x12, 0xe3, 0x9f, 0xea, 0x52, 0xd7, 0xed, - 0x01, 0x7d, 0xc5, 0xf1, 0x96, 0x2d, 0xf5, 0x4a, 0xa3, 0xcb, 0x69, 0x6c, - 0x9a, 0x48, 0xe9, 0xf5, 0x01, 0xef, 0x1d, 0x2e, 0x90, 0x64, 0x6c, 0x0b, - 0x79, 0xe0, 0xeb, 0x64, 0x29, 0x02, 0x81, 0x81, 0x00, 0xdb, 0xc1, 0xe7, - 0xdd, 0xba, 0x3c, 0x1f, 0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47, - 0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2, 0x25, 0x64, 0x0a, 0x02, - 0xbc, 0x7d, 0x7f, 0x50, 0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d, - 0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9, 0x53, 0x0b, 0x5c, 0xa2, - 0x71, 0x14, 0x02, 0xfd, 0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e, - 0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8, 0x3d, 0xcf, 0x8c, 0x89, - 0x65, 0x6c, 0x35, 0x19, 0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d, - 0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43, 0xe5, 0xdd, 0x39, 0x3a, - 0x78, 0x8f, 0x07, 0xb8, 0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02, - 0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01, 0x90, 0x81, 0x29, 0x94, - 0xad, 0x77, 0xeb, 0x86, 0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88, - 0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32, 0x12, 0x5e, 0xdf, 0x28, - 0x0c, 0x96, 0x0d, 0xa8, 0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb, - 0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2, 0xf3, 0xf2, 0x95, 0xff, - 0xd8, 0x33, 0x3f, 0x8c, 0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66, - 0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1, 0xbc, 0xbe, 0x44, 0x09, - 0xb4, 0xfe, 0x95, 0x06, 0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0, - 0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8, 0xcc, 0xeb, 0x10, 0x4d, - 0xa7, 0xd0, 0x4b, 0x46, 0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3, - 0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b, 0x7b, 0xae, 0x6d, 0x08, - 0x9f, 0x0c, 0x2a, 0xe1, 0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d, - 0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80, 0x61, 0x73, 0x3d, 0x64, - 0xff, 0xdf, 0x05, 0x8d, 0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53, - 0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f, 0xae, 0x2b, 0x1a, 0x47, - 0x87, 0xc7, 0x5b, 0x78, 0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c, - 0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d, 0x40, 0xfe, 0x95, 0x32, - 0x5b, 0xd3, 0x6f, 0x90, 0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7, - 0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78, 0xad, 0x7e, 0xfe, 0xb6, - 0xb1, 0x23, 0x63, 0x01, 0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1, - 0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec, 0xcb, 0x0b, 0x43, 0xb8, - 0x8e, 0x84, 0xb8, 0x09, 0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95, - 0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f, 0x91, 0x17, 0x65, 0x4c, - 0xff, 0x6e, 0xbc, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8, - 0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7, 0xce, 0x72, 0x02, 0x38, - 0xf2, 0x0f, 0x9c, 0x27, 0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19, - 0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e, 0xe6, 0xb8, 0xfc, 0x07, - 0x3c, 0xd1, 0x1b, 0x16, 0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd, - 0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd, 0xf9, 0xdb, 0x4e, 0x48, - 0x52, 0xd8, 0xe6, 0x4b, 0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3, - 0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71, 0xd3, 0xcd, 0x6b, 0x8f, - 0x79, 0x22, 0x83, 0x02, 0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8, - 0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e, 0xa4, 0x89, 0xdc, 0xbf, - 0xf9, 0x0d, 0x32, 0xc8, 0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e, - 0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x35, 0x1b, 0x19, - 0x75, 0x3f, 0x61, 0xf2, 0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a, - 0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d, 0x1f, 0x86, 0x58, 0x4f, - 0xd8, 0xee, 0xfa, 0x76, 0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62, - 0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83, 0x07, 0xac, 0x8c, 0xa3, - 0x7e, 0x18, 0xc0, 0x1c, 0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3, - 0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43, 0x04, 0x36, 0xc8, 0x19, - 0xbe, 0xdc, 0xa6, 0xe5, 0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3, - 0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31, 0x44, 0x74, 0xfa, 0x7c, - 0xb4, 0xea, 0xfc, 0x15, 0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b, - 0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b, 0x21, 0xdc, 0x86, 0x17, - 0x6e, 0xc8, 0xee, 0x24}; - -static const unsigned char kTestRsaPrivateKey4CarmichaelTotient_2048[] = { - 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xb5, 0xed, 0x90, 0x77, 0xfe, 0xb4, 0xac, 0x2c, 0x7a, 0x53, 0x0a, 0xe0, - 0x94, 0x87, 0xfe, 0xc7, 0xc4, 0xa8, 0x3f, 0x09, 0x5b, 0xdd, 0xa7, 0x6e, - 0x70, 0xc9, 0xf0, 0xef, 0x9e, 0x47, 0xad, 0xcf, 0xbe, 0xdc, 0x9b, 0x89, - 0xc7, 0xbd, 0xb5, 0x2f, 0xa9, 0x43, 0x97, 0xd5, 0x5b, 0xae, 0x73, 0x46, - 0xa9, 0x10, 0x47, 0x67, 0x35, 0xa0, 0x6e, 0xfc, 0xfb, 0x45, 0xf8, 0x85, - 0xb0, 0xf1, 0xd3, 0x67, 0x84, 0x91, 0x03, 0x1b, 0x90, 0xb1, 0x18, 0x12, - 0xa4, 0x15, 0x7a, 0x65, 0xfa, 0x74, 0x4f, 0x73, 0x34, 0x70, 0x9b, 0x64, - 0x91, 0x1f, 0x89, 0x4f, 0x40, 0x2d, 0x37, 0x2f, 0xbf, 0x2b, 0x1e, 0x54, - 0x95, 0x7c, 0x16, 0x14, 0xd3, 0x60, 0xf4, 0xd7, 0x86, 0xf7, 0x0c, 0x2c, - 0xbb, 0x3f, 0xe7, 0x49, 0xdf, 0x74, 0x8b, 0xc9, 0x8f, 0x7c, 0x22, 0x23, - 0xd9, 0xbd, 0x2a, 0x57, 0xfe, 0xfb, 0x7a, 0x77, 0x91, 0xce, 0xa9, 0xd8, - 0xa7, 0xfb, 0xf5, 0xe7, 0x39, 0xbe, 0xfb, 0xf5, 0x47, 0x57, 0x48, 0xe7, - 0x71, 0x37, 0xda, 0x53, 0xe7, 0x89, 0xd3, 0x37, 0x31, 0x98, 0xba, 0xd8, - 0xd0, 0xd9, 0x74, 0xb2, 0xda, 0x06, 0x99, 0x3b, 0x97, 0x87, 0xc4, 0x22, - 0x3c, 0xf7, 0xa3, 0x13, 0x84, 0x49, 0x27, 0x74, 0x50, 0x03, 0x51, 0xea, - 0xc9, 0x57, 0xeb, 0x16, 0xa9, 0x7a, 0xea, 0x3c, 0x26, 0xda, 0xcb, 0xc6, - 0x86, 0x85, 0xfc, 0xd0, 0x73, 0x26, 0xce, 0xe8, 0xd9, 0x92, 0x09, 0xaf, - 0x68, 0x0c, 0x01, 0x8d, 0x95, 0xfd, 0x8d, 0x01, 0xde, 0x26, 0x0f, 0x25, - 0xb9, 0xd5, 0x80, 0x99, 0x62, 0xb1, 0x71, 0xcd, 0xa1, 0x5f, 0x52, 0xab, - 0x97, 0x97, 0x3f, 0xa7, 0x93, 0x40, 0x89, 0x4f, 0xbc, 0x7d, 0x99, 0x7a, - 0x7e, 0x35, 0xa5, 0xfc, 0x74, 0xfb, 0xe4, 0x5a, 0x0b, 0xed, 0xf0, 0xef, - 0x65, 0xed, 0x22, 0x95, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, - 0x00, 0x35, 0x4a, 0x9d, 0x36, 0xa1, 0x3c, 0x50, 0x71, 0x08, 0xf6, 0x19, - 0x6a, 0x16, 0xe8, 0x4d, 0x68, 0x3c, 0x41, 0xa2, 0x91, 0x7d, 0xc1, 0x0c, - 0xa2, 0x2b, 0xd4, 0xe3, 0xc8, 0x75, 0x3f, 0x7e, 0xf9, 0x2b, 0x6a, 0x18, - 0xff, 0xbf, 0xac, 0x61, 0x0e, 0x50, 0x91, 0x55, 0xc1, 0x30, 0x85, 0x86, - 0x0c, 0x0d, 0x4b, 0x10, 0xf7, 0x79, 0x3c, 0x81, 0x36, 0x86, 0xee, 0x84, - 0xb1, 0xb8, 0xd6, 0xe5, 0xbb, 0xdd, 0x97, 0xd2, 0xe6, 0xb8, 0xb8, 0x3f, - 0x9a, 0x7a, 0x49, 0x36, 0x5c, 0xf8, 0x04, 0x29, 0x1f, 0xd0, 0x9d, 0x29, - 0xcf, 0xc8, 0x39, 0x0a, 0x32, 0x56, 0x54, 0xc8, 0x65, 0x2a, 0xa5, 0x19, - 0x51, 0xe2, 0xa6, 0x02, 0x1b, 0xe0, 0x9d, 0x76, 0xab, 0x49, 0xc4, 0x45, - 0x63, 0x37, 0x08, 0xad, 0x9a, 0x34, 0xa4, 0x41, 0xac, 0x6d, 0xe5, 0x09, - 0x65, 0x22, 0x0b, 0xa9, 0x03, 0x34, 0xd4, 0x7a, 0x97, 0x5c, 0x5d, 0xdc, - 0xa3, 0xae, 0xfd, 0xe8, 0xd6, 0xe8, 0xf8, 0x52, 0x44, 0x9c, 0xf6, 0x00, - 0xe3, 0x8e, 0xad, 0xee, 0xa3, 0x82, 0x8a, 0x85, 0x07, 0x8b, 0x46, 0x12, - 0x0f, 0xa1, 0xca, 0x07, 0x0d, 0x50, 0x02, 0x96, 0x71, 0x2f, 0x1b, 0x2b, - 0x59, 0x17, 0x95, 0xec, 0x90, 0xa6, 0xb9, 0x05, 0xff, 0xa2, 0x25, 0x75, - 0xc5, 0x57, 0x42, 0x37, 0x12, 0xa0, 0xb6, 0x09, 0xa1, 0xe0, 0xef, 0x70, - 0x85, 0xa7, 0x39, 0x47, 0xb1, 0x72, 0x78, 0x0d, 0xf4, 0x4a, 0xa7, 0xca, - 0x92, 0x68, 0x2c, 0xe8, 0x53, 0x54, 0x52, 0xe2, 0x21, 0xce, 0xaf, 0x7e, - 0x56, 0x05, 0x74, 0xe1, 0xb7, 0x18, 0xed, 0x7f, 0x83, 0xf6, 0x7d, 0x99, - 0x33, 0xf9, 0x60, 0x24, 0xae, 0x59, 0x09, 0xc0, 0x95, 0x90, 0x5a, 0x19, - 0x25, 0xb0, 0x79, 0xfd, 0x0b, 0x2c, 0x73, 0x85, 0xc5, 0xa0, 0xe5, 0x7b, - 0x3a, 0x47, 0xce, 0x8d, 0x03, 0x02, 0x81, 0x81, 0x00, 0xe2, 0xd7, 0xeb, - 0x7f, 0xc1, 0x1f, 0x13, 0x8f, 0x52, 0x49, 0xa2, 0x83, 0x22, 0xb7, 0x3d, - 0x93, 0xfe, 0xe7, 0x20, 0x03, 0xf6, 0x6c, 0xd8, 0x95, 0x25, 0xef, 0x5f, - 0xa4, 0xd4, 0x8f, 0xb1, 0x38, 0x39, 0x7c, 0xe0, 0xdd, 0xff, 0x56, 0xa7, - 0xdf, 0x59, 0xe1, 0x26, 0x36, 0x72, 0x78, 0xdf, 0xd4, 0x19, 0xc0, 0x37, - 0x58, 0x75, 0x85, 0xdd, 0x8b, 0x2e, 0x73, 0xfa, 0xf5, 0x65, 0x93, 0xc7, - 0x36, 0x3d, 0xb7, 0x8e, 0xa9, 0x5e, 0x41, 0x71, 0x55, 0x1d, 0x22, 0x83, - 0x13, 0x91, 0x76, 0xa4, 0x80, 0xa0, 0xac, 0xf6, 0xd5, 0xbb, 0x6a, 0xf3, - 0x47, 0x01, 0x81, 0x3d, 0x34, 0xd6, 0x32, 0x49, 0xb2, 0xc9, 0xa7, 0xb3, - 0x93, 0x64, 0x47, 0x6d, 0x30, 0x8b, 0x23, 0xbd, 0xf0, 0xe8, 0x3c, 0xb5, - 0x4e, 0x33, 0x74, 0x4b, 0x60, 0x38, 0x25, 0x89, 0xaf, 0xf8, 0x86, 0x53, - 0x73, 0x62, 0x74, 0x35, 0xb7, 0x02, 0x81, 0x81, 0x00, 0xcd, 0x4f, 0xbd, - 0xe1, 0x43, 0xb4, 0xfe, 0x9a, 0x50, 0xb8, 0xeb, 0xf3, 0xd6, 0x3f, 0x2a, - 0xbe, 0x19, 0x7a, 0x2c, 0xf4, 0x63, 0x35, 0x29, 0x47, 0x39, 0x17, 0xb4, - 0xc7, 0x58, 0xc0, 0x5a, 0xbf, 0x5c, 0xa4, 0xcf, 0x9e, 0x4b, 0xad, 0x5a, - 0x95, 0xfd, 0xfa, 0x50, 0xbe, 0x54, 0x12, 0xbe, 0xd8, 0x8e, 0xaf, 0x8b, - 0xb2, 0x15, 0xa1, 0xb5, 0x78, 0x03, 0xa6, 0x3b, 0x18, 0x13, 0x1d, 0xfe, - 0x38, 0xb7, 0x65, 0x1e, 0x20, 0x39, 0xa9, 0x25, 0x37, 0xed, 0xe8, 0x5b, - 0xc7, 0xd0, 0x60, 0xe2, 0x1f, 0xf2, 0x06, 0x5d, 0x3c, 0x5c, 0x36, 0xe0, - 0xc6, 0x83, 0x52, 0xd3, 0xd3, 0x3f, 0x7c, 0x43, 0x82, 0x4a, 0x13, 0xf8, - 0x8d, 0x48, 0x03, 0x4f, 0xb8, 0xad, 0x64, 0x85, 0xa9, 0xee, 0xde, 0x3d, - 0x0c, 0x23, 0xb6, 0xe9, 0x8d, 0xad, 0x02, 0x62, 0x32, 0x58, 0x39, 0xbf, - 0x5f, 0x3c, 0x6c, 0x0a, 0x13, 0x02, 0x81, 0x80, 0x7f, 0x87, 0x3c, 0x12, - 0x3a, 0x94, 0x29, 0xfe, 0xed, 0x18, 0x10, 0x91, 0x00, 0xb7, 0x5b, 0x9b, - 0x14, 0x37, 0x03, 0xbc, 0xb6, 0x91, 0x42, 0xc1, 0xb6, 0xed, 0xf8, 0x2b, - 0x46, 0x84, 0xf1, 0xf0, 0xd6, 0x00, 0xea, 0xba, 0x63, 0x8e, 0x68, 0x1a, - 0x1d, 0x01, 0x82, 0xe6, 0x21, 0x3c, 0xeb, 0x38, 0xe6, 0xb1, 0x35, 0x6c, - 0x39, 0xc5, 0xe4, 0x63, 0x16, 0xde, 0x85, 0x3b, 0xe8, 0xbb, 0x47, 0xc7, - 0xaa, 0xb2, 0xc3, 0x35, 0x5c, 0x94, 0x16, 0x0e, 0xef, 0xae, 0x33, 0x5a, - 0x90, 0xf0, 0xce, 0x52, 0xb2, 0x02, 0x0b, 0x52, 0xe5, 0x66, 0x9f, 0x16, - 0x50, 0x36, 0x44, 0x1e, 0xac, 0x3c, 0xe1, 0x49, 0xee, 0x2c, 0xa5, 0xbc, - 0x3b, 0x28, 0x1c, 0xae, 0xa9, 0xca, 0x92, 0x42, 0x19, 0x8d, 0xe7, 0xaf, - 0xeb, 0x25, 0x7a, 0x2a, 0xc1, 0xe5, 0xf8, 0x9e, 0x41, 0x6d, 0xe3, 0x04, - 0x7f, 0x59, 0x2d, 0xc9, 0x02, 0x81, 0x81, 0x00, 0xbe, 0xc3, 0x51, 0xdd, - 0x25, 0x48, 0xdd, 0xab, 0xca, 0x47, 0x17, 0xcd, 0x57, 0x0b, 0x18, 0x0e, - 0xcb, 0xa3, 0x4e, 0x73, 0xc0, 0x5e, 0x1b, 0xbd, 0x76, 0x99, 0xc5, 0x39, - 0xd8, 0x07, 0xda, 0x09, 0xa5, 0xed, 0xe8, 0x8e, 0xdf, 0x27, 0xf2, 0x5c, - 0x1d, 0x40, 0xe0, 0x97, 0x07, 0x8c, 0xe7, 0x50, 0x55, 0xbb, 0x5c, 0x24, - 0x1a, 0x9f, 0x46, 0xfa, 0x7d, 0x01, 0x8e, 0x34, 0xbf, 0x46, 0x85, 0xf8, - 0x72, 0xc6, 0x7c, 0x68, 0x5a, 0xcb, 0x03, 0xae, 0xe4, 0xd9, 0x99, 0xb5, - 0x9d, 0xb2, 0xf7, 0x47, 0xd1, 0x5c, 0x02, 0x73, 0x5c, 0x07, 0x0d, 0x70, - 0xc5, 0x82, 0x47, 0x19, 0x28, 0x0a, 0xb0, 0xbb, 0x35, 0x53, 0x3b, 0x05, - 0x22, 0x9d, 0x19, 0x0c, 0xb1, 0xe7, 0x0d, 0x9e, 0xa8, 0x38, 0x4c, 0x26, - 0xa4, 0x64, 0x86, 0xbb, 0x41, 0xbe, 0x4e, 0x39, 0x12, 0xea, 0x8d, 0x1a, - 0xd3, 0x0c, 0x5b, 0x8b, 0x02, 0x81, 0x81, 0x00, 0xa9, 0x2d, 0x4b, 0x43, - 0x55, 0x7f, 0x90, 0xb4, 0xea, 0xf9, 0xc2, 0x4c, 0x8c, 0x4d, 0xee, 0x62, - 0x85, 0xd2, 0x58, 0x71, 0xc7, 0xb3, 0xfb, 0x80, 0x37, 0xd9, 0xc5, 0x20, - 0x61, 0xeb, 0x39, 0x7f, 0x4d, 0x09, 0x7c, 0x32, 0x46, 0x8b, 0x49, 0xa4, - 0xd6, 0x99, 0xb4, 0xdc, 0xb6, 0xe3, 0x2a, 0x77, 0x53, 0xa3, 0xee, 0xdb, - 0x4d, 0xf9, 0x59, 0x20, 0x8a, 0x83, 0x94, 0x29, 0x72, 0x96, 0x76, 0x36, - 0x63, 0xbe, 0xa1, 0xe8, 0x94, 0xf9, 0x50, 0x71, 0x56, 0xaa, 0xeb, 0x90, - 0x06, 0xf2, 0x05, 0xb1, 0x19, 0xf0, 0x13, 0x89, 0x2d, 0x7b, 0x94, 0xb7, - 0xf2, 0x18, 0xfa, 0x52, 0x09, 0x82, 0x99, 0x20, 0xe9, 0x7a, 0x1c, 0x68, - 0xfe, 0x44, 0xe5, 0xf8, 0xc5, 0xd3, 0xc6, 0x66, 0x3d, 0xe3, 0x43, 0xc3, - 0x63, 0x81, 0xff, 0x78, 0x91, 0x5c, 0x48, 0x16, 0xbe, 0x92, 0x90, 0x2f, - 0x10, 0x9f, 0x2d, 0x17}; - -RsaTestKeys::RsaTestKeys() - : private_key_1_3072_bits_(std::begin(kTestRsaPrivateKey1_3072), - std::end(kTestRsaPrivateKey1_3072)), - public_key_1_3072_bits_(std::begin(kTestRsaPublicKey1_3072), - std::end(kTestRsaPublicKey1_3072)), - private_key_2_2048_bits_(std::begin(kTestRsaPrivateKey2_2048), - std::end(kTestRsaPrivateKey2_2048)), - public_key_2_2048_bits_(std::begin(kTestRsaPublicKey2_2048), - std::end(kTestRsaPublicKey2_2048)), - private_key_3_2048_bits_(std::begin(kTestRsaPrivateKey3_2048), - std::end(kTestRsaPrivateKey3_2048)), - public_key_3_2048_bits_(std::begin(kTestRsaPublicKey3_2048), - std::end(kTestRsaPublicKey3_2048)), - private_key_2_carmichael_totient_2048_bits_( - std::begin(kTestRsaPrivateKey2CarmichaelTotient_2048), - std::end(kTestRsaPrivateKey2CarmichaelTotient_2048)), - private_key_3_carmichael_totient_2048_bits_( - std::begin(kTestRsaPrivateKey3CarmichaelTotient_2048), - std::end(kTestRsaPrivateKey3CarmichaelTotient_2048)), - private_key_4_carmichael_totient_2048_bits_( - std::begin(kTestRsaPrivateKey4CarmichaelTotient_2048), - std::end(kTestRsaPrivateKey4CarmichaelTotient_2048)) {} - -} // namespace widevine diff --git a/common/rsa_test_keys.h b/common/rsa_test_keys.h deleted file mode 100644 index 68d98a4..0000000 --- a/common/rsa_test_keys.h +++ /dev/null @@ -1,92 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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: -// RSA keys generated using fake_prng for purposes of testing. - -#ifndef COMMON_RSA_TEST_KEYS_H_ -#define COMMON_RSA_TEST_KEYS_H_ - -#include - -namespace widevine { - -// Container for test RSA keys -// -// Except for the keys noted below, these keys were generated using Euler's -// Totient. -// -class RsaTestKeys { - public: - RsaTestKeys(); - - // Returns 3072-bit private RSA test key 1 - const std::string& private_test_key_1_3072_bits() const { - return private_key_1_3072_bits_; - } - // Returns 3072-bit public RSA test key 1 - const std::string& public_test_key_1_3072_bits() const { - return public_key_1_3072_bits_; - } - // Returns 2048-bit private RSA test key 2 - const std::string& private_test_key_2_2048_bits() const { - return private_key_2_2048_bits_; - } - // Returns 2048-bit public RSA test key 2 - const std::string& public_test_key_2_2048_bits() const { - return public_key_2_2048_bits_; - } - // Returns 2048-bit private RSA test key 3 - const std::string& private_test_key_3_2048_bits() const { - return private_key_3_2048_bits_; - } - // Returns 2048-bit public RSA test key 3 - const std::string& public_test_key_3_2048_bits() const { - return public_key_3_2048_bits_; - } - - // This key was converted to a Carmichael totient version from the original - // private_key_2_2048_bits_. - const std::string& private_test_key_2_carmichael_totient_2048_bits() const { - return private_key_2_carmichael_totient_2048_bits_; - } - - // This key was converted to a Carmichael totient version from the original - // private_key_3_2048_bits_. - const std::string& private_test_key_3_carmichael_totient_2048_bits() const { - return private_key_3_carmichael_totient_2048_bits_; - } - - // This key has been created using the Carmichael totient. This is - // useful for testing with some RSA implementations that had challenges - // with keys generated this way. - const std::string& private_test_key_4_carmichael_totient_2048_bits() const { - return private_key_4_carmichael_totient_2048_bits_; - } - - private: - RsaTestKeys(const RsaTestKeys&) = delete; - RsaTestKeys& operator=(const RsaTestKeys&) = delete; - - std::string private_key_1_3072_bits_; - std::string public_key_1_3072_bits_; - std::string private_key_2_2048_bits_; - std::string public_key_2_2048_bits_; - std::string private_key_3_2048_bits_; - std::string public_key_3_2048_bits_; - - // Tests keys that use the Carmichael totient to calculate d. - std::string private_key_2_carmichael_totient_2048_bits_; - std::string private_key_3_carmichael_totient_2048_bits_; - std::string private_key_4_carmichael_totient_2048_bits_; -}; - -} // namespace widevine - -#endif // COMMON_RSA_TEST_KEYS_H_ diff --git a/common/rsa_util_test.cc b/common/rsa_util_test.cc deleted file mode 100644 index 23cdf4b..0000000 --- a/common/rsa_util_test.cc +++ /dev/null @@ -1,353 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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: -// Unit test for rsa_util RSA utilties library. - -#include -#include - -#include -#include "glog/logging.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "openssl/bn.h" -#include "common/rsa_test_keys.h" -#include "common/rsa_util.h" - -using ::testing::NotNull; - -namespace { -const uint32_t kRsaPublicExponent = 65537; -const int kTestRsaBits = 2048; -} // anonymous namespace - -namespace widevine { -namespace rsa_util { - -class RsaUtilTest : public ::testing::Test { - protected: - RsaTestKeys test_keys_; -}; - -TEST_F(RsaUtilTest, SerializeDeserializePrivateKey) { - RSA* private_key; - std::string serialized_private_key; - // Key 1 - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_1_3072_bits(), &private_key)); - ASSERT_TRUE(private_key != NULL); - EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key)); - EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_1_3072_bits()); - EXPECT_EQ(RSA_check_key(private_key), 1); - RSA_free(private_key); - // Key 2 - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_2_2048_bits(), &private_key)); - ASSERT_TRUE(private_key != NULL); - EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key)); - EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_2_2048_bits()); - EXPECT_EQ(RSA_check_key(private_key), 1); - RSA_free(private_key); - // Key 3 - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_3_2048_bits(), &private_key)); - ASSERT_TRUE(private_key != NULL); - EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key)); - EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_3_2048_bits()); - EXPECT_EQ(RSA_check_key(private_key), 1); - RSA_free(private_key); - // Invalid key - EXPECT_FALSE(DeserializeRsaPrivateKey("this is a bad key", &private_key)); -} - -TEST_F(RsaUtilTest, SerializeDeserializePublicKey) { - RSA* public_key; - std::string serialized_public_key; - // Key 1 - EXPECT_TRUE(DeserializeRsaPublicKey( - test_keys_.public_test_key_1_3072_bits(), &public_key)); - ASSERT_TRUE(public_key != NULL); - EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits()); - RSA_free(public_key); - // Key 2 - EXPECT_TRUE(DeserializeRsaPublicKey( - test_keys_.public_test_key_2_2048_bits(), &public_key)); - ASSERT_TRUE(public_key != NULL); - EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits()); - RSA_free(public_key); - // Key 3 - EXPECT_TRUE(DeserializeRsaPublicKey( - test_keys_.public_test_key_3_2048_bits(), &public_key)); - ASSERT_TRUE(public_key != NULL); - EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits()); - RSA_free(public_key); - // Invalid key - EXPECT_FALSE(DeserializeRsaPublicKey("this is a bad key", &public_key)); -} - -TEST_F(RsaUtilTest, PublicKeyExtraction) { - RSA* private_key; - std::string serialized_public_key; - // Key 1 - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_1_3072_bits(), &private_key)); - ASSERT_TRUE(private_key != NULL); - EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits()); - RSA_free(private_key); - // Key 2 - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_2_2048_bits(), &private_key)); - ASSERT_TRUE(private_key != NULL); - EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits()); - RSA_free(private_key); - // Key 3 - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_3_2048_bits(), &private_key)); - ASSERT_TRUE(private_key != NULL); - EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key)); - EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits()); - RSA_free(private_key); -} - -TEST_F(RsaUtilTest, Pkcs8PrivateKeyInfo) { - // The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8 - // serialization/deserialization functionality , so we test those. - std::string serialized_pkcs8; - std::string serialized_pkcs1; - // Key 1 - EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo( - test_keys_.private_test_key_1_3072_bits(), &serialized_pkcs8)); - EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, - &serialized_pkcs1)); - EXPECT_NE(serialized_pkcs1, serialized_pkcs8); - EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1); - // Key 2 - EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo( - test_keys_.private_test_key_2_2048_bits(), &serialized_pkcs8)); - EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, - &serialized_pkcs1)); - EXPECT_NE(serialized_pkcs1, serialized_pkcs8); - EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1); - // Key 3 - EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo( - test_keys_.private_test_key_3_2048_bits(), &serialized_pkcs8)); - EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, - &serialized_pkcs1)); - EXPECT_NE(serialized_pkcs1, serialized_pkcs8); - EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1); -} - -TEST_F(RsaUtilTest, Pkcs8EncryptedPrivateKeyInfo) { - // The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8 - // serialization/deserialization functionality , so we test those. - std::string serialized_pkcs8; - std::string serialized_pkcs1; - std::string passphrase("passphrase"); - // Key 1 - EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo( - test_keys_.private_test_key_1_3072_bits(), passphrase, - &serialized_pkcs8)); - EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, - passphrase, - &serialized_pkcs1)); - EXPECT_NE(serialized_pkcs1, serialized_pkcs8); - EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1); - // Key 2 - EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo( - test_keys_.private_test_key_2_2048_bits(), passphrase, - &serialized_pkcs8)); - EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, - passphrase, - &serialized_pkcs1)); - EXPECT_NE(serialized_pkcs1, serialized_pkcs8); - EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1); - // Key 3 - EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo( - test_keys_.private_test_key_3_2048_bits(), passphrase, - &serialized_pkcs8)); - EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8, - passphrase, - &serialized_pkcs1)); - EXPECT_NE(serialized_pkcs1, serialized_pkcs8); - EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1); -} - -TEST_F(RsaUtilTest, FailOnInvalidParams) { - RSA* test_input_key = NULL; - RSA* test_output_key = NULL; - std::string test_string; - std::string pass("password"); - ASSERT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_2_2048_bits(), &test_input_key)); - ASSERT_TRUE(test_input_key != NULL); - EXPECT_FALSE(SerializeRsaPrivateKey(NULL, &test_string)); - EXPECT_FALSE(SerializeRsaPrivateKey(test_input_key, NULL)); - EXPECT_FALSE(SerializeRsaPublicKey(NULL, &test_string)); - EXPECT_FALSE(SerializeRsaPublicKey(test_input_key, NULL)); - EXPECT_FALSE(SerializePrivateKeyInfo(NULL, &test_string)); - EXPECT_FALSE(SerializePrivateKeyInfo(test_input_key, NULL)); - EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(NULL, pass, &test_string)); - EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass, NULL)); - EXPECT_FALSE(DeserializeRsaPrivateKey("", &test_output_key)); - EXPECT_FALSE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_2_2048_bits(), NULL)); - EXPECT_FALSE(DeserializeRsaPublicKey("", &test_output_key)); - EXPECT_FALSE(DeserializeRsaPublicKey( - test_keys_.public_test_key_2_2048_bits(), NULL)); - EXPECT_FALSE(DeserializePrivateKeyInfo("", &test_output_key)); - EXPECT_FALSE(DeserializePrivateKeyInfo( - test_keys_.private_test_key_2_2048_bits(), NULL)); - EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo("", pass, &test_output_key)); - EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo( - test_keys_.private_test_key_2_2048_bits(), pass, NULL)); - RSA_free(test_input_key); -} - -TEST_F(RsaUtilTest, Pkcs8FailOnInvalidPassword) { - RSA* test_input_key = NULL; - RSA* test_output_key = NULL; - std::string serialized_pkcs8; - std::string pass("password"); - ASSERT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_2_2048_bits(), &test_input_key)); - EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, "", - &serialized_pkcs8)); - ASSERT_TRUE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass, - &serialized_pkcs8)); - EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass + "a", - &test_output_key)); - EXPECT_TRUE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass, - &test_output_key)); - RSA_free(test_input_key); - RSA_free(test_output_key); -} - -TEST_F(RsaUtilTest, ConvertToCarmichaelTotient_ExistingKey_Success) { - bssl::UniquePtr original_private_key; - RSA* original_key_ptr = nullptr; - - EXPECT_TRUE(DeserializeRsaPrivateKey( - test_keys_.private_test_key_2_2048_bits(), &original_key_ptr)); - original_private_key.reset(original_key_ptr); - ASSERT_THAT(original_private_key, NotNull()); - - bssl::UniquePtr private_key( - RSAPrivateKey_dup(original_private_key.get())); - ASSERT_THAT(private_key, NotNull()); - EXPECT_TRUE(ConvertToCarmichaelTotient(private_key.get())); - - // Confirm that the key is valid and has changed from the original. - EXPECT_EQ(1, RSA_check_key(private_key.get())); - std::string serialized_carmichael_private_key; - EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(), - &serialized_carmichael_private_key)); - EXPECT_NE(serialized_carmichael_private_key, - test_keys_.private_test_key_2_2048_bits()); - - // Convert back and make sure the serialized key matches the original. - EXPECT_TRUE(ConvertToEulerTotient(private_key.get())); - EXPECT_EQ(1, RSA_check_key(private_key.get())); - std::string serialized_euler_private_key; - EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(), - &serialized_euler_private_key)); - EXPECT_EQ(serialized_euler_private_key, - test_keys_.private_test_key_2_2048_bits()); -} - -TEST_F(RsaUtilTest, ConvertToEulerTotient_NewKey_Success) { - bssl::UniquePtr rsa; - bssl::UniquePtr private_key; - bssl::UniquePtr exponent(BN_new()); - ASSERT_TRUE(BN_set_word(exponent.get(), kRsaPublicExponent)); - - // It is possible that sometimes, the d value generated using carmichael - // and euler is the same. For this test, find a key where they are not the - // same (max 100 tries). - bool found_distinct_keys = false; - for (int i = 0; i < 100; i++) { - rsa.reset(RSA_new()); - ASSERT_TRUE(RSA_generate_key_ex(rsa.get(), kTestRsaBits, - exponent.get(), nullptr)); - - private_key.reset(RSAPrivateKey_dup(rsa.get())); - EXPECT_TRUE(ConvertToEulerTotient(private_key.get())); - EXPECT_EQ(1, RSA_check_key(private_key.get())); - - // If the values are different, break. - if (BN_cmp(private_key->d, rsa->d) != 0) { - found_distinct_keys = true; - break; - } - - LOG(INFO) << "Euler and Carmichael d values are the same. Count: " << i; - } - - ASSERT_TRUE(found_distinct_keys) - << "Reached maximum attempts, but did not generate distinct keys"; - EXPECT_EQ(1, RSA_check_key(private_key.get())); - - // Sanity check that the serialized keys are distinct. - std::string serialized_carmichael_private_key; - std::string serialized_private_key; - EXPECT_TRUE(SerializeRsaPrivateKey(rsa.get(), - &serialized_carmichael_private_key)); - - EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(), - &serialized_private_key)); - EXPECT_NE(serialized_carmichael_private_key, serialized_private_key); - - // Convert back to Carmichael, validate, and confirm that the keys are the - // same. - EXPECT_TRUE(ConvertToCarmichaelTotient(private_key.get())); - EXPECT_EQ(1, RSA_check_key(private_key.get())); - EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(), - &serialized_private_key)); - EXPECT_EQ(serialized_carmichael_private_key, serialized_private_key); -} - -TEST_F(RsaUtilTest, ConvertToSerializedCarmichaelTotient_Success) { - std::string private_key; - EXPECT_TRUE(ConvertToCarmichaelTotient( - test_keys_.private_test_key_2_2048_bits(), &private_key)); - EXPECT_EQ(test_keys_.private_test_key_2_carmichael_totient_2048_bits(), - private_key); -} - -TEST_F(RsaUtilTest, ConvertToSerializedEulerTotient_Success) { - std::string private_key; - EXPECT_TRUE(ConvertToEulerTotient( - test_keys_.private_test_key_2_carmichael_totient_2048_bits(), - &private_key)); - EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), private_key); -} - -TEST_F(RsaUtilTest, ConvertToEulerTotient_Idempotent_Success) { - std::string private_key; - EXPECT_TRUE(ConvertToEulerTotient(test_keys_.private_test_key_2_2048_bits(), - &private_key)); - EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), private_key); -} - -TEST_F(RsaUtilTest, ConvertToCarmichaelTotient_Idempotent_Success) { - std::string private_key; - EXPECT_TRUE(ConvertToCarmichaelTotient( - test_keys_.private_test_key_2_carmichael_totient_2048_bits(), - &private_key)); - EXPECT_EQ(test_keys_.private_test_key_2_carmichael_totient_2048_bits(), - private_key); -} - -} // namespace rsa_util -} // namespace widevine diff --git a/common/security_profile_list.cc b/common/security_profile_list.cc deleted file mode 100644 index 2d753a2..0000000 --- a/common/security_profile_list.cc +++ /dev/null @@ -1,245 +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. -//////////////////////////////////////////////////////////////////////////////// -// Implementation of the SecurityProfileList class. - -#include "common/security_profile_list.h" - -#include - -#include "glog/logging.h" -#include "google/protobuf/text_format.h" -#include "common/client_id_util.h" -#include "common/device_status_list.h" -#include "protos/public/client_identification.pb.h" -#include "protos/public/device_certificate_status.pb.h" -#include "protos/public/device_common.pb.h" -#include "protos/public/provisioned_device_info.pb.h" -#include "protos/public/security_profile.pb.h" - -namespace widevine { -using ClientCapabilities = ClientIdentification::ClientCapabilities; - -SecurityProfileList::SecurityProfileList(const std::string& profile_namespace) - : profile_namespace_(profile_namespace) {} - -int SecurityProfileList::Init() { return 0; } - -int SecurityProfileList::GetQualifiedProfilesFromSpecifiedProfiles( - const std::vector& profiles_to_check, - const ClientIdentification& client_id, - const ProvisionedDeviceInfo& device_info, - std::vector* qualified_profiles) const { - if (qualified_profiles == nullptr) { - return 0; - } - qualified_profiles->clear(); - absl::ReaderMutexLock lock(&mutex_); - for (auto& profile_name : profiles_to_check) { - SecurityProfile profile; - if (GetProfileByName(profile_name, &profile)) { - if (DoesProfileQualify(profile, client_id, device_info)) { - qualified_profiles->push_back(profile.name()); - } - } - } - return qualified_profiles->size(); -} - -int SecurityProfileList::GetQualifiedProfiles( - const ClientIdentification& client_id, - const ProvisionedDeviceInfo& device_info, - std::vector* qualified_profiles) const { - if (qualified_profiles == nullptr) { - return 0; - } - qualified_profiles->clear(); - absl::ReaderMutexLock lock(&mutex_); - for (auto& profile : security_profiles_) { - if (DoesProfileQualify(profile, client_id, device_info)) { - qualified_profiles->push_back(profile.name()); - } - } - return qualified_profiles->size(); -} - -bool SecurityProfileList::GetDrmInfo(const ClientIdentification& client_id, - const ProvisionedDeviceInfo& device_info, - SecurityProfile::DrmInfo* drm_info) const { - if (drm_info == nullptr) { - return false; - } - drm_info->mutable_output()->set_hdcp_version( - client_id.client_capabilities().max_hdcp_version()); - drm_info->mutable_output()->set_analog_output_capabilities( - client_id.client_capabilities().analog_output_capabilities()); - drm_info->mutable_security()->set_oemcrypto_api_version( - client_id.client_capabilities().oem_crypto_api_version()); - drm_info->mutable_security()->set_resource_rating_tier( - client_id.client_capabilities().resource_rating_tier()); - drm_info->mutable_security()->set_security_level( - device_info.security_level()); - drm_info->mutable_request_model_info()->set_manufacturer( - GetClientInfo(client_id, kModDrmMake)); - drm_info->mutable_request_model_info()->set_model_name( - GetClientInfo(client_id, kModDrmModel)); - drm_info->mutable_request_model_info()->set_status( - DeviceModel::MODEL_STATUS_UNVERIFIED); - for (const auto& model_info : device_info.model_info()) { - if (model_info.manufacturer() == - drm_info->request_model_info().manufacturer() && - model_info.model_name() == - drm_info->request_model_info().model_name()) { - drm_info->mutable_request_model_info()->set_status(model_info.status()); - drm_info->mutable_request_model_info()->set_model_year( - model_info.model_year()); - break; - } - } - drm_info->set_system_id(device_info.system_id()); - SecurityProfile::ClientInfo* client_info = drm_info->mutable_client_info(); - client_info->set_device_name(GetClientInfo(client_id, kModDrmDeviceName)); - SecurityProfile::ClientInfo::ProductInfo* product_info = - client_info->mutable_product_info(); - product_info->set_product_name(GetClientInfo(client_id, kModDrmProductName)); - product_info->set_build_info(GetClientInfo(client_id, kModDrmBuildInfo)); - product_info->set_oem_crypto_security_patch_level( - GetClientInfo(client_id, kModDrmOemCryptoSecurityPatchLevel)); - // TODO(user): Figure out how to get device platform pushed into SPL API. - DeviceCertificateStatus device_certificate_status; - SecurityProfile::DeviceState device_model_state = - SecurityProfile::DEVICE_STATE_UNKNOWN; - Status status = - DeviceStatusList::Instance()->GetDeviceCertificateStatusBySystemId( - device_info.system_id(), &device_certificate_status); - if (status.ok() && device_certificate_status.has_status()) { - switch (device_certificate_status.status()) { - case DeviceCertificateStatus::STATUS_IN_TESTING: - device_model_state = SecurityProfile::IN_TESTING; - break; - case DeviceCertificateStatus::STATUS_RELEASED: - device_model_state = SecurityProfile::RELEASED; - break; - case DeviceCertificateStatus::STATUS_TEST_ONLY: - device_model_state = SecurityProfile::TEST_ONLY; - break; - case DeviceCertificateStatus::STATUS_REVOKED: - device_model_state = SecurityProfile::REVOKED; - break; - default: - break; - } - } - drm_info->set_device_model_state(device_model_state); - return true; -} - -bool SecurityProfileList::GetProfileByName( - const std::string& name, SecurityProfile* security_profile) const { - absl::ReaderMutexLock lock(&mutex_); - for (auto& profile : security_profiles_) { - if (profile.name() == name) { - if (security_profile != nullptr) { - *security_profile = profile; - } - return true; - } - } - return false; -} - -bool SecurityProfileList::InsertProfile( - const SecurityProfile& profile_to_insert) { - // Check if profile already exist. - if (GetProfileByName(profile_to_insert.name(), nullptr)) { - LOG(ERROR) << "Unable to insert profile: " << profile_to_insert.name() - << ". Name already exist."; - return false; - } - if (profile_to_insert.min_security_requirements().security_level() == - ProvisionedDeviceInfo::LEVEL_UNSPECIFIED) { - LOG(ERROR) << "Unable to insert profile: " << profile_to_insert.name() - << ". Security level not specified."; - return false; - } - - absl::WriterMutexLock lock(&mutex_); - security_profiles_.push_back(profile_to_insert); - return true; -} - -int SecurityProfileList::NumProfiles() const { - absl::ReaderMutexLock lock(&mutex_); - return security_profiles_.size(); -} - -void SecurityProfileList::ClearAllProfiles() { - absl::WriterMutexLock lock(&mutex_); - security_profiles_.clear(); -} - -bool SecurityProfileList::DoesProfileQualify( - const SecurityProfile& profile, const ClientIdentification& client_id, - const ProvisionedDeviceInfo& device_info) const { - if (profile.min_security_requirements().security_level() < - device_info.security_level()) { - VLOG(1) << "Profile does not qualify <" << profile.name() - << "> security level: " - << profile.min_security_requirements().security_level() - << ", device: " << device_info.security_level(); - return false; - } - if (profile.min_security_requirements().oemcrypto_api_version() > - client_id.client_capabilities().oem_crypto_api_version()) { - VLOG(1) << "Profile does not qualify <" << profile.name() - << "> oemcrypto version: " - << profile.min_security_requirements().oemcrypto_api_version() - << ", device: " - << client_id.client_capabilities().oem_crypto_api_version(); - return false; - } - if (profile.min_output_requirements().hdcp_version() > - client_id.client_capabilities().max_hdcp_version()) { - VLOG(1) << "profile does not qualify <" << profile.name() - << "> hdcp_version: " - << profile.min_output_requirements().hdcp_version() << ", device: " - << client_id.client_capabilities().max_hdcp_version(); - return false; - } - if (profile.min_output_requirements().analog_output_capabilities() > - client_id.client_capabilities().analog_output_capabilities()) { - VLOG(1) << "Profile idoes not qualify <" << profile.name() - << "> analog output: " - << profile.min_output_requirements().analog_output_capabilities() - << ", device: " - << client_id.client_capabilities().analog_output_capabilities(); - return false; - } - if (profile.min_security_requirements().resource_rating_tier() > - client_id.client_capabilities().resource_rating_tier()) { - VLOG(1) << "Profile does not qualify <" << profile.name() - << "> resource rating tier: " - << profile.min_security_requirements().resource_rating_tier() - << ", device: " - << client_id.client_capabilities().resource_rating_tier(); - return false; - } - return true; -} - -void SecurityProfileList::GetProfileNames( - std::vector* profile_names) const { - if (profile_names == nullptr) { - return; - } - absl::ReaderMutexLock lock(&mutex_); - for (auto& profile : security_profiles_) { - profile_names->push_back(profile.name()); - } -} - -} // namespace widevine diff --git a/common/security_profile_list.h b/common/security_profile_list.h deleted file mode 100644 index 07b2a3b..0000000 --- a/common/security_profile_list.h +++ /dev/null @@ -1,93 +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 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/common/security_profile_list_test.cc b/common/security_profile_list_test.cc deleted file mode 100644 index 964a779..0000000 --- a/common/security_profile_list_test.cc +++ /dev/null @@ -1,206 +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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/security_profile_list.h" - -#include "glog/logging.h" -#include "google/protobuf/util/message_differencer.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/memory/memory.h" -#include "common/client_id_util.h" -#include "protos/public/device_common.pb.h" -#include "protos/public/security_profile.pb.h" - -namespace widevine { -namespace security_profile { - -const char kMakeName[] = "company_name"; -const char kMakeValue[] = "Google"; -const char kModelName[] = "model_name"; -const char kModelValue[] = "model1"; -const char kDeviceNameValue[] = "TestDeviceName"; -const char kProductNameValue[] = "TestProductName"; -const char kBuildInfoValue[] = "TestBuildInfo"; -const char kOemCryptoSecurityPatchLevelValue[] = - "TestOemCryptoSecurityPatchLevel"; -const char kDefaultContentOwnerName[] = "Widevine"; -const uint32_t kSystemId = 1234; -const uint32_t kResourceTierLow = 1; -const uint32_t kResourceTierMed = 2; -const uint32_t kResourceTierHigh = 3; - -class SecurityProfileListTest : public ::testing::Test { - public: - SecurityProfileListTest() {} - ~SecurityProfileListTest() override {} - - void SetUp() override { - const uint32_t oemcrypto_12 = 12; - SecurityProfile profile; - std::string profile_namespace = "widevine"; - profile_list_ = absl::make_unique(profile_namespace); - - AddClientInfo(&client_id_, kMakeName, kMakeValue); - AddClientInfo(&client_id_, kModelName, kModelValue); - AddClientInfo(&client_id_, kModDrmDeviceName, kDeviceNameValue); - AddClientInfo(&client_id_, kModDrmProductName, kProductNameValue); - AddClientInfo(&client_id_, kModDrmBuildInfo, kBuildInfoValue); - AddClientInfo(&client_id_, kModDrmOemCryptoSecurityPatchLevel, - kOemCryptoSecurityPatchLevelValue); - client_id_.mutable_client_capabilities()->set_oem_crypto_api_version( - oemcrypto_12); - client_id_.mutable_client_capabilities()->set_max_hdcp_version( - ClientCapabilities::HDCP_V2_2); - client_id_.mutable_client_capabilities()->set_resource_rating_tier( - kResourceTierHigh); - - device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_1); - device_info_.set_system_id(kSystemId); - } - std::unique_ptr profile_list_; - ClientIdentification client_id_; - ProvisionedDeviceInfo device_info_; -}; - -TEST_F(SecurityProfileListTest, InsertProfile) { - // Insert test profile1 into the list. - SecurityProfileList profile_list("widevine-test"); - SecurityProfile profile1; - profile1.set_name("profile1"); - profile1.mutable_min_security_requirements()->set_security_level( - ProvisionedDeviceInfo::LEVEL_3); - EXPECT_TRUE(profile_list.InsertProfile(profile1)); - // Verify the list still has one profile. - EXPECT_EQ(1, profile_list.NumProfiles()); - // Should not allow insert if existing profile has the same name. - SecurityProfile profile2; - profile2.set_name(profile1.name()); - profile2.mutable_min_security_requirements()->set_security_level( - ProvisionedDeviceInfo::LEVEL_3); - EXPECT_FALSE(profile_list.InsertProfile(profile2)); - // Verify the list still has one profile. - EXPECT_EQ(1, profile_list.NumProfiles()); - // Should allow insert since this profile has a different name. - profile2.set_name("profile2"); - EXPECT_TRUE(profile_list.InsertProfile(profile2)); - EXPECT_EQ(2, profile_list.NumProfiles()); -} - -TEST_F(SecurityProfileListTest, GetDrmInfo) { - SecurityProfile::DrmInfo drm_info; - DeviceModel* device_model = device_info_.add_model_info(); - device_model->set_manufacturer(GetClientInfo(client_id_, kModDrmMake)); - device_model->set_model_name(GetClientInfo(client_id_, kModDrmModel)); - device_model->set_status(DeviceModel::MODEL_STATUS_VERIFIED); - const uint32_t model_launch_year = 2015; - device_model->set_model_year(model_launch_year); - ASSERT_TRUE(profile_list_->GetDrmInfo(client_id_, device_info_, &drm_info)); - EXPECT_EQ(client_id_.client_capabilities().max_hdcp_version(), - drm_info.output().hdcp_version()); - EXPECT_EQ(client_id_.client_capabilities().analog_output_capabilities(), - drm_info.output().analog_output_capabilities()); - EXPECT_EQ(client_id_.client_capabilities().oem_crypto_api_version(), - drm_info.security().oemcrypto_api_version()); - EXPECT_EQ(client_id_.client_capabilities().resource_rating_tier(), - drm_info.security().resource_rating_tier()); - - EXPECT_EQ(device_info_.security_level(), - drm_info.security().security_level()); - EXPECT_EQ(device_info_.system_id(), drm_info.system_id()); - - EXPECT_EQ(kMakeValue, drm_info.request_model_info().manufacturer()); - EXPECT_EQ(kModelValue, drm_info.request_model_info().model_name()); - EXPECT_EQ(DeviceModel::MODEL_STATUS_VERIFIED, - drm_info.request_model_info().status()); - EXPECT_EQ(model_launch_year, drm_info.request_model_info().model_year()); - EXPECT_EQ(kDeviceNameValue, drm_info.client_info().device_name()); - EXPECT_EQ(kProductNameValue, - drm_info.client_info().product_info().product_name()); - EXPECT_EQ(kBuildInfoValue, - drm_info.client_info().product_info().build_info()); - EXPECT_EQ( - kOemCryptoSecurityPatchLevelValue, - drm_info.client_info().product_info().oem_crypto_security_patch_level()); -} - -TEST_F(SecurityProfileListTest, QualifiedProfiles) { - SecurityProfile profile1; - profile1.set_name("profile1"); - profile1.mutable_min_security_requirements()->set_security_level( - ProvisionedDeviceInfo::LEVEL_3); - profile1.mutable_min_output_requirements()->set_hdcp_version( - ClientCapabilities::HDCP_V1); - profile_list_->InsertProfile(profile1); - - SecurityProfile profile2; - profile2.set_name("profile2"); - profile2.mutable_min_security_requirements()->set_security_level( - ProvisionedDeviceInfo::LEVEL_1); - profile2.mutable_min_output_requirements()->set_hdcp_version( - ClientCapabilities::HDCP_V2); - profile_list_->InsertProfile(profile2); - - // Both profiles should qualify based on client_info and device_info from the - // Setup function. - std::vector qualified_profiles; - EXPECT_EQ(2, profile_list_->GetQualifiedProfiles(client_id_, device_info_, - &qualified_profiles)); - EXPECT_NE(qualified_profiles.end(), - std::find(qualified_profiles.begin(), qualified_profiles.end(), - profile1.name())); - EXPECT_NE(qualified_profiles.end(), - std::find(qualified_profiles.begin(), qualified_profiles.end(), - profile2.name())); - - // Reduce the DRM capabilities of the device so profile2 will not qualify. - client_id_.mutable_client_capabilities()->set_max_hdcp_version( - ClientCapabilities::HDCP_V1); - ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_, - &qualified_profiles)); - EXPECT_NE(qualified_profiles.end(), - std::find(qualified_profiles.begin(), qualified_profiles.end(), - profile1.name())); -} - -TEST_F(SecurityProfileListTest, FindProfile) { - SecurityProfileList profile_list("widevine-test"); - SecurityProfile profile1; - profile1.set_name("profile1"); - profile1.mutable_min_security_requirements()->set_security_level( - ProvisionedDeviceInfo::LEVEL_3); - EXPECT_EQ(kDefaultContentOwnerName, profile1.owner()); - SecurityProfile profile2; - profile2.set_name("profile2"); - profile2.mutable_min_security_requirements()->set_security_level( - ProvisionedDeviceInfo::LEVEL_3); - // Override the default owner name. - profile2.set_owner("owner2"); - // Insert profiles 1 & 2. - EXPECT_TRUE(profile_list.InsertProfile(profile1)); - EXPECT_TRUE(profile_list.InsertProfile(profile2)); - EXPECT_EQ(2, profile_list.NumProfiles()); - - // Find the profile by its name. - SecurityProfile profile; - EXPECT_TRUE(profile_list.GetProfileByName(profile1.name(), &profile)); - EXPECT_EQ(profile1.name(), profile.name()); - EXPECT_EQ(profile1.level(), profile.level()); - EXPECT_EQ(profile1.owner(), profile.owner()); - - EXPECT_TRUE(profile_list.GetProfileByName(profile2.name(), &profile)); - EXPECT_EQ(profile2.name(), profile.name()); - EXPECT_EQ(profile2.level(), profile.level()); - EXPECT_EQ(profile2.owner(), profile.owner()); - - EXPECT_FALSE( - profile_list.GetProfileByName("you-should-not-find-me", &profile)); -} - -} // namespace security_profile -} // namespace widevine diff --git a/common/sha_util_test.cc b/common/sha_util_test.cc deleted file mode 100644 index 9d71936..0000000 --- a/common/sha_util_test.cc +++ /dev/null @@ -1,74 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/sha_util.h" - -#include "testing/gunit.h" -#include "absl/strings/escaping.h" - -namespace widevine { - -TEST(ShaUtilTest, Sha1Empty) { - const uint8_t kExpected[] = { - 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, - 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09, - }; - EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), - Sha1_Hash("")); -} - -TEST(ShaUtilTest, Sha256Empty) { - const uint8_t kExpected[] = { - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, - 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, - 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, - }; - EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), - Sha256_Hash("")); -} - -TEST(ShaUtilTest, Sha1) { - const uint8_t kExpected[] = { - 0x6b, 0x63, 0xa5, 0xe3, 0x6b, 0xfe, 0x54, 0x19, 0x4e, 0xfe, - 0x9f, 0xe0, 0x29, 0x7e, 0xd8, 0x11, 0x0f, 0x10, 0x0d, 0x1d, - }; - EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), - Sha1_Hash("random data")); -} - -TEST(ShaUtilTest, Sha256) { - const uint8_t kExpected[] = { - 0x62, 0x4b, 0x56, 0xb3, 0x38, 0x1b, 0xbc, 0xe0, 0x4f, 0x58, 0x88, - 0x83, 0xb4, 0x2f, 0x4e, 0x27, 0xfe, 0xc0, 0x95, 0x56, 0xf8, 0x61, - 0xcf, 0x94, 0x49, 0xe6, 0x5f, 0x26, 0xea, 0x70, 0xad, 0x88, - }; - EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), - Sha256_Hash("random data")); -} - -TEST(ShaUtilTest, Sha512) { - const uint8_t kExpected[] = { - 0x8f, 0x49, 0x93, 0x1f, 0x4d, 0x4a, 0x67, 0x6f, 0x9a, 0x7e, 0x62, - 0x60, 0xea, 0xe1, 0x54, 0xfe, 0xe2, 0x75, 0x3c, 0xec, 0x3b, 0xb2, - 0x2e, 0xd7, 0x51, 0xcc, 0x39, 0xf9, 0x89, 0x69, 0xad, 0xd0, 0x14, - 0xaa, 0xbe, 0x40, 0xce, 0xe3, 0xab, 0xef, 0x10, 0x2f, 0x24, 0x0e, - 0xd8, 0x26, 0x7b, 0xb5, 0x7d, 0x86, 0xce, 0xbd, 0xd7, 0x32, 0x86, - 0x3a, 0x5e, 0x9e, 0x8d, 0x23, 0x77, 0x10, 0x80, 0x0c}; - EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)), - Sha512_Hash("random data")); -} - -TEST(ShaUtilTest, GenerateSha1Uuid) { - std::string name_space = - absl::HexStringToBytes("4d20ad7dd95bc4b250fae56fb143e774"); - std::string name = "some seed value"; - EXPECT_EQ("730621a55c675c4086be38e72aefa03e", - absl::BytesToHexString(GenerateSha1Uuid(name_space, name))); -} - -} // namespace widevine diff --git a/common/signer_public_key.cc b/common/signer_public_key.cc deleted file mode 100644 index 87dd617..0000000 --- a/common/signer_public_key.cc +++ /dev/null @@ -1,70 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/signer_public_key.h" - -#include "absl/memory/memory.h" -#include "common/ec_key.h" -#include "common/rsa_key.h" - -namespace widevine { - -// SignerPublicKeyImpl is a generic implementation of SignerPublicKey. The -// initialization details are in the SignerPublicKey factory method. -template -class SignerPublicKeyImpl : public SignerPublicKey { - public: - explicit SignerPublicKeyImpl(std::unique_ptr signer_public_key) - : signer_public_key_(std::move(signer_public_key)) {} - ~SignerPublicKeyImpl() override {} - SignerPublicKeyImpl(const SignerPublicKeyImpl&) = delete; - SignerPublicKeyImpl& operator=(const SignerPublicKeyImpl&) = delete; - - bool VerifySignature(const std::string& message, HashAlgorithm hash_algorithm, - const std::string& signature) const override { - if (!signer_public_key_->VerifySignature(message, hash_algorithm, - signature)) { - return false; - } - return true; - } - - private: - std::unique_ptr signer_public_key_; -}; - -std::unique_ptr SignerPublicKey::Create( - const std::string& signer_public_key, DrmCertificate::Algorithm algorithm) { - switch (algorithm) { - case DrmCertificate::RSA: { - std::unique_ptr public_key( - RsaPublicKey::Create(signer_public_key)); - if (public_key == nullptr) { - return nullptr; - } - return absl::make_unique>( - std::move(public_key)); - } - // All supported ECC curves are specified here. - case DrmCertificate::ECC_SECP256R1: - case DrmCertificate::ECC_SECP384R1: - case DrmCertificate::ECC_SECP521R1: { - std::unique_ptr public_key = - ECPublicKey::Create(signer_public_key); - if (public_key == nullptr) { - return nullptr; - } - return absl::make_unique>( - std::move(public_key)); - } - default: - return nullptr; - } -} - -} // namespace widevine diff --git a/common/signer_public_key.h b/common/signer_public_key.h deleted file mode 100644 index 9670f6d..0000000 --- a/common/signer_public_key.h +++ /dev/null @@ -1,42 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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_SIGNER_PUBLIC_KEY_H_ -#define COMMON_SIGNER_PUBLIC_KEY_H_ - -#include - -#include "common/hash_algorithm.h" -#include "protos/public/drm_certificate.pb.h" - -namespace widevine { - -// SignerPublicKey is implemented for each provisioning key type that are -// defined in video/widevine/proto/public.drm_certificate.proto. -class SignerPublicKey { - public: - SignerPublicKey() = default; - virtual ~SignerPublicKey() = default; - SignerPublicKey(const SignerPublicKey&) = delete; - SignerPublicKey& operator=(const SignerPublicKey&) = delete; - - // Verify message using |signer_public_key_| and |hash_algorithm|. - virtual bool VerifySignature(const std::string& message, - HashAlgorithm hash_algorithm, - const std::string& signature) const = 0; - - // A factory method to create a SignerPublicKey. The |algorithm| is used to - // create an appropriate SignerPublicKey for the key type. - // The returned pointer is a nullptr if the key cannot be deserialized. - static std::unique_ptr Create( - const std::string& signer_public_key, - DrmCertificate::Algorithm algorithm); -}; - -} // namespace widevine -#endif // COMMON_SIGNER_PUBLIC_KEY_H_ diff --git a/common/signer_public_key_test.cc b/common/signer_public_key_test.cc deleted file mode 100644 index 2243690..0000000 --- a/common/signer_public_key_test.cc +++ /dev/null @@ -1,82 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2019 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/signer_public_key.h" - -#include - -#include "testing/gunit.h" -#include "common/ec_key.h" -#include "common/ec_test_keys.h" -#include "common/hash_algorithm.h" -#include "common/rsa_key.h" -#include "common/rsa_test_keys.h" -#include "protos/public/drm_certificate.pb.h" - -namespace widevine { - -static const char kMessage[] = "The rain in Spain falls mainly in the blank?"; -const HashAlgorithm kHashAlgorithm = HashAlgorithm::kSha256; - -class SignerPublicKeyTest : public ::testing::Test { - public: - RsaTestKeys rsa_test_keys_; - ECTestKeys ec_test_keys_; -}; - -TEST_F(SignerPublicKeyTest, RSA) { - std::unique_ptr private_key( - RsaPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits())); - - std::string signature; - ASSERT_TRUE( - private_key->GenerateSignature(kMessage, kHashAlgorithm, &signature)); - - std::unique_ptr public_key = SignerPublicKey::Create( - rsa_test_keys_.public_test_key_1_3072_bits(), DrmCertificate::RSA); - ASSERT_NE(public_key, nullptr); - EXPECT_TRUE(public_key->VerifySignature(kMessage, kHashAlgorithm, signature)); -} - -TEST_F(SignerPublicKeyTest, ECC) { - std::unique_ptr private_key = - ECPrivateKey::Create(ec_test_keys_.private_test_key_1_secp521r1()); - - std::string signature; - ASSERT_TRUE( - private_key->GenerateSignature(kMessage, kHashAlgorithm, &signature)); - - std::unique_ptr public_key = - SignerPublicKey::Create(ec_test_keys_.public_test_key_1_secp521r1(), - DrmCertificate::ECC_SECP521R1); - ASSERT_NE(public_key, nullptr); - EXPECT_TRUE(public_key->VerifySignature(kMessage, kHashAlgorithm, signature)); -} - -TEST_F(SignerPublicKeyTest, IncorrectAlgorithm) { - std::unique_ptr rsa_public_key = - SignerPublicKey::Create(rsa_test_keys_.public_test_key_1_3072_bits(), - DrmCertificate::ECC_SECP521R1); - ASSERT_EQ(rsa_public_key, nullptr); - - std::unique_ptr ec_public_key = SignerPublicKey::Create( - ec_test_keys_.public_test_key_1_secp521r1(), DrmCertificate::RSA); - ASSERT_EQ(ec_public_key, nullptr); -} - -TEST_F(SignerPublicKeyTest, BadKey) { - std::unique_ptr rsa_public_key = - SignerPublicKey::Create("GobbletyGook", DrmCertificate::RSA); - ASSERT_EQ(rsa_public_key, nullptr); - - std::unique_ptr ec_public_key = SignerPublicKey::Create( - "MoreGobbletyGook", DrmCertificate::ECC_SECP521R1); - ASSERT_EQ(ec_public_key, nullptr); -} - -} // namespace widevine diff --git a/common/signing_key_util.cc b/common/signing_key_util.cc deleted file mode 100644 index 65ca55e..0000000 --- a/common/signing_key_util.cc +++ /dev/null @@ -1,44 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/signing_key_util.h" - -#include "glog/logging.h" -#include "common/crypto_util.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { - -using crypto_util::kSigningKeySizeBits; - -uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version) { - if (protocol_version <= VERSION_2_0) { - return kSigningKeySizeBits; - } else { - return kSigningKeySizeBits * 2; - } -} - -using crypto_util::kSigningKeySizeBytes; -std::string GetClientSigningKey(const std::string& derived_key, - ProtocolVersion protocol_version) { - if (protocol_version == VERSION_2_0) { - DCHECK(derived_key.size() >= kSigningKeySizeBytes); - return derived_key.substr(0, kSigningKeySizeBytes); - } else { - DCHECK(derived_key.size() >= kSigningKeySizeBytes * 2); - return derived_key.substr(kSigningKeySizeBytes, kSigningKeySizeBytes); - } -} - -std::string GetServerSigningKey(const std::string& derived_key) { - DCHECK(derived_key.size() >= kSigningKeySizeBytes); - return derived_key.substr(0, kSigningKeySizeBytes); -} - -} // namespace widevine diff --git a/common/signing_key_util.h b/common/signing_key_util.h deleted file mode 100644 index 7e7557f..0000000 --- a/common/signing_key_util.h +++ /dev/null @@ -1,54 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Contains functions that are used to create and parse derived keys created -// using the NIST 800-108 KDF recommendation, using AES-CMAC PRF. -// NIST 800-108: -// http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf -// AES-CMAC: -// http://tools.ietf.org/html/rfc4493 -// -// Example usage: -// using video::widevine::common::crypto_util::DeriveKey; -// using widevine_server::sdk::VERSION_2_1; -// -// std::string derived_key = DeriveKey(key_str, -// label, -// context, -// SigningKeyMaterialSizeBits(VERSION_2_1)); -// std::string server_derived_key = GetServerSigningKey(derived_key); -// std::string client_derived_key = GetClientSigninKey(derived_key); -#ifndef COMMON_SIGNING_KEY_UTIL_H_ -#define COMMON_SIGNING_KEY_UTIL_H_ - -#include - -#include "protos/public/license_protocol.pb.h" - -namespace widevine { - -// Returns the size of the signing key based on the License Protocol -// Version. Signing keys for version 2.0 have a length of 256. Signing -// keys for version 2.1 have a length of 512. -uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version); - -// Returns the client portion of the derived_key. The client portion -// depend on the size of the key. Keys that are 512 bits in length -// are assumed to be version 2.1 keys. The last 256 bits of those -// keys are returned. Keys that are 256 bits in length are returned -// in there entirety, version 2.0 keys. -std::string GetClientSigningKey(const std::string& derived_key, - ProtocolVersion protocol_version); - -// Returns the server portion of the derived_key. The server portion -// is the first 256 bits of the key. -std::string GetServerSigningKey(const std::string& derived_key); - -} // namespace widevine - -#endif // COMMON_SIGNING_KEY_UTIL_H_ diff --git a/common/signing_key_util_test.cc b/common/signing_key_util_test.cc deleted file mode 100644 index 70e448c..0000000 --- a/common/signing_key_util_test.cc +++ /dev/null @@ -1,66 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/signing_key_util.h" - -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/crypto_util.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { -namespace signing_key_util { -namespace { -const char* kFrontKeyHex = - "0a1a2a3a4a5a6a7a8a9a0b1b2b3b4b5b0a1a2a3a4a5a6a7a8a9a0b1b2b3b4b5b"; -const char* kBackKeyHex = - "0c1c2c3c4c5c6c7c8c9c0d1d2d3d4d5d0c1c2c3c4c5c6c7c8c9c0d1d2d3d4d5d"; - -std::string GenerateDerivedKey( - widevine::ProtocolVersion protocol_version) { - if (protocol_version == widevine::VERSION_2_0) { - return absl::HexStringToBytes(kFrontKeyHex); - } else { - return absl::HexStringToBytes(kFrontKeyHex) + - absl::HexStringToBytes(kBackKeyHex); - } -} -} // namespace - -TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_0) { - ASSERT_EQ(crypto_util::kSigningKeySizeBits, - SigningKeyMaterialSizeBits(VERSION_2_0)); -} - -TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_1) { - ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2, - SigningKeyMaterialSizeBits(VERSION_2_1)); -} - -TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_1) { - ASSERT_EQ(kFrontKeyHex, absl::BytesToHexString(GetServerSigningKey( - GenerateDerivedKey(VERSION_2_1)))); -} - -TEST(DerivedKeyUtilTest, GetClientSigningKeyProtocolVersion2_1) { - ASSERT_EQ(kBackKeyHex, absl::BytesToHexString(GetClientSigningKey( - GenerateDerivedKey(VERSION_2_1), VERSION_2_1))); -} - -TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_0) { - ASSERT_EQ(kFrontKeyHex, absl::BytesToHexString(GetServerSigningKey( - GenerateDerivedKey(VERSION_2_0)))); -} - -TEST(DerivedKeyUtilTest, GetClientSigningKeyProtocolVersion2_0) { - ASSERT_EQ(kFrontKeyHex, absl::BytesToHexString(GetClientSigningKey( - GenerateDerivedKey(VERSION_2_0), VERSION_2_0))); -} - -} // namespace signing_key_util -} // namespace widevine diff --git a/common/status_test.cc b/common/status_test.cc deleted file mode 100644 index e3fda01..0000000 --- a/common/status_test.cc +++ /dev/null @@ -1,61 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2007 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/status.h" -#include "testing/gunit.h" - -namespace widevine { - -TEST(StatusTest, OK_Status) { - // test case for ok status. - Status status(error::OK); - EXPECT_EQ("OK", status.ToString()); -} - -TEST(StatusTest, OK_Status2) { - // test case for ok status. - Status status; - EXPECT_EQ("OK", status.ToString()); -} - -TEST(StatusTest, ALREADY_EXISTS_Status) { - Status status(error::ALREADY_EXISTS, "it is already exist"); - EXPECT_EQ("Errors::already_exists: it is already exist", status.ToString()); -} - -// test case for status in boundary cases. -TEST(StatusTest, UNAVAILABLE_Status) { - Status status(error::UNAVAILABLE, "unavailable"); - EXPECT_EQ("Errors::unavailable: unavailable", status.ToString()); -} - -TEST(StatusTest, NoNameCode) { - Status status(static_cast(101), "Unknown error"); - EXPECT_EQ("Errors::101: Unknown error", status.ToString()); -} - -TEST(StatusTest, EQUAL_OPERATOR) { - Status status1(error::ALREADY_EXISTS, "already exists 1"); - Status status2(error::ALREADY_EXISTS, "already exists 1"); - EXPECT_EQ(status1, status2); -} - -TEST(StatusTest, NOT_EQUAL_OPERATOR) { - Status status1(error::ALREADY_EXISTS, "already exists"); - Status status2(error::UNAVAILABLE, "unavailable"); - EXPECT_NE(status1, status2); -} - -TEST(StatusTest, NOT_EQUAL_OPERATOR_NONE_MSG) { - Status status1(error::ALREADY_EXISTS); - Status status2(error::UNAVAILABLE); - EXPECT_NE(status1, status2); -} - - -} // namespace widevine diff --git a/common/test_drm_certificates.cc b/common/test_drm_certificates.cc deleted file mode 100644 index 3dabb44..0000000 --- a/common/test_drm_certificates.cc +++ /dev/null @@ -1,720 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// - -#include "common/test_drm_certificates.h" - -namespace widevine { - -static const unsigned char kTestRootCertificate[] = { - 0x0a, 0x9b, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xb9, 0x60, 0x22, - 0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5, - 0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78, - 0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f, - 0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca, - 0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b, - 0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46, - 0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01, - 0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c, - 0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14, - 0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd, - 0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6, - 0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde, - 0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31, - 0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a, - 0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90, - 0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49, - 0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f, - 0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda, - 0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17, - 0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30, - 0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf, - 0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16, - 0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42, - 0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9, - 0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4, - 0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a, - 0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72, - 0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde, - 0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04, - 0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b, - 0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33, - 0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67, - 0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02, - 0x03, 0x01, 0x00, 0x01, 0x48, 0x01, 0x12, 0x80, 0x03, 0x45, 0x3d, 0x03, - 0x60, 0xd1, 0x13, 0x9e, 0xcd, 0x69, 0x5f, 0xd5, 0xa7, 0x62, 0x12, 0x28, - 0x49, 0x4a, 0x73, 0x05, 0x1b, 0xf3, 0xd4, 0x4e, 0x54, 0x3f, 0x5f, 0x43, - 0x2c, 0x17, 0x56, 0xbf, 0xc3, 0xb9, 0xe1, 0xb8, 0xb7, 0xc7, 0xd6, 0x52, - 0x8e, 0xfb, 0x1c, 0x24, 0x9b, 0x84, 0x13, 0x08, 0xec, 0x0b, 0xd9, 0xfa, - 0xe3, 0x9d, 0x37, 0x55, 0x72, 0x69, 0xfc, 0x39, 0x50, 0xbb, 0x49, 0x86, - 0xe2, 0x85, 0x01, 0x20, 0x3e, 0x08, 0x2c, 0xdc, 0xee, 0x36, 0x04, 0xff, - 0x24, 0x50, 0x88, 0x17, 0xfb, 0x8e, 0x86, 0xf6, 0xc5, 0xd6, 0xc5, 0x5b, - 0x32, 0xe1, 0x3f, 0xff, 0x9c, 0x23, 0xd8, 0x84, 0x61, 0x26, 0x1d, 0x46, - 0x82, 0x99, 0x3f, 0x1a, 0x5a, 0xc7, 0xd5, 0x97, 0x6d, 0xdb, 0x3a, 0x80, - 0xef, 0x80, 0x2d, 0x11, 0x06, 0xf2, 0x14, 0x2b, 0x40, 0x61, 0x6f, 0x91, - 0xea, 0x8a, 0xc5, 0xde, 0xad, 0x68, 0x31, 0xda, 0x11, 0x82, 0x11, 0x2b, - 0x19, 0x3c, 0x89, 0xbc, 0x4a, 0xed, 0x87, 0x44, 0x1b, 0x79, 0xa9, 0x22, - 0xb7, 0x81, 0xb3, 0xa9, 0xa2, 0x9b, 0x77, 0xf9, 0x40, 0x31, 0x4a, 0x9a, - 0x5a, 0x9d, 0x56, 0xf9, 0x81, 0x2f, 0x9b, 0xe1, 0xd1, 0xca, 0xe7, 0xc5, - 0xdc, 0x43, 0x92, 0x96, 0x5a, 0x22, 0x07, 0xcd, 0x0e, 0xec, 0x70, 0xe8, - 0xd7, 0xdb, 0x52, 0xbe, 0x23, 0x23, 0x4c, 0xb8, 0x9e, 0x0a, 0x94, 0x64, - 0xa7, 0xc8, 0xd8, 0x30, 0x78, 0xb9, 0x31, 0x8f, 0x5f, 0x98, 0x71, 0x24, - 0xbd, 0xc2, 0xdc, 0x52, 0xf5, 0x0a, 0xf7, 0x0d, 0x48, 0x58, 0x6b, 0xdd, - 0xa9, 0x95, 0xc6, 0x03, 0x13, 0x39, 0x87, 0xf8, 0x7a, 0x0e, 0x32, 0xd5, - 0x77, 0x46, 0x59, 0x12, 0xae, 0x52, 0xd1, 0x48, 0xdf, 0x4c, 0xdd, 0xbf, - 0xd7, 0xcc, 0x38, 0x1e, 0x07, 0x35, 0x3f, 0x1b, 0xe5, 0xa4, 0x2a, 0x01, - 0x77, 0x22, 0xe6, 0x02, 0x90, 0x4d, 0x8b, 0x02, 0x75, 0x07, 0x36, 0xb0, - 0xfa, 0x82, 0xf6, 0x7e, 0x74, 0xde, 0xba, 0xfa, 0x0e, 0x5a, 0x9a, 0x70, - 0x50, 0xf4, 0x42, 0x05, 0xb1, 0xca, 0xc7, 0x18, 0xb7, 0x76, 0xff, 0x04, - 0x8e, 0x2e, 0xe3, 0x44, 0x41, 0x38, 0x16, 0xa4, 0x34, 0x84, 0x66, 0x72, - 0x0f, 0xc8, 0x2f, 0x9c, 0xe1, 0x5f, 0xe6, 0x35, 0x79, 0x64, 0x67, 0xa0, - 0x53, 0x89, 0x4c, 0x51, 0xc8, 0x34, 0x6e, 0x70, 0xba, 0xfe, 0xdd, 0xca, - 0xc2, 0xc6, 0x91, 0x8b, 0x08, 0x5e, 0x25, 0x96, 0xd0, 0x0d, 0xe7, 0xee, - 0x25, 0x92, 0x39, 0xa3, 0xba, 0xa4, 0x0b, 0xab, 0xa4, 0x2e, 0x16, 0xfc, - 0xad, 0xed, 0xcf, 0x12, 0xda, 0x9b, 0xe9, 0x67, 0x4d, 0xb2, 0x4e, 0xe9, - 0xb3, 0xe8, 0x53, 0xc8, 0x5a, 0xc7, 0xbd, 0x69, 0xa7, 0x12, 0x4e, 0x43, - 0x20, 0x62, 0x34, 0xb0, 0xbd, 0xb2, 0xea, 0x95, 0xf6, -}; - -const unsigned char kTestIntermediateCertificate[] = { - 0x0a, 0xb1, 0x02, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18, - 0xb2, 0x92, 0x04, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, - 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, - 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, - 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, - 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, - 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, - 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, - 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, - 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, - 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, - 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, - 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, - 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, - 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, - 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, - 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, - 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, - 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, - 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, - 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, - 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, - 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, - 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, - 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, 0x01, 0x12, 0x80, 0x03, 0x06, - 0xe2, 0xc2, 0x94, 0x0e, 0x81, 0x87, 0x59, 0xe3, 0xe8, 0x15, 0x7f, 0xc6, - 0xff, 0x6b, 0xc8, 0x7e, 0x0c, 0xd9, 0x9b, 0x40, 0x34, 0x22, 0x44, 0x00, - 0xdf, 0x0e, 0x9e, 0xcd, 0xb9, 0x1d, 0x3d, 0xfe, 0x5a, 0xb9, 0x28, 0xdc, - 0x94, 0x43, 0xc4, 0x1c, 0x66, 0xa9, 0x8a, 0xa4, 0x61, 0xdf, 0x8a, 0xf3, - 0x7c, 0xf0, 0xbe, 0x66, 0xe9, 0xdf, 0x65, 0x93, 0x6c, 0xc7, 0xb5, 0x1a, - 0x76, 0x07, 0x40, 0xde, 0xa1, 0xc5, 0x40, 0xde, 0xac, 0x5b, 0x9f, 0x32, - 0xbb, 0xd4, 0xf2, 0x09, 0x13, 0x20, 0xbe, 0xee, 0xf4, 0xb5, 0xb0, 0xec, - 0xeb, 0x1e, 0xfa, 0x03, 0x1b, 0x9d, 0x5a, 0xa0, 0x2f, 0x71, 0x1a, 0x76, - 0xe7, 0x6f, 0x71, 0x7d, 0x3a, 0x7d, 0x8c, 0x46, 0xaf, 0x93, 0x94, 0x47, - 0x27, 0xec, 0x1b, 0x1e, 0xd7, 0x8c, 0x7c, 0xec, 0x42, 0xaf, 0x55, 0x82, - 0x3b, 0x6d, 0x07, 0x24, 0xb3, 0xfa, 0x2d, 0x1e, 0x12, 0x02, 0x94, 0x04, - 0x23, 0xeb, 0xf3, 0x74, 0x04, 0x7e, 0x2a, 0x7f, 0x00, 0x34, 0x2b, 0x5c, - 0x5b, 0x10, 0xe7, 0x36, 0x52, 0xde, 0x9f, 0x56, 0x10, 0xe3, 0x0b, 0xa5, - 0x29, 0x85, 0xa5, 0x95, 0xed, 0xf5, 0x39, 0x0a, 0x03, 0x51, 0x29, 0x64, - 0xa1, 0x4f, 0x38, 0xde, 0x3b, 0x4d, 0x0a, 0xf3, 0x7e, 0x37, 0x14, 0xce, - 0xdf, 0x9d, 0x86, 0x16, 0xad, 0x62, 0xa8, 0xf8, 0xa7, 0xc2, 0xa4, 0xc1, - 0xe2, 0xd6, 0x40, 0xa4, 0x7b, 0x20, 0x1b, 0x6d, 0x7c, 0x97, 0x0b, 0x73, - 0x85, 0xbf, 0xdb, 0xc3, 0xa1, 0xf5, 0xd4, 0xb7, 0x95, 0xf2, 0xe7, 0x10, - 0x77, 0xc6, 0x82, 0xb2, 0x68, 0x24, 0x31, 0xdc, 0x69, 0x43, 0x56, 0xf5, - 0x76, 0x20, 0x0a, 0x82, 0x1a, 0x98, 0xb3, 0x02, 0x0f, 0x67, 0xcd, 0x4f, - 0xab, 0x43, 0x44, 0xbd, 0xdb, 0x07, 0xd3, 0xff, 0x8b, 0x68, 0x33, 0x24, - 0x35, 0xe5, 0xc6, 0x1a, 0x94, 0x14, 0x4f, 0x40, 0xef, 0x92, 0xfb, 0xfd, - 0x72, 0x15, 0xd4, 0x10, 0x60, 0x22, 0x3e, 0x60, 0x49, 0x3d, 0x58, 0xc6, - 0x3d, 0x28, 0x70, 0x55, 0x32, 0xd5, 0x78, 0x03, 0x51, 0xff, 0xd6, 0x4f, - 0x4e, 0x89, 0x0e, 0x50, 0x85, 0x6e, 0x1c, 0x6a, 0x5f, 0x11, 0xd0, 0xf5, - 0xee, 0xe5, 0x1c, 0xa8, 0xb2, 0xdb, 0x26, 0x93, 0xb1, 0xe2, 0xc1, 0x05, - 0xe0, 0x7f, 0x16, 0xe7, 0x9c, 0xcf, 0xe7, 0xb7, 0x7e, 0xaa, 0x96, 0x21, - 0x64, 0x39, 0x6d, 0x7a, 0xdc, 0x70, 0x6e, 0xc8, 0xf5, 0x44, 0x2e, 0x9f, - 0xc1, 0xe9, 0x46, 0x8c, 0x1b, 0x58, 0xec, 0x73, 0x1b, 0x9a, 0x04, 0xcb, - 0x68, 0x58, 0x21, 0x0e, 0xd6, 0xd7, 0x7a, 0x2b, 0x60, 0x02, 0x20, 0x7b, - 0x85, 0xe5, 0x84, 0x2c, 0x5f, 0x24, 0x90, 0x2d, 0xc5, 0x19, 0xea, 0xf3, - 0x91, 0x78, 0xc2, 0xa7, 0x36, 0x5a, 0x72, 0x64, 0x45, 0x13, 0x49, -}; - -const unsigned char kTestIntermediateCertificateWithECKey[] = { - 0x0a, 0x9a, 0x01, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18, - 0xb2, 0x92, 0x04, 0x22, 0x78, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, - 0x22, 0x03, 0x62, 0x00, 0x04, 0xb0, 0x50, 0x2a, 0x13, 0x20, 0x3e, 0x66, - 0x67, 0xdf, 0x11, 0x2a, 0xbc, 0x0f, 0x76, 0x69, 0x4b, 0xa1, 0x88, 0xec, - 0xb8, 0x71, 0xcf, 0xc9, 0xbb, 0xd2, 0xbc, 0xf8, 0x53, 0xfd, 0x8b, 0x8d, - 0x14, 0x6f, 0xda, 0xea, 0x60, 0x51, 0xc8, 0xd3, 0x3a, 0xd4, 0x75, 0x81, - 0x05, 0x16, 0x03, 0x0b, 0xcb, 0x33, 0x2c, 0x8b, 0xe6, 0xd3, 0x57, 0x6c, - 0xfb, 0x81, 0x4b, 0xfe, 0x79, 0x56, 0xf7, 0x6a, 0x2b, 0xca, 0xa7, 0x04, - 0xe9, 0x37, 0xd6, 0x49, 0xe5, 0x8b, 0x2c, 0xe9, 0x8e, 0xcd, 0xe7, 0xe3, - 0xc9, 0xf5, 0x4c, 0x90, 0x82, 0x5f, 0xf0, 0x53, 0xd2, 0xa4, 0x1a, 0xb3, - 0x53, 0x3d, 0xa7, 0xa7, 0xfd, 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, - 0x03, 0x12, 0x80, 0x03, 0x42, 0x90, 0xc4, 0x87, 0x0b, 0x55, 0x78, 0xb5, - 0x25, 0x64, 0x23, 0xf2, 0x6a, 0x28, 0x7b, 0x1e, 0x12, 0xeb, 0x94, 0x08, - 0x4f, 0xce, 0x6b, 0x53, 0x35, 0xda, 0xa6, 0xf3, 0x90, 0x3b, 0x1b, 0xa8, - 0x2f, 0x17, 0x8e, 0x09, 0x12, 0x4b, 0xc6, 0x10, 0xfc, 0x8a, 0x63, 0xda, - 0xf6, 0x7e, 0x18, 0x3e, 0x49, 0x4c, 0x85, 0x5b, 0x2c, 0xcb, 0x09, 0x67, - 0x3b, 0xd3, 0xf3, 0x90, 0xe7, 0x4e, 0x06, 0x2f, 0x25, 0xbe, 0x22, 0x7f, - 0xd6, 0x5c, 0xd5, 0xda, 0xac, 0x60, 0x29, 0x83, 0x53, 0x54, 0x73, 0x0d, - 0x96, 0xca, 0x50, 0x6e, 0x45, 0xd6, 0x3c, 0xe6, 0xab, 0xf7, 0xe8, 0x69, - 0x9e, 0xe2, 0x8e, 0xfd, 0x46, 0x11, 0x40, 0x9d, 0xfc, 0xd8, 0x2d, 0xe0, - 0x94, 0xbc, 0x05, 0x74, 0x3c, 0x0a, 0xdd, 0x64, 0x37, 0x93, 0x9d, 0x5a, - 0x08, 0xfe, 0x5f, 0xae, 0xa3, 0xc6, 0x48, 0xbd, 0x8a, 0x4e, 0x3c, 0xac, - 0x7c, 0x66, 0xad, 0xc4, 0x7b, 0x7b, 0x89, 0xd9, 0xae, 0xf5, 0x8d, 0xf3, - 0x0e, 0x3b, 0x1c, 0xb6, 0xf0, 0xff, 0x52, 0x22, 0xbc, 0xdd, 0x1e, 0xe5, - 0x90, 0xe1, 0x09, 0xe2, 0x65, 0x42, 0x70, 0x4b, 0xfa, 0xf0, 0x41, 0x41, - 0x53, 0xa2, 0x2c, 0x32, 0xc4, 0x1a, 0x42, 0x0d, 0xbe, 0x8d, 0x5b, 0x14, - 0xae, 0x8f, 0xca, 0x85, 0xda, 0xfb, 0xe1, 0x25, 0x71, 0xc6, 0x8a, 0x3c, - 0xe1, 0x99, 0x09, 0x30, 0x9d, 0xa7, 0xec, 0x10, 0x7b, 0x43, 0xee, 0xf8, - 0xa5, 0x58, 0x9d, 0xd7, 0x31, 0x6a, 0x22, 0x45, 0xf5, 0x0c, 0x30, 0xb2, - 0x77, 0x05, 0x13, 0x10, 0xfd, 0xc1, 0xf9, 0x13, 0xc2, 0x88, 0xc8, 0x71, - 0xd9, 0x14, 0x5f, 0xc9, 0xde, 0x96, 0xe7, 0x55, 0xb9, 0x4a, 0xb0, 0x18, - 0x22, 0x17, 0x9f, 0x95, 0xe2, 0xa7, 0x66, 0x9b, 0xfd, 0x38, 0xf9, 0x5c, - 0xa0, 0xaa, 0xf4, 0x60, 0xee, 0x00, 0x53, 0x87, 0x29, 0x63, 0x53, 0x55, - 0xfb, 0x32, 0x7a, 0x80, 0x56, 0xea, 0xaa, 0x95, 0x22, 0x08, 0x9e, 0x25, - 0x53, 0x50, 0xb4, 0xd0, 0x07, 0x3c, 0x29, 0x3f, 0x03, 0xab, 0x68, 0xf5, - 0xa5, 0xc6, 0xd2, 0x73, 0xf6, 0xee, 0xa2, 0x6c, 0xec, 0xd4, 0xf3, 0x20, - 0xdc, 0x56, 0x00, 0x3d, 0xea, 0x57, 0x14, 0xc7, 0x90, 0x86, 0x82, 0x1b, - 0x14, 0x57, 0x68, 0xec, 0x24, 0x0e, 0x8d, 0x6b, 0xcc, 0x5f, 0x7a, 0x53, - 0xac, 0x60, 0x20, 0x5f, 0xe7, 0x79, 0xb6, 0x2c, 0xfb, 0x23, 0xa3, 0x43, - 0x91, 0x0f, 0x53, 0x38, 0x0e, 0xcc, 0x27, 0xaf, 0x57, 0x01, 0x26, 0xd8, - 0x01, 0x41, 0x27, 0x63, 0xca, 0x9f, 0xf5, 0xa7, 0x43, 0x26, 0x74, 0x59, - 0xec, 0xce, 0x71, 0x09, 0x0d, 0xda, 0x5d, 0x63, 0xef, 0xfd, 0x6e, 0x92, - 0x53, 0x12, 0xbc, 0x6a, 0x5b, 0x4d, 0x4a, 0x43, 0x04, 0x5d, 0x8e, 0x93, - 0xd7, 0x89, 0x21, 0xff, -}; - -const unsigned char kTestUserDrmCertificate[] = { - 0x0a, 0xc3, 0x02, 0x08, 0x02, 0x12, 0x10, 0x46, 0x45, 0x44, 0x43, 0x42, - 0x41, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x18, - 0x91, 0xab, 0x4b, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, - 0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, - 0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, - 0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, - 0x61, 0x36, 0x44, 0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, - 0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, - 0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, - 0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, - 0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, - 0x95, 0x47, 0x94, 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, - 0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, - 0xee, 0x03, 0x68, 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, - 0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, - 0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, - 0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, - 0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, - 0x24, 0x05, 0x06, 0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, - 0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, - 0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, - 0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, - 0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, - 0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, - 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, - 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, - 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, - 0x48, 0x01, 0x12, 0x80, 0x02, 0x23, 0x61, 0xfb, 0xd0, 0xf4, 0xcf, 0xf2, - 0x58, 0xd7, 0xb0, 0x79, 0x4e, 0x4e, 0xf3, 0x2c, 0x83, 0x63, 0x34, 0x6c, - 0x49, 0x80, 0xdd, 0x85, 0xf4, 0xa5, 0x23, 0x89, 0x95, 0x0c, 0x8f, 0xf6, - 0xc6, 0xdc, 0x90, 0x8b, 0x83, 0xd3, 0x0b, 0x1c, 0x34, 0xd2, 0xa0, 0x08, - 0xdc, 0x05, 0x76, 0x8f, 0xff, 0xa3, 0x2e, 0xf8, 0x93, 0x9e, 0xe6, 0xf3, - 0x62, 0x0f, 0x70, 0x1c, 0x31, 0x15, 0xbb, 0x98, 0xf4, 0xa6, 0x22, 0x2c, - 0x90, 0x59, 0xc2, 0x16, 0x48, 0xe0, 0x5a, 0xb8, 0x94, 0x6f, 0xde, 0x80, - 0xaf, 0x83, 0x8e, 0x77, 0x6a, 0xa4, 0xf4, 0x9b, 0xf8, 0x76, 0xd1, 0x1b, - 0x6d, 0x87, 0x85, 0x35, 0xd9, 0xd0, 0x62, 0x55, 0xfe, 0x11, 0xed, 0x4a, - 0x6c, 0xc9, 0x14, 0x67, 0x72, 0xb6, 0x46, 0x56, 0xbc, 0x81, 0xac, 0xe6, - 0xf0, 0x7a, 0x0e, 0x57, 0x95, 0x4d, 0x53, 0xf5, 0x33, 0x2e, 0xa5, 0x7e, - 0x71, 0x8e, 0x04, 0x64, 0x50, 0x88, 0x6b, 0xb9, 0x6e, 0xbc, 0x6b, 0x74, - 0xfc, 0x69, 0xa3, 0x81, 0x30, 0x1f, 0xac, 0x9d, 0x7b, 0xa0, 0xf5, 0x7f, - 0x42, 0xfd, 0x14, 0xca, 0x89, 0x5b, 0xb0, 0xcd, 0xa2, 0x4b, 0xef, 0xcf, - 0x84, 0x8f, 0xe8, 0xe4, 0xf7, 0xd2, 0x63, 0xe2, 0x95, 0x94, 0x45, 0xd5, - 0xc2, 0xe3, 0x99, 0xfc, 0x34, 0xcb, 0x6a, 0x15, 0x74, 0x6e, 0x16, 0xe3, - 0x6f, 0x8e, 0xe7, 0x9b, 0x01, 0xed, 0x7f, 0xf8, 0x90, 0xc6, 0x87, 0xf4, - 0x9e, 0x45, 0x64, 0x09, 0xf9, 0xaa, 0x46, 0xe4, 0x83, 0x3b, 0x4f, 0x36, - 0xdb, 0x32, 0x72, 0x00, 0xcf, 0x3c, 0x4c, 0x41, 0x67, 0x59, 0xf2, 0x93, - 0xff, 0x4e, 0x07, 0x22, 0x6e, 0x5a, 0x03, 0xf5, 0xe1, 0x48, 0x72, 0x9d, - 0x2f, 0xfc, 0xcd, 0x38, 0x5f, 0x2d, 0x69, 0x47, 0xd3, 0xa8, 0x09, 0x8e, - 0xd5, 0x9b, 0x24, 0x45, 0x43, 0x08, 0xca, 0xc6, 0xed, 0x1a, 0xb7, 0x05, - 0x0a, 0xb1, 0x02, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18, - 0xb2, 0x92, 0x04, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, - 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, - 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, - 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, - 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, - 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, - 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, - 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, - 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, - 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, - 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, - 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, - 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, - 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, - 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, - 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, - 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, - 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, - 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, - 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, - 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, - 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, - 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, - 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, 0x01, 0x12, 0x80, 0x03, 0x06, - 0xe2, 0xc2, 0x94, 0x0e, 0x81, 0x87, 0x59, 0xe3, 0xe8, 0x15, 0x7f, 0xc6, - 0xff, 0x6b, 0xc8, 0x7e, 0x0c, 0xd9, 0x9b, 0x40, 0x34, 0x22, 0x44, 0x00, - 0xdf, 0x0e, 0x9e, 0xcd, 0xb9, 0x1d, 0x3d, 0xfe, 0x5a, 0xb9, 0x28, 0xdc, - 0x94, 0x43, 0xc4, 0x1c, 0x66, 0xa9, 0x8a, 0xa4, 0x61, 0xdf, 0x8a, 0xf3, - 0x7c, 0xf0, 0xbe, 0x66, 0xe9, 0xdf, 0x65, 0x93, 0x6c, 0xc7, 0xb5, 0x1a, - 0x76, 0x07, 0x40, 0xde, 0xa1, 0xc5, 0x40, 0xde, 0xac, 0x5b, 0x9f, 0x32, - 0xbb, 0xd4, 0xf2, 0x09, 0x13, 0x20, 0xbe, 0xee, 0xf4, 0xb5, 0xb0, 0xec, - 0xeb, 0x1e, 0xfa, 0x03, 0x1b, 0x9d, 0x5a, 0xa0, 0x2f, 0x71, 0x1a, 0x76, - 0xe7, 0x6f, 0x71, 0x7d, 0x3a, 0x7d, 0x8c, 0x46, 0xaf, 0x93, 0x94, 0x47, - 0x27, 0xec, 0x1b, 0x1e, 0xd7, 0x8c, 0x7c, 0xec, 0x42, 0xaf, 0x55, 0x82, - 0x3b, 0x6d, 0x07, 0x24, 0xb3, 0xfa, 0x2d, 0x1e, 0x12, 0x02, 0x94, 0x04, - 0x23, 0xeb, 0xf3, 0x74, 0x04, 0x7e, 0x2a, 0x7f, 0x00, 0x34, 0x2b, 0x5c, - 0x5b, 0x10, 0xe7, 0x36, 0x52, 0xde, 0x9f, 0x56, 0x10, 0xe3, 0x0b, 0xa5, - 0x29, 0x85, 0xa5, 0x95, 0xed, 0xf5, 0x39, 0x0a, 0x03, 0x51, 0x29, 0x64, - 0xa1, 0x4f, 0x38, 0xde, 0x3b, 0x4d, 0x0a, 0xf3, 0x7e, 0x37, 0x14, 0xce, - 0xdf, 0x9d, 0x86, 0x16, 0xad, 0x62, 0xa8, 0xf8, 0xa7, 0xc2, 0xa4, 0xc1, - 0xe2, 0xd6, 0x40, 0xa4, 0x7b, 0x20, 0x1b, 0x6d, 0x7c, 0x97, 0x0b, 0x73, - 0x85, 0xbf, 0xdb, 0xc3, 0xa1, 0xf5, 0xd4, 0xb7, 0x95, 0xf2, 0xe7, 0x10, - 0x77, 0xc6, 0x82, 0xb2, 0x68, 0x24, 0x31, 0xdc, 0x69, 0x43, 0x56, 0xf5, - 0x76, 0x20, 0x0a, 0x82, 0x1a, 0x98, 0xb3, 0x02, 0x0f, 0x67, 0xcd, 0x4f, - 0xab, 0x43, 0x44, 0xbd, 0xdb, 0x07, 0xd3, 0xff, 0x8b, 0x68, 0x33, 0x24, - 0x35, 0xe5, 0xc6, 0x1a, 0x94, 0x14, 0x4f, 0x40, 0xef, 0x92, 0xfb, 0xfd, - 0x72, 0x15, 0xd4, 0x10, 0x60, 0x22, 0x3e, 0x60, 0x49, 0x3d, 0x58, 0xc6, - 0x3d, 0x28, 0x70, 0x55, 0x32, 0xd5, 0x78, 0x03, 0x51, 0xff, 0xd6, 0x4f, - 0x4e, 0x89, 0x0e, 0x50, 0x85, 0x6e, 0x1c, 0x6a, 0x5f, 0x11, 0xd0, 0xf5, - 0xee, 0xe5, 0x1c, 0xa8, 0xb2, 0xdb, 0x26, 0x93, 0xb1, 0xe2, 0xc1, 0x05, - 0xe0, 0x7f, 0x16, 0xe7, 0x9c, 0xcf, 0xe7, 0xb7, 0x7e, 0xaa, 0x96, 0x21, - 0x64, 0x39, 0x6d, 0x7a, 0xdc, 0x70, 0x6e, 0xc8, 0xf5, 0x44, 0x2e, 0x9f, - 0xc1, 0xe9, 0x46, 0x8c, 0x1b, 0x58, 0xec, 0x73, 0x1b, 0x9a, 0x04, 0xcb, - 0x68, 0x58, 0x21, 0x0e, 0xd6, 0xd7, 0x7a, 0x2b, 0x60, 0x02, 0x20, 0x7b, - 0x85, 0xe5, 0x84, 0x2c, 0x5f, 0x24, 0x90, 0x2d, 0xc5, 0x19, 0xea, 0xf3, - 0x91, 0x78, 0xc2, 0xa7, 0x36, 0x5a, 0x72, 0x64, 0x45, 0x13, 0x49, -}; - -const unsigned char kTestUserDrmCertificateWithECKey[] = { - 0x0a, 0x8f, 0x01, 0x08, 0x02, 0x12, 0x10, 0x46, 0x45, 0x44, 0x43, 0x42, - 0x41, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x18, - 0x91, 0xab, 0x4b, 0x22, 0x5b, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, - 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x8a, 0xea, 0x3f, 0x16, - 0xff, 0x24, 0xa9, 0xbf, 0x03, 0x28, 0x30, 0x15, 0xee, 0x52, 0x50, 0x9a, - 0x55, 0x1c, 0x60, 0xc7, 0xa7, 0xcc, 0x4b, 0x99, 0x5b, 0x40, 0x55, 0xce, - 0x46, 0x19, 0xd4, 0xd4, 0x5e, 0xfd, 0xe0, 0x68, 0x27, 0xea, 0x78, 0xf3, - 0x07, 0x1f, 0x02, 0x4a, 0x78, 0x52, 0x44, 0xd3, 0xdf, 0xbe, 0xac, 0x5f, - 0xa5, 0x1c, 0x8a, 0x49, 0x8d, 0xa6, 0x5a, 0xac, 0xa1, 0x25, 0x2b, 0xd1, - 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, - 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, - 0x48, 0x02, 0x12, 0x66, 0x30, 0x64, 0x02, 0x30, 0x4c, 0x7a, 0x79, 0x4a, - 0x18, 0xf2, 0x2f, 0x9f, 0x29, 0x3b, 0x6f, 0x8f, 0x8f, 0xe4, 0xe0, 0xf2, - 0xd9, 0x38, 0x18, 0x8a, 0x9a, 0x88, 0x85, 0x95, 0x72, 0xb7, 0x3c, 0xb6, - 0x47, 0xa4, 0x6b, 0x0a, 0x56, 0x4a, 0x38, 0x1d, 0x2f, 0x4a, 0xc6, 0x61, - 0x97, 0x35, 0x81, 0x87, 0x4b, 0xca, 0xdc, 0x20, 0x02, 0x30, 0x28, 0x4e, - 0xf1, 0x23, 0x6d, 0x3f, 0x4f, 0x29, 0x29, 0x86, 0x75, 0x46, 0x83, 0x03, - 0xa0, 0xe7, 0x23, 0x07, 0x2b, 0x28, 0x4d, 0xa9, 0x72, 0xb6, 0x5e, 0x3b, - 0xd2, 0x90, 0x05, 0xd3, 0x33, 0x35, 0x99, 0xdc, 0xe9, 0x54, 0xa0, 0x6e, - 0xca, 0x38, 0x63, 0x4d, 0x95, 0xab, 0x99, 0x77, 0x87, 0x38, 0x1a, 0xa0, - 0x04, 0x0a, 0x9a, 0x01, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, - 0x18, 0xb2, 0x92, 0x04, 0x22, 0x78, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, - 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, - 0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xb0, 0x50, 0x2a, 0x13, 0x20, 0x3e, - 0x66, 0x67, 0xdf, 0x11, 0x2a, 0xbc, 0x0f, 0x76, 0x69, 0x4b, 0xa1, 0x88, - 0xec, 0xb8, 0x71, 0xcf, 0xc9, 0xbb, 0xd2, 0xbc, 0xf8, 0x53, 0xfd, 0x8b, - 0x8d, 0x14, 0x6f, 0xda, 0xea, 0x60, 0x51, 0xc8, 0xd3, 0x3a, 0xd4, 0x75, - 0x81, 0x05, 0x16, 0x03, 0x0b, 0xcb, 0x33, 0x2c, 0x8b, 0xe6, 0xd3, 0x57, - 0x6c, 0xfb, 0x81, 0x4b, 0xfe, 0x79, 0x56, 0xf7, 0x6a, 0x2b, 0xca, 0xa7, - 0x04, 0xe9, 0x37, 0xd6, 0x49, 0xe5, 0x8b, 0x2c, 0xe9, 0x8e, 0xcd, 0xe7, - 0xe3, 0xc9, 0xf5, 0x4c, 0x90, 0x82, 0x5f, 0xf0, 0x53, 0xd2, 0xa4, 0x1a, - 0xb3, 0x53, 0x3d, 0xa7, 0xa7, 0xfd, 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, - 0x48, 0x03, 0x12, 0x80, 0x03, 0x42, 0x90, 0xc4, 0x87, 0x0b, 0x55, 0x78, - 0xb5, 0x25, 0x64, 0x23, 0xf2, 0x6a, 0x28, 0x7b, 0x1e, 0x12, 0xeb, 0x94, - 0x08, 0x4f, 0xce, 0x6b, 0x53, 0x35, 0xda, 0xa6, 0xf3, 0x90, 0x3b, 0x1b, - 0xa8, 0x2f, 0x17, 0x8e, 0x09, 0x12, 0x4b, 0xc6, 0x10, 0xfc, 0x8a, 0x63, - 0xda, 0xf6, 0x7e, 0x18, 0x3e, 0x49, 0x4c, 0x85, 0x5b, 0x2c, 0xcb, 0x09, - 0x67, 0x3b, 0xd3, 0xf3, 0x90, 0xe7, 0x4e, 0x06, 0x2f, 0x25, 0xbe, 0x22, - 0x7f, 0xd6, 0x5c, 0xd5, 0xda, 0xac, 0x60, 0x29, 0x83, 0x53, 0x54, 0x73, - 0x0d, 0x96, 0xca, 0x50, 0x6e, 0x45, 0xd6, 0x3c, 0xe6, 0xab, 0xf7, 0xe8, - 0x69, 0x9e, 0xe2, 0x8e, 0xfd, 0x46, 0x11, 0x40, 0x9d, 0xfc, 0xd8, 0x2d, - 0xe0, 0x94, 0xbc, 0x05, 0x74, 0x3c, 0x0a, 0xdd, 0x64, 0x37, 0x93, 0x9d, - 0x5a, 0x08, 0xfe, 0x5f, 0xae, 0xa3, 0xc6, 0x48, 0xbd, 0x8a, 0x4e, 0x3c, - 0xac, 0x7c, 0x66, 0xad, 0xc4, 0x7b, 0x7b, 0x89, 0xd9, 0xae, 0xf5, 0x8d, - 0xf3, 0x0e, 0x3b, 0x1c, 0xb6, 0xf0, 0xff, 0x52, 0x22, 0xbc, 0xdd, 0x1e, - 0xe5, 0x90, 0xe1, 0x09, 0xe2, 0x65, 0x42, 0x70, 0x4b, 0xfa, 0xf0, 0x41, - 0x41, 0x53, 0xa2, 0x2c, 0x32, 0xc4, 0x1a, 0x42, 0x0d, 0xbe, 0x8d, 0x5b, - 0x14, 0xae, 0x8f, 0xca, 0x85, 0xda, 0xfb, 0xe1, 0x25, 0x71, 0xc6, 0x8a, - 0x3c, 0xe1, 0x99, 0x09, 0x30, 0x9d, 0xa7, 0xec, 0x10, 0x7b, 0x43, 0xee, - 0xf8, 0xa5, 0x58, 0x9d, 0xd7, 0x31, 0x6a, 0x22, 0x45, 0xf5, 0x0c, 0x30, - 0xb2, 0x77, 0x05, 0x13, 0x10, 0xfd, 0xc1, 0xf9, 0x13, 0xc2, 0x88, 0xc8, - 0x71, 0xd9, 0x14, 0x5f, 0xc9, 0xde, 0x96, 0xe7, 0x55, 0xb9, 0x4a, 0xb0, - 0x18, 0x22, 0x17, 0x9f, 0x95, 0xe2, 0xa7, 0x66, 0x9b, 0xfd, 0x38, 0xf9, - 0x5c, 0xa0, 0xaa, 0xf4, 0x60, 0xee, 0x00, 0x53, 0x87, 0x29, 0x63, 0x53, - 0x55, 0xfb, 0x32, 0x7a, 0x80, 0x56, 0xea, 0xaa, 0x95, 0x22, 0x08, 0x9e, - 0x25, 0x53, 0x50, 0xb4, 0xd0, 0x07, 0x3c, 0x29, 0x3f, 0x03, 0xab, 0x68, - 0xf5, 0xa5, 0xc6, 0xd2, 0x73, 0xf6, 0xee, 0xa2, 0x6c, 0xec, 0xd4, 0xf3, - 0x20, 0xdc, 0x56, 0x00, 0x3d, 0xea, 0x57, 0x14, 0xc7, 0x90, 0x86, 0x82, - 0x1b, 0x14, 0x57, 0x68, 0xec, 0x24, 0x0e, 0x8d, 0x6b, 0xcc, 0x5f, 0x7a, - 0x53, 0xac, 0x60, 0x20, 0x5f, 0xe7, 0x79, 0xb6, 0x2c, 0xfb, 0x23, 0xa3, - 0x43, 0x91, 0x0f, 0x53, 0x38, 0x0e, 0xcc, 0x27, 0xaf, 0x57, 0x01, 0x26, - 0xd8, 0x01, 0x41, 0x27, 0x63, 0xca, 0x9f, 0xf5, 0xa7, 0x43, 0x26, 0x74, - 0x59, 0xec, 0xce, 0x71, 0x09, 0x0d, 0xda, 0x5d, 0x63, 0xef, 0xfd, 0x6e, - 0x92, 0x53, 0x12, 0xbc, 0x6a, 0x5b, 0x4d, 0x4a, 0x43, 0x04, 0x5d, 0x8e, - 0x93, 0xd7, 0x89, 0x21, 0xff, -}; - -const unsigned char kTestUserDrmCertificateWithRotId[] = { - 0x0a, 0xdf, 0x03, 0x08, 0x02, 0x12, 0x10, 0x46, 0x45, 0x44, 0x43, 0x42, - 0x41, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x18, - 0x91, 0xab, 0x4b, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, - 0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, - 0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, - 0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, - 0x61, 0x36, 0x44, 0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, - 0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, - 0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, - 0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, - 0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, - 0x95, 0x47, 0x94, 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, - 0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, - 0xee, 0x03, 0x68, 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, - 0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, - 0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, - 0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, - 0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, - 0x24, 0x05, 0x06, 0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, - 0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, - 0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, - 0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, - 0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, - 0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, - 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, - 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, - 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, - 0x48, 0x01, 0x52, 0x99, 0x01, 0x08, 0x01, 0x10, 0x00, 0x1a, 0x71, 0x04, - 0x8a, 0xea, 0x3f, 0x16, 0xff, 0x24, 0xa9, 0xbf, 0x03, 0x28, 0x30, 0x15, - 0xee, 0x52, 0x50, 0x9a, 0x55, 0x1c, 0x60, 0xc7, 0xa7, 0xcc, 0x4b, 0x99, - 0x5b, 0x40, 0x55, 0xce, 0x46, 0x19, 0xd4, 0xd4, 0x5e, 0xfd, 0xe0, 0x68, - 0x27, 0xea, 0x78, 0xf3, 0x07, 0x1f, 0x02, 0x4a, 0x78, 0x52, 0x44, 0xd3, - 0xdf, 0xbe, 0xac, 0x5f, 0xa5, 0x1c, 0x8a, 0x49, 0x8d, 0xa6, 0x5a, 0xac, - 0xa1, 0x25, 0x2b, 0xd1, 0xd9, 0xeb, 0xa7, 0x91, 0x26, 0x46, 0x3a, 0xe4, - 0x5b, 0x06, 0x6b, 0x77, 0x83, 0xa9, 0x0f, 0xa3, 0xf3, 0x2a, 0x39, 0x36, - 0xc1, 0xbd, 0x37, 0xeb, 0xd7, 0x83, 0x3e, 0xbd, 0x17, 0x53, 0x82, 0x69, - 0xc3, 0xe4, 0x48, 0xb5, 0x0d, 0x8c, 0xe1, 0x30, 0x17, 0xef, 0x01, 0x88, - 0x30, 0x62, 0x5a, 0xb3, 0x22, 0x20, 0x91, 0x69, 0x9e, 0xbc, 0xa2, 0x5c, - 0xd4, 0x51, 0x79, 0xfd, 0xbc, 0x2f, 0x92, 0xcd, 0x48, 0x2d, 0xd3, 0x30, - 0xe6, 0x1e, 0xbd, 0x4e, 0x23, 0x96, 0x2b, 0xb0, 0x3a, 0xfc, 0xb4, 0x7b, - 0x0e, 0x3d, 0x12, 0x80, 0x02, 0xa0, 0xe0, 0x2b, 0x1d, 0xe4, 0x28, 0x7b, - 0x57, 0x64, 0x3f, 0xe2, 0xf7, 0x10, 0xda, 0x97, 0x7f, 0x49, 0xf4, 0xd2, - 0x57, 0xc5, 0xf5, 0xe1, 0xd9, 0xd9, 0xbb, 0x34, 0xac, 0x90, 0x0c, 0xfa, - 0x9f, 0x0d, 0xd7, 0x14, 0xfc, 0xbb, 0xc9, 0xfa, 0xa5, 0x41, 0xd8, 0x87, - 0xa5, 0xef, 0x39, 0xf8, 0x70, 0x4f, 0x93, 0xfc, 0xb8, 0x62, 0xb8, 0x7e, - 0x6e, 0x9f, 0x25, 0xe9, 0x47, 0x08, 0xe6, 0x89, 0xe9, 0xc2, 0x41, 0x6a, - 0xc6, 0x0f, 0x84, 0x71, 0xa7, 0x90, 0xf2, 0x86, 0x7b, 0xbc, 0x99, 0xca, - 0xf1, 0xd4, 0xa5, 0xc0, 0x9f, 0x4e, 0x53, 0x27, 0xde, 0x3e, 0x4b, 0x7b, - 0x7d, 0x6a, 0xa4, 0xaa, 0x53, 0x9c, 0x4f, 0xff, 0xf6, 0x61, 0xbe, 0x4d, - 0xa7, 0x9b, 0xa6, 0xc9, 0xb1, 0x00, 0x57, 0xd6, 0x47, 0xb2, 0x0e, 0xf6, - 0x56, 0x1b, 0xc3, 0x7d, 0xe0, 0x97, 0x85, 0x93, 0xe9, 0xa4, 0x43, 0xfa, - 0x02, 0xd9, 0x40, 0x97, 0x22, 0x86, 0x15, 0xd8, 0x24, 0x92, 0x35, 0x32, - 0x15, 0xc2, 0x19, 0xbc, 0x32, 0x21, 0x3f, 0x8c, 0xdf, 0x9f, 0x5c, 0x3a, - 0x57, 0x73, 0x4f, 0x25, 0x3b, 0xa1, 0x88, 0x6f, 0xbb, 0x4a, 0xb7, 0xe5, - 0xc6, 0x33, 0x1b, 0x59, 0xa9, 0xe9, 0xc3, 0x0b, 0xdb, 0xe9, 0x41, 0xb0, - 0x06, 0x49, 0xdf, 0x0a, 0xa9, 0x85, 0xf5, 0xc7, 0xe6, 0x2c, 0x20, 0x25, - 0x50, 0x45, 0xf2, 0x86, 0x57, 0xdb, 0x3f, 0x28, 0x0b, 0xd6, 0xc4, 0xac, - 0xb0, 0x1c, 0xc3, 0xed, 0x7a, 0x8d, 0xa9, 0x83, 0x20, 0x43, 0xc7, 0x42, - 0x03, 0xca, 0x23, 0xc8, 0xf7, 0xbf, 0x2e, 0x70, 0x9a, 0xff, 0x23, 0xff, - 0x17, 0x22, 0xca, 0xe0, 0x58, 0x2f, 0xd3, 0x0d, 0xa4, 0xa2, 0x90, 0x6c, - 0xf1, 0x78, 0x7c, 0xee, 0x1a, 0xe7, 0x0c, 0xe2, 0x89, 0xf0, 0x5b, 0x9a, - 0x24, 0x4e, 0x10, 0xcf, 0x58, 0xa1, 0xdb, 0x3f, 0x1b, 0x1a, 0xb7, 0x05, - 0x0a, 0xb1, 0x02, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18, - 0xb2, 0x92, 0x04, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, - 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, - 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, - 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, - 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, - 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, - 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, - 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, - 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, - 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, - 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, - 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, - 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, - 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, - 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, - 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, - 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, - 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, - 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, - 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, - 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, - 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, - 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, - 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, 0x01, 0x12, 0x80, 0x03, 0x06, - 0xe2, 0xc2, 0x94, 0x0e, 0x81, 0x87, 0x59, 0xe3, 0xe8, 0x15, 0x7f, 0xc6, - 0xff, 0x6b, 0xc8, 0x7e, 0x0c, 0xd9, 0x9b, 0x40, 0x34, 0x22, 0x44, 0x00, - 0xdf, 0x0e, 0x9e, 0xcd, 0xb9, 0x1d, 0x3d, 0xfe, 0x5a, 0xb9, 0x28, 0xdc, - 0x94, 0x43, 0xc4, 0x1c, 0x66, 0xa9, 0x8a, 0xa4, 0x61, 0xdf, 0x8a, 0xf3, - 0x7c, 0xf0, 0xbe, 0x66, 0xe9, 0xdf, 0x65, 0x93, 0x6c, 0xc7, 0xb5, 0x1a, - 0x76, 0x07, 0x40, 0xde, 0xa1, 0xc5, 0x40, 0xde, 0xac, 0x5b, 0x9f, 0x32, - 0xbb, 0xd4, 0xf2, 0x09, 0x13, 0x20, 0xbe, 0xee, 0xf4, 0xb5, 0xb0, 0xec, - 0xeb, 0x1e, 0xfa, 0x03, 0x1b, 0x9d, 0x5a, 0xa0, 0x2f, 0x71, 0x1a, 0x76, - 0xe7, 0x6f, 0x71, 0x7d, 0x3a, 0x7d, 0x8c, 0x46, 0xaf, 0x93, 0x94, 0x47, - 0x27, 0xec, 0x1b, 0x1e, 0xd7, 0x8c, 0x7c, 0xec, 0x42, 0xaf, 0x55, 0x82, - 0x3b, 0x6d, 0x07, 0x24, 0xb3, 0xfa, 0x2d, 0x1e, 0x12, 0x02, 0x94, 0x04, - 0x23, 0xeb, 0xf3, 0x74, 0x04, 0x7e, 0x2a, 0x7f, 0x00, 0x34, 0x2b, 0x5c, - 0x5b, 0x10, 0xe7, 0x36, 0x52, 0xde, 0x9f, 0x56, 0x10, 0xe3, 0x0b, 0xa5, - 0x29, 0x85, 0xa5, 0x95, 0xed, 0xf5, 0x39, 0x0a, 0x03, 0x51, 0x29, 0x64, - 0xa1, 0x4f, 0x38, 0xde, 0x3b, 0x4d, 0x0a, 0xf3, 0x7e, 0x37, 0x14, 0xce, - 0xdf, 0x9d, 0x86, 0x16, 0xad, 0x62, 0xa8, 0xf8, 0xa7, 0xc2, 0xa4, 0xc1, - 0xe2, 0xd6, 0x40, 0xa4, 0x7b, 0x20, 0x1b, 0x6d, 0x7c, 0x97, 0x0b, 0x73, - 0x85, 0xbf, 0xdb, 0xc3, 0xa1, 0xf5, 0xd4, 0xb7, 0x95, 0xf2, 0xe7, 0x10, - 0x77, 0xc6, 0x82, 0xb2, 0x68, 0x24, 0x31, 0xdc, 0x69, 0x43, 0x56, 0xf5, - 0x76, 0x20, 0x0a, 0x82, 0x1a, 0x98, 0xb3, 0x02, 0x0f, 0x67, 0xcd, 0x4f, - 0xab, 0x43, 0x44, 0xbd, 0xdb, 0x07, 0xd3, 0xff, 0x8b, 0x68, 0x33, 0x24, - 0x35, 0xe5, 0xc6, 0x1a, 0x94, 0x14, 0x4f, 0x40, 0xef, 0x92, 0xfb, 0xfd, - 0x72, 0x15, 0xd4, 0x10, 0x60, 0x22, 0x3e, 0x60, 0x49, 0x3d, 0x58, 0xc6, - 0x3d, 0x28, 0x70, 0x55, 0x32, 0xd5, 0x78, 0x03, 0x51, 0xff, 0xd6, 0x4f, - 0x4e, 0x89, 0x0e, 0x50, 0x85, 0x6e, 0x1c, 0x6a, 0x5f, 0x11, 0xd0, 0xf5, - 0xee, 0xe5, 0x1c, 0xa8, 0xb2, 0xdb, 0x26, 0x93, 0xb1, 0xe2, 0xc1, 0x05, - 0xe0, 0x7f, 0x16, 0xe7, 0x9c, 0xcf, 0xe7, 0xb7, 0x7e, 0xaa, 0x96, 0x21, - 0x64, 0x39, 0x6d, 0x7a, 0xdc, 0x70, 0x6e, 0xc8, 0xf5, 0x44, 0x2e, 0x9f, - 0xc1, 0xe9, 0x46, 0x8c, 0x1b, 0x58, 0xec, 0x73, 0x1b, 0x9a, 0x04, 0xcb, - 0x68, 0x58, 0x21, 0x0e, 0xd6, 0xd7, 0x7a, 0x2b, 0x60, 0x02, 0x20, 0x7b, - 0x85, 0xe5, 0x84, 0x2c, 0x5f, 0x24, 0x90, 0x2d, 0xc5, 0x19, 0xea, 0xf3, - 0x91, 0x78, 0xc2, 0xa7, 0x36, 0x5a, 0x72, 0x64, 0x45, 0x13, 0x49}; - -const unsigned char kTestDrmServiceCertificateLicenseSdk[] = { - 0x0a, 0xc0, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32, - 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, - 0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, - 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, - 0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, - 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, - 0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, - 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, - 0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, - 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, - 0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, - 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, - 0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, - 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, - 0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, - 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, - 0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, - 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, - 0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, - 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, - 0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, - 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, - 0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, - 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, - 0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, - 0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x40, 0x01, 0x48, 0x01, 0x12, - 0x80, 0x03, 0x20, 0x54, 0x65, 0x70, 0x93, 0x53, 0x0a, 0x76, 0x95, 0xe5, - 0xaa, 0x48, 0x94, 0xa1, 0xb8, 0x25, 0xa6, 0xa4, 0x5a, 0x56, 0x59, 0x8d, - 0x80, 0x64, 0x7c, 0xb2, 0x1e, 0xeb, 0xda, 0xfb, 0x30, 0x26, 0x09, 0xc0, - 0x25, 0x65, 0xdb, 0xb8, 0x7d, 0x0e, 0xe0, 0x2b, 0xfb, 0xfe, 0xe6, 0x3a, - 0x5b, 0x9b, 0x1f, 0xbb, 0xa4, 0x89, 0xf5, 0x7c, 0x52, 0x6f, 0x52, 0xe3, - 0xb3, 0xc7, 0x27, 0x9d, 0xca, 0x01, 0x78, 0x08, 0x9b, 0x59, 0x37, 0x9f, - 0x27, 0x52, 0x90, 0x80, 0x22, 0xfb, 0x0d, 0xca, 0x57, 0xc2, 0xd9, 0x89, - 0xb6, 0x69, 0x45, 0x1f, 0x15, 0x23, 0xf1, 0xf8, 0x39, 0xbb, 0x45, 0xb9, - 0x39, 0xe5, 0x1e, 0x8b, 0x71, 0x82, 0x25, 0x4a, 0x32, 0xc2, 0x44, 0xee, - 0x76, 0x91, 0x61, 0xa2, 0xe2, 0x7a, 0xb4, 0x68, 0x56, 0xaf, 0x33, 0xe4, - 0x97, 0x44, 0xfe, 0x6d, 0x70, 0x85, 0x4f, 0x16, 0x1a, 0xda, 0xa4, 0x30, - 0x66, 0xf7, 0x95, 0xe9, 0x7b, 0x84, 0x42, 0xd6, 0x7c, 0x4b, 0x05, 0xca, - 0x67, 0x2f, 0xf4, 0xdc, 0x81, 0x9b, 0x7c, 0x80, 0xc4, 0x9e, 0x25, 0x98, - 0x84, 0xc4, 0x43, 0x35, 0x13, 0xf4, 0x9d, 0x57, 0x02, 0x1e, 0x67, 0x86, - 0x00, 0x6c, 0x46, 0xde, 0x91, 0x9f, 0x1f, 0x42, 0xbb, 0xa7, 0xd1, 0xb8, - 0x80, 0x2c, 0x33, 0x51, 0x87, 0x93, 0x6d, 0x75, 0x03, 0xb0, 0x42, 0xc9, - 0xe6, 0xa1, 0xc7, 0xa5, 0xd3, 0x40, 0xe7, 0x99, 0x6d, 0x07, 0x78, 0x13, - 0x8a, 0x01, 0x4d, 0x3e, 0xb4, 0x9a, 0x1b, 0x52, 0xb7, 0xac, 0x6d, 0x27, - 0xda, 0x5c, 0xa2, 0x78, 0x01, 0xe3, 0x4d, 0x5d, 0x0a, 0xd0, 0xc7, 0xb5, - 0x73, 0xcf, 0x6e, 0xdd, 0x89, 0xc6, 0xd4, 0x9c, 0xc7, 0xfa, 0x87, 0xe9, - 0x74, 0x01, 0xe9, 0xdd, 0x16, 0x0f, 0x3a, 0x8e, 0x38, 0x8d, 0x0b, 0x5a, - 0xc8, 0x01, 0xca, 0xb2, 0x7f, 0xcb, 0xe3, 0x25, 0xaa, 0x10, 0xc9, 0x4f, - 0x5a, 0x17, 0xe0, 0x31, 0x30, 0x34, 0xe8, 0xe6, 0x06, 0x27, 0xb3, 0x26, - 0xee, 0x44, 0x5d, 0x34, 0x2d, 0xc0, 0xff, 0x98, 0x1d, 0x33, 0x99, 0x96, - 0x29, 0xa9, 0xc6, 0x31, 0xc1, 0xe1, 0x2f, 0xb9, 0x3a, 0xd2, 0x80, 0x16, - 0xc2, 0x4a, 0x38, 0x58, 0x9f, 0x78, 0x7b, 0x11, 0x6c, 0x4e, 0xb0, 0x6b, - 0x3b, 0x8f, 0x77, 0x59, 0xb7, 0xca, 0x08, 0x85, 0xc5, 0xe2, 0x03, 0xa7, - 0x33, 0xe7, 0x34, 0xc5, 0x64, 0x37, 0x9b, 0x19, 0x48, 0x54, 0xa7, 0xe5, - 0x74, 0xe3, 0xa9, 0xfc, 0xe7, 0x6f, 0x9f, 0x04, 0xd4, 0xbd, 0x4a, 0x70, - 0xc9, 0x09, 0x67, 0x1a, 0xc5, 0x7b, 0xe9, 0x88, 0x71, 0xcb, 0x96, 0x46, - 0x2f, 0x5e, 0x47, 0x19, 0x48, 0xc0, 0xc6, 0xc1, 0xef, 0xb1, 0x26, 0x95, - 0x0c, 0x16, 0xed, 0x88, 0x4d, 0xaf, 0x96, 0x3f, 0xa2, 0xf8, 0xc7, 0x38, - 0x95, 0x48, -}; - -const unsigned char kTestDrmServiceCertificateAllTypes[] = { - 0x0a, 0xc4, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32, - 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, - 0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, - 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, - 0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, - 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, - 0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, - 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, - 0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, - 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, - 0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, - 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, - 0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, - 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, - 0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, - 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, - 0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, - 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, - 0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, - 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, - 0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, - 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, - 0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, - 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, - 0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, - 0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x40, 0x01, 0x40, 0x02, 0x40, - 0x03, 0x48, 0x01, 0x12, 0x80, 0x03, 0x72, 0x7c, 0xb3, 0x19, 0x62, 0x88, - 0x4d, 0xc5, 0x46, 0x11, 0xcc, 0x6b, 0x32, 0x47, 0x65, 0x7a, 0x5e, 0xe7, - 0xf7, 0x58, 0x7e, 0xbc, 0x76, 0xa6, 0x55, 0x75, 0x32, 0x19, 0xaa, 0xf6, - 0xb7, 0x02, 0x16, 0x75, 0xfd, 0x05, 0x0b, 0x1c, 0x2c, 0xc5, 0x44, 0x6c, - 0xcf, 0x96, 0x02, 0x93, 0x23, 0x60, 0x4b, 0xd4, 0x97, 0x81, 0xa4, 0xe5, - 0x5f, 0x0a, 0xe0, 0x5f, 0x53, 0x23, 0x66, 0x19, 0x70, 0xe0, 0x8c, 0x08, - 0x19, 0x88, 0xf2, 0xda, 0xd9, 0x7c, 0x69, 0x52, 0xc0, 0x8a, 0x7a, 0x62, - 0x81, 0xaa, 0x2b, 0x0e, 0xe8, 0x28, 0x21, 0xce, 0x4a, 0x63, 0x52, 0x23, - 0xab, 0xea, 0x65, 0xf9, 0x0f, 0x8a, 0xd2, 0x77, 0xa5, 0x94, 0x05, 0x77, - 0x8b, 0x35, 0x99, 0x8b, 0xa9, 0xdd, 0xe4, 0x69, 0x00, 0xbe, 0x4d, 0xd2, - 0xce, 0x6c, 0xe4, 0xf9, 0x34, 0x97, 0xaa, 0x59, 0xd8, 0xc9, 0x58, 0x11, - 0xa9, 0xb4, 0x9b, 0x0e, 0xce, 0xb7, 0x15, 0x73, 0x6b, 0xb5, 0x5f, 0x87, - 0xea, 0xf1, 0x1c, 0x8d, 0x66, 0x5a, 0x28, 0x7e, 0x9a, 0x01, 0x15, 0xfb, - 0xb1, 0x92, 0x28, 0x3b, 0x62, 0x6a, 0xcb, 0xb0, 0xe7, 0x11, 0x76, 0x44, - 0x5a, 0x97, 0x4b, 0x1a, 0x26, 0xbe, 0x3c, 0xa6, 0x33, 0xd8, 0x99, 0x7b, - 0x97, 0xb2, 0xec, 0xa3, 0x18, 0xdf, 0x6b, 0xeb, 0x9f, 0x43, 0x14, 0x0a, - 0x49, 0xdb, 0xb0, 0xe2, 0xc0, 0xe0, 0xe3, 0x73, 0x66, 0x0f, 0x14, 0x1c, - 0x48, 0x21, 0x28, 0x3a, 0x90, 0xfd, 0x32, 0x1d, 0x35, 0x9a, 0x11, 0x6c, - 0xf8, 0x39, 0xd1, 0xcb, 0x45, 0x76, 0xc0, 0x5e, 0xc5, 0xa8, 0xba, 0xd9, - 0x09, 0xfc, 0x44, 0xf2, 0x9e, 0xaf, 0x95, 0xc4, 0xe0, 0x06, 0x0e, 0xbf, - 0x99, 0x6e, 0x57, 0xfa, 0xa8, 0xcd, 0x2b, 0x4b, 0x97, 0x62, 0xf7, 0x92, - 0x14, 0x8f, 0xf4, 0x8c, 0xba, 0xb1, 0xb4, 0x8e, 0x07, 0xd2, 0x7b, 0x93, - 0xd1, 0xbf, 0x90, 0x60, 0xe0, 0xbf, 0x1a, 0x3b, 0xd2, 0xee, 0xad, 0xf8, - 0x4f, 0x5b, 0xee, 0xe5, 0xf4, 0x8e, 0x97, 0x5b, 0x24, 0xd2, 0xa6, 0x80, - 0x5c, 0x09, 0x27, 0x8e, 0x14, 0xa9, 0xcc, 0xff, 0x5a, 0xc1, 0xb4, 0x5f, - 0xb5, 0x07, 0x04, 0xd0, 0x3a, 0xef, 0xa9, 0x45, 0xa1, 0x23, 0x0f, 0xc2, - 0x13, 0x4f, 0xc8, 0xd4, 0x7f, 0xef, 0x54, 0x5c, 0xcc, 0xdb, 0xdf, 0x89, - 0x4c, 0x31, 0x8f, 0x27, 0x50, 0x2b, 0x99, 0xd8, 0xee, 0xdf, 0x8b, 0x06, - 0x93, 0xc0, 0xd0, 0x59, 0xf5, 0x66, 0xaf, 0x4b, 0x98, 0x68, 0xb6, 0x8c, - 0xd7, 0x70, 0xad, 0x69, 0x60, 0xca, 0xae, 0x64, 0xc2, 0x53, 0xcb, 0xa1, - 0x39, 0xb7, 0x08, 0x50, 0x31, 0x12, 0xc1, 0x02, 0x08, 0x58, 0x59, 0xc8, - 0x69, 0x9e, 0x43, 0xac, 0x60, 0x7d, 0x4c, 0x8b, 0x1a, 0xe8, 0xa8, 0x3d, - 0x65, 0x29, 0x83, 0x85, 0x9b, 0x8e, -}; - -const unsigned char kTestDrmServiceCertificateNoType[] = { - 0x0a, 0xbe, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32, - 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, - 0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, - 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, - 0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, - 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, - 0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, - 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, - 0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, - 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, - 0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, - 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, - 0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, - 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, - 0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, - 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, - 0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, - 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, - 0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, - 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, - 0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, - 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, - 0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, - 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, - 0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, - 0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x48, 0x01, 0x12, 0x80, 0x03, - 0x21, 0xa4, 0x86, 0x36, 0x40, 0x9d, 0x0f, 0x7d, 0x31, 0x8a, 0xbe, 0x98, - 0x85, 0x0f, 0x4a, 0xe6, 0x5e, 0x2e, 0x94, 0xc3, 0x4a, 0x69, 0x26, 0x55, - 0x76, 0xf6, 0x11, 0xfe, 0xd4, 0x1d, 0xfc, 0xb3, 0xbe, 0x94, 0x6a, 0x5c, - 0x51, 0x2d, 0xda, 0x95, 0x70, 0x6f, 0x62, 0x23, 0x69, 0xfa, 0x3d, 0xce, - 0x09, 0x0c, 0x2f, 0xc7, 0x30, 0xac, 0xf2, 0x46, 0x6a, 0x14, 0x42, 0x24, - 0x8f, 0x2a, 0xb4, 0xa7, 0x32, 0xbb, 0x8c, 0x02, 0xe2, 0x1f, 0x63, 0xfd, - 0xf4, 0x40, 0x14, 0xd9, 0x12, 0x88, 0xa6, 0x46, 0x15, 0x67, 0x85, 0xa3, - 0xe2, 0xe4, 0x88, 0x5f, 0xdd, 0x20, 0xcd, 0xa7, 0xd1, 0x26, 0x71, 0x63, - 0x89, 0x2e, 0x1a, 0x8a, 0x52, 0x59, 0xba, 0x3b, 0x09, 0x8a, 0x1c, 0x67, - 0x0c, 0xfd, 0xc9, 0xad, 0x7b, 0x4f, 0xd8, 0x0e, 0x47, 0x9e, 0x47, 0x44, - 0x20, 0x67, 0x7a, 0xec, 0x3b, 0xfe, 0x58, 0xf2, 0x25, 0xb2, 0x72, 0xe1, - 0x05, 0xbd, 0x7c, 0x02, 0xc9, 0xdb, 0x40, 0x3c, 0x90, 0x04, 0xab, 0xa7, - 0xb6, 0x06, 0xb2, 0x30, 0x64, 0x42, 0x84, 0x3e, 0x89, 0xd7, 0xd5, 0x90, - 0xaa, 0x14, 0x00, 0xa6, 0x45, 0x26, 0xe1, 0x16, 0xa8, 0x24, 0x65, 0x01, - 0xe1, 0x0e, 0xd3, 0xff, 0x68, 0x0c, 0x0f, 0x8f, 0xc3, 0x68, 0xed, 0x82, - 0x7c, 0xae, 0x21, 0x97, 0x6a, 0x5a, 0x55, 0x76, 0x4b, 0x4e, 0x65, 0x9b, - 0xbd, 0x18, 0x8b, 0xf4, 0xc4, 0x28, 0xab, 0x6c, 0x52, 0xc7, 0xfc, 0xb3, - 0x12, 0x79, 0x3c, 0x29, 0x82, 0x15, 0xd1, 0x45, 0xae, 0x0b, 0xbc, 0x46, - 0x13, 0x24, 0x80, 0xb1, 0x6a, 0x15, 0x7f, 0x68, 0x91, 0xfe, 0xa6, 0x5d, - 0x7a, 0xdb, 0x81, 0xc4, 0x14, 0xf0, 0x7d, 0x59, 0x15, 0x7c, 0x11, 0x6d, - 0xe5, 0x97, 0xc2, 0x5e, 0x00, 0xfc, 0x36, 0x4f, 0xf7, 0xc1, 0xe6, 0x62, - 0x92, 0x03, 0x92, 0x4d, 0x91, 0x61, 0x7e, 0xdc, 0xe9, 0xd3, 0x16, 0x17, - 0xa7, 0x21, 0xb8, 0xf7, 0x27, 0xc4, 0x72, 0xe9, 0xff, 0x66, 0x60, 0x65, - 0x50, 0x6d, 0x2d, 0xe9, 0x02, 0xf2, 0x48, 0xbc, 0xfa, 0x7b, 0x3e, 0xdc, - 0x51, 0x4a, 0xd8, 0x2a, 0xd2, 0x32, 0x95, 0xff, 0x32, 0xf0, 0x68, 0xae, - 0x74, 0xb3, 0xaf, 0x93, 0x79, 0x2e, 0x4e, 0xd8, 0x23, 0x61, 0xf4, 0xca, - 0x34, 0x3f, 0x2d, 0x12, 0x5d, 0xef, 0x05, 0xd0, 0xdc, 0x72, 0x0b, 0x02, - 0xc4, 0x2d, 0x97, 0x65, 0x6d, 0x44, 0x25, 0x50, 0x8e, 0xd1, 0x34, 0x8b, - 0xc3, 0xff, 0xca, 0x17, 0xcb, 0x5c, 0x64, 0x8e, 0xd1, 0xe5, 0x81, 0xb2, - 0x5c, 0xd6, 0xd3, 0x2a, 0x0c, 0x74, 0x41, 0x14, 0xc5, 0x27, 0x3c, 0x3f, - 0x2b, 0xf8, 0xba, 0x33, 0x0b, 0xf4, 0x88, 0x9c, 0x8b, 0x75, 0xf5, 0xf0, - 0x29, 0x08, 0x23, 0x91, 0xe1, 0xcc, 0xc3, 0x6e, 0x5e, 0x60, 0x5d, 0x5a, -}; - -TestDrmCertificates::TestDrmCertificates() - : test_root_certificate_( - kTestRootCertificate, - kTestRootCertificate + sizeof(kTestRootCertificate)), - test_intermediate_certificate_( - kTestIntermediateCertificate, - kTestIntermediateCertificate + sizeof(kTestIntermediateCertificate)), - test_intermediate_certificate_with_ec_key_( - kTestIntermediateCertificateWithECKey, - kTestIntermediateCertificateWithECKey + - sizeof(kTestIntermediateCertificateWithECKey)), - test_user_device_certificate_( - kTestUserDrmCertificate, - kTestUserDrmCertificate + sizeof(kTestUserDrmCertificate)), - test_user_device_certificate_with_ec_key_( - kTestUserDrmCertificateWithECKey, - kTestUserDrmCertificateWithECKey + - sizeof(kTestUserDrmCertificateWithECKey)), - test_user_device_certificate_with_rot_id_( - kTestUserDrmCertificateWithRotId, - kTestUserDrmCertificateWithRotId + - sizeof(kTestUserDrmCertificateWithRotId)), - test_service_certificate_license_sdk_( - kTestDrmServiceCertificateLicenseSdk, - kTestDrmServiceCertificateLicenseSdk + - sizeof(kTestDrmServiceCertificateLicenseSdk)), - test_service_certificate_all_types_( - kTestDrmServiceCertificateAllTypes, - kTestDrmServiceCertificateAllTypes + - sizeof(kTestDrmServiceCertificateAllTypes)), - test_service_certificate_no_type_( - kTestDrmServiceCertificateNoType, - kTestDrmServiceCertificateNoType + - sizeof(kTestDrmServiceCertificateNoType)) {} - -} // namespace widevine diff --git a/common/test_drm_certificates.h b/common/test_drm_certificates.h deleted file mode 100644 index ae3b8f5..0000000 --- a/common/test_drm_certificates.h +++ /dev/null @@ -1,91 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// -// Class contains certificates that can be used for testing. Provides methods -// to retrieve a test root certificate, a test intermediate certificate and a -// test user device certificate. -#ifndef COMMON_TEST_DRM_CERTIFICATES_H_ -#define COMMON_TEST_DRM_CERTIFICATES_H_ - -#include - -namespace widevine { - -class TestDrmCertificates { - public: - TestDrmCertificates(); - - TestDrmCertificates(const TestDrmCertificates&) = delete; - TestDrmCertificates& operator=(const TestDrmCertificates&) = delete; - - virtual ~TestDrmCertificates() {} - - // returns a test root certificate - const std::string& test_root_certificate() const { - return test_root_certificate_; - } - - // returns a test intermediate certificate with an RSA key - - const std::string& test_intermediate_certificate() const { - return test_intermediate_certificate_; - } - - // returns a test intermediate certificate with an EC key - const std::string& test_intermediate_certificate_with_ec_key() const { - return test_intermediate_certificate_with_ec_key_; - } - - // returns a user device certificate with an RSA key - - const std::string& test_user_device_certificate() const { - return test_user_device_certificate_; - } - - // returns a user device certificate with an EC key - const std::string& test_user_device_certificate_with_ec_key() const { - return test_user_device_certificate_with_ec_key_; - } - - // returns a user device certificate with a Root of Trust Id. - const std::string& test_user_device_certificate_with_rot_id() const { - return test_user_device_certificate_with_rot_id_; - } - - // returns a service certificate with license sdk service type - const std::string& test_service_certificate_license_sdk() const { - return test_service_certificate_license_sdk_; - } - - // returns a service certificate with all service types - const std::string& test_service_certificate_all_types() const { - return test_service_certificate_all_types_; - } - - // returns a service certificate prior to a change requiring the service - // type to be specified. - const std::string& test_service_certificate_no_type() const { - return test_service_certificate_no_type_; - } - - private: - const std::string test_root_certificate_; - const std::string test_intermediate_certificate_; - const std::string test_intermediate_certificate_with_ec_key_; - const std::string test_user_device_certificate_; - const std::string test_user_device_certificate_with_ec_key_; - const std::string test_user_device_certificate_with_rot_id_; - const std::string test_service_certificate_license_sdk_; - const std::string test_service_certificate_all_types_; - const std::string test_service_certificate_no_type_; -}; - -} // namespace widevine - -#endif // COMMON_TEST_DRM_CERTIFICATES_H_ diff --git a/common/test_utils.cc b/common/test_utils.cc deleted file mode 100644 index 2b4973a..0000000 --- a/common/test_utils.cc +++ /dev/null @@ -1,72 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/test_utils.h" - -#include - -#include - -#include "glog/logging.h" -#include "openssl/pem.h" -#include "openssl/rsa.h" -#include "openssl/sha.h" - -namespace widevine { - -Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, - const std::string& message, - std::string* signature) { - CHECK(signature); - if (pem_private_key.empty()) { - return Status(error::INVALID_ARGUMENT, "Empty PEM private key"); - } - if (message.empty()) { - return Status(error::INVALID_ARGUMENT, "Empty message"); - } - BIO* bio(NULL); - bio = BIO_new_mem_buf(const_cast(pem_private_key.data()), - pem_private_key.size()); - if (bio == NULL) { - return Status(error::INTERNAL, "BIO allocation failed"); - } - Status status; - RSA* key(NULL); - std::unique_ptr sig_buffer; - unsigned int sig_size; - unsigned char digest[SHA256_DIGEST_LENGTH]; - key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL); - if (key == NULL) { - status = Status(Status::canonical_space(), error::INVALID_ARGUMENT, - "PEM RSA private key load failed"); - goto cleanup; - } - SHA256(reinterpret_cast(message.data()), message.size(), - digest); - sig_size = RSA_size(key); - sig_buffer.reset(new char[sig_size]); - if (RSA_sign(NID_sha256, digest, sizeof(digest), - reinterpret_cast(sig_buffer.get()), &sig_size, - key) != 1) { - status = Status(Status::canonical_space(), error::INTERNAL, - "RSA private encrypt failed"); - goto cleanup; - } - signature->assign(sig_buffer.get(), sig_size); - -cleanup: - if (key != NULL) { - RSA_free(key); - } - if (bio != NULL) { - BIO_free(bio); - } - return status; -} - -} // namespace widevine diff --git a/common/test_utils.h b/common/test_utils.h deleted file mode 100644 index bc8f701..0000000 --- a/common/test_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2013 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: -// Auxiliary functions for license server SDK testing. - -#ifndef COMMON_TEST_UTILS_H_ -#define COMMON_TEST_UTILS_H_ - -#include - -#include "common/status.h" - -namespace widevine { - -// Generate RSA signature using the specified RSA private key, SHA256 digest, -// and PKCS#1 1.5 padding. |pem_private_key| is a PEM-encoded private RSA key, -// |message| is the message to be signed, and |signature| is a pointer to a -// std::string where the signature will be stored. The caller returns ownership of -// all parameters. -Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, - const std::string& message, - std::string* signature); - -} // namespace widevine - -#endif // COMMON_TEST_UTILS_H_ diff --git a/common/verified_media_pipeline.cc b/common/verified_media_pipeline.cc deleted file mode 100644 index a3a9d96..0000000 --- a/common/verified_media_pipeline.cc +++ /dev/null @@ -1,43 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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: -// Helper methods for verifying VMP (Verified Media Pipeline) data. - -#include "common/verified_media_pipeline.h" - -#include "common/vmp_checker.h" - -namespace widevine { -Status VerifyVmpData(const std::string& vmp_data, - PlatformVerificationStatus* platform_verification_status) { - *platform_verification_status = PLATFORM_UNVERIFIED; - VmpChecker::Result vmp_result; - Status status = VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result); - if (status.ok()) { - switch (vmp_result) { - case VmpChecker::kUnverified: - *platform_verification_status = PLATFORM_UNVERIFIED; - break; - case VmpChecker::kVerified: - *platform_verification_status = PLATFORM_SOFTWARE_VERIFIED; - break; - case VmpChecker::kSecureStorageVerified: - *platform_verification_status = - PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED; - break; - case VmpChecker::kTampered: - *platform_verification_status = PLATFORM_TAMPERED; - break; - } - } else { - *platform_verification_status = PLATFORM_TAMPERED; - } - return status; -} -} // namespace widevine diff --git a/common/verified_media_pipeline.h b/common/verified_media_pipeline.h deleted file mode 100644 index 8a95a22..0000000 --- a/common/verified_media_pipeline.h +++ /dev/null @@ -1,28 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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: -// Helper methods for verifying VMP (Verified Media Pipeline) data. - -#ifndef COMMON_VERIFIED_MEDIA_PIPELINE_H_ -#define COMMON_VERIFIED_MEDIA_PIPELINE_H_ - -#include - -#include "common/status.h" -#include "protos/public/license_protocol.pb.h" - -namespace widevine { - -// Retrieve the PlatformVerificationStatus for |vmp_data|. The -// PlatformVerificationStatus is defined at -Status VerifyVmpData(const std::string& vmp_data, - PlatformVerificationStatus* platform_verification_status); - -} // namespace widevine -#endif // COMMON_VERIFIED_MEDIA_PIPELINE_H_ diff --git a/common/vmp_checker.cc b/common/vmp_checker.cc deleted file mode 100644 index 9479582..0000000 --- a/common/vmp_checker.cc +++ /dev/null @@ -1,362 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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: -// Singleton object which validates VMP (Verified Media Pipeline) data for -// purposes of platform software verification. Thread safe. - -#include "common/vmp_checker.h" - -#include - -#include - -#include -#include "glog/logging.h" -#include "common/certificate_type.h" -#include "common/error_space.h" -#include "common/hash_algorithm_util.h" -#include "common/rsa_key.h" -#include "common/x509_cert.h" -#include "protos/public/errors.pb.h" -#include "protos/public/verified_media_pipeline.pb.h" - -namespace { - -const uint32_t kBlessedBinaryFlag = 0x00000001; - -const uint8_t kDevVmpCodeSigningDrmRootCertificate[] = { - 0x30, 0x82, 0x04, 0xb8, 0x30, 0x82, 0x03, 0x20, 0x02, 0x09, 0x00, 0xc5, - 0xf8, 0x2f, 0x03, 0x8f, 0xac, 0xf1, 0x58, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, - 0x9c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, - 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, - 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, - 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, - 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, - 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, - 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, - 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, - 0x55, 0x04, 0x03, 0x0c, 0x15, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, - 0x65, 0x2d, 0x64, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, - 0x67, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x74, 0x69, 0x6e, 0x73, 0x6b, - 0x69, 0x70, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, - 0x6d, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x32, 0x38, 0x30, - 0x31, 0x30, 0x37, 0x34, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x31, 0x36, - 0x31, 0x30, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x34, 0x30, 0x5a, 0x30, - 0x81, 0x9c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, - 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, - 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, - 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, - 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, - 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x1e, 0x30, 0x1c, 0x06, - 0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, - 0x6e, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, - 0x69, 0x67, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x74, 0x69, 0x6e, 0x73, - 0x6b, 0x69, 0x70, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, - 0x6f, 0x6d, 0x30, 0x82, 0x01, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, - 0x8f, 0x00, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xd2, - 0x6f, 0x60, 0x7f, 0xff, 0x7c, 0xbd, 0xa4, 0xe5, 0x8c, 0xa6, 0xcf, 0xde, - 0x22, 0x6d, 0x3a, 0x5e, 0x83, 0xa9, 0x0e, 0x9b, 0xd4, 0x93, 0xb8, 0xb0, - 0xe0, 0x5d, 0x03, 0x3d, 0xc1, 0x00, 0xb8, 0x1a, 0xcc, 0x84, 0x31, 0xfb, - 0x9e, 0x97, 0x79, 0x17, 0x04, 0x48, 0xe7, 0x13, 0x98, 0x0a, 0x47, 0x41, - 0xac, 0x6c, 0x52, 0xb0, 0xca, 0x9e, 0xfb, 0xfd, 0x78, 0x65, 0xd0, 0xd6, - 0x12, 0x07, 0x7e, 0x24, 0x65, 0x46, 0x6c, 0xb9, 0x23, 0xbb, 0xdc, 0x02, - 0x03, 0xc7, 0xb0, 0x02, 0xc1, 0xd3, 0x10, 0x59, 0xe7, 0x0b, 0x45, 0x13, - 0x73, 0x5f, 0xae, 0x58, 0xcd, 0xbf, 0x42, 0x8a, 0xac, 0xf5, 0x6a, 0x1e, - 0x75, 0x26, 0xb1, 0x69, 0x07, 0xad, 0xf5, 0xfd, 0x4c, 0xaa, 0x66, 0x55, - 0x74, 0x56, 0x9a, 0x9e, 0x40, 0x78, 0x77, 0x9a, 0x39, 0x7a, 0x37, 0xe4, - 0x25, 0x6b, 0x07, 0x09, 0xbe, 0xe2, 0x0d, 0x23, 0x83, 0xfc, 0x94, 0x9f, - 0x26, 0x98, 0x0e, 0x49, 0x81, 0x7b, 0xf4, 0xe6, 0xd4, 0xda, 0x7a, 0xc9, - 0xa4, 0x14, 0x5a, 0xa9, 0xaf, 0x0c, 0xd9, 0xf1, 0xbc, 0xd8, 0x6c, 0xd2, - 0xd4, 0x1b, 0x82, 0x10, 0x3d, 0x87, 0xf1, 0x81, 0xe6, 0x1a, 0xb7, 0xfa, - 0xfa, 0x1f, 0x9c, 0xde, 0xa1, 0x3f, 0x11, 0xb1, 0xd8, 0x26, 0xd1, 0x86, - 0x21, 0xdc, 0x03, 0xcb, 0xd6, 0x40, 0xfb, 0x5f, 0xb0, 0x84, 0x7f, 0x69, - 0x9e, 0xa3, 0xbc, 0xfb, 0x03, 0xb6, 0xc1, 0xb9, 0x23, 0xb1, 0x20, 0x6f, - 0x71, 0xf5, 0x7a, 0x3b, 0x84, 0x30, 0xa8, 0x59, 0xc0, 0x8f, 0x75, 0xfd, - 0xcb, 0xe1, 0xc3, 0x5f, 0xe7, 0x8a, 0xb0, 0xe9, 0xf8, 0xef, 0x04, 0x4b, - 0x4a, 0xf6, 0xc3, 0x7d, 0x08, 0xfe, 0x08, 0x52, 0x2e, 0xbc, 0x1f, 0x65, - 0xf6, 0x51, 0xb7, 0xd8, 0x24, 0x21, 0x49, 0x1d, 0x7f, 0x16, 0x28, 0x14, - 0xd9, 0xc2, 0x19, 0xdb, 0xa2, 0xc6, 0xf0, 0x3a, 0x2d, 0x98, 0x70, 0x72, - 0x45, 0xf7, 0x80, 0x37, 0x56, 0x0b, 0x0c, 0x6f, 0x80, 0xf1, 0x8c, 0xe2, - 0xf3, 0x4d, 0x16, 0xc5, 0x74, 0x90, 0x34, 0x1e, 0x57, 0x3c, 0xde, 0xf1, - 0xc4, 0x8c, 0x17, 0x09, 0xd3, 0xc5, 0x92, 0x9d, 0xcf, 0xdc, 0x7b, 0x4f, - 0xae, 0x20, 0x10, 0xd7, 0x04, 0x56, 0x9d, 0x9a, 0xa9, 0xd8, 0x06, 0x4a, - 0xd6, 0x68, 0xd4, 0x83, 0xcb, 0x7d, 0xe2, 0x62, 0xd1, 0x99, 0xb8, 0x9d, - 0x81, 0xc7, 0xfc, 0x94, 0x69, 0x0d, 0x2a, 0x1c, 0x99, 0xcf, 0x40, 0xc3, - 0xfd, 0xe9, 0x64, 0x5b, 0xc3, 0x1d, 0xda, 0x1c, 0x89, 0xab, 0x34, 0x1b, - 0x53, 0x6e, 0xad, 0xf0, 0x6e, 0x97, 0x87, 0xe8, 0xfb, 0x0c, 0x96, 0x93, - 0x1b, 0x52, 0x82, 0x6a, 0xba, 0x0f, 0xe3, 0x5d, 0xc4, 0x17, 0xdc, 0xe4, - 0x31, 0x78, 0x12, 0x26, 0x10, 0x74, 0x14, 0x7c, 0x45, 0xb2, 0xb9, 0x02, - 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x81, 0x00, - 0x8f, 0x5b, 0x2a, 0x40, 0xce, 0xae, 0xa2, 0x79, 0xfc, 0xc5, 0x5e, 0x94, - 0xc8, 0x10, 0x4b, 0xf1, 0x21, 0x7f, 0x4b, 0xeb, 0x81, 0x3d, 0xb8, 0x26, - 0x83, 0x84, 0x76, 0x79, 0xda, 0x35, 0xfc, 0xdf, 0xfe, 0x10, 0x7a, 0xd5, - 0x17, 0xc0, 0xad, 0x0d, 0xf9, 0x3f, 0xa6, 0xa1, 0xcd, 0x6c, 0x9c, 0x3b, - 0x52, 0xbd, 0x04, 0xf9, 0xe2, 0x9e, 0x86, 0x83, 0x98, 0x60, 0x01, 0x99, - 0xb7, 0xbd, 0x02, 0x87, 0xd8, 0xea, 0x65, 0xaa, 0x60, 0x6f, 0x33, 0x50, - 0x25, 0x84, 0xb7, 0x42, 0x63, 0x39, 0xfd, 0x17, 0x67, 0x74, 0x88, 0x66, - 0xe2, 0x38, 0x59, 0xf6, 0x9b, 0x98, 0x95, 0xdd, 0x54, 0x2c, 0x69, 0x6a, - 0x0a, 0x51, 0x66, 0x4d, 0x65, 0xc0, 0x58, 0x3e, 0xcf, 0x15, 0x63, 0x7a, - 0x32, 0xc8, 0xfb, 0xe7, 0x11, 0x2e, 0x25, 0x17, 0x52, 0x4d, 0x8e, 0x6b, - 0x6d, 0x58, 0x4e, 0xf6, 0xd6, 0xb0, 0xfa, 0x0d, 0x7a, 0xb1, 0x44, 0x52, - 0x9a, 0x6c, 0x90, 0x38, 0x68, 0xa5, 0xa9, 0x9b, 0xc5, 0x45, 0x09, 0xfa, - 0xaa, 0x8c, 0xfe, 0x91, 0x55, 0x93, 0x35, 0x52, 0x45, 0xbb, 0xaa, 0x5b, - 0xf0, 0x63, 0x53, 0x13, 0xcf, 0x48, 0x7b, 0xaa, 0x20, 0xa0, 0x07, 0x43, - 0x1d, 0xd7, 0xb3, 0x4a, 0x1b, 0x8c, 0x51, 0xb5, 0xf6, 0xb9, 0x5b, 0x13, - 0x02, 0x74, 0x3e, 0x48, 0xde, 0xec, 0xeb, 0x65, 0xfe, 0xf2, 0x61, 0xe5, - 0x68, 0xd5, 0xea, 0xd9, 0x79, 0xa6, 0x71, 0xb1, 0x57, 0x0f, 0xbc, 0xd0, - 0x31, 0x4f, 0xff, 0xc5, 0x95, 0xe8, 0xee, 0x70, 0x18, 0xb9, 0xbc, 0x19, - 0xcd, 0x3a, 0x06, 0x75, 0xe4, 0x57, 0xc1, 0x2e, 0x32, 0x19, 0xdd, 0x2e, - 0x45, 0xc0, 0x19, 0xe6, 0x72, 0x81, 0x2c, 0xb6, 0xed, 0x1c, 0xd4, 0xef, - 0x42, 0x18, 0x44, 0x44, 0x75, 0xd6, 0x29, 0x81, 0xe1, 0xf7, 0x5b, 0x48, - 0xa3, 0xf8, 0x92, 0x54, 0xd0, 0x79, 0xa1, 0xe1, 0x8e, 0xa8, 0x98, 0x2d, - 0x57, 0x5d, 0xb5, 0x5a, 0x01, 0x1b, 0xb3, 0xcf, 0x5f, 0x64, 0x2e, 0x70, - 0xba, 0xa0, 0x41, 0xbb, 0xd4, 0x82, 0x28, 0x3c, 0xb1, 0x81, 0x76, 0xd6, - 0x85, 0x2e, 0xc6, 0x01, 0x7f, 0xae, 0xc3, 0x17, 0x2f, 0xed, 0xbe, 0xad, - 0xa2, 0x7c, 0x53, 0xc6, 0x77, 0x73, 0x1d, 0x19, 0x90, 0x2a, 0xf8, 0xd5, - 0x50, 0x65, 0xc1, 0x22, 0x3c, 0x24, 0x96, 0xeb, 0x7b, 0x53, 0x8f, 0xbf, - 0xd9, 0xf7, 0x80, 0xa8, 0x76, 0x72, 0xea, 0xb7, 0x7f, 0xf7, 0xa2, 0x52, - 0xc7, 0xa7, 0xd6, 0x88, 0xa1, 0x38, 0x40, 0x5d, 0xcd, 0xdb, 0xe3, 0x8e, - 0xc7, 0xf9, 0x39, 0xbe, 0xfa, 0x27, 0x41, 0x73, 0x3a, 0x1c, 0xb3, 0x03, - 0xf1, 0x36, 0xea, 0xe8, 0xb3, 0xe1, 0x6e, 0x59, 0xcc, 0xe2, 0x75, 0x2b, - 0xf9, 0x55, 0xb9, 0xc2, 0xdf, 0x0a, 0x8d, 0x8d, 0xd1, 0x62, 0x3b, 0x86}; - -const uint8_t kProdVmpCodeSigningDrmRootCertificate[] = { - 0x30, 0x82, 0x04, 0xd7, 0x30, 0x82, 0x03, 0x3f, 0xa0, 0x03, 0x02, 0x01, - 0x02, 0x02, 0x11, 0x00, 0xca, 0xa4, 0xbd, 0x6b, 0x93, 0x56, 0x4a, 0xf1, - 0x84, 0xef, 0x5e, 0xed, 0xe8, 0xf7, 0xe2, 0x0b, 0x30, 0x0d, 0x06, 0x09, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, - 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, - 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, - 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, - 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, - 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, - 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, - 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, - 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, - 0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, - 0x65, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x2d, 0x72, - 0x6f, 0x6f, 0x74, 0x2d, 0x63, 0x61, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x37, - 0x30, 0x31, 0x32, 0x34, 0x32, 0x33, 0x33, 0x38, 0x31, 0x34, 0x5a, 0x18, - 0x0f, 0x33, 0x30, 0x31, 0x36, 0x30, 0x35, 0x32, 0x37, 0x32, 0x33, 0x33, - 0x38, 0x31, 0x34, 0x5a, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, - 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, - 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, - 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, - 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, - 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x69, - 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, - 0x69, 0x67, 0x6e, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x63, 0x61, 0x30, - 0x82, 0x01, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, - 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xe0, 0xb5, 0xc5, 0x6d, - 0x04, 0xc1, 0x97, 0xaf, 0xe7, 0x62, 0xfb, 0x84, 0xdc, 0xd1, 0xf4, 0xb1, - 0xb5, 0xa2, 0x7c, 0xca, 0x31, 0xf8, 0xce, 0xa7, 0x7a, 0x92, 0xc2, 0xbe, - 0x14, 0xdc, 0x85, 0x9f, 0x18, 0x9e, 0x78, 0xba, 0x65, 0x05, 0x56, 0x88, - 0x88, 0xdc, 0x1f, 0x4f, 0x24, 0x7f, 0xf5, 0x26, 0x6f, 0x6e, 0xcc, 0x04, - 0x2f, 0x38, 0xb8, 0xcd, 0x27, 0xd7, 0x9e, 0x07, 0xd3, 0xa9, 0xd4, 0x6b, - 0x84, 0xfe, 0xf8, 0xac, 0x9c, 0x53, 0xdf, 0x7a, 0x45, 0x5e, 0x77, 0xf8, - 0x4e, 0x88, 0x00, 0x5c, 0x6f, 0xb6, 0xa7, 0x0b, 0x4b, 0x63, 0x57, 0x92, - 0x7a, 0x7b, 0x3d, 0x20, 0x88, 0x3e, 0x7b, 0xb4, 0x28, 0x2b, 0x63, 0x81, - 0xd4, 0x0c, 0x4c, 0xb7, 0x54, 0x68, 0x68, 0x2c, 0x0d, 0xf5, 0xa6, 0x9e, - 0x16, 0x93, 0x76, 0xdd, 0xc0, 0xd5, 0x93, 0x65, 0x99, 0x90, 0x17, 0x2d, - 0x2b, 0xdc, 0x6f, 0xaf, 0x58, 0xfd, 0x78, 0xe9, 0xf5, 0xde, 0x2e, 0x36, - 0x95, 0xf0, 0xcf, 0x25, 0x41, 0x3d, 0x4f, 0x37, 0xd1, 0x70, 0x5b, 0xb5, - 0xc0, 0xc8, 0xf3, 0x63, 0xa3, 0xda, 0x9f, 0x94, 0xdb, 0xf8, 0x51, 0xf2, - 0xa9, 0xe5, 0x67, 0x0e, 0x29, 0xb3, 0x45, 0x12, 0xc5, 0x42, 0xf9, 0x3b, - 0x38, 0xf9, 0xa5, 0x7b, 0x41, 0x88, 0x6f, 0x32, 0x62, 0x03, 0x5f, 0xfd, - 0x35, 0x97, 0xc2, 0x83, 0x15, 0xb6, 0x56, 0x4f, 0xbb, 0x81, 0x39, 0x37, - 0xf2, 0x9c, 0x2a, 0x61, 0xa8, 0x63, 0x5f, 0xa0, 0x27, 0x30, 0x06, 0xd4, - 0xcb, 0x9d, 0xb7, 0xe9, 0xf2, 0xae, 0xd6, 0xc9, 0xcd, 0x72, 0xa3, 0xe6, - 0xf8, 0x54, 0x03, 0x6e, 0xe1, 0x95, 0x03, 0xdd, 0x7a, 0x85, 0xb3, 0x5c, - 0xa7, 0xca, 0x99, 0xec, 0xa6, 0xe8, 0x1a, 0xb2, 0x72, 0xe1, 0x91, 0x2d, - 0x97, 0xe3, 0x2a, 0x9c, 0x42, 0xaa, 0x45, 0xf2, 0x8e, 0x51, 0xc0, 0xd8, - 0x21, 0x83, 0x66, 0x07, 0xb5, 0x20, 0xb8, 0x28, 0xa5, 0xde, 0xfb, 0x4e, - 0x2e, 0xc7, 0x70, 0x9b, 0x3d, 0x52, 0x66, 0x24, 0xc5, 0xa2, 0x2e, 0x49, - 0x54, 0x5c, 0xfd, 0xc0, 0xde, 0xf6, 0x9d, 0xb4, 0x70, 0x31, 0x2b, 0xac, - 0x14, 0xfb, 0x19, 0x9e, 0x89, 0xd5, 0x07, 0x87, 0xa0, 0xd8, 0x15, 0x96, - 0xe9, 0xf7, 0x91, 0x36, 0x52, 0x83, 0x3c, 0x2c, 0xfa, 0xb5, 0xc4, 0xc6, - 0x1a, 0x34, 0xf0, 0x53, 0x94, 0x15, 0x82, 0xa2, 0x2f, 0x98, 0xbb, 0x49, - 0xca, 0xf7, 0xe0, 0xcb, 0x9e, 0x3c, 0xa6, 0x64, 0x59, 0x77, 0x63, 0xd1, - 0x05, 0x03, 0x99, 0x6c, 0x50, 0x08, 0xec, 0x64, 0x86, 0xf7, 0x97, 0xaf, - 0xf8, 0xcc, 0xdf, 0x91, 0xc7, 0x2c, 0x15, 0x0f, 0xa7, 0x0e, 0x02, 0x33, - 0x63, 0x84, 0xb7, 0x7e, 0xd3, 0x10, 0x89, 0x05, 0x2d, 0xb4, 0x68, 0x38, - 0xe0, 0x00, 0x49, 0xda, 0xaa, 0xb9, 0xf9, 0xbf, 0x02, 0x03, 0x01, 0x00, - 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, - 0x04, 0x16, 0x04, 0x14, 0xca, 0x3d, 0xd8, 0x8e, 0x0f, 0x74, 0x57, 0x7f, - 0xd0, 0x9a, 0xd9, 0xe1, 0x21, 0xbf, 0x42, 0xfb, 0x23, 0x55, 0x29, 0x86, - 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, - 0x14, 0xca, 0x3d, 0xd8, 0x8e, 0x0f, 0x74, 0x57, 0x7f, 0xd0, 0x9a, 0xd9, - 0xe1, 0x21, 0xbf, 0x42, 0xfb, 0x23, 0x55, 0x29, 0x86, 0x30, 0x0c, 0x06, - 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, - 0x05, 0x00, 0x03, 0x82, 0x01, 0x81, 0x00, 0xc1, 0x81, 0x17, 0x08, 0x0a, - 0xcb, 0xae, 0x54, 0x92, 0xed, 0x0f, 0xc0, 0xf0, 0x83, 0xb8, 0xe9, 0x2a, - 0xd5, 0x65, 0x18, 0xb5, 0x92, 0xfc, 0x67, 0x9c, 0x39, 0x9e, 0x3a, 0x93, - 0x1f, 0x91, 0x7b, 0x35, 0x6d, 0x09, 0x6c, 0x3c, 0x02, 0x85, 0xe8, 0xc6, - 0x0c, 0x6b, 0x35, 0xeb, 0x8c, 0xe4, 0x44, 0x80, 0xc5, 0x4e, 0x65, 0xa6, - 0xbc, 0x25, 0x93, 0x5a, 0xed, 0x5a, 0xd1, 0x5a, 0xcf, 0xf1, 0xbe, 0xd5, - 0x46, 0x7c, 0x78, 0xfe, 0xb6, 0xa6, 0x9c, 0x85, 0xa9, 0xe2, 0x13, 0x70, - 0x99, 0x03, 0x5a, 0x3a, 0xa8, 0x7b, 0xdd, 0x50, 0x76, 0x83, 0xfe, 0x49, - 0xc0, 0x5e, 0xc7, 0xf1, 0x18, 0xc0, 0xe6, 0xb7, 0xc7, 0xe4, 0x9d, 0x54, - 0xaf, 0x25, 0xdf, 0xe4, 0x81, 0xc1, 0xe9, 0xaa, 0x7c, 0x05, 0x20, 0xfa, - 0x91, 0x47, 0xd1, 0x4a, 0xe2, 0x24, 0x6f, 0x72, 0x22, 0x69, 0xd0, 0x89, - 0x78, 0x2c, 0x9a, 0x16, 0x7d, 0x92, 0xdd, 0x64, 0x6c, 0xc8, 0xbf, 0x33, - 0xe3, 0x91, 0xb9, 0xb5, 0x16, 0xfe, 0xfd, 0xa2, 0xdb, 0x82, 0xf0, 0xec, - 0xac, 0xe7, 0xf9, 0x2e, 0xac, 0x50, 0xf0, 0xcf, 0xba, 0xe1, 0x55, 0xa9, - 0xb0, 0xd9, 0x66, 0x3f, 0xb6, 0xee, 0x57, 0xff, 0x8d, 0x43, 0xb7, 0xc3, - 0xb4, 0x44, 0xa9, 0xcc, 0x99, 0xa2, 0xbf, 0xac, 0x4f, 0xec, 0xed, 0xb5, - 0xd0, 0x3f, 0xa9, 0x50, 0x3b, 0xc1, 0x24, 0xf2, 0xd0, 0xef, 0x5c, 0xbf, - 0x5c, 0xc2, 0x41, 0x29, 0xbe, 0xb6, 0x76, 0x5a, 0x19, 0xde, 0x67, 0x1c, - 0x2a, 0x67, 0xae, 0x07, 0xe8, 0xfa, 0x49, 0xf1, 0x81, 0xbc, 0x22, 0xa1, - 0xe6, 0x5d, 0x27, 0x76, 0x0f, 0x4d, 0x41, 0x57, 0xcf, 0x0f, 0x12, 0x2f, - 0xdd, 0x20, 0x88, 0xcf, 0xc8, 0xa7, 0xc0, 0xe5, 0xec, 0xcd, 0xb9, 0xa7, - 0x1c, 0x29, 0x55, 0xed, 0x67, 0xf9, 0x38, 0x33, 0xea, 0x85, 0xe9, 0x69, - 0x5a, 0x7c, 0xfe, 0x37, 0x3b, 0xdd, 0x61, 0x5f, 0xaa, 0xc3, 0x18, 0xbc, - 0x58, 0x95, 0x39, 0x61, 0x79, 0xa1, 0x46, 0xcc, 0xc0, 0xe7, 0xd6, 0x52, - 0x3c, 0xc7, 0xfa, 0xed, 0x89, 0x06, 0xeb, 0xd4, 0x5e, 0x9c, 0xa5, 0x55, - 0x8c, 0xe3, 0x5f, 0xe6, 0xb4, 0x0a, 0xf4, 0xf6, 0x7d, 0xeb, 0x64, 0x74, - 0xa9, 0x1a, 0x8d, 0x6e, 0xf1, 0x41, 0xc7, 0x7e, 0xc6, 0x26, 0x3a, 0x47, - 0x70, 0x49, 0x07, 0x27, 0xa2, 0xb9, 0xc6, 0x79, 0x9d, 0x94, 0xf5, 0x51, - 0x69, 0xdf, 0xbd, 0x84, 0xee, 0xaa, 0x46, 0xea, 0x4b, 0x27, 0xb6, 0x5c, - 0xac, 0xcf, 0x4a, 0x48, 0x12, 0x40, 0x86, 0x80, 0xd4, 0xb8, 0x0a, 0xb1, - 0x9f, 0xdc, 0x68, 0x60, 0x14, 0x33, 0x1d, 0x88, 0xfb, 0xa2, 0xfc, 0x49, - 0x0c, 0xa9, 0x76, 0x2d, 0xd7, 0x32, 0x3f, 0x77, 0xdb, 0x62, 0x8c, 0x35, - 0x88, 0x5d, 0x66, 0xc9, 0x8d, 0x07, 0xe5}; - -const char kCodeSigningDevelopmentFlagOid[] = "1.3.6.1.4.1.11129.4.1.2"; -const char kSecureStorageFlagOid[] = "1.3.6.1.4.1.11129.4.1.3"; - -} // namespace - -namespace widevine { - -VmpChecker::VmpChecker() : allow_development_vmp_(false) {} - -VmpChecker::~VmpChecker() {} - -Status VmpChecker::SelectCertificateType(CertificateType cert_type) { - std::unique_ptr ca_cert(new X509Cert); - Status status = ca_cert->LoadDer( - cert_type == kCertificateTypeProduction - ? std::string(reinterpret_cast( - kProdVmpCodeSigningDrmRootCertificate), - sizeof(kProdVmpCodeSigningDrmRootCertificate)) - : std::string(reinterpret_cast( - kDevVmpCodeSigningDrmRootCertificate), - sizeof(kDevVmpCodeSigningDrmRootCertificate))); - if (!status.ok()) return status; - - ca_.reset(new X509CA(ca_cert.release())); - - return OkStatus(); -} - -VmpChecker* VmpChecker::Instance() { - static VmpChecker instance; - return &instance; -} - -// Verify VMP data and return appropriate result. -Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) { - DCHECK(!vmp_data.empty()); - DCHECK(result); - - if (!ca_) return Status(error_space, CERT_CHAIN_NOT_SELECTED, ""); - - vmp::VmpData vmp_data_obj; - if (!vmp_data_obj.ParseFromString(vmp_data)) { - LOG(INFO) << "Error deserializing VmpData."; - return Status(error_space, INVALID_MESSAGE, "vmp-data-deserialize-failed"); - } - - std::vector> code_signing_certs; - const std::string kDevelopmentFlagOid(kCodeSigningDevelopmentFlagOid); - bool secure_storage_verified(true); - for (int cert_idx = 0; cert_idx < vmp_data_obj.certificates_size(); - ++cert_idx) { - code_signing_certs.emplace_back(new X509Cert); - Status status(code_signing_certs.back()->LoadDer( - vmp_data_obj.certificates(cert_idx))); - if (!status.ok()) return status; - - if (!allow_development_vmp_) { - bool dev_flag; - if (code_signing_certs.back()->GetV3BooleanExtension(kDevelopmentFlagOid, - &dev_flag) && - dev_flag) { - return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, - "development-vmp-certificate-not-allowed"); - } - } - status = ca_->VerifyCert(*code_signing_certs.back()); - if (!status.ok()) return status; - - if (secure_storage_verified) { - bool secure_storage_flag; - if (!code_signing_certs.back()->GetV3BooleanExtension( - kSecureStorageFlagOid, &secure_storage_flag) || - !secure_storage_flag) { - secure_storage_verified = false; - } - } - } - - size_t num_blessed_binaries(0); - for (int binary_idx = 0; binary_idx < vmp_data_obj.signed_binary_info_size(); - ++binary_idx) { - const vmp::VmpData::SignedBinaryInfo& binary_info( - vmp_data_obj.signed_binary_info(binary_idx)); - if (binary_info.signature().empty()) { - LOG(INFO) << "Unsigned binary \"" << binary_info.file_name() << "\"."; - *result = kTampered; - return OkStatus(); - } - if (binary_info.certificate_index() >= code_signing_certs.size()) { - LOG(INFO) << "Invalid code signing certificate index."; - *result = kTampered; - return OkStatus(); - } - X509Cert* cert = code_signing_certs[binary_info.certificate_index()].get(); - std::unique_ptr key(cert->GetRsaPublicKey()); - std::string message(binary_info.binary_hash()); - message += binary_info.flags() & 0xff; - if (!key->VerifySignature( - message, HashAlgorithmProtoToEnum(binary_info.hash_algorithm()), - binary_info.signature())) { - LOG(INFO) << "Code signature verification failed for file \"" - << binary_info.file_name() << "\"."; - *result = kTampered; - return OkStatus(); - } - if (binary_info.flags() & kBlessedBinaryFlag) ++num_blessed_binaries; - } - if (num_blessed_binaries != 1) { - LOG(INFO) << "Invalid number of blessed binaries (" << num_blessed_binaries - << ")."; - *result = kTampered; - return OkStatus(); - } - - VLOG(2) << "VMP verification success. Secure storage: " - << secure_storage_verified; - *result = secure_storage_verified ? kSecureStorageVerified : kVerified; - return OkStatus(); -} - -} // namespace widevine diff --git a/common/vmp_checker.h b/common/vmp_checker.h deleted file mode 100644 index 54caf6f..0000000 --- a/common/vmp_checker.h +++ /dev/null @@ -1,57 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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: -// Singleton object which validates VMP (Verified Media Pipeline) data for -// purposes of platform software verification. - -#ifndef COMMON_VMP_CHECKER_H_ -#define COMMON_VMP_CHECKER_H_ - -#include -#include - -#include "common/certificate_type.h" -#include "common/status.h" - -namespace widevine { -class X509CA; - -class VmpChecker { - public: - enum Result { - kUnverified = 0, - kVerified = 1, - kSecureStorageVerified = 2, - kTampered = 3 - }; - - // Singleton accessor. - static VmpChecker* Instance(); - - // Select the type of root to use. Not thread-safe. - virtual Status SelectCertificateType(CertificateType cert_type); - - // Verify VMP data and return appropriate result. - virtual Status VerifyVmpData(const std::string& vmp_data, Result* result); - - // Enable/disable development code signing certificates. - void set_allow_development_vmp(bool allow) { allow_development_vmp_ = allow; } - bool allow_development_vmp() const { return allow_development_vmp_; } - - private: - VmpChecker(); - ~VmpChecker(); - - std::unique_ptr ca_; - bool allow_development_vmp_ = false; -}; - -} // namespace widevine - -#endif // COMMON_VMP_CHECKER_H_ diff --git a/common/vmp_checker_test.cc b/common/vmp_checker_test.cc deleted file mode 100644 index d10958a..0000000 --- a/common/vmp_checker_test.cc +++ /dev/null @@ -1,326 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/vmp_checker.h" - -#include - -#include "glog/logging.h" -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/hash_algorithm_util.h" -#include "common/rsa_key.h" -#include "protos/public/errors.pb.h" -#include "protos/public/verified_media_pipeline.pb.h" - -namespace widevine { - -namespace { - -const uint32_t kBlessedBinaryFlag = 0x00000001; - -const char kDevVmpCodeSigningKey[] = - "308204a50201000282010100b3a7da87309390688388d614a5a37e7ee73a" - "c3b296caf4464bfeccbeedf2e3d802d62d5de2f7b409b1eac2dc578b2bfd" - "8b5f20acef13d8ba6a4ccfd406f29a60e1af4151212a062c62c71d894fe6" - "d5524e1b28af1d51d2b806aca778f77fd0e4ef278c4fbd5eb756398d646b" - "b50d3a13d8687ad304005b0b0a054e5109d70dec9953b2f99768fca8fe51" - "957dc4608fd34c999a7b35245bce2795715d8a5957a0872398473eed4860" - "29286f51d4118927e88634ad040034e061fd3f58632961761b1fbb8faf45" - "391d84f7ffe2bf5e27bd499eee14a17bc8be2fd258331e7a86baa7394706" - "424420f6eaba0001bffe74976a5b4cc46380ceef9ce93b3bb73008150203" - "01000102820101008befeb1ff28e7ea56a0f63f1a133c08c48c0553efe86" - "07cfd9d216d981aef81a81db226b47277a6d32d09207df88e03316247ae7" - "39325456a00644bbfacd6dc2990851f047ccdc1226bec21afac9eacfb957" - "1e51889cfb6dac853fcdd1bb1593bd5528cdd3cbbb32c69183ef018fd3f5" - "3153f097fd3de9aca7998a6f4522e60c5e76ecc717033a2be16c233fe3e2" - "94c0ae68179a1ae5d33d51f2c0bcda35cffa21e1814374af1c014c280cfb" - "09e294a099f9a6f003d3da026af0f53029cad3d401178b0db53ca97fd166" - "a5eddf1384ddd92c55ab31758e0651e41dd7b24f2c438d58de00f55343cc" - "a461b94ff6358fc37f404ecbda2365d3e75391566248d3e102818100e4c8" - "783343b43fc127f5077fb35b37145ab6ee5f9a802e8100161ce441cbdbdc" - "1eb15f50bbef1f5088ba83ff914977862dffc63bd364172c9044e1131dbb" - "ff98755daa49670a014163b3c121395d880ad874b9ebdf66ff72a245c2b5" - "4f8fe1e233e72fd9cc253cbcd144f52537e9b7ed16b8a6d328de61c41f86" - "ea1d9ef326fb02818100c90738b2cf61af785e53393d9e96bc2f4d79358b" - "7bd487a242d170b8372af0a26af4980534a099647a4f38efb1a47d9dcdcf" - "a4ea6036396ef333e4f1de62ec529c3122f0d3b6abc818918494a52b028b" - "2cdf06bf2b450d5b99da7f203ff011318c030a01659c4c56244c2c312528" - "e30dd3b7709022d8fd14a2dba23a855da02f0281804f8ebeede4cf5b9449" - "d6d582bcd62d73309088984a5be4d00b3da55262e7074fa684bbc69173f8" - "09c36248e0a89f49a7297bd66d9b7724efe4436f997c2f92146c4be4199e" - "71463a7cf75763bc552027d559d2058a2c810c560db845e0a30243ed14a9" - "f92d1a8de2834b5d8c51c33ea87dcc3c8715a12f9249fc5a916e62d3dd02" - "8181008f74c7d1528cb35b82748174a7a789c377d5f790025e382c62e273" - "3e02a071f875baf681407d1af9c90e9fe2ed322532679cb6634b2566f6f6" - "37223a3828ffdc33fa1ca51f704c460ec2498a8a13974d1a484dd83e5898" - "9fb5bb66dcecc3b4815719141acb182ea18a659163c0d0dcb7114ee6d4f5" - "09441165e6b66e6c9dd3a102818100c449003eee6d9a0b724b66027a791e" - "3b86a72b2098ab085c2e69c276627fd6beeee98918de14ce15d17e059906" - "a178015d04e205918203ffa6c1324868d5c0a019f6fe82335403743322ee" - "14b1159692194ac22d9056c0c39309d249b33abaddb0d08ee87cc053a12a" - "83f12d261525e1b37df643c3e55770ef247d5d094816a0"; - -const char kDevVmpCodeSigningCert[] = - "3082056a308203d2a003020102020f112233445566778899aabbccddeeff300d06092a86" - "4886f70d01010b050030819c310b30090603550406130255533113301106035504080c0a" - "57617368696e67746f6e3111300f06035504070c084b69726b6c616e64310f300d060355" - "040a0c06476f6f676c653111300f060355040b0c085769646576696e65311e301c060355" - "04030c157769646576696e652d6465762d636f64657369676e3121301f06092a864886f7" - "0d010901161274696e736b697040676f6f676c652e636f6d301e170d3137313030393231" - "323835385a170d3237313030373231323835385a3081a0310b3009060355040613025553" - "3113301106035504080c0a57617368696e67746f6e3111300f06035504070c084b69726b" - "6c616e64310f300d060355040a0c06476f6f676c653111300f060355040b0c0857696465" - "76696e653122302006035504030c197769646576696e652d6465762d766d702d636f6465" - "7369676e3121301f06092a864886f70d010901161274696e736b697040676f6f676c652e" - "636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100" - "b3a7da87309390688388d614a5a37e7ee73ac3b296caf4464bfeccbeedf2e3d802d62d5d" - "e2f7b409b1eac2dc578b2bfd8b5f20acef13d8ba6a4ccfd406f29a60e1af4151212a062c" - "62c71d894fe6d5524e1b28af1d51d2b806aca778f77fd0e4ef278c4fbd5eb756398d646b" - "b50d3a13d8687ad304005b0b0a054e5109d70dec9953b2f99768fca8fe51957dc4608fd3" - "4c999a7b35245bce2795715d8a5957a0872398473eed486029286f51d4118927e88634ad" - "040034e061fd3f58632961761b1fbb8faf45391d84f7ffe2bf5e27bd499eee14a17bc8be" - "2fd258331e7a86baa7394706424420f6eaba0001bffe74976a5b4cc46380ceef9ce93b3b" - "b73008150203010001a38201213082011d301d0603551d0e041604147266b4ce84aafd02" - "b1159cd2fa04c2553c6c02463081bb0603551d230481b33081b0a181a2a4819f30819c31" - "0b30090603550406130255533113301106035504080c0a57617368696e67746f6e311130" - "0f06035504070c084b69726b6c616e64310f300d060355040a0c06476f6f676c65311130" - "0f060355040b0c085769646576696e65311e301c06035504030c157769646576696e652d" - "6465762d636f64657369676e3121301f06092a864886f70d010901161274696e736b6970" - "40676f6f676c652e636f6d820900c5f82f038facf15830090603551d1304023000300b06" - "03551d0f04040302078030130603551d25040c300a06082b060105050703033011060a2b" - "06010401d67904010204030101ff300d06092a864886f70d01010b05000382018100aa23" - "6a5c0e23d5bf67c9f80f893d8347ba489541cf7f4ab7dfffda0ca21a3372e8ee8cfea863" - "628b9e0795904bc0e7495517246143c7b8555884e82fe1c305f0f4c3575447d4e7ce3243" - "4e1e0cf11712d537cd434c11d1328b814c94dbd0bab802e8fed5390da5f0cd719ce0e366" - "47620bcf40ed3945c80ab19beb7728080a74d4ff5d62564f47b32c4915c1f14890d379c8" - "8060f0bac73301defda06275a2e1a2024f92f0b4700d4e50d2d6f8d033715a362d7ca5ab" - "6d2dae20d8cefa2d3fc4f61e1734802984e5078dd6d957719fa75ea10dd02d983f7e383b" - "10fa92be7add70238388e63ec2c7ec49a37aa0c8a2566c46e9755cd9ce654c6d42053d1e" - "1cd9555f8a3bc5e426857072a8e8b44a756543893b1d29dabf31a2301597df2666612f23" - "a442613526e19f2aa9b2ea49f16f14b16794e053967a21b821c7b2495b2e02b01344a339" - "9d7e31dd71982cf21a546b1947bbce236381d717070c27096b6a91413abc69c3c0759574" - "4b7e91daf24b2a0acfd85924669f00292a4bd0c57b4c"; - -const char kDevSecureStorageVmpCodeSigningCert[] = - "30820571308203d9a0030201020203112233300d06092a864886f70d01010b050030819c" - "310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3111" - "300f06035504070c084b69726b6c616e64310f300d060355040a0c06476f6f676c653111" - "300f060355040b0c085769646576696e65311e301c06035504030c157769646576696e65" - "2d6465762d636f64657369676e3121301f06092a864886f70d010901161274696e736b69" - "7040676f6f676c652e636f6d301e170d3138303232323231323834395a170d3238303232" - "303231323834395a3081a0310b30090603550406130255533113301106035504080c0a57" - "617368696e67746f6e3111300f06035504070c084b69726b6c616e64310f300d06035504" - "0a0c06476f6f676c653111300f060355040b0c085769646576696e653122302006035504" - "030c197769646576696e652d6465762d766d702d636f64657369676e3121301f06092a86" - "4886f70d010901161274696e736b697040676f6f676c652e636f6d30820122300d06092a" - "864886f70d01010105000382010f003082010a0282010100b3a7da87309390688388d614" - "a5a37e7ee73ac3b296caf4464bfeccbeedf2e3d802d62d5de2f7b409b1eac2dc578b2bfd" - "8b5f20acef13d8ba6a4ccfd406f29a60e1af4151212a062c62c71d894fe6d5524e1b28af" - "1d51d2b806aca778f77fd0e4ef278c4fbd5eb756398d646bb50d3a13d8687ad304005b0b" - "0a054e5109d70dec9953b2f99768fca8fe51957dc4608fd34c999a7b35245bce2795715d" - "8a5957a0872398473eed486029286f51d4118927e88634ad040034e061fd3f5863296176" - "1b1fbb8faf45391d84f7ffe2bf5e27bd499eee14a17bc8be2fd258331e7a86baa7394706" - "424420f6eaba0001bffe74976a5b4cc46380ceef9ce93b3bb73008150203010001a38201" - "3430820130301d0603551d0e041604147266b4ce84aafd02b1159cd2fa04c2553c6c0246" - "3081bb0603551d230481b33081b0a181a2a4819f30819c310b3009060355040613025553" - "3113301106035504080c0a57617368696e67746f6e3111300f06035504070c084b69726b" - "6c616e64310f300d060355040a0c06476f6f676c653111300f060355040b0c0857696465" - "76696e65311e301c06035504030c157769646576696e652d6465762d636f64657369676e" - "3121301f06092a864886f70d010901161274696e736b697040676f6f676c652e636f6d82" - "0900c5f82f038facf15830090603551d1304023000300b0603551d0f0404030207803013" - "0603551d25040c300a06082b060105050703033011060a2b06010401d679040102040301" - "01ff3011060a2b06010401d67904010304030101ff300d06092a864886f70d01010b0500" - "038201810069482a9bb125b17c76c77f86004e36ca4fc36bbde9c86901481c70d165e3cf" - "1c8541264190b3e7106c33ff4920a99bc9f939298091dc72ff898d22f5017b04d213eb60" - "626382656fdd66b9cd1830d98ef89d8e405b2d7ce9445db8de2ca365438b848f85d5266b" - "c211c8934154bb88ddb9e6f9aaff761814c1c0da90dd499f174507b5f4e89339e8abd157" - "8b3238d8f5c9dcb1f76e4d810679c2eca3583144f1ac0ce955b7c6a2cc9fc9f3d6c87069" - "28e301ebc3844e53f4905ff60803110dfc3b4f74b50ae1baffd091daad3ea29925f8009e" - "adc471a9ae673d9a9a003901d962f58fede85b2f65d9a470725459b19a69b06ae49179a3" - "395286b7d7039b32985a6db5b30bcd5cbed975d9a68de44fbcd1dbc8b6fbf67746b87d30" - "122c1cd8ed303a8bec7e23d284c0de35cfdccf261c317efe192efa84d2600bba3f9af846" - "8f89953a98f92c97b13d320f484627790d5b7b407f29f343c41154efbcf06e98632a3f3d" - "7138184a6f40af2435b3d98054ed9f4c3aa9ecf95c5c3014d3aa4d12f2"; - -const char kSameAsPrevious[] = ""; - -} // namespace - -class VmpCheckerTest : public ::testing::Test { - public: - void SetUp() override { - ASSERT_OK( - VmpChecker::Instance()->SelectCertificateType(kCertificateTypeTesting)); - vmp_data_.Clear(); - VmpChecker::Instance()->set_allow_development_vmp(true); - signing_key_.reset( - RsaPrivateKey::Create(absl::HexStringToBytes(kDevVmpCodeSigningKey))); - ASSERT_TRUE(signing_key_); - } - - // Adds a binary to the VMP data to be verified. If |signing_cert| is - // |kSameAsPrevious| (empty), then the binary is signed using the same - // certificate as the previously added binary. This means that the first - // call to this function should not use |kSameAsPrevious|. - void AddVmpBinary(const std::string& signing_cert, - const std::string& file_name, - const std::string& binary_hash, uint32_t flags) { - DCHECK(!signing_cert.empty() || !vmp_data_.certificates().empty()); - - if (!signing_cert.empty()) { - *vmp_data_.add_certificates() = absl::HexStringToBytes(signing_cert); - } - vmp::VmpData::SignedBinaryInfo* new_binary = - vmp_data_.add_signed_binary_info(); - new_binary->set_file_name(file_name); - new_binary->set_certificate_index(vmp_data_.certificates_size() - 1); - new_binary->set_binary_hash(binary_hash); - new_binary->set_flags(flags); - std::string message(binary_hash); - message += flags & 0xff; - std::string signature; - ASSERT_TRUE(signing_key_->GenerateSignature( - message, HashAlgorithmProtoToEnum(new_binary->hash_algorithm()), - &signature)); - new_binary->set_signature(signature); - } - - const std::string GetVmpData() { - std::string result; - vmp_data_.SerializeToString(&result); - return result; - } - - protected: - vmp::VmpData vmp_data_; - std::unique_ptr signing_key_; -}; - -TEST_F(VmpCheckerTest, Success) { - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevSecureStorageVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kVerified, result); -} - -TEST_F(VmpCheckerTest, SecureStorageSuccess) { - AddVmpBinary(kDevSecureStorageVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevSecureStorageVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kSecureStorageVerified, result); -} - -TEST_F(VmpCheckerTest, FailDevelopmentCert) { - VmpChecker::Instance()->set_allow_development_vmp(false); - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - VmpChecker::Result result; - EXPECT_EQ(DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, - VmpChecker::Instance() - ->VerifyVmpData(GetVmpData(), &result) - .error_code()); -} - -TEST_F(VmpCheckerTest, FailTwoBlessedBinaries) { - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - vmp_data_.mutable_signed_binary_info(0)->set_flags(kBlessedBinaryFlag); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kTampered, result); -} - -TEST_F(VmpCheckerTest, FailNoBlessedBinaries) { - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - vmp_data_.mutable_signed_binary_info(3)->set_flags(0); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kTampered, result); -} - -TEST_F(VmpCheckerTest, FailBadSignature) { - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - ++((*vmp_data_.mutable_signed_binary_info(2)->mutable_signature())[10]); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kTampered, result); -} - -TEST_F(VmpCheckerTest, FailSignatureVerification) { - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - ++((*vmp_data_.mutable_signed_binary_info(3)->mutable_binary_hash())[16]); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kTampered, result); -} - -TEST_F(VmpCheckerTest, FailUnsignedBinary) { - AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe", - "0123456789abdef0123456789abdef", 0); - AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - 0); - AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll", - "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0); - AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc", - kBlessedBinaryFlag); - vmp_data_.mutable_signed_binary_info(2)->clear_binary_hash(); - VmpChecker::Result result; - ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result)); - EXPECT_EQ(VmpChecker::kTampered, result); -} - -} // namespace widevine diff --git a/common/widevine_system_id.cc b/common/widevine_system_id.cc deleted file mode 100644 index 3caf4ac..0000000 --- a/common/widevine_system_id.cc +++ /dev/null @@ -1,19 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// -// -// Common Encryption (CENC) system ID for Widevine DRM. - -#include "common/widevine_system_id.h" - -namespace widevine { - -const uint8_t kWidevineSystemId[16] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, - 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, - 0xd5, 0x1d, 0x21, 0xed}; - -} // namespace widevine diff --git a/common/widevine_system_id.h b/common/widevine_system_id.h deleted file mode 100644 index 4b02791..0000000 --- a/common/widevine_system_id.h +++ /dev/null @@ -1,22 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// -// -// Common Encryption (CENC) system ID for Widevine DRM. - -#ifndef COMMON_WIDEVINE_SYSTEM_ID_H_ -#define COMMON_WIDEVINE_SYSTEM_ID_H_ - -#include - -namespace widevine { - -extern const uint8_t kWidevineSystemId[16]; - -} // namespace widevine - -#endif // COMMON_WIDEVINE_SYSTEM_ID_H_ diff --git a/common/wvm_test_keys.cc b/common/wvm_test_keys.cc deleted file mode 100644 index c0842a7..0000000 --- a/common/wvm_test_keys.cc +++ /dev/null @@ -1,87 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/wvm_test_keys.h" - -#include - -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "common/wvm_token_handler.h" - -namespace widevine { -namespace wvm_test_keys { - -// Preprov key and keyboxes in this header use system ID 0x112. -const char kTestPreprovKeyHex[] = "f7538b38acc78ec68c732ac665c55c65"; -const char kBadPreprovKey1Hex[] = "1badbadbadbadbadbadbadbadbadbad1"; -const char kBadPreprovKey2Hex[] = "2badbadbadbadbadbadbadbadbadbad2"; - -const char kTestToken1Hex[] = - "00000002000001128e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"; - -// The device key corresponding to kTestToken1. -const char kTestDeviceKey1Hex[] = "4071197f1f8910d9bf10c6bc4c987638"; - -// Base64Encode(kTestToken1) -const char kTestToken1Base64[] = - "AAAAAgAAARKOHr/gN4KAlsplOLT29Ly1HCtxkc8Dfpi+qiSSSQfhKPn/SbVKFlzZ" - "wz5lR1N+tNKft+jfPCwc2SUXoS9JIpU+"; - -const char kTestToken2Hex[] = - "0000000200000112d906feebe1750c5886ff77c2dfa31bb40e002f3adbc0fa5b" - "eb2486cf5f419549cdaa23230e5165ac2ffab56d53b692b7ba0c1857400c6add" - "3af3ff3d5cb24985"; - -// The device key corresponding to kTestToken2. -const char kTestDeviceKey2Hex[] = "42cfb1765201042302a404d1e0fac8ed"; - -// Base64Encode(kTestToken2) -const char kTestToken2Base64[] = - "AAAAAgAAARLZBv7r4XUMWIb/d8Lfoxu0DgAvOtvA+lvrJIbPX0GVSc2qIyMOUWWs" - "L/q1bVO2kre6DBhXQAxq3Trz/z1cskmF"; - -const char kTestToken3DesHex[] = - "00000002100000138e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"; - -const char kTestDeviceKey3DesHex[] = "4071197f1f8910d9bf10c6bc4c987638"; - -std::vector GetPreprovKeyVector() { - return { - // Return multiple preprov keys for the same device. - WvmTokenHandler::PreprovKey(kTestSystemId, - absl::HexStringToBytes(kBadPreprovKey1Hex)), - WvmTokenHandler::PreprovKey(kTestSystemId, - absl::HexStringToBytes(kTestPreprovKeyHex)), - WvmTokenHandler::PreprovKey(kTestSystemId, - absl::HexStringToBytes(kBadPreprovKey2Hex)), - - // Add another device that uses 3DES encryption for asset keys. Tokens - // the same except for the system ID portion. - WvmTokenHandler::PreprovKey(kTestSystemId3Des, - absl::HexStringToBytes(kTestPreprovKeyHex), - WvmTokenHandler::DES3), - }; -} - -std::map GetPreprovKeyTable() { - return {{kTestSystemId, std::string(kTestPreprovKeyHex)}}; -} - -std::multimap GetPreprovKeyMultimap() { - return {{kTestSystemId, kBadPreprovKey1Hex}, - {kTestSystemId, kTestPreprovKeyHex}, - {kTestSystemId, kBadPreprovKey2Hex}}; -} - -} // namespace wvm_test_keys -} // namespace widevine diff --git a/common/wvm_test_keys.h b/common/wvm_test_keys.h deleted file mode 100644 index b39d194..0000000 --- a/common/wvm_test_keys.h +++ /dev/null @@ -1,58 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -// Sample keys for use in tests of Widevine WVM crypto code. - -#ifndef COMMON_WVM_TEST_KEYS_H_ -#define COMMON_WVM_TEST_KEYS_H_ - -#include -#include -#include - -#include -#include "common/wvm_token_handler.h" - -namespace widevine { -namespace wvm_test_keys { - -// Most preprov key and keyboxes in this header use system ID 0x112. -const uint32_t kTestSystemId = 0x112; - -// One oddball system that uses 3DES. (We'll re-use the system and device keys). -const uint32_t kTestSystemId3Des = 0x10000013; - -extern const char kTestPreprovKeyHex[]; - -extern const char kTestToken1Hex[]; -extern const char kTestDeviceKey1Hex[]; - -extern const char kTestToken2Hex[]; -extern const char kTestDeviceKey2Hex[]; - -extern const char kTestToken3DesHex[]; -extern const char kTestDeviceKey3DesHex[]; - -// Return a list of preprovisioning keys, suitable for initializing -// the preprov key table for tests. -std::vector GetPreprovKeyVector(); - -// Old version of GetPreprovKeyTable() which uses a simple int->std::string -// map. Doesn't support multiple devices per system ID. -// TODO(user): get rid of this once other code as been migrated off of it. -std::map GetPreprovKeyTable(); - -// Version of GetPreprovKeyTable() which uses a simple int->hex_string -// multimap, useful for modular DRM code which doesn't care about the asset -// key cipher. -std::multimap GetPreprovKeyMultimap(); - -} // namespace wvm_test_keys -} // namespace widevine - -#endif // COMMON_WVM_TEST_KEYS_H_ diff --git a/common/wvm_token_handler.cc b/common/wvm_token_handler.cc deleted file mode 100644 index 11e3cb8..0000000 --- a/common/wvm_token_handler.cc +++ /dev/null @@ -1,315 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/wvm_token_handler.h" - -#include - -#include "glog/logging.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/string_view.h" -#include "absl/synchronization/mutex.h" -#include "util/endian/endian.h" -#include "util/gtl/map_util.h" -#include "common/aes_cbc_util.h" -#include "common/ecb_util.h" -#include "common/sha_util.h" -#include "common/status.h" - -namespace widevine { - -namespace { -const int kKeyboxFlagInsecure = 1; -const int kSystemIdSamsungTVFactory = 8; -const int kPreProvisioningKeySizeBytes = 16; -const int kKeyboxSizeBytes = 72; -const std::string kZeroIV(16, '\0'); - -class PreprovKeysMap { - public: - void Update(const std::vector& key_vector); - std::vector GetPreprovKeys(uint32_t system_id); - bool IsSystemIdKnown(uint32_t system_id); - bool IsEmpty(); - - static PreprovKeysMap* GetSingleton(); - - private: - absl::Mutex mutex_; - std::multimap preprov_keys_; -}; - -void PreprovKeysMap::Update( - const std::vector& key_vector) { - absl::WriterMutexLock lock(&mutex_); - preprov_keys_.clear(); - for (const WvmTokenHandler::PreprovKey& ppk : key_vector) { - if (ppk.key_bytes.size() != kPreProvisioningKeySizeBytes) { - LOG(WARNING) << "Invalid preprov key for system id: " << ppk.system_id; - continue; - } - preprov_keys_.insert(std::make_pair(ppk.system_id, ppk)); - } -} - -std::vector PreprovKeysMap::GetPreprovKeys( - uint32_t system_id) { - absl::ReaderMutexLock lock(&mutex_); - std::vector key_vector; - auto range = preprov_keys_.equal_range(system_id); - for (auto it = range.first; it != range.second; ++it) - key_vector.push_back(it->second); - return key_vector; -} - -bool PreprovKeysMap::IsSystemIdKnown(uint32_t system_id) { - absl::ReaderMutexLock lock(&mutex_); - return gtl::ContainsKey(preprov_keys_, system_id); -} - -bool PreprovKeysMap::IsEmpty() { - absl::ReaderMutexLock lock(&mutex_); - return preprov_keys_.empty(); -} - -PreprovKeysMap* PreprovKeysMap::GetSingleton() { - static auto* const kInstance = new PreprovKeysMap(); - return kInstance; -} - -} // namespace - -WvmTokenHandler::PreprovKey::PreprovKey(uint32_t system_id, - const std::string& key_bytes, - Cipher cipher, - const std::string& model_filter) - : system_id(system_id), - key_bytes(key_bytes), - cipher(cipher), - model_filter(model_filter) {} - -WvmTokenHandler::PreprovKey::PreprovKey(uint32_t system_id, - const std::string& key_bytes, - Cipher cipher) - : system_id(system_id), key_bytes(key_bytes), cipher(cipher) {} - -WvmTokenHandler::PreprovKey::PreprovKey(uint32_t system_id, - const std::string& key_bytes) - : system_id(system_id), key_bytes(key_bytes), cipher(AES) {} - -void WvmTokenHandler::SetPreprovKeys(const std::vector& keyvec) { - PreprovKeysMap::GetSingleton()->Update(keyvec); -} - -bool WvmTokenHandler::IsSystemIdKnown(uint32_t system_id) { - return PreprovKeysMap::GetSingleton()->IsSystemIdKnown(system_id); -} - -Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, - std::string* device_key_out, - Cipher* cipher_out, - bool* insecure_out) { - const std::string default_make_model; - return DecryptDeviceKey(token, default_make_model, device_key_out, cipher_out, - insecure_out); -} - -Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, - const std::string& make_model, - std::string* device_key_out, - Cipher* cipher_out, - bool* insecure_out) { - DCHECK(device_key_out); - // DCHECK below is commented out because preprov_keys_ being nullptr - // is a valid test in wvm_token_handler_test.cc. If we have - // DCHECK(preprov_keys_) here it would thrown an failure in Kokoro - // presubmit because evidently Kokoro does debug build. - // DCHECK(preprov_keys_); - if (token.size() < kKeyboxSizeBytes) { - return Status(error::INVALID_ARGUMENT, "Keybox token is too short."); - } - if (PreprovKeysMap::GetSingleton()->IsEmpty()) { - return Status(error::INVALID_ARGUMENT, - "Pre-provisioning key map is nullptr."); - } - - uint32_t system_id = GetSystemId(token); - - // There may be multiple preprov keys for a system ID; try them all. - std::vector key_vector = - PreprovKeysMap::GetSingleton()->GetPreprovKeys(system_id); - - Status status; - // First pass through the matching system Ids is an attempt to find an - // alternate preprov key specific to this make/model. - const PreprovKey* preferred_ppk = NULL; - for (const PreprovKey& ppk : key_vector) { - if (!ppk.model_filter.empty() && ppk.model_filter == make_model) { - preferred_ppk = &ppk; - break; - } - } - for (const PreprovKey& ppk : key_vector) { - if (preferred_ppk && preferred_ppk != &ppk) { - continue; - } - uint32_t version; - status = DecryptDeviceKeyWithPreprovKey( - ppk.key_bytes, token, device_key_out, insecure_out, &version); - if (version != 2) { - // Only version 2 keyboxes supported. - return Status(error::PERMISSION_DENIED, - absl::StrCat("invalid-keybox-version ", version)); - } - if (status.ok()) { - if (cipher_out) { - *cipher_out = ppk.cipher; - } - return status; - } - } - if (!status.ok()) { - // Return error from last attempt. - return status; - } - return Status( - error::NOT_FOUND, - absl::StrCat("Unknown system id: ", system_id).c_str()); // NOLINT -} - -// Decrypt a token using the preprov key for its system ID, and use the -// decrypted device key to encrypt the given asset key. Returns the encrypted -// asset key in |result|. -// On failure, returns an error from the Widevine Server SDK error space. -Status WvmTokenHandler::GetEncryptedAssetKey(absl::string_view token, - absl::string_view raw_asset_key, - const std::string& make_model, - std::string* result) { - std::string device_key; - Cipher cipher = AES; - Status status = - DecryptDeviceKey(token, make_model, &device_key, &cipher, nullptr); - if (!status.ok()) { - return status; - } - return EncryptAssetKey(device_key, raw_asset_key, cipher, result); -} - -uint32_t WvmTokenHandler::GetSystemId(absl::string_view token) { - uint32_t system_id = 0; - if (token.size() >= 8) { - // Bytes 4-8 contain the little-endian system ID. - system_id = BigEndian::Load32(token.data() + 4); - } - return system_id; -} - -std::string WvmTokenHandler::GetEncryptedUniqueId(absl::string_view token) { - std::string encrypted_unique_id(""); - if (token.size() >= 24) { - encrypted_unique_id = std::string(token.substr(8, 16)); - } - return encrypted_unique_id; -} - -Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( - absl::string_view preprov_key, absl::string_view token, - std::string* device_key_out) { - return DecryptDeviceKeyWithPreprovKey(preprov_key, token, device_key_out, - nullptr, nullptr); -} - -Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( - absl::string_view preprov_key, absl::string_view token, - std::string* device_key_out, bool* insecure_out, uint32_t* version) { - CHECK(device_key_out); - if (token.size() < kKeyboxSizeBytes) { - return Status(error::INVALID_ARGUMENT, "Keybox token is too short."); - } - if (version) { - // Bytes 0-3 contain the keybox version. - *version = BigEndian::Load32(token.data()); - } - - // This was checked at initialization, so if it fails now something is wrong. - CHECK_EQ(preprov_key.size(), kPreProvisioningKeySizeBytes); - - absl::string_view encrypted_unique_id = token.substr(8, 16); - std::string unique_id = crypto_util::DecryptAesCbcNoPad( - std::string(preprov_key), kZeroIV, std::string(encrypted_unique_id)); - - if (unique_id.size() != 16) { - // Decrypting 16 bytes should result in 16 bytes. - LOG(WARNING) << "Internal error decrypting unique id from token."; - return Status(error::INTERNAL, "Wrong size after decrypt/16."); - } - - absl::string_view encrypted_bits = token.substr(24, 48); - std::string decrypted_bits = crypto_util::DecryptAesCbcNoPad( - unique_id, kZeroIV, std::string(encrypted_bits)); - if (decrypted_bits.size() != 48) { - // Decrypting 48 bytes should result in 48 bytes. - LOG(WARNING) << "Internal error decrypting device key from token."; - return Status(error::INTERNAL, "Wrong size after decrypt/48."); - } - uint8_t keybox_flags = decrypted_bits[36]; - absl::string_view device_key = - absl::string_view(decrypted_bits).substr(0, 16); - absl::string_view expected_hash = - absl::string_view(decrypted_bits).substr(16, 20); - std::string actual_hash = Sha1_Hash(std::string(device_key)); - - if (GetSystemId(token) == kSystemIdSamsungTVFactory) { - // Keyboxes with this system ID have corrupted bytes starting after the - // first 16 bytes of the hash, so we use only the uncorrupted part. - expected_hash = expected_hash.substr(0, 16); - actual_hash.resize(16); - keybox_flags = 0; - } - if (expected_hash != actual_hash) { - return Status(error::PERMISSION_DENIED, "Keybox validation failed."); - } - *device_key_out = std::string(device_key); - if (insecure_out) { - *insecure_out = (keybox_flags & kKeyboxFlagInsecure) != 0; - } - return OkStatus(); -} - -Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key, - absl::string_view raw_asset_key, - Cipher cipher, std::string* result) { - CHECK(result); - if (device_key.size() != 16) { - return Status(error::INVALID_ARGUMENT, "Invalid device key: size != 16"); - } - if (raw_asset_key.size() < 16) { - return Status(error::INVALID_ARGUMENT, "Invalid asset key: size < 16"); - } - // Truncate extra characters in the key; wvm always uses 16. - absl::string_view asset_key = raw_asset_key.substr(0, 16); - switch (cipher) { - case DES3: - if (!crypto_util::Encrypt3DesEcb(device_key, asset_key, result)) { - return Status(error::INTERNAL, "Error encrypting asset key with 3DES."); - } - return OkStatus(); - case AES: - if (!crypto_util::EncryptAesEcb(device_key, asset_key, result)) { - return Status(error::INTERNAL, "Error encrypting asset key with AES."); - } - return OkStatus(); - case PASS_THRU: - result->assign(raw_asset_key.data(), raw_asset_key.size()); - return OkStatus(); - default: - return Status(error::INVALID_ARGUMENT, "Unknown cipher type"); - } -} - -} // namespace widevine diff --git a/common/wvm_token_handler.h b/common/wvm_token_handler.h deleted file mode 100644 index 1250f2a..0000000 --- a/common/wvm_token_handler.h +++ /dev/null @@ -1,125 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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_WVM_TOKEN_HANDLER_H_ -#define COMMON_WVM_TOKEN_HANDLER_H_ - -#include -#include - -#include "absl/strings/string_view.h" -#include "common/status.h" - -namespace widevine { - -// Class for decoding the encrypted token that comes from a WVM classic keybox. -// -// Internally, this class keeps a multimap from system ID to the preprov key(s) -// for that system, so construction is relatively expensive; don't create an -// instance of this class per-request. -// -// Errors in this file are returned in the canonical space, but are chosen so -// that it's possible to map different failure modes to the appropriate codes -// in the WVM or server SDK error spaces: -// OK - success. -// NOT_FOUND - system id from token wasn't in the preprov key table. -// PERMISSION_DENIED - hash of device key didn't match. -// INVALID_ARGUMENT - token or a key is wrong size or otherwise invalid. -// INTERNAL_ERROR - something went wrong that shouldn't have been able to. -class WvmTokenHandler { - public: - WvmTokenHandler(const WvmTokenHandler&) = delete; - WvmTokenHandler& operator=(const WvmTokenHandler&) = delete; - - // Cipher type to use for encrypting asset keys. This matches the enum in - // video/widevine/lockbox/public/key.proto. - enum Cipher { - DES3 = 0, - AES = 1, - PASS_THRU = 2, - }; - - struct PreprovKey { - // Utility constructor. - PreprovKey(uint32_t system_id, const std::string& key_bytes, Cipher cipher, - const std::string& model_filter); - PreprovKey(uint32_t system_id, const std::string& key_bytes, Cipher cipher); - // Constructor if the cipher isn't needed (i.e. modular DRM). - PreprovKey(uint32_t system_id, const std::string& key_bytes); - uint32_t system_id; - std::string key_bytes; - Cipher cipher; - // If set, the make/model in the license request must match this value. - std::string model_filter; - }; - - // Set pre-provisioning keys from the given vector. This may be called - // concurrently with other methods. - static void SetPreprovKeys(const std::vector& preprov_keys); - - // Returns true if system_id is in the preprov key table. - static bool IsSystemIdKnown(uint32_t system_id); - - // Decrypt a token using the preprov key for its system ID, and - // return the decrypted device key in result. - // On failure, returns one of the errors listed above. - // cipher_out may be null; if not, *cipher_out will be set to the cipher type - // to use with the device key. - // insecure_out may be null; if not, *insecure_out will be set to the - // decrypted value of the 'insecure keybox' flag. - static Status DecryptDeviceKey(absl::string_view token, - std::string* device_key_out, - Cipher* cipher_out, bool* insecure_out); - // Same as above, except takes in the make/model from the license request. - // For legacy WVM license, we have some special cases where we need to inspect - // the make/model as we apply alternate keys. - static Status DecryptDeviceKey(absl::string_view token, - const std::string& make_model, - std::string* device_key_out, - Cipher* cipher_out, bool* insecure_out); - - // Decrypt a token using the preprov key for its system ID, and use the - // decrypted device key to encrypt the given asset key. Returns the encrypted - // asset key in result. - static Status GetEncryptedAssetKey(absl::string_view token, - absl::string_view raw_asset_key, - const std::string& make_model, - std::string* result); - - // Extract the system ID component of a token (bytes 4-8). - static uint32_t GetSystemId(absl::string_view token); - - // Extract the encrypted unique ID component of a token (bytes 8-24). - static std::string GetEncryptedUniqueId(absl::string_view token); - - // Try to decrypt a token using the provided preprov key, and return the - // decrypted device key in result. - // - // Note that the if the input std::string lengths are correct (16 and 72 bytes), - // the only possible cause of failure is the decrypted device key hash - // being incorrect. - static Status DecryptDeviceKeyWithPreprovKey( - absl::string_view preprov_key_bytes, absl::string_view token, - std::string* device_key_out); - - // Same as above, but allows extracting the 'insecure keybox' flag and keybox - // version. - static Status DecryptDeviceKeyWithPreprovKey( - absl::string_view preprov_key_bytes, absl::string_view token, - std::string* device_key_out, bool* insecure_out, uint32_t* version); - - // Given a decrypted device key as returned by DecryptToken(), use it to - // encrypt an asset key with the given cipher. - static Status EncryptAssetKey(absl::string_view device_key, - absl::string_view raw_asset_key, Cipher cipher, - std::string* result); -}; - -} // namespace widevine - -#endif // COMMON_WVM_TOKEN_HANDLER_H_ diff --git a/common/wvm_token_handler_test.cc b/common/wvm_token_handler_test.cc deleted file mode 100644 index 872096a..0000000 --- a/common/wvm_token_handler_test.cc +++ /dev/null @@ -1,230 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2016 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/wvm_token_handler.h" - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "absl/strings/string_view.h" -#include "common/wvm_test_keys.h" - -using widevine::wvm_test_keys::GetPreprovKeyVector; -using widevine::wvm_test_keys::kTestDeviceKey1Hex; -using widevine::wvm_test_keys::kTestDeviceKey2Hex; -using widevine::wvm_test_keys::kTestDeviceKey3DesHex; -using widevine::wvm_test_keys::kTestPreprovKeyHex; -using widevine::wvm_test_keys::kTestSystemId; -using widevine::wvm_test_keys::kTestSystemId3Des; -using widevine::wvm_test_keys::kTestToken1Hex; -using widevine::wvm_test_keys::kTestToken2Hex; -using widevine::wvm_test_keys::kTestToken3DesHex; - -namespace widevine { - -using absl::BytesToHexString; -using absl::HexStringToBytes; - -TEST(WvmTokenHandlerTest, GetSystemId) { - EXPECT_EQ(kTestSystemId, - WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken1Hex))); - EXPECT_EQ(kTestSystemId, - WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken2Hex))); -} - -TEST(WvmTokenHandlerTest, GetEncryptedUniqueId) { - EXPECT_EQ( - HexStringToBytes("8e1ebfe037828096ca6538b4f6f4bcb5"), - WvmTokenHandler::GetEncryptedUniqueId(HexStringToBytes(kTestToken1Hex))); - EXPECT_EQ( - HexStringToBytes("d906feebe1750c5886ff77c2dfa31bb4"), - WvmTokenHandler::GetEncryptedUniqueId(HexStringToBytes(kTestToken2Hex))); -} - -TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) { - Status status; - std::string device_key; - - status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( - HexStringToBytes(kTestPreprovKeyHex), HexStringToBytes(kTestToken1Hex), - &device_key); - EXPECT_OK(status) << status; - EXPECT_EQ(kTestDeviceKey1Hex, BytesToHexString(device_key)); - - status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( - HexStringToBytes(kTestPreprovKeyHex), HexStringToBytes(kTestToken2Hex), - &device_key); - EXPECT_OK(status); - EXPECT_EQ(kTestDeviceKey2Hex, BytesToHexString(device_key)); - - // Test with invalid token. Hash failure should produce PERMISSION_DENIED. - device_key.clear(); - std::string token = HexStringToBytes( - "00000002000001129e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"); - status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( - HexStringToBytes(kTestPreprovKeyHex), token, &device_key); - EXPECT_FALSE(status.ok()); - EXPECT_EQ(error::PERMISSION_DENIED, status.error_code()); - EXPECT_TRUE(device_key.empty()); -} - -// See b/68798704 for background of this test. -// It is important to keep this test *before* all the DecryptDeviceKey* tests -// below, in which WvmTokenHandler::SetPreprovKeys() would be called. -TEST(WvmTokenHandlerTest, DecryptDeviceKey_PreprovKeysNullPtr) { - // Not calling WvmTokenHandler::SetPreprovKeys() - // So preprov_keys_ would be nullptr. - Status status; - std::string device_key; - status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex), - &device_key, nullptr, nullptr); - EXPECT_FALSE(status.ok()); - EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code()); -} - -// Same tests as DecryptDeviceKeyWithPreprovKey(), but we use the handler's -// table of preprov keys instead of providing our own. -TEST(WvmTokenHandlerTest, DecryptDeviceKey) { - Status status; - std::string device_key; - WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector()); - - status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex), - &device_key, nullptr, nullptr); - EXPECT_OK(status); - EXPECT_EQ(HexStringToBytes(kTestDeviceKey1Hex), device_key); - - status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken2Hex), - &device_key, nullptr, nullptr); - EXPECT_OK(status); - EXPECT_EQ(HexStringToBytes(kTestDeviceKey2Hex), device_key); - - // Test with invalid token. Hash failure should produce PERMISSION_DENIED. - device_key.clear(); - std::string token = HexStringToBytes( - "00000002000001129e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"); - status = - WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr); - EXPECT_FALSE(status.ok()); - EXPECT_EQ(error::PERMISSION_DENIED, status.error_code()); - EXPECT_TRUE(device_key.empty()); - - // Test with nonexistent system id. Should produce NOT_FOUND. - device_key.clear(); - token = HexStringToBytes( - "00000002555555559e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" - "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" - "2517a12f4922953e"); - status = - WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr); - EXPECT_FALSE(status.ok()); - EXPECT_EQ(error::NOT_FOUND, status.error_code()); - EXPECT_TRUE(device_key.empty()); -} - -TEST(WvmTokenHandlerTest, GetEncryptedAssetKey) { - WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector()); - - std::string raw_asset_key = "asset-key-000000"; - std::string asset_key; - std::string make_model; - Status status = WvmTokenHandler::GetEncryptedAssetKey( - HexStringToBytes(kTestToken1Hex), raw_asset_key, make_model, &asset_key); - EXPECT_OK(status); - EXPECT_EQ("305d5f979074b1c4f932be70d3cc850c", BytesToHexString(asset_key)); - - status = WvmTokenHandler::GetEncryptedAssetKey( - HexStringToBytes(kTestToken2Hex), raw_asset_key, make_model, &asset_key); - EXPECT_OK(status); - EXPECT_EQ("091802159bf8da12aecfcdfb092075c8", BytesToHexString(asset_key)); - - // Check 3DES encryption of asset keys - status = WvmTokenHandler::EncryptAssetKey( - HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key, - WvmTokenHandler::DES3, &asset_key); - EXPECT_OK(status); - EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key)); - - asset_key.clear(); - status = WvmTokenHandler::GetEncryptedAssetKey( - HexStringToBytes(kTestToken3DesHex), raw_asset_key, make_model, - &asset_key); - EXPECT_OK(status); - EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key)); - - // Test with pass-thru (Cipher=PASS_THRU). - asset_key.clear(); - status = WvmTokenHandler::EncryptAssetKey( - HexStringToBytes(kTestDeviceKey1Hex), raw_asset_key, - WvmTokenHandler::PASS_THRU, &asset_key); - - EXPECT_OK(status); - EXPECT_EQ(BytesToHexString(raw_asset_key), BytesToHexString(asset_key)); -} - -TEST(WvmTokenHandlerTest, FilterOnMakeModel) { - // Use all good keys, but only the key for LG:BD572 should work. It works - // by setting only that one to DES3. All other AES ppks will encrypt the - // asset key incorrectly. - std::vector ppks; - ppks.push_back(WvmTokenHandler::PreprovKey( - kTestSystemId3Des, HexStringToBytes(kTestPreprovKeyHex), - WvmTokenHandler::AES, "")); - ppks.push_back(WvmTokenHandler::PreprovKey( - kTestSystemId3Des, HexStringToBytes(kTestPreprovKeyHex), - WvmTokenHandler::DES3, "LG:BD572")); - ppks.push_back(WvmTokenHandler::PreprovKey( - kTestSystemId3Des, HexStringToBytes(kTestPreprovKeyHex), - WvmTokenHandler::AES, "")); - WvmTokenHandler::SetPreprovKeys(ppks); - std::string raw_asset_key = "asset-key-000000"; - std::string asset_key; - // Check 3DES encryption of asset keys - Status status = WvmTokenHandler::EncryptAssetKey( - HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key, - WvmTokenHandler::DES3, &asset_key); - EXPECT_OK(status); - EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key)); - - asset_key.clear(); - std::string make_model; - status = WvmTokenHandler::GetEncryptedAssetKey( - HexStringToBytes(kTestToken3DesHex), raw_asset_key, make_model, - &asset_key); - EXPECT_OK(status); - // Should fail because the asset key was encrypted with AES instead of DES3. - EXPECT_NE("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key)); - - // Set the make/model so we find and use the correct ppk. - make_model = "LG:BD572"; - status = WvmTokenHandler::GetEncryptedAssetKey( - HexStringToBytes(kTestToken3DesHex), raw_asset_key, make_model, - &asset_key); - EXPECT_OK(status); - // Should work because the asset key was encrypted with DES3. - EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key)); -} - -TEST(WvmTokenHandlerTest, AncientKeybox) { - Status status; - std::string device_key; - - std::string v1_token( - std::string(kTestPreprovKeyHex).replace(0, 16, "0000000100000001")); - status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( - HexStringToBytes(v1_token), HexStringToBytes(kTestToken1Hex), - &device_key); - EXPECT_EQ(error::PERMISSION_DENIED, status.error_code()); - EXPECT_TRUE(device_key.empty()); -} - -} // namespace widevine diff --git a/common/x509_cert.cc b/common/x509_cert.cc deleted file mode 100644 index 8627f6e..0000000 --- a/common/x509_cert.cc +++ /dev/null @@ -1,459 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/x509_cert.h" - -#include - -#include -#include "glog/logging.h" -#include "absl/strings/escaping.h" -#include "absl/synchronization/mutex.h" -#include "openssl/bio.h" -#include "openssl/evp.h" -#include "openssl/pem.h" -#include "openssl/pkcs7.h" -#include "openssl/x509.h" -#include "openssl/x509v3.h" -#include "common/openssl_util.h" -#include "common/rsa_key.h" - -namespace { -// Serializes the X509 |certificate| into a PEM-encoded string. Returns true -// on success, false otherwise. The caller retains ownership of -// |certificate| and |serialized_certificate|. |serialized_certificate| must -// not be NULL. -bool PemEncodeX509Certificate(const X509& certificate, - std::string* serialized_certificate) { - CHECK(serialized_certificate) << "serialized_certificate can not be null."; - - ScopedBIO bio(BIO_new(BIO_s_mem())); - if (bio == nullptr) { - return false; - } - - // The const_cast is necessary for the openssl call. - PEM_write_bio_X509(bio.get(), const_cast(&certificate)); - int serialized_size = BIO_pending(bio.get()); - serialized_certificate->resize(serialized_size); - if (BIO_read(bio.get(), &(*serialized_certificate)[0], serialized_size) != - serialized_size) { - return false; - } - - return true; -} - -} // anonymous namespace. - -namespace widevine { - -std::unique_ptr X509Cert::FromOpenSslCert(ScopedX509 certificate) { - return std::unique_ptr(new X509Cert(certificate.release())); -} - -X509Cert::X509Cert() : openssl_cert_(NULL) {} - -X509Cert::~X509Cert() { - if (openssl_cert_ != NULL) { - X509_free(openssl_cert_); - } -} - -X509Cert::X509Cert(X509* openssl_cert) : openssl_cert_(openssl_cert) {} - -Status X509Cert::LoadPem(const std::string& pem_cert) { - if (pem_cert.empty()) { - return Status(error::INVALID_ARGUMENT, "Empty PEM certificate"); - } - BIO* bio(NULL); - X509* new_cert(NULL); - bio = BIO_new_mem_buf(const_cast(pem_cert.data()), pem_cert.size()); - if (bio == NULL) { - return Status(error::INTERNAL, "BIO allocation failed"); - } - Status status; - new_cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); - if (new_cert == NULL) { - status = Status(error::INVALID_ARGUMENT, "PEM certificate load failed"); - goto cleanup; - } - if (openssl_cert_ != NULL) { - X509_free(openssl_cert_); - } - openssl_cert_ = new_cert; - -cleanup: - if (bio != NULL) { - BIO_free(bio); - } - return status; -} - -Status X509Cert::LoadDer(const std::string& der_cert) { - if (der_cert.empty()) { - return Status(error::INVALID_ARGUMENT, "Empty DER certificate"); - } - const unsigned char* cert_data = - reinterpret_cast(der_cert.data()); - X509* new_cert = d2i_X509(NULL, &cert_data, der_cert.size()); - if (new_cert == NULL) { - return Status(error::INVALID_ARGUMENT, "DER certificate load failed"); - } - if (openssl_cert_ != NULL) { - X509_free(openssl_cert_); - } - openssl_cert_ = new_cert; - return OkStatus(); -} - -std::string X509Cert::GetPem() const { - std::string serialized_certificate; - if (!PemEncodeX509Certificate(*openssl_cert_, &serialized_certificate)) { - return ""; - } - return serialized_certificate; -} - -std::unique_ptr X509Cert::GetRsaPublicKey() const { - ScopedPKEY pkey(X509_get_pubkey(openssl_cert_)); - return std::unique_ptr( - new RsaPublicKey(EVP_PKEY_get1_RSA(pkey.get()))); -} - -const std::string& X509Cert::GetSubjectName() { - if (subject_name_.empty() && (openssl_cert_ != NULL)) { - X509_NAME* subject = X509_get_subject_name(openssl_cert_); - if (subject != NULL) { - BIO* bio = BIO_new(BIO_s_mem()); - if (bio != NULL) { - X509_NAME_print_ex(bio, subject, 0, 0); - int size = BIO_pending(bio); - std::unique_ptr buffer(new char[size]); - int bytes_read = BIO_read(bio, buffer.get(), size); - if (bytes_read == size) { - subject_name_.assign(buffer.get(), bytes_read); - } - BIO_free(bio); - } - } - } - return subject_name_; -} - -std::string X509Cert::GetSubjectNameField(const std::string& field) { - if (field.empty()) { - return std::string(); - } - const std::string& subject = GetSubjectName(); - size_t start_pos = subject.find(field + "="); - if (start_pos == std::string::npos) { - return std::string(); - } - start_pos += field.size() + 1; - size_t end_pos = subject.find(",", start_pos); - if (end_pos == std::string::npos) { - end_pos = subject.size(); - } - return subject.substr(start_pos, end_pos - start_pos); -} - -std::string X509Cert::GetSerialNumber() const { - if (openssl_cert_ == NULL) { - return std::string(); - } - BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(openssl_cert_), NULL); - if (bn == NULL) { - return std::string(); - } - std::string result; - char* openssl_sn = BN_bn2hex(bn); - if (openssl_sn != NULL) { - result = absl::HexStringToBytes(openssl_sn); - OPENSSL_free(openssl_sn); - } - BN_free(bn); - return result; -} - -bool X509Cert::GetNotBeforeSeconds(int64_t* valid_start_seconds) const { - if (openssl_cert_ == nullptr) { - return false; - } - return Asn1TimeToEpochSeconds(X509_get0_notBefore(openssl_cert_), - valid_start_seconds) - .ok(); -} - -bool X509Cert::GetNotAfterSeconds(int64_t* valid_end_seconds) const { - if (openssl_cert_ == nullptr) { - return false; - } - return Asn1TimeToEpochSeconds(X509_get0_notAfter(openssl_cert_), - valid_end_seconds) - .ok(); -} - -bool X509Cert::IsCaCertificate() const { - return X509_check_ca(openssl_cert_) != 0; -} - -bool X509Cert::GetV3BooleanExtension(const std::string& oid, - bool* value) const { - ScopedAsn1Object extension_name(OBJ_txt2obj(oid.c_str(), 1)); - int ext_pos = X509_get_ext_by_OBJ(openssl_cert_, extension_name.get(), -1); - if (ext_pos < 0) return false; - X509_EXTENSION* extension(X509_get_ext(openssl_cert_, ext_pos)); - if (!extension) return false; - ASN1_OCTET_STRING* extension_data(X509_EXTENSION_get_data(extension)); - if (!extension_data) return false; - if ((extension_data->length != 3) || (extension_data->data[0] != 1) || - (extension_data->data[1] != 1)) - return false; - - *value = extension_data->data[2] != 0; - return true; -} - -Status X509Cert::Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, - int64_t* epoch_seconds) const { - if (asn1_time == nullptr) { - // This code is exported to shared source. The exported code does not yet - // support MakeStatus. - // NOLINTNEXTLINE - return Status(error::INVALID_ARGUMENT, "asn1_time cannot be null."); - } - - if (epoch_seconds == nullptr) { - // NOLINTNEXTLINE - return Status(error::INVALID_ARGUMENT, "epoch_seconds cannot be null."); - } - - ScopedAsn1Time epoch_time(ASN1_TIME_new()); - if (!ASN1_TIME_set(epoch_time.get(), 0)) { - // NOLINTNEXTLINE - return Status(error::INTERNAL, "Failed to set epoch time."); - } - - int day = 0; - int seconds = 0; - if (!ASN1_TIME_diff(&day, &seconds, epoch_time.get(), asn1_time)) { - // NOLINTNEXTLINE - return Status(error::INTERNAL, - "Failed to convert asn1 time to epoch time."); - } - - *epoch_seconds = 24L * 3600L * day + seconds; - return OkStatus(); -} - -X509CertChain::~X509CertChain() { Reset(); } - -void X509CertChain::Reset() { - for (auto certp : cert_chain_) { - delete certp; - } - cert_chain_.clear(); -} - -Status X509CertChain::LoadPem(const std::string& pem_cert_chain) { - static const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----"; - static const char kEndCertificate[] = "-----END CERTIFICATE-----"; - - Reset(); - size_t begin_pos = pem_cert_chain.find(kBeginCertificate); - while (begin_pos != std::string::npos) { - size_t end_pos = pem_cert_chain.find( - kEndCertificate, begin_pos + sizeof(kBeginCertificate) - 1); - if (end_pos != std::string::npos) { - end_pos += sizeof(kEndCertificate) - 1; - std::unique_ptr new_cert(new X509Cert); - Status status = new_cert->LoadPem( - pem_cert_chain.substr(begin_pos, end_pos - begin_pos)); - if (!status.ok()) { - return status; - } - cert_chain_.push_back(new_cert.release()); - begin_pos = pem_cert_chain.find(kBeginCertificate, end_pos); - } - } - return OkStatus(); -} - -Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) { - ScopedX509Stack cert_stack(sk_X509_new_null()); - CBS cbs; - CBS_init(&cbs, reinterpret_cast(pk7_cert_chain.data()), - pk7_cert_chain.size()); - if (!PKCS7_get_certificates(cert_stack.get(), &cbs)) { - return Status(error::INVALID_ARGUMENT, - "Unable to load PKCS#7 certificate chain"); - } - - while (sk_X509_num(cert_stack.get()) > 0) { - cert_chain_.insert(cert_chain_.begin(), - new X509Cert(sk_X509_pop(cert_stack.get()))); - } - - return OkStatus(); -} - -std::string X509CertChain::GetPkcs7() { - std::string pkcs7_cert; - ScopedX509Stack cert_stack(sk_X509_new_null()); - for (X509Cert* cert : cert_chain_) { - // X509 stack takes ownership of certificates. Copy certificates to retain - // |cert_chain_|. - X509Cert cert_copy; - if (!cert_copy.LoadPem(cert->GetPem()).ok()) { - LOG(WARNING) << "Certificate chain serialization failed"; - return ""; - } - X509* openssl_cert_copy = const_cast(cert_copy.openssl_cert()); - cert_copy.openssl_cert_ = nullptr; - sk_X509_push(cert_stack.get(), openssl_cert_copy); - } - ScopedPKCS7 pkcs7( - PKCS7_sign(nullptr, nullptr, cert_stack.get(), nullptr, PKCS7_DETACHED)); - if (!pkcs7) { - LOG(WARNING) << "Could not convert certificate chain to PKCS7"; - return ""; - } - ScopedBIO bio(BIO_new(BIO_s_mem())); - if (bio.get() == nullptr || !i2d_PKCS7_bio(bio.get(), pkcs7.get())) { - LOG(WARNING) << "Failed writing PKCS7 to bio"; - return ""; - } - int cert_size = BIO_pending(bio.get()); - pkcs7_cert.resize(cert_size); - if (BIO_read(bio.get(), &pkcs7_cert[0], cert_size) != cert_size) { - LOG(WARNING) << "BIO_read failure"; - return ""; - } - return pkcs7_cert; -} - -X509Cert* X509CertChain::GetCert(size_t cert_index) const { - if (cert_index >= cert_chain_.size()) { - return NULL; - } - return cert_chain_[cert_index]; -} - -X509CA::X509CA(X509Cert* ca_cert) : ca_cert_(ca_cert), openssl_store_(NULL) {} - -X509CA::~X509CA() { - if (openssl_store_ != NULL) { - X509_STORE_free(openssl_store_); - } -} - -Status X509CA::InitializeStore() { - absl::WriterMutexLock lock(&openssl_store_mutex_); - if (openssl_store_ == NULL) { - if (ca_cert_ == NULL) { - return Status(error::INTERNAL, "CA X.509Cert is NULL"); - } - openssl_store_ = X509_STORE_new(); - if (openssl_store_ == NULL) { - return Status(error::INTERNAL, "Failed to allocate X.509 store"); - } - if (X509_STORE_add_cert(openssl_store_, - const_cast(ca_cert_->openssl_cert())) == 0) { - X509_STORE_free(openssl_store_); - openssl_store_ = NULL; - - return Status(error::INTERNAL, - "Failed to add X.509 CA certificate to store"); - } - } - return OkStatus(); -} - -Status X509CA::VerifyCert(const X509Cert& cert) { - return OpenSslX509Verify(cert.openssl_cert(), nullptr); -} - -Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) { - if (cert_chain.GetNumCerts() < 1) { - return Status(error::INVALID_ARGUMENT, - "Cannot verify empty certificate chain"); - } - - ScopedX509StackOnly intermediates(sk_X509_new_null()); - if (!intermediates) { - return Status(error::INTERNAL, - "Failed to allocate X.509 intermediate certificate stack"); - } - const X509Cert* leaf_cert(nullptr); - for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) { - if (cert_chain.GetCert(idx)->IsCaCertificate()) { - sk_X509_push(intermediates.get(), - const_cast(cert_chain.GetCert(idx)->openssl_cert())); - } else { - leaf_cert = cert_chain.GetCert(idx); - } - } - if (!leaf_cert) { - return Status(error::INVALID_ARGUMENT, - "X.509 certificate chain without leaf certificate."); - } - return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get()); -} - -Status X509CA::VerifyCertWithChain(const X509Cert& cert, - const X509CertChain& cert_chain) { - ScopedX509StackOnly intermediates(sk_X509_new_null()); - if (!intermediates) { - // MakeStatus is now preferred. But we don't support it in the exported - // version, yet. So, ignore lint here. - // NOLINTNEXTLINE - return Status(error::INTERNAL, - "Failed to allocate X.509 intermediate certificate stack"); - } - for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) { - sk_X509_push(intermediates.get(), - const_cast(cert_chain.GetCert(idx)->openssl_cert())); - } - - return OpenSslX509Verify(cert.openssl_cert(), intermediates.get()); -} - -Status X509CA::OpenSslX509Verify(const X509* cert, - STACK_OF(X509) * intermediates) { - DCHECK(cert); - - absl::ReaderMutexLock lock(&openssl_store_mutex_); - if (openssl_store_ == NULL) { - openssl_store_mutex_.ReaderUnlock(); - Status status = InitializeStore(); - if (!status.ok()) { - return status; - } - openssl_store_mutex_.ReaderLock(); - } - ScopedX509StoreCtx store_ctx(X509_STORE_CTX_new()); - if (!store_ctx) { - return Status(error::INTERNAL, "Failed to allocate X.509 store context"); - } - if (X509_STORE_CTX_init(store_ctx.get(), openssl_store_, - const_cast(cert), intermediates) == 0) { - return Status(error::INTERNAL, "Failed to initialize X.509 store context"); - } - int x509_status = X509_verify_cert(store_ctx.get()); - if (x509_status != 1) { - return Status(error::INTERNAL, - std::string("X.509 certificate chain validation failed: ") + - X509_verify_cert_error_string( - X509_STORE_CTX_get_error(store_ctx.get()))); - } - - return OkStatus(); -} - -} // namespace widevine diff --git a/common/x509_cert.h b/common/x509_cert.h deleted file mode 100644 index 20f062e..0000000 --- a/common/x509_cert.h +++ /dev/null @@ -1,181 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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: -// X.509 certificate classes used by the license server SDK. - -#ifndef COMMON_X509_CERT_H_ -#define COMMON_X509_CERT_H_ - -#include - -#include -#include -#include -#include - -#include "absl/base/thread_annotations.h" -#include "absl/synchronization/mutex.h" -#include "openssl/pem.h" -#include "openssl/x509.h" -#include "openssl/x509v3.h" -#include "common/openssl_util.h" -#include "common/rsa_key.h" -#include "common/status.h" - -namespace widevine { - -// NOTE: All Status codes are in the canonical error space. - -// Class which holds a single X.509 certificates. -class X509Cert { - public: - // Load the certificate from an openssl X509 certificate instance. - static std::unique_ptr FromOpenSslCert(ScopedX509 openssl_cert_); - - X509Cert(); - - X509Cert(const X509Cert&) = delete; - X509Cert& operator=(const X509Cert&) = delete; - - virtual ~X509Cert(); - - // Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is - // a PEM-encoded certificate. - Status LoadPem(const std::string& pem_cert); - - // Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is - // a DER-encoded certificate. - Status LoadDer(const std::string& der_cert); - - // Return a std::string containing the PEM-encoded certificate. - std::string GetPem() const; - - // Returns certificate RSA public key. nullptr if not found, or if key type - // is not RSA. - std::unique_ptr GetRsaPublicKey() const; - - // Returns the internal OpenSSL X509 certificate. - const X509* openssl_cert() const { return openssl_cert_; } - - // Returns the certificate subject name. - const std::string& GetSubjectName(); - - // Returns a field within the certificate subject name, or an empty std::string - // if the field is not found. - std::string GetSubjectNameField(const std::string& field); - - // Returns the certificate serial number, binary encoded, or an empty std::string - // if an error occurs. - std::string GetSerialNumber() const; - - // Gets the start of the validity period for the certificate in seconds - // since the epoch. |valid_start_seconds| must not be null. Returns true on - // success, false otherwise. - bool GetNotBeforeSeconds(int64_t* valid_start_seconds) const; - - // Gets the end of the validity period for the certificate in seconds - // since the epoch. |valid_end_seconds| must not be null. Returns true on - // success, false otherwise. - bool GetNotAfterSeconds(int64_t* valid_end_seconds) const; - - // Returns true if the certificate is a CA (root or intermediate) certificate. - bool IsCaCertificate() const; - - // Gets the value of an X.509 V3 extension encoded as a boolean. |oid| is the - // object identifier sequence for the extension, and |value| is a pointer to - // an integer which will contain the extension value upon successful return. - // Returns true if successful, or false otherwise. - bool GetV3BooleanExtension(const std::string& oid, bool* value) const; - - private: - explicit X509Cert(X509* openssl_cert); - Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, - int64_t* epoch_seconds) const; - - X509* openssl_cert_; - std::string subject_name_; - - friend class X509CertChain; -}; - -// Class which holds a chain of X.509 certificates. -class X509CertChain { - public: - X509CertChain() = default; - X509CertChain(const X509CertChain&) = delete; - X509CertChain& operator=(const X509CertChain&) = delete; - - virtual ~X509CertChain(); - - // Loads a chain of PEM-encoded X.509 certificates. Takes a single parameter, - // |pem_cert_chain|, which is the concatenation of a number of PEM X.509 - // certificates, beginning with the leaf certificate, and ending with the - // certificate signed by the root CA. - Status LoadPem(const std::string& pem_cert_chain); - - // Loads a chain of DER-encoded PKCS#7 certificates. Takes a single parameter, - // |pk7_cert_chain|, which is a DER-encoded PKCS#7 X.509 certificate - // container. - Status LoadPkcs7(const std::string& pk7_cert_chain); - - // Writes the |cert_chain_| to a DER-encoded PKCS#7 X.509 cryptographic - // message. The final message does not include signed data. - std::string GetPkcs7(); - - // Returns the number of certificates in the chain. - size_t GetNumCerts() const { return cert_chain_.size(); } - - // Returns the X509Cert at the specified chain index (0 start). Returns - // NULL if cert_index is out of range. The X509CertChain retains ownwership - // of the object returned. - X509Cert* GetCert(size_t cert_index) const; - - private: - void Reset(); - - std::vector cert_chain_; -}; - -// CA class which holds the root CA cert, and verifies certificate chains. -class X509CA { - public: - // New object assumes ownership of |ca_cert|. - explicit X509CA(X509Cert* ca_cert); - - X509CA(const X509CA&) = delete; - X509CA& operator=(const X509CA&) = delete; - - virtual ~X509CA(); - - // Does X.509 PKI validation of |cert| against the root CA certificate - // used when constructing X509CA. This method is thread-safe. - Status VerifyCert(const X509Cert& cert); - - // Does X.509 PKI validation of |cert_chain| against the root CA certificate - // used when constructing X509CA. This method is thread-safe. - Status VerifyCertChain(const X509CertChain& cert_chain); - - // Does X.509 PKI validation of |cert| using the |cert_chain| - // certificates. This method allows |cert| to be an ICA. This method is - // thread-safe. - Status VerifyCertWithChain(const X509Cert& cert, - const X509CertChain& cert_chain); - - private: - Status InitializeStore(); - Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * intermediates); - - std::unique_ptr ca_cert_; - absl::Mutex openssl_store_mutex_; - X509_STORE* openssl_store_ ABSL_GUARDED_BY(openssl_store_mutex_); -}; - -} // namespace widevine - -#endif // COMMON_X509_CERT_H_ diff --git a/common/x509_cert_test.cc b/common/x509_cert_test.cc deleted file mode 100644 index 0ebe8a1..0000000 --- a/common/x509_cert_test.cc +++ /dev/null @@ -1,531 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 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. -//////////////////////////////////////////////////////////////////////////////// - -#include "common/x509_cert.h" - -#include - -#include "testing/gunit.h" -#include "absl/strings/escaping.h" -#include "common/rsa_key.h" -#include "common/test_utils.h" - -namespace widevine { -const char kTestRootCaDerCert[] = - "30820403308202eba003020102020900a24f94af7ae6831f300d06092a86" - "4886f70d0101050500308197310b30090603550406130255533113301106" - "035504080c0a57617368696e67746f6e3111300f06035504070c084b6972" - "6b6c616e6431133011060355040a0c0a476f6f676c6520496e633111300f" - "060355040b0c085769646576696e653115301306035504030c0c54657374" - "20526f6f742043413121301f06092a864886f70d010901161274696e736b" - "697040676f6f676c652e636f6d301e170d3133303831363030353731305a" - "170d3333303831353030353731305a308197310b30090603550406130255" - "533113301106035504080c0a57617368696e67746f6e3111300f06035504" - "070c084b69726b6c616e6431133011060355040a0c0a476f6f676c652049" - "6e633111300f060355040b0c085769646576696e65311530130603550403" - "0c0c5465737420526f6f742043413121301f06092a864886f70d01090116" - "1274696e736b697040676f6f676c652e636f6d30820122300d06092a8648" - "86f70d01010105000382010f003082010a0282010100c6eee629d99f7736" - "2db5545ed1d6dfb3616c742c617d5fd48f2fbfcb3f2ec40a080bd04d551c" - "e519471a8bb4ec5c2c75bf8a2d2caf3f85d90e9e39391dfbdaae68051319" - "0da71b1b2ae4829a15c44bc1b19b17134844b94c6f06d9216333236574f3" - "f11b0d10c3c621410e42630c57ce9e901057eda5c3c2203ee2ad805a0d93" - "52fa91da45a6f4875b4524c193c42fd9048a10204e5b2c8203402ba760e7" - "e1b4126c3e2ab4258f2bf28cd3170de8c738a6a1f4cfcc0649fa95f1414f" - "d9d09dd4f511bc0a9bf3a5844a334d9e0a4b9525d2789be6abafe2d0cc20" - "79dcf030ffa9be8ae3fe2cab4ebdfa494d48aa8c63264d31e2208a9c28f7" - "3e0103ce164683bf0203010001a350304e301d0603551d0e041604144d30" - "ff181ac4f10da99e6a12c01e02accadf840a301f0603551d230418301680" - "144d30ff181ac4f10da99e6a12c01e02accadf840a300c0603551d130405" - "30030101ff300d06092a864886f70d01010505000382010100779e9b98d3" - "ec066f29862903a00e9c98259d987c04b9e6a2e6c3381ee59ec1dd0d7dee" - "79da612e4dfaa3465c8916993ed7adebb27340de20ca101067f8342b2124" - "ec0d5db531277b4653c3bc72b2a8daeae120e5348e1a338f6e68e7129436" - "026e78024f04d766b132252ec152402dcec28174346aa0ba997d7f1af140" - "ff025bec841f8039ba10d7cc098cf24554f8cbb2aa31875205c67df2f053" - "0d8784faf63c4f945e62da374cad6155e6ae44f597bcff4566ea2aac4258" - "e4ae81569c0eddd1df6929532b4538bd204b2ff5847cb46ac7383c96fe82" - "d22de9a13c5092c92c297021c51a2a0a5250cf26c271ff262f25a7738ae4" - "c270d87191c13aefdd177b"; - -const char kTestRootCaPemCert[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIEAzCCAuugAwIBAgIJAKJPlK965oMfMA0GCSqGSIb3DQEBBQUAMIGXMQswCQYD\n" - "VQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQx\n" - "EzARBgNVBAoMCkdvb2dsZSBJbmMxETAPBgNVBAsMCFdpZGV2aW5lMRUwEwYDVQQD\n" - "DAxUZXN0IFJvb3QgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNv\n" - "bTAeFw0xMzA4MTYwMDU3MTBaFw0zMzA4MTUwMDU3MTBaMIGXMQswCQYDVQQGEwJV\n" - "UzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQxEzARBgNV\n" - "BAoMCkdvb2dsZSBJbmMxETAPBgNVBAsMCFdpZGV2aW5lMRUwEwYDVQQDDAxUZXN0\n" - "IFJvb3QgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNvbTCCASIw\n" - "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbu5inZn3c2LbVUXtHW37NhbHQs\n" - "YX1f1I8vv8s/LsQKCAvQTVUc5RlHGou07Fwsdb+KLSyvP4XZDp45OR372q5oBRMZ\n" - "DacbGyrkgpoVxEvBsZsXE0hEuUxvBtkhYzMjZXTz8RsNEMPGIUEOQmMMV86ekBBX\n" - "7aXDwiA+4q2AWg2TUvqR2kWm9IdbRSTBk8Qv2QSKECBOWyyCA0Arp2Dn4bQSbD4q\n" - "tCWPK/KM0xcN6Mc4pqH0z8wGSfqV8UFP2dCd1PURvAqb86WESjNNngpLlSXSeJvm\n" - "q6/i0MwgedzwMP+pvorj/iyrTr36SU1IqoxjJk0x4iCKnCj3PgEDzhZGg78CAwEA\n" - "AaNQME4wHQYDVR0OBBYEFE0w/xgaxPENqZ5qEsAeAqzK34QKMB8GA1UdIwQYMBaA\n" - "FE0w/xgaxPENqZ5qEsAeAqzK34QKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n" - "BQADggEBAHeem5jT7AZvKYYpA6AOnJglnZh8BLnmoubDOB7lnsHdDX3uedphLk36\n" - "o0ZciRaZPtet67JzQN4gyhAQZ/g0KyEk7A1dtTEne0ZTw7xysqja6uEg5TSOGjOP\n" - "bmjnEpQ2Am54Ak8E12axMiUuwVJALc7CgXQ0aqC6mX1/GvFA/wJb7IQfgDm6ENfM\n" - "CYzyRVT4y7KqMYdSBcZ98vBTDYeE+vY8T5ReYto3TK1hVeauRPWXvP9FZuoqrEJY\n" - "5K6BVpwO3dHfaSlTK0U4vSBLL/WEfLRqxzg8lv6C0i3poTxQksksKXAhxRoqClJQ\n" - "zybCcf8mLyWnc4rkwnDYcZHBOu/dF3s=\n" - "-----END CERTIFICATE-----\n"; - -const char kTestPemCert[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n" - "VQQIDApXYXNoaW5ndG9uMREwDwYDVQQHDAhLaXJrbGFuZDETMBEGA1UECgwKR29v\n" - "Z2xlIEluYzERMA8GA1UECwwIV2lkZXZpbmUxHTAbBgNVBAMMFFRlc3QgSW50ZXJt\n" - "ZWRpYXRlIENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcN\n" - "MTMwODE2MjE0NDAwWhcNMzMwODE1MjE0NDAwWjCBrjELMAkGA1UEBhMCVVMxEzAR\n" - "BgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMSkwJwYDVQQKDCBD\n" - "aHJvbWUgRGV2aWNlIENvbnRlbnQgUHJvdGVjdGlvbjEVMBMGA1UECwwMdGVzdGlu\n" - "Zy50ZXN0MRIwEAYDVQQDDAlzdGFibGUgaWQxITAfBgkqhkiG9w0BCQEWEnRpbnNr\n" - "aXBAZ29vZ2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKlb\n" - "DqstOK0TlLtJZOGzysjD48ZXEnpwti0cQAK6JcN9htwpHemBlzAbIuOIjeY2tfvk\n" - "l2uIOOnNMgAiKs/Dpu9VbedXAVCnuxE7/yrWIw/rg1ZmqdxQXFqTo+52ErteMru4\n" - "krOaNgQ63SE934yR0MSFzuSbvTgTFLP7hHueaeg8+CUvQRU0WoC2akMXzY1G6AkV\n" - "wyY/lufA/XEQXgPbhvP67YxR+exwCfzQGolB5hkliKux0rmzDfcIiHMM0IDaE6nu\n" - "fbm8BKPxlZS/QrzTZAr9Q5GMyjcu0XTI1fknGVrE4pZMh8ge+ondcgIQxXBOhfJK\n" - "FCofYSP7rBxtasK+4ncCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEATcNfaLpfLbX6\n" - "qz1qKMLYaNe4OI0X8t8ZNXqEdqyNd4C7kSdaQkwNunVAqw1CadUzLRi8Of18cwlQ\n" - "EXBN4bPTeODCobPjS71YcYPhDsvGQcQ3GQC6BOyHKCTYpqgcIIPEGFzI+FrACede\n" - "f4tyIexq63iIx1IpmTBnpYnnfgc8v4anphNODHKMRBHy8BJRcKpTFFFo571c5OjE\n" - "QjhKEOp9eD72GuEgtK0f7jXYH2bRT4lmSLxg2L1jbwg3qIjoX2gjeILyzUF+FTzO\n" - "7G5JWQnyDjd/ZJuld7FRsJmuzAgISeqVeraYXU1p4utbqutATmmHBcYhkXJKBKkf\n" - "3rDeUI+Odg==\n" - "-----END CERTIFICATE-----\n"; -const char kTestPemCertSubjectField_C[] = "US"; -const char kTestPemCertSubjectField_CN[] = - "stable id/emailAddress=tinskip@google.com"; -const char kTestPemCertSerialNumber[] = "\002"; - -const int64_t kTestPemCertNotBeforeSeconds = 1376689440; -const int64_t kTestPemCertNotAfterSeconds = 2007755040; - -const char kTestPemCertChain[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n" - "VQQIDApXYXNoaW5ndG9uMREwDwYDVQQHDAhLaXJrbGFuZDETMBEGA1UECgwKR29v\n" - "Z2xlIEluYzERMA8GA1UECwwIV2lkZXZpbmUxHTAbBgNVBAMMFFRlc3QgSW50ZXJt\n" - "ZWRpYXRlIENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcN\n" - "MTMwODE2MjE0NDAwWhcNMzMwODE1MjE0NDAwWjCBrjELMAkGA1UEBhMCVVMxEzAR\n" - "BgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMSkwJwYDVQQKDCBD\n" - "aHJvbWUgRGV2aWNlIENvbnRlbnQgUHJvdGVjdGlvbjEVMBMGA1UECwwMdGVzdGlu\n" - "Zy50ZXN0MRIwEAYDVQQDDAlzdGFibGUgaWQxITAfBgkqhkiG9w0BCQEWEnRpbnNr\n" - "aXBAZ29vZ2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKlb\n" - "DqstOK0TlLtJZOGzysjD48ZXEnpwti0cQAK6JcN9htwpHemBlzAbIuOIjeY2tfvk\n" - "l2uIOOnNMgAiKs/Dpu9VbedXAVCnuxE7/yrWIw/rg1ZmqdxQXFqTo+52ErteMru4\n" - "krOaNgQ63SE934yR0MSFzuSbvTgTFLP7hHueaeg8+CUvQRU0WoC2akMXzY1G6AkV\n" - "wyY/lufA/XEQXgPbhvP67YxR+exwCfzQGolB5hkliKux0rmzDfcIiHMM0IDaE6nu\n" - "fbm8BKPxlZS/QrzTZAr9Q5GMyjcu0XTI1fknGVrE4pZMh8ge+ondcgIQxXBOhfJK\n" - "FCofYSP7rBxtasK+4ncCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEATcNfaLpfLbX6\n" - "qz1qKMLYaNe4OI0X8t8ZNXqEdqyNd4C7kSdaQkwNunVAqw1CadUzLRi8Of18cwlQ\n" - "EXBN4bPTeODCobPjS71YcYPhDsvGQcQ3GQC6BOyHKCTYpqgcIIPEGFzI+FrACede\n" - "f4tyIexq63iIx1IpmTBnpYnnfgc8v4anphNODHKMRBHy8BJRcKpTFFFo571c5OjE\n" - "QjhKEOp9eD72GuEgtK0f7jXYH2bRT4lmSLxg2L1jbwg3qIjoX2gjeILyzUF+FTzO\n" - "7G5JWQnyDjd/ZJuld7FRsJmuzAgISeqVeraYXU1p4utbqutATmmHBcYhkXJKBKkf\n" - "3rDeUI+Odg==\n" - "-----END CERTIFICATE-----\n" - "-----BEGIN CERTIFICATE-----\n" - "MIIEAzCCAuugAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMx\n" - "EzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQK\n" - "DApHb29nbGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEVMBMGA1UEAwwMVGVzdCBS\n" - "b290IENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcNMTMw\n" - "ODE2MjE0MTQ2WhcNMzMwODE1MjE0MTQ2WjCBnzELMAkGA1UEBhMCVVMxEzARBgNV\n" - "BAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQKDApHb29n\n" - "bGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEdMBsGA1UEAwwUVGVzdCBJbnRlcm1l\n" - "ZGlhdGUgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNvbTCCASIw\n" - "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANooBi6x3I9Incs6ytlPjBu7yEy5\n" - "f6BLf5NREE5nQm74Rt7PAA7YVDtxHP+pi1uyxsL3fUrx904s4tdXNRK85/2zn7+o\n" - "oZPYb8fH6dgl7ocmYeyC0jSmg7++ZiaS6OsjPSUTE2aEbAe6Q+ZhYsAbdkL7Z2dN\n" - "UJR9akhLEqlqfX4q5bWA0M3P/2/fqNYMS0w010Nwpd+KydbceT0rHQTmTGVsqCCL\n" - "gmaP9a8aQRMSP0dn5IOcc/K1Qnnfw1gxnjGF4aBP7KbCMxNBrbgBOwiTxgEMIcKZ\n" - "9IGszAcpftKX5ra3XePzFWCcnwilppaaE/2XWXkcAehc8d3xtkdAYZyVIBUCAwEA\n" - "AaNQME4wHQYDVR0OBBYEFDm35gzM6ll13HhZUbW5uDw7BieTMB8GA1UdIwQYMBaA\n" - "FE0w/xgaxPENqZ5qEsAeAqzK34QKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n" - "BQADggEBALj+/Z8ygfWVNncV0N9UsAcwlGUe5ME+VoXUF/0SOmdrc8LtPc2Dkc8b\n" - "xiQN1wHxE/OFsbsOdobPzwOBh67KyYyVWtxzzsLO0MHGxsbOmwa1AersoP4x8xoC\n" - "HaBU90cviYqz5k6rZyBIlFIrM5lqG1JB3U0kTceG/1sqwRAAu94BYqMW1iWyr9Mq\n" - "ASRCVBOrksWda4pZkCLp62vk7ItOcs2PrHf6UWbANTDH+8Q+pIw2wuJ5lf/imqKO\n" - "qrYCJmAi6VBa2jyHqXVPMk6lL1Rmdk4UgOsRvsbmKzb2vYeWIwhsXY5Spo3WVTLv\n" - "6kIkGZCFP/ws7ctk+fQyjjttncIdL2k=\n" - "-----END CERTIFICATE-----\n"; - -const char kTestPemIca[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIEAzCCAuugAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMx\n" - "EzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQK\n" - "DApHb29nbGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEVMBMGA1UEAwwMVGVzdCBS\n" - "b290IENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcNMTMw\n" - "ODE2MjE0MTQ2WhcNMzMwODE1MjE0MTQ2WjCBnzELMAkGA1UEBhMCVVMxEzARBgNV\n" - "BAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQKDApHb29n\n" - "bGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEdMBsGA1UEAwwUVGVzdCBJbnRlcm1l\n" - "ZGlhdGUgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNvbTCCASIw\n" - "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANooBi6x3I9Incs6ytlPjBu7yEy5\n" - "f6BLf5NREE5nQm74Rt7PAA7YVDtxHP+pi1uyxsL3fUrx904s4tdXNRK85/2zn7+o\n" - "oZPYb8fH6dgl7ocmYeyC0jSmg7++ZiaS6OsjPSUTE2aEbAe6Q+ZhYsAbdkL7Z2dN\n" - "UJR9akhLEqlqfX4q5bWA0M3P/2/fqNYMS0w010Nwpd+KydbceT0rHQTmTGVsqCCL\n" - "gmaP9a8aQRMSP0dn5IOcc/K1Qnnfw1gxnjGF4aBP7KbCMxNBrbgBOwiTxgEMIcKZ\n" - "9IGszAcpftKX5ra3XePzFWCcnwilppaaE/2XWXkcAehc8d3xtkdAYZyVIBUCAwEA\n" - "AaNQME4wHQYDVR0OBBYEFDm35gzM6ll13HhZUbW5uDw7BieTMB8GA1UdIwQYMBaA\n" - "FE0w/xgaxPENqZ5qEsAeAqzK34QKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n" - "BQADggEBALj+/Z8ygfWVNncV0N9UsAcwlGUe5ME+VoXUF/0SOmdrc8LtPc2Dkc8b\n" - "xiQN1wHxE/OFsbsOdobPzwOBh67KyYyVWtxzzsLO0MHGxsbOmwa1AersoP4x8xoC\n" - "HaBU90cviYqz5k6rZyBIlFIrM5lqG1JB3U0kTceG/1sqwRAAu94BYqMW1iWyr9Mq\n" - "ASRCVBOrksWda4pZkCLp62vk7ItOcs2PrHf6UWbANTDH+8Q+pIw2wuJ5lf/imqKO\n" - "qrYCJmAi6VBa2jyHqXVPMk6lL1Rmdk4UgOsRvsbmKzb2vYeWIwhsXY5Spo3WVTLv\n" - "6kIkGZCFP/ws7ctk+fQyjjttncIdL2k=\n" - "-----END CERTIFICATE-----\n"; - -const char kTestPk7CertChain[] = - "308207fb06092a864886f70d010702a08207ec308207e80201013100300b" - "06092a864886f70d010701a08207ce308203c3308202ab020102300d0609" - "2a864886f70d010105050030819f310b3009060355040613025553311330" - "1106035504080c0a57617368696e67746f6e3111300f06035504070c084b" - "69726b6c616e6431133011060355040a0c0a476f6f676c6520496e633111" - "300f060355040b0c085769646576696e65311d301b06035504030c145465" - "737420496e7465726d6564696174652043413121301f06092a864886f70d" - "010901161274696e736b697040676f6f676c652e636f6d301e170d313330" - "3831363231343430305a170d3333303831353231343430305a3081ae310b" - "30090603550406130255533113301106035504080c0a57617368696e6774" - "6f6e3111300f06035504070c084b69726b6c616e6431293027060355040a" - "0c204368726f6d652044657669636520436f6e74656e742050726f746563" - "74696f6e31153013060355040b0c0c74657374696e672e74657374311230" - "1006035504030c09737461626c652069643121301f06092a864886f70d01" - "0901161274696e736b697040676f6f676c652e636f6d30820122300d0609" - "2a864886f70d01010105000382010f003082010a0282010100a95b0eab2d" - "38ad1394bb4964e1b3cac8c3e3c657127a70b62d1c4002ba25c37d86dc29" - "1de98197301b22e3888de636b5fbe4976b8838e9cd3200222acfc3a6ef55" - "6de7570150a7bb113bff2ad6230feb835666a9dc505c5a93a3ee7612bb5e" - "32bbb892b39a36043add213ddf8c91d0c485cee49bbd381314b3fb847b9e" - "69e83cf8252f4115345a80b66a4317cd8d46e80915c3263f96e7c0fd7110" - "5e03db86f3faed8c51f9ec7009fcd01a8941e6192588abb1d2b9b30df708" - "88730cd080da13a9ee7db9bc04a3f19594bf42bcd3640afd43918cca372e" - "d174c8d5f927195ac4e2964c87c81efa89dd720210c5704e85f24a142a1f" - "6123fbac1c6d6ac2bee2770203010001300d06092a864886f70d01010505" - "0003820101004dc35f68ba5f2db5faab3d6a28c2d868d7b8388d17f2df19" - "357a8476ac8d7780bb91275a424c0dba7540ab0d4269d5332d18bc39fd7c" - "73095011704de1b3d378e0c2a1b3e34bbd587183e10ecbc641c4371900ba" - "04ec872824d8a6a81c2083c4185cc8f85ac009e75e7f8b7221ec6aeb7888" - "c75229993067a589e77e073cbf86a7a6134e0c728c4411f2f0125170aa53" - "145168e7bd5ce4e8c442384a10ea7d783ef61ae120b4ad1fee35d81f66d1" - "4f896648bc60d8bd636f0837a888e85f68237882f2cd417e153cceec6e49" - "5909f20e377f649ba577b151b099aecc080849ea957ab6985d4d69e2eb5b" - "aaeb404e698705c62191724a04a91fdeb0de508f8e7630820403308202eb" - "a003020102020101300d06092a864886f70d0101050500308197310b3009" - "0603550406130255533113301106035504080c0a57617368696e67746f6e" - "3111300f06035504070c084b69726b6c616e6431133011060355040a0c0a" - "476f6f676c6520496e633111300f060355040b0c085769646576696e6531" - "15301306035504030c0c5465737420526f6f742043413121301f06092a86" - "4886f70d010901161274696e736b697040676f6f676c652e636f6d301e17" - "0d3133303831363231343134365a170d3333303831353231343134365a30" - "819f310b30090603550406130255533113301106035504080c0a57617368" - "696e67746f6e3111300f06035504070c084b69726b6c616e643113301106" - "0355040a0c0a476f6f676c6520496e633111300f060355040b0c08576964" - "6576696e65311d301b06035504030c145465737420496e7465726d656469" - "6174652043413121301f06092a864886f70d010901161274696e736b6970" - "40676f6f676c652e636f6d30820122300d06092a864886f70d0101010500" - "0382010f003082010a0282010100da28062eb1dc8f489dcb3acad94f8c1b" - "bbc84cb97fa04b7f9351104e67426ef846decf000ed8543b711cffa98b5b" - "b2c6c2f77d4af1f74e2ce2d7573512bce7fdb39fbfa8a193d86fc7c7e9d8" - "25ee872661ec82d234a683bfbe662692e8eb233d25131366846c07ba43e6" - "6162c01b7642fb67674d50947d6a484b12a96a7d7e2ae5b580d0cdcfff6f" - "dfa8d60c4b4c34d74370a5df8ac9d6dc793d2b1d04e64c656ca8208b8266" - "8ff5af1a4113123f4767e4839c73f2b54279dfc358319e3185e1a04feca6" - "c2331341adb8013b0893c6010c21c299f481accc07297ed297e6b6b75de3" - "f315609c9f08a5a6969a13fd9759791c01e85cf1ddf1b64740619c952015" - "0203010001a350304e301d0603551d0e0416041439b7e60cccea5975dc78" - "5951b5b9b83c3b062793301f0603551d230418301680144d30ff181ac4f1" - "0da99e6a12c01e02accadf840a300c0603551d13040530030101ff300d06" - "092a864886f70d01010505000382010100b8fefd9f3281f595367715d0df" - "54b0073094651ee4c13e5685d417fd123a676b73c2ed3dcd8391cf1bc624" - "0dd701f113f385b1bb0e7686cfcf038187aecac98c955adc73cec2ced0c1" - "c6c6c6ce9b06b501eaeca0fe31f31a021da054f7472f898ab3e64eab6720" - "4894522b33996a1b5241dd4d244dc786ff5b2ac11000bbde0162a316d625" - "b2afd32a0124425413ab92c59d6b8a599022e9eb6be4ec8b4e72cd8fac77" - "fa5166c03530c7fbc43ea48c36c2e27995ffe29aa28eaab602266022e950" - "5ada3c87a9754f324ea52f5466764e1480eb11bec6e62b36f6bd87962308" - "6c5d8e52a68dd65532efea42241990853ffc2cedcb64f9f4328e3b6d9dc2" - "1d2f69a1003100"; - -const char kTestCertPrivateKey[] = - "-----BEGIN RSA PRIVATE KEY-----\n" - "MIIEowIBAAKCAQEAqVsOqy04rROUu0lk4bPKyMPjxlcSenC2LRxAArolw32G3Ckd\n" - "6YGXMBsi44iN5ja1++SXa4g46c0yACIqz8Om71Vt51cBUKe7ETv/KtYjD+uDVmap\n" - "3FBcWpOj7nYSu14yu7iSs5o2BDrdIT3fjJHQxIXO5Ju9OBMUs/uEe55p6Dz4JS9B\n" - "FTRagLZqQxfNjUboCRXDJj+W58D9cRBeA9uG8/rtjFH57HAJ/NAaiUHmGSWIq7HS\n" - "ubMN9wiIcwzQgNoTqe59ubwEo/GVlL9CvNNkCv1DkYzKNy7RdMjV+ScZWsTilkyH\n" - "yB76id1yAhDFcE6F8koUKh9hI/usHG1qwr7idwIDAQABAoIBADdwlZa30QvnkxLU\n" - "be/s+X9LkS8GpgfrCdgunU3HPkGGwDUmSKJ+R835tCwkMb+hPWXeaStMhsUS5UFh\n" - "7f3hoK5MmxPWSZnrrrNvnpKZUxUNFgucxBJZREJqfom7oVow9g6511xwKSqtUmJl\n" - "bN8JhPwwiZAQ45qNtINO3QnSy/y4IGrUPgjMpmJa26a+JhduTRq+LMPu2wz+HxS1\n" - "Vf2q0H1IOJr/kimMFMaBRYErNclFa8VIFjwjz5reH5lJyptajGhruor6EK1qqhNc\n" - "zPSRY4TZH5QcjM46zui6l3tL9e32j6oUd4mAp4HhH0fws/pwawFYECI+M+7OCjgK\n" - "y+qSJ1ECgYEA1g+L0yN4i+uScs7EpsYJfaRP1PMtGnUsof64Pg6i9IKcuf5mi5Kp\n" - "aIgZdXAZIzsACH5XbfuC5Srs4565k/9XrHehLcuBzodulrzwmOUDbJAxIDw4uTUX\n" - "95W0uK9UqyGLyM8wNYs/EzhveSFL8fnFWzOAL/+HshQpKCBzedSU+G0CgYEAyolH\n" - "xws2mim7rSrYyRz1Vj02rLZuBUR7cPaHDxjjuuSUbI2nsDRsm6ZUCNlJtReHBkpH\n" - "eW5iClBGkksVsJJYJBmyDw6a3mnj0mfxBnh9zGaHQi0RCuOwmYlu2L/XVQXiMFKT\n" - "gffazuvysg7N/bz7CJjm8PRRx/cAxxFfAozdf/MCgYEAtBagLCHLaOvnaW9LQoOZ\n" - "uHpkL2PmrjumMSN7HbpyngLEmDXPT90zaR4XTRXiECGzBXJFW+IdXW+fnGANANXx\n" - "jMeYck6kBn0qLOcIA5moJ82nhtcjYa2pXEI2qKnZMaAnWen1RRbBGgqAvgelPQ5F\n" - "W1UYo0j3gHo1peynOff+3IECgYAsP53M4KhHOgLkrE28cnUvKCR/y0NyJyoI3fNX\n" - "2wo11KaQqMoP9wQbZVVKsZ4m0EMRnrzKzNDii/M/FuRgNTjIekyqeXhgSyYY29iO\n" - "n1hshaHbVVk51dDJWns7I3559tUZ1ZCgfnPxbR8Sw6VBYD4//JfH4LjVRSOIWkU1\n" - "m2zw/QKBgGE55o0xrCywF3wDUtFa6vgpsOfZu9IblsWktSbD/lk1YOqGpU//B0O4\n" - "GqihOQT7E9kDNusspFUGpZrE0T0B+GW1T9iTR0zd+lC+qExv2ggDJoH063DnH5OU\n" - "Qz2M8LESeFxf6ZlBxkcyrk6G1RAy7lUs9fHhfmpEJLVv4DTCuWDl\n" - "-----END RSA PRIVATE KEY-----\n"; - -const char kTestMessage[] = - "c8635a17ccc672c941d0cc287715411a0a0222613a04d47693a53eb7f32c" - "1ebae1f5d916a815b880426362c42f5f18f694a380756e0452018c70b3e4" - "f72ebb5269cb7233a3b8a2a1840e33ca9d473224d17ff91bae6b8d4ff2d1" - "8e5c89b5fc8a52c4f791c2063ab1a29ffd3372db483e4975c1c9c7408bf6" - "dfe5696e256e86b75313c501ab781175971b9411a73c444592afb1ec1667" - "2bfb935715ef5302f3bef712d2296be4f64ef2dc861f0611b06c35d0a5c2" - "5ff9f4a2563f265f109d2fa8f8165d7891b8a83c84520eaa284d49a4f76e" - "ac158204a5bdf018edd9401ae6593092ba97970be9a58b10720a235c9158" - "b9f235f9dda3de05990cef8c2fd04920a2a434bd5b6aa75767762d89b964" - "90e42524855a7eab49a8f82ac593e4df01990206d3fa98329aa50e31db89" - "b46b82ee0073851826f77aabb3779738a6f311b79f54d036a98dca4881ef" - "88c3cbfc86ac358c7bd107dc234d3772fc707df01637354dcb9270c7aefa" - "852dd21818ede33ab7154c32f25268b82f89b344e6469b81b6699df68c56" - "a6e61f1dd8f140f3be4edce755ceee8ee7868f45a17f8b4b4b0988f45815" - "1b43d07dcb0cd80b1ffa37b824e0abc25897cb41c242a3db845bedd37adf" - "88a13c0b2f0b158464b02f9fd97ad6e87b92c13cbeee5e69d183cc898c4e" - "0cfa9c59abde74a437d030cb966137ffe9abe6be71ed21ef751cdea73625" - "7cff9e378718f7d7e9c4d567cbec8e0afdfab0585b8ed0d5f8de159b6524" - "22c90737b44c84603ba1131f557604fe4e6b4d91e45363903b8db179cee0" - "a50f2ae73394973c8671df7a7b2eeb8341a3417727cfe43290a67ac3ad02" - "a52c3d1698c2c28a46268518aea66cecb40f43f50bb9cea4ed1d49ceb51d" - "9967fabccccc7237a36b6cecda5916234730d7b3ca3295519d77b7516824" - "10e8a238b6345e8d28132f60423a13fdf4b6a6cf272cef9a0833abb4b86d" - "9828af45442a390e241b2b8c3290671da4a163d7e55fea7828098c0749ca" - "ff65145dd6b4a6e4c65d214801bb8302d8914864e99c4d0b390b8126d4bc" - "0353e376e69aba56cf71b9943a47dcffa07c6a24986a077f69b7bec6bd9c" - "357e211875453bdadd9bfc4526f96c458e0052d27a903611c09a9c7b5f51" - "83daad078aec0e79ef991d102d4af492773f1509a265c5644cbab3253e34" - "3015e4305fffd17ce0261bcb232cfa0e1dcc71f83dc1aac490e526f6269f" - "606d0e0e556bb30b774c2208ed3771474be23f39b7fc21dcbf304a923d9c"; - -const char kTestDevCodeSigningCert[] = - "-----BEGIN CERTIFICATE-----\n" - "MIIFDjCCA3agAwIBAgIPESIzRFVmd4iZqrvM3e7/MA0GCSqGSIb3DQEBCwUAMIGc\n" - "MQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2ly\n" - "a2xhbmQxDzANBgNVBAoMBkdvb2dsZTERMA8GA1UECwwIV2lkZXZpbmUxHjAcBgNV\n" - "BAMMFXdpZGV2aW5lLWRldi1jb2Rlc2lnbjEhMB8GCSqGSIb3DQEJARYSdGluc2tp\n" - "cEBnb29nbGUuY29tMB4XDTE3MTAwOTIwMjUwNloXDTI3MTAwNzIwMjUwNlowRTEL\n" - "MAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n" - "bmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" - "ggEBAObsg/w+dJedH3x5KEsXdA/5sunWc8G+iZl0wMcngh2DiwmOSkKf68uCK/iW\n" - "T0a2XGgk13zl1HuKrjatgc7n6E1j/sqDZBGkr0q1wQgsdzm3qvGZoDG/+Z2U23WU\n" - "kX6ZcyIYUbpO2VtQELEl6DgNwoUi/9Yp+vCb6lsItpSZ1WRD9NhbWh1MxZxj1s18\n" - "OYcEzpEYg4/vHTVhocUR/1Rp9M9yn0nH1MUdtjhgBM3BmlRH7TA/nF111A4+GzMN\n" - "qyqfb0/6yXE64Ca3+fGg1hstfUUXkpmjjNPhYJ6QTgA3Xfrz04a4uwB+pSliF3SD\n" - "gip7O3rDyK0ES55lGpZ7B3s3TakCAwEAAaOCASEwggEdMB0GA1UdDgQWBBQ2jJme\n" - "0BuaGrhgFGJR2i59HR+DizCBuwYDVR0jBIGzMIGwoYGipIGfMIGcMQswCQYDVQQG\n" - "EwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQxDzAN\n" - "BgNVBAoMBkdvb2dsZTERMA8GA1UECwwIV2lkZXZpbmUxHjAcBgNVBAMMFXdpZGV2\n" - "aW5lLWRldi1jb2Rlc2lnbjEhMB8GCSqGSIb3DQEJARYSdGluc2tpcEBnb29nbGUu\n" - "Y29tggkAxfgvA4+s8VgwCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwEwYDVR0lBAww\n" - "CgYIKwYBBQUHAwMwEQYKKwYBBAHWeQQBAgQDAQH/MA0GCSqGSIb3DQEBCwUAA4IB\n" - "gQAtan04ZGie7rRsKpb1F6t7xs48KE6cj6L99B5dgl37fZaZIQ3XE2vbmmmY5YTx\n" - "wofCkvOZMXHeQfJEK5GIK49TW/lAR+3kJUJzSh+N67f0X8O1pUl97IUFsbi6PTw/\n" - "mjhu197Kdy/OxPu/csOkEChuOfJLagRxXtIXeIyaeVOmn6fkFTOMOL2BusWOPuIs\n" - "9OmOQ+UHXpMuX4c2x9iO4NzZwwI/MgULLCrd/c73q199H+ttdPFoNs8+xGdodqA/\n" - "NFlHtMHMLMKVGpazAf+JW1/c3nb8L3S0nw4q7vPWi216RdZTfKfSIs/f/IW3CYJh\n" - "/IAuHOYvlD0GdSOFZHfhrnAvKhJ2iRu32psN87L9rL5EL22LT8csV/gLMc3SZ35n\n" - "/viuYcTDnMbe9S/Mge3mMJ9XHD5XBhN3hzmGDQEUdRS5MXrYdY32viPE7f+GAO9s\n" - "5MXS+h+FxQ6QUar2q1zHc/0Gr1hLzA6HYBmI0/AF8LsHs799XjrMKHkSBN6UQkC1\n" - "hRk=\n" - "-----END CERTIFICATE-----\n"; - -const char kDevCertFlagOid[] = "1.3.6.1.4.1.11129.4.1.2"; -const bool kTestDevCodeSigningCertFlagValue = true; - -TEST(X509CertTest, LoadCert) { - X509Cert test_cert; - EXPECT_EQ(OkStatus(), - test_cert.LoadDer(absl::HexStringToBytes(kTestRootCaDerCert))); - EXPECT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); - // TODO(user): Add more specific status checks to failure tests. - EXPECT_NE(OkStatus(), test_cert.LoadDer("bad cert")); - EXPECT_NE(OkStatus(), test_cert.LoadPem("bad cert")); - EXPECT_NE(OkStatus(), test_cert.LoadDer("")); - EXPECT_NE(OkStatus(), test_cert.LoadPem("")); -} - -TEST(X509CertTest, VerifySignature) { - X509Cert test_cert; - ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); - std::string message(absl::HexStringToBytes(kTestMessage)); - std::string signature; - ASSERT_EQ(OkStatus(), GenerateRsaSignatureSha256Pkcs1(kTestCertPrivateKey, - message, &signature)); - std::unique_ptr pub_key(test_cert.GetRsaPublicKey()); - ASSERT_TRUE(pub_key); - EXPECT_TRUE(pub_key->VerifySignatureSha256Pkcs7(message, signature)); - - EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7(message, "bad signature")); - EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7("bad digest", signature)); - EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7(message, "")); - EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7("", signature)); -} - -TEST(X509CertTest, GetSubjectNameField) { - X509Cert test_cert; - ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); - EXPECT_EQ(kTestPemCertSubjectField_C, test_cert.GetSubjectNameField("C")); - EXPECT_EQ(kTestPemCertSubjectField_CN, test_cert.GetSubjectNameField("CN")); - EXPECT_EQ("", test_cert.GetSubjectNameField("invalid_field")); -} - -TEST(X509CertTest, GetSerialNumber) { - X509Cert test_cert; - ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); - EXPECT_EQ(kTestPemCertSerialNumber, test_cert.GetSerialNumber()); -} - -TEST(X509CertTest, GetNotBeforeSeconds) { - X509Cert test_cert; - ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); - int64_t not_before_seconds = 0; - ASSERT_TRUE(test_cert.GetNotBeforeSeconds(¬_before_seconds)); - EXPECT_EQ(kTestPemCertNotBeforeSeconds, not_before_seconds); -} - -TEST(X509CertTest, GetNotAfterSeconds) { - X509Cert test_cert; - ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); - int64_t not_after_seconds = 0; - ASSERT_TRUE(test_cert.GetNotAfterSeconds(¬_after_seconds)); - EXPECT_EQ(kTestPemCertNotAfterSeconds, not_after_seconds); -} - -TEST(X509CertTest, CertChain) { - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - ASSERT_EQ(2, test_chain.GetNumCerts()); - EXPECT_FALSE(test_chain.GetCert(0) == NULL); - EXPECT_FALSE(test_chain.GetCert(1) == NULL); - EXPECT_TRUE(test_chain.GetCert(2) == NULL); -} - -TEST(X509CertTest, IsCaCertificate) { - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - ASSERT_EQ(2, test_chain.GetNumCerts()); - EXPECT_FALSE(test_chain.GetCert(0)->IsCaCertificate()); - EXPECT_TRUE(test_chain.GetCert(1)->IsCaCertificate()); -} - -TEST(X509CertTest, ChainVerificationPem) { - std::unique_ptr ca_cert(new X509Cert); - ASSERT_EQ(OkStatus(), - ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert))); - X509CA ca(ca_cert.release()); - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert)); - ASSERT_EQ(1, test_chain.GetNumCerts()); - EXPECT_NE(OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain)); -} - -TEST(X509CertTest, ChainVerificationPkcs7) { - std::unique_ptr ca_cert(new X509Cert); - ASSERT_EQ(OkStatus(), - ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert))); - X509CA ca(ca_cert.release()); - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), - test_chain.LoadPkcs7(absl::HexStringToBytes(kTestPk7CertChain))); - EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert)); - ASSERT_EQ(1, test_chain.GetNumCerts()); - EXPECT_NE(OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain)); -} - -TEST(X509CertTest, VerifyCertWithChainIca) { - std::unique_ptr ca_cert(new X509Cert); - ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); - X509CA ca(ca_cert.release()); - - // Verify the ICA with the root succeeds. - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert)); - ASSERT_EQ(1, test_chain.GetNumCerts()); - X509Cert ica_cert; - ASSERT_EQ(OkStatus(), ica_cert.LoadPem(kTestPemIca)); - EXPECT_EQ(OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain)); -} - -TEST(X509CertTest, VerifyCertWithChainLeaf) { - std::unique_ptr ca_cert(new X509Cert); - ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); - X509CA ca(ca_cert.release()); - - // Verify the leaf with the root and ICA succeeds. - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemIca)); - ASSERT_EQ(1, test_chain.GetNumCerts()); - X509Cert leaf_cert; - ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert)); - EXPECT_EQ(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain)); -} - -TEST(X509CertTest, VerifyCertWithChainLeafMissincIca) { - std::unique_ptr ca_cert(new X509Cert); - ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); - X509CA ca(ca_cert.release()); - - // Verify the leaf with only the root fails (ICA missing). - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert)); - ASSERT_EQ(1, test_chain.GetNumCerts()); - X509Cert leaf_cert; - ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert)); - EXPECT_NE(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain)); -} - -TEST(X509CertTest, GetPkcs7) { - X509CertChain test_chain; - ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - std::string pkcs7_certificate = test_chain.GetPkcs7(); - ASSERT_NE(pkcs7_certificate.size(), 0); - X509CertChain new_test_chain; - ASSERT_EQ(OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate)); - ASSERT_EQ(test_chain.GetNumCerts(), new_test_chain.GetNumCerts()); - for (int i = 0; i < test_chain.GetNumCerts(); i++) { - ASSERT_EQ(test_chain.GetCert(i)->GetPem(), - new_test_chain.GetCert(i)->GetPem()); - } -} - -TEST(X509CertTest, BooleanExtension) { - std::unique_ptr cert1(new X509Cert); - ASSERT_EQ(OkStatus(), cert1->LoadPem(kTestPemCert)); - bool extension_value; - EXPECT_FALSE(cert1->GetV3BooleanExtension(kDevCertFlagOid, &extension_value)); - - std::unique_ptr cert2(new X509Cert); - ASSERT_EQ(OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert)); - ASSERT_TRUE(cert2->GetV3BooleanExtension(kDevCertFlagOid, &extension_value)); - EXPECT_EQ(kTestDevCodeSigningCertFlagValue, extension_value); -} - -} // namespace widevine diff --git a/example/BUILD b/example/BUILD index 2553dc6..7ab741b 100644 --- a/example/BUILD +++ b/example/BUILD @@ -67,3 +67,13 @@ cc_binary( srcs = ["wv_cas_types_example.cc"], deps = ["//media_cas_packager_sdk/public:wv_cas_types"], ) + +cc_binary( + name = "wv_cas_emm_example", + srcs = ["wv_cas_emm_example.cc"], + deps = [ + "//base", + "//common:status", + "//media_cas_packager_sdk/public:wv_cas_emm", + ], +) diff --git a/example/test_emmg_messages.h b/example/test_emmg_messages.h index cbc53ca..44b68ef 100644 --- a/example/test_emmg_messages.h +++ b/example/test_emmg_messages.h @@ -52,7 +52,7 @@ const char kTestEmmgChannelSetup[] = { '\x01' // parameter_value }; -const char kTestEmmgStreamSetup[] = { +const char kTestEmmgStreamSetupForPrivateData[] = { '\x02', // protocol_version '\x01', '\x11', // message_type - Stream_setup '\x00', '\x1f', // message_length @@ -73,6 +73,27 @@ const char kTestEmmgStreamSetup[] = { '\x01' // parameter_value - private data }; +const char kTestEmmgStreamSetupForEmm[] = { + '\x02', // protocol_version + '\x01', '\x11', // message_type - Stream_setup + '\x00', '\x1f', // 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', '\x07', // parameter_type - data_type + '\x00', '\x01', // parameter_length + '\x00' // parameter_value - emm +}; + const char kTestEmmgStreamBwRequest[] = { '\x02', // protocol_version '\x01', '\x17', // message_type - Stream_BW_request @@ -109,7 +130,7 @@ const char kTestEmmgStreamBwAllocation[] = { '\x00', '\x32' // parameter_value (50 kbps) }; -const char kTestEmmgDataProvision[] = { +const char kTestEmmgPrivateDataProvision[] = { '\x02', // protocol_version '\x02', '\x11', // message_type - Data_provision '\x00', '\xda', // message_length @@ -149,10 +170,10 @@ const char kTestEmmgDataProvision[] = { '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'}; -const char kTestEmptyEmmgDataProvision[] = { +const char kTestEmmgEmmDataProvision[] = { '\x02', // protocol_version '\x02', '\x11', // message_type - Data_provision - '\x00', '\x00', // message_length + '\x01', '\x96', // message_length '\x00', '\x01', // parameter_type - client_id '\x00', '\x04', // parameter_length '\x4a', '\xd4', '\x00', '\x00', // parameter_value @@ -165,9 +186,57 @@ const char kTestEmptyEmmgDataProvision[] = { '\x00', '\x08', // parameter_type - data_id '\x00', '\x02', // parameter_length '\x00', '\x01', // parameter_value - '\x00', '\x00', // parameter_type - datagram - '\x00', '\x00', // parameter_length -}; + '\x00', '\x05', // parameter_type - datagram + '\x01', '\x78', // parameter_length + // 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). + // 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', + '\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', + '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', + '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', + // 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', + '\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', '\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', '\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', '\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', '\xff', '\xff', '\xff', '\xff', '\xff', + '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', + '\xff', '\xff', '\xff', '\xff'}; const char kTestEmmgStreamCloseRequest[] = { '\x02', // protocol_version diff --git a/example/wv_cas_emm_example.cc b/example/wv_cas_emm_example.cc new file mode 100644 index 0000000..a88457f --- /dev/null +++ b/example/wv_cas_emm_example.cc @@ -0,0 +1,133 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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. +//////////////////////////////////////////////////////////////////////////////// + +// Example of how to use the wv_cas_emm library. + +#include +#include +#include +#include + +#include +#include "common/status.h" +#include "media_cas_packager_sdk/public/wv_cas_emm.h" + +namespace { + +using widevine::cas::WvCasEmm; +using widevine::cas::WvCasFingerprintingInitParameters; +using widevine::cas::WvCasServiceBlockingInitParameters; + +// PID for the EMM packet. +static constexpr int kEmmPid = 1; +static constexpr size_t kTsPacketSize = 188; +static constexpr size_t kMaxPossibleTsPacketsCount = 6; +static constexpr size_t kMaxPossibleTsPacketsSizeBytes = + kMaxPossibleTsPacketsCount * kTsPacketSize; +static 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}; + +std::vector GetFingerprintingParams() { + WvCasFingerprintingInitParameters fingerprinting_1; + // Channels used in the fingerprinting and service blocking info. The channel + // definition is opaque to Widevine. + fingerprinting_1.channels = {"CH1", "CH2"}; + // Fingerprinting control information. The format is opaque to Widevine. + fingerprinting_1.control = "controls"; + + WvCasFingerprintingInitParameters fingerprinting_2; + fingerprinting_2.channels = {"CH3"}; + fingerprinting_2.control = "another control"; + + return {fingerprinting_1, fingerprinting_2}; +} + +std::vector GetServiceBlockingParams() { + WvCasServiceBlockingInitParameters service_blocking_1; + service_blocking_1.channels = {"CH1"}; + // Device groups that should have service blocking. The group definition is + // opaque to Widevine. + service_blocking_1.device_groups = {"Group1", "Group2"}; + // Service blocking start and end time, Epoch time in seconds. + service_blocking_1.start_time = 1598398260; + service_blocking_1.end_time = 1598398261; + + WvCasServiceBlockingInitParameters service_blocking_2; + service_blocking_2.channels = {"CH2", "CH3"}; + service_blocking_2.device_groups = {"Group3"}; + service_blocking_2.start_time = 0; // start_time set to 0 means immediate. + service_blocking_2.end_time = 1598398261; + + return {service_blocking_1, service_blocking_2}; +} +} // namespace + +int main(int argc, char** argv) { + widevine::Status status; + // Create EMM object with the ECC signing key. + std::string ecc_signing_key(std::begin(kTestECPrivateKey2Secp256r1), + std::end(kTestECPrivateKey2Secp256r1)); + std::unique_ptr emm = WvCasEmm::Create(ecc_signing_key); + if (emm == nullptr) { + std::cerr << "Failed to create WvCasEmm object"; + return -1; + } + // Optionally set the fingerprinting info. + status = emm->SetFingerprinting(GetFingerprintingParams()); + if (!status.ok()) { + std::cerr << "Failed to set fingerprinting info: " << status << std::endl; + return -2; + } + // Optionally set the service blocking info. + status = emm->SetServiceBlocking(GetServiceBlockingParams()); + if (!status.ok()) { + std::cerr << "Failed to set service blocking info: " << status << std::endl; + return -3; + } + + // Generate serialized EMM. + std::string serialized_emm; + status = emm->GenerateEmm(&serialized_emm); + if (!status.ok()) { + std::cerr << "Failed to generate serialized EMM: " << status << std::endl; + return -4; + } + std::cout << "Successfully generated EMM bytes: "; + for (size_t i = 0; i < serialized_emm.size(); i++) { + printf("'\\x%02x', ", static_cast(serialized_emm[i])); + } + std::cout << std::endl; + + // Generate EMM wrapped in TS packet. + // Notice that the signature of the EMM is expected to differ for each call. + uint8_t packet[kMaxPossibleTsPacketsSizeBytes]; + ssize_t packet_size = kMaxPossibleTsPacketsSizeBytes; + uint8_t continuity_counter = 0; + status = emm->GenerateEmmTsPackets(kEmmPid, &continuity_counter, packet, + &packet_size); + if (!status.ok()) { + std::cerr << "Failed to generate EMM TS packet: " << status << std::endl; + return -5; + } + std::cout << "Successfully generated EMM TS packet bytes: "; + for (size_t i = 0; i < packet_size; i++) { + printf("'\\x%02x', ", packet[i]); + } + std::cout << std::endl; + return 0; +} diff --git a/media_cas_packager_sdk/internal/BUILD b/media_cas_packager_sdk/internal/BUILD index 767ec4a..d504807 100644 --- a/media_cas_packager_sdk/internal/BUILD +++ b/media_cas_packager_sdk/internal/BUILD @@ -68,6 +68,7 @@ cc_test( "//external:protobuf", "//testing:gunit_main", "@abseil_repo//absl/memory", + "@abseil_repo//absl/strings", "//common:aes_cbc_util", "//protos/public:media_cas_encryption_cc_proto", ], @@ -87,7 +88,7 @@ cc_library( ":simulcrypt_util", ":util", "//base", - "@abseil_repo//absl/container:node_hash_map", + "@abseil_repo//absl/container:flat_hash_map", "@abseil_repo//absl/memory", "@abseil_repo//absl/strings", "@abseil_repo//absl/types:optional", @@ -123,10 +124,12 @@ cc_library( "simulcrypt_constants.h", ], deps = [ + ":emm", ":simulcrypt_util", ":ts_packet", ":util", "//base", + "@abseil_repo//absl/memory", "@abseil_repo//absl/strings", "@abseil_repo//absl/strings:str_format", "@abseil_repo//absl/time", @@ -226,6 +229,7 @@ cc_library( ":mpeg2ts", ":ts_packet", "//base", + "@abseil_repo//absl/strings", "//common:status", ], ) @@ -249,8 +253,12 @@ cc_library( srcs = ["emm.cc"], hdrs = ["emm.h"], deps = [ + ":util", "//base", "@abseil_repo//absl/strings", + "@abseil_repo//absl/time", + "//common:ec_key", + "//common:hash_algorithm", "//common:status", "//common:string_util", "//protos/public:media_cas_cc_proto", @@ -262,6 +270,14 @@ cc_test( srcs = ["emm_test.cc"], deps = [ ":emm", + ":util", "//testing:gunit_main", + "@abseil_repo//absl/memory", + "@abseil_repo//absl/strings", + "@abseil_repo//absl/time", + "//common:ec_key", + "//common:ec_test_keys", + "//common:hash_algorithm", + "//common:status", ], ) diff --git a/media_cas_packager_sdk/internal/ecm_generator_test.cc b/media_cas_packager_sdk/internal/ecm_generator_test.cc index f5f16ef..f7163c4 100644 --- a/media_cas_packager_sdk/internal/ecm_generator_test.cc +++ b/media_cas_packager_sdk/internal/ecm_generator_test.cc @@ -13,6 +13,7 @@ #include "testing/gmock.h" #include "testing/gunit.h" #include "absl/memory/memory.h" +#include "absl/strings/string_view.h" #include "common/aes_cbc_util.h" #include "media_cas_packager_sdk/internal/fixed_key_fetcher.h" #include "protos/public/media_cas_encryption.pb.h" @@ -50,9 +51,24 @@ constexpr char kEcmContentIvOdd[] = "AaCbEcGd"; constexpr char kFakeCasEncryptionResponseKeyId[] = "fake_key_id....."; constexpr char kFakeCasEncryptionResponseKeyData[] = "fakefakefakefakefakefakefakefake"; +constexpr char kFakeCasEncryptionResponseGroupKeyId[] = "fake_key_id12345"; +constexpr char kFakeCasEncryptionResponseGroupKeyData[] = + "fakefakefakefakefakefake12345678"; constexpr char kTrackType[] = "SD"; +void SetKeyInfoInTestResponse( + widevine::CasEncryptionResponse_KeyInfo* key, bool group_id_exists) { + ASSERT_TRUE(key != nullptr); + if (!group_id_exists) { + key->set_key_id(kFakeCasEncryptionResponseKeyId); + key->set_key(kFakeCasEncryptionResponseKeyData); + } else { + key->set_key_id(kFakeCasEncryptionResponseGroupKeyId); + key->set_key(kFakeCasEncryptionResponseGroupKeyData); + } +} + Status HandleCasEncryptionRequest(const std::string& signed_request_json, std::string* http_response_json) { SignedCasEncryptionRequest signed_request; @@ -72,24 +88,22 @@ Status HandleCasEncryptionRequest(const std::string& signed_request_json, CasEncryptionResponse response; response.set_status(CasEncryptionResponse::OK); response.set_content_id(request.content_id()); + response.set_group_id(request.group_id()); for (const auto& track_type : request.track_types()) { if (request.key_rotation()) { // Add the Even key. auto key = response.add_entitlement_keys(); - key->set_key_id(kFakeCasEncryptionResponseKeyId); - key->set_key(kFakeCasEncryptionResponseKeyData); + SetKeyInfoInTestResponse(key, request.has_group_id()); key->set_track_type(track_type); key->set_key_slot(CasEncryptionResponse::KeyInfo::EVEN); // Add the Odd key. key = response.add_entitlement_keys(); - key->set_key_id(kFakeCasEncryptionResponseKeyId); - key->set_key(kFakeCasEncryptionResponseKeyData); + SetKeyInfoInTestResponse(key, request.has_group_id()); key->set_track_type(track_type); key->set_key_slot(CasEncryptionResponse::KeyInfo::ODD); } else { auto key = response.add_entitlement_keys(); - key->set_key_id(kFakeCasEncryptionResponseKeyId); - key->set_key(kFakeCasEncryptionResponseKeyData); + SetKeyInfoInTestResponse(key, request.has_group_id()); key->set_track_type(track_type); key->set_key_slot(CasEncryptionResponse::KeyInfo::SINGLE); } @@ -146,7 +160,8 @@ class EcmGeneratorTest : public testing::Test { } // Call this to setup the guts (Ecm) of the ECM Generator. - void PrepareEcmGenerator(bool key_rotation_enabled) { + void PrepareEcmGenerator(bool key_rotation_enabled, + const std::string& group_id) { std::string entitlement_request; std::string entitlement_response; ecm_init_params_.key_rotation_enabled = key_rotation_enabled; @@ -154,6 +169,7 @@ class EcmGeneratorTest : public testing::Test { EntitlementRequestParams request_params; request_params.content_id = kContentId; request_params.content_provider = kProvider; + request_params.group_id = group_id; request_params.track_types = {kTrackType}; request_params.key_rotation = key_rotation_enabled; ASSERT_OK(key_fetcher.CreateEntitlementRequest(request_params, @@ -169,6 +185,78 @@ class EcmGeneratorTest : public testing::Test { ecm_gen_.set_ecm(std::move(ecm_)); } + void CheckECMOutput(absl::string_view ecm_string, + absl::string_view response_entitlement_key_id, + absl::string_view response_entitltement_key_data, + bool key_rotation_enabled) { + // Expected size (bytes): + // CA system ID: 2 bytes + // version: 1 byte + // flags: 1 byte + // flags: 1 byte + // entitlement key ID: 16 bytes + // Single key: ID (16), Data (16), IV (16), IV (8) = 56 + // total = 77 (ECM message complete if no key retotation) + // second entitlement key ID: 16 bytes + // Second key: ID (16), Data (16), IV (16), IV (8) = 56 + // total = 149 + uint32_t ecm_string_size = key_rotation_enabled ? 149 : 77; + ASSERT_EQ(ecm_string_size, ecm_string.size()); + EXPECT_EQ('\x4A', ecm_string[0]); // CA System ID first byte. + EXPECT_EQ('\xD4', ecm_string[1]); // CA System ID second byte. + EXPECT_EQ('\x02', ecm_string[2]); // ECM version + if (key_rotation_enabled) { + EXPECT_EQ('\x03', ecm_string[3]); // flags + } else { + EXPECT_EQ('\x02', ecm_string[3]); // flags + } + EXPECT_EQ('\x80', ecm_string[4]); // flags + EXPECT_EQ(response_entitlement_key_id, ecm_string.substr(5, 16)); + if (!key_rotation_enabled) { + EXPECT_EQ(kEcmKeyIdSingle, ecm_string.substr(21, 16)); + // Key data has been wrapped (encrypted). + EXPECT_NE(kEcmKeyDataSingle, ecm_string.substr(37, 16)); + EXPECT_EQ(kEcmWrappedKeyIvSingle, ecm_string.substr(53, 16)); + // Unwrap key and compare with original. + absl::string_view wrapping_key = response_entitltement_key_data; + absl::string_view wrapping_iv = ecm_string.substr(53, 16); + absl::string_view wrapped_key = ecm_string.substr(37, 16); + std::string unwrapped_key = crypto_util::DecryptAesCbcNoPad( + std::string(wrapping_key), std::string(wrapping_iv), + std::string(wrapped_key)); + EXPECT_EQ(kEcmKeyDataSingle, unwrapped_key); + EXPECT_EQ(kEcmContentIvSingle, ecm_string.substr(69, 8)); + } else { + EXPECT_EQ(kEcmKeyIdEven, ecm_string.substr(21, 16)); + // Key data has been wrapped (encrypted). + EXPECT_NE(kEcmKeyDataEven, ecm_string.substr(37, 16)); + EXPECT_EQ(kEcmWrappedKeyIvEven, ecm_string.substr(53, 16)); + EXPECT_EQ(kEcmContentIvEven, ecm_string.substr(69, 8)); + EXPECT_EQ(response_entitlement_key_id, ecm_string.substr(77, 16)); + EXPECT_EQ(kEcmKeyIdOdd, ecm_string.substr(93, 16)); + // Key data has been wrapped (encrypted). + EXPECT_NE(kEcmKeyDataOdd, ecm_string.substr(109, 16)); + EXPECT_EQ(kEcmWrappedKeyIvOdd, ecm_string.substr(125, 16)); + EXPECT_EQ(kEcmContentIvOdd, ecm_string.substr(141, 8)); + // Unwrap even key and compare with original. + absl::string_view wrapping_key_even = response_entitltement_key_data; + absl::string_view wrapping_iv_even = ecm_string.substr(53, 16); + absl::string_view wrapped_key_even = ecm_string.substr(37, 16); + std::string unwrapped_key_even = crypto_util::DecryptAesCbcNoPad( + std::string(wrapping_key_even), std::string(wrapping_iv_even), + std::string(wrapped_key_even)); + EXPECT_EQ(kEcmKeyDataEven, unwrapped_key_even); + // Unwrap odd key and compare with original. + absl::string_view wrapping_key_odd = response_entitltement_key_data; + absl::string_view wrapping_iv_odd = ecm_string.substr(125, 16); + absl::string_view wrapped_key_odd = ecm_string.substr(109, 16); + std::string unwrapped_key_odd = crypto_util::DecryptAesCbcNoPad( + std::string(wrapping_key_odd), std::string(wrapping_iv_odd), + std::string(wrapped_key_odd)); + EXPECT_EQ(kEcmKeyDataOdd, unwrapped_key_odd); + } + } + const KeyParameters kKeyParamsSingle{kEcmKeyIdSingle, kEcmKeyDataSingle, kEcmWrappedKeyIvSingle, @@ -187,101 +275,55 @@ class EcmGeneratorTest : public testing::Test { TEST_F(EcmGeneratorTest, InitializeNoRotation) { EXPECT_FALSE(ecm_gen_.initialized()); - - PrepareEcmGenerator(false); - + PrepareEcmGenerator(false, /*group_id=*/""); EcmParameters ecm_params; std::vector keys; - SetTestConfig1(&ecm_params); Status status = ProcessEcmParameters(ecm_params, &keys); ASSERT_OK(status); - ASSERT_EQ(EntitlementKeySize(ecm_params), 16); ASSERT_TRUE(ecm_gen_.initialized()); EXPECT_FALSE(ecm_gen_.rotation_enabled()); } TEST_F(EcmGeneratorTest, GenerateNoRotation) { - PrepareEcmGenerator(false); + PrepareEcmGenerator(false, /*group_id=*/""); EcmParameters ecm_params; - SetTestConfig1(&ecm_params); - std::string ecm_string = ecm_gen_.GenerateEcm(ecm_params); - // Expected size (bytes): - // CA system ID: 2 bytes - // version: 1 byte - // flags: 1 byte - // flags: 1 byte - // entitlement key ID: 16 bytes - // Single key: ID (16), Data (16), IV (16), IV (8) = 56 - // total = 77 - ASSERT_EQ(77, ecm_string.size()); - EXPECT_EQ('\x4A', ecm_string[0]); // CA System ID first byte. - EXPECT_EQ('\xD4', ecm_string[1]); // CA System ID second byte. - EXPECT_EQ('\x02', ecm_string[2]); // ECM version - EXPECT_EQ('\x02', ecm_string[3]); // flags - EXPECT_EQ('\x80', ecm_string[4]); // flags - EXPECT_EQ(kFakeCasEncryptionResponseKeyId, ecm_string.substr(5, 16)); - EXPECT_EQ(kEcmKeyIdSingle, ecm_string.substr(21, 16)); - // Key data has been wrapped (encrypted). - EXPECT_NE(kEcmKeyDataSingle, ecm_string.substr(37, 16)); - EXPECT_EQ(kEcmWrappedKeyIvSingle, ecm_string.substr(53, 16)); - // Unwrap key and compare with original. - std::string wrapping_key = kFakeCasEncryptionResponseKeyData; - std::string wrapping_iv = ecm_string.substr(53, 16); - std::string wrapped_key = ecm_string.substr(37, 16); - std::string unwrapped_key = - crypto_util::DecryptAesCbcNoPad(wrapping_key, wrapping_iv, wrapped_key); - EXPECT_EQ(kEcmKeyDataSingle, unwrapped_key); - EXPECT_EQ(kEcmContentIvSingle, ecm_string.substr(69, 8)); + CheckECMOutput(ecm_string, kFakeCasEncryptionResponseKeyId, + kFakeCasEncryptionResponseKeyData, false); +} + +TEST_F(EcmGeneratorTest, GenerateNoRotationWithGroupId) { + PrepareEcmGenerator(false, "groupId_1"); + EcmParameters ecm_params; + SetTestConfig1(&ecm_params); + std::string ecm_string = ecm_gen_.GenerateEcm(ecm_params); + CheckECMOutput(ecm_string, kFakeCasEncryptionResponseGroupKeyId, + kFakeCasEncryptionResponseGroupKeyData, false); } TEST_F(EcmGeneratorTest, Generate2NoRotation) { - PrepareEcmGenerator(false); + PrepareEcmGenerator(false, /*group_id=*/""); EcmParameters ecm_params; - SetTestConfig1(&ecm_params); - std::string ecm_string = ecm_gen_.GenerateEcm(ecm_params); ecm_string = ecm_gen_.GenerateEcm(ecm_params); - - ASSERT_EQ(77, ecm_string.size()); - EXPECT_EQ('\x4A', ecm_string[0]); // CA System ID first byte. - EXPECT_EQ('\xD4', ecm_string[1]); // CA System ID second byte. - EXPECT_EQ('\x02', ecm_string[2]); // ECM version - EXPECT_EQ('\x02', ecm_string[3]); // flags - EXPECT_EQ('\x80', ecm_string[4]); // flags - EXPECT_EQ(kFakeCasEncryptionResponseKeyId, ecm_string.substr(5, 16)); - EXPECT_EQ(kEcmKeyIdSingle, ecm_string.substr(21, 16)); - // Key data has been wrapped (encrypted). - EXPECT_NE(kEcmKeyDataSingle, ecm_string.substr(37, 16)); - EXPECT_EQ(kEcmWrappedKeyIvSingle, ecm_string.substr(53, 16)); - // Unwrap key and compare with original. - std::string wrapping_key = kFakeCasEncryptionResponseKeyData; - std::string wrapping_iv = ecm_string.substr(53, 16); - std::string wrapped_key = ecm_string.substr(37, 16); - std::string unwrapped_key = - crypto_util::DecryptAesCbcNoPad(wrapping_key, wrapping_iv, wrapped_key); - EXPECT_EQ(kEcmKeyDataSingle, unwrapped_key); - EXPECT_EQ(kEcmContentIvSingle, ecm_string.substr(69, 8)); + CheckECMOutput(ecm_string, kFakeCasEncryptionResponseKeyId, + kFakeCasEncryptionResponseKeyData, false); } TEST_F(EcmGeneratorTest, InitializeSimpleRotation) { EXPECT_FALSE(ecm_gen_.initialized()); EcmParameters ecm_params; std::vector keys; - - PrepareEcmGenerator(true); - + PrepareEcmGenerator(true, /*group_id=*/""); SetTestConfig2(&ecm_params); ecm_init_params_.key_rotation_enabled = true; - Status status = ProcessEcmParameters(ecm_params, &keys); - EXPECT_TRUE(status.ok()); EXPECT_TRUE(ecm_gen_.initialized()); EXPECT_TRUE(ecm_gen_.rotation_enabled()); @@ -289,50 +331,20 @@ TEST_F(EcmGeneratorTest, InitializeSimpleRotation) { TEST_F(EcmGeneratorTest, GenerateSimpleRotation) { EcmParameters ecm_params; - - PrepareEcmGenerator(true); - + PrepareEcmGenerator(true, /*group_id=*/""); SetTestConfig2(&ecm_params); - std::string ecm_string = ecm_gen_.GenerateEcm(ecm_params); + CheckECMOutput(ecm_string, kFakeCasEncryptionResponseKeyId, + kFakeCasEncryptionResponseKeyData, true); +} - // Expected size (bytes): - // same as no rotation case = 77 - // second entitlement key ID: 16 bytes - // Second key: ID (16), Data (16), IV (16), IV (8) = 56 - // total = 149 - ASSERT_EQ(149, ecm_string.size()); - EXPECT_EQ('\x4A', ecm_string[0]); // CA System ID first byte. - EXPECT_EQ('\xD4', ecm_string[1]); // CA System ID second byte. - EXPECT_EQ('\x02', ecm_string[2]); // ECM version - EXPECT_EQ('\x03', ecm_string[3]); // flags - EXPECT_EQ('\x80', ecm_string[4]); // flags - EXPECT_EQ(kFakeCasEncryptionResponseKeyId, ecm_string.substr(5, 16)); - EXPECT_EQ(kEcmKeyIdEven, ecm_string.substr(21, 16)); - // Key data has been wrapped (encrypted). - EXPECT_NE(kEcmKeyDataEven, ecm_string.substr(37, 16)); - EXPECT_EQ(kEcmWrappedKeyIvEven, ecm_string.substr(53, 16)); - EXPECT_EQ(kEcmContentIvEven, ecm_string.substr(69, 8)); - EXPECT_EQ(kFakeCasEncryptionResponseKeyId, ecm_string.substr(77, 16)); - EXPECT_EQ(kEcmKeyIdOdd, ecm_string.substr(93, 16)); - // Key data has been wrapped (encrypted). - EXPECT_NE(kEcmKeyDataOdd, ecm_string.substr(109, 16)); - EXPECT_EQ(kEcmWrappedKeyIvOdd, ecm_string.substr(125, 16)); - EXPECT_EQ(kEcmContentIvOdd, ecm_string.substr(141, 8)); - // Unwrap even key and compare with original. - std::string wrapping_key_even = kFakeCasEncryptionResponseKeyData; - std::string wrapping_iv_even = ecm_string.substr(53, 16); - std::string wrapped_key_even = ecm_string.substr(37, 16); - std::string unwrapped_key_even = crypto_util::DecryptAesCbcNoPad( - wrapping_key_even, wrapping_iv_even, wrapped_key_even); - EXPECT_EQ(kEcmKeyDataEven, unwrapped_key_even); - // Unwrap odd key and compare with original. - std::string wrapping_key_odd = kFakeCasEncryptionResponseKeyData; - std::string wrapping_iv_odd = ecm_string.substr(125, 16); - std::string wrapped_key_odd = ecm_string.substr(109, 16); - std::string unwrapped_key_odd = crypto_util::DecryptAesCbcNoPad( - wrapping_key_odd, wrapping_iv_odd, wrapped_key_odd); - EXPECT_EQ(kEcmKeyDataOdd, unwrapped_key_odd); +TEST_F(EcmGeneratorTest, GenerateSimpleRotationWithGroupId) { + EcmParameters ecm_params; + PrepareEcmGenerator(true, "groupId_1"); + SetTestConfig2(&ecm_params); + std::string ecm_string = ecm_gen_.GenerateEcm(ecm_params); + CheckECMOutput(ecm_string, kFakeCasEncryptionResponseGroupKeyId, + kFakeCasEncryptionResponseGroupKeyData, true); } } // namespace cas diff --git a/media_cas_packager_sdk/internal/ecmg_client_handler.cc b/media_cas_packager_sdk/internal/ecmg_client_handler.cc index 4be8aa9..8e87994 100644 --- a/media_cas_packager_sdk/internal/ecmg_client_handler.cc +++ b/media_cas_packager_sdk/internal/ecmg_client_handler.cc @@ -24,6 +24,9 @@ // CA System ID for Widevine. static constexpr uint16_t kWidevineSystemId = 0x4AD4; +// New CA System ID range for Widevine, all inclusive. +static constexpr uint16_t kWidevineNewSystemIdLowerBound = 0x56C0; +static constexpr uint16_t kWidevineNewSystemIdUpperBound = 0x56C9; // 'section_TSpkt_flag' defines the format of the ECM. // We only support MPEG-2 transport stream packet format for now. // We do NOT support MPEG-2 section format yet. @@ -500,7 +503,10 @@ void EcmgClientHandler::HandleChannelSetup(const EcmgParameters& params, } // The super_cas_id is a 32-bit identifier formed by the concatenation of the // CA_system_id (16 bit) and the CA_subsystem_id (16 bit). - if ((params.super_cas_id >> 16) != kWidevineSystemId) { + uint16_t cas_id = params.super_cas_id >> 16; + if (cas_id != kWidevineSystemId && + (cas_id < kWidevineNewSystemIdLowerBound || + cas_id > kWidevineNewSystemIdUpperBound)) { BuildChannelError(params.ecm_channel_id, UNKNOWN_SUPER_CAS_ID_VALUE, "", response, response_length); return; diff --git a/media_cas_packager_sdk/internal/ecmg_client_handler.h b/media_cas_packager_sdk/internal/ecmg_client_handler.h index 7ffe6e7..1965a3b 100644 --- a/media_cas_packager_sdk/internal/ecmg_client_handler.h +++ b/media_cas_packager_sdk/internal/ecmg_client_handler.h @@ -15,7 +15,7 @@ #include #include -#include "absl/container/node_hash_map.h" +#include "absl/container/flat_hash_map.h" #include "absl/types/optional.h" #include "common/status.h" #include "media_cas_packager_sdk/internal/ecm.h" @@ -141,7 +141,7 @@ class EcmgClientHandler { std::vector content_ivs_; // Map from ECM_stream_id to EcmgStreamInfo. - absl::node_hash_map> streams_info_; + absl::flat_hash_map> streams_info_; }; } // namespace cas diff --git a/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc b/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc index 0f04e79..cb73337 100644 --- a/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc +++ b/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc @@ -34,7 +34,10 @@ using simulcrypt_util::AddUint8Param; using simulcrypt_util::BuildMessageHeader; constexpr size_t kBufferSize = 1024; -constexpr size_t kSuperCasId = 0x4AD40000; +constexpr uint16_t kWidevineSystemId = 0x4AD4; +constexpr uint32_t kSuperCasId = kWidevineSystemId << 16; +constexpr uint16_t kWidevineNewSystemIdLowerBound = 0x56C0; +constexpr uint16_t kWidevineNewSystemIdUpperBound = 0x56C9; constexpr size_t kChannelId = 1; constexpr size_t kStreamId = 1; constexpr size_t kEcmId = 2; @@ -605,6 +608,38 @@ TEST_F(EcmgClientHandlerTest, BuildEcmDatagramSequenceOfEvenOdd) { EXPECT_NE(std::string(response_, response_len_), first_response); } +class CasIdTest + : public EcmgClientHandlerTest, + public ::testing::WithParamInterface<::testing::tuple> {}; + +TEST_P(CasIdTest, ValidateCasIds) { + uint32_t super_cas_id = ::testing::get<0>(GetParam()) << 16; + bool is_valid_cas_id = ::testing::get<1>(GetParam()); + BuildChannelSetupRequest(kChannelId, super_cas_id, kAgeRestriction, + kCryptoMode, request_, &request_len_); + handler_->HandleRequest(request_, response_, &response_len_); + if (is_valid_cas_id) { + EXPECT_EQ(response_len_, sizeof(kTestEcmgChannelStatus)); + } else { + EXPECT_EQ(response_len_, sizeof(kTestEcmgChannelError)); + } +} + +INSTANTIATE_TEST_SUITE_P( + ChannelSetupWithNewCasId, CasIdTest, + ::testing::Combine( + ::testing::Range(static_cast(kWidevineNewSystemIdLowerBound), + static_cast(kWidevineNewSystemIdUpperBound) + 1), + ::testing::Values(true))); + +INSTANTIATE_TEST_SUITE_P( + ChannelSetupWithInvalidCasId, CasIdTest, + ::testing::Combine(::testing::Values(0, kWidevineSystemId - 1, + kWidevineSystemId + 1, + kWidevineNewSystemIdLowerBound - 1, + kWidevineNewSystemIdUpperBound + 1), + ::testing::Values(false))); + } // namespace } // namespace cas } // namespace widevine diff --git a/media_cas_packager_sdk/internal/emm.cc b/media_cas_packager_sdk/internal/emm.cc index 0f3266c..a10de47 100644 --- a/media_cas_packager_sdk/internal/emm.cc +++ b/media_cas_packager_sdk/internal/emm.cc @@ -12,14 +12,18 @@ #include "glog/logging.h" #include "absl/strings/str_cat.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "common/ec_key.h" +#include "common/hash_algorithm.h" #include "common/status.h" #include "common/string_util.h" +#include "media_cas_packager_sdk/internal/util.h" namespace widevine { namespace cas { namespace { - constexpr int kNumBitsVersionField = 8; constexpr int kNumBitsHeaderLengthField = 8; constexpr int kNumBitsTimestampLengthField = 64; @@ -29,13 +33,27 @@ constexpr int kNumBitsPayloadLengthField = 16; constexpr uint8_t kEmmVersion = 1; } // namespace +Status Emm::SetPrivateSigningKey(const std::string& private_signing_key) { + if (private_signing_key.empty()) { + return {error::INVALID_ARGUMENT, "private_signing_key must not be empty."}; + } + private_signing_key_ = private_signing_key; + return OkStatus(); +} + Status Emm::SetFingerprinting( const std::vector& fingerprintings) { // First clear all current fingerprinting payload. emm_payload_.clear_fingerprinting(); - // TODO(b/161149665): validate passed in data. Status status; + for (const auto& fingerprinting : fingerprintings) { + status = ValidateFingerprintingInitParameters(fingerprinting); + if (!status.ok()) { + return status; + } + } + for (const auto& fingerprinting_param : fingerprintings) { Fingerprinting* fingerprinting_payload = emm_payload_.add_fingerprinting(); for (const auto& channel : fingerprinting_param.channels) { @@ -51,8 +69,14 @@ Status Emm::SetServiceBlocking( // First clear all current service blocking payload. emm_payload_.clear_service_blocking(); - // TODO(b/161149665): validate passed in data. Status status; + for (const auto& service_blocking : service_blockings) { + status = ValidateServiceBlockingInitParameters(service_blocking); + if (!status.ok()) { + return status; + } + } + for (const auto& service_blocking_param : service_blockings) { ServiceBlocking* service_blocking_payload = emm_payload_.add_service_blocking(); @@ -78,7 +102,7 @@ Status Emm::GenerateEmm(std::string* serialized_emm) const { EmmSerializingParameters serializing_params; serializing_params.payload = emm_payload_.SerializeAsString(); - serializing_params.timestamp = GenerateTimestamp(); + serializing_params.timestamp = GenerateTimestampEpochSeconds(); // Generate serialized emm (without signature yet). Status status = @@ -88,7 +112,47 @@ Status Emm::GenerateEmm(std::string* serialized_emm) const { } // Calculate and append signature. - absl::StrAppend(serialized_emm, GenerateSignature(*serialized_emm)); + std::string signature; + status = GenerateSignature(*serialized_emm, &signature); + if (!status.ok()) { + return status; + } + absl::StrAppend(serialized_emm, signature); + return OkStatus(); +} + +Status Emm::GenerateEmmTsPackets(uint16_t pid, uint8_t* continuity_counter, + uint8_t* packet, ssize_t* packet_size) const { + if (continuity_counter == nullptr || packet == nullptr || + packet_size == nullptr) { + return {error::INVALID_ARGUMENT, + "continuity_counter, packet and packet_size must not be null"}; + } + + std::string serialized_emm; + Status status = GenerateEmm(&serialized_emm); + if (!status.ok()) { + return status; + } + if (*packet_size < static_cast(CalculateTsBufferSizeForEcmEmm( + serialized_emm.size()))) { + return {error::INVALID_ARGUMENT, "packet buffer is too small"}; + } + + ssize_t bytes_modified = 0; + status = InsertEmmAsTsPacket(serialized_emm, pid, continuity_counter, packet, + &bytes_modified); + if (!status.ok() || bytes_modified <= 0 || + bytes_modified % kTsPacketSize != 0) { + LOG(ERROR) << "Failed to generate TS packet: " + << (status.ok() + ? absl::StrCat("Unexpected bytes_modified value ", + bytes_modified) + : status.error_message()); + return {error::INTERNAL, "Failed to generate TS packet"}; + } + + *packet_size = bytes_modified; return OkStatus(); } @@ -121,15 +185,76 @@ Status Emm::GenerateSerializedEmmNoSignature( return OkStatus(); } -int64_t Emm::GenerateTimestamp() const { - // TODO(b/161252065): Generate timestamp. - return 0; +int64_t Emm::GenerateTimestampEpochSeconds() const { + return absl::ToUnixSeconds(absl::Now()); } -std::string Emm::GenerateSignature(const std::string& content) const { - // TODO(b/161252442): Calculate signature. - std::string signature(32, 'x'); // A fake 32 bytes signature. - return signature; +Status Emm::GenerateSignature(const std::string& message, + std::string* signature) const { + DCHECK(signature); + if (message.empty()) { + return {error::INVALID_ARGUMENT, "Input message must not be empty."}; + } + if (private_signing_key_.empty()) { + return {error::NOT_FOUND, "Private signing key is not set."}; + } + + std::unique_ptr ec_private_key( + ECPrivateKey::Create(private_signing_key_)); + if (ec_private_key == nullptr) { + return Status(error::INTERNAL, "Failed to construct a ECPrivateKey."); + } + if (!ec_private_key->GenerateSignature(message, HashAlgorithm::kSha256, + signature)) { + return Status(error::INTERNAL, "Failed to generate signature."); + } + if (signature->empty()) { + return Status(error::INTERNAL, "Computed signature is empty."); + } + return OkStatus(); +} + +Status Emm::ValidateFingerprintingInitParameters( + const FingerprintingInitParameters& fingerprinting) const { + if (fingerprinting.channels.empty()) { + return {error::INVALID_ARGUMENT, "channels are missing."}; + } + if (fingerprinting.control.empty()) { + return {error::INVALID_ARGUMENT, "control is missing."}; + } + for (const auto& channel : fingerprinting.channels) { + if (channel.empty()) { + return {error::INVALID_ARGUMENT, "empty channel is observed."}; + } + } + return OkStatus(); +} + +Status Emm::ValidateServiceBlockingInitParameters( + const ServiceBlockingInitParameters& service_blocking) const { + if (service_blocking.channels.empty()) { + return {error::INVALID_ARGUMENT, "channels are missing."}; + } + if (service_blocking.device_groups.empty()) { + return {error::INVALID_ARGUMENT, "device_groups are missing."}; + } + for (const auto& channel : service_blocking.channels) { + if (channel.empty()) { + return {error::INVALID_ARGUMENT, "empty channel is observed."}; + } + } + for (const auto& device_group : service_blocking.device_groups) { + if (device_group.empty()) { + return {error::INVALID_ARGUMENT, "empty device_group is observed."}; + } + } + if (service_blocking.end_time == 0) { + return {error::INVALID_ARGUMENT, "end_time must be specified"}; + } + if (service_blocking.end_time <= service_blocking.start_time) { + return {error::INVALID_ARGUMENT, "end_time must be after start_time"}; + } + return OkStatus(); } } // namespace cas diff --git a/media_cas_packager_sdk/internal/emm.h b/media_cas_packager_sdk/internal/emm.h index cfb6a84..7863e48 100644 --- a/media_cas_packager_sdk/internal/emm.h +++ b/media_cas_packager_sdk/internal/emm.h @@ -27,14 +27,15 @@ struct FingerprintingInitParameters { struct ServiceBlockingInitParameters { std::vector channels; std::vector device_groups; - // Value 0 in start_time means immediate. + // Epoch time in seconds. Value 0 in start_time means immediate. int64_t start_time = 0; - int64_t end_time; + // Epoch time in seconds. + int64_t end_time = 0; }; -// Generator for producing Widevine CAS-compliant EMMs. Used to construct the -// Transport Stream packet payload of an EMM containing messages including -// fingerprinting and service blocking. +// Generator for producing Widevine CAS-compliant EMMs (Entitlement Management +// Messages). Used to construct the TS (Transport Stream) packet payload of an +// EMM containing messages including fingerprinting and service blocking. // Class Emm is not thread safe. class Emm { public: @@ -43,16 +44,34 @@ class Emm { Emm& operator=(const Emm&) = delete; virtual ~Emm() = default; + // Sets the signing key used to generate signature field in EMM. + // Must be called before calling GenerateEmm() or GenerateEmmTsPackets(). + virtual Status SetPrivateSigningKey(const std::string& private_signing_key); + // Replaces current fingerprinting info with |fingerprintings|. - Status SetFingerprinting( + virtual Status SetFingerprinting( const std::vector& fingerprintings); // Replaces current service blocking info with |service_blockings|. - Status SetServiceBlocking( + virtual Status SetServiceBlocking( const std::vector& service_blockings); // Generates serialized EMM to |serialized_emm|. - Status GenerateEmm(std::string* serialized_emm) const; + virtual Status GenerateEmm(std::string* serialized_emm) const; + + // Generates serialized EMM and wraps it in TS (transport stream) packets. + // Args (all pointer parameters must be not nullptr): + // - |pid| program ID for the EMM stream + // - |continuity_counter| continuity_counter for the EMM packet, + // it will be incremented, only last 4 bits are used + // - |packet| a buffer to be used to return the generated TS packet. Must be + // able to hold the maximum possible size of genereated Ts packets + // (kMaxPossibleTsPacketsSizeBytes = 1128 bytes). + // - |packet_size| is the size of the allocated |packet|. It will be updated + // as the number of bytes actually used. + virtual Status GenerateEmmTsPackets(uint16_t pid, uint8_t* continuity_counter, + uint8_t* packet, + ssize_t* packet_size) const; private: struct EmmSerializingParameters { @@ -63,10 +82,17 @@ class Emm { Status GenerateSerializedEmmNoSignature( const EmmSerializingParameters& params, std::string* serialized_emm) const; - int64_t GenerateTimestamp() const; - std::string GenerateSignature(const std::string& content) const; + virtual int64_t GenerateTimestampEpochSeconds() const; + virtual Status GenerateSignature(const std::string& message, + std::string* signature) const; + + Status ValidateFingerprintingInitParameters( + const FingerprintingInitParameters& fingerprinting) const; + Status ValidateServiceBlockingInitParameters( + const ServiceBlockingInitParameters& service_blocking) const; EmmPayload emm_payload_; + std::string private_signing_key_; }; } // namespace cas diff --git a/media_cas_packager_sdk/internal/emm_test.cc b/media_cas_packager_sdk/internal/emm_test.cc index ffa4e1c..b861f64 100644 --- a/media_cas_packager_sdk/internal/emm_test.cc +++ b/media_cas_packager_sdk/internal/emm_test.cc @@ -8,9 +8,26 @@ #include "media_cas_packager_sdk/internal/emm.h" +#include + #include "testing/gmock.h" #include "testing/gunit.h" +#include "absl/memory/memory.h" +#include "absl/strings/escaping.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "common/ec_key.h" +#include "common/ec_test_keys.h" +#include "common/hash_algorithm.h" +#include "common/status.h" +#include "media_cas_packager_sdk/internal/mpeg2ts.h" +using ::testing::DoAll; +using ::testing::ElementsAreArray; +using ::testing::HasSubstr; +using ::testing::NotNull; +using ::testing::Return; +using ::testing::SetArgPointee; namespace widevine { namespace cas { @@ -22,19 +39,91 @@ constexpr char kChannelThree[] = "CH3"; constexpr char kFingerprintingControl[] = "controls"; constexpr char kDeviceGroupOne[] = "Group1"; constexpr char kDeviceGroupTwo[] = "Group2"; -constexpr int64_t kServiceBockingStartTime = 100; -constexpr int64_t kServiceBockingEndTime = 1000; +constexpr int64_t kServiceBockingStartTime = 1597342393; +constexpr int64_t kServiceBockingEndTime = 1597342394; +constexpr uint16_t kTestPid = 1; +constexpr int64_t kTestTimestamp = 1597882875; +// Hex std::string of kTestTimestamp. +constexpr char kTestTimestampHexString[] = "000000005f3dc1fb"; -// Length in bytes when there is no payload. -constexpr uint8_t kExpectedNoPayloadLengthBytes = 44; constexpr uint8_t kExpectedEmmVersion = 1; constexpr uint8_t kExpectedHeaderLength = 8; -constexpr uint8_t kVersionStartIndex = 0; -constexpr uint8_t kHeaderLengthStartIndex = 1; -constexpr uint8_t kPayloadLengthStartIndex = 10; -constexpr uint8_t kPayloadStartIndex = 12; -constexpr uint8_t kSignatureLength = 32; +constexpr int kVersionStartIndex = 0; +constexpr int kHeaderLengthStartIndex = 1; +constexpr int kTimestampStartIndex = 2; +constexpr int kTimestampLengthBytes = 8; +constexpr int kPayloadLengthStartIndex = 10; +constexpr int kPayloadStartIndex = 12; +constexpr int kSignatureLength = 71; +// Length in bytes when there is no payload. +constexpr int kExpectedNoPayloadLengthBytes = + kPayloadStartIndex + kSignatureLength; + +constexpr char kFakeSignatureFiller = 'x'; // 0x78 + +constexpr char kExpectedEmptyEmmPacket[] = { + // TS header. + '\x47', '\x40', '\x01', '\x10', + // Section header. + '\x00', '\x82', '\x70', '\x53', + // EMM version. + '\x01', + // EMM header size. + '\x08', + // Timestamp (8 bytes) + '\x00', '\x00', '\x00', '\x00', '\x5f', '\x3d', '\xc1', '\xfb', + // Payload length (2 bytes) + '\x00', '\x00', + // Signature (71 bytes) + '\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', + '\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', + // Padding + '\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', '\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', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', + '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', + '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff'}; +constexpr char kExpectedMockEmmPacket[] = { + // TS header. + '\x47', '\x40', '\x01', '\x10', + // Section header. + '\x00', '\x82', '\x70', '\x07', + // Mocked EMM payload ("abcdefg"). + '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', + // Padding + '\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', '\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', '\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', '\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', '\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'}; FingerprintingInitParameters GetValidFingerprintingParams() { FingerprintingInitParameters fingerprinting_params; @@ -68,25 +157,86 @@ void LoadExpectedServiceBlockingProto( service_blocking_payload->set_end_time_sec(kServiceBockingEndTime); } -TEST(EmmTest, GenerateEmmSinglePayloadSuccess) { - Emm emm_gen; +class FakeEmmWithFakeSignature : public Emm { + private: + // Generates a fake signature. + Status GenerateSignature(const std::string& message, + std::string* signature) const override { + signature->assign(kSignatureLength, kFakeSignatureFiller); + return OkStatus(); + } +}; + +// Verifies a timestamp can be generated and inserted into EMM. +TEST(GenerateTimestampEpochSecondsTest, TimestampGenerated) { + const absl::Time test_start_time = absl::Now(); + FakeEmmWithFakeSignature emm_gen; + std::string serialized_emm; + EXPECT_OK(emm_gen.GenerateEmm(&serialized_emm)); + uint32_t timestamp = 0; + // Extract timestamp value from serialized EMM. + for (const auto& timestamp_byte : + serialized_emm.substr(kTimestampStartIndex, kTimestampLengthBytes)) { + timestamp = (timestamp << 8) | static_cast(timestamp_byte); + } + EXPECT_NE(timestamp, 0); + EXPECT_GE(timestamp, absl::ToUnixSeconds(test_start_time)); +} + +class FakeEmm : public Emm { + private: + // Generates a fake timestamp. + int64_t GenerateTimestampEpochSeconds() const override { + return kTestTimestamp; + } + // Generates a fake signature. + Status GenerateSignature(const std::string& message, + std::string* signature) const override { + signature->assign(kSignatureLength, kFakeSignatureFiller); + return OkStatus(); + } +}; + +class EmmTest : public ::testing::Test { + protected: + EmmTest() : emm_(absl::make_unique()) {} + + void VerifiyEmmHeader(const std::string& serialized_emm) { + EXPECT_EQ(static_cast(serialized_emm[kVersionStartIndex]), + kExpectedEmmVersion); + EXPECT_EQ(static_cast(serialized_emm[kHeaderLengthStartIndex]), + kExpectedHeaderLength); + EXPECT_EQ(absl::BytesToHexString(serialized_emm.substr( + kTimestampStartIndex, kTimestampLengthBytes)), + kTestTimestampHexString); + } + void VerifiySignature(const std::string& signature) { + std::string expected_signature(kSignatureLength, kFakeSignatureFiller); + EXPECT_EQ(signature, expected_signature); + } + int GetPayloadLength(const std::string& serialized_emm) { + return static_cast(serialized_emm[kPayloadLengthStartIndex]) << 8 | + static_cast(serialized_emm[kPayloadLengthStartIndex + 1]); + } + + std::unique_ptr emm_; +}; + +// Verifies GenerateEmm is successful with single fingerprinting and +// service_blocking information in the payload. +TEST_F(EmmTest, GenerateEmmSinglePayloadSuccess) { FingerprintingInitParameters fingerprinting = GetValidFingerprintingParams(); ServiceBlockingInitParameters service_blocking = GetValidServiceBlockingParams(); - EXPECT_EQ(emm_gen.SetFingerprinting({fingerprinting}), OkStatus()); - EXPECT_EQ(emm_gen.SetServiceBlocking({service_blocking}), OkStatus()); + EXPECT_OK(emm_->SetFingerprinting({fingerprinting})); + EXPECT_OK(emm_->SetServiceBlocking({service_blocking})); std::string result; - EXPECT_EQ(emm_gen.GenerateEmm(&result), OkStatus()); + EXPECT_OK(emm_->GenerateEmm(&result)); EXPECT_GT(result.length(), kExpectedNoPayloadLengthBytes); + VerifiyEmmHeader(result); - EXPECT_EQ(static_cast(result[kVersionStartIndex]), - kExpectedEmmVersion); - EXPECT_EQ(static_cast(result[kHeaderLengthStartIndex]), - kExpectedHeaderLength); - int payload_lengh = static_cast(result[kPayloadLengthStartIndex]) - << 8 | - static_cast(result[kPayloadLengthStartIndex + 1]); + int payload_lengh = GetPayloadLength(result); ASSERT_GT(payload_lengh, 0); ASSERT_EQ(result.length(), kPayloadStartIndex + payload_lengh + kSignatureLength); @@ -103,37 +253,33 @@ TEST(EmmTest, GenerateEmmSinglePayloadSuccess) { std::string serialized_expected_payload; expected_payload.SerializeToString(&serialized_expected_payload); EXPECT_EQ(payload_section, serialized_expected_payload); + + VerifiySignature(result.substr(kPayloadStartIndex + payload_lengh)); } -TEST(EmmTest, GenerateEmmMultiplePayloadSuccess) { - Emm emm_gen; +// Verifies GenerateEmm is successful with multiple fingerprinting and +// service_blocking information in the payload. +TEST_F(EmmTest, GenerateEmmMultiplePayloadSuccess) { FingerprintingInitParameters fingerprinting_params; fingerprinting_params.channels = {kChannelThree}; fingerprinting_params.control = kFingerprintingControl; - EXPECT_EQ(emm_gen.SetFingerprinting( - {GetValidFingerprintingParams(), fingerprinting_params}), - OkStatus()); + EXPECT_OK(emm_->SetFingerprinting( + {GetValidFingerprintingParams(), fingerprinting_params})); ServiceBlockingInitParameters service_blocking_params; service_blocking_params.channels = {kChannelThree}; service_blocking_params.device_groups = {kDeviceGroupOne, kDeviceGroupTwo}; service_blocking_params.start_time = kServiceBockingStartTime; service_blocking_params.end_time = kServiceBockingEndTime; - EXPECT_EQ(emm_gen.SetServiceBlocking( - {GetValidServiceBlockingParams(), service_blocking_params}), - OkStatus()); + EXPECT_OK(emm_->SetServiceBlocking( + {GetValidServiceBlockingParams(), service_blocking_params})); std::string result; - EXPECT_EQ(emm_gen.GenerateEmm(&result), OkStatus()); + EXPECT_OK(emm_->GenerateEmm(&result)); EXPECT_GT(result.length(), kExpectedNoPayloadLengthBytes); + VerifiyEmmHeader(result); - EXPECT_EQ(static_cast(result[kVersionStartIndex]), - kExpectedEmmVersion); - EXPECT_EQ(static_cast(result[kHeaderLengthStartIndex]), - kExpectedHeaderLength); - int payload_lengh = static_cast(result[kPayloadLengthStartIndex]) - << 8 | - static_cast(result[kPayloadLengthStartIndex + 1]); + int payload_lengh = GetPayloadLength(result); ASSERT_GT(payload_lengh, 0); ASSERT_EQ(result.length(), kPayloadStartIndex + payload_lengh + kSignatureLength); @@ -145,26 +291,24 @@ TEST(EmmTest, GenerateEmmMultiplePayloadSuccess) { ASSERT_TRUE(emm_payload.ParseFromString(payload_section)); EXPECT_EQ(emm_payload.fingerprinting_size(), 2); EXPECT_EQ(emm_payload.service_blocking_size(), 2); + + VerifiySignature(result.substr(kPayloadStartIndex + payload_lengh)); } -TEST(EmmTest, GenerateEmmFingerprintingOnlySuccess) { - Emm emm_gen; +// Verifies GenerateEmm is successful with only fingerprinting information in +// the payload. +TEST_F(EmmTest, GenerateEmmFingerprintingOnlySuccess) { FingerprintingInitParameters fingerprinting = GetValidFingerprintingParams(); - EXPECT_EQ(emm_gen.SetFingerprinting({fingerprinting}), OkStatus()); + EXPECT_OK(emm_->SetFingerprinting({fingerprinting})); // OK to be called again. - EXPECT_EQ(emm_gen.SetFingerprinting({fingerprinting}), OkStatus()); + EXPECT_OK(emm_->SetFingerprinting({fingerprinting})); std::string result; - EXPECT_EQ(emm_gen.GenerateEmm(&result), OkStatus()); + EXPECT_OK(emm_->GenerateEmm(&result)); EXPECT_GT(result.length(), kExpectedNoPayloadLengthBytes); + VerifiyEmmHeader(result); - EXPECT_EQ(static_cast(result[kVersionStartIndex]), - kExpectedEmmVersion); - EXPECT_EQ(static_cast(result[kHeaderLengthStartIndex]), - kExpectedHeaderLength); - int payload_lengh = static_cast(result[kPayloadLengthStartIndex]) - << 8 | - static_cast(result[kPayloadLengthStartIndex + 1]); + int payload_lengh = GetPayloadLength(result); ASSERT_GT(payload_lengh, 0); ASSERT_EQ(result.length(), kPayloadStartIndex + payload_lengh + kSignatureLength); @@ -179,25 +323,23 @@ TEST(EmmTest, GenerateEmmFingerprintingOnlySuccess) { std::string serialized_expected_payload; expected_payload.SerializeToString(&serialized_expected_payload); EXPECT_EQ(payload_section, serialized_expected_payload); + + VerifiySignature(result.substr(kPayloadStartIndex + payload_lengh)); } -TEST(EmmTest, GenerateEmmServiceBlockingOnlySuccess) { - Emm emm_gen; +// Verifies GenerateEmm is successful with only service_blocking information in +// the payload. +TEST_F(EmmTest, GenerateEmmServiceBlockingOnlySuccess) { ServiceBlockingInitParameters service_blocking = GetValidServiceBlockingParams(); - EXPECT_EQ(emm_gen.SetServiceBlocking({service_blocking}), OkStatus()); + EXPECT_OK(emm_->SetServiceBlocking({service_blocking})); std::string result; - EXPECT_EQ(emm_gen.GenerateEmm(&result), OkStatus()); + EXPECT_OK(emm_->GenerateEmm(&result)); EXPECT_GT(result.length(), kExpectedNoPayloadLengthBytes); + VerifiyEmmHeader(result); - EXPECT_EQ(static_cast(result[kVersionStartIndex]), - kExpectedEmmVersion); - EXPECT_EQ(static_cast(result[kHeaderLengthStartIndex]), - kExpectedHeaderLength); - int payload_lengh = static_cast(result[kPayloadLengthStartIndex]) - << 8 | - static_cast(result[kPayloadLengthStartIndex + 1]); + int payload_lengh = GetPayloadLength(result); ASSERT_GT(payload_lengh, 0); ASSERT_EQ(result.length(), kPayloadStartIndex + payload_lengh + kSignatureLength); @@ -212,23 +354,246 @@ TEST(EmmTest, GenerateEmmServiceBlockingOnlySuccess) { std::string serialized_expected_payload; expected_payload.SerializeToString(&serialized_expected_payload); EXPECT_EQ(payload_section, serialized_expected_payload); + + VerifiySignature(result.substr(kPayloadStartIndex + payload_lengh)); } -TEST(EmmTest, GenerateEmmNoPayloadSuccess) { - Emm emm_gen; +// Verifies GenerateEmm is successful with empty payload. +TEST_F(EmmTest, GenerateEmmNoPayloadSuccess) { std::string result; - EXPECT_EQ(emm_gen.GenerateEmm(&result), OkStatus()); + EXPECT_OK(emm_->GenerateEmm(&result)); EXPECT_EQ(result.length(), kExpectedNoPayloadLengthBytes); + VerifiyEmmHeader(result); - EXPECT_EQ(static_cast(result[kVersionStartIndex]), - kExpectedEmmVersion); - EXPECT_EQ(static_cast(result[kHeaderLengthStartIndex]), - kExpectedHeaderLength); - int payload_lengh = static_cast(result[kPayloadLengthStartIndex]) - << 8 | - static_cast(result[kPayloadLengthStartIndex + 1]); + int payload_lengh = GetPayloadLength(result); EXPECT_EQ(payload_lengh, 0); EXPECT_EQ(result.length(), kPayloadStartIndex + kSignatureLength); + + VerifiySignature(result.substr(kPayloadStartIndex + payload_lengh)); +} + +// Verifies GenerateEmmTsPackets is successful with empty payload. +TEST_F(EmmTest, GenerateEmmTsPacketsNoPayloadSuccess) { + uint8_t counter = 0; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = kTsPacketSize; + EXPECT_OK( + emm_->GenerateEmmTsPackets(kTestPid, &counter, packet, &packet_size)); + EXPECT_THAT(packet, ElementsAreArray(kExpectedEmptyEmmPacket)); + EXPECT_EQ(packet_size, kTsPacketSize); +} + +// Verifies GenerateSignature is successful with empty payload. +TEST(GenerateSignatureTest, GenerateSignatureSuccess) { + Emm emm; + std::string emm_generated; + ECTestKeys test_keys; + + // Generates signature for empty EMM payload. + EXPECT_OK(emm.SetPrivateSigningKey(test_keys.private_test_key_1_secp256r1())); + EXPECT_OK(emm.GenerateEmm(&emm_generated)); + + // Empty payload, so payload start is signature start. + std::string message = emm_generated.substr(0, kPayloadStartIndex); + std::string signature = emm_generated.substr(kPayloadStartIndex); + EXPECT_FALSE(signature.empty()); + + // Check the signaure can be verified. + std::unique_ptr public_key( + ECPublicKey::Create(test_keys.public_test_key_1_secp256r1())); + ASSERT_TRUE(public_key != nullptr); + EXPECT_TRUE( + public_key->VerifySignature(message, HashAlgorithm::kSha256, signature)); +} + +// Verifies GenerateEmm fails with no singing key set. +TEST(GenerateSignatureTest, SignningKeyNotSetFail) { + Emm emm; + std::string emm_generated; + Status status = emm.GenerateEmm(&emm_generated); + EXPECT_EQ(status.error_code(), error::NOT_FOUND); + EXPECT_THAT(status.error_message(), HasSubstr("signing key is not set")); +} + +// Verifies GenerateEmm fails with empty singing key set. +TEST(GenerateSignatureTest, SetPrivateSigningKeyEmptyKeyFail) { + Emm emm; + EXPECT_EQ(emm.SetPrivateSigningKey("").error_code(), error::INVALID_ARGUMENT); +} + +// Verifies GenerateEmm fails with invalid singing key set. +TEST(GenerateSignatureTest, InvalidSigningKeyFail) { + Emm emm; + EXPECT_OK(emm.SetPrivateSigningKey("signing key")); + + std::string emm_generated; + Status status = emm.GenerateEmm(&emm_generated); + EXPECT_EQ(status.error_code(), error::INTERNAL); + EXPECT_THAT(status.error_message(), + HasSubstr("Failed to construct a ECPrivateKey")); +} + +// Overrides GenerateEmm() with mocked method for easier test of +// GenerateEmmTsPacketsTest. +class MockEmmGenerate : public Emm { + public: + MOCK_METHOD(Status, GenerateEmm, (std::string * serialized_emm), + (const, override)); +}; + +// Verifies GenerateEmmTsPackets is successful with mocked EMM. +TEST(GenerateEmmTsPacketsTest, MockPayloadSuccess) { + MockEmmGenerate emm_gen; + std::string serialized_emm = "abcdefg"; + EXPECT_CALL(emm_gen, GenerateEmm(NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(serialized_emm), Return(OkStatus()))); + + uint8_t counter = 0; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = kTsPacketSize; + EXPECT_OK( + emm_gen.GenerateEmmTsPackets(kTestPid, &counter, packet, &packet_size)); + EXPECT_THAT(packet, ElementsAreArray(kExpectedMockEmmPacket)); + EXPECT_EQ(packet_size, kTsPacketSize); +} + +// Verifies GenerateEmmTsPackets fails if the given continuity counter is null. +TEST(GenerateEmmTsPacketsTest, NullContinuityCounterPointerFail) { + Emm emm_gen; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = kTsPacketSize; + EXPECT_EQ( + emm_gen.GenerateEmmTsPackets(kTestPid, nullptr, packet, &packet_size) + .error_code(), + error::INVALID_ARGUMENT); +} + +// Verifies GenerateEmmTsPackets fails if the given packet buffer is null. +TEST(GenerateEmmTsPacketsTest, NullPacketBufferFail) { + Emm emm_gen; + uint8_t counter = 0; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = kTsPacketSize; + EXPECT_EQ( + emm_gen.GenerateEmmTsPackets(kTestPid, &counter, nullptr, &packet_size) + .error_code(), + error::INVALID_ARGUMENT); + EXPECT_EQ(emm_gen.GenerateEmmTsPackets(kTestPid, &counter, packet, nullptr) + .error_code(), + error::INVALID_ARGUMENT); +} + +// Verifies GenerateEmmTsPackets fails if the given buffer is too small. +TEST(GenerateEmmTsPacketsTest, PacketBufferTooSmallFail) { + MockEmmGenerate emm_gen; + std::string serialized_emm = "abcdefg"; + EXPECT_CALL(emm_gen, GenerateEmm(NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(serialized_emm), Return(OkStatus()))); + + uint8_t counter = 0; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = 1; + Status status = + emm_gen.GenerateEmmTsPackets(kTestPid, &counter, packet, &packet_size); + EXPECT_EQ(status.error_code(), error::INVALID_ARGUMENT); + EXPECT_THAT(status.error_message(), HasSubstr("buffer is too small")); +} + +TEST(SetFingerprinting, ValidParametersSuccess) { + Emm emm_gen; + EXPECT_OK(emm_gen.SetFingerprinting({GetValidFingerprintingParams()})); +} + +TEST(SetFingerprinting, EmptyParamsFail) { + Emm emm_gen; + FingerprintingInitParameters params; + EXPECT_EQ(emm_gen.SetFingerprinting({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetFingerprinting, EmptyChannelsFail) { + Emm emm_gen; + FingerprintingInitParameters params = GetValidFingerprintingParams(); + params.channels = {}; + EXPECT_EQ(emm_gen.SetFingerprinting({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetFingerprinting, EmptyChannelValueFail) { + Emm emm_gen; + FingerprintingInitParameters params = GetValidFingerprintingParams(); + params.channels = {kChannelOne, ""}; + EXPECT_EQ(emm_gen.SetFingerprinting({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetFingerprinting, EmptyControlsFail) { + Emm emm_gen; + FingerprintingInitParameters params = GetValidFingerprintingParams(); + params.control = ""; + EXPECT_EQ(emm_gen.SetFingerprinting({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, ValidParametersSuccess) { + Emm emm_gen; + EXPECT_OK(emm_gen.SetServiceBlocking({GetValidServiceBlockingParams()})); +} + +TEST(SetServiceBlocking, EmptyParamsFail) { + Emm emm_gen; + ServiceBlockingInitParameters params; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, EmptyChannelsFail) { + Emm emm_gen; + ServiceBlockingInitParameters params = GetValidServiceBlockingParams(); + params.channels = {}; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, EmptyChannelValueFail) { + Emm emm_gen; + ServiceBlockingInitParameters params = GetValidServiceBlockingParams(); + params.channels = {kChannelOne, ""}; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, EmptyDeviceGroupsFail) { + Emm emm_gen; + ServiceBlockingInitParameters params = GetValidServiceBlockingParams(); + params.device_groups = {}; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, EmptyDeviceGroupValueFail) { + Emm emm_gen; + ServiceBlockingInitParameters params = GetValidServiceBlockingParams(); + params.device_groups = {"", kDeviceGroupTwo}; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, InvalidEndTimeFail) { + Emm emm_gen; + ServiceBlockingInitParameters params = GetValidServiceBlockingParams(); + params.end_time = 0; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST(SetServiceBlocking, EndTimeBeforeStartTimeFail) { + Emm emm_gen; + ServiceBlockingInitParameters params = GetValidServiceBlockingParams(); + params.start_time = 10; + params.end_time = 9; + EXPECT_EQ(emm_gen.SetServiceBlocking({params}).error_code(), + error::INVALID_ARGUMENT); } } // namespace diff --git a/media_cas_packager_sdk/internal/emmg.cc b/media_cas_packager_sdk/internal/emmg.cc index baed4bd..c86b3d7 100644 --- a/media_cas_packager_sdk/internal/emmg.cc +++ b/media_cas_packager_sdk/internal/emmg.cc @@ -14,6 +14,8 @@ #include #include "glog/logging.h" +#include "absl/memory/memory.h" +#include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/time/clock.h" @@ -26,17 +28,16 @@ #include "media_cas_packager_sdk/internal/util.h" #include "protos/public/media_cas.pb.h" -// Minimum sending interval in milliseconds. -static constexpr uint16_t KMinSendIntervalMs = 2; -// Maximum number of entitlement key ids shown in private data. -static constexpr uint16_t kMaxNumOfEntitlementKeyIds = 2; -// Entitlement key id length is fixed to 16 bytes. -static constexpr uint16_t kEntitlementKeyIdLength = 16; - namespace widevine { namespace cas { namespace { +// Minimum sending interval in milliseconds. +constexpr uint16_t KMinSendIntervalMillis = 2; +// Data type is Emm. +constexpr uint8_t kEmmDataType = 0; +// Data type is private data. +constexpr uint8_t kPrivateDataDataType = 1; void Print(const char* const msg, size_t msg_size) { for (size_t i = 0; i < msg_size; i++) { @@ -142,7 +143,8 @@ Status HandleParameters(const char* const response, size_t response_length, } // namespace -Emmg::Emmg(EmmgConfig* emmg_config, int server_socket_fd) { +Emmg::Emmg(EmmgConfig* emmg_config, int server_socket_fd) + : emm_impl_(absl::make_unique()) { CHECK(emmg_config); emmg_config_ = emmg_config; server_socket_fd_ = server_socket_fd; @@ -157,7 +159,7 @@ void Emmg::Start() { for (size_t i = 0; i < emmg_config_->max_num_message; i++) { SendDataProvision(); - absl::SleepFor(std::max(absl::Milliseconds(KMinSendIntervalMs), + absl::SleepFor(std::max(absl::Milliseconds(KMinSendIntervalMillis), absl::Milliseconds(send_interval_ms_))); } @@ -226,28 +228,11 @@ void Emmg::BuildStreamBwRequest() { Status Emmg::GeneratePrivateData( const std::string& content_provider, const std::string& content_id, - const std::vector& entitlement_key_ids, uint8_t* buffer) { - DCHECK(buffer); + const std::vector& entitlement_key_ids) { // Generate payload. CaDescriptorPrivateData private_data; private_data.set_provider(content_provider); private_data.set_content_id(content_id); - - if (entitlement_key_ids.size() > kMaxNumOfEntitlementKeyIds) { - return Status( - error::INVALID_ARGUMENT, - absl::StrCat("Number of entitlement key ids shouldn't exceed ", - kMaxNumOfEntitlementKeyIds)); - } - for (const auto& entitlement_key_id : entitlement_key_ids) { - if (entitlement_key_id.size() != kEntitlementKeyIdLength) { - return Status( - error::INVALID_ARGUMENT, - absl::StrCat("Entitlement key id length must be ", - kEntitlementKeyIdLength, ". The offending key id is ", - entitlement_key_id)); - } - } for (const auto& entitlement_key_id : entitlement_key_ids) { private_data.add_entitlement_key_ids(entitlement_key_id); } @@ -270,7 +255,45 @@ Status Emmg::GeneratePrivateData( LOG(ERROR) << status.ToString(); return status; } - memcpy(buffer, ecm_ts_packet.data(), ecm_ts_packet.size()); + + uint8_t datagram[kTsPacketSize]; + memcpy(datagram, ecm_ts_packet.data(), ecm_ts_packet.size()); + simulcrypt_util::AddParam(EMMG_DATAGRAM, datagram, kTsPacketSize, request_, + &request_length_); + return OkStatus(); +} + +Status Emmg::GenerateEmmData() { + Status status; + if (!has_configured_emm_impl_) { + status = emm_impl_->SetPrivateSigningKey( + absl::HexStringToBytes(emmg_config_->ecc_signing_key)); + if (!status.ok()) { + return status; + } + status = emm_impl_->SetFingerprinting(emmg_config_->fingerprinting); + if (!status.ok()) { + return status; + } + status = emm_impl_->SetServiceBlocking(emmg_config_->service_blocking); + if (!status.ok()) { + return status; + } + has_configured_emm_impl_ = true; + } + + uint8_t datagram[kMaxPossibleTsPacketsSizeBytes]; + ssize_t datagram_size = kMaxPossibleTsPacketsSizeBytes; + status = emm_impl_->GenerateEmmTsPackets( + /*pid=*/0, &continuity_counter_, datagram, &datagram_size); + if (!status.ok()) { + return status; + } + if (datagram_size <= 0 || datagram_size % kTsPacketSize != 0) { + return {error::INTERNAL, "Failed to generate EMM TS packet"}; + } + simulcrypt_util::AddParam(EMMG_DATAGRAM, datagram, datagram_size, request_, + &request_length_); return OkStatus(); } @@ -291,16 +314,26 @@ void Emmg::BuildDataProvision() { simulcrypt_util::AddUint16Param(EMMG_DATA_ID, emmg_config_->data_id, request_, &request_length_); - uint8_t datagram[kTsPacketSize]; - Status status = GeneratePrivateData( - emmg_config_->content_provider, emmg_config_->content_id, - emmg_config_->entitlement_key_ids, datagram); + Status status; + // Generate and load datagram to |request_| message based on specified + // data_type. + switch (emmg_config_->data_type) { + case kEmmDataType: + status = GenerateEmmData(); + break; + case kPrivateDataDataType: + status = GeneratePrivateData(emmg_config_->content_provider, + emmg_config_->content_id, + emmg_config_->entitlement_key_ids); + break; + default: + LOG(ERROR) << "Unexpected data type: " << emmg_config_->data_type; + return; + } if (!status.ok()) { - LOG(ERROR) << "Fail to generate private data. " << status.ToString(); + LOG(ERROR) << "Fail to generate datagram. " << status.ToString(); return; } - simulcrypt_util::AddParam(EMMG_DATAGRAM, datagram, kTsPacketSize, request_, - &request_length_); uint16_t total_param_length = request_length_ - 5; Host16ToBigEndian(request_ + 3, &total_param_length); @@ -413,7 +446,7 @@ void Emmg::UpdateSendInterval(uint16_t bandwidth_kbps) { return; } send_interval_ms_ = - std::max(KMinSendIntervalMs, + std::max(KMinSendIntervalMillis, static_cast((kTsPacketSize * 8) / bandwidth_kbps)); LOG(INFO) << "Send interval set to " << send_interval_ms_ << " ms."; } diff --git a/media_cas_packager_sdk/internal/emmg.h b/media_cas_packager_sdk/internal/emmg.h index 005b0a6..f5ca551 100644 --- a/media_cas_packager_sdk/internal/emmg.h +++ b/media_cas_packager_sdk/internal/emmg.h @@ -15,8 +15,9 @@ #include #include "common/status.h" +#include "media_cas_packager_sdk/internal/emm.h" -#define BUFFER_SIZE (1024) +#define BUFFER_SIZE (2048) namespace widevine { namespace cas { @@ -34,6 +35,9 @@ struct EmmgConfig { std::vector entitlement_key_ids; uint16_t bandwidth; uint32_t max_num_message; + std::string ecc_signing_key; + std::vector fingerprinting; + std::vector service_blocking; }; // A struct that is used to hold all possible params for a EMMG request. @@ -67,10 +71,11 @@ class Emmg { size_t request_length_ = 0; char request_[BUFFER_SIZE]; - // Sending interval in milliseconds. Stream specific parameter but currently // only one stream will be setup. uint16_t send_interval_ms_ = 0; + // Internal implementation of Emm. + std::unique_ptr emm_impl_; private: void SendChannelSetup(); @@ -86,7 +91,9 @@ class Emmg { Status GeneratePrivateData( const std::string& content_provider, const std::string& content_id, - const std::vector& entitlement_key_ids, uint8_t* buffer); + const std::vector& entitlement_key_ids); + Status GenerateEmmData(); + void ReceiveResponseAndVerify(uint16_t expected_type); void Send(uint16_t message_type); @@ -98,7 +105,9 @@ class Emmg { // with the MUX server. int server_socket_fd_; // |continuity_counter| is incremented each time private data is generated. - int continuity_counter_ = 0; + // Only the lower 4 bits are used. + uint8_t continuity_counter_ = 0; + bool has_configured_emm_impl_ = false; }; } // namespace cas diff --git a/media_cas_packager_sdk/internal/emmg_test.cc b/media_cas_packager_sdk/internal/emmg_test.cc index bcf4e58..68b18ce 100644 --- a/media_cas_packager_sdk/internal/emmg_test.cc +++ b/media_cas_packager_sdk/internal/emmg_test.cc @@ -23,10 +23,30 @@ namespace widevine { namespace cas { namespace { +constexpr int64_t kTestTimestamp = 1597882875; +constexpr int kSignatureLength = 71; +constexpr char kFakeSignatureFiller = 'x'; // 0x78 + +class FakeEmm : public Emm { + private: + // Generates a fake timestamp. + int64_t GenerateTimestampEpochSeconds() const override { + return kTestTimestamp; + } + // Generates a fake signature. + Status GenerateSignature(const std::string& message, + std::string* signature) const override { + signature->assign(kSignatureLength, kFakeSignatureFiller); + return OkStatus(); + } +}; + class TestableEmmg : public Emmg { public: explicit TestableEmmg(EmmgConfig* emmg_config) - : Emmg(emmg_config, /* server_socket_fd= */ 1) {} + : Emmg(emmg_config, /* server_socket_fd= */ 1) { + emm_impl_ = absl::make_unique(); + } void PublicBuildChannelSetup() { BuildChannelSetup(); } void PublicBuildStreamSetup() { BuildStreamSetup(); } void PublicBuildStreamBwRequest() { BuildStreamBwRequest(); } @@ -48,13 +68,46 @@ class EmmgTest : public ::testing::Test { config_.data_channel_id = 0x0001; config_.data_stream_id = 0x0001; config_.data_id = 0x0001; + config_.bandwidth = 100; + config_.max_num_message = 100; + config_.data_type = 0x01; + } + + void InitEmmg() { emmg_ = absl::make_unique(&config_); } + + void LoadPrivateDataConfigs() { config_.data_type = 0x01; config_.content_provider = "widevine_test"; config_.content_id = "CasTsFake"; config_.entitlement_key_ids = {"fakeKeyId1KeyId1", "fakeKeyId2KeyId2"}; - config_.bandwidth = 100; - config_.max_num_message = 100; - emmg_ = absl::make_unique(&config_); + } + + void LoadEmmDataConfigs() { + config_.data_type = 0x00; + config_.ecc_signing_key = "signing_key"; + FingerprintingInitParameters fingerprinting_1; + fingerprinting_1.channels = {"CH1", "CH2"}; + fingerprinting_1.control = "controls"; + config_.fingerprinting.push_back(std::move(fingerprinting_1)); + + FingerprintingInitParameters fingerprinting_2; + fingerprinting_2.channels = {"CH3"}; + fingerprinting_2.control = "another control"; + config_.fingerprinting.push_back(std::move(fingerprinting_2)); + + ServiceBlockingInitParameters service_blocking_1; + service_blocking_1.channels = {"CH1", "CH2"}; + service_blocking_1.device_groups = {"Group1"}; + service_blocking_1.start_time = 0; + service_blocking_1.end_time = 1234567890; + config_.service_blocking.push_back(std::move(service_blocking_1)); + + ServiceBlockingInitParameters service_blocking_2; + service_blocking_2.channels = {"CH3"}; + service_blocking_2.device_groups = {"Group2", "Group3"}; + service_blocking_2.start_time = 1234567890; + service_blocking_2.end_time = 1234567891; + config_.service_blocking.push_back(std::move(service_blocking_2)); } protected: @@ -76,63 +129,76 @@ class EmmgTest : public ::testing::Test { }; TEST_F(EmmgTest, BuildChannelSetup) { + InitEmmg(); emmg_->PublicBuildChannelSetup(); - EXPECT_EQ(0, memcmp(kTestEmmgChannelSetup, emmg_->GetRequest(), - sizeof(kTestEmmgChannelSetup))); + EXPECT_EQ(memcmp(kTestEmmgChannelSetup, emmg_->GetRequest(), + sizeof(kTestEmmgChannelSetup)), + 0); } -TEST_F(EmmgTest, BuildStreamSetup) { +TEST_F(EmmgTest, BuildStreamSetupPrivateData) { + InitEmmg(); emmg_->PublicBuildStreamSetup(); - EXPECT_EQ(0, memcmp(kTestEmmgStreamSetup, emmg_->GetRequest(), - sizeof(kTestEmmgStreamSetup))); + EXPECT_EQ(memcmp(kTestEmmgStreamSetupForPrivateData, emmg_->GetRequest(), + sizeof(kTestEmmgStreamSetupForPrivateData)), + 0); +} + +TEST_F(EmmgTest, BuildStreamSetupEmm) { + config_.data_type = 0x00; // EMM data type. + InitEmmg(); + emmg_->PublicBuildStreamSetup(); + EXPECT_EQ(memcmp(kTestEmmgStreamSetupForEmm, emmg_->GetRequest(), + sizeof(kTestEmmgStreamSetupForEmm)), + 0); } TEST_F(EmmgTest, BuildStreamBwRequest) { + InitEmmg(); emmg_->PublicBuildStreamBwRequest(); - EXPECT_EQ(0, memcmp(kTestEmmgStreamBwRequest, emmg_->GetRequest(), - sizeof(kTestEmmgStreamBwRequest))); + EXPECT_EQ(memcmp(kTestEmmgStreamBwRequest, emmg_->GetRequest(), + sizeof(kTestEmmgStreamBwRequest)), + 0); } TEST_F(EmmgTest, HandleStreamBwAllocation) { + InitEmmg(); emmg_->PublicHandleResponse(kTestEmmgStreamBwAllocation); - EXPECT_EQ(30, emmg_->GetSendInterval()); + EXPECT_EQ(emmg_->GetSendInterval(), 30); } -TEST_F(EmmgTest, BuildDataProvision) { +TEST_F(EmmgTest, BuildDataProvisionPrivateData) { + LoadPrivateDataConfigs(); + InitEmmg(); emmg_->PublicBuildDataProvision(); - EXPECT_EQ(0, memcmp(kTestEmmgDataProvision, emmg_->GetRequest(), - sizeof(kTestEmmgDataProvision))); + EXPECT_EQ(memcmp(kTestEmmgPrivateDataProvision, emmg_->GetRequest(), + sizeof(kTestEmmgPrivateDataProvision)), + 0); } -TEST_F(EmmgTest, - BuildDataProvisionFailedWhenNumOfEntitlementKeyIdsExceedLimit) { - config_.entitlement_key_ids = {"fakeKeyId1KeyId1", "fakeKeyId2KeyId2", - "fakeKeyId3KeyId3"}; - emmg_ = absl::make_unique(&config_); +TEST_F(EmmgTest, BuildDataProvisionEmmData) { + LoadEmmDataConfigs(); + InitEmmg(); emmg_->PublicBuildDataProvision(); - EXPECT_EQ(0, memcmp(kTestEmptyEmmgDataProvision, emmg_->GetRequest(), - sizeof(kTestEmptyEmmgDataProvision))); -} - -TEST_F(EmmgTest, - BuildDataProvisionFailedWhenEntitlementKeyIdLengthExceedLimit) { - config_.entitlement_key_ids = {"fakeKeyId1KeyId1", "fakeKeyId2KeyId2KeyId2"}; - emmg_ = absl::make_unique(&config_); - emmg_->PublicBuildDataProvision(); - EXPECT_EQ(0, memcmp(kTestEmptyEmmgDataProvision, emmg_->GetRequest(), - sizeof(kTestEmptyEmmgDataProvision))); + EXPECT_EQ(memcmp(kTestEmmgEmmDataProvision, emmg_->GetRequest(), + sizeof(kTestEmmgEmmDataProvision)), + 0); } TEST_F(EmmgTest, BuildStreamCloseRequest) { + InitEmmg(); emmg_->PublicBuildStreamCloseRequest(); - EXPECT_EQ(0, memcmp(kTestEmmgStreamCloseRequest, emmg_->GetRequest(), - sizeof(kTestEmmgStreamCloseRequest))); + EXPECT_EQ(memcmp(kTestEmmgStreamCloseRequest, emmg_->GetRequest(), + sizeof(kTestEmmgStreamCloseRequest)), + 0); } TEST_F(EmmgTest, BuildChannelClose) { + InitEmmg(); emmg_->PublicBuildChannelClose(); - EXPECT_EQ(0, memcmp(kTestEmmgChannelClose, emmg_->GetRequest(), - sizeof(kTestEmmgChannelClose))); + EXPECT_EQ(memcmp(kTestEmmgChannelClose, emmg_->GetRequest(), + sizeof(kTestEmmgChannelClose)), + 0); } } // namespace diff --git a/media_cas_packager_sdk/internal/fixed_key_fetcher.cc b/media_cas_packager_sdk/internal/fixed_key_fetcher.cc index 90daacf..2cb77a7 100644 --- a/media_cas_packager_sdk/internal/fixed_key_fetcher.cc +++ b/media_cas_packager_sdk/internal/fixed_key_fetcher.cc @@ -37,6 +37,9 @@ Status FixedKeyFetcher::MakeHttpRequest(const std::string& signed_request_json, CasEncryptionResponse response; response.set_status(CasEncryptionResponse::OK); response.set_content_id(request.content_id()); + if (request.has_group_id()) { + response.set_group_id(request.group_id()); + } for (const auto& track_type : request.track_types()) { if (request.key_rotation()) { // Add the Even key. diff --git a/media_cas_packager_sdk/internal/mpeg2ts.h b/media_cas_packager_sdk/internal/mpeg2ts.h index 6ac5cf2..ce453e8 100644 --- a/media_cas_packager_sdk/internal/mpeg2ts.h +++ b/media_cas_packager_sdk/internal/mpeg2ts.h @@ -27,6 +27,10 @@ constexpr ProgramId kInvalidPid = 0x2000; constexpr size_t kTsPacketSize = 188; constexpr size_t kTsPacketHeaderSize = 4; constexpr size_t kMaxTsPayloadSize = kTsPacketSize - kTsPacketHeaderSize; +constexpr size_t kMaxSectionSize = 1021; +constexpr size_t kMaxPossibleTsPacketsCount = 6; +constexpr size_t kMaxPossibleTsPacketsSizeBytes = + kMaxPossibleTsPacketsCount * kTsPacketSize; constexpr uint8_t kTsPacketSyncByte = 0x47; diff --git a/media_cas_packager_sdk/internal/util.cc b/media_cas_packager_sdk/internal/util.cc index b7c4803..25064a0 100644 --- a/media_cas_packager_sdk/internal/util.cc +++ b/media_cas_packager_sdk/internal/util.cc @@ -10,22 +10,113 @@ #include +#include #include #include #include "glog/logging.h" +#include "absl/strings/str_cat.h" +#include "common/status.h" #include "media_cas_packager_sdk/internal/ts_packet.h" namespace widevine { namespace cas { namespace { +// Reference https://en.wikipedia.org/wiki/Program-specific_information constexpr size_t kSectionHeaderSize = 4; constexpr size_t kTsFillValue = 0xFF; +// ETSI ETR 289 specifies table ids 0x82 to 0x8F are for CA System private +// usage, which are typically used by EMM, with one table id for each EMM type. +constexpr uint8_t kEmmTableId = 0x82; +// Present at the start of the TS packet payload signaled by the +// payload_unit_start_indicator bit in the TS header. Used to set packet +// alignment bytes or content before the start of tabled payload data. +constexpr uint8_t kPointerFieldZero = '\x00'; +// Here are the 8 bits covers multiple fields from +// "section syntax indicator" to the first two bits of "section length". +// Section syntax indicator (1 bit): Set to 0 as this is not PAT, PMT or CAT. +// Private bit (1 bit): Set to 1 as this is not PAT, PMT or CAT. +// Reserved bits (2 bits): Set to 0x03 (all bits on). +// Section length unused bits (2 bits): Set to 0 (all bits off). +// Section length higher 2 bits (2 bits): 0. +constexpr uint8_t kSyntaxIndicatorToLengthByte = '\x70'; ContinuityCounter Increment(ContinuityCounter continuity_counter) { return ++continuity_counter & 0xf; } + +Status InsertDataAsTsPacket(const std::string& insert_data, ProgramId pid, + uint8_t table_id, ContinuityCounter* cc, + uint8_t* buffer, ssize_t* bytes_modified) { + if (insert_data.empty()) { + return {error::INVALID_ARGUMENT, "insert_data must not be empty"}; + } + if (cc == nullptr || buffer == nullptr || bytes_modified == nullptr) { + return {error::INVALID_ARGUMENT, + "cc, buffer and bytes_modified must not be null"}; + } + if (*bytes_modified % kTsPacketSize != 0) { + return {error::INVALID_ARGUMENT, + "bytes_modified must be a multiple of TS packet size (188 bytes)"}; + } + if (insert_data.size() > kMaxSectionSize) { + return {error::INVALID_ARGUMENT, + absl::StrCat("Data is too large. Max: ", kMaxSectionSize)}; + } + + int reading_index = 0; + while (reading_index < insert_data.size()) { + bool is_first_packet = reading_index == 0; + // Create a TS payload of 184 bytes (Max TS size - ts header length). + std::string payload(kMaxTsPayloadSize, kTsFillValue); + + // Section header if this is the first TS packet. + if (is_first_packet) { + uint8_t syntax_indicator_to_length_byte = + kSyntaxIndicatorToLengthByte | ((insert_data.size() >> 8) & 0x3); + uint8_t emm_size_lower_bits = insert_data.size() & 0xFF; + + memcpy(&payload.at(0), &kPointerFieldZero, 1); + memcpy(&payload.at(1), &table_id, 1); + memcpy(&payload.at(2), &syntax_indicator_to_length_byte, 1); + memcpy(&payload.at(3), &emm_size_lower_bits, 1); + } + + // Payload data. + int payload_index = is_first_packet ? kSectionHeaderSize : 0; + // Min of {remaining bytes in TS payload, remaining bytes in insert data}. + int used_bytes = std::min(kMaxTsPayloadSize - payload_index, + insert_data.size() - reading_index); + memcpy(&payload.at(payload_index), insert_data.substr(reading_index).data(), + used_bytes); + reading_index += used_bytes; + + // Wrap the data with a TS header. + TsPacket ts_packet; + ts_packet.set_payload_unit_start_indicator(is_first_packet); + ts_packet.set_pid(pid); + ts_packet.set_payload(payload); + ts_packet.set_adaptation_field_control(TsPacket::kPayloadOnly); + ts_packet.set_continuity_counter(*cc); + *cc = Increment(*cc); + + // And write the packet to the buffer. + std::string serialized_ts_packet; + Status status = ts_packet.Write(&serialized_ts_packet); + if (!status.ok()) { + return status; + } + if (serialized_ts_packet.size() != kTsPacketSize) { + return {error::INTERNAL, "Unexpected TS packet size generated."}; + } + memcpy(buffer + *bytes_modified, serialized_ts_packet.data(), + serialized_ts_packet.size()); + *bytes_modified += serialized_ts_packet.size(); + } + + return OkStatus(); +} } // namespace void BigEndianToHost16(uint16_t* destination, const void* source) { @@ -68,52 +159,20 @@ void Host32ToBigEndian(void* destination, const uint32_t* source) { Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, uint8_t table_id, ContinuityCounter* cc, uint8_t* buffer, ssize_t* bytes_modified) { - DCHECK(cc); - DCHECK(buffer); - DCHECK(bytes_modified); - DCHECK_EQ(*bytes_modified % kTsPacketSize, 0); + return InsertDataAsTsPacket(ecm, pid, table_id, cc, buffer, bytes_modified); +} - // Create a TS payload of 184 bytes (Max TS size - ts header length). - CHECK_LE(ecm.size(), kMaxTsPayloadSize); - std::string payload(kMaxTsPayloadSize, kTsFillValue); - // Reference https://en.wikipedia.org/wiki/Program-specific_information - static constexpr uint8_t kPointerField = '\x00'; - // Here are the 8 bits covers multiple fields from - // "section syntax indicator" to the first two bits of "section length". - // We always set the first two bits of "section length" to 0 because - // the data follows (i.e. the ECM) cannot be more than 180 bytes, so - // the remaining 8 bits in "section length" is sufficient to store its - // length. - static constexpr uint8_t kSyntaxtIndicatorToLength = '\x70'; - uint8_t ecm_length = ecm.size(); - // Section header. - memcpy(&payload.at(0), &kPointerField, 1); - memcpy(&payload.at(1), &table_id, 1); - memcpy(&payload.at(2), &kSyntaxtIndicatorToLength, 1); - memcpy(&payload.at(3), &ecm_length, 1); - // ECM follows the header. - memcpy(&payload.at(kSectionHeaderSize), ecm.data(), ecm.size()); +Status InsertEmmAsTsPacket(const std::string& emm, ProgramId pid, + ContinuityCounter* cc, uint8_t* buffer, + ssize_t* bytes_modified) { + return InsertDataAsTsPacket(emm, pid, kEmmTableId, cc, buffer, + bytes_modified); +} - // Wrap the data with a TS header. - TsPacket ecm_packet; - ecm_packet.set_payload_unit_start_indicator(true); - ecm_packet.set_pid(pid); - ecm_packet.set_payload(payload); - ecm_packet.set_adaptation_field_control(0x1); - ecm_packet.set_continuity_counter(*cc); - *cc = Increment(*cc); - - // And write the packet. - std::string ecm_ts_packet; - Status status = ecm_packet.Write(&ecm_ts_packet); - if (!status.ok()) { - return status; - } - - memcpy(buffer + *bytes_modified, ecm_ts_packet.data(), ecm_ts_packet.size()); - *bytes_modified += ecm_ts_packet.size(); - - return OkStatus(); +uint16_t CalculateTsBufferSizeForEcmEmm(uint16_t ecm_emm_size) { + return kTsPacketSize * + std::ceil(static_cast(kSectionHeaderSize + ecm_emm_size) / + kMaxTsPayloadSize); } } // namespace cas diff --git a/media_cas_packager_sdk/internal/util.h b/media_cas_packager_sdk/internal/util.h index 0e7c883..d471920 100644 --- a/media_cas_packager_sdk/internal/util.h +++ b/media_cas_packager_sdk/internal/util.h @@ -49,15 +49,39 @@ void Host32ToBigEndian(void* destination, const uint32_t* source); // - |cc| is the continuity counter to use in the header, which will also be // incremented by this function. // - |buffer| is the output buffer. Must be big enough to hold an additional -// 188 bytes. +// 188 bytes * number of TS packets needed to put |ecm|. // - |bytes_modified| the number of bytes which have already been modified in // the |buffer| and is used as an offset. -// |bytes_modified| will be incremented by 188 if insertion of ECM into -// |buffer| is successful. +// |bytes_modified| will be incremented by a multiple of 188 if insertion of +// ECM into |buffer| is successful. Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, uint8_t table_id, ContinuityCounter* cc, uint8_t* buffer, ssize_t* bytes_modified); +// Packages an EMM as a TS packet and inserts it into a buffer. +// Args: +// - |emm| is the serialized EMM. +// - |pid| is the PID used for ECMs in the TS header. +// - |cc| is the continuity counter to use in the header, which will also be +// incremented by this function. +// - |buffer| is the output buffer. Must be big enough to hold an additional +// 188 bytes * number of TS packets needed to put |emm|. +// - |bytes_modified| the number of bytes which have already been modified in +// the |buffer| and is used as an offset. +// |bytes_modified| will be incremented by a multiple of 188 if insertion of +// ECM into |buffer| is successful. +Status InsertEmmAsTsPacket(const std::string& emm, ProgramId pid, + ContinuityCounter* cc, uint8_t* buffer, + ssize_t* bytes_modified); + +// Calculates the buffer size needed to hold TS packets generated by inserting +// ECM/EMM calls InsertEcmAsTsPacket() and InsertEmmAsTsPacket(). The returned +// buffer size will always be a multiple of kTsPacketSize (188 bytes). +// Args: +// - |ecm_emm_size| is the size of the serialized ECM or EMM that will be +// inserted to TS packets. +uint16_t CalculateTsBufferSizeForEcmEmm(uint16_t ecm_emm_size); + } // namespace cas } // namespace widevine diff --git a/media_cas_packager_sdk/internal/util_test.cc b/media_cas_packager_sdk/internal/util_test.cc index 1f8c18b..5f0db0f 100644 --- a/media_cas_packager_sdk/internal/util_test.cc +++ b/media_cas_packager_sdk/internal/util_test.cc @@ -13,8 +13,11 @@ #include "testing/gmock.h" #include "testing/gunit.h" +namespace widevine { +namespace cas { namespace { +constexpr ProgramId kTestPid = 0x1FFD; // ECM payload data taken from a CETS encrypted file at Google Fiber // default_key_id = 0000000000000002, random_iv = 0x30EB, 0xDAF4, 0xC66D, 0x57DC constexpr char kEcmPayload[] = {'\x5F', '\x08', '\x30', '\x30', '\x30', '\x30', @@ -53,28 +56,209 @@ constexpr char kExpectedEcmPacket[] = { '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF', '\xFF'}; -} // namespace - -namespace widevine { -namespace cas { +// 300 bytes payload. +constexpr char kLongPayload[] = { + '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', + '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', + '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', + '\x1c', '\x1d', '\x1e', '\x1f', '\x20', '\x21', '\x22', '\x23', '\x24', + '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', + '\x2e', '\x2f', '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', + '\x37', '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', + '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', '\x48', + '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', '\x50', '\x51', + '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', '\x58', '\x59', '\x5a', + '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', '\x60', '\x61', '\x62', '\x63', + '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6a', '\x6b', '\x6c', + '\x6d', '\x6e', '\x6f', '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', + '\x76', '\x77', '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', + '\x7f', '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', + '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', '\x90', + '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', + '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', '\xa0', '\xa1', '\xa2', + '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', '\xa8', '\xa9', '\xaa', '\xab', + '\xac', '\xad', '\xae', '\xaf', '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', + '\xb5', '\xb6', '\xb7', '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', + '\xbe', '\xbf', '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', + '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', + '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', '\xd8', + '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', '\xe0', '\xe1', + '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', + '\xeb', '\xec', '\xed', '\xee', '\xef', '\xf0', '\xf1', '\xf2', '\xf3', + '\xf4', '\xf5', '\xf6', '\xf7', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', + '\xfd', '\xfe', '\xff', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', + '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', + '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\x20', '\x21', + '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', + '\x2b', '\x2c', '\x2d'}; +constexpr char kExpectedLongTs[] = { + // The 1st TS header. + '\x47', '\x5f', '\xfd', '\x10', + // Section header. + '\x00', '\x80', '\x71', '\x2c', + // Payload. + '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\x09', + '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', '\x10', '\x11', '\x12', + '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', + '\x1c', '\x1d', '\x1e', '\x1f', '\x20', '\x21', '\x22', '\x23', '\x24', + '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', + '\x2e', '\x2f', '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', + '\x37', '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f', + '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', '\x48', + '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', '\x50', '\x51', + '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', '\x58', '\x59', '\x5a', + '\x5b', '\x5c', '\x5d', '\x5e', '\x5f', '\x60', '\x61', '\x62', '\x63', + '\x64', '\x65', '\x66', '\x67', '\x68', '\x69', '\x6a', '\x6b', '\x6c', + '\x6d', '\x6e', '\x6f', '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', + '\x76', '\x77', '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', + '\x7f', '\x80', '\x81', '\x82', '\x83', '\x84', '\x85', '\x86', '\x87', + '\x88', '\x89', '\x8a', '\x8b', '\x8c', '\x8d', '\x8e', '\x8f', '\x90', + '\x91', '\x92', '\x93', '\x94', '\x95', '\x96', '\x97', '\x98', '\x99', + '\x9a', '\x9b', '\x9c', '\x9d', '\x9e', '\x9f', '\xa0', '\xa1', '\xa2', + '\xa3', '\xa4', '\xa5', '\xa6', '\xa7', '\xa8', '\xa9', '\xaa', '\xab', + '\xac', '\xad', '\xae', '\xaf', '\xb0', '\xb1', '\xb2', '\xb3', '\xb4', + // The 2nd TS header. + '\x47', '\x1f', '\xfd', '\x11', + // Payload (continued). + '\xb5', '\xb6', '\xb7', '\xb8', '\xb9', '\xba', '\xbb', '\xbc', '\xbd', + '\xbe', '\xbf', '\xc0', '\xc1', '\xc2', '\xc3', '\xc4', '\xc5', '\xc6', + '\xc7', '\xc8', '\xc9', '\xca', '\xcb', '\xcc', '\xcd', '\xce', '\xcf', + '\xd0', '\xd1', '\xd2', '\xd3', '\xd4', '\xd5', '\xd6', '\xd7', '\xd8', + '\xd9', '\xda', '\xdb', '\xdc', '\xdd', '\xde', '\xdf', '\xe0', '\xe1', + '\xe2', '\xe3', '\xe4', '\xe5', '\xe6', '\xe7', '\xe8', '\xe9', '\xea', + '\xeb', '\xec', '\xed', '\xee', '\xef', '\xf0', '\xf1', '\xf2', '\xf3', + '\xf4', '\xf5', '\xf6', '\xf7', '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', + '\xfd', '\xfe', '\xff', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', + '\x07', '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', + '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', '\x20', '\x21', + '\x22', '\x23', '\x24', '\x25', '\x26', '\x27', '\x28', '\x29', '\x2a', + '\x2b', '\x2c', '\x2d', + // Padding. + '\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', '\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'}; // TODO(user): Add unit tests for BigEndianToHost16, BigEndianToHost32 and // Host16ToBigEndian. -TEST(InsertEcmAsTsPacketTest, BasicHappyPath) { +TEST(InsertEcmAsTsPacketTest, SingleTsPacket) { // declare variables used by InsertEcmAsTsPacket() - ContinuityCounter ecm_cc_ = 0; - ProgramId video_ecm_pid_ = 0x1FFD; - uint8_t buffer[188]; // output ts packet size + ContinuityCounter ecm_cc = 0; + uint8_t buffer[kTsPacketSize]; // output ts packet size ssize_t output_bytes_modified = 0; // convert kEcmPayload[] into a std::string to be accepted by the method std::string ecm_data(kEcmPayload); - EXPECT_OK(InsertEcmAsTsPacket(ecm_data, video_ecm_pid_, kTsPacketTableId80, - &ecm_cc_, buffer, &output_bytes_modified)); - EXPECT_EQ(0, memcmp(kExpectedEcmPacket, buffer, sizeof(buffer))); - EXPECT_EQ(1, ecm_cc_); - EXPECT_EQ(188, output_bytes_modified); + + EXPECT_OK(InsertEcmAsTsPacket(ecm_data, kTestPid, kTsPacketTableId80, &ecm_cc, + buffer, &output_bytes_modified)); + + EXPECT_EQ(memcmp(kExpectedEcmPacket, buffer, sizeof(buffer)), 0); + EXPECT_EQ(ecm_cc, 1); + EXPECT_EQ(output_bytes_modified, kTsPacketSize); } +TEST(InsertEcmAsTsPacketTest, MultipleTsPackets) { + ContinuityCounter ecm_cc = 0; + uint8_t buffer[kTsPacketSize * 2]; + ssize_t output_bytes_modified = 0; + std::string long_payload(kLongPayload); + + EXPECT_OK(InsertEcmAsTsPacket(long_payload, kTestPid, kTsPacketTableId80, + &ecm_cc, buffer, &output_bytes_modified)); + + EXPECT_EQ(memcmp(kExpectedLongTs, buffer, sizeof(buffer)), 0); + EXPECT_EQ(ecm_cc, 2); + EXPECT_EQ(output_bytes_modified, kTsPacketSize * 2); +} + +TEST(InsertEmmAsTsPacketTest, SingleTsPacket) { + ContinuityCounter counter = 0; + uint8_t buffer[kTsPacketSize]; + ssize_t output_bytes_modified = 0; + std::string payload(kEcmPayload); + + EXPECT_OK(InsertEmmAsTsPacket(payload, kTestPid, &counter, buffer, + &output_bytes_modified)); + + char expectedEmmPacket[sizeof(kExpectedEcmPacket)]; + memcpy(expectedEmmPacket, kExpectedEcmPacket, sizeof(kExpectedEcmPacket)); + expectedEmmPacket[5] = 0x82; // Expected table id for emm + EXPECT_EQ(memcmp(expectedEmmPacket, buffer, sizeof(buffer)), 0); + EXPECT_EQ(counter, 1); + EXPECT_EQ(output_bytes_modified, kTsPacketSize); +} + +TEST(InsertEmmAsTsPacketTest, MultipleTsPackets) { + ContinuityCounter counter = 0; + uint8_t buffer[kTsPacketSize * 2]; + ssize_t output_bytes_modified = 0; + std::string long_payload(kLongPayload); + + EXPECT_OK(InsertEmmAsTsPacket(long_payload, kTestPid, &counter, buffer, + &output_bytes_modified)); + + char expectedEmmPacket[sizeof(kExpectedLongTs)]; + memcpy(expectedEmmPacket, kExpectedLongTs, sizeof(kExpectedLongTs)); + expectedEmmPacket[5] = 0x82; // Expected table id for emm + EXPECT_EQ(memcmp(expectedEmmPacket, buffer, sizeof(buffer)), 0); + EXPECT_EQ(counter, 2); + EXPECT_EQ(output_bytes_modified, kTsPacketSize * 2); +} + +TEST(InsertEcmAsTsPacketTest, InvalidArgument) { + ContinuityCounter counter = 0; + uint8_t buffer[kTsPacketSize]; + ssize_t output_bytes_modified = 0; + std::string payload(kEcmPayload); + + // Continuity counter is null. + EXPECT_EQ(InsertEcmAsTsPacket(payload, kTestPid, kTsPacketTableId80, nullptr, + buffer, &output_bytes_modified) + .error_code(), + error::INVALID_ARGUMENT); + // Buffer is null. + EXPECT_EQ(InsertEcmAsTsPacket(payload, kTestPid, kTsPacketTableId80, &counter, + nullptr, &output_bytes_modified) + .error_code(), + error::INVALID_ARGUMENT); + // Output bytes modified is null. + EXPECT_EQ(InsertEcmAsTsPacket(payload, kTestPid, kTsPacketTableId80, &counter, + buffer, nullptr) + .error_code(), + error::INVALID_ARGUMENT); + + // Payload is empty. + EXPECT_EQ(InsertEcmAsTsPacket("", kTestPid, kTsPacketTableId80, &counter, + buffer, &output_bytes_modified) + .error_code(), + error::INVALID_ARGUMENT); + + // Payload is too large. + std::string too_large_payload(kMaxSectionSize + 1, '\x11'); + EXPECT_EQ(InsertEcmAsTsPacket(too_large_payload, kTestPid, kTsPacketTableId80, + &counter, buffer, &output_bytes_modified) + .error_code(), + error::INVALID_ARGUMENT); +} + +TEST(CalculateTsBufferSizeForEcmEmm, VariousSize) { + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(1), kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(180), kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(181), 2 * kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(300), 2 * kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(364), 2 * kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(365), 3 * kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(500), 3 * kTsPacketSize); + EXPECT_EQ(CalculateTsBufferSizeForEcmEmm(1021), 6 * kTsPacketSize); +} + +} // namespace } // namespace cas } // namespace widevine diff --git a/media_cas_packager_sdk/public/BUILD b/media_cas_packager_sdk/public/BUILD index 05ab129..310c238 100644 --- a/media_cas_packager_sdk/public/BUILD +++ b/media_cas_packager_sdk/public/BUILD @@ -177,6 +177,18 @@ cc_library( alwayslink = 1, ) +cc_library( + name = "wv_cas_emm", + srcs = ["wv_cas_emm.cc"], + hdrs = ["wv_cas_emm.h"], + deps = [ + "//base", + "@abseil_repo//absl/memory", + "//common:status", + "//media_cas_packager_sdk/internal:emm", + ], +) + cc_test( name = "wv_cas_types_test", size = "small", @@ -187,6 +199,17 @@ cc_test( ], ) +cc_test( + name = "wv_cas_emm_test", + srcs = ["wv_cas_emm_test.cc"], + deps = [ + ":wv_cas_emm", + "//testing:gunit_main", + "//media_cas_packager_sdk/internal:emm", + "//media_cas_packager_sdk/internal:util", + ], +) + cc_binary( name = "wv_ecmg", srcs = ["wv_ecmg.cc"], @@ -206,6 +229,7 @@ cc_binary( "//base", "@abseil_repo//absl/flags:flag", "@abseil_repo//absl/flags:parse", + "@abseil_repo//absl/strings", "//media_cas_packager_sdk/internal:emmg", ], ) diff --git a/media_cas_packager_sdk/public/wv_cas_emm.cc b/media_cas_packager_sdk/public/wv_cas_emm.cc new file mode 100644 index 0000000..39973fd --- /dev/null +++ b/media_cas_packager_sdk/public/wv_cas_emm.cc @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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. +//////////////////////////////////////////////////////////////////////////////// + +#include "media_cas_packager_sdk/public/wv_cas_emm.h" + +#include "glog/logging.h" +#include "absl/memory/memory.h" +#include "media_cas_packager_sdk/internal/emm.h" + +namespace widevine { +namespace cas { + +namespace { +std::vector ConvertFingerprintingInitVector( + const std::vector& params) { + std::vector converted_vector; + converted_vector.reserve(params.size()); + for (const auto& param : params) { + FingerprintingInitParameters converted; + converted.channels.assign(param.channels.begin(), param.channels.end()); + converted.control = param.control; + converted_vector.push_back(converted); + } + return converted_vector; +} + +std::vector ConvertServiceBlockingInitVector( + const std::vector& params) { + std::vector converted_vector; + converted_vector.reserve(params.size()); + for (const auto& param : params) { + ServiceBlockingInitParameters converted; + converted.channels.assign(param.channels.begin(), param.channels.end()); + converted.device_groups.assign(param.device_groups.begin(), + param.device_groups.end()); + converted.start_time = param.start_time; + converted.end_time = param.end_time; + converted_vector.push_back(converted); + } + return converted_vector; +} + +} // namespace + +WvCasEmm::WvCasEmm(std::unique_ptr emm) : emm_(std::move(emm)) {} +WvCasEmm::~WvCasEmm() = default; + +std::unique_ptr WvCasEmm::Create( + const std::string& private_ecc_signing_key) { + if (private_ecc_signing_key.empty()) { + LOG(ERROR) << "private_ecc_signing_key must not be empty."; + return nullptr; + } + + auto emm = absl::make_unique(); + Status status = emm->SetPrivateSigningKey(private_ecc_signing_key); + if (!status.ok()) { + LOG(ERROR) << "Failed to set private signing key: " << status.ToString(); + return nullptr; + } + return absl::WrapUnique(new WvCasEmm(std::move(emm))); +} + +Status WvCasEmm::SetFingerprinting( + const std::vector& fingerprintings) { + return emm_->SetFingerprinting( + ConvertFingerprintingInitVector(fingerprintings)); +} + +Status WvCasEmm::SetServiceBlocking( + const std::vector& service_blockings) { + return emm_->SetServiceBlocking( + ConvertServiceBlockingInitVector(service_blockings)); +} + +Status WvCasEmm::GenerateEmm(std::string* serialized_emm) const { + if (serialized_emm == nullptr) { + return {error::INVALID_ARGUMENT, "serialized_emm must not be null"}; + } + return emm_->GenerateEmm(serialized_emm); +} + +Status WvCasEmm::GenerateEmmTsPackets(uint16_t pid, uint8_t* continuity_counter, + uint8_t* packet, + ssize_t* packet_size) const { + if (continuity_counter == nullptr || packet == nullptr || + packet_size == nullptr) { + return {error::INVALID_ARGUMENT, + "continuity_counter, packet and packet_size must not be null"}; + } + return emm_->GenerateEmmTsPackets(pid, continuity_counter, packet, + packet_size); +} + +} // namespace cas +} // namespace widevine diff --git a/media_cas_packager_sdk/public/wv_cas_emm.h b/media_cas_packager_sdk/public/wv_cas_emm.h new file mode 100644 index 0000000..60f9a80 --- /dev/null +++ b/media_cas_packager_sdk/public/wv_cas_emm.h @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_EMM_H_ +#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_EMM_H_ + +#include +#include +#include + +#include +#include "common/status.h" + +namespace widevine { +namespace cas { + +class Emm; + +struct WvCasFingerprintingInitParameters { + std::vector channels; + std::string control; +}; + +struct WvCasServiceBlockingInitParameters { + std::vector channels; + std::vector device_groups; + // Value 0 in start_time means immediate. + int64_t start_time = 0; + int64_t end_time; +}; + +// Class for generating Widevine CAS EMMs. Widevine CAS EMMs are not used for +// carrying entitlement information. Instead, it is used as an information +// channel carrying information for fingerprinting, service blocking, etc. +// Class WvCasEmm is NOT thread-safe. +class WvCasEmm { + public: + WvCasEmm(const WvCasEmm&) = delete; + WvCasEmm& operator=(const WvCasEmm&) = delete; + virtual ~WvCasEmm(); + + // Creates and returns a WvCasEmm with the given private ECC signing key. + // Returns a null value if the creation is unsuccessful. + static std::unique_ptr Create( + const std::string& private_ecc_signing_key); + + // Replaces current fingerprinting info with |fingerprintings|. + virtual Status SetFingerprinting( + const std::vector& fingerprintings); + + // Replaces current service blocking info with |service_blockings|. + virtual Status SetServiceBlocking( + const std::vector& service_blockings); + + // Constructs an EMM payload with fingerprinting info set by calling + // SetFingerprinting(), and service blocking info set by calling + // SetServiceBlocking(). + // Args (all pointer parameters must not be nullptr): + // - |serialized_emm| caller-supplied std::string pointer to receive the EMM. + virtual Status GenerateEmm(std::string* serialized_emm) const; + + // Generates EMM that are wrapped in TS packets. + // Args (all pointer parameters must not be nullptr): + // - |pid| program ID for the EMM stream. + // - |continuity_counter| continuity_counter for the TS packet. It will be + // automatically incremented. Only the last 4 bits are used. + // - |packet| a buffer to be used to return the generated TS packet. Must be + // able to hold the maximum possible size of genereated Ts packets + // (kMaxPossibleTsPacketsSizeBytes = 1128 bytes). + // - |packet_size| is the size of the allocated |packet|. It will be updated + // as the number of bytes actually used. + virtual Status GenerateEmmTsPackets(uint16_t pid, uint8_t* continuity_counter, + uint8_t* packet, + ssize_t* packet_size) const; + + protected: + explicit WvCasEmm(std::unique_ptr emm); + + private: + std::unique_ptr emm_; +}; + +} // namespace cas +} // namespace widevine + +#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_EMM_H_ diff --git a/media_cas_packager_sdk/public/wv_cas_emm_test.cc b/media_cas_packager_sdk/public/wv_cas_emm_test.cc new file mode 100644 index 0000000..022481b --- /dev/null +++ b/media_cas_packager_sdk/public/wv_cas_emm_test.cc @@ -0,0 +1,260 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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. +//////////////////////////////////////////////////////////////////////////////// + +#include "media_cas_packager_sdk/public/wv_cas_emm.h" + +#include +#include + +#include "testing/gmock.h" +#include "testing/gunit.h" +#include "media_cas_packager_sdk/internal/emm.h" +#include "media_cas_packager_sdk/internal/mpeg2ts.h" + +using ::testing::DoAll; +using ::testing::ElementsAreArray; +using ::testing::IsEmpty; +using ::testing::IsNull; +using ::testing::NotNull; +using ::testing::Pointwise; +using ::testing::Return; +using ::testing::SetArgPointee; +using ::testing::SetArrayArgument; + +namespace widevine { +namespace cas { +namespace { + +constexpr int kTestPid = 1; +constexpr char kChannelOne[] = "CH1"; +constexpr char kChannelTwo[] = "CH2"; +constexpr char kChannelThree[] = "CH3"; +constexpr char kFingerprintingControl[] = "controls"; +constexpr char kFingerprintingControlTwo[] = "another control"; +constexpr char kDeviceGroupOne[] = "Group1"; +constexpr char kDeviceGroupTwo[] = "Group2"; +constexpr int64_t kServiceBockingStartTime = 100; +constexpr int64_t kServiceBockingEndTime = 1000; + +TEST(WvCasEmmFactoryCeateTest, FactoryCreateSuccess) { + EXPECT_THAT(WvCasEmm::Create("Signing key"), NotNull()); +} + +TEST(WvCasEmmFactoryCeateTest, EmptySigningKeyFail) { + EXPECT_THAT(WvCasEmm::Create(/*private_ecc_signing_key=*/""), IsNull()); +} + +class MockEmm : public Emm { + public: + MOCK_METHOD( + Status, SetFingerprinting, + (const std::vector& fingerprintings), + (override)); + MOCK_METHOD( + Status, SetServiceBlocking, + (const std::vector& service_blockings), + (override)); + MOCK_METHOD(Status, GenerateEmm, (std::string * serialized_emm), + (const, override)); + MOCK_METHOD(Status, GenerateEmmTsPackets, + (uint16_t pid, uint8_t* continuity_counter, uint8_t* packet, + ssize_t* packet_size), + (const, override)); +}; + +class MockWvCasEmm : public WvCasEmm { + public: + explicit MockWvCasEmm(Emm* emm) : WvCasEmm(std::unique_ptr(emm)) {} +}; + +class WvCasEmmTest : public ::testing::Test { + protected: + WvCasEmmTest() + : mock_internal_emm_(new MockEmm()), + cas_emm_(new MockWvCasEmm(mock_internal_emm_)) {} + + MockEmm* const mock_internal_emm_; + std::unique_ptr cas_emm_; +}; + +MATCHER(FingerprintingEq, "") { + const auto& actual = std::get<0>(arg); + const auto& expected = std::get<1>(arg); + return (actual.channels == expected.channels) && + (actual.control == expected.control); +} + +MATCHER(ServiceBlockingEq, "") { + const auto& actual = std::get<0>(arg); + const auto& expected = std::get<1>(arg); + return (actual.channels == expected.channels) && + (actual.device_groups == expected.device_groups) && + (actual.start_time == expected.start_time) && + (actual.end_time == expected.end_time); +} + +TEST_F(WvCasEmmTest, SetFingerprintingSuccess) { + EXPECT_CALL(*mock_internal_emm_, SetFingerprinting(IsEmpty())) + .WillOnce(Return(OkStatus())); + EXPECT_OK(cas_emm_->SetFingerprinting({})); +} + +TEST_F(WvCasEmmTest, SetFingerprintingConvertSuccess) { + std::vector param_vector; + param_vector.reserve(2); + param_vector.emplace_back(); + param_vector.back().channels = {kChannelOne, kChannelTwo}; + param_vector.back().control = kFingerprintingControl; + param_vector.emplace_back(); + param_vector.back().channels = {kChannelThree}; + param_vector.back().control = kFingerprintingControlTwo; + + std::vector expected_vector; + expected_vector.reserve(2); + expected_vector.emplace_back(); + expected_vector.back().channels = {kChannelOne, kChannelTwo}; + expected_vector.back().control = kFingerprintingControl; + expected_vector.emplace_back(); + expected_vector.back().channels = {kChannelThree}; + expected_vector.back().control = kFingerprintingControlTwo; + + EXPECT_CALL(*mock_internal_emm_, + SetFingerprinting(Pointwise(FingerprintingEq(), expected_vector))) + .WillOnce(Return(OkStatus())); + EXPECT_OK(cas_emm_->SetFingerprinting(param_vector)); +} + +TEST_F(WvCasEmmTest, SetFingerprintingFail) { + EXPECT_CALL(*mock_internal_emm_, SetFingerprinting(IsEmpty())) + .WillOnce(Return(Status(error::INVALID_ARGUMENT))); + EXPECT_EQ(cas_emm_->SetFingerprinting({}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST_F(WvCasEmmTest, SetServiceBlockingSuccess) { + EXPECT_CALL(*mock_internal_emm_, SetServiceBlocking(IsEmpty())) + .WillOnce(Return(OkStatus())); + EXPECT_OK(cas_emm_->SetServiceBlocking({})); +} + +TEST_F(WvCasEmmTest, SetServiceBlockingConvertSuccess) { + std::vector param_vector; + param_vector.reserve(2); + param_vector.emplace_back(); + param_vector.back().channels = {kChannelOne, kChannelTwo}; + param_vector.back().device_groups = {kDeviceGroupOne, kDeviceGroupTwo}; + param_vector.back().start_time = kServiceBockingStartTime; + param_vector.back().end_time = kServiceBockingEndTime; + param_vector.emplace_back(); + param_vector.back().channels = {kChannelThree}; + + std::vector expected_vector; + expected_vector.reserve(2); + expected_vector.emplace_back(); + expected_vector.back().channels = {kChannelOne, kChannelTwo}; + expected_vector.back().device_groups = {kDeviceGroupOne, kDeviceGroupTwo}; + expected_vector.back().start_time = kServiceBockingStartTime; + expected_vector.back().end_time = kServiceBockingEndTime; + expected_vector.emplace_back(); + expected_vector.back().channels = {kChannelThree}; + + EXPECT_CALL(*mock_internal_emm_, SetServiceBlocking(Pointwise( + ServiceBlockingEq(), expected_vector))) + .WillOnce(Return(OkStatus())); + EXPECT_OK(cas_emm_->SetServiceBlocking(param_vector)); +} + +TEST_F(WvCasEmmTest, SetServiceBlockingFail) { + EXPECT_CALL(*mock_internal_emm_, SetServiceBlocking(IsEmpty())) + .WillOnce(Return(Status(error::INVALID_ARGUMENT))); + EXPECT_EQ(cas_emm_->SetServiceBlocking({}).error_code(), + error::INVALID_ARGUMENT); +} + +TEST_F(WvCasEmmTest, GenerateEmmSuccess) { + std::string expected_emm = "emm"; + EXPECT_CALL(*mock_internal_emm_, GenerateEmm(NotNull())) + .WillOnce(DoAll(SetArgPointee<0>(expected_emm), Return(OkStatus()))); + + std::string generated_emm; + EXPECT_OK(cas_emm_->GenerateEmm(&generated_emm)); + EXPECT_EQ(generated_emm, expected_emm); +} + +TEST_F(WvCasEmmTest, GenerateEmmFail) { + EXPECT_CALL(*mock_internal_emm_, GenerateEmm(NotNull())) + .WillOnce(Return(Status(error::INVALID_ARGUMENT))); + + std::string generated_emm; + EXPECT_EQ(cas_emm_->GenerateEmm(&generated_emm).error_code(), + error::INVALID_ARGUMENT); +} + +TEST_F(WvCasEmmTest, GenerateEmmNullBuffer) { + EXPECT_EQ(cas_emm_->GenerateEmm(nullptr).error_code(), + error::INVALID_ARGUMENT); +} + +TEST_F(WvCasEmmTest, GenerateEmmTsPacketsSuccess) { + uint8_t expected_continuity_counter = 2; + uint8_t expected_packet[] = {1, 2, 3, 4, 5}; + EXPECT_CALL(*mock_internal_emm_, + GenerateEmmTsPackets(kTestPid, NotNull(), NotNull(), NotNull())) + .WillOnce( + DoAll(SetArgPointee<1>(expected_continuity_counter), + SetArrayArgument<2>(expected_packet, + expected_packet + sizeof(expected_packet)), + SetArgPointee<3>(sizeof(expected_packet)), Return(OkStatus()))); + + uint8_t continuity_counter = 1; + uint8_t packet[sizeof(expected_packet)]; + ssize_t packet_size = kTsPacketSize; + EXPECT_OK(cas_emm_->GenerateEmmTsPackets(kTestPid, &continuity_counter, + packet, &packet_size)); + EXPECT_EQ(continuity_counter, expected_continuity_counter); + EXPECT_THAT(packet, ElementsAreArray(expected_packet)); +} + +TEST_F(WvCasEmmTest, GenerateEmmTsPacketsFail) { + EXPECT_CALL(*mock_internal_emm_, + GenerateEmmTsPackets(kTestPid, NotNull(), NotNull(), NotNull())) + .WillOnce(Return(Status(error::INVALID_ARGUMENT))); + + uint8_t continuity_counter = 1; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = kTsPacketSize; + EXPECT_EQ(cas_emm_ + ->GenerateEmmTsPackets(kTestPid, &continuity_counter, packet, + &packet_size) + .error_code(), + error::INVALID_ARGUMENT); +} + +TEST_F(WvCasEmmTest, GenerateEmmTsPacketsNullPointer) { + uint8_t continuity_counter = 1; + uint8_t packet[kTsPacketSize]; + ssize_t packet_size = kTsPacketSize; + EXPECT_EQ( + cas_emm_->GenerateEmmTsPackets(kTestPid, nullptr, packet, &packet_size) + .error_code(), + error::INVALID_ARGUMENT); + EXPECT_EQ(cas_emm_ + ->GenerateEmmTsPackets(kTestPid, &continuity_counter, nullptr, + &packet_size) + .error_code(), + error::INVALID_ARGUMENT); + EXPECT_EQ( + cas_emm_ + ->GenerateEmmTsPackets(kTestPid, &continuity_counter, packet, nullptr) + .error_code(), + error::INVALID_ARGUMENT); +} + +} // namespace +} // namespace cas +} // namespace widevine 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 a43af2f..2aab593 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc @@ -61,6 +61,9 @@ Status WvCasKeyFetcher::CreateEntitlementRequest( request.set_content_id(request_params.content_id); request.set_provider(request_params.content_provider); request.set_key_rotation(request_params.key_rotation); + if (!request_params.group_id.empty()) { + request.set_group_id(request_params.group_id); + } // Add labels for tracks. for (const auto& track_type : request_params.track_types) { request.add_track_types(track_type); 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 35c9ac4..8f8213c 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.h +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.h @@ -26,11 +26,15 @@ namespace cas { // server. // |key_rotation| the encryption uses two keys if set. Two entitlement keys // are requested for each track type. +// |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. struct EntitlementRequestParams { std::string content_id; std::string content_provider; std::vector track_types; bool key_rotation; + std::string group_id; }; // WV CAS KeyFetcher. Performs the communication with the Widevine License diff --git a/media_cas_packager_sdk/public/wv_cas_key_fetcher_test.cc b/media_cas_packager_sdk/public/wv_cas_key_fetcher_test.cc index 8c51684..6a6c360 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher_test.cc +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher_test.cc @@ -13,6 +13,7 @@ #include "testing/gmock.h" #include "testing/gunit.h" #include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" #include "protos/public/media_cas_encryption.pb.h" using testing::_; @@ -37,6 +38,12 @@ const char kSignedCasEncryptionRequest[] = "RyYWNrX3R5cGVzIjpbIlNEIl0sImtleV9yb3RhdGlvbiI6ZmFsc2V9\",\"signature\":" "\"JyTnKEy1w98HRP1lL78+OIEiqtIXyfCN8iudvNXIWhw=\",\"signer\":\"widevine_" "test\"}"; +absl::string_view kSignedCasEncryptionRequestForGroupKey = + "{\"request\":" + "\"eyJjb250ZW50X2lkIjoiTWpFeE5EQTRORFE9IiwicHJvdmlkZXIiOiJ3aWRldmluZSIsInRy" + "YWNrX3R5cGVzIjpbIlNEIl0sImtleV9yb3RhdGlvbiI6ZmFsc2UsImdyb3VwX2lkIjoiWjNKdm" + "RYQXgifQ==\",\"signature\":\"iDaAr74ldEV6X1X9kwyLoZ/" + "hfP5RJOkXEzucq6IXyfQ=\",\"signer\":\"widevine_test\"}"; const char kHttpResponse[] = "{\"response\":" "\"eyJzdGF0dXMiOiJPSyIsImNvbnRlbnRfaWQiOiJNakV4TkRBNE5EUT0iLCJlbnRpdGxlbWVu" @@ -47,6 +54,9 @@ const char kTrackTypeSD[] = "SD"; const char kTrackTypeHD[] = "HD"; const char kProvider[] = "widevine"; const char kContentId[] = "21140844"; +const char kGroupId[] = "group1"; +const char kEntitlementKeyId[] = "fake_key_id....."; +const char kEntitlementKey[] = "fakefakefakefakefakefakefakefake"; } // namespace namespace widevine { @@ -89,6 +99,12 @@ class MockWvCasKeyFetcher : public WvCasKeyFetcher { LOG(ERROR) << "Unable to understand signed_request_json."; return Status(error::INTERNAL); } + // Validate the parameters shown in the request. + EXPECT_EQ(request.content_id(), kContentId); + EXPECT_EQ(request.provider(), kProvider); + if (request.has_group_id()) { + EXPECT_EQ(request.group_id(), kGroupId); + } CasEncryptionResponse response; if (!report_status_ok_) { @@ -96,24 +112,27 @@ class MockWvCasKeyFetcher : public WvCasKeyFetcher { } else { response.set_status(CasEncryptionResponse::OK); response.set_content_id(request.content_id()); + if (request.has_group_id()) { + response.set_group_id(request.group_id()); + } for (const auto& track_type : request.track_types()) { if (request.key_rotation()) { // Add the Even key. auto key = response.add_entitlement_keys(); - key->set_key_id("fake_key_id....."); - key->set_key("fakefakefakefakefakefakefakefake"); + key->set_key_id(kEntitlementKeyId); + key->set_key(kEntitlementKey); key->set_track_type(track_type); key->set_key_slot(CasEncryptionResponse::KeyInfo::EVEN); // Add the Odd key. key = response.add_entitlement_keys(); - key->set_key_id("fake_key_id....."); - key->set_key("fakefakefakefakefakefakefakefake"); + key->set_key_id(kEntitlementKeyId); + key->set_key(kEntitlementKey); key->set_track_type(track_type); key->set_key_slot(CasEncryptionResponse::KeyInfo::ODD); } else { auto key = response.add_entitlement_keys(); - key->set_key_id("fake_key_id....."); - key->set_key("fakefakefakefakefakefakefakefake"); + key->set_key_id(kEntitlementKeyId); + key->set_key(kEntitlementKey); key->set_track_type(track_type); key->set_key_slot(CasEncryptionResponse::KeyInfo::SINGLE); } @@ -148,10 +167,12 @@ class WvCasKeyFetcherTest : public ::testing::Test { protected: EntitlementRequestParams CreateRequestParamsStruct( const std::string& content_id, const std::string& content_provider, - const std::vector& track_types, bool key_rotation) { + const std::string& group_id, const std::vector& track_types, + bool key_rotation) { EntitlementRequestParams request_params; request_params.content_id = content_id; request_params.content_provider = content_provider; + request_params.group_id = group_id; request_params.track_types.assign(track_types.begin(), track_types.end()); request_params.key_rotation = key_rotation; return request_params; @@ -161,8 +182,9 @@ class WvCasKeyFetcherTest : public ::testing::Test { TEST_F(WvCasKeyFetcherTest, TestRequestEntitlementKey) { HardcodedWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, kSingingIv); - EntitlementRequestParams request_params = CreateRequestParamsStruct( - kContentId, kProvider, {kTrackTypeSD}, /*key_rotation=*/false); + EntitlementRequestParams request_params = + CreateRequestParamsStruct(kContentId, kProvider, /*group_id=*/"", + {kTrackTypeSD}, /*key_rotation=*/false); std::string signed_request_json; mock_key_fetcher.CreateEntitlementRequest(request_params, &signed_request_json); @@ -180,7 +202,7 @@ TEST_F(WvCasKeyFetcherTest, TestRequestEntitlementKey) { &entitlements)); ASSERT_EQ(entitlements.size(), 1); - const EntitlementKeyInfo& entitlement = entitlements.at(0); + const EntitlementKeyInfo& entitlement = entitlements[0]; EXPECT_EQ(entitlement.track_type, "SD"); EXPECT_EQ(entitlement.is_even_key, true); std::string expected_key_id; @@ -192,12 +214,62 @@ TEST_F(WvCasKeyFetcherTest, TestRequestEntitlementKey) { EXPECT_EQ(entitlement.key_value, expected_key_value); } +TEST_F(WvCasKeyFetcherTest, TestRequestWithGroupId) { + MockWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, + kSingingIv); + EntitlementRequestParams request_params = CreateRequestParamsStruct( + kContentId, kProvider, kGroupId, {kTrackTypeSD}, /*key_rotation=*/false); + std::string signed_request_json; + ASSERT_OK(mock_key_fetcher.CreateEntitlementRequest(request_params, + &signed_request_json)); + EXPECT_EQ(signed_request_json, kSignedCasEncryptionRequestForGroupKey); + // Parse the signed request json std::string and validate the request proto. + SignedCasEncryptionRequest signed_request; + ASSERT_OK( + google::protobuf::util::JsonStringToMessage(signed_request_json, &signed_request)); + CasEncryptionRequest request; + ASSERT_OK( + google::protobuf::util::JsonStringToMessage(signed_request.request(), &request)); + EXPECT_EQ(request.content_id(), kContentId); + EXPECT_EQ(request.provider(), kProvider); + EXPECT_EQ(request.group_id(), kGroupId); + EXPECT_EQ(request.track_types_size(), 1); + EXPECT_EQ(request.track_types(0), kTrackTypeSD); + EXPECT_FALSE(request.key_rotation()); + + std::string actual_signed_response; + EXPECT_OK(mock_key_fetcher.MakeHttpRequest(signed_request_json, + &actual_signed_response)); + // Parse the signed response json std::string and validate the response proto. + SignedCasEncryptionResponse signed_response; + ASSERT_OK(google::protobuf::util::JsonStringToMessage(actual_signed_response, + &signed_response)); + CasEncryptionResponse response; + ASSERT_OK( + google::protobuf::util::JsonStringToMessage(signed_response.response(), &response)); + EXPECT_EQ(response.content_id(), kContentId); + EXPECT_EQ(response.status(), CasEncryptionResponse::OK); + EXPECT_EQ(response.group_id(), kGroupId); + + std::vector entitlements; + EXPECT_OK(mock_key_fetcher.ParseEntitlementResponse(actual_signed_response, + &entitlements)); + // Validate the entitlement key info in the response. + ASSERT_EQ(entitlements.size(), 1); + const EntitlementKeyInfo& entitlement = entitlements[0]; + EXPECT_EQ(entitlement.track_type, "SD"); + EXPECT_EQ(entitlement.is_even_key, true); + EXPECT_EQ(entitlement.key_id, kEntitlementKeyId); + EXPECT_EQ(entitlement.key_value, kEntitlementKey); +} + TEST_F(WvCasKeyFetcherTest, OneKeyOK) { MockWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, kSingingIv); std::string request; - EntitlementRequestParams request_params = CreateRequestParamsStruct( - kContentId, kProvider, {kTrackTypeSD}, /*key_rotation*/ false); + EntitlementRequestParams request_params = + CreateRequestParamsStruct(kContentId, kProvider, /*group_id=*/"", + {kTrackTypeSD}, /*key_rotation=*/false); ASSERT_OK( mock_key_fetcher.CreateEntitlementRequest(request_params, &request)); @@ -217,8 +289,9 @@ TEST_F(WvCasKeyFetcherTest, OneKeyOK) { TEST_F(WvCasKeyFetcherTest, OneKeyConvenientOK) { MockWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, kSingingIv); - EntitlementRequestParams request_params = CreateRequestParamsStruct( - kContentId, kProvider, {kTrackTypeSD}, /*key_rotation*/ false); + EntitlementRequestParams request_params = + CreateRequestParamsStruct(kContentId, kProvider, /*group_id=*/"", + {kTrackTypeSD}, /*key_rotation=*/false); std::vector entitlements; ASSERT_OK(mock_key_fetcher.FetchEntitlements(request_params, &entitlements)); @@ -233,8 +306,9 @@ TEST_F(WvCasKeyFetcherTest, OneKeyConvenientOK) { TEST_F(WvCasKeyFetcherTest, TwoKeysOK) { MockWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, kSingingIv); - EntitlementRequestParams request_params = CreateRequestParamsStruct( - kContentId, kProvider, {kTrackTypeSD}, /*key_rotation*/ true); + EntitlementRequestParams request_params = + CreateRequestParamsStruct(kContentId, kProvider, /*group_id=*/"", + {kTrackTypeSD}, /*key_rotation=*/true); std::vector entitlements; ASSERT_OK(mock_key_fetcher.FetchEntitlements(request_params, &entitlements)); @@ -247,8 +321,8 @@ TEST_F(WvCasKeyFetcherTest, TwoTracksOK) { MockWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, kSingingIv); EntitlementRequestParams request_params = CreateRequestParamsStruct( - kContentId, kProvider, {kTrackTypeSD, kTrackTypeHD}, - /*key_rotation*/ true); + kContentId, kProvider, /*group_id=*/"", {kTrackTypeSD, kTrackTypeHD}, + /*key_rotation=*/true); std::vector entitlements; ASSERT_OK(mock_key_fetcher.FetchEntitlements(request_params, &entitlements)); ASSERT_EQ(entitlements.size(), 4); @@ -258,8 +332,9 @@ TEST_F(WvCasKeyFetcherTest, BadResponseFail) { MockWvCasKeyFetcher mock_key_fetcher(kSigningProvider, kSingingKey, kSingingIv); std::string request; - EntitlementRequestParams request_params = CreateRequestParamsStruct( - kContentId, kProvider, {kTrackTypeSD}, /*key_rotation*/ true); + EntitlementRequestParams request_params = + CreateRequestParamsStruct(kContentId, kProvider, /*group_id=*/"", + {kTrackTypeSD}, /*key_rotation=*/true); ASSERT_OK( mock_key_fetcher.CreateEntitlementRequest(request_params, &request)); std::string response; diff --git a/media_cas_packager_sdk/public/wv_cas_types.cc b/media_cas_packager_sdk/public/wv_cas_types.cc index afe0f84..8a43d99 100644 --- a/media_cas_packager_sdk/public/wv_cas_types.cc +++ b/media_cas_packager_sdk/public/wv_cas_types.cc @@ -92,6 +92,9 @@ Status CreateWvCasEncryptionRequestJson(const WvCasEncryptionRequest& request, CasEncryptionRequest request_proto; request_proto.set_content_id(request.content_id); request_proto.set_provider(request.provider); + if (!request.group_id.empty()) { + request_proto.set_group_id(request.group_id); + } for (const std::string& track_type : request.track_types) { request_proto.add_track_types(track_type); } @@ -129,6 +132,7 @@ Status ParseWvCasEncryptionResponseJson(const std::string& response_json, static_cast(response_proto.status()); response->status_message = response_proto.status_message(); response->content_id = response_proto.content_id(); + response->group_id = response_proto.group_id(); for (const auto& key_info_proto : response_proto.entitlement_keys()) { WvCasEncryptionResponse::KeyInfo key_info; key_info.key_id = key_info_proto.key_id(); diff --git a/media_cas_packager_sdk/public/wv_cas_types.h b/media_cas_packager_sdk/public/wv_cas_types.h index e5c882c..e8b4bfd 100644 --- a/media_cas_packager_sdk/public/wv_cas_types.h +++ b/media_cas_packager_sdk/public/wv_cas_types.h @@ -68,6 +68,7 @@ struct EntitlementKeyInfo { struct WvCasEncryptionRequest { std::string content_id; std::string provider; + std::string group_id; // Track types such as "AUDIO", SD" or "HD". std::vector track_types; // Indicates if the client is using key rotation. If true, the server will @@ -104,6 +105,7 @@ struct WvCasEncryptionResponse { Status status; std::string status_message; std::string content_id; + std::string group_id; std::vector entitlement_keys; }; diff --git a/media_cas_packager_sdk/public/wv_cas_types_test.cc b/media_cas_packager_sdk/public/wv_cas_types_test.cc index 94b8078..ae3a13c 100644 --- a/media_cas_packager_sdk/public/wv_cas_types_test.cc +++ b/media_cas_packager_sdk/public/wv_cas_types_test.cc @@ -83,6 +83,17 @@ TEST(WvCasTypesTest, CreateWvCasEncryptionRequestJson) { "{\"content_id\":\"dGVzdF9jb250ZW50X2lk\",\"provider\":\"test_provider\"," "\"track_types\":[\"SD\",\"AUDIO\"],\"key_rotation\":true}"; EXPECT_EQ(expected_request_json, actual_request_json); + + // Set group_id in the request. + request.group_id = "test_group_id"; + actual_request_json.clear(); + EXPECT_OK(CreateWvCasEncryptionRequestJson(request, &actual_request_json)); + // Content_id and group_id have been base64 encoded. + std::string expected_request_json_with_group_id = + "{\"content_id\":\"dGVzdF9jb250ZW50X2lk\",\"provider\":\"test_provider\"," + "\"track_types\":[\"SD\",\"AUDIO\"],\"key_rotation\":true,\"group_id\":" + "\"dGVzdF9ncm91cF9pZA==\"}"; + EXPECT_EQ(actual_request_json, expected_request_json_with_group_id); } TEST(WvCasTypesTest, ParseWvCasEncryptionResponseJson) { @@ -93,7 +104,7 @@ TEST(WvCasTypesTest, ParseWvCasEncryptionResponseJson) { "\"track_type\":\"SD\",\"key_slot\":\"EVEN\"},{\"key_id\":" "\"ZmFrZV9rZXlfaWQyLi4uLg==\",\"key\":" "\"ZmFrZWZha2VmYWtlZmFrZWZha2VmYWtlZmFrZTIuLi4=\",\"track_type\":\"SD\"," - "\"key_slot\":\"ODD\"}]}"; + "\"key_slot\":\"ODD\"}],\"group_id\":\"Z3JvdXAx\"}"; WvCasEncryptionResponse actual_response; EXPECT_OK(ParseWvCasEncryptionResponseJson(response_json, &actual_response)); @@ -116,6 +127,8 @@ TEST(WvCasTypesTest, ParseWvCasEncryptionResponseJson) { EXPECT_EQ("SD", actual_response.entitlement_keys.at(1).track_type); EXPECT_EQ(WvCasEncryptionResponse::KeyInfo::KeySlot::ODD, actual_response.entitlement_keys.at(1).key_slot); + // "group1" is base64 decode of "Z3JvdXAx". + EXPECT_EQ(actual_response.group_id, "group1"); } } // namespace cas diff --git a/media_cas_packager_sdk/public/wv_emmg.cc b/media_cas_packager_sdk/public/wv_emmg.cc index cc0f5e9..6fa4869 100644 --- a/media_cas_packager_sdk/public/wv_emmg.cc +++ b/media_cas_packager_sdk/public/wv_emmg.cc @@ -20,8 +20,19 @@ #include "glog/logging.h" #include "absl/flags/flag.h" #include "absl/flags/parse.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_split.h" #include "media_cas_packager_sdk/internal/emmg.h" +namespace { +// Maximum number of entitlement key ids shown in private data. +constexpr uint16_t kMaxNumOfEntitlementKeyIds = 2; +// Entitlement key id length is fixed to 16 bytes. +constexpr uint16_t kEntitlementKeyIdLengthBytes = 16; +constexpr int32_t kEmmDataType = 0; +constexpr int32_t kPrivateDataType = 1; +} // namespace + ABSL_FLAG(std::string, mux_address, "", "Mux server address."); ABSL_FLAG(int32_t, mux_port, 0, "Mux server port number."); // EMMG specific configs. @@ -40,43 +51,167 @@ ABSL_FLAG(int32_t, data_id, 0, "EMMG data_id."); // 0x01: private data; // 0x02: DVB reserved (ECM); // other values: DVB reserved. -ABSL_FLAG(int32_t, data_type, 1, "EMMG data_type"); -ABSL_FLAG(std::string, content_provider, "", "Content provider"); -ABSL_FLAG(std::string, content_id, "", "Content id"); +ABSL_FLAG(int32_t, data_type, kPrivateDataType, + "EMMG data_type, must be either 0 (EMM) or 1 (Private data)."); +ABSL_FLAG(std::string, content_provider, "", + "Content provider to put into priavte data."); +ABSL_FLAG(std::string, content_id, "", "Content id to put into priavte data"); ABSL_FLAG( std::vector, entitlement_key_ids, {}, "Comma-separated list of entitlement_key_ids to put into private data"); ABSL_FLAG(int32_t, bandwidth, 100, "Requested bandwidth in kbps"); ABSL_FLAG(int32_t, max_num_message, 100, "Maximum number of messages that can be sent"); +ABSL_FLAG(std::string, ecc_signing_key, "", + "Signing key used to sign EMM data. Must be elliptic-curve " + "cryptography key."); +ABSL_FLAG(std::string, fingerprinting, "", + "Fingerprinting info to put into EMM data. Must follow this format:\n" + "1. Multiple fingerprintings are separated by \'||\';\n" + "2. Different fields (e.g., channels) within a fingerprinting are " + "separated by \';\'. All fields must present (channels;control);\n" + "3. Value list within a field is separated by \',\'.\n" + "Example: channel1,channel2;control||channel3;control2"); +ABSL_FLAG( + std::string, service_blocking, "", + "Service blocking info to put into EMM data. Must follow this format:\n" + "1. Multiple service_blockings are separated by \'||\';\n" + "2. Different fields (e.g., channels) within a service_blocking are " + "separated by \';\'. All fields must present (channels;device_groups;" + "start_time;end_time). The start/end time are Epoch time in seconds with " + "start_time = 0 means immediate;\n" + "3. Value list within a field is separated by \',\'.\n" + "Example: channel1,channel2;device_group1,device_group2;0;1597186636" + "||channel3;device_group3;1597186636,1597186637"); -#define BUFFER_SIZE (1024) +void CheckEmmgUsage(const widevine::cas::EmmgConfig& config) { + // Emmg is configured as EMM generator. + if (config.data_type == kEmmDataType) { + LOG_IF(WARNING, !config.content_provider.empty()) + << "content_provider is set but ignored as data_type is set to 0 (EMM " + "data)."; + LOG_IF(WARNING, !config.content_id.empty()) + << "content_id is set but ignored as data_type is set to 0 (EMM data)."; + LOG_IF(WARNING, !config.entitlement_key_ids.empty()) + << "entitlement_key_ids is set but ignored as data_type is set to 0 " + "(EMM data)."; + } -void BuildEmmgConfig(widevine::cas::EmmgConfig *config) { + // Emmg is configured as private data generator (PDG). + if (config.data_type == kPrivateDataType) { + LOG_IF(WARNING, !config.ecc_signing_key.empty()) + << "ecc_signing_key is set but ignored as data_type is set to 1 " + "(Private data)."; + LOG_IF(WARNING, !config.fingerprinting.empty()) + << "fingerprinting is set but ignored as data_type is set to 1 " + "(Private data)."; + LOG_IF(WARNING, !config.service_blocking.empty()) + << "service_blocking is set but ignored as data_type is set to 1 " + "(Private data)."; + } +} + +void BuildEmmgConfig(widevine::cas::EmmgConfig* config) { CHECK(config); config->client_id = absl::GetFlag(FLAGS_client_id); config->section_tspkt_flag = absl::GetFlag(FLAGS_section_tspkt_flag); config->data_channel_id = absl::GetFlag(FLAGS_data_channel_id); config->data_stream_id = absl::GetFlag(FLAGS_data_stream_id); config->data_id = absl::GetFlag(FLAGS_data_id); - config->data_type = absl::GetFlag(FLAGS_data_type); - config->content_provider = absl::GetFlag(FLAGS_content_provider); - config->content_id = absl::GetFlag(FLAGS_content_id); - config->entitlement_key_ids = absl::GetFlag(FLAGS_entitlement_key_ids); config->bandwidth = absl::GetFlag(FLAGS_bandwidth); config->max_num_message = absl::GetFlag(FLAGS_max_num_message); + // Check and set data_type. + config->data_type = absl::GetFlag(FLAGS_data_type); + CHECK(config->data_type == kEmmDataType || + config->data_type == kPrivateDataType) + << "Data type must be either 0 (EMM) or 1 (Private data)."; + + // Below are private data specific configurations. + config->content_provider = absl::GetFlag(FLAGS_content_provider); + config->content_id = absl::GetFlag(FLAGS_content_id); + // Check and set entitlement_key_ids. + config->entitlement_key_ids = absl::GetFlag(FLAGS_entitlement_key_ids); + CHECK_LE(config->entitlement_key_ids.size(), kMaxNumOfEntitlementKeyIds) + << absl::StrCat("Number of entitlement key ids shouldn't exceed ", + kMaxNumOfEntitlementKeyIds); + for (const auto& entitlement_key_id : config->entitlement_key_ids) { + CHECK_EQ(entitlement_key_id.size(), kEntitlementKeyIdLengthBytes) + << absl::StrCat("Entitlement key id length must be ", + kEntitlementKeyIdLengthBytes, + ". The offending key id is ", entitlement_key_id); + } + + // Below are EMM data specific configurations. + config->ecc_signing_key = absl::GetFlag(FLAGS_ecc_signing_key); + if (config->data_type == kEmmDataType) { + CHECK(!config->ecc_signing_key.empty()) + << "ECC signing key is required to generate EMM data."; + } + // Check and set fingerprinting. + std::vector fingerprintings = absl::StrSplit( + absl::GetFlag(FLAGS_fingerprinting), "||", absl::SkipWhitespace()); + config->fingerprinting.reserve(fingerprintings.size()); + for (const auto& fingerprinting : fingerprintings) { + config->fingerprinting.emplace_back(); + widevine::cas::FingerprintingInitParameters& fingerprinting_inserted = + config->fingerprinting.back(); + + std::vector fields = absl::StrSplit(fingerprinting, ';'); + CHECK_EQ(fields.size(), 2) + << "Each fingerprinting must contain exactly 2 fields (channels;" + "control) separated by \';\'."; + + fingerprinting_inserted.channels = absl::StrSplit(fields[0], ','); + CHECK(!fingerprinting_inserted.channels.empty()) + << "Channels in fingerprinting must be specified."; + + fingerprinting_inserted.control = fields[1]; + CHECK(!fingerprinting_inserted.control.empty()) + << "Conrtol in fingerprinting must be specified."; + } + + // Check and set service_blocking. + std::vector service_blockings = absl::StrSplit( + absl::GetFlag(FLAGS_service_blocking), "||", absl::SkipWhitespace()); + config->service_blocking.reserve(service_blockings.size()); + for (const auto& service_blocking : service_blockings) { + config->service_blocking.emplace_back(); + widevine::cas::ServiceBlockingInitParameters& + service_blocking_inserted = config->service_blocking.back(); + + std::vector fields = absl::StrSplit(service_blocking, ';'); + CHECK_EQ(fields.size(), 4) + << "Each service blocking must contain exactly 4 fields (channels;" + "device_groups;start_time;end_time) separated by \';\'."; + + service_blocking_inserted.channels = absl::StrSplit(fields[0], ','); + CHECK(!service_blocking_inserted.channels.empty()) + << "Channels in service blocking must be specified."; + + service_blocking_inserted.device_groups = absl::StrSplit(fields[1], ','); + CHECK(!service_blocking_inserted.device_groups.empty()) + << "Device groups in service blocking must be specified."; + + service_blocking_inserted.start_time = std::stoll(fields[2]); + service_blocking_inserted.end_time = std::stoll(fields[3]); + CHECK_NE(service_blocking_inserted.end_time, 0) + << "End time in service blocking must be non zero."; + } } -int main(int argc, char **argv) { +int main(int argc, char** argv) { absl::ParseCommandLine(argc, argv); CHECK(!absl::GetFlag(FLAGS_mux_address).empty()) << "flag --mux_address is required"; CHECK(absl::GetFlag(FLAGS_mux_port) != 0) << "flag --mux_port is required"; + widevine::cas::EmmgConfig emmg_config; + BuildEmmgConfig(&emmg_config); + CheckEmmgUsage(emmg_config); // Create server address. struct hostent ret; - struct hostent *server; - char buffer[BUFFER_SIZE]; + struct hostent* server; + char buffer[1024]; int h_errnop = 0; int return_val = gethostbyname_r(absl::GetFlag(FLAGS_mux_address).c_str(), &ret, buffer, @@ -86,10 +221,10 @@ int main(int argc, char **argv) { << absl::GetFlag(FLAGS_mux_address); } struct sockaddr_in server_address; - bzero(reinterpret_cast(&server_address), sizeof(server_address)); + bzero(reinterpret_cast(&server_address), sizeof(server_address)); server_address.sin_family = AF_INET; bcopy(server->h_addr, - reinterpret_cast(&server_address.sin_addr.s_addr), + reinterpret_cast(&server_address.sin_addr.s_addr), server->h_length); server_address.sin_port = htons(absl::GetFlag(FLAGS_mux_port)); @@ -99,14 +234,12 @@ int main(int argc, char **argv) { LOG(FATAL) << "Failed to create socket."; } if (connect(server_socket_fd, - reinterpret_cast(&server_address), + reinterpret_cast(&server_address), sizeof(server_address)) < 0) { LOG(FATAL) << "Failed to connect to server."; } // Send EMMG messages. - widevine::cas::EmmgConfig emmg_config; - BuildEmmgConfig(&emmg_config); widevine::cas::Emmg emmg(&emmg_config, server_socket_fd); emmg.Start(); diff --git a/util/endian/BUILD b/util/endian/BUILD index fbe70d4..0b0ad15 100644 --- a/util/endian/BUILD +++ b/util/endian/BUILD @@ -17,3 +17,13 @@ cc_library( "endian.h", ], ) + +cc_test( + name = "endian_test", + srcs = ["endian_test.cc"], + deps = [ + ":endian", + "//testing:gunit_main", + "@abseil_repo//absl/strings", + ], +) diff --git a/util/endian/endian.h b/util/endian/endian.h index df04c32..031c701 100644 --- a/util/endian/endian.h +++ b/util/endian/endian.h @@ -10,6 +10,7 @@ #define UTIL_ENDIAN_ENDIAN_H_ #include + #include @@ -19,7 +20,8 @@ namespace widevine { // order and big-endian byte order (same as network byte order) class BigEndian { public: - static uint32_t Load32(const char* data) { + static uint32_t Load32(const char* indata) { + const uint8_t* data = reinterpret_cast(indata); return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; } diff --git a/common/string_util_test.cc b/util/endian/endian_test.cc similarity index 51% rename from common/string_util_test.cc rename to util/endian/endian_test.cc index a28e619..60ca0f8 100644 --- a/common/string_util_test.cc +++ b/util/endian/endian_test.cc @@ -1,27 +1,21 @@ //////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 Google LLC. +// 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. //////////////////////////////////////////////////////////////////////////////// - -#include "common/string_util.h" +#include "util/endian/endian.h" #include "testing/gmock.h" #include "testing/gunit.h" +#include "absl/strings/escaping.h" -namespace widevine { -namespace string_util { - -TEST(StringUtilTest, BitsetStringToBinaryString) { - std::string input = "01110100011001010111001101110100"; - std::string output; - - EXPECT_OK(BitsetStringToBinaryString(input, &output)); - - EXPECT_EQ("test", output); +TEST(BigEndian, Load32) { + const char value[] = "000000c8"; + EXPECT_EQ(static_cast(0xC8), + widevine::BigEndian::Load32( + absl::HexStringToBytes(std::string(value)).data())); } -} // namespace string_util -} // namespace widevine +namespace widevine {} // namespace widevine