diff --git a/common/BUILD b/common/BUILD index 660c7f5..a048b23 100644 --- a/common/BUILD +++ b/common/BUILD @@ -16,6 +16,7 @@ filegroup( name = "binary_release_files", srcs = [ "certificate_type.h", + "status.h", ], ) @@ -37,9 +38,9 @@ cc_library( hdrs = ["status.h"], deps = [ "//base", - "//util:error_space", "@abseil_repo//absl/base:core_headers", "@abseil_repo//absl/strings", + "//util:error_space", ], ) @@ -62,20 +63,21 @@ cc_library( ":error_space", ":random_util", ":rsa_key", + ":sha_util", ":signing_key_util", + ":status", ":wvm_token_handler", "//base", - "//common:status", + "//strings", + "@abseil_repo//absl/strings", + "@abseil_repo//absl/synchronization", + "@abseil_repo//absl/time", + "//util/gtl:map_util", "//protos/public:client_identification_proto", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", "//protos/public:license_protocol_proto", "//protos/public:signed_drm_certificate_proto", - "//strings", - "//util/gtl:map_util", - "@abseil_repo//absl/strings", - "@abseil_repo//absl/synchronization", - "@abseil_repo//absl/time", ], ) @@ -86,18 +88,20 @@ cc_test( ":client_cert", ":drm_root_certificate", ":error_space", + ":sha_util", + ":test_drm_certificates", ":wvm_test_keys", "//base", - "//common:rsa_key", - "//common:rsa_test_keys", - "//protos/public:drm_certificate_proto", - "//protos/public:errors_proto", - "//protos/public:signed_drm_certificate_proto", "//strings", "//testing:gunit_main", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", "@abseil_repo//absl/time", + "//common:rsa_key", + "//common:rsa_test_keys", + "//protos/public:drm_certificate_proto", + "//protos/public:errors_proto", + "//protos/public:signed_drm_certificate_proto", ], ) @@ -114,15 +118,15 @@ cc_library( ":random_util", ":rsa_key", ":signing_key_util", + ":status", "//base", - "//common:status", + "@abseil_repo//absl/strings", + "@abseil_repo//absl/synchronization", + "//util/gtl:map_util", "//protos/public:client_identification_proto", "//protos/public:device_certificate_status_proto", "//protos/public:errors_proto", "//protos/public:provisioned_device_info_proto", - "//util/gtl:map_util", - "@abseil_repo//absl/strings", - "@abseil_repo//absl/synchronization", ], ) @@ -134,14 +138,14 @@ cc_test( ":client_cert", ":device_status_list", "//base", + "//testing:gunit_main", + "@abseil_repo//absl/strings", "//common:rsa_key", "//common:rsa_test_keys", "//protos/public:client_identification_proto", "//protos/public:errors_proto", "//protos/public:provisioned_device_info_proto", "//protos/public:signed_drm_certificate_proto", - "//testing:gunit_main", - "@abseil_repo//absl/strings", ], ) @@ -154,15 +158,15 @@ cc_library( ":error_space", ":rsa_key", ":sha_util", + ":status", "//base", - "//common:status", + "@abseil_repo//absl/memory", + "@abseil_repo//absl/strings", + "@abseil_repo//absl/synchronization", "//external:openssl", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", "//protos/public:signed_drm_certificate_proto", - "@abseil_repo//absl/memory", - "@abseil_repo//absl/strings", - "@abseil_repo//absl/synchronization", ], ) @@ -178,10 +182,10 @@ cc_test( ":test_drm_certificates", "//base", "//external:protobuf", + "//testing:gunit_main", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", "//protos/public:signed_drm_certificate_proto", - "//testing:gunit_main", ], ) @@ -193,11 +197,11 @@ cc_library( ":aes_cbc_util", ":drm_service_certificate", ":error_space", + ":status", "//base", - "//common:status", + "@abseil_repo//absl/strings", "//protos/public:client_identification_proto", "//protos/public:errors_proto", - "@abseil_repo//absl/strings", ], ) @@ -220,9 +224,9 @@ cc_test( ":rsa_test_keys", ":rsa_util", "//base", - "//external:openssl", "//testing:gunit", "//testing:gunit_main", + "//external:openssl", ], ) @@ -307,9 +311,9 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//base", + "@abseil_repo//absl/strings", "//external:openssl", "//util/endian", - "@abseil_repo//absl/strings", ], ) @@ -332,8 +336,8 @@ cc_library( visibility = ["//visibility:public"], deps = [ "//base", - "//external:openssl", "@abseil_repo//absl/strings", + "//external:openssl", ], ) @@ -415,8 +419,8 @@ cc_library( ":aes_cbc_util", ":rsa_key", ":sha_util", + ":status", "//base", - "//common:status", ], ) @@ -438,10 +442,10 @@ cc_test( deps = [ ":crypto_util", ":signing_key_util", - "//protos/public:license_protocol_proto", "//testing:gunit", "//testing:gunit_main", "@abseil_repo//absl/strings", + "//protos/public:license_protocol_proto", ], ) @@ -464,12 +468,12 @@ cc_library( ":aes_cbc_util", ":ecb_util", ":sha_util", + ":status", "//base", - "//common:status", - "//util/endian", - "//util/gtl:map_util", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", + "//util/endian", + "//util/gtl:map_util", ], ) @@ -503,9 +507,9 @@ cc_library( srcs = ["error_space.cc"], hdrs = ["error_space.h"], deps = [ - "//common:status", - "//protos/public:errors_proto", + "//util:error_space", "//util:proto_status", + "//protos/public:errors_proto", ], ) @@ -518,14 +522,14 @@ cc_library( ":drm_service_certificate", ":error_space", ":rsa_key", + ":status", ":x509_cert", "//base", - "//common:status", + "@abseil_repo//absl/strings", + "@abseil_repo//absl/synchronization", "//protos/public:client_identification_proto", "//protos/public:errors_proto", "//protos/public:remote_attestation_proto", - "@abseil_repo//absl/strings", - "@abseil_repo//absl/synchronization", ], ) @@ -540,15 +544,15 @@ cc_library( ":error_space", ":rsa_key", ":rsa_util", + ":status", "//base", - "//common:status", + "@abseil_repo//absl/strings", + "@abseil_repo//absl/synchronization", + "//util/gtl:map_util", "//protos/public:client_identification_proto", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", "//protos/public:signed_drm_certificate_proto", - "//util/gtl:map_util", - "@abseil_repo//absl/strings", - "@abseil_repo//absl/synchronization", ], ) @@ -566,13 +570,13 @@ cc_test( ":test_drm_certificates", "//base", "//external:protobuf", + "//testing:gunit_main", + "@abseil_repo//absl/strings", "//protos/public:client_identification_proto", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", "//protos/public:license_server_sdk_proto", "//protos/public:signed_drm_certificate_proto", - "//testing:gunit_main", - "@abseil_repo//absl/strings", ], ) @@ -581,11 +585,11 @@ cc_library( srcs = ["verified_media_pipeline.cc"], hdrs = ["verified_media_pipeline.h"], deps = [ + ":status", ":vmp_checker", "//base", - "//common:status", - "//protos/public:license_protocol_proto", "@abseil_repo//absl/strings", + "//protos/public:license_protocol_proto", ], ) @@ -597,11 +601,11 @@ cc_library( ":error_space", ":openssl_util", ":rsa_key", + ":status", "//base", - "//common:status", - "//external:openssl", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", + "//external:openssl", ], ) @@ -611,8 +615,8 @@ cc_library( srcs = ["test_utils.cc"], hdrs = ["test_utils.h"], deps = [ + ":status", "//base", - "//common:status", "//external:openssl", ], ) @@ -639,9 +643,9 @@ cc_library( ":certificate_type", ":error_space", ":rsa_key", + ":status", ":x509_cert", "//base", - "//common:status", "//protos/public:errors_proto", "//protos/public:verified_media_pipeline_proto", ], @@ -655,10 +659,10 @@ cc_test( ":rsa_key", ":vmp_checker", "//base", - "//protos/public:errors_proto", - "//protos/public:verified_media_pipeline_proto", "//testing:gunit_main", "@abseil_repo//absl/strings", + "//protos/public:errors_proto", + "//protos/public:verified_media_pipeline_proto", ], ) @@ -667,8 +671,8 @@ cc_library( srcs = ["string_util.cc"], hdrs = ["string_util.h"], deps = [ + ":status", "//base", - "//common:status", ], ) diff --git a/common/client_cert.cc b/common/client_cert.cc index 78b9f5f..4940614 100644 --- a/common/client_cert.cc +++ b/common/client_cert.cc @@ -17,19 +17,18 @@ #include "absl/strings/escaping.h" #include "absl/synchronization/mutex.h" #include "util/gtl/map_util.h" -#include "common/status.h" #include "common/crypto_util.h" #include "common/drm_root_certificate.h" #include "common/error_space.h" #include "common/random_util.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" -// TODO(user): Get rid of this horror. - namespace widevine { namespace { @@ -37,45 +36,44 @@ const int kKeyboxSizeBytes = 72; } // namespace -// TODO(user): change to util::StatusOr> // instead of ClientCert** to explicitly assigning ownership of the created // object to the caller. -util::Status ClientCert::Create(const DrmRootCertificate* root_certificate, - ClientIdentification::TokenType token_type, - const std::string& token, ClientCert** client_cert) { +Status ClientCert::Create(const DrmRootCertificate* root_certificate, + ClientIdentification::TokenType token_type, + const std::string& token, ClientCert** client_cert) { DCHECK(client_cert); if (token_type == ClientIdentification::KEYBOX) { *client_cert = nullptr; if (token.size() < kKeyboxSizeBytes) { - return util::Status(error_space, INVALID_KEYBOX_TOKEN, - "keybox-token-is-too-short"); + return Status(error_space, INVALID_KEYBOX_TOKEN, + "keybox-token-is-too-short"); } return ClientCert::CreateWithKeybox(token, client_cert); } else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) { return CreateWithDrmCertificate(root_certificate, token, client_cert); } else { - return util::Status(error_space, util::error::UNIMPLEMENTED, - "client-type-not-implemented"); + return Status(error_space, error::UNIMPLEMENTED, + "client-type-not-implemented"); } } -util::Status ClientCert::CreateWithKeybox(const std::string& keybox_token, - ClientCert** client_cert) { +Status ClientCert::CreateWithKeybox(const std::string& keybox_token, + ClientCert** client_cert) { CHECK(client_cert); *client_cert = nullptr; std::unique_ptr new_client_cert(new KeyboxClientCert); - util::Status status = new_client_cert->Initialize(keybox_token); + Status status = new_client_cert->Initialize(keybox_token); if (!status.ok()) { return status; } *client_cert = new_client_cert.release(); - return util::OkStatus(); + return OkStatus(); } -util::Status ClientCert::CreateWithDrmCertificate( +Status ClientCert::CreateWithDrmCertificate( const DrmRootCertificate* root_certificate, const std::string& drm_certificate, ClientCert** client_cert) { CHECK(client_cert); @@ -83,14 +81,14 @@ util::Status ClientCert::CreateWithDrmCertificate( std::unique_ptr new_client_cert( new CertificateClientCert); - util::Status status = + Status status = new_client_cert->Initialize(root_certificate, drm_certificate); if (!status.ok()) { return status; } *client_cert = new_client_cert.release(); - return util::OkStatus(); + return OkStatus(); } void ClientCert::CreateSignature(const std::string& message, std::string* signature) { @@ -110,8 +108,10 @@ void ClientCert::GenerateSigningKey(const std::string& message, DCHECK(!key().empty()); using crypto_util::DeriveKey; using crypto_util::kSigningKeyLabel; - set_signing_key(DeriveKey(key(), kSigningKeyLabel, message, - SigningKeyMaterialSize(protocol_version))); + set_signing_key( + DeriveKey(key(), kSigningKeyLabel, + protocol_version < VERSION_2_2 ? message : Sha512_Hash(message), + SigningKeyMaterialSizeBits(protocol_version))); } KeyboxClientCert::KeyboxClientCert() {} @@ -139,51 +139,51 @@ uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) { return WvmTokenHandler::GetSystemId(keybox_bytes); } -util::Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) { +Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) { if (keybox_bytes.size() < kKeyboxSizeBytes) { - return util::Status(error_space, INVALID_KEYBOX_TOKEN, - "keybox-token-is-too-short"); + return Status(error_space, INVALID_KEYBOX_TOKEN, + "keybox-token-is-too-short"); } set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes)); set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes)); bool insecure_keybox = false; - util::Status status = WvmTokenHandler::DecryptDeviceKey( - keybox_bytes, &device_key_, nullptr, &insecure_keybox); + Status status = WvmTokenHandler::DecryptDeviceKey(keybox_bytes, &device_key_, + nullptr, &insecure_keybox); if (!status.ok()) { - Errors new_code = status.error_code() == util::error::NOT_FOUND + Errors new_code = status.error_code() == error::NOT_FOUND ? MISSING_PRE_PROV_KEY : KEYBOX_DECRYPT_ERROR; - return util::Status(error_space, new_code, status.error_message()); + return Status(error_space, new_code, status.error_message()); } - return util::OkStatus(); + return OkStatus(); } -util::Status KeyboxClientCert::VerifySignature( - const std::string& message, const std::string& signature, - ProtocolVersion protocol_version) { +Status KeyboxClientCert::VerifySignature(const std::string& message, + const std::string& signature, + ProtocolVersion protocol_version) { DCHECK(!signing_key().empty()); using crypto_util::VerifySignatureHmacSha256; if (!VerifySignatureHmacSha256( GetClientSigningKey(signing_key(), protocol_version), signature, message)) { - return util::Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac"); + return Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac"); } - return util::OkStatus(); + return OkStatus(); } CertificateClientCert::CertificateClientCert() {} CertificateClientCert::~CertificateClientCert() {} -util::Status CertificateClientCert::Initialize( +Status CertificateClientCert::Initialize( const DrmRootCertificate* drm_root_certificate, const std::string& serialized_certificate) { CHECK(drm_root_certificate); SignedDrmCertificate signed_device_cert; DrmCertificate device_cert; - util::Status status = drm_root_certificate->VerifyCertificate( + Status status = drm_root_certificate->VerifyCertificate( serialized_certificate, &signed_device_cert, &device_cert); if (!status.ok()) { return status; @@ -192,12 +192,12 @@ util::Status CertificateClientCert::Initialize( const SignedDrmCertificate& signer = signed_device_cert.signer(); DrmCertificate model_certificate; if (!model_certificate.ParseFromString(signer.drm_certificate())) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-invalid-signer"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "drm-certificate-invalid-signer"); } if (!model_certificate.has_serial_number()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-signer-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). @@ -205,56 +205,58 @@ util::Status CertificateClientCert::Initialize( DrmCertificate provisioner_certificate; if (!provisioner_certificate.ParseFromString( signer.signer().drm_certificate())) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "model-certificate-invalid-signer"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "model-certificate-invalid-signer"); } if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) { set_signed_by_provisioner(true); } else { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "expected-provisioning-provider-certificate-type"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "expected-provisioning-provider-certificate-type"); } if (!provisioner_certificate.has_provider_id() || provisioner_certificate.provider_id().empty()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-provisioning-service-id"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-provisioning-service-id"); } set_service_id(provisioner_certificate.provider_id()); } set_signer_serial_number(model_certificate.serial_number()); set_signer_creation_time_seconds(model_certificate.creation_time_seconds()); if (!model_certificate.has_system_id()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "model-certificate-missing-system-id"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "model-certificate-missing-system-id"); } set_system_id(model_certificate.system_id()); set_serial_number(device_cert.serial_number()); set_public_key(device_cert.public_key()); rsa_public_key_.reset(RsaPublicKey::Create(public_key())); if (rsa_public_key_ == nullptr) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-public-key-failed"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "drm-certificate-public-key-failed"); } // TODO(user): Move this somewhere else. It is license protocol. set_key(Random16Bytes()); if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) { - return util::Status(error_space, ENCRYPT_ERROR, - "drm-certificate-failed-encrypt-session-key"); + return Status(error_space, ENCRYPT_ERROR, + "drm-certificate-failed-encrypt-session-key"); } - return util::OkStatus(); + return OkStatus(); } -util::Status CertificateClientCert::VerifySignature( +Status CertificateClientCert::VerifySignature( const std::string& message, const std::string& signature, ProtocolVersion protocol_version) { CHECK(rsa_public_key_); - if (!rsa_public_key_->VerifySignature(message, signature)) { - return util::Status(error_space, INVALID_SIGNATURE, ""); + if (!rsa_public_key_->VerifySignature( + protocol_version < VERSION_2_2 ? message : Sha512_Hash(message), + signature)) { + return Status(error_space, INVALID_SIGNATURE, ""); } - return util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/client_cert.h b/common/client_cert.h index 4ae4c5a..b2dc786 100644 --- a/common/client_cert.h +++ b/common/client_cert.h @@ -13,8 +13,8 @@ #include #include -#include "common/status.h" #include "common/rsa_key.h" +#include "common/status.h" #include "protos/public/client_identification.pb.h" #include "protos/public/license_protocol.pb.h" @@ -29,15 +29,15 @@ class SignedDrmCertificate; class ClientCert { public: virtual ~ClientCert() {} - static util::Status Create( + static Status Create( const DrmRootCertificate* root_certificate, widevine::ClientIdentification::TokenType token_type, const std::string& token, ClientCert** client_cert); // Creates a Keybox based ClientCert. - static util::Status CreateWithKeybox(const std::string& keybox_token, - ClientCert** client_cert); + static Status CreateWithKeybox(const std::string& keybox_token, + ClientCert** client_cert); // Creates a Device Certificate based ClientCert. - static util::Status CreateWithDrmCertificate( + static Status CreateWithDrmCertificate( const DrmRootCertificate* root_certificate, const std::string& drm_certificate, ClientCert** client_cert); // Creates a HMAC SHA256 signature based on the message and the key(). @@ -46,9 +46,8 @@ class ClientCert { // 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 util::Status VerifySignature(const std::string& message, - const std::string& signature, - ProtocolVersion protocol_version) = 0; + virtual Status VerifySignature(const std::string& message, const std::string& signature, + ProtocolVersion protocol_version) = 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, @@ -118,10 +117,10 @@ class KeyboxClientCert : public ClientCert { static bool IsSystemIdKnown(const uint32_t system_id); static uint32_t GetSystemId(const std::string& keybox_bytes); - util::Status Initialize(const std::string& keybox_bytes); + Status Initialize(const std::string& keybox_bytes); - util::Status VerifySignature(const std::string& message, const std::string& signature, - ProtocolVersion protocol_version) override; + Status VerifySignature(const std::string& message, const std::string& signature, + ProtocolVersion protocol_version) override; const std::string& key() const override { return device_key_; } void set_key(const std::string& key) override { device_key_ = key; } const std::string& encrypted_key() const override { return encrypted_device_key_; } @@ -148,8 +147,8 @@ class CertificateClientCert : public ClientCert { public: ~CertificateClientCert() override; - util::Status VerifySignature(const std::string& message, const std::string& signature, - ProtocolVersion protocol_version) override; + Status VerifySignature(const std::string& message, const std::string& signature, + ProtocolVersion protocol_version) override; const std::string& key() const override { return session_key_; } void set_key(const std::string& key) override { session_key_ = key; } const std::string& encrypted_key() const override { @@ -162,8 +161,8 @@ class CertificateClientCert : public ClientCert { protected: friend class ClientCert; friend class MockCertificateClientCert; - util::Status Initialize(const DrmRootCertificate* drm_root_certificate, - const std::string& serialized_certificate); + Status Initialize(const DrmRootCertificate* drm_root_certificate, + const std::string& serialized_certificate); virtual void set_public_key(const std::string& public_key) { public_key_ = public_key; } diff --git a/common/client_cert_test.cc b/common/client_cert_test.cc index 4321f30..7a4b579 100644 --- a/common/client_cert_test.cc +++ b/common/client_cert_test.cc @@ -24,6 +24,8 @@ #include "common/drm_root_certificate.h" #include "common/error_space.h" #include "common/rsa_test_keys.h" +#include "common/sha_util.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" @@ -31,7 +33,7 @@ // TODO(user): Change these tests to use on-the-fly generated intermediate // and device certificates based on RsaTestKeys. -// TODO(user): Add testcase(s) VerifySignature, CreateSignature, +// TODO(user): Add testcase(s) CreateSignature, // and GenerateSigningKey. namespace widevine { @@ -73,11 +75,10 @@ class ClientCertTest : public ::testing::Test { const std::string certificate_; const std::string expected_serial_number_; uint32_t expected_system_id_; - util::Status expected_status_; + Status expected_status_; TestCertificateAndData(const std::string& certificate, const std::string& expected_serial_number, - uint32_t expected_system_id, - util::Status expected_status) + uint32_t expected_system_id, Status expected_status) : certificate_(certificate), expected_serial_number_(expected_serial_number), expected_system_id_(expected_system_id), @@ -111,7 +112,8 @@ class ClientCertTest : public ::testing::Test { SignedDrmCertificate* signer, uint32_t system_id, const std::string& serial_number); - RsaTestKeys test_keys_; + RsaTestKeys test_rsa_keys_; + TestDrmCertificates test_drm_certs_; std::unique_ptr root_cert_; static bool setup_preprov_keys_; }; @@ -121,7 +123,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation, const bool expect_success, const bool compare_device_key) { // Test validation of a valid request. - util::Status status; + Status status; ClientCert* client_cert_ptr = nullptr; // Two ways to create a client cert object, test both. @@ -136,7 +138,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation, } std::unique_ptr keybox_cert(client_cert_ptr); if (expect_success) { - ASSERT_EQ(util::OkStatus(), status); + 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_, @@ -145,7 +147,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation, EXPECT_EQ(expectation.expected_device_key_, keybox_cert->key()); } } else { - EXPECT_NE(util::OkStatus(), status); + EXPECT_NE(OkStatus(), status); EXPECT_FALSE(keybox_cert); } } @@ -159,7 +161,7 @@ void ClientCertTest::TestBasicValidationDrmCertificate( DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); // Test validation of a valid request. - util::Status status; + Status status; ClientCert* client_cert_ptr = nullptr; status = ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, @@ -209,7 +211,7 @@ DrmCertificate* ClientCertTest::GenerateIntermediateCertificate( intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL); intermediate_certificate->set_serial_number(serial_number); intermediate_certificate->set_public_key( - test_keys_.public_test_key_2_2048_bits()); + test_rsa_keys_.public_test_key_2_2048_bits()); intermediate_certificate->set_system_id(system_id); intermediate_certificate->set_creation_time_seconds(1234); return intermediate_certificate.release(); @@ -221,7 +223,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedIntermediateCertificate( std::unique_ptr intermediate_certificate( GenerateIntermediateCertificate(system_id, serial_number)); return SignCertificate(*intermediate_certificate, signer, - test_keys_.private_test_key_1_3072_bits()); + test_rsa_keys_.private_test_key_1_3072_bits()); } DrmCertificate* ClientCertTest::GenerateDrmCertificate( @@ -230,7 +232,7 @@ DrmCertificate* ClientCertTest::GenerateDrmCertificate( 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(test_keys_.public_test_key_3_2048_bits()); + drm_certificate->set_public_key(test_rsa_keys_.public_test_key_3_2048_bits()); drm_certificate->set_creation_time_seconds(4321); return drm_certificate.release(); } @@ -241,7 +243,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedDrmCertificate( std::unique_ptr drm_certificate( GenerateDrmCertificate(system_id, serial_number)); std::unique_ptr signed_drm_certificate(SignCertificate( - *drm_certificate, signer, test_keys_.private_test_key_2_2048_bits())); + *drm_certificate, signer, test_rsa_keys_.private_test_key_2_2048_bits())); return signed_drm_certificate.release(); } @@ -252,7 +254,7 @@ DrmCertificate* ClientCertTest::GenerateProvisionerCertificate( provisioner_certificate->set_serial_number(serial_number); // TODO(user): Need to generate 3072 bit test for provisioner certificates. provisioner_certificate->set_public_key( - test_keys_.public_test_key_1_3072_bits()); + test_rsa_keys_.public_test_key_1_3072_bits()); provisioner_certificate->set_system_id(system_id); provisioner_certificate->set_provider_id(provider_id); provisioner_certificate->set_creation_time_seconds(1234); @@ -264,7 +266,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedProvisionerCertificate( std::unique_ptr provisioner_certificate( GenerateProvisionerCertificate(system_id, serial_number, service_id)); return SignCertificate(*provisioner_certificate, nullptr, - test_keys_.private_test_key_1_3072_bits()); + test_rsa_keys_.private_test_key_1_3072_bits()); } TEST_F(ClientCertTest, BasicValidation) { @@ -302,8 +304,7 @@ TEST_F(ClientCertTest, BasicCertValidation) { nullptr, system_id, serial_number), system_id, serial_number + "-device")); const TestCertificateAndData kValidCertificateAndExpectedData( - signed_cert->SerializeAsString(), serial_number, system_id, - util::OkStatus()); + signed_cert->SerializeAsString(), serial_number, system_id, OkStatus()); const bool compare_data = true; TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData, compare_data); @@ -347,7 +348,7 @@ TEST_F(ClientCertTest, InvalidCertificate) { new SignedDrmCertificate); invalid_drm_cert->set_drm_certificate("bad-serialized-cert"); GenerateSignature(invalid_drm_cert->drm_certificate(), - test_keys_.private_test_key_2_2048_bits(), + test_rsa_keys_.private_test_key_2_2048_bits(), invalid_drm_cert->mutable_signature()); invalid_drm_cert->set_allocated_signer( GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn)); @@ -357,18 +358,18 @@ TEST_F(ClientCertTest, InvalidCertificate) { std::unique_ptr bad_device_public_key(SignCertificate( *dev_cert, GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn), - test_keys_.private_test_key_2_2048_bits())); + test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid serialized intermediate certificate. signed_signer.reset( GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn)); signed_signer->set_drm_certificate("bad-serialized-cert"); GenerateSignature(signed_signer->drm_certificate(), - test_keys_.private_test_key_1_3072_bits(), + test_rsa_keys_.private_test_key_1_3072_bits(), signed_signer->mutable_signature()); dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); std::unique_ptr invalid_signer( SignCertificate(*dev_cert, signed_signer.release(), - test_keys_.private_test_key_2_2048_bits())); + test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid signer public key. dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn)); @@ -376,8 +377,8 @@ TEST_F(ClientCertTest, InvalidCertificate) { std::unique_ptr bad_signer_public_key(SignCertificate( *dev_cert, SignCertificate(*signer_cert, nullptr, - test_keys_.private_test_key_1_3072_bits()), - test_keys_.private_test_key_2_2048_bits())); + test_rsa_keys_.private_test_key_1_3072_bits()), + test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid device certificate signature. std::unique_ptr bad_device_signature( GenerateSignedDrmCertificate( @@ -391,8 +392,8 @@ TEST_F(ClientCertTest, InvalidCertificate) { std::unique_ptr missing_model_sn(SignCertificate( *dev_cert, SignCertificate(*signer_cert, nullptr, - test_keys_.private_test_key_1_3072_bits()), - test_keys_.private_test_key_2_2048_bits())); + test_rsa_keys_.private_test_key_1_3072_bits()), + test_rsa_keys_.private_test_key_2_2048_bits())); // Missing signer serial number. dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn)); @@ -400,8 +401,8 @@ TEST_F(ClientCertTest, InvalidCertificate) { std::unique_ptr missing_signer_sn(SignCertificate( *dev_cert, SignCertificate(*signer_cert, nullptr, - test_keys_.private_test_key_1_3072_bits()), - test_keys_.private_test_key_2_2048_bits())); + test_rsa_keys_.private_test_key_1_3072_bits()), + test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid serialized intermediate certificate. dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); signed_signer.reset( @@ -409,37 +410,36 @@ TEST_F(ClientCertTest, InvalidCertificate) { signed_signer->set_signature("bad-signature"); std::unique_ptr bad_signer_signature( SignCertificate(*dev_cert, signed_signer.release(), - test_keys_.private_test_key_2_2048_bits())); + test_rsa_keys_.private_test_key_2_2048_bits())); const TestCertificateAndData kInvalidCertificate[] = { TestCertificateAndData("f", "", 0, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signed-drm-certificate")), + Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signed-drm-certificate")), TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-drm-certificate")), + Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-drm-certificate")), TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "drm-certificate-public-key-failed")), + Status(error_space, INVALID_DRM_CERTIFICATE, + "drm-certificate-public-key-failed")), TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-certificate")), + Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signer-certificate")), TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-leaf-signer-public-key")), + Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-leaf-signer-public-key")), TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature")), - TestCertificateAndData( - missing_model_sn->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "model-certificate-missing-system-id")), + 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, - util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-signer-serial-number")), + Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-signer-serial-number")), TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0, - util::Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature")), + Status(error_space, INVALID_SIGNATURE, + "cache-miss-invalid-signature")), }; for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) { @@ -454,7 +454,7 @@ TEST_F(ClientCertTest, MissingPreProvKey) { "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" "2517a12f4922953e")); ClientCert* client_cert_ptr = nullptr; - util::Status status = ClientCert::CreateWithKeybox(token, &client_cert_ptr); + Status status = ClientCert::CreateWithKeybox(token, &client_cert_ptr); ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code()); } @@ -563,4 +563,55 @@ TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) { EXPECT_FALSE(client_cert_ptr); } +TEST_F(ClientCertTest, Protocol21WithDrmCert) { + const char message[] = "A weekend wasted is a weekend well spent."; + + ClientCert* client_cert_ptr = nullptr; + ASSERT_OK(ClientCert::Create( + root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, + test_drm_certs_.test_user_device_certificate(), &client_cert_ptr)); + std::unique_ptr client_cert(client_cert_ptr); + + 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, &signature)); + EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_1)); + + // Failure + ASSERT_EQ(256, signature.size()); + ++signature[127]; + EXPECT_FALSE( + client_cert->VerifySignature(message, 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)); + + ClientCert* client_cert_ptr = nullptr; + ASSERT_OK(ClientCert::Create( + root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, + test_drm_certs_.test_user_device_certificate(), &client_cert_ptr)); + std::unique_ptr client_cert(client_cert_ptr); + + 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, &signature)); + EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_2)); + + // Failure + ASSERT_EQ(256, signature.size()); + ++signature[127]; + EXPECT_FALSE( + client_cert->VerifySignature(message, signature, VERSION_2_2).ok()); +} + } // namespace widevine diff --git a/common/client_id_util.cc b/common/client_id_util.cc index 35013a2..327a3bf 100644 --- a/common/client_id_util.cc +++ b/common/client_id_util.cc @@ -51,39 +51,39 @@ std::string GetClientInfo(const ClientIdentification& client_id, return default_value; } -util::Status DecryptEncryptedClientIdentification( +Status DecryptEncryptedClientIdentification( const EncryptedClientIdentification& encrypted_client_id, ClientIdentification* client_id) { return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id, client_id); } -util::Status DecryptEncryptedClientIdentification( +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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id"); + 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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id-iv"); + 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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-decryption-failed"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "client-id-decryption-failed"); } if (!client_id->ParseFromString(serialized_client_id)) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-parse-failed"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "client-id-parse-failed"); } - return util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/client_id_util.h b/common/client_id_util.h index b0afa41..6aef13d 100644 --- a/common/client_id_util.h +++ b/common/client_id_util.h @@ -43,16 +43,16 @@ std::string GetClientInfo(const ClientIdentification& client_id, // |client_id| using the private key for the service certificate which was // used to encrypt the information. // |client_id| is owned by caller. -// Returns util::Status::OK, if successful, else an error. -util::Status DecryptEncryptedClientIdentification( +// 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 util::Status::OK, if successful, else an error. -util::Status DecryptEncryptedClientIdentification( +// Returns Status::OK, if successful, else an error. +Status DecryptEncryptedClientIdentification( const EncryptedClientIdentification& encrypted_client_id, const std::string& privacy_key, ClientIdentification* client_id); diff --git a/common/crypto_util.cc b/common/crypto_util.cc index 901b991..2a1ab2a 100644 --- a/common/crypto_util.cc +++ b/common/crypto_util.cc @@ -22,8 +22,8 @@ namespace widevine { namespace crypto_util { -const char kEncryptionKeyLabel[] = "ENCRYPTION"; -const int kEncryptionKeySizeBits = 128; +const char kWrappingKeyLabel[] = "ENCRYPTION"; +const int kWrappingKeySizeBits = 128; const char kSigningKeyLabel[] = "AUTHENTICATION"; const int kSigningKeySizeBits = 256; const size_t kSigningKeySizeBytes = 32; diff --git a/common/crypto_util.h b/common/crypto_util.h index dc00f4e..75e8dc0 100644 --- a/common/crypto_util.h +++ b/common/crypto_util.h @@ -22,8 +22,8 @@ namespace crypto_util { // Default constants used for key derivation for encryption and signing. // TODO(user): These are duplicated in session.cc in the sdk. de-dup. -extern const char kEncryptionKeyLabel[]; -extern const int kEncryptionKeySizeBits; +extern const char kWrappingKeyLabel[]; +extern const int kWrappingKeySizeBits; extern const char kSigningKeyLabel[]; extern const int kSigningKeySizeBits; extern const size_t kSigningKeySizeBytes; diff --git a/common/device_status_list.cc b/common/device_status_list.cc index 187b0f0..da97d3f 100644 --- a/common/device_status_list.cc +++ b/common/device_status_list.cc @@ -52,47 +52,47 @@ DeviceStatusList::DeviceStatusList() DeviceStatusList::~DeviceStatusList() {} -util::Status DeviceStatusList::UpdateStatusList( +Status DeviceStatusList::UpdateStatusList( const std::string& root_certificate_public_key, const std::string& serialized_certificate_status_list, uint32_t expiration_period_seconds) { SignedDeviceCertificateStatusList signed_certificate_status_list; if (!signed_certificate_status_list.ParseFromString( serialized_certificate_status_list)) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "signed-certificate-status-list-parse-error"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "signed-certificate-status-list-parse-error"); } if (!signed_certificate_status_list.has_certificate_status_list()) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "missing-status-list"); } if (!signed_certificate_status_list.has_signature()) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list-signature"); + 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 util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-root-public-key"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-root-public-key"); } if (!root_key->VerifySignature( signed_certificate_status_list.certificate_status_list(), signed_certificate_status_list.signature())) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "invalid-status-list-signature"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "invalid-status-list-signature"); } DeviceCertificateStatusList certificate_status_list; if (!certificate_status_list.ParseFromString( signed_certificate_status_list.certificate_status_list())) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "certificate-status-list-parse-error"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "certificate-status-list-parse-error"); } if (expiration_period_seconds && (GetCurrentTime() > (certificate_status_list.creation_time_seconds() + expiration_period_seconds))) { - return util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, - "certificate-status-list-expired"); + return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, + "certificate-status-list-expired"); } absl::WriterMutexLock lock(&status_map_lock_); @@ -106,44 +106,44 @@ util::Status DeviceStatusList::UpdateStatusList( if (device_info.has_system_id()) { device_status_map_[device_info.system_id()] = cert_status; } else { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "device-info-missing-system-id"); + 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 util::OkStatus(); + return OkStatus(); } -util::Status DeviceStatusList::GetCertStatus( - const ClientCert& client_cert, ProvisionedDeviceInfo* device_info) { +Status DeviceStatusList::GetCertStatus(const ClientCert& client_cert, + ProvisionedDeviceInfo* device_info) { CHECK(device_info); // Keybox checks. if (client_cert.type() == ClientIdentification::KEYBOX) { if (!KeyboxClientCert::IsSystemIdKnown(client_cert.system_id())) { - return util::Status(error_space, UNSUPPORTED_SYSTEM_ID, - "keybox-unsupported-system-id"); + return Status(error_space, UNSUPPORTED_SYSTEM_ID, + "keybox-unsupported-system-id"); } // Get device information from certificate status list if available. if (!GetDeviceInfo(client_cert, device_info)) { device_info->Clear(); } - return util::OkStatus(); + return OkStatus(); } // DRM certificate checks. if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "device-certificate-unsupported-token-type"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "device-certificate-unsupported-token-type"); } absl::ReaderMutexLock lock(&status_map_lock_); if (expiration_period_seconds_ && (GetCurrentTime() > (creation_time_seconds_ + expiration_period_seconds_))) { - return util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, - "certificate-status-list-expired"); + 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()); @@ -155,15 +155,15 @@ util::Status DeviceStatusList::GetCertStatus( LOG(WARNING) << "Allowing REVOKED device: " << device_info->ShortDebugString(); } else { - return util::Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, - "device-certificate-revoked"); + return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, + "device-certificate-revoked"); } } if ((device_cert_status->status() == DeviceCertificateStatus::STATUS_TEST_ONLY) && !allow_test_only_devices_) { - return util::Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, - "test-only-drm-certificate-not-allowed"); + 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() != @@ -175,21 +175,21 @@ util::Status DeviceStatusList::GetCertStatus( // list is older than the certificate, the certificate is for all purposes // unknown. if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "intermediate-certificate-serial-number-mismatch"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "intermediate-certificate-serial-number-mismatch"); } - return util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, - "device-certificate-status-unknown"); + return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, + "device-certificate-status-unknown"); } } else { if (!allow_unknown_devices_) { - return util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, - "device-certificate-status-unknown"); + return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, + "device-certificate-status-unknown"); } device_info->Clear(); } - return util::OkStatus(); + return OkStatus(); } bool DeviceStatusList::GetDeviceInfo(const ClientCert& client_cert, @@ -247,18 +247,18 @@ bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) { return it; } -util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse( +Status DeviceStatusList::ExtractFromProvisioningServiceResponse( const std::string& certificate_provisioning_service_response, std::string* signed_certificate_status_list, std::string* certificate_status_list) { - util::Status status = util::OkStatus(); + Status status = OkStatus(); size_t signed_list_start = certificate_provisioning_service_response.find(kSignedList); if (signed_list_start != std::string::npos) { size_t signed_list_end = certificate_provisioning_service_response.find( kSignedListTerminator, signed_list_start); if (signed_list_end == std::string::npos) { - return util::Status( - error_space, util::error::INVALID_ARGUMENT, + return Status( + error_space, error::INVALID_ARGUMENT, "Unable to parse the certificate_provisioning_service_response. " "SignedList not terminated."); } @@ -284,8 +284,8 @@ util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse( if (!absl::WebSafeBase64Unescape(signed_list, signed_certificate_status_list)) { if (!absl::Base64Unescape(signed_list, signed_certificate_status_list)) { - return util::Status(error_space, util::error::INVALID_ARGUMENT, - "Base64 decode of signedlist failed."); + return Status(error_space, error::INVALID_ARGUMENT, + "Base64 decode of signedlist failed."); } } } else { @@ -295,42 +295,40 @@ util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse( signed_certificate_status_list)) { if (!absl::Base64Unescape(certificate_provisioning_service_response, signed_certificate_status_list)) { - return util::Status(error_space, util::error::INVALID_ARGUMENT, - "Base64 decode of certList failed."); + return Status(error_space, error::INVALID_ARGUMENT, + "Base64 decode of certList failed."); } } } SignedDeviceCertificateStatusList signed_status_list; if (!signed_status_list.ParseFromString(*signed_certificate_status_list)) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "signed-certificate-status-list-parse-error"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "signed-certificate-status-list-parse-error"); } if (!signed_status_list.has_certificate_status_list()) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "missing-status-list"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "missing-status-list"); } DeviceCertificateStatusList device_certificate_status_list; if (!device_certificate_status_list.ParseFromString( signed_status_list.certificate_status_list())) { - return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, - "certificate-status-list-parse-error"); + return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, + "certificate-status-list-parse-error"); } *certificate_status_list = signed_status_list.certificate_status_list(); - return util::OkStatus(); + return OkStatus(); } -util::Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( +Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( const std::string& version, std::string* signed_device_certificate_status_list_request) { if (version.empty()) { - return util::Status(error_space, util::error::INVALID_ARGUMENT, - "SDK version is 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 util::Status( - error_space, util::error::INVALID_ARGUMENT, - "Signed_device_certificate_status_list_request is empty"); + return Status(error_space, error::INVALID_ARGUMENT, + "Signed_device_certificate_status_list_request is empty"); } // Construct SignedDeviceCertificateStatusListRequest. DeviceCertificateStatusListRequest request; @@ -345,15 +343,13 @@ util::Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( DrmServiceCertificate::GetDefaultDrmServiceCertificate(); if (sc == nullptr) { signed_device_certificate_status_list_request->clear(); - return util::Status(error_space, - widevine::INVALID_SERVICE_CERTIFICATE, - "Drm service certificate is not loaded."); + return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE, + "Drm service certificate is not loaded."); } const RsaPrivateKey* private_key = sc->private_key(); if (private_key == nullptr) { - return util::Status(error_space, - widevine::INVALID_SERVICE_CERTIFICATE, - "Private key in the service certificate is null."); + return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE, + "Private key in the service certificate is null."); } std::string signature; private_key->GenerateSignature(device_certificate_status_list_request, @@ -361,6 +357,6 @@ util::Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( signed_request.set_signature(signature); signed_request.SerializeToString( signed_device_certificate_status_list_request); - return util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/device_status_list.h b/common/device_status_list.h index e96971f..13782c7 100644 --- a/common/device_status_list.h +++ b/common/device_status_list.h @@ -37,12 +37,12 @@ class DeviceStatusList { DeviceStatusList(); virtual ~DeviceStatusList(); - // Takes |signed_certificate_status_list| and copies to an internal map of + // Takes |serialized_certificate_status_list| and copies to an internal map of // device certifcate status list. The internal map is used to verify // a device was not revoked. Returns true is the list was successfully parsed. - util::Status UpdateStatusList(const std::string& root_certificate_public_key, - const std::string& signed_certificate_status_list, - uint32_t expiration_period_seconds); + Status UpdateStatusList(const std::string& root_certificate_public_key, + const std::string& serialized_certificate_status_list, + 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) { @@ -58,9 +58,8 @@ class DeviceStatusList { // DRM_DEVICE_CERTIFICATE_UNKNOWN // If status is OK, a copy of the provisioned device info is copied // into |device_info|. Caller owns |device_info| and it must not be null. - util::Status GetCertStatus( - const ClientCert& client_cert, - widevine::ProvisionedDeviceInfo* device_info); + Status GetCertStatus(const ClientCert& client_cert, + widevine::ProvisionedDeviceInfo* device_info); // 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); @@ -86,7 +85,7 @@ class DeviceStatusList { * @param certificate_status_list * @return WvPLStatus - Status::OK if success, else error. */ - static util::Status ExtractFromProvisioningServiceResponse( + static Status ExtractFromProvisioningServiceResponse( const std::string& certificate_provisioning_service_response, std::string* signed_certificate_status_list, std::string* certificate_status_list); /** @@ -94,9 +93,9 @@ class DeviceStatusList { * * @param signed_device_certificate_status_list_request * @param version - * @return util::Status - Status::OK if success, else error. + * @return Status - Status::OK if success, else error. */ - static util::Status GenerateSignedDeviceCertificateStatusListRequest( + static Status GenerateSignedDeviceCertificateStatusListRequest( const std::string& version, std::string* signed_device_certificate_status_list_request); diff --git a/common/device_status_list_test.cc b/common/device_status_list_test.cc index b76ce55..73d4683 100644 --- a/common/device_status_list_test.cc +++ b/common/device_status_list_test.cc @@ -114,10 +114,9 @@ class DeviceStatusListTest : public ::testing::Test { ASSERT_TRUE( signed_cert_status_list_.SerializeToString(&serialized_status_list_)); - ASSERT_EQ(util::OkStatus(), - device_status_list_.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_status_list_, kDefaultExpirePeriod)); + ASSERT_EQ(OkStatus(), device_status_list_.UpdateStatusList( + test_keys_.public_test_key_1_3072_bits(), + serialized_status_list_, kDefaultExpirePeriod)); } DeviceStatusList device_status_list_; @@ -140,7 +139,7 @@ TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) { .WillRepeatedly(Return(kValidCertSystemId)); EXPECT_CALL(valid_client_cert, signer_serial_number()) .WillRepeatedly(ReturnRef(valid_drm_serial_number)); - EXPECT_EQ(util::OkStatus(), + EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(valid_client_cert, &device_info)); EXPECT_TRUE(device_info.has_model()); EXPECT_EQ(kDeviceModel, device_info.model()); @@ -191,8 +190,8 @@ TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) { .WillRepeatedly(Return(kTestOnlyCertSystemId)); EXPECT_CALL(test_only_client_cert, signer_serial_number()) .WillRepeatedly(ReturnRef(test_only_drm_serial_number)); - EXPECT_EQ(util::OkStatus(), device_status_list_.GetCertStatus( - test_only_client_cert, &device_info)); + EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(test_only_client_cert, + &device_info)); } TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) { @@ -208,8 +207,8 @@ TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) { .WillRepeatedly(Return(ClientIdentification::KEYBOX)); EXPECT_CALL(valid_client_keybox, system_id()) .WillRepeatedly(Return(kValidCertSystemId)); - EXPECT_EQ(util::OkStatus(), device_status_list_.GetCertStatus( - valid_client_keybox, &device_info)); + EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(valid_client_keybox, + &device_info)); EXPECT_TRUE(device_info.has_model()); EXPECT_EQ(kDeviceModel, device_info.model()); @@ -249,7 +248,7 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) { // 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(util::OkStatus(), + EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(older_client_cert, &device_info)); EXPECT_TRUE(device_info.has_system_id()); EXPECT_EQ(kValidCertSystemId, device_info.system_id()); @@ -314,9 +313,9 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) { .Times(2) .WillOnce(Return(kStatusListCreationTime + 100)) .WillOnce(Return(kStatusListCreationTime + 101)); - EXPECT_EQ(util::OkStatus(), mock_device_status_list.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_status_list_, 100)); + EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( + test_keys_.public_test_key_1_3072_bits(), + serialized_status_list_, 100)); EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST, mock_device_status_list .UpdateStatusList(test_keys_.public_test_key_1_3072_bits(), @@ -331,9 +330,9 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) { .WillOnce(Return(kStatusListCreationTime + 100)) .WillOnce(Return(kStatusListCreationTime + 100)) .WillOnce(Return(kStatusListCreationTime + 101)); - EXPECT_EQ(util::OkStatus(), mock_device_status_list.UpdateStatusList( - test_keys_.public_test_key_1_3072_bits(), - serialized_status_list_, 100)); + EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( + test_keys_.public_test_key_1_3072_bits(), + serialized_status_list_, 100)); ProvisionedDeviceInfo device_info; MockCertificateClientCert valid_client_cert; @@ -346,8 +345,8 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) { .WillRepeatedly(ReturnRef(valid_drm_serial_number)); EXPECT_CALL(valid_client_cert, signer_creation_time_seconds()) .WillRepeatedly(Return(kStatusListCreationTime - 1)); - EXPECT_EQ(util::OkStatus(), mock_device_status_list.GetCertStatus( - valid_client_cert, &device_info)); + EXPECT_EQ(OkStatus(), mock_device_status_list.GetCertStatus(valid_client_cert, + &device_info)); EXPECT_EQ( EXPIRED_CERTIFICATE_STATUS_LIST, diff --git a/common/drm_root_certificate.cc b/common/drm_root_certificate.cc index 9e52ad9..b211a96 100644 --- a/common/drm_root_certificate.cc +++ b/common/drm_root_certificate.cc @@ -265,10 +265,10 @@ class VerifiedCertSignatureCache { // Checks cache, on miss, uses public key. If successful, adds to // cache. - util::Status VerifySignature(const std::string& cert, const std::string& serial_number, - const std::string& signature, - const std::string& signer_public_key, - const std::string& signer_serial_number) { + Status VerifySignature(const std::string& cert, const std::string& serial_number, + const std::string& signature, + const std::string& signer_public_key, + const std::string& signer_serial_number) { { VerifiedCertSignatures::iterator cached_signature; absl::ReaderMutexLock read_lock(&signature_cache_mutex_); @@ -279,11 +279,11 @@ class VerifiedCertSignatureCache { (signature != cached_signature->second.signature) || (signer_serial_number != cached_signature->second.signer_serial)) { // Cached signature mismatch. - return util::Status(error_space, INVALID_SIGNATURE, - "cached-signature-mismatch"); + return Status(error_space, INVALID_SIGNATURE, + "cached-signature-mismatch"); } // Cached signature match. - return util::OkStatus(); + return OkStatus(); } } @@ -291,12 +291,12 @@ class VerifiedCertSignatureCache { std::unique_ptr signer_key( key_factory_->CreateFromPkcs1PublicKey(signer_public_key)); if (!signer_key) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-public-key"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signer-public-key"); } if (!signer_key->VerifySignature(cert, signature)) { - return util::Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature"); + return Status(error_space, INVALID_SIGNATURE, + "cache-miss-invalid-signature"); } // Add signature to cache. @@ -304,7 +304,7 @@ class VerifiedCertSignatureCache { signature_cache_.emplace( serial_number, VerifiedCertSignature(cert, signature, signer_serial_number)); - return util::OkStatus(); + return OkStatus(); } private: @@ -313,7 +313,7 @@ class VerifiedCertSignatureCache { const RsaKeyFactory* key_factory_; }; -util::Status DrmRootCertificate::CreateByType( +Status DrmRootCertificate::CreateByType( CertificateType cert_type, std::unique_ptr* cert) { CHECK(cert); @@ -321,7 +321,7 @@ util::Status DrmRootCertificate::CreateByType( } std::unique_ptr DrmRootCertificate::CreateByType( - CertificateType cert_type, util::Status* status) { + CertificateType cert_type, Status* status) { CHECK(status); std::unique_ptr new_root_cert; @@ -329,7 +329,7 @@ std::unique_ptr DrmRootCertificate::CreateByType( return new_root_cert; } -util::Status DrmRootCertificate::CreateByTypeString( +Status DrmRootCertificate::CreateByTypeString( const std::string& cert_type_string, std::unique_ptr* cert) { CHECK(cert); @@ -341,17 +341,16 @@ util::Status DrmRootCertificate::CreateByTypeString( } else if (cert_type_string == kTestingString) { cert_type = kCertificateTypeTesting; } else { - return util::Status( - error_space, INVALID_PARAMETER, - absl::StrCat("invalid-certificate-type ", cert_type_string)); + return Status(error_space, INVALID_PARAMETER, + absl::StrCat("invalid-certificate-type ", cert_type_string)); } return CreateByType(cert_type, cert); } -util::Status DrmRootCertificate::Create( - CertificateType cert_type, std::unique_ptr key_factory, - std::unique_ptr* cert) { +Status DrmRootCertificate::Create(CertificateType cert_type, + std::unique_ptr key_factory, + std::unique_ptr* cert) { DCHECK(cert); std::string serialized_certificate; @@ -375,49 +374,48 @@ util::Status DrmRootCertificate::Create( break; } default: - return util::Status(error_space, INVALID_PARAMETER, - "invalid-certificate-type"); + return Status(error_space, INVALID_PARAMETER, "invalid-certificate-type"); } SignedDrmCertificate signed_root_cert; if (!signed_root_cert.ParseFromString(serialized_certificate)) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "signed-root-cert-deserialize-fail"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "signed-root-cert-deserialize-fail"); } DrmCertificate root_cert; if (!signed_root_cert.has_drm_certificate()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-root-device-certificate"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-root-device-certificate"); } if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "root-cert-deserialize-fail"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "root-cert-deserialize-fail"); } if (!root_cert.has_public_key()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-root-cert-public-key"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-root-cert-public-key"); } if (!signed_root_cert.has_signature()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-root-certificate-signature"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-root-certificate-signature"); } std::unique_ptr public_key( key_factory->CreateFromPkcs1PublicKey(root_cert.public_key())); if (!public_key) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-root-public-key"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-root-public-key"); } if (!public_key->VerifySignature(signed_root_cert.drm_certificate(), signed_root_cert.signature())) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-root-certificate-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 util::OkStatus(); + return OkStatus(); } DrmRootCertificate::DrmRootCertificate( @@ -437,7 +435,7 @@ std::string DrmRootCertificate::GetDigest() const { return absl::BytesToHexString(Sha256_Hash(serialized_certificate_)); } -util::Status DrmRootCertificate::VerifyCertificate( +Status DrmRootCertificate::VerifyCertificate( const std::string& serialized_certificate, SignedDrmCertificate* signed_certificate, DrmCertificate* certificate) const { @@ -447,8 +445,8 @@ util::Status DrmRootCertificate::VerifyCertificate( signed_certificate = local_signed_certificate.get(); } if (!signed_certificate->ParseFromString(serialized_certificate)) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signed-drm-certificate"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signed-drm-certificate"); } std::unique_ptr local_certificate; @@ -458,20 +456,19 @@ util::Status DrmRootCertificate::VerifyCertificate( } if (signed_certificate->drm_certificate().empty() || !certificate->ParseFromString(signed_certificate->drm_certificate())) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-drm-certificate"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-drm-certificate"); } if (certificate->serial_number().empty()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-serial-number"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-serial-number"); } if (!certificate->has_creation_time_seconds()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-creation-time"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "missing-creation-time"); } if (certificate->public_key().empty()) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-public-key"); + return Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"); } // Verify signature chain, but do not use cache for leaf certificates. @@ -485,7 +482,7 @@ util::Status DrmRootCertificate::VerifyCertificate( // 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. -util::Status DrmRootCertificate::VerifySignatures( +Status DrmRootCertificate::VerifySignatures( const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number, bool use_cache) const { if (!signed_cert.has_signer()) { @@ -497,12 +494,12 @@ util::Status DrmRootCertificate::VerifySignatures( DrmCertificate signer; if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-certificate"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signer-certificate"); } // Verify the signer before verifying signed_cert. - util::Status status = + Status status = VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache); if (!status.ok()) { return status; @@ -519,17 +516,17 @@ util::Status DrmRootCertificate::VerifySignatures( std::unique_ptr signer_public_key( key_factory_->CreateFromPkcs1PublicKey(signer.public_key())); if (!signer_public_key) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-leaf-signer-public-key"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-leaf-signer-public-key"); } if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(), signed_cert.signature())) { - return util::Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature"); + return Status(error_space, INVALID_SIGNATURE, + "cache-miss-invalid-signature"); } } - return util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/drm_root_certificate.h b/common/drm_root_certificate.h index 993ef77..e786351 100644 --- a/common/drm_root_certificate.h +++ b/common/drm_root_certificate.h @@ -42,13 +42,13 @@ class DrmRootCertificate { // 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 - // util::Status::OK on success, or appropriate error status otherwise. - static util::Status CreateByType(CertificateType cert_type, - std::unique_ptr* cert); + // 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, util::Status* status); + CertificateType cert_type, Status* status); // Creates a DrmRootCertificate object given a certificate type std::string, which // must be one of "prod", "qa", or "test". @@ -56,19 +56,16 @@ class DrmRootCertificate { // 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 - // util::Status::OK on success, or appropriate error status otherwise. - static util::Status CreateByTypeString( - const std::string& cert_type_string, - std::unique_ptr* cert); + // 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 util::Status::OK if successful, or an appropriate error code - // otherwise. - virtual util::Status VerifyCertificate( - const std::string& serialized_certificate, - SignedDrmCertificate* signed_certificate, - DrmCertificate* certificate) const; + // 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; @@ -86,13 +83,13 @@ class DrmRootCertificate { private: friend class DrmRootCertificateTest; - static util::Status Create(CertificateType cert_type, - std::unique_ptr key_factory, - std::unique_ptr* cert); + static Status Create(CertificateType cert_type, + std::unique_ptr key_factory, + std::unique_ptr* cert); - util::Status VerifySignatures(const SignedDrmCertificate& signed_cert, - const std::string& cert_serial_number, - bool use_cache) const; + Status VerifySignatures(const SignedDrmCertificate& signed_cert, + const std::string& cert_serial_number, + bool use_cache) const; CertificateType type_; std::string serialized_certificate_; diff --git a/common/drm_root_certificate_test.cc b/common/drm_root_certificate_test.cc index 5b192ce..24c3509 100644 --- a/common/drm_root_certificate_test.cc +++ b/common/drm_root_certificate_test.cc @@ -33,8 +33,8 @@ TEST(DrmRootCertificateCreateTest, TestCertificate) { "49f917b1bdfed78002a58e799a58e940" "1fffaaed9d8d80752782b066757e2c8c"); std::unique_ptr root_cert; - ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeTesting, &root_cert)); + ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( + kCertificateTypeTesting, &root_cert)); ASSERT_TRUE(root_cert != nullptr); EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest()); } @@ -44,8 +44,8 @@ TEST(DrmRootCertificateCreateTest, DevCertificate) { "0e25ee95476a770f30b98ac5ef778b3f" "137b66c29385b84f547a361b4724b17d"); std::unique_ptr root_cert; - ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeDevelopment, &root_cert)); + ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( + kCertificateTypeDevelopment, &root_cert)); ASSERT_TRUE(root_cert != nullptr); EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest()); } @@ -55,8 +55,8 @@ TEST(DrmRootCertificateCreateTest, ProdCertificate) { "d62fdabc9286648a81f7d3bedaf2f5a5" "27bbad39bc38da034ba98a21569adb9b"); std::unique_ptr root_cert; - ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeProduction, &root_cert)); + ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( + kCertificateTypeProduction, &root_cert)); ASSERT_TRUE(root_cert != nullptr); EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest()); } @@ -111,8 +111,8 @@ class DrmRootCertificateTest : public testing::Test { drm_certificates_[2].set_public_key( test_keys_.public_test_key_3_2048_bits()); - ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType( - kCertificateTypeTesting, &root_cert_)); + ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType( + kCertificateTypeTesting, &root_cert_)); } void GenerateSignedDrmCertificate() { @@ -144,7 +144,7 @@ class DrmRootCertificateTest : public testing::Test { TEST_F(DrmRootCertificateTest, SuccessNoOutput) { GenerateSignedDrmCertificate(); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), root_cert_->VerifyCertificate( signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); } @@ -153,25 +153,25 @@ TEST_F(DrmRootCertificateTest, SuccessWithOutput) { GenerateSignedDrmCertificate(); SignedDrmCertificate out_signed_cert; DrmCertificate out_cert; - ASSERT_EQ(util::OkStatus(), root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), - &out_signed_cert, &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_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) { - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signed-drm-certificate"), + EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signed-drm-certificate"), root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) { GenerateSignedDrmCertificate(); signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage"); - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-certificate"), + EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, + "invalid-signer-certificate"), root_cert_->VerifyCertificate( signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); } @@ -179,86 +179,84 @@ TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) { TEST_F(DrmRootCertificateTest, MissingDrmCertificate) { GenerateSignedDrmCertificate(); signed_drm_certificate_.clear_drm_certificate(); - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-drm-certificate"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); + EXPECT_EQ( + Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"), + root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), + nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, InvalidDrmCertificate) { GenerateSignedDrmCertificate(); signed_drm_certificate_.set_drm_certificate("junk"); - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-drm-certificate"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); + EXPECT_EQ( + Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"), + root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), + nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, InvalidPublicKey) { drm_certificates_[0].set_public_key("rubbish"); GenerateSignedDrmCertificate(); - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "invalid-signer-public-key"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); + EXPECT_EQ( + Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signer-public-key"), + root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), + nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, MissingPublicKey) { drm_certificates_[2].clear_public_key(); GenerateSignedDrmCertificate(); - EXPECT_EQ( - util::Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); + EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"), + root_cert_->VerifyCertificate( + signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, MissingCreationTime) { drm_certificates_[2].clear_creation_time_seconds(); GenerateSignedDrmCertificate(); - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-creation-time"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); + EXPECT_EQ( + Status(error_space, INVALID_DRM_CERTIFICATE, "missing-creation-time"), + root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), + nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, MissingSerialNumber) { drm_certificates_[2].set_serial_number(""); GenerateSignedDrmCertificate(); - EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE, - "missing-serial-number"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); + EXPECT_EQ( + Status(error_space, INVALID_DRM_CERTIFICATE, "missing-serial-number"), + root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), + nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, InvalidSignatureWithNoCache) { GenerateSignedDrmCertificate(); signed_drm_certificate_.mutable_signer()->set_signature( "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); - EXPECT_EQ(util::Status(error_space, INVALID_SIGNATURE, - "cache-miss-invalid-signature"), - root_cert_->VerifyCertificate( - signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); + EXPECT_EQ( + Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature"), + root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), + nullptr, nullptr)); } TEST_F(DrmRootCertificateTest, InvalidSignatureWithCache) { GenerateSignedDrmCertificate(); // Verify and cache. - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), root_cert_->VerifyCertificate( signed_drm_certificate_.SerializeAsString(), nullptr, nullptr)); // Verify success using cache. - ASSERT_EQ(util::OkStatus(), + 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( - util::Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"), - root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(), - nullptr, nullptr)); + 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 index 466ee31..9229859 100644 --- a/common/drm_service_certificate.cc +++ b/common/drm_service_certificate.cc @@ -107,41 +107,41 @@ DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() { } // namespace -util::Status DrmServiceCertificate::AddDrmServiceCertificate( - const DrmRootCertificate* root_cert, const std::string& service_certificate, +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; - util::Status status = - root_cert->VerifyCertificate(service_certificate, nullptr, &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 util::Status(error_space, INVALID_SERVICE_CERTIFICATE, - "not-service-certificate"); + return Status(error_space, INVALID_SERVICE_CERTIFICATE, + "not-service-certificate"); } if (drm_cert.provider_id().empty()) { - return util::Status(error_space, INVALID_SERVICE_CERTIFICATE, - "missing-certificate-service-id"); + 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 util::Status(error_space, INVALID_SERVICE_CERTIFICATE, - "invalid-certificate-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 util::Status(error_space, INVALID_SERVICE_PRIVATE_KEY, - "key-decryption-failed"); + 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 util::Status(error_space, INVALID_SERVICE_PRIVATE_KEY, - "invalid-private-key"); + return Status(error_space, INVALID_SERVICE_PRIVATE_KEY, + "invalid-private-key"); } std::unique_ptr new_cert(new DrmServiceCertificate( @@ -150,7 +150,7 @@ util::Status DrmServiceCertificate::AddDrmServiceCertificate( std::move(private_key))); DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert)); - return util::OkStatus(); + return OkStatus(); } const DrmServiceCertificate* @@ -171,7 +171,7 @@ const DrmServiceCertificate* DrmServiceCertificate::GetDrmServiceCertificate( return DrmServiceCertificateMap::GetInstance()->GetCert(serial_number); } -util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate( +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) { @@ -181,36 +181,36 @@ util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate( service_private_key_passphrase); } -util::Status DrmServiceCertificate::DecryptClientIdentification( +Status DrmServiceCertificate::DecryptClientIdentification( const EncryptedClientIdentification& encrypted_client_id, ClientIdentification* client_id) { DCHECK(client_id); if (encrypted_client_id.service_certificate_serial_number().empty()) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-service-certificate-serial-number"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "missing-service-certificate-serial-number"); } if (encrypted_client_id.provider_id().empty()) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-service-id"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "missing-service-id"); } if (encrypted_client_id.encrypted_client_id().empty()) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "missing-encrypted-client-id"); } if (encrypted_client_id.encrypted_client_id_iv().empty()) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-client-id-iv"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "missing-encrypted-client-id-iv"); } if (encrypted_client_id.encrypted_privacy_key().empty()) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "missing-encrypted-privacy-key"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "missing-encrypted-privacy-key"); } std::string privacy_key; std::string provider_id; const DrmServiceCertificate* cert = GetDrmServiceCertificate( encrypted_client_id.service_certificate_serial_number()); if (!cert) { - return util::Status( + return Status( error_space, SERVICE_CERTIFICATE_NOT_FOUND, "service-certificate-not-found (SN " + absl::BytesToHexString( @@ -219,56 +219,56 @@ util::Status DrmServiceCertificate::DecryptClientIdentification( } if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(), &privacy_key)) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "privacy-key-decryption-failed"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "privacy-key-decryption-failed"); } if (cert->provider_id() != encrypted_client_id.provider_id()) { - return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, - std::string("provider-id-mismatch (") + 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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-decryption-failed"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "client-id-decryption-failed"); } if (!client_id->ParseFromString(serialized_client_id)) { - return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, - "client-id-parse-failed"); + return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION, + "client-id-parse-failed"); } - return util::OkStatus(); + return OkStatus(); } void DrmServiceCertificate::ResetServiceCertificates() { DrmServiceCertificateMap::GetInstance()->Reset(); } -util::Status DrmServiceCertificate::ValidateDrmServiceCertificate() { +Status DrmServiceCertificate::ValidateDrmServiceCertificate() { const DrmServiceCertificate* service_certificate = GetDefaultDrmServiceCertificate(); if (!service_certificate) { - return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, - "drm service certificate is not found."); + 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 util::Status(error_space, INVALID_DRM_CERTIFICATE, - "signed drm service certificate is failed to parse."); + 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 util::Status(error_space, INVALID_DRM_CERTIFICATE, - "Drm service certificate is failed to parse."); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "Drm service certificate is failed to parse."); } if (!drm_cert.has_creation_time_seconds()) { - return util::Status(error_space, INVALID_SERVICE_CERTIFICATE, - "missing certificate creation time"); + 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 util::OkStatus(); + return OkStatus(); } DrmServiceCertificate::DrmServiceCertificate( diff --git a/common/drm_service_certificate.h b/common/drm_service_certificate.h index 008b8a1..fec6055 100644 --- a/common/drm_service_certificate.h +++ b/common/drm_service_certificate.h @@ -18,9 +18,9 @@ #include #include "base/macros.h" -#include "common/status.h" #include "common/certificate_type.h" #include "common/rsa_key.h" +#include "common/status.h" namespace widevine { class RequestInspectorTest; @@ -48,7 +48,7 @@ class DrmServiceCertificate { // If the default service certificate is not set, this certificate will be // used as the default service certificate. // This method is thread-safe. - static util::Status AddDrmServiceCertificate( + 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); @@ -56,7 +56,7 @@ class DrmServiceCertificate { // 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 util::Status SetDefaultDrmServiceCertificate( + 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); @@ -79,7 +79,7 @@ class DrmServiceCertificate { // 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 util::Status DecryptClientIdentification( + static Status DecryptClientIdentification( const EncryptedClientIdentification& encrypted_client_id, ClientIdentification* client_id); @@ -93,18 +93,18 @@ class DrmServiceCertificate { // 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 util::Status ValidateDrmServiceCertificate(); + static Status ValidateDrmServiceCertificate(); private: friend class DrmServiceCertificateTest; friend class widevine::RequestInspectorTest; - static util::Status AddDrmServiceCertificate( + 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 util::Status SetDefaultDrmServiceCertificate( + 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); diff --git a/common/drm_service_certificate_test.cc b/common/drm_service_certificate_test.cc index b2b8628..b5eef32 100644 --- a/common/drm_service_certificate_test.cc +++ b/common/drm_service_certificate_test.cc @@ -69,9 +69,9 @@ class DrmServiceCertificateTest : public ::testing::Test { return serialized_cert; } - util::Status SetDefaultDrmServiceCertificate(const std::string& serial_number, - const std::string& provider_id, - uint32_t creation_time_seconds) { + 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())); @@ -79,15 +79,15 @@ class DrmServiceCertificateTest : public ::testing::Test { if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( test_keys_.private_test_key_2_2048_bits(), kPassphrase, &encrypted_private_key)) { - return util::Status(util::error::INTERNAL, ""); + return Status(error::INTERNAL, ""); } return DrmServiceCertificate::SetDefaultDrmServiceCertificate( root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase); } - util::Status AddDrmServiceCertificate(const std::string& serial_number, - const std::string& provider_id, - uint32_t creation_time_seconds) { + 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())); @@ -95,7 +95,7 @@ class DrmServiceCertificateTest : public ::testing::Test { if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( test_keys_.private_test_key_2_2048_bits(), kPassphrase, &encrypted_private_key)) { - return util::Status(util::error::INTERNAL, ""); + return Status(error::INTERNAL, ""); } return DrmServiceCertificate::AddDrmServiceCertificate( root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase); @@ -140,9 +140,8 @@ TEST_F(DrmServiceCertificateTest, BasicClientIdDecrypt) { test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; - EXPECT_EQ(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &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)); } @@ -220,27 +219,24 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) { test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; - EXPECT_EQ(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &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(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &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_number3, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); - EXPECT_EQ(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &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)); @@ -292,9 +288,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) { test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; - ASSERT_EQ(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &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)); @@ -310,9 +305,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) { invalid = encrypted_client_id; ++(*invalid.mutable_encrypted_client_id_iv())[4]; - EXPECT_NE(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - invalid, &decrypted_client_id)); + EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( + invalid, &decrypted_client_id)); invalid.clear_encrypted_client_id_iv(); EXPECT_EQ( @@ -324,9 +318,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) { invalid = encrypted_client_id; ++(*invalid.mutable_encrypted_client_id())[0]; - EXPECT_NE(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - invalid, &decrypted_client_id)); + EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( + invalid, &decrypted_client_id)); invalid.clear_encrypted_client_id(); EXPECT_EQ( @@ -349,9 +342,8 @@ TEST_F(DrmServiceCertificateTest, PrivateKeyDecryptError) { test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; - ASSERT_EQ(util::OkStatus(), - DrmServiceCertificate::DecryptClientIdentification( - encrypted_client_id, &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)); diff --git a/common/remote_attestation_verifier.cc b/common/remote_attestation_verifier.cc index 185369a..5d9f4c0 100644 --- a/common/remote_attestation_verifier.cc +++ b/common/remote_attestation_verifier.cc @@ -113,99 +113,99 @@ void RemoteAttestationVerifier::EnableTestDrmCertificates(bool enable) { ca_.reset(); } -util::Status RemoteAttestationVerifier::VerifyRemoteAttestation( +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 (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-certificate-missing")); + return (Status(error_space, INVALID_MESSAGE, + "remote-attestation-certificate-missing")); } if (!remote_attestation.has_salt()) { - return (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-salt-missing")); + return (Status(error_space, INVALID_MESSAGE, + "remote-attestation-salt-missing")); } if (!remote_attestation.has_signature()) { - return (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-signature-missing")); + 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; - util::Status status = DrmServiceCertificate::DecryptClientIdentification( + Status status = DrmServiceCertificate::DecryptClientIdentification( remote_attestation.certificate(), &client_id); if (!status.ok()) return status; if (client_id.type() != ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) { - return (util::Status(error_space, INVALID_MESSAGE, - std::string("remote-attestation-invalid-client-id-type (") + - absl::StrCat(client_id.type()) + ")")); + 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); } -util::Status RemoteAttestationVerifier::VerifyRemoteAttestation( +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 (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-certificate-missing")); + return (Status(error_space, INVALID_MESSAGE, + "remote-attestation-certificate-missing")); } if (!remote_attestation.has_salt()) { - return (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-salt-missing")); + return (Status(error_space, INVALID_MESSAGE, + "remote-attestation-salt-missing")); } if (!remote_attestation.has_signature()) { - return (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-signature-missing")); + 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; - util::Status status = DecryptEncryptedClientIdentification( + Status status = DecryptEncryptedClientIdentification( remote_attestation.certificate(), privacy_key, &client_id); if (!status.ok()) return status; if (client_id.type() != ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) { - return (util::Status(error_space, INVALID_MESSAGE, - std::string("remote-attestation-invalid-client-id-type (") + - absl::StrCat(client_id.type()) + ")")); + 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); } -util::Status RemoteAttestationVerifier::VerifyRemoteAttestation( +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 (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-token-missing")); + return (Status(error_space, INVALID_MESSAGE, + "remote-attestation-token-missing")); } // Load and verify the certificate chain. std::unique_ptr cert_chain(new X509CertChain); - util::Status status = cert_chain->LoadPem(client_id.token()); + Status status = cert_chain->LoadPem(client_id.token()); if (!status.ok()) return status; if (cert_chain->GetNumCerts() < 1) { - return (util::Status(error_space, INVALID_MESSAGE, - "remote-attestation-empty-certificate-chain")); + 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 (util::Status(error_space, REMOTE_ATTESTATION_FAILED, - std::string("remote-attestation-device-not-verified (") + - device_mode_string + " / " + kDeviceModeFieldName + - ")")); + return (Status(error_space, REMOTE_ATTESTATION_FAILED, + std::string("remote-attestation-device-not-verified (") + + device_mode_string + " / " + kDeviceModeFieldName + + ")")); } ca_mutex_.ReaderLock(); if (ca_ == NULL) { @@ -217,10 +217,9 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation( status = ca_->VerifyCertChain(*cert_chain); ca_mutex_.ReaderUnlock(); if (!status.ok()) { - return (util::Status( - error_space, REMOTE_ATTESTATION_FAILED, - std::string("remote-attestation-cert-chain-validation-failed: ") + - status.error_message())); + 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; @@ -232,30 +231,30 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation( } } if (!leaf_key) { - return util::Status(error_space, REMOTE_ATTESTATION_FAILED, - "remote-attestation-cert-chain-no-leaf"); + return Status(error_space, REMOTE_ATTESTATION_FAILED, + "remote-attestation-cert-chain-no-leaf"); } if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt, remote_attestation.signature())) { - return (util::Status(error_space, REMOTE_ATTESTATION_FAILED, - "remote-attestation-signature-verification-failed: ")); + return (Status(error_space, REMOTE_ATTESTATION_FAILED, + "remote-attestation-signature-verification-failed: ")); } *remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber(); - return util::OkStatus(); + return OkStatus(); } -util::Status RemoteAttestationVerifier::LoadCa() { +Status RemoteAttestationVerifier::LoadCa() { absl::WriterMutexLock lock(&ca_mutex_); std::unique_ptr ca_cert(new X509Cert); - util::Status status = ca_cert->LoadDer(absl::HexStringToBytes( + 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 util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/remote_attestation_verifier.h b/common/remote_attestation_verifier.h index 740a69b..40462ce 100644 --- a/common/remote_attestation_verifier.h +++ b/common/remote_attestation_verifier.h @@ -50,9 +50,9 @@ class RemoteAttestationVerifier { // return will contain the serial number for the client's remote attestation // certificate. // This method is thread-safe. - util::Status VerifyRemoteAttestation( - const std::string& message, const RemoteAttestation& remote_attestation, - std::string* remote_attestation_cert_sn); + 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. @@ -61,9 +61,9 @@ class RemoteAttestationVerifier { // |privacy_key| is used to decrypt the EncryptedClientIdentification within // the |remote_attestation| message. // This method is thread-safe. - util::Status VerifyRemoteAttestation( - const std::string& message, const RemoteAttestation& remote_attestation, - const std::string& privacy_key); + Status VerifyRemoteAttestation(const std::string& message, + const RemoteAttestation& remote_attestation, + const std::string& privacy_key); private: // Common subroutine to perform the verification. @@ -73,12 +73,12 @@ class RemoteAttestationVerifier { // |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. - util::Status VerifyRemoteAttestation( - const std::string& message, const RemoteAttestation& remote_attestation, - const ClientIdentification& client_id, - std::string* remote_attestation_cert_sn); + Status VerifyRemoteAttestation(const std::string& message, + const RemoteAttestation& remote_attestation, + const ClientIdentification& client_id, + std::string* remote_attestation_cert_sn); - util::Status LoadCa(); + Status LoadCa(); bool enable_test_certificates_; absl::Mutex ca_mutex_; diff --git a/common/sha_util.cc b/common/sha_util.cc index 1ad68fc..5f3d5b2 100644 --- a/common/sha_util.cc +++ b/common/sha_util.cc @@ -29,6 +29,14 @@ std::string Sha256_Hash(const std::string& message) { return digest; } +std::string Sha512_Hash(const std::string& message) { + std::string digest; + digest.resize(SHA512_DIGEST_LENGTH); + SHA512(reinterpret_cast(message.data()), message.size(), + reinterpret_cast(&digest[0])); + return digest; +} + std::string GenerateSha1Uuid(const std::string& name_space, const std::string& name) { // X.667 14 Setting the fields of a name-based UUID. // - Allocate a UUID to use as a "name space identifier" for all UUIDs diff --git a/common/sha_util.h b/common/sha_util.h index bc9390d..1e2b70a 100644 --- a/common/sha_util.h +++ b/common/sha_util.h @@ -21,6 +21,9 @@ std::string Sha1_Hash(const std::string& message); // Calculates SHA256 hash. std::string Sha256_Hash(const std::string& message); +// Calculate SHA512 hash. +std::string Sha512_Hash(const std::string& message); + // Generates a UUID as specified in ITU-T X.667 ch. 14, SHA-1 name-based, // 16-byte binary representation. Name_space is a GUID prefix; name is a unique // name in the namespace. diff --git a/common/sha_util_test.cc b/common/sha_util_test.cc index 6adc7ca..8b3eb7c 100644 --- a/common/sha_util_test.cc +++ b/common/sha_util_test.cc @@ -48,6 +48,18 @@ TEST(ShaUtilTest, Sha256) { 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"); diff --git a/common/signature_util.cc b/common/signature_util.cc index 05c9e21..1e80e09 100644 --- a/common/signature_util.cc +++ b/common/signature_util.cc @@ -11,55 +11,50 @@ #include #include -#include "common/status.h" #include "common/aes_cbc_util.h" #include "common/rsa_key.h" #include "common/sha_util.h" +#include "common/status.h" namespace widevine { namespace signature_util { -util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key, - const std::string& aes_iv, std::string* signature) { +Status GenerateAesSignature(const std::string& message, const std::string& aes_key, + const std::string& aes_iv, std::string* signature) { if (signature == nullptr) { - return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr"); + return Status(error::INVALID_ARGUMENT, "signature is nullptr"); } std::string hash = Sha1_Hash(message); if (hash.empty()) { - return util::Status(util::error::INTERNAL, "Computed hash is empty"); + return Status(error::INTERNAL, "Computed hash is empty"); } std::string sig = crypto_util::EncryptAesCbc(aes_key, aes_iv, hash); if (sig.empty()) { - return util::Status(util::error::INTERNAL, - "Computed AES signature is empty"); + return Status(error::INTERNAL, "Computed AES signature is empty"); } *signature = sig; - return util::OkStatus(); + return OkStatus(); } -util::Status GenerateRsaSignature(const std::string& message, - const std::string& private_key, - std::string* signature) { +Status GenerateRsaSignature(const std::string& message, const std::string& private_key, + std::string* signature) { if (signature == nullptr) { - return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr"); + return Status(error::INVALID_ARGUMENT, "signature is nullptr"); } std::unique_ptr rsa_private_key( RsaPrivateKey::Create(private_key)); if (rsa_private_key == nullptr) { - return util::Status(util::error::INTERNAL, - "Failed to construct a RsaPrivateKey"); + return Status(error::INTERNAL, "Failed to construct a RsaPrivateKey"); } std::string sig; if (!rsa_private_key->GenerateSignature(message, &sig)) { - return util::Status(util::error::INTERNAL, - "Failed to generate a RSA signature"); + return Status(error::INTERNAL, "Failed to generate a RSA signature"); } if (sig.empty()) { - return util::Status(util::error::INTERNAL, - "Computed RSA signature is empty"); + return Status(error::INTERNAL, "Computed RSA signature is empty"); } *signature = sig; - return util::OkStatus(); + return OkStatus(); } } // namespace signature_util diff --git a/common/signature_util.h b/common/signature_util.h index b770d28..25238fb 100644 --- a/common/signature_util.h +++ b/common/signature_util.h @@ -19,14 +19,14 @@ namespace signature_util { // Generates an AES signature of |message| using |aes_key| and |aes_iv|. // Signature is returned via |signature| if generation was successful. // Returns a Status that carries the details of error if generation failed. -util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key, - const std::string& aes_iv, std::string* signature); +Status GenerateAesSignature(const std::string& message, const std::string& aes_key, + const std::string& aes_iv, std::string* signature); // Generates a RSA signature of |message| using |private_key|. // Signature is returned via |sigature| if generation was successful. // Returns a Status that carries the details of error if generation failed. -util::Status GenerateRsaSignature(const std::string& message, - const std::string& private_key, std::string* signature); +Status GenerateRsaSignature(const std::string& message, const std::string& private_key, + std::string* signature); } // namespace signature_util } // namespace widevine diff --git a/common/signing_key_util.cc b/common/signing_key_util.cc index 959f437..6b7b596 100644 --- a/common/signing_key_util.cc +++ b/common/signing_key_util.cc @@ -16,7 +16,7 @@ namespace widevine { using crypto_util::kSigningKeySizeBits; -uint32_t SigningKeyMaterialSize(ProtocolVersion protocol_version) { +uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version) { if (protocol_version <= VERSION_2_0) { return kSigningKeySizeBits; } else { diff --git a/common/signing_key_util.h b/common/signing_key_util.h index eb71297..34179cd 100644 --- a/common/signing_key_util.h +++ b/common/signing_key_util.h @@ -20,7 +20,7 @@ // std::string derived_key = DeriveKey(key_str, // label, // context, -// SigningKeyMaterialSize(VERSION_2_1)); +// 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_ @@ -36,7 +36,7 @@ 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 SigningKeyMaterialSize(ProtocolVersion protocol_version); +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 diff --git a/common/signing_key_util_test.cc b/common/signing_key_util_test.cc index ae017a8..6c887d2 100644 --- a/common/signing_key_util_test.cc +++ b/common/signing_key_util_test.cc @@ -30,14 +30,14 @@ std::string GenerateDerivedKey(widevine::ProtocolVersion protocol_version) { } } // namespace -TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_0) { +TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_0) { ASSERT_EQ(crypto_util::kSigningKeySizeBits, - SigningKeyMaterialSize(VERSION_2_0)); + SigningKeyMaterialSizeBits(VERSION_2_0)); } -TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_1) { +TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_1) { ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2, - SigningKeyMaterialSize(VERSION_2_1)); + SigningKeyMaterialSizeBits(VERSION_2_1)); } TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_1) { diff --git a/common/status.cc b/common/status.cc index bccf3ad..94513ef 100644 --- a/common/status.cc +++ b/common/status.cc @@ -12,10 +12,9 @@ #include "absl/base/macros.h" #include "absl/strings/str_cat.h" -#include "common/status.h" +#include "util/error_space.h" namespace widevine { -namespace util { namespace { @@ -72,5 +71,4 @@ std::ostream& operator<<(std::ostream& os, const Status& x) { return os; } -} // namespace util } // namespace widevine diff --git a/common/status.h b/common/status.h index c716834..1d6597b 100644 --- a/common/status.h +++ b/common/status.h @@ -14,7 +14,6 @@ #include "util/error_space.h" namespace widevine { -namespace util { namespace error { enum StatusCode { @@ -104,7 +103,6 @@ std::ostream& operator<<(std::ostream& os, const Status& x); #define CHECK_OK(expression) CHECK(expression.ok()) << expression.ToString() -} // namespace util } // namespace widevine #endif // COMMON_STATUS_H_ diff --git a/common/status_test.cc b/common/status_test.cc index 7c1b6ac..e3fda01 100644 --- a/common/status_test.cc +++ b/common/status_test.cc @@ -10,7 +10,6 @@ #include "testing/gunit.h" namespace widevine { -namespace util { TEST(StatusTest, OK_Status) { // test case for ok status. @@ -59,5 +58,4 @@ TEST(StatusTest, NOT_EQUAL_OPERATOR_NONE_MSG) { } -} // namespace util } // namespace widevine diff --git a/common/string_util.cc b/common/string_util.cc index 5da8e4f..84031bb 100644 --- a/common/string_util.cc +++ b/common/string_util.cc @@ -16,9 +16,9 @@ namespace widevine { namespace string_util { -util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) { +Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) { if (output == nullptr) { - return util::Status(util::error::INTERNAL, "output is nullptr."); + return Status(error::INTERNAL, "output is nullptr."); } std::stringstream sstream(bitset); @@ -29,7 +29,7 @@ util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* *output += c; } - return util::OkStatus(); + return OkStatus(); } } // namespace string_util diff --git a/common/string_util.h b/common/string_util.h index b5b8845..9c9922d 100644 --- a/common/string_util.h +++ b/common/string_util.h @@ -17,7 +17,7 @@ namespace string_util { // Converts std::string representation of a bitset to its binary equivalent string. // For example, converts "01110100011001010111001101110100" to "test". -util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output); +Status BitsetStringToBinaryString(const std::string& bitset, std::string* output); } // namespace string_util } // namespace widevine diff --git a/common/test_utils.cc b/common/test_utils.cc index 8628d64..5dfce0b 100644 --- a/common/test_utils.cc +++ b/common/test_utils.cc @@ -18,32 +18,31 @@ namespace widevine { -util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, - const std::string& message, - std::string* signature) { +Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, + const std::string& message, + std::string* signature) { CHECK(signature); if (pem_private_key.empty()) { - return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM private key"); + return Status(error::INVALID_ARGUMENT, "Empty PEM private key"); } if (message.empty()) { - return util::Status(util::error::INVALID_ARGUMENT, "Empty message"); + 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 util::Status(util::error::INTERNAL, "BIO allocation failed"); + return Status(error::INTERNAL, "BIO allocation failed"); } - util::Status status; + 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 = util::Status(util::Status::canonical_space(), - util::error::INVALID_ARGUMENT, - "PEM RSA private key load failed"); + status = Status(Status::canonical_space(), error::INVALID_ARGUMENT, + "PEM RSA private key load failed"); goto cleanup; } SHA256(reinterpret_cast(message.data()), message.size(), @@ -53,9 +52,8 @@ util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, if (RSA_sign(NID_sha256, digest, sizeof(digest), reinterpret_cast(sig_buffer.get()), &sig_size, key) != 1) { - status = - util::Status(util::Status::canonical_space(), util::error::INTERNAL, - "RSA private encrypt failed"); + status = Status(Status::canonical_space(), error::INTERNAL, + "RSA private encrypt failed"); goto cleanup; } signature->assign(sig_buffer.get(), sig_size); diff --git a/common/test_utils.h b/common/test_utils.h index 448ccf0..9252f93 100644 --- a/common/test_utils.h +++ b/common/test_utils.h @@ -23,9 +23,9 @@ namespace widevine { // |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 paramters. -util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, - const std::string& message, - std::string* signature); +Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key, + const std::string& message, + std::string* signature); } // namespace widevine diff --git a/common/verified_media_pipeline.cc b/common/verified_media_pipeline.cc index 641ddaf..a3a9d96 100644 --- a/common/verified_media_pipeline.cc +++ b/common/verified_media_pipeline.cc @@ -14,13 +14,11 @@ #include "common/vmp_checker.h" namespace widevine { -util::Status VerifyVmpData( - const std::string& vmp_data, - PlatformVerificationStatus* platform_verification_status) { +Status VerifyVmpData(const std::string& vmp_data, + PlatformVerificationStatus* platform_verification_status) { *platform_verification_status = PLATFORM_UNVERIFIED; VmpChecker::Result vmp_result; - util::Status status = - VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result); + Status status = VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result); if (status.ok()) { switch (vmp_result) { case VmpChecker::kUnverified: diff --git a/common/verified_media_pipeline.h b/common/verified_media_pipeline.h index fd0aaf0..a6372ce 100644 --- a/common/verified_media_pipeline.h +++ b/common/verified_media_pipeline.h @@ -20,9 +20,8 @@ namespace widevine { // Retrieve the PlatformVerificationStatus for |vmp_data|. The // PlatformVerificationStatus is defined at -util::Status VerifyVmpData( - const std::string& vmp_data, - PlatformVerificationStatus* platform_verification_status); +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 index e4354b8..a6d15c8 100644 --- a/common/vmp_checker.cc +++ b/common/vmp_checker.cc @@ -248,9 +248,9 @@ VmpChecker::VmpChecker() : allow_development_vmp_(false) {} VmpChecker::~VmpChecker() {} -util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) { +Status VmpChecker::SelectCertificateType(CertificateType cert_type) { std::unique_ptr ca_cert(new X509Cert); - util::Status status = ca_cert->LoadDer( + Status status = ca_cert->LoadDer( cert_type == kCertificateTypeProduction ? std::string(reinterpret_cast( kProdVmpCodeSigningDrmRootCertificate), @@ -262,7 +262,7 @@ util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) { ca_.reset(new X509CA(ca_cert.release())); - return util::OkStatus(); + return OkStatus(); } VmpChecker* VmpChecker::Instance() { @@ -271,17 +271,16 @@ VmpChecker* VmpChecker::Instance() { } // Verify VMP data and return appropriate result. -util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) { +Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) { DCHECK(!vmp_data.empty()); DCHECK(result); - if (!ca_) return util::Status(error_space, CERT_CHAIN_NOT_SELECTED, ""); + 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 util::Status(error_space, INVALID_MESSAGE, - "vmp-data-deserialize-failed"); + return Status(error_space, INVALID_MESSAGE, "vmp-data-deserialize-failed"); } std::vector> code_signing_certs; @@ -290,7 +289,7 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu for (int cert_idx = 0; cert_idx < vmp_data_obj.certificates_size(); ++cert_idx) { code_signing_certs.emplace_back(new X509Cert); - util::Status status(code_signing_certs.back()->LoadDer( + Status status(code_signing_certs.back()->LoadDer( vmp_data_obj.certificates(cert_idx))); if (!status.ok()) return status; @@ -299,8 +298,8 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu if (code_signing_certs.back()->GetV3BooleanExtension(kDevelopmentFlagOid, &dev_flag) && dev_flag) { - return util::Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, - "development-vmp-certificate-not-allowed"); + return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, + "development-vmp-certificate-not-allowed"); } } status = ca_->VerifyCert(*code_signing_certs.back()); @@ -324,12 +323,12 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu if (binary_info.signature().empty()) { LOG(INFO) << "Unsigned binary \"" << binary_info.file_name() << "\"."; *result = kTampered; - return util::OkStatus(); + return OkStatus(); } if (binary_info.certificate_index() >= code_signing_certs.size()) { LOG(INFO) << "Invalid code signing certificate index."; *result = kTampered; - return util::OkStatus(); + return OkStatus(); } X509Cert* cert = code_signing_certs[binary_info.certificate_index()].get(); std::unique_ptr key(cert->GetRsaPublicKey()); @@ -339,7 +338,7 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu LOG(INFO) << "Code signature verification failed for file \"" << binary_info.file_name() << "\"."; *result = kTampered; - return util::OkStatus(); + return OkStatus(); } if (binary_info.flags() & kBlessedBinaryFlag) ++num_blessed_binaries; } @@ -347,13 +346,13 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu LOG(INFO) << "Invalid number of blessed binaries (" << num_blessed_binaries << ")."; *result = kTampered; - return util::OkStatus(); + return OkStatus(); } VLOG(2) << "VMP verification success. Secure storage: " << secure_storage_verified; *result = secure_storage_verified ? kSecureStorageVerified : kVerified; - return util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/vmp_checker.h b/common/vmp_checker.h index f77ac65..54caf6f 100644 --- a/common/vmp_checker.h +++ b/common/vmp_checker.h @@ -16,8 +16,8 @@ #include #include -#include "common/status.h" #include "common/certificate_type.h" +#include "common/status.h" namespace widevine { class X509CA; @@ -35,10 +35,10 @@ class VmpChecker { static VmpChecker* Instance(); // Select the type of root to use. Not thread-safe. - virtual util::Status SelectCertificateType(CertificateType cert_type); + virtual Status SelectCertificateType(CertificateType cert_type); // Verify VMP data and return appropriate result. - virtual util::Status VerifyVmpData(const std::string& vmp_data, Result* 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; } diff --git a/common/wvm_token_handler.cc b/common/wvm_token_handler.cc index 9099b65..188adc1 100644 --- a/common/wvm_token_handler.cc +++ b/common/wvm_token_handler.cc @@ -16,10 +16,10 @@ #include "absl/synchronization/mutex.h" #include "util/endian/endian.h" #include "util/gtl/map_util.h" -#include "common/status.h" #include "common/aes_cbc_util.h" #include "common/ecb_util.h" #include "common/sha_util.h" +#include "common/status.h" namespace widevine { @@ -108,20 +108,20 @@ bool WvmTokenHandler::IsSystemIdKnown(uint32_t system_id) { return PreprovKeysMap::GetSingleton()->IsSystemIdKnown(system_id); } -util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, - std::string* device_key_out, - Cipher* cipher_out, - bool* insecure_out) { +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); } -util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, - const std::string& make_model, - std::string* device_key_out, - Cipher* cipher_out, - bool* 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 @@ -129,12 +129,11 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, // presubmit because evidently Kokoro does debug build. // DCHECK(preprov_keys_); if (token.size() < kKeyboxSizeBytes) { - return util::Status(util::error::INVALID_ARGUMENT, - "Keybox token is too short."); + return Status(error::INVALID_ARGUMENT, "Keybox token is too short."); } if (PreprovKeysMap::GetSingleton()->IsEmpty()) { - return util::Status(util::error::INVALID_ARGUMENT, - "Pre-provisioning key map is nullptr."); + return Status(error::INVALID_ARGUMENT, + "Pre-provisioning key map is nullptr."); } uint32_t system_id = GetSystemId(token); @@ -143,7 +142,7 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, std::vector key_vector = PreprovKeysMap::GetSingleton()->GetPreprovKeys(system_id); - util::Status status; + 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; @@ -162,8 +161,8 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, ppk.key_bytes, token, device_key_out, insecure_out, &version); if (version != 2) { // Only version 2 keyboxes supported. - return util::Status(util::error::PERMISSION_DENIED, - absl::StrCat("invalid-keybox-version ", version)); + return Status(error::PERMISSION_DENIED, + absl::StrCat("invalid-keybox-version ", version)); } if (status.ok()) { if (cipher_out) { @@ -176,8 +175,8 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, // Return error from last attempt. return status; } - return util::Status( - util::error::NOT_FOUND, + return Status( + error::NOT_FOUND, absl::StrCat("Unknown system id: ", system_id).c_str()); // NOLINT } @@ -185,12 +184,13 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token, // 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. -util::Status WvmTokenHandler::GetEncryptedAssetKey( - absl::string_view token, absl::string_view raw_asset_key, - const std::string& make_model, std::string* result) { +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; - util::Status status = + Status status = DecryptDeviceKey(token, make_model, &device_key, &cipher, nullptr); if (!status.ok()) { return status; @@ -215,20 +215,19 @@ std::string WvmTokenHandler::GetEncryptedUniqueId(absl::string_view token) { return encrypted_unique_id; } -util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( +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); } -util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( +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 util::Status(util::error::INVALID_ARGUMENT, - "Keybox token is too short."); + return Status(error::INVALID_ARGUMENT, "Keybox token is too short."); } if (version) { *version = BigEndian::Load32(token.data()); @@ -243,7 +242,7 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( if (unique_id.size() != 16) { // Decrypting 16 bytes should result in 16 bytes. LOG(WARNING) << "Internal error decrypting unique id from token."; - return util::Status(util::error::INTERNAL, "Wrong size after decrypt/16."); + return Status(error::INTERNAL, "Wrong size after decrypt/16."); } absl::string_view encrypted_bits = token.substr(24, 48); @@ -252,7 +251,7 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( if (decrypted_bits.size() != 48) { // Decrypting 48 bytes should result in 48 bytes. LOG(WARNING) << "Internal error decrypting device key from token."; - return util::Status(util::error::INTERNAL, "Wrong size after decrypt/48."); + return Status(error::INTERNAL, "Wrong size after decrypt/48."); } uint8_t keybox_flags = decrypted_bits[36]; absl::string_view device_key = @@ -269,48 +268,43 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( keybox_flags = 0; } if (expected_hash != actual_hash) { - return util::Status(util::error::PERMISSION_DENIED, - "Keybox validation failed."); + 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 util::OkStatus(); + return OkStatus(); } -util::Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key, - absl::string_view raw_asset_key, - Cipher cipher, std::string* result) { +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 util::Status(util::error::INVALID_ARGUMENT, - "Invalid device key: size != 16"); + return Status(error::INVALID_ARGUMENT, "Invalid device key: size != 16"); } if (raw_asset_key.size() < 16) { - return util::Status(util::error::INVALID_ARGUMENT, - "Invalid 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 util::Status(util::error::INTERNAL, - "Error encrypting asset key with 3DES."); + return Status(error::INTERNAL, "Error encrypting asset key with 3DES."); } - return util::OkStatus(); + return OkStatus(); case AES: if (!crypto_util::EncryptAesEcb(device_key, asset_key, result)) { - return util::Status(util::error::INTERNAL, - "Error encrypting asset key with AES."); + return Status(error::INTERNAL, "Error encrypting asset key with AES."); } - return util::OkStatus(); + return OkStatus(); case PASS_THRU: result->assign(raw_asset_key.data(), raw_asset_key.size()); - return util::OkStatus(); + return OkStatus(); default: - return util::Status(util::error::INVALID_ARGUMENT, "Unknown cipher type"); + return Status(error::INVALID_ARGUMENT, "Unknown cipher type"); } } diff --git a/common/wvm_token_handler.h b/common/wvm_token_handler.h index 6fca42a..e300928 100644 --- a/common/wvm_token_handler.h +++ b/common/wvm_token_handler.h @@ -70,24 +70,23 @@ class WvmTokenHandler { // 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 util::Status DecryptDeviceKey(absl::string_view token, - std::string* device_key_out, - Cipher* cipher_out, bool* insecure_out); + 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 util::Status DecryptDeviceKey(absl::string_view token, - const std::string& make_model, - std::string* device_key_out, - Cipher* cipher_out, bool* insecure_out); + 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 util::Status GetEncryptedAssetKey(absl::string_view token, - absl::string_view raw_asset_key, - const std::string& make_model, - std::string* 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); @@ -101,21 +100,21 @@ class WvmTokenHandler { // 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 util::Status DecryptDeviceKeyWithPreprovKey( + 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 util::Status DecryptDeviceKeyWithPreprovKey( + 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 util::Status EncryptAssetKey(absl::string_view device_key, - absl::string_view raw_asset_key, - Cipher cipher, std::string* result); + static Status EncryptAssetKey(absl::string_view device_key, + absl::string_view raw_asset_key, Cipher cipher, + std::string* result); private: DISALLOW_IMPLICIT_CONSTRUCTORS(WvmTokenHandler); diff --git a/common/wvm_token_handler_test.cc b/common/wvm_token_handler_test.cc index 364d568..b3f0bf9 100644 --- a/common/wvm_token_handler_test.cc +++ b/common/wvm_token_handler_test.cc @@ -29,12 +29,6 @@ namespace widevine { using absl::BytesToHexString; using absl::HexStringToBytes; -// TODO(user): Add EXPECT_OK macro to testing/gmock.h. -// (b/37545268). -#define EXPECT_OK(expression) \ - EXPECT_EQ(util::error::OK, expression.error_code()) - - TEST(WvmTokenHandlerTest, GetSystemId) { EXPECT_EQ(kTestSystemId, WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken1Hex))); @@ -52,7 +46,7 @@ TEST(WvmTokenHandlerTest, GetEncryptedUniqueId) { } TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) { - util::Status status; + Status status; std::string device_key; status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( @@ -76,7 +70,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) { status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( HexStringToBytes(kTestPreprovKeyHex), token, &device_key); EXPECT_FALSE(status.ok()); - EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code()); + EXPECT_EQ(error::PERMISSION_DENIED, status.error_code()); EXPECT_TRUE(device_key.empty()); } @@ -86,18 +80,18 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) { TEST(WvmTokenHandlerTest, DecryptDeviceKey_PreprovKeysNullPtr) { // Not calling WvmTokenHandler::SetPreprovKeys() // So preprov_keys_ would be nullptr. - util::Status status; + Status status; std::string device_key; status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex), &device_key, nullptr, nullptr); EXPECT_FALSE(status.ok()); - EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code()); + 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) { - util::Status status; + Status status; std::string device_key; WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector()); @@ -120,7 +114,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKey) { status = WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr); EXPECT_FALSE(status.ok()); - EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code()); + EXPECT_EQ(error::PERMISSION_DENIED, status.error_code()); EXPECT_TRUE(device_key.empty()); // Test with nonexistent system id. Should produce NOT_FOUND. @@ -132,7 +126,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKey) { status = WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr); EXPECT_FALSE(status.ok()); - EXPECT_EQ(util::error::NOT_FOUND, status.error_code()); + EXPECT_EQ(error::NOT_FOUND, status.error_code()); EXPECT_TRUE(device_key.empty()); } @@ -142,7 +136,7 @@ TEST(WvmTokenHandlerTest, GetEncryptedAssetKey) { std::string raw_asset_key = "asset-key-000000"; std::string asset_key; std::string make_model; - util::Status status = WvmTokenHandler::GetEncryptedAssetKey( + Status status = WvmTokenHandler::GetEncryptedAssetKey( HexStringToBytes(kTestToken1Hex), raw_asset_key, make_model, &asset_key); EXPECT_OK(status); EXPECT_EQ("305d5f979074b1c4f932be70d3cc850c", BytesToHexString(asset_key)); @@ -194,7 +188,7 @@ TEST(WvmTokenHandlerTest, FilterOnMakeModel) { std::string raw_asset_key = "asset-key-000000"; std::string asset_key; // Check 3DES encryption of asset keys - util::Status status = WvmTokenHandler::EncryptAssetKey( + Status status = WvmTokenHandler::EncryptAssetKey( HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key, WvmTokenHandler::DES3, &asset_key); EXPECT_OK(status); @@ -220,7 +214,7 @@ TEST(WvmTokenHandlerTest, FilterOnMakeModel) { } TEST(WvmTokenHandlerTest, AncientKeybox) { - util::Status status; + Status status; std::string device_key; std::string v1_token( @@ -228,7 +222,7 @@ TEST(WvmTokenHandlerTest, AncientKeybox) { status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey( HexStringToBytes(v1_token), HexStringToBytes(kTestToken1Hex), &device_key); - EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code()); + EXPECT_EQ(error::PERMISSION_DENIED, status.error_code()); EXPECT_TRUE(device_key.empty()); } diff --git a/common/x509_cert.cc b/common/x509_cert.cc index aa95ff4..5699486 100644 --- a/common/x509_cert.cc +++ b/common/x509_cert.cc @@ -67,22 +67,20 @@ X509Cert::~X509Cert() { X509Cert::X509Cert(X509* openssl_cert) : openssl_cert_(openssl_cert) {} -util::Status X509Cert::LoadPem(const std::string& pem_cert) { +Status X509Cert::LoadPem(const std::string& pem_cert) { if (pem_cert.empty()) { - return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM certificate"); + 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 util::Status(util::error::INTERNAL, "BIO allocation failed"); + return Status(error::INTERNAL, "BIO allocation failed"); } - util::Status status; + Status status; new_cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); if (new_cert == NULL) { - status = util::Status(util::Status::canonical_space(), - util::error::INVALID_ARGUMENT, - "PEM certificate load failed"); + status = Status(error::INVALID_ARGUMENT, "PEM certificate load failed"); goto cleanup; } if (openssl_cert_ != NULL) { @@ -97,22 +95,21 @@ cleanup: return status; } -util::Status X509Cert::LoadDer(const std::string& der_cert) { +Status X509Cert::LoadDer(const std::string& der_cert) { if (der_cert.empty()) { - return util::Status(util::error::INVALID_ARGUMENT, "Empty DER certificate"); + 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 util::Status(util::error::INVALID_ARGUMENT, - "DER certificate load failed"); + return Status(error::INVALID_ARGUMENT, "DER certificate load failed"); } if (openssl_cert_ != NULL) { X509_free(openssl_cert_); } openssl_cert_ = new_cert; - return util::OkStatus(); + return OkStatus(); } std::string X509Cert::GetPem() const { @@ -222,38 +219,36 @@ bool X509Cert::GetV3BooleanExtension(const std::string& oid, bool* value) const return true; } -util::Status X509Cert::Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, - int64_t* epoch_seconds) const { +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 util::Status(util::error::INVALID_ARGUMENT, - "asn1_time cannot be null."); + return Status(error::INVALID_ARGUMENT, "asn1_time cannot be null."); } if (epoch_seconds == nullptr) { // NOLINTNEXTLINE - return util::Status(util::error::INVALID_ARGUMENT, - "epoch_seconds cannot be null."); + 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 util::Status(util::error::INTERNAL, "Failed to set epoch time."); + 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 util::Status(util::error::INTERNAL, - "Failed to convert asn1 time to epoch time."); + return Status(error::INTERNAL, + "Failed to convert asn1 time to epoch time."); } *epoch_seconds = 24L * 3600L * day + seconds; - return util::OkStatus(); + return OkStatus(); } X509CertChain::~X509CertChain() { Reset(); } @@ -265,7 +260,7 @@ void X509CertChain::Reset() { cert_chain_.clear(); } -util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) { +Status X509CertChain::LoadPem(const std::string& pem_cert_chain) { static const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----"; static const char kEndCertificate[] = "-----END CERTIFICATE-----"; @@ -277,7 +272,7 @@ util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) { if (end_pos != std::string::npos) { end_pos += sizeof(kEndCertificate) - 1; std::unique_ptr new_cert(new X509Cert); - util::Status status = new_cert->LoadPem( + Status status = new_cert->LoadPem( pem_cert_chain.substr(begin_pos, end_pos - begin_pos)); if (!status.ok()) { return status; @@ -286,17 +281,17 @@ util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) { begin_pos = pem_cert_chain.find(kBeginCertificate, end_pos); } } - return util::OkStatus(); + return OkStatus(); } -util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) { +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 util::Status(util::error::INVALID_ARGUMENT, - "Unable to load PKCS#7 certificate chain"); + return Status(error::INVALID_ARGUMENT, + "Unable to load PKCS#7 certificate chain"); } while (sk_X509_num(cert_stack.get()) > 0) { @@ -304,7 +299,7 @@ util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) { new X509Cert(sk_X509_pop(cert_stack.get()))); } - return util::OkStatus(); + return OkStatus(); } std::string X509CertChain::GetPkcs7() { @@ -357,44 +352,42 @@ X509CA::~X509CA() { } } -util::Status X509CA::InitializeStore() { +Status X509CA::InitializeStore() { absl::WriterMutexLock lock(&openssl_store_mutex_); if (openssl_store_ == NULL) { if (ca_cert_ == NULL) { - return util::Status(util::error::INTERNAL, "CA X.509Cert is NULL"); + return Status(error::INTERNAL, "CA X.509Cert is NULL"); } openssl_store_ = X509_STORE_new(); if (openssl_store_ == NULL) { - return util::Status(util::error::INTERNAL, - "Failed to allocate X.509 store"); + 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 util::Status(util::error::INTERNAL, - "Failed to add X.509 CA certificate to store"); + return Status(error::INTERNAL, + "Failed to add X.509 CA certificate to store"); } } - return util::OkStatus(); + return OkStatus(); } -util::Status X509CA::VerifyCert(const X509Cert& cert) { +Status X509CA::VerifyCert(const X509Cert& cert) { return OpenSslX509Verify(cert.openssl_cert(), nullptr); } -util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) { +Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) { if (cert_chain.GetNumCerts() < 1) { - return util::Status(util::error::INVALID_ARGUMENT, - "Cannot verify empty certificate chain"); + return Status(error::INVALID_ARGUMENT, + "Cannot verify empty certificate chain"); } ScopedX509StackOnly intermediates(sk_X509_new_null()); if (!intermediates) { - return util::Status( - util::Status::canonical_space(), util::error::INTERNAL, - "Failed to allocate X.509 intermediate certificate stack"); + 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) { @@ -406,23 +399,21 @@ util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) { } } if (!leaf_cert) { - return util::Status(util::Status::canonical_space(), - util::error::INVALID_ARGUMENT, - "X.509 certificate chain without leaf certificate."); + return Status(error::INVALID_ARGUMENT, + "X.509 certificate chain without leaf certificate."); } return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get()); } -util::Status X509CA::VerifyCertWithChain(const X509Cert& cert, - const X509CertChain& cert_chain) { +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 util::Status( - util::Status::canonical_space(), util::error::INTERNAL, - "Failed to allocate X.509 intermediate certificate stack"); + 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(), @@ -432,14 +423,14 @@ util::Status X509CA::VerifyCertWithChain(const X509Cert& cert, return OpenSslX509Verify(cert.openssl_cert(), intermediates.get()); } -util::Status X509CA::OpenSslX509Verify(const X509* cert, - STACK_OF(X509) * intermediates) { +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(); - util::Status status = InitializeStore(); + Status status = InitializeStore(); if (!status.ok()) { return status; } @@ -447,23 +438,21 @@ util::Status X509CA::OpenSslX509Verify(const X509* cert, } ScopedX509StoreCtx store_ctx(X509_STORE_CTX_new()); if (!store_ctx) { - return util::Status(util::Status::canonical_space(), util::error::INTERNAL, - "Failed to allocate X.509 store context"); + 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 util::Status(util::Status::canonical_space(), util::error::INTERNAL, - "Failed to initialize X.509 store context"); + 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 util::Status(util::Status::canonical_space(), util::error::INTERNAL, - std::string("X.509 certificate chain validation failed: ") + - X509_verify_cert_error_string( - X509_STORE_CTX_get_error(store_ctx.get()))); + 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 util::OkStatus(); + return OkStatus(); } } // namespace widevine diff --git a/common/x509_cert.h b/common/x509_cert.h index 2bb9bb3..d773cba 100644 --- a/common/x509_cert.h +++ b/common/x509_cert.h @@ -24,13 +24,13 @@ #include "openssl/pem.h" #include "openssl/x509.h" #include "openssl/x509v3.h" -#include "common/status.h" #include "common/openssl_util.h" #include "common/rsa_key.h" +#include "common/status.h" namespace widevine { -// NOTE: All util::Status codes are in the canonical error space. +// NOTE: All Status codes are in the canonical error space. // Class which holds a single X.509 certificates. class X509Cert { @@ -43,11 +43,11 @@ class X509Cert { // Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is // a PEM-encoded certificate. - util::Status LoadPem(const std::string& pem_cert); + Status LoadPem(const std::string& pem_cert); // Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is // a DER-encoded certificate. - util::Status LoadDer(const std::string& der_cert); + Status LoadDer(const std::string& der_cert); // Return a std::string containing the PEM-encoded certificate. std::string GetPem() const; @@ -91,8 +91,8 @@ class X509Cert { private: explicit X509Cert(X509* openssl_cert); - util::Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, - int64_t* epoch_seconds) const; + Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, + int64_t* epoch_seconds) const; X509* openssl_cert_; std::string subject_name_; @@ -112,12 +112,12 @@ class X509CertChain { // |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. - util::Status LoadPem(const std::string& pem_cert_chain); + 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. - util::Status LoadPkcs7(const std::string& pk7_cert_chain); + 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. @@ -148,21 +148,21 @@ class X509CA { // Does X.509 PKI validation of |cert| against the root CA certificate // used when constructing X509CA. This method is thread-safe. - util::Status VerifyCert(const X509Cert& cert); + 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. - util::Status VerifyCertChain(const X509CertChain& cert_chain); + 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. - util::Status VerifyCertWithChain(const X509Cert& cert, - const X509CertChain& cert_chain); + Status VerifyCertWithChain(const X509Cert& cert, + const X509CertChain& cert_chain); private: - util::Status InitializeStore(); - util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * stack); + Status InitializeStore(); + Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * intermediates); std::unique_ptr ca_cert_; absl::Mutex openssl_store_mutex_; diff --git a/common/x509_cert_test.cc b/common/x509_cert_test.cc index 85cdee2..efc9ee3 100644 --- a/common/x509_cert_test.cc +++ b/common/x509_cert_test.cc @@ -355,23 +355,23 @@ const bool kTestDevCodeSigningCertFlagValue = true; TEST(X509CertTest, LoadCert) { X509Cert test_cert; - EXPECT_EQ(util::OkStatus(), + EXPECT_EQ(OkStatus(), test_cert.LoadDer(absl::HexStringToBytes(kTestRootCaDerCert))); - EXPECT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert)); + EXPECT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); // TODO(user): Add more specific status checks to failure tests. - EXPECT_NE(util::OkStatus(), test_cert.LoadDer("bad cert")); - EXPECT_NE(util::OkStatus(), test_cert.LoadPem("bad cert")); - EXPECT_NE(util::OkStatus(), test_cert.LoadDer("")); - EXPECT_NE(util::OkStatus(), test_cert.LoadPem("")); + 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(util::OkStatus(), test_cert.LoadPem(kTestPemCert)); + ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); std::string message(absl::HexStringToBytes(kTestMessage)); std::string signature; - ASSERT_EQ(util::OkStatus(), GenerateRsaSignatureSha256Pkcs1( - kTestCertPrivateKey, message, &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)); @@ -384,7 +384,7 @@ TEST(X509CertTest, VerifySignature) { TEST(X509CertTest, GetSubjectNameField) { X509Cert test_cert; - ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert)); + 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")); @@ -392,13 +392,13 @@ TEST(X509CertTest, GetSubjectNameField) { TEST(X509CertTest, GetSerialNumber) { X509Cert test_cert; - ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert)); + ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); EXPECT_EQ(kTestPemCertSerialNumber, test_cert.GetSerialNumber()); } TEST(X509CertTest, GetNotBeforeSeconds) { X509Cert test_cert; - ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert)); + 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); @@ -406,7 +406,7 @@ TEST(X509CertTest, GetNotBeforeSeconds) { TEST(X509CertTest, GetNotAfterSeconds) { X509Cert test_cert; - ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert)); + 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); @@ -414,7 +414,7 @@ TEST(X509CertTest, GetNotAfterSeconds) { TEST(X509CertTest, CertChain) { X509CertChain test_chain; - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain)); + 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); @@ -423,7 +423,7 @@ TEST(X509CertTest, CertChain) { TEST(X509CertTest, IsCaCertificate) { X509CertChain test_chain; - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain)); + 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()); @@ -431,84 +431,84 @@ TEST(X509CertTest, IsCaCertificate) { TEST(X509CertTest, ChainVerificationPem) { std::unique_ptr ca_cert(new X509Cert); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert))); X509CA ca(ca_cert.release()); X509CertChain test_chain; - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert)); + 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(util::OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain)); + 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(util::OkStatus(), + ASSERT_EQ(OkStatus(), ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert))); X509CA ca(ca_cert.release()); X509CertChain test_chain; - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), test_chain.LoadPkcs7(absl::HexStringToBytes(kTestPk7CertChain))); - EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert)); + EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain)); + ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert)); ASSERT_EQ(1, test_chain.GetNumCerts()); - EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain)); - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain)); - EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain)); + 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(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); + ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); X509CA ca(ca_cert.release()); // Verify the ICA with the root succeeds. X509CertChain test_chain; - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert)); + ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert)); ASSERT_EQ(1, test_chain.GetNumCerts()); X509Cert ica_cert; - ASSERT_EQ(util::OkStatus(), ica_cert.LoadPem(kTestPemIca)); - EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain)); + 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(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); + 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(util::OkStatus(), test_chain.LoadPem(kTestPemIca)); + ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemIca)); ASSERT_EQ(1, test_chain.GetNumCerts()); X509Cert leaf_cert; - ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert)); - EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain)); + 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(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert)); + 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(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert)); + ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert)); ASSERT_EQ(1, test_chain.GetNumCerts()); X509Cert leaf_cert; - ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert)); - EXPECT_NE(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain)); + ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert)); + EXPECT_NE(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain)); } TEST(X509CertTest, GetPkcs7) { X509CertChain test_chain; - ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain)); + 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(util::OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate)); + 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(), @@ -518,12 +518,12 @@ TEST(X509CertTest, GetPkcs7) { TEST(X509CertTest, BooleanExtension) { std::unique_ptr cert1(new X509Cert); - ASSERT_EQ(util::OkStatus(), cert1->LoadPem(kTestPemCert)); + ASSERT_EQ(OkStatus(), cert1->LoadPem(kTestPemCert)); bool extension_value; EXPECT_FALSE(cert1->GetV3BooleanExtension(kDevCertFlagOid, &extension_value)); std::unique_ptr cert2(new X509Cert); - ASSERT_EQ(util::OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert)); + ASSERT_EQ(OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert)); ASSERT_TRUE(cert2->GetV3BooleanExtension(kDevCertFlagOid, &extension_value)); EXPECT_EQ(kTestDevCodeSigningCertFlagValue, extension_value); } diff --git a/curl.BUILD b/curl.BUILD deleted file mode 100644 index 3c912a3..0000000 --- a/curl.BUILD +++ /dev/null @@ -1,584 +0,0 @@ -################################################################################ -# Copyright 2018 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. -################################################################################ - -# Build file for curl. - -exports_files(["COPYING"]) - -cc_library( - name = "curl", - srcs = [ - "include/curl_config.h", # generated by genrule below - "lib/amigaos.c", - "lib/amigaos.h", - "lib/arpa_telnet.h", - "lib/asyn-ares.c", - "lib/asyn-thread.c", - "lib/asyn.h", - "lib/base64.c", - "lib/config-amigaos.h", - "lib/config-dos.h", - "lib/config-mac.h", - "lib/config-os400.h", - "lib/config-riscos.h", - "lib/config-symbian.h", - "lib/config-tpf.h", - "lib/config-vxworks.h", - "lib/config-win32.h", - "lib/config-win32ce.h", - "lib/conncache.c", - "lib/conncache.h", - "lib/connect.c", - "lib/connect.h", - "lib/content_encoding.c", - "lib/content_encoding.h", - "lib/cookie.c", - "lib/cookie.h", - "lib/curl_addrinfo.c", - "lib/curl_addrinfo.h", - "lib/curl_base64.h", - "lib/curl_ctype.c", - "lib/curl_ctype.h", - "lib/curl_des.c", - "lib/curl_des.h", - "lib/curl_endian.c", - "lib/curl_endian.h", - "lib/curl_fnmatch.c", - "lib/curl_fnmatch.h", - "lib/curl_gethostname.c", - "lib/curl_gethostname.h", - "lib/curl_gssapi.c", - "lib/curl_gssapi.h", - "lib/curl_hmac.h", - "lib/curl_ldap.h", - "lib/curl_md4.h", - "lib/curl_md5.h", - "lib/curl_memory.h", - "lib/curl_memrchr.c", - "lib/curl_memrchr.h", - "lib/curl_multibyte.c", - "lib/curl_multibyte.h", - "lib/curl_ntlm_core.c", - "lib/curl_ntlm_core.h", - "lib/curl_ntlm_wb.c", - "lib/curl_ntlm_wb.h", - "lib/curl_path.c", - "lib/curl_path.h", - "lib/curl_printf.h", - "lib/curl_range.c", - "lib/curl_range.h", - "lib/curl_rtmp.c", - "lib/curl_rtmp.h", - "lib/curl_sasl.c", - "lib/curl_sasl.h", - "lib/curl_sec.h", - "lib/curl_setup.h", - "lib/curl_setup_once.h", - "lib/curl_sha256.h", - "lib/curl_sspi.c", - "lib/curl_sspi.h", - "lib/curl_threads.c", - "lib/curl_threads.h", - "lib/curlx.h", - "lib/dict.c", - "lib/dict.h", - "lib/doh.c", - "lib/doh.h", - "lib/dotdot.c", - "lib/dotdot.h", - "lib/easy.c", - "lib/easyif.h", - "lib/escape.c", - "lib/escape.h", - "lib/file.c", - "lib/file.h", - "lib/fileinfo.c", - "lib/fileinfo.h", - "lib/formdata.c", - "lib/formdata.h", - "lib/ftp.c", - "lib/ftp.h", - "lib/ftplistparser.c", - "lib/ftplistparser.h", - "lib/getenv.c", - "lib/getinfo.c", - "lib/getinfo.h", - "lib/gopher.c", - "lib/gopher.h", - "lib/hash.c", - "lib/hash.h", - "lib/hmac.c", - "lib/hostasyn.c", - "lib/hostcheck.c", - "lib/hostcheck.h", - "lib/hostip.c", - "lib/hostip.h", - "lib/hostip4.c", - "lib/hostip6.c", - "lib/hostsyn.c", - "lib/http.c", - "lib/http.h", - "lib/http2.c", - "lib/http2.h", - "lib/http_chunks.c", - "lib/http_chunks.h", - "lib/http_digest.c", - "lib/http_digest.h", - "lib/http_negotiate.c", - "lib/http_negotiate.h", - "lib/http_ntlm.c", - "lib/http_ntlm.h", - "lib/http_proxy.c", - "lib/http_proxy.h", - "lib/idn_win32.c", - "lib/if2ip.c", - "lib/if2ip.h", - "lib/imap.c", - "lib/imap.h", - "lib/inet_ntop.c", - "lib/inet_ntop.h", - "lib/inet_pton.c", - "lib/inet_pton.h", - "lib/krb5.c", - "lib/ldap.c", - "lib/llist.c", - "lib/llist.h", - "lib/md4.c", - "lib/md5.c", - "lib/memdebug.c", - "lib/memdebug.h", - "lib/mime.c", - "lib/mime.h", - "lib/mprintf.c", - "lib/multi.c", - "lib/multihandle.h", - "lib/multiif.h", - "lib/netrc.c", - "lib/netrc.h", - "lib/non-ascii.c", - "lib/non-ascii.h", - "lib/nonblock.c", - "lib/nonblock.h", - "lib/nwlib.c", - "lib/nwos.c", - "lib/openldap.c", - "lib/parsedate.c", - "lib/parsedate.h", - "lib/pingpong.c", - "lib/pingpong.h", - "lib/pipeline.c", - "lib/pipeline.h", - "lib/pop3.c", - "lib/pop3.h", - "lib/progress.c", - "lib/progress.h", - "lib/psl.c", - "lib/psl.h", - "lib/rand.c", - "lib/rand.h", - "lib/rtsp.c", - "lib/rtsp.h", - "lib/security.c", - "lib/select.c", - "lib/select.h", - "lib/sendf.c", - "lib/sendf.h", - "lib/setopt.c", - "lib/setopt.h", - "lib/setup-os400.h", - "lib/setup-vms.h", - "lib/sha256.c", - "lib/share.c", - "lib/share.h", - "lib/sigpipe.h", - "lib/slist.c", - "lib/slist.h", - "lib/smb.c", - "lib/smb.h", - "lib/smtp.c", - "lib/smtp.h", - "lib/sockaddr.h", - "lib/socks.c", - "lib/socks.h", - "lib/socks_gssapi.c", - "lib/socks_sspi.c", - "lib/speedcheck.c", - "lib/speedcheck.h", - "lib/splay.c", - "lib/splay.h", - "lib/ssh-libssh.c", - "lib/ssh.c", - "lib/ssh.h", - "lib/strcase.c", - "lib/strcase.h", - "lib/strdup.c", - "lib/strdup.h", - "lib/strerror.c", - "lib/strerror.h", - "lib/strtok.c", - "lib/strtok.h", - "lib/strtoofft.c", - "lib/strtoofft.h", - "lib/system_win32.c", - "lib/system_win32.h", - "lib/telnet.c", - "lib/telnet.h", - "lib/tftp.c", - "lib/tftp.h", - "lib/timeval.c", - "lib/timeval.h", - "lib/transfer.c", - "lib/transfer.h", - "lib/url.c", - "lib/url.h", - "lib/urlapi-int.h", - "lib/urlapi.c", - "lib/urldata.h", - "lib/vauth/cleartext.c", - "lib/vauth/cram.c", - "lib/vauth/digest.c", - "lib/vauth/digest.h", - "lib/vauth/digest_sspi.c", - "lib/vauth/krb5_gssapi.c", - "lib/vauth/krb5_sspi.c", - "lib/vauth/ntlm.c", - "lib/vauth/ntlm.h", - "lib/vauth/ntlm_sspi.c", - "lib/vauth/oauth2.c", - "lib/vauth/spnego_gssapi.c", - "lib/vauth/spnego_sspi.c", - "lib/vauth/vauth.c", - "lib/vauth/vauth.h", - "lib/version.c", - "lib/vtls/cyassl.c", - "lib/vtls/cyassl.h", - "lib/vtls/darwinssl.c", - "lib/vtls/darwinssl.h", - "lib/vtls/gskit.c", - "lib/vtls/gskit.h", - "lib/vtls/gtls.c", - "lib/vtls/gtls.h", - "lib/vtls/mbedtls.c", - "lib/vtls/mbedtls.h", - "lib/vtls/mesalink.c", - "lib/vtls/mesalink.h", - "lib/vtls/nss.c", - "lib/vtls/nssg.h", - "lib/vtls/openssl.c", - "lib/vtls/openssl.h", - "lib/vtls/polarssl.c", - "lib/vtls/polarssl.h", - "lib/vtls/polarssl_threadlock.c", - "lib/vtls/polarssl_threadlock.h", - "lib/vtls/schannel.c", - "lib/vtls/schannel.h", - "lib/vtls/schannel_verify.c", - "lib/vtls/vtls.c", - "lib/vtls/vtls.h", - "lib/warnless.c", - "lib/warnless.h", - "lib/wildcard.c", - "lib/wildcard.h", - "lib/x509asn1.c", - "lib/x509asn1.h", - ], - hdrs = [ - "include/curl/curl.h", - "include/curl/curlver.h", - "include/curl/easy.h", - "include/curl/mprintf.h", - "include/curl/multi.h", - "include/curl/stdcheaders.h", - "include/curl/system.h", - "include/curl/typecheck-gcc.h", - "include/curl/urlapi.h", - ], - copts = [ - "-Iexternal/curl/lib", - "-D_GNU_SOURCE", - "-DHAVE_CONFIG_H", - "-DCURL_DISABLE_FTP", - "-DCURL_DISABLE_NTLM", # turning it off in configure is not enough - "-DHAVE_LIBZ", - "-DHAVE_ZLIB_H", - "-Wno-std::string-plus-int", - "-DCURL_MAX_WRITE_SIZE=65536", - # dealing with conflicting types when building - "-DBUILDING_LIBCURL", - ], - includes = [ - "include", - # lib/curl_setup.h is included by many .c files under lib/ - "lib" - ], - linkopts = [ - "-lrt", - ], - visibility = ["//visibility:public"], - deps = [ - "@zlib_repo//:zlib", - "@boringssl_repo//:ssl", - ], -) - -genrule( - name = "configure", - outs = ["include/curl_config.h"], - cmd = "\n".join([ - "cat <<'EOF' >$@", - "#ifndef EXTERNAL_CURL_INCLUDE_CURL_CONFIG_H_", - "#define EXTERNAL_CURL_INCLUDE_CURL_CONFIG_H_", - "", - "#if !defined(_WIN32) && !defined(__APPLE__)", - "# include ", - "# if defined(OPENSSL_IS_BORINGSSL)", - "# define HAVE_BORINGSSL 1", - "# endif", - "#endif", - "", - "#if defined(_WIN32)", - "# include \"lib/config-win32.h\"", - "# define BUILDING_LIBCURL 1", - "# define CURL_DISABLE_CRYPTO_AUTH 1", - "# define CURL_DISABLE_IMAP 1", - "# define CURL_DISABLE_LDAP 1", - "# define CURL_DISABLE_LDAPS 1", - "# define CURL_DISABLE_POP3 1", - "# define CURL_PULL_WS2TCPIP_H 1", - "# define HTTP_ONLY 1", - "#elif defined(__APPLE__)", - "# define HAVE_FSETXATTR_6 1", - "# define HAVE_SETMODE 1", - "# define HAVE_SYS_FILIO_H 1", - "# define HAVE_SYS_SOCKIO_H 1", - "# define OS \"x86_64-apple-darwin15.5.0\"", - "# define USE_DARWINSSL 1", - "#else", - "# define CURL_CA_BUNDLE \"/etc/ssl/certs/ca-certificates.crt\"", - "# define GETSERVBYPORT_R_ARGS 6", - "# define GETSERVBYPORT_R_BUFSIZE 4096", - "# define HAVE_BORINGSSL 1", - "# define HAVE_CLOCK_GETTIME_MONOTONIC 1", - "# define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1", - "# define HAVE_FSETXATTR_5 1", - "# define HAVE_GETHOSTBYADDR_R 1", - "# define HAVE_GETHOSTBYADDR_R_8 1", - "# define HAVE_GETHOSTBYNAME_R 1", - "# define HAVE_GETHOSTBYNAME_R_6 1", - "# define HAVE_GETSERVBYPORT_R 1", - "# define HAVE_LIBSSL 1", - "# define HAVE_MALLOC_H 1", - "# define HAVE_MSG_NOSIGNAL 1", - "# define HAVE_OPENSSL_CRYPTO_H 1", - "# define HAVE_OPENSSL_ERR_H 1", - "# define HAVE_OPENSSL_PEM_H 1", - "# define HAVE_OPENSSL_PKCS12_H 1", - "# define HAVE_OPENSSL_RSA_H 1", - "# define HAVE_OPENSSL_SSL_H 1", - "# define HAVE_OPENSSL_X509_H 1", - "# define HAVE_RAND_EGD 1", - "# define HAVE_RAND_STATUS 1", - "# define HAVE_SSL_GET_SHUTDOWN 1", - "# define HAVE_STROPTS_H 1", - "# define HAVE_TERMIOS_H 1", - "# define OS \"x86_64-pc-linux-gnu\"", - "# define RANDOM_FILE \"/dev/urandom\"", - "# define USE_OPENSSL 1", - "#endif", - "", - "#if !defined(_WIN32)", - "# define CURL_DISABLE_DICT 1", - "# define CURL_DISABLE_FILE 1", - "# define CURL_DISABLE_GOPHER 1", - "# define CURL_DISABLE_IMAP 1", - "# define CURL_DISABLE_LDAP 1", - "# define CURL_DISABLE_LDAPS 1", - "# define CURL_DISABLE_POP3 1", - "# define CURL_DISABLE_SMTP 1", - "# define CURL_DISABLE_TELNET 1", - "# define CURL_DISABLE_TFTP 1", - "# define CURL_EXTERN_SYMBOL __attribute__ ((__visibility__ (\"default\")))", - "# define ENABLE_IPV6 1", - "# define GETHOSTNAME_TYPE_ARG2 size_t", - "# define GETNAMEINFO_QUAL_ARG1 const", - "# define GETNAMEINFO_TYPE_ARG1 struct sockaddr *", - "# define GETNAMEINFO_TYPE_ARG2 socklen_t", - "# define GETNAMEINFO_TYPE_ARG46 socklen_t", - "# define GETNAMEINFO_TYPE_ARG7 int", - "# define HAVE_ALARM 1", - "# define HAVE_ALLOCA_H 1", - "# define HAVE_ARPA_INET_H 1", - "# define HAVE_ARPA_TFTP_H 1", - "# define HAVE_ASSERT_H 1", - "# define HAVE_BASENAME 1", - "# define HAVE_BOOL_T 1", - "# define HAVE_CONNECT 1", - "# define HAVE_DLFCN_H 1", - "# define HAVE_ERRNO_H 1", - "# define HAVE_FCNTL 1", - "# define HAVE_FCNTL_H 1", - "# define HAVE_FCNTL_O_NONBLOCK 1", - "# define HAVE_FDOPEN 1", - "# define HAVE_FORK 1", - "# define HAVE_FREEADDRINFO 1", - "# define HAVE_FREEIFADDRS 1", - "# if !defined(__ANDROID__)", - "# define HAVE_FSETXATTR 1", - "# endif", - "# define HAVE_FTRUNCATE 1", - "# define HAVE_GAI_STRERROR 1", - "# define HAVE_GETADDRINFO 1", - "# define HAVE_GETADDRINFO_THREADSAFE 1", - "# define HAVE_GETEUID 1", - "# define HAVE_GETHOSTBYADDR 1", - "# define HAVE_GETHOSTBYNAME 1", - "# define HAVE_GETHOSTNAME 1", - "# if !defined(__ANDROID__)", - "# define HAVE_GETIFADDRS 1", - "# endif", - "# define HAVE_GETNAMEINFO 1", - "# define HAVE_GETPPID 1", - "# define HAVE_GETPROTOBYNAME 1", - "# define HAVE_GETPWUID 1", - "# if !defined(__ANDROID__)", - "# define HAVE_GETPWUID_R 1", - "# endif", - "# define HAVE_GETRLIMIT 1", - "# define HAVE_GETTIMEOFDAY 1", - "# define HAVE_GMTIME_R 1", - "# if !defined(__ANDROID__)", - "# define HAVE_IFADDRS_H 1", - "# endif", - "# define HAVE_IF_NAMETOINDEX 1", - "# define HAVE_INET_ADDR 1", - "# define HAVE_INET_NTOP 1", - "# define HAVE_INET_PTON 1", - "# define HAVE_INTTYPES_H 1", - "# define HAVE_IOCTL 1", - "# define HAVE_IOCTL_FIONBIO 1", - "# define HAVE_IOCTL_SIOCGIFADDR 1", - "# define HAVE_LIBGEN_H 1", - "# define HAVE_LIBZ 1", - "# define HAVE_LIMITS_H 1", - "# define HAVE_LL 1", - "# define HAVE_LOCALE_H 1", - "# define HAVE_LOCALTIME_R 1", - "# define HAVE_LONGLONG 1", - "# define HAVE_MEMORY_H 1", - "# define HAVE_NETDB_H 1", - "# define HAVE_NETINET_IN_H 1", - "# define HAVE_NETINET_TCP_H 1", - "# define HAVE_NET_IF_H 1", - "# define HAVE_PERROR 1", - "# define HAVE_PIPE 1", - "# define HAVE_POLL 1", - "# define HAVE_POLL_FINE 1", - "# define HAVE_POLL_H 1", - "# define HAVE_POSIX_STRERROR_R 1", - "# define HAVE_PWD_H 1", - "# define HAVE_RECV 1", - "# define HAVE_SELECT 1", - "# define HAVE_SEND 1", - "# define HAVE_SETJMP_H 1", - "# define HAVE_SETLOCALE 1", - "# define HAVE_SETRLIMIT 1", - "# define HAVE_SETSOCKOPT 1", - "# define HAVE_SGTTY_H 1", - "# define HAVE_SIGACTION 1", - "# define HAVE_SIGINTERRUPT 1", - "# define HAVE_SIGNAL 1", - "# define HAVE_SIGNAL_H 1", - "# define HAVE_SIGSETJMP 1", - "# define HAVE_SIG_ATOMIC_T 1", - "# define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1", - "# define HAVE_SOCKET 1", - "# define HAVE_SOCKETPAIR 1", - "# define HAVE_STDBOOL_H 1", - "# define HAVE_STDINT_H 1", - "# define HAVE_STDIO_H 1", - "# define HAVE_STDLIB_H 1", - "# define HAVE_STRCASECMP 1", - "# define HAVE_STRDUP 1", - "# define HAVE_STRERROR_R 1", - "# define HAVE_STRINGS_H 1", - "# define HAVE_STRING_H 1", - "# define HAVE_STRNCASECMP 1", - "# define HAVE_STRSTR 1", - "# define HAVE_STRTOK_R 1", - "# define HAVE_STRTOLL 1", - "# define HAVE_STRUCT_SOCKADDR_STORAGE 1", - "# define HAVE_STRUCT_TIMEVAL 1", - "# define HAVE_SYS_IOCTL_H 1", - "# define HAVE_SYS_PARAM_H 1", - "# define HAVE_SYS_POLL_H 1", - "# define HAVE_SYS_RESOURCE_H 1", - "# define HAVE_SYS_SELECT_H 1", - "# define HAVE_SYS_SOCKET_H 1", - "# define HAVE_SYS_STAT_H 1", - "# define HAVE_SYS_TIME_H 1", - "# define HAVE_SYS_TYPES_H 1", - "# define HAVE_SYS_UIO_H 1", - "# define HAVE_SYS_UN_H 1", - "# define HAVE_SYS_WAIT_H 1", - "# define HAVE_SYS_XATTR_H 1", - "# define HAVE_TIME_H 1", - "# define HAVE_UNAME 1", - "# define HAVE_UNISTD_H 1", - "# define HAVE_UTIME 1", - "# define HAVE_UTIME_H 1", - "# define HAVE_VARIADIC_MACROS_C99 1", - "# define HAVE_VARIADIC_MACROS_GCC 1", - "# define HAVE_WRITABLE_ARGV 1", - "# define HAVE_WRITEV 1", - "# define HAVE_ZLIB_H 1", - "# define LT_OBJDIR \".libs/\"", - "# define PACKAGE \"curl\"", - "# define PACKAGE_BUGREPORT \"a suitable curl mailing list: https://curl.haxx.se/mail/\"", - "# define PACKAGE_NAME \"curl\"", - "# define PACKAGE_STRING \"curl -\"", - "# define PACKAGE_TARNAME \"curl\"", - "# define PACKAGE_URL \"\"", - "# define PACKAGE_VERSION \"-\"", - "# define RECV_TYPE_ARG1 int", - "# define RECV_TYPE_ARG2 void *", - "# define RECV_TYPE_ARG3 size_t", - "# define RECV_TYPE_ARG4 int", - "# define RECV_TYPE_RETV ssize_t", - "# define RETSIGTYPE void", - "# define SELECT_QUAL_ARG5", - "# define SELECT_TYPE_ARG1 int", - "# define SELECT_TYPE_ARG234 fd_set *", - "# define SELECT_TYPE_ARG5 struct timeval *", - "# define SELECT_TYPE_RETV int", - "# define SEND_QUAL_ARG2 const", - "# define SEND_TYPE_ARG1 int", - "# define SEND_TYPE_ARG2 void *", - "# define SEND_TYPE_ARG3 size_t", - "# define SEND_TYPE_ARG4 int", - "# define SEND_TYPE_RETV ssize_t", - "# define SIZEOF_INT 4", - "# define SIZEOF_LONG 8", - "# define SIZEOF_OFF_T 8", - "# define SIZEOF_SHORT 2", - "# define SIZEOF_SIZE_T 8", - "# define SIZEOF_TIME_T 8", - "# define SIZEOF_VOIDP 8", - "# define SIZEOF_CURL_OFF_T 8", - "# define STDC_HEADERS 1", - "# define STRERROR_R_TYPE_ARG3 size_t", - "# define TIME_WITH_SYS_TIME 1", - "# define VERSION \"-\"", - "# ifndef _DARWIN_USE_64_BIT_INODE", - "# define _DARWIN_USE_64_BIT_INODE 1", - "# endif", - "#endif", - "", - "#endif // EXTERNAL_CURL_INCLUDE_CURL_CONFIG_H_", - "EOF", - ]), -) diff --git a/example/BUILD b/example/BUILD index b3938aa..23cae36 100644 --- a/example/BUILD +++ b/example/BUILD @@ -16,6 +16,7 @@ package( filegroup( name = "binary_release_files", srcs = [ + "test_ecmg_messages.h", "wv_cas_ecm_example.cc", ":wv_cas_ecm_example", ], @@ -26,20 +27,9 @@ cc_library( hdrs = ["constants.h"], ) -cc_binary( - name = "simulcrypt_client", - srcs = ["simulcrypt_client.cc"], - deps = [ - "//base", - ], -) - cc_library( - name = "test_simulcrypt_messages", - hdrs = ["test_simulcrypt_messages.h"], - deps = [ - "//base", - ], + name = "test_ecmg_messages", + hdrs = ["test_ecmg_messages.h"], ) cc_binary( @@ -57,7 +47,7 @@ cc_binary( srcs = ["wv_cas_key_fetcher_example.cc"], deps = [ "//base", - "//util:status", + "//common:status", "//media_cas_packager_sdk/public:wv_cas_key_fetcher", "//protos/public:media_cas_encryption_proto", ], diff --git a/example/simulcrypt_client.cc b/example/simulcrypt_client.cc deleted file mode 100644 index 1df3822..0000000 --- a/example/simulcrypt_client.cc +++ /dev/null @@ -1,80 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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 client for demonstrating network calls to public/simulcrypt_server. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gflags/gflags.h" -#include "glog/logging.h" - -DEFINE_string(server, "", "Server host name"); -DEFINE_int32(port, 0, "Server port number"); - -constexpr uint32_t kBufferSize = 256; - -int main(int argc, char **argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - CHECK(!FLAGS_server.empty()) << "need --server"; - CHECK(FLAGS_port != 0) << "need --port"; - - struct hostent server; - { - int buflen = 1024; - char buf[1024]; - struct hostent *result; - int h_errnop; - gethostbyname_r(/* __name= */ FLAGS_server.c_str(), - /* __result_buf= */ &server, /* __buf= */ buf, - /* __buflen= */ buflen, - /* __result= */ &result, /* __h_errnop= */ &h_errnop); - } - - struct sockaddr_in server_addr; - bzero(reinterpret_cast(&server_addr), sizeof(server_addr)); - server_addr.sin_family = AF_INET; - // TODO(user): Consider using inet_pton() to populate server_addr.sin_addr. - bcopy(server.h_addr, reinterpret_cast(&server_addr.sin_addr.s_addr), - server.h_length); - server_addr.sin_port = htons(FLAGS_port); - - int socket_fd = socket(AF_INET, SOCK_STREAM, /* protocol= */ 0); - CHECK(socket_fd >= 0) << "failed to opening socket"; - CHECK(connect(socket_fd, (struct sockaddr *)&server_addr, - sizeof(server_addr)) >= 0) - << "failed to connect to socket"; - - printf("Please enter the message: "); - char buffer[kBufferSize]; - bzero(buffer, kBufferSize); - fgets(buffer, kBufferSize - 1, stdin); - int total_bytes_written = 0; - while (total_bytes_written != strlen(buffer)) { - int num_bytes_written = write(socket_fd, buffer, strlen(buffer)); - if (num_bytes_written < 0) { - LOG(FATAL) << "ERROR writing to socket: " << strerror(errno); - } - total_bytes_written += num_bytes_written; - } - bzero(buffer, kBufferSize); - if (read(socket_fd, buffer, kBufferSize - 1) < 0) { - LOG(FATAL) << "ERROR reading from socket: " << strerror(errno); - } - printf("Read from buffer: %s\n", buffer); - - close(socket_fd); - return 0; -} diff --git a/example/test_ecmg_messages.h b/example/test_ecmg_messages.h new file mode 100644 index 0000000..36e4a77 --- /dev/null +++ b/example/test_ecmg_messages.h @@ -0,0 +1,203 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2018 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 ECMG messages used in unit tests and example client. + +#ifndef MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_ECMG_MESSAGES_H_ +#define MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_ECMG_MESSAGES_H_ + +namespace widevine { +namespace cas { + +const char kTestChannelSetup[] = { + '\x03', // protocol_version + '\x00', '\x01', // message_type - Channel_setup + '\x00', '\x0e', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x01', // parameter_type- SUPER_CAS_ID + '\x00', '\x04', // parameter_length + '\x4a', '\xd4', '\x00', '\x00' // parameter_value +}; + +const char kTestChannelStatus[] = { + '\x03', // protocol_version + '\x00', '\x03', // message_type - Channel_status + '\x00', '\x39', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x02', // parameter_type - setion_TSpkt_flag + '\x00', '\x01', // parameter_length + '\x01', // parameter_value + '\x00', '\x03', // parameter_type - delay_start + '\x00', '\x02', // parameter_length + '\x00', '\xc8', // parameter_value + '\x00', '\x04', // parameter_type - delay_stop + '\x00', '\x02', // parameter_length + '\x00', '\xc8', // parameter_value + '\x00', '\x07', // parameter_type - ECM_rep_period + '\x00', '\x02', // parameter_length + '\x00', '\x64', // parameter_value + '\x00', '\x08', // parameter_type - max_streams + '\x00', '\x02', // parameter_length + '\x00', '\x00', // parameter_value + '\x00', '\x09', // parameter_type - min_CP_duration + '\x00', '\x02', // parameter_length + '\x00', '\x64', // parameter_value + '\x00', '\x0a', // parameter_type - lead_CW + '\x00', '\x01', // parameter_value + '\x01', // parameter_value + '\x00', '\x0b', // parameter_type - CW_per_msg + '\x00', '\x01', // parameter_length + '\x02', // parameter_value + '\x00', '\x0c', // parameter_type - max_comp_time + '\x00', '\x02', // parameter_length + '\x00', '\x64' // parameter_value +}; + +const char kTestStreamSetup[] = { + '\x03', // protocol_version + '\x01', '\x01', // message_type - Stream_setup + '\x00', '\x18', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x19', // parameter_type - ECM_id + '\x00', '\x02', // parameter_length + '\x00', '\x02', // parameter_value + '\x00', '\x10', // parameter_type - nominal_CP_duration + '\x00', '\x02', // parameter_length + '\x00', '\x64' // parameter_value +}; + +const char kTestStreamStatus[] = { + '\x03', // protocol_version + '\x01', '\x03', // message_type - Stream_status + '\x00', '\x17', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x19', // parameter_type - ECM_id + '\x00', '\x02', // parameter_length + '\x00', '\x02', // parameter_value + '\x00', '\x11', // parameter_type - access_criteria_transfer_mode + '\x00', '\x01', // parameter_length + '\x01' // parameter_value +}; + +const char kTestCwProvision[] = { + '\x03', // protocol_version + '\x02', '\x01', // message_type - CW_provision + '\x00', '\x44', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x12', // parameter_type - CP_number + '\x00', '\x02', // parameter_length + '\x00', '\x00', // parameter_value + '\x00', '\x13', // parameter_type - CP_duration + '\x00', '\x02', // parameter_length + '\x00', '\x64', // parameter_value + '\x00', '\x14', // parameter_type - CP_CW_Combination + '\x00', '\x12', // parameter_length + '\x00', '\x00', // parameter_value - CP (2 bytes) then CW next (16 bytes) + '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', + '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f', + '\x00', '\x14', // parameter_type - CP_CW_Combination + '\x00', '\x12', // parameter_length + '\x00', '\x01', // parameter_value - CP (2 bytes) then CW next (16 bytes) + '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', + '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'}; + +// CW is encrypted using hardcoded fixed entitlement key. +const char kTestEcmResponse[] = { + '\x03', // protocol_version + '\x02', '\x02', // message_type - ECM_response + '\x00', '\xd2', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x12', // parameter_type - CP_number + '\x00', '\x02', // parameter_length + '\x00', '\x00', // parameter_value + '\x00', '\x15', // parameter_type - ECM_datagram + '\x00', '\xbc', // parameter_length + // parameter_value - ECM_datagram + '\x47', '\x40', '\x02', '\x10', '\x00', '\x80', '\x70', '\x95', '\x4a', + '\xd4', '\x01', '\x05', '\x80', '\x66', '\x61', '\x6b', '\x65', '\x5f', + '\x6b', '\x65', '\x79', '\x5f', '\x69', '\x64', '\x31', '\x2e', '\x2e', + '\x2e', '\x2e', '\xef', '\x40', '\x57', '\x48', '\xa7', '\xad', '\xdd', + '\x34', '\x73', '\xfe', '\x5d', '\x1c', '\x65', '\xa0', '\xbf', '\x93', + '\xfe', '\x01', '\x4b', '\x1d', '\xcd', '\x9e', '\x1d', '\x3a', '\x36', + '\x99', '\x8f', '\x47', '\xa1', '\x3b', '\x46', '\xf1', '\xde', '\x9e', + '\xc2', '\x88', '\xf8', '\x27', '\x2f', '\xea', '\xa1', '\x63', '\x9b', + '\x1b', '\x6a', '\x56', '\x2d', '\x26', '\x31', '\x32', '\x33', '\x34', + '\x35', '\x36', '\x37', '\x38', '\x66', '\x61', '\x6b', '\x65', '\x5f', + '\x6b', '\x65', '\x79', '\x5f', '\x69', '\x64', '\x32', '\x2e', '\x2e', + '\x2e', '\x2e', '\xf4', '\x71', '\x2a', '\x4b', '\x6d', '\x6d', '\x14', + '\x4d', '\x2e', '\x53', '\xe7', '\x4b', '\x9f', '\x4b', '\x0a', '\x34', + '\xb4', '\xfd', '\xbe', '\x86', '\x21', '\x35', '\x1e', '\xda', '\x81', + '\x89', '\x6f', '\x70', '\xd3', '\xd2', '\xb2', '\x79', '\xf2', '\xcd', + '\xeb', '\xc5', '\xaf', '\x89', '\xab', '\xeb', '\xf0', '\x1b', '\xd0', + '\xd3', '\xe9', '\x7d', '\x81', '\x8a', '\x31', '\x32', '\x33', '\x34', + '\x35', '\x36', '\x37', '\x38', '\xff', '\xff', '\xff', '\xff', '\xff', + '\xff', '\xff', '\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 kTestStreamCloseRequest[] = { + '\x03', // protocol_version + '\x01', '\x04', // message_type - Stream_close_request + '\x00', '\x0c', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01' // parameter_value +}; + +const char kTestStreamCloseResponse[] = { + '\x03', // protocol_version + '\x01', '\x05', // message_type - Stream_close_response + '\x00', '\x0c', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01', // parameter_value + '\x00', '\x0f', // parameter_type - ECM_stream_id + '\x00', '\x02', // parameter_length + '\x00', '\x01' // parameter_value +}; + +const char kTestChannelClose[] = { + '\x03', // protocol_version + '\x00', '\x04', // message_type - Channel_close + '\x00', '\x06', // message_length + '\x00', '\x0e', // parameter_type - ECM_channel_id + '\x00', '\x02', // parameter_length + '\x00', '\x01' // parameter_value +}; + +} // namespace cas +} // namespace widevine + +#endif // MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_ECMG_MESSAGES_H_ diff --git a/example/test_simulcrypt_messages.h b/example/test_simulcrypt_messages.h deleted file mode 100644 index 7bff06d..0000000 --- a/example/test_simulcrypt_messages.h +++ /dev/null @@ -1,166 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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 Simulcrypt messages used in unit tests and example client. - -#ifndef MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_SIMULCRYPT_MESSAGES_H_ -#define MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_SIMULCRYPT_MESSAGES_H_ - -namespace widevine { -namespace cas { - -const char kTestEcmgStreamSetupMessage[] = { // protocol_version - '\x01', - // message_type - Stream_set-up - '\x01', '\x01', - // message_length - // 18 bytes below, 3 parameters 6 bytes each - '\x00', '\x12', - // parameter_type - ECM_channel_id - '\x00', '\x0e', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x01', - // parameter_type - ECM_stream_id - '\x00', '\x0f', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x02', - // parameter_type - nominal_CP_duration - '\x00', '\x10', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x03'}; - -const char kTestEcmgCwProvisionMessageWithOneCw[] = { - // protocol_version - '\x01', - // message_type - CW_provision - '\x02', '\x01', - // message_length - // 64 bytes below, 3 * 6 + 8 + 10 + 1 * 22 + 6 - '\x00', '\x40', - // parameter_type - ECM_channel_id - '\x00', '\x0e', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x01', - // parameter_type - ECM_stream_id - '\x00', '\x0f', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x02', - // parameter_type - CP_number - '\x00', '\x12', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\xa1', - // parameter_type - access_criteria - '\x00', '\x0d', - // parameter_length - '\x00', '\x04', - // parameter_value - '\x00', '\x00', '\x00', '\x00', - // parameter_type - CW_encryption - '\x00', '\x18', - // parameter_length - '\x00', '\x06', - // parameter_value - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - // parameter_type - CP_CW_combination - '\x00', '\x14', - // parameter_length - 2 + 16 - '\x00', '\x12', - // parameter_value - CP then CW - // CP - '\x00', '\xa1', - // CW (16 bytes) - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - // parameter_type - CP_duration - '\x00', '\x13', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x0a'}; - -const char kTestEcmgCwProvisionMessageWithTwoCw[] = { - // protocol_version - '\x01', - // message_type - CW_provision - '\x02', '\x01', - // message_length - // 86 bytes below, 3 * 6 + 8 + 10 + 2 * 22 + 6 - '\x00', '\x56', - // parameter_type - ECM_channel_id - '\x00', '\x0e', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x01', - // parameter_type - ECM_stream_id - '\x00', '\x0f', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x02', - // parameter_type - CP_number - '\x00', '\x12', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\xa1', - // parameter_type - access_criteria - '\x00', '\x0d', - // parameter_length - '\x00', '\x04', - // parameter_value - '\x00', '\x00', '\x00', '\x00', - // parameter_type - CW_encryption - '\x00', '\x18', - // parameter_length - '\x00', '\x06', - // parameter_value - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - // parameter_type - CP_CW_combination - '\x00', '\x14', - // parameter_length - 2 + 16 - '\x00', '\x12', - // parameter_value - CP then CW - // CP - '\x00', '\xa1', - // CW (16 bytes) - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - // parameter_type - CP_CW_combination - '\x00', '\x14', - // parameter_length - 2 + 16 - '\x00', '\x12', - // parameter_value - CP then CW - // CP - '\x00', '\xa2', - // CW (16 bytes) - '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', - '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', - // parameter_type - CP_duration - '\x00', '\x13', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x0a'}; - -} // namespace cas -} // namespace widevine - -#endif // MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_SIMULCRYPT_MESSAGES_H_ diff --git a/example/wv_cas_key_fetcher_example.cc b/example/wv_cas_key_fetcher_example.cc index f8a48a9..40dc653 100644 --- a/example/wv_cas_key_fetcher_example.cc +++ b/example/wv_cas_key_fetcher_example.cc @@ -20,8 +20,6 @@ DEFINE_string(content_id, "21140844", "Content ID"); DEFINE_bool(key_rotation, true, "Whether key rotation is enabled"); DEFINE_string(track_type, "SD", "Provider name"); -namespace util = widevine::util; - int main(int argc, char **argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); CHECK(!FLAGS_content_id.empty() && !FLAGS_track_type.empty()) @@ -47,7 +45,7 @@ int main(int argc, char **argv) { std::string signed_response_str; widevine::cas::WvCasKeyFetcher key_fetcher; - util::Status status = + widevine::Status status = key_fetcher.RequestEntitlementKey(request_str, &signed_response_str); if (!status.ok()) { LOG(ERROR) << "Failed to request entitlement key"; diff --git a/external_build_files/curl.BUILD b/external_build_files/curl.BUILD old mode 100755 new mode 100644 diff --git a/external_build_files/zlib.BUILD b/external_build_files/zlib.BUILD old mode 100755 new mode 100644 diff --git a/media_cas_packager_sdk/internal/BUILD b/media_cas_packager_sdk/internal/BUILD index 17b702d..050cc83 100644 --- a/media_cas_packager_sdk/internal/BUILD +++ b/media_cas_packager_sdk/internal/BUILD @@ -28,9 +28,9 @@ cc_library( "//base", "@abseil_repo//absl/base:core_headers", "@abseil_repo//absl/strings", - "//common:status", "//common:aes_cbc_util", "//common:random_util", + "//common:status", "//common:string_util", "//media_cas_packager_sdk/public:wv_cas_types", "//protos/public:media_cas_encryption_proto", @@ -76,27 +76,42 @@ cc_test( ) cc_library( - name = "ecmg", - srcs = ["ecmg.cc"], + name = "ecmg_client_handler", + srcs = ["ecmg_client_handler.cc"], hdrs = [ - "ecmg.h", + "ecmg_client_handler.h", "ecmg_constants.h", ], deps = [ ":ecm", ":ecm_generator", ":fixed_key_fetcher", + ":mpeg2ts", ":util", "//base", "@abseil_repo//absl/base:core_headers", "@abseil_repo//absl/memory", "@abseil_repo//absl/strings", + "//common:crypto_util", "//common:status", "//example:constants", + "//media_cas_packager_sdk/public:wv_cas_ecm", "//media_cas_packager_sdk/public:wv_cas_types", ], ) +cc_test( + name = "ecmg_client_handler_test", + size = "small", + srcs = ["ecmg_client_handler_test.cc"], + deps = [ + ":ecmg_client_handler", + "//testing:gunit_main", + "@abseil_repo//absl/memory", + "//example:test_ecmg_messages", + ], +) + cc_library( name = "fixed_key_fetcher", srcs = [ @@ -131,34 +146,6 @@ cc_library( ], ) -cc_library( - name = "simulcrypt", - srcs = ["simulcrypt.cc"], - hdrs = [ - "simulcrypt.h", - "simulcrypt_constants.h", - ], - deps = [ - ":ecmg", - ":util", - "//base", - "@abseil_repo//absl/base:core_headers", - "@abseil_repo//absl/strings", - "//common:status", - ], -) - -cc_test( - name = "simulcrypt_test", - size = "small", - srcs = ["simulcrypt_test.cc"], - deps = [ - ":simulcrypt", - "//testing:gunit_main", - "//example:test_simulcrypt_messages", - ], -) - cc_library( name = "ts_packet", srcs = [ diff --git a/media_cas_packager_sdk/internal/ecm.cc b/media_cas_packager_sdk/internal/ecm.cc index d3da0e7..2d928d3 100644 --- a/media_cas_packager_sdk/internal/ecm.cc +++ b/media_cas_packager_sdk/internal/ecm.cc @@ -14,9 +14,9 @@ #include "glog/logging.h" #include "absl/strings/str_cat.h" -#include "common/status.h" #include "common/aes_cbc_util.h" #include "common/random_util.h" +#include "common/status.h" #include "common/string_util.h" #include "protos/public/media_cas_encryption.pb.h" @@ -112,31 +112,31 @@ bool ConvertIvSizeParam(EcmIvSize param, size_t* size) { } // namespace -util::Status CasEcm::Initialize(const std::string& content_id, - const std::string& content_provider, - const EcmInitParameters& ecm_init_parameters, - std::string* key_request_message) { +Status CasEcm::Initialize(const std::string& content_id, + const std::string& content_provider, + const EcmInitParameters& ecm_init_parameters, + std::string* key_request_message) { if (initialized_) { - return {util::error::INTERNAL, "Already initialized."}; + return {error::INTERNAL, "Already initialized."}; } if (content_id.empty()) { - return {util::error::INVALID_ARGUMENT, "Content ID is empty."}; + return {error::INVALID_ARGUMENT, "Content ID is empty."}; } if (content_provider.empty()) { - return {util::error::INVALID_ARGUMENT, "Content Provider is empty."}; + return {error::INVALID_ARGUMENT, "Content Provider is empty."}; } if (key_request_message == nullptr) { - return {util::error::INVALID_ARGUMENT, "key_request_message is null."}; + return {error::INVALID_ARGUMENT, "key_request_message is null."}; } if (ecm_init_parameters.track_types.empty()) { - return {util::error::INVALID_ARGUMENT, + return {error::INVALID_ARGUMENT, "Parameter track_ids must be set with one or more Track IDs."}; } if (!ConvertIvSizeParam(ecm_init_parameters.content_iv_size, &content_iv_size_)) { - return {util::error::INVALID_ARGUMENT, + return {error::INVALID_ARGUMENT, "Parameter content_iv_size must be kIvSize8 or kIvSize16."}; } @@ -151,7 +151,7 @@ util::Status CasEcm::Initialize(const std::string& content_id, generation_ = kMaxGeneration; // Construct and return CasEncryptionRequest message for caller to use. - util::Status status = CreateEntitlementRequest(key_request_message); + Status status = CreateEntitlementRequest(key_request_message); if (!status.ok()) { LOG(ERROR) << "Entitlement request message could not be created."; return status; @@ -160,31 +160,30 @@ util::Status CasEcm::Initialize(const std::string& content_id, // Everything is set up except entitlement keys. ClearEntitlementKeys(); initialized_ = true; - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ProcessCasEncryptionResponse(const std::string& response) { +Status CasEcm::ProcessCasEncryptionResponse(const std::string& response) { if (!initialized_) { - return {util::error::INTERNAL, "Not initialized."}; + return {error::INTERNAL, "Not initialized."}; } if (response.empty()) { - return {util::error::INVALID_ARGUMENT, "Response std::string is empty."}; + return {error::INVALID_ARGUMENT, "Response std::string is empty."}; } return ParseEntitlementResponse(response); } -util::Status CasEcm::GenerateEcm(EntitledKeyInfo* even_key, - EntitledKeyInfo* odd_key, - const std::string& track_type, - std::string* serialized_ecm, uint32_t* generation) { +Status CasEcm::GenerateEcm(EntitledKeyInfo* even_key, EntitledKeyInfo* odd_key, + const std::string& track_type, std::string* serialized_ecm, + uint32_t* generation) { if (!initialized_) { - return {util::error::INTERNAL, "Not initialized."}; + return {error::INTERNAL, "Not initialized."}; } if (!HaveEntitlementKeys()) { - return {util::error::INTERNAL, "Need entitlement key."}; + return {error::INTERNAL, "Need entitlement key."}; } if (!paired_keys_required_) { - return {util::error::INVALID_ARGUMENT, + return {error::INVALID_ARGUMENT, "Key rotation not enabled - use GenerateSingleKeyEcm()."}; } @@ -195,18 +194,18 @@ util::Status CasEcm::GenerateEcm(EntitledKeyInfo* even_key, return GenerateEcmCommon(keys, track_type, serialized_ecm, generation); } -util::Status CasEcm::GenerateSingleKeyEcm(EntitledKeyInfo* key, - const std::string& track_type, - std::string* serialized_ecm, - uint32_t* generation) { +Status CasEcm::GenerateSingleKeyEcm(EntitledKeyInfo* key, + const std::string& track_type, + std::string* serialized_ecm, + uint32_t* generation) { if (!initialized_) { - return {util::error::INTERNAL, "Not initialized."}; + return {error::INTERNAL, "Not initialized."}; } if (!HaveEntitlementKeys()) { - return {util::error::INTERNAL, "Need entitlement key."}; + return {error::INTERNAL, "Need entitlement key."}; } if (paired_keys_required_) { - return {util::error::INVALID_ARGUMENT, + return {error::INVALID_ARGUMENT, "Key rotation enabled - use GenerateEcm()."}; } @@ -216,17 +215,17 @@ util::Status CasEcm::GenerateSingleKeyEcm(EntitledKeyInfo* key, return GenerateEcmCommon(keys, track_type, serialized_ecm, generation); } -util::Status CasEcm::GenerateEcmCommon( - const std::vector& keys, const std::string& track_type, - std::string* serialized_ecm, uint32_t* generation) { +Status CasEcm::GenerateEcmCommon(const std::vector& keys, + const std::string& track_type, + std::string* serialized_ecm, uint32_t* generation) { if (serialized_ecm == nullptr) { - return {util::error::INVALID_ARGUMENT, "No return ecm std::string pointer."}; + return {error::INVALID_ARGUMENT, "No return ecm std::string pointer."}; } if (generation == nullptr) { - return {util::error::INVALID_ARGUMENT, "No return generation pointer."}; + return {error::INVALID_ARGUMENT, "No return generation pointer."}; } - util::Status status = ValidateKeys(keys); + Status status = ValidateKeys(keys); if (!status.ok()) { return status; } @@ -254,37 +253,34 @@ util::Status CasEcm::GenerateEcmCommon( if (kMaxEcmSizeBytes < serialized_ecm->size()) { generation_ = previous_generation; serialized_ecm->clear(); - return util::Status(util::error::INTERNAL, - "Maximum size of ECM has been exceeded."); + return Status(error::INTERNAL, "Maximum size of ECM has been exceeded."); } *generation = generation_; - return util::OkStatus(); + return OkStatus(); } void CasEcm::IncrementGeneration() { generation_ = (generation_ >= kMaxGeneration) ? 0 : generation_ + 1; } -util::Status CasEcm::WrapEntitledKeys( - const std::string& track_type, const std::vector keys) { +Status CasEcm::WrapEntitledKeys(const std::string& track_type, + const std::vector keys) { if (!initialized_) { - return {util::error::INTERNAL, "Not initialized."}; + return {error::INTERNAL, "Not initialized."}; } if (keys.empty()) { - return {util::error::INVALID_ARGUMENT, - "Vector of EntitledKeyInfo is empty."}; + return {error::INVALID_ARGUMENT, "Vector of EntitledKeyInfo is empty."}; } auto ekey_map_entry = entitlement_keys_.find(track_type); if (ekey_map_entry == entitlement_keys_.end()) { - return {util::error::INTERNAL, - "No Entitlement Key found for given track_type."}; + return {error::INTERNAL, "No Entitlement Key found for given track_type."}; } const auto& ekey_list = ekey_map_entry->second; if (ekey_list.size() != keys.size()) { - return {util::error::INTERNAL, + return {error::INTERNAL, "Number of Entitled keys and Entitlement keys must match."}; } @@ -298,7 +294,7 @@ util::Status CasEcm::WrapEntitledKeys( if (entitled_key->wrapped_key_iv.empty()) { CHECK(RandomBytes(kWrappedKeyIvSizeBytes, &entitled_key->wrapped_key_iv)); } - util::Status status = + Status status = WrapKey(entitlement_key->key_value, entitled_key->wrapped_key_iv, entitled_key->key_value, &entitled_key->wrapped_key_value); if (!status.ok()) { @@ -306,13 +302,12 @@ util::Status CasEcm::WrapEntitledKeys( } entitlement_key++; } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::WrapKey(const std::string& wrapping_key, - const std::string& wrapping_iv, const std::string& key_value, - std::string* wrapped_key) { - util::Status status = ValidateKeyValue(wrapping_key, kWrappingKeySizeBytes); +Status CasEcm::WrapKey(const std::string& wrapping_key, const std::string& wrapping_iv, + const std::string& key_value, std::string* wrapped_key) { + Status status = ValidateKeyValue(wrapping_key, kWrappingKeySizeBytes); if (!status.ok()) { return status; } @@ -328,14 +323,14 @@ util::Status CasEcm::WrapKey(const std::string& wrapping_key, *wrapped_key = crypto_util::EncryptAesCbcNoPad(wrapping_key, wrapping_iv, key_value); if (wrapped_key->empty()) { - return util::Status(util::error::INTERNAL, "Failed to wrap key"); + return Status(error::INTERNAL, "Failed to wrap key"); } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ValidateKeys(const std::vector& keys) { +Status CasEcm::ValidateKeys(const std::vector& keys) { for (const auto& key : keys) { - util::Status status; + Status status; status = ValidateKeyId(key->key_id); if (!status.ok()) { return status; @@ -349,13 +344,12 @@ util::Status CasEcm::ValidateKeys(const std::vector& keys) { return status; } } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ValidateWrappedKeys( - const std::vector& keys) { +Status CasEcm::ValidateWrappedKeys(const std::vector& keys) { for (const auto& key : keys) { - util::Status status; + Status status; status = ValidateKeyId(key->key_id); if (!status.ok()) { return status; @@ -374,31 +368,31 @@ util::Status CasEcm::ValidateWrappedKeys( return status; } } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ValidateKeyId(const std::string& key_id) { +Status CasEcm::ValidateKeyId(const std::string& key_id) { if (key_id.size() != kKeyIdSizeBytes) { - return {util::error::INVALID_ARGUMENT, "Key ID must be 16 bytes."}; + return {error::INVALID_ARGUMENT, "Key ID must be 16 bytes."}; } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ValidateKeyValue(const std::string& key_value, - size_t key_value_size) { +Status CasEcm::ValidateKeyValue(const std::string& key_value, + size_t key_value_size) { if (key_value.size() != key_value_size) { - return util::Status( - util::error::INVALID_ARGUMENT, + return Status( + error::INVALID_ARGUMENT, absl::StrCat("Key is wrong size (", key_value.size(), " bytes).")); } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ValidateIv(const std::string& iv, size_t size) { +Status CasEcm::ValidateIv(const std::string& iv, size_t size) { if (iv.size() != size) { - return {util::error::INVALID_ARGUMENT, "IV is wrong size."}; + return {error::INVALID_ARGUMENT, "IV is wrong size."}; } - return util::OkStatus(); + return OkStatus(); } std::string CasEcm::SerializeEcm(const std::vector& keys) { @@ -427,7 +421,7 @@ std::string CasEcm::SerializeEcm(const std::vector& keys) { LOG(FATAL) << "ECM bitset incorret size: " << ecm_bitset.size(); } std::string serialized_ecm; - util::Status status = + Status status = string_util::BitsetStringToBinaryString(ecm_bitset, &serialized_ecm); if (!status.ok()) { LOG(FATAL) << "Failed to convert ECM bitset to std::string"; @@ -441,7 +435,7 @@ std::string CasEcm::SerializeEcm(const std::vector& keys) { return serialized_ecm; } -util::Status CasEcm::CreateEntitlementRequest(std::string* request_string) { +Status CasEcm::CreateEntitlementRequest(std::string* request_string) { CasEncryptionRequest request; request.set_content_id(content_id_); @@ -454,43 +448,42 @@ util::Status CasEcm::CreateEntitlementRequest(std::string* request_string) { if (!request.SerializeToString(request_string)) { request_string->clear(); - return {util::error::INTERNAL, "Failure serializing request."}; + return {error::INTERNAL, "Failure serializing request."}; } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcm::ParseEntitlementResponse(const std::string& response_string) { +Status CasEcm::ParseEntitlementResponse(const std::string& response_string) { // TODO(user): parse valid response. NOT Implemented. ClearEntitlementKeys(); SignedCasEncryptionResponse signed_response; if (!signed_response.ParseFromString(response_string)) { - return {util::error::INTERNAL, "Failure parsing signed response."}; + return {error::INTERNAL, "Failure parsing signed response."}; } // TODO(user): Should verify signature. CasEncryptionResponse response; if (!response.ParseFromString(signed_response.response())) { - return {util::error::INTERNAL, "Failure parsing signed response."}; + return {error::INTERNAL, "Failure parsing signed response."}; } if (response.status() != CasEncryptionResponse_Status_OK) { - return util::Status( - util::error::INTERNAL, - absl::StrCat("Failure reported by server: ", response.status(), " : ", - response.status_message())); + return Status(error::INTERNAL, absl::StrCat("Failure reported by server: ", + response.status(), " : ", + response.status_message())); } if (content_id_ != response.content_id()) { - return util::Status( - util::error::INTERNAL, + return Status( + error::INTERNAL, absl::StrCat("Content ID mismatch in Entitlement Response - expected: ", content_id_, " received: ", response.content_id())); } if (response.entitlement_keys().empty()) { - return {util::error::INTERNAL, "Failure: no entitlement keys in response."}; + return {error::INTERNAL, "Failure: no entitlement keys in response."}; } size_t keys_needed = (paired_keys_required_ ? 2 : 1) * track_types_.size(); if (keys_needed > response.entitlement_keys().size()) { - return util::Status( - util::error::INTERNAL, + return Status( + error::INTERNAL, absl::StrCat( "Wrong number of keys in Entitlement Response - expected: ", keys_needed, " got: ", response.entitlement_keys().size())); @@ -509,7 +502,7 @@ util::Status CasEcm::ParseEntitlementResponse(const std::string& response_string EntitlementKeyInfo ekey; ekey.key_id = key.key_id(); ekey.key_value = key.key(); - util::Status status = ValidateKeyValue(key.key(), kWrappingKeySizeBytes); + Status status = ValidateKeyValue(key.key(), kWrappingKeySizeBytes); if (!status.ok()) { return status; } @@ -534,10 +527,9 @@ util::Status CasEcm::ParseEntitlementResponse(const std::string& response_string if (!CheckEntitlementKeys()) { LOG(ERROR) << "Could not stage entitlement keys from response:"; response.ShortDebugString(); - return util::Status(util::error::INTERNAL, - "No suitable entitlement key was found."); + return Status(error::INTERNAL, "No suitable entitlement key was found."); } - return util::OkStatus(); + return OkStatus(); } size_t CasEcm::CountEntitlementKeys() const { diff --git a/media_cas_packager_sdk/internal/ecm.h b/media_cas_packager_sdk/internal/ecm.h index 9e55b64..8bb27cf 100644 --- a/media_cas_packager_sdk/internal/ecm.h +++ b/media_cas_packager_sdk/internal/ecm.h @@ -91,10 +91,10 @@ class CasEcm { // Notes: // The returned |key_request_message| must be sent to the server and // the response correctly parsed before ECMs can be generated. - virtual util::Status Initialize(const std::string& content_id, - const std::string& content_provider, - const EcmInitParameters& ecm_init_parameters, - std::string* key_request_message); + virtual Status Initialize(const std::string& content_id, + const std::string& content_provider, + const EcmInitParameters& ecm_init_parameters, + std::string* key_request_message); // Parse a CasEncryptionResponse message holding the entitlement keys for // generating the ECM stream. The entitlement keys are used to encrypt the @@ -102,7 +102,7 @@ class CasEcm { // Args: // |response| a serialized CasEncryptionRequest message from the server // holding entitlement key information (or error information). - virtual util::Status ProcessCasEncryptionResponse(const std::string& response); + virtual Status ProcessCasEncryptionResponse(const std::string& response); // Accept keys and IVs and construct an ECM that will fit into a Transport // Stream packet payload (184 bytes). @@ -118,10 +118,9 @@ class CasEcm { // entitlement key. Wrapping modifies the original structure. // Generation is a mod 32 counter. If the ECM has any changes from the // previous ECM, the generation is increased by one. - virtual util::Status GenerateEcm(EntitledKeyInfo* even_key, - EntitledKeyInfo* odd_key, - const std::string& track_type, - std::string* serialized_ecm, uint32_t* generation); + virtual Status GenerateEcm(EntitledKeyInfo* even_key, + EntitledKeyInfo* odd_key, const std::string& track_type, + std::string* serialized_ecm, uint32_t* generation); // Accept a key and IV and construct an ECM that will fit into a Transport // Stream packet payload (184 bytes). This call is specifically for the case @@ -135,10 +134,10 @@ class CasEcm { // with the initialized settings. // Generation is a mod 32 counter. If the ECM has any changes from the // previous ECM, the generation is increased by one. - virtual util::Status GenerateSingleKeyEcm(EntitledKeyInfo* key, - const std::string& track_type, - std::string* serialized_ecm, - uint32_t* generation); + virtual Status GenerateSingleKeyEcm(EntitledKeyInfo* key, + const std::string& track_type, + std::string* serialized_ecm, + uint32_t* generation); protected: // For unit tests. // Take the input entitled |keys| and our current state, and generate @@ -154,8 +153,8 @@ class CasEcm { // |track_type| the track type for the keys. The type_track must match one // of the |EcmInitParameters::track_types| strings passed into Initialize(). // |key| the Entitled Key to be wrapped. - virtual util::Status WrapEntitledKeys( - const std::string& track_type, const std::vector keys); + virtual Status WrapEntitledKeys(const std::string& track_type, + const std::vector keys); private: // Entitlement key - |key_value| is used to wrap the content key, and |key_id| @@ -194,29 +193,27 @@ class CasEcm { } // Common helper for GenerateEcm() and GenerateSingleKeyEcm() - virtual util::Status GenerateEcmCommon( - const std::vector& keys, const std::string& track_type, - std::string* serialized_ecm, uint32_t* generation); + virtual Status GenerateEcmCommon(const std::vector& keys, + const std::string& track_type, + std::string* serialized_ecm, uint32_t* generation); // Wrap |key_value| using |wrapping_key| (entitlement key) and |wrapping_iv|. // Returns the resulting wrapped key in |wrapped_key|. // Return a status indicating whether there has been any error. - virtual util::Status WrapKey(const std::string& wrapping_key, - const std::string& wrapping_iv, - const std::string& key_value, std::string* wrapped_key); + virtual Status WrapKey(const std::string& wrapping_key, const std::string& wrapping_iv, + const std::string& key_value, std::string* wrapped_key); - virtual util::Status ValidateKeys(const std::vector& keys); - virtual util::Status ValidateWrappedKeys( - const std::vector& keys); + virtual Status ValidateKeys(const std::vector& keys); + virtual Status ValidateWrappedKeys(const std::vector& keys); - util::Status ValidateKeyId(const std::string& key_id); - util::Status ValidateKeyValue(const std::string& key_value, size_t key_value_size); - util::Status ValidateIv(const std::string& iv, size_t size); + Status ValidateKeyId(const std::string& key_id); + Status ValidateKeyValue(const std::string& key_value, size_t key_value_size); + Status ValidateIv(const std::string& iv, size_t size); // TODO(user): need unit tests for CreateEntitlementRequest. - virtual util::Status CreateEntitlementRequest(std::string* request_string); + virtual Status CreateEntitlementRequest(std::string* request_string); // TODO(user): need unit tests for ParseEntitlementResponse. - virtual util::Status ParseEntitlementResponse(const std::string& response_string); + virtual Status ParseEntitlementResponse(const std::string& response_string); virtual uint32_t generation() const { return generation_; } virtual CryptoMode crypto_mode() const { return crypto_mode_; } diff --git a/media_cas_packager_sdk/internal/ecm_generator.cc b/media_cas_packager_sdk/internal/ecm_generator.cc index 907af1b..7bbe11c 100644 --- a/media_cas_packager_sdk/internal/ecm_generator.cc +++ b/media_cas_packager_sdk/internal/ecm_generator.cc @@ -20,7 +20,7 @@ static constexpr int kMaxBytesKeyIdField = 16; std::string CasEcmGenerator::GenerateEcm(const EcmParameters& params) { std::vector keys; - util::Status status = ProcessEcmParameters(params, &keys); + Status status = ProcessEcmParameters(params, &keys); if (!status.ok() || !initialized_) { LOG(ERROR) << " EcmParameters is not set up properly: " << status; return ""; @@ -43,7 +43,7 @@ std::string CasEcmGenerator::GenerateEcm(const EcmParameters& params) { return serialized_ecm; } -util::Status CasEcmGenerator::ProcessEcmParameters( +Status CasEcmGenerator::ProcessEcmParameters( const EcmParameters& ecm_params, std::vector* keys) { initialized_ = false; rotation_enabled_ = ecm_params.rotation_enabled; @@ -52,11 +52,11 @@ util::Status CasEcmGenerator::ProcessEcmParameters( keys->clear(); uint32_t keys_needed = ecm_params.rotation_enabled ? 2 : 1; if (ecm_params.key_params.size() < keys_needed) { - return {util::error::INVALID_ARGUMENT, + return {error::INVALID_ARGUMENT, "Number of supplied keys is wrong (check rotation periods)."}; } for (int i = 0; i < keys_needed; i++) { - util::Status status = ValidateKeyParameters(ecm_params.key_params[i]); + Status status = ValidateKeyParameters(ecm_params.key_params[i]); if (!status.ok()) { return status; } @@ -70,80 +70,77 @@ util::Status CasEcmGenerator::ProcessEcmParameters( current_key_index_ = 0; current_key_even_ = true; initialized_ = true; - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcmGenerator::ValidateKeyId(const std::string& id) { +Status CasEcmGenerator::ValidateKeyId(const std::string& id) { if (id.empty()) { - return {util::error::INVALID_ARGUMENT, "Key id is empty."}; + return {error::INVALID_ARGUMENT, "Key id is empty."}; } if (id.size() > kMaxBytesKeyIdField) { - return {util::error::INVALID_ARGUMENT, "Key id is too long."}; + return {error::INVALID_ARGUMENT, "Key id is too long."}; } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcmGenerator::ValidateKeyData(const std::string& key_data) { +Status CasEcmGenerator::ValidateKeyData(const std::string& key_data) { if (key_data.empty()) { - return {util::error::INVALID_ARGUMENT, "Key data is empty."}; + return {error::INVALID_ARGUMENT, "Key data is empty."}; } if (key_data.size() != kKeyDataSize) { - return {util::error::INVALID_ARGUMENT, "Key data is wrong size."}; + return {error::INVALID_ARGUMENT, "Key data is wrong size."}; } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcmGenerator::ValidateIv(const std::string& iv, - size_t required_size) { +Status CasEcmGenerator::ValidateIv(const std::string& iv, size_t required_size) { if (iv.empty()) { - return {util::error::INVALID_ARGUMENT, "IV is empty."}; + return {error::INVALID_ARGUMENT, "IV is empty."}; } if (required_size != 8 && required_size != 16) { - return {util::error::INTERNAL, "IV size has not been set up correctly."}; + return {error::INTERNAL, "IV size has not been set up correctly."}; } if (iv.size() != required_size) { - return {util::error::INVALID_ARGUMENT, - "IV has wrong or inconsistent size."}; + return {error::INVALID_ARGUMENT, "IV has wrong or inconsistent size."}; } - return util::OkStatus(); + return OkStatus(); } -util::Status CasEcmGenerator::ValidateWrappedKeyIv(const std::string& iv) { +Status CasEcmGenerator::ValidateWrappedKeyIv(const std::string& iv) { // All wrapped key IVs must be 16 bytes. - util::Status status = ValidateIv(iv, kIvSize16); + Status status = ValidateIv(iv, kIvSize16); if (!status.ok()) { LOG(ERROR) << " Wrapped key IV is not valid: " << status; } return status; } -util::Status CasEcmGenerator::ValidateContentIv(const std::string& iv) { +Status CasEcmGenerator::ValidateContentIv(const std::string& iv) { // If content_iv_size_ is zero, use this IV as the size for all future IVs in // this stream. if (content_iv_size_ == 0) { content_iv_size_ = iv.size(); } - util::Status status = ValidateIv(iv, content_iv_size_); + Status status = ValidateIv(iv, content_iv_size_); if (!status.ok()) { LOG(ERROR) << " Content IV is not valid: " << status; } return status; } -util::Status CasEcmGenerator::ValidateKeyParameters( - const KeyParameters& key_params) { - util::Status status; +Status CasEcmGenerator::ValidateKeyParameters(const KeyParameters& key_params) { + Status status; status = ValidateKeyId(key_params.key_id); if (!status.ok()) return status; if (key_params.content_ivs.empty()) { - return {util::error::INVALID_ARGUMENT, "Content IVs is empty."}; + return {error::INVALID_ARGUMENT, "Content IVs is empty."}; } for (int i = 0; i < key_params.content_ivs.size(); i++) { status = ValidateContentIv(key_params.content_ivs[i]); if (!status.ok()) return status; } - return util::OkStatus(); + return OkStatus(); } } // namespace cas diff --git a/media_cas_packager_sdk/internal/ecm_generator.h b/media_cas_packager_sdk/internal/ecm_generator.h index 5021172..9b24057 100644 --- a/media_cas_packager_sdk/internal/ecm_generator.h +++ b/media_cas_packager_sdk/internal/ecm_generator.h @@ -74,16 +74,16 @@ class CasEcmGenerator { private: friend class CasEcmGeneratorTest; - util::Status ProcessEcmParameters(const EcmParameters& ecm_params, - std::vector* keys); + Status ProcessEcmParameters(const EcmParameters& ecm_params, + std::vector* keys); - util::Status ProcessEcmParameters(const EcmParameters& ecm_params); - util::Status ValidateKeyId(const std::string& id); - util::Status ValidateKeyData(const std::string& key_data); - util::Status ValidateWrappedKeyIv(const std::string& iv); - util::Status ValidateIv(const std::string& iv, size_t required_size); - util::Status ValidateContentIv(const std::string& iv); - util::Status ValidateKeyParameters(const KeyParameters& key_params); + Status ProcessEcmParameters(const EcmParameters& ecm_params); + Status ValidateKeyId(const std::string& id); + Status ValidateKeyData(const std::string& key_data); + Status ValidateWrappedKeyIv(const std::string& iv); + Status ValidateIv(const std::string& iv, size_t required_size); + Status ValidateContentIv(const std::string& iv); + Status ValidateKeyParameters(const KeyParameters& key_params); bool initialized_ = false; uint32_t generation_ = 0; diff --git a/media_cas_packager_sdk/internal/ecm_generator_test.cc b/media_cas_packager_sdk/internal/ecm_generator_test.cc index ea21b3e..a8d8dd4 100644 --- a/media_cas_packager_sdk/internal/ecm_generator_test.cc +++ b/media_cas_packager_sdk/internal/ecm_generator_test.cc @@ -54,8 +54,8 @@ constexpr char kFakeCasEncryptionResponseKeyId[] = "fake_key_id....."; constexpr char kFakeCasEncryptionResponseKeyData[] = "fakefakefakefakefakefakefakefake"; -util::Status HandleCasEncryptionRequest(const std::string& request_string, - std::string* signed_response_string) { +Status HandleCasEncryptionRequest(const std::string& request_string, + std::string* signed_response_string) { CasEncryptionRequest request; request.ParseFromString(request_string); @@ -89,7 +89,7 @@ util::Status HandleCasEncryptionRequest(const std::string& request_string, SignedCasEncryptionResponse signed_response; signed_response.set_response(response_string); signed_response.SerializeToString(signed_response_string); - return util::OkStatus(); + return OkStatus(); } } // namespace @@ -99,8 +99,8 @@ class CasEcmGeneratorTest : public testing::Test { void SetUp() override { } - util::Status ProcessEcmParameters(const EcmParameters& params, - std::vector* keys) { + Status ProcessEcmParameters(const EcmParameters& params, + std::vector* keys) { return ecm_gen_.ProcessEcmParameters(params, keys); } @@ -170,7 +170,7 @@ TEST_F(CasEcmGeneratorTest, InitializeNoRotation) { SetTestConfig1(&ecm_params); - util::Status status = ProcessEcmParameters(ecm_params, &keys); + Status status = ProcessEcmParameters(ecm_params, &keys); ASSERT_OK(status); ASSERT_EQ(EntitlementKeySize(ecm_params), 16); @@ -254,7 +254,7 @@ TEST_F(CasEcmGeneratorTest, InitializeSimpleRotation) { SetTestConfig2(&ecm_params); ecm_init_params_.key_rotation_enabled = true; - util::Status status = ProcessEcmParameters(ecm_params, &keys); + Status status = ProcessEcmParameters(ecm_params, &keys); EXPECT_TRUE(status.ok()); EXPECT_TRUE(ecm_gen_.initialized()); diff --git a/media_cas_packager_sdk/internal/ecm_test.cc b/media_cas_packager_sdk/internal/ecm_test.cc index a172d11..86585b7 100644 --- a/media_cas_packager_sdk/internal/ecm_test.cc +++ b/media_cas_packager_sdk/internal/ecm_test.cc @@ -68,14 +68,14 @@ class MockCasEcm : public CasEcm { return SerializeEcm(keys); } - virtual util::Status MockWrapEntitledKeys( + virtual Status MockWrapEntitledKeys( const std::string& track_type, const std::vector& keys) { for (auto entitled_key : keys) { entitled_key->entitlement_key_id = "entitlement_Mock"; entitled_key->wrapped_key_value = "MockMockMockMock"; entitled_key->wrapped_key_iv = "WRAPPED_KIV....x"; } - return util::OkStatus(); + return OkStatus(); } void MockSetup(bool two_keys, const std::string& track_type, uint32_t generation, @@ -226,7 +226,7 @@ TEST_F(CasEcmTest, GenerateEcmNotInitialized) { EntitledKeyInfo key1; std::string ecm_data; uint32_t gen; - EXPECT_EQ(util::error::INTERNAL, + EXPECT_EQ(error::INTERNAL, ecm_gen.GenerateSingleKeyEcm(&key1, kTrackTypeSD, &ecm_data, &gen) .error_code()); } @@ -237,7 +237,7 @@ TEST_F(CasEcmTest, GenerateEcm2NotInitialized) { EntitledKeyInfo key2; std::string ecm_data; uint32_t gen; - EXPECT_EQ(util::error::INTERNAL, + EXPECT_EQ(error::INTERNAL, ecm_gen.GenerateEcm(&key1, &key2, kTrackTypeSD, &ecm_data, &gen) .error_code()); } @@ -245,7 +245,7 @@ TEST_F(CasEcmTest, GenerateEcm2NotInitialized) { TEST_F(CasEcmTest, SetResponseNotInitialized) { CasEcm ecm_gen; const std::string response("anything"); - EXPECT_EQ(util::error::INTERNAL, + EXPECT_EQ(error::INTERNAL, ecm_gen.ProcessCasEncryptionResponse(response).error_code()); } @@ -253,7 +253,7 @@ TEST_F(CasEcmTest, InitNoTracksFail) { CasEcm ecm_gen; std::string request; EXPECT_EQ( - util::error::INVALID_ARGUMENT, + error::INVALID_ARGUMENT, ecm_gen.Initialize(content_id_, provider_, params_default_, &request) .error_code()); } @@ -270,7 +270,7 @@ TEST_F(CasEcmTest, SecondInitFail) { std::string request; ASSERT_OK( ecm_gen.Initialize(content_id_, provider_, params_simple_, &request)); - EXPECT_EQ(util::error::INTERNAL, + EXPECT_EQ(error::INTERNAL, ecm_gen.Initialize(content_id_, provider_, params_simple_, &request) .error_code()); } @@ -280,7 +280,7 @@ TEST_F(CasEcmTest, InitEmptyContentIdFail) { const std::string empty_content_id; std::string request; EXPECT_EQ( - util::error::INVALID_ARGUMENT, + error::INVALID_ARGUMENT, ecm_gen.Initialize(empty_content_id, provider_, params_simple_, &request) .error_code()); } @@ -290,7 +290,7 @@ TEST_F(CasEcmTest, InitEmptyProviderFail) { const std::string empty_provider; std::string request; EXPECT_EQ( - util::error::INVALID_ARGUMENT, + error::INVALID_ARGUMENT, ecm_gen.Initialize(content_id_, empty_provider, params_simple_, &request) .error_code()); } @@ -315,7 +315,7 @@ TEST_F(CasEcmTest, GenerateWithNoEntitlementOneKeyFail) { uint32_t gen; // This will fail because the entitlement key has not been acquired // (via server call and ProcessCasEncryptionResponse()). - EXPECT_EQ(util::error::INTERNAL, + EXPECT_EQ(error::INTERNAL, ecm_gen.GenerateSingleKeyEcm(&key1, kTrackTypeSD, &ecm, &gen) .error_code()); } @@ -334,13 +334,13 @@ TEST_F(CasEcmTest, GenerateWithNoEntitlementTwoKeysFail) { // This will fail because the entitlement keys have not been acquired // (via server call and ProcessCasEncryptionResponse()). EXPECT_EQ( - util::error::INTERNAL, + error::INTERNAL, ecm_gen.GenerateEcm(&key1, &key2, kTrackTypeSD, &ecm, &gen).error_code()); } TEST_F(CasEcmTest, RequestNullFail) { CasEcm ecm_gen; - EXPECT_EQ(util::error::INVALID_ARGUMENT, + EXPECT_EQ(error::INVALID_ARGUMENT, ecm_gen.Initialize(content_id_, provider_, params_simple_, nullptr) .error_code()); } @@ -374,7 +374,7 @@ TEST_F(CasEcmTest, BadResponseFail) { std::string response; ServerCall(request, &response, false, true); - EXPECT_EQ(util::error::INTERNAL, + EXPECT_EQ(error::INTERNAL, ecm_gen.ProcessCasEncryptionResponse(response).error_code()); } @@ -411,7 +411,7 @@ TEST_F(CasEcmTest, GenerateOneKeyNoGenFail) { ASSERT_OK(ecm_gen.ProcessCasEncryptionResponse(response)); std::string ecm; - EXPECT_EQ(util::error::INVALID_ARGUMENT, + EXPECT_EQ(error::INVALID_ARGUMENT, ecm_gen.GenerateSingleKeyEcm(&key1, kTrackTypeSD, &ecm, nullptr) .error_code()); } @@ -431,7 +431,7 @@ TEST_F(CasEcmTest, GenerateOneKeyBadKeyIdFail) { std::string ecm; uint32_t gen; - EXPECT_EQ(util::error::INVALID_ARGUMENT, + EXPECT_EQ(error::INVALID_ARGUMENT, ecm_gen.GenerateSingleKeyEcm(&key1, kTrackTypeSD, &ecm, &gen) .error_code()); } @@ -455,7 +455,7 @@ TEST_F(CasEcmTest, GenerateOneKeyWrong) { EXPECT_THAT(0, gen); EXPECT_THAT(77, ecm.size()); EXPECT_EQ( - util::error::INVALID_ARGUMENT, + error::INVALID_ARGUMENT, ecm_gen.GenerateEcm(&key1, &key1, kTrackTypeSD, &ecm, &gen).error_code()); } @@ -477,7 +477,7 @@ TEST_F(CasEcmTest, GenerateTwoKeysIvSizeFail) { std::string ecm; uint32_t gen; EXPECT_EQ( - util::error::INVALID_ARGUMENT, + error::INVALID_ARGUMENT, ecm_gen.GenerateEcm(&key1, &key2, kTrackTypeSD, &ecm, &gen).error_code()); } @@ -548,7 +548,7 @@ TEST_F(CasEcmTest, GenerateThreeKeysIvSize16x16Fail) { std::string ecm; uint32_t gen; EXPECT_EQ( - util::error::INTERNAL, + error::INTERNAL, ecm_gen.GenerateEcm(&key1, &key2, kTrackTypeSD, &ecm, &gen).error_code()); } diff --git a/media_cas_packager_sdk/internal/ecmg.cc b/media_cas_packager_sdk/internal/ecmg.cc deleted file mode 100644 index 1bc9663..0000000 --- a/media_cas_packager_sdk/internal/ecmg.cc +++ /dev/null @@ -1,282 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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/internal/ecmg.h" - -#include -#include -#include -#include -#include -#include - -#include "glog/logging.h" -#include "absl/memory/memory.h" -#include "absl/strings/str_cat.h" -#include "common/status.h" -#include "example/constants.h" -#include "media_cas_packager_sdk/internal/ecm_generator.h" -#include "media_cas_packager_sdk/internal/ecmg_constants.h" -#include "media_cas_packager_sdk/internal/util.h" -#include "media_cas_packager_sdk/public/wv_cas_types.h" - -namespace widevine { -namespace cas { - -namespace { - -// Local helper function that processes all the parameters in an ECMG message. -util::Status ProcessParameters(const char* message, size_t message_length, - EcmgParameters* parameters) { - DCHECK(message); - DCHECK(parameters); - - uint16_t parameter_type; - uint16_t parameter_length; - // 'offset' is used to track where we are within |message|. - size_t offset = 0; - // There could be CW_per_msg instances of CP_CW_combinations, - // so we need to track how many we have processed so far - // in order to know where to store the next CP_CW_combination. - int current_cp_cw_combination_index = 0; - while (offset != message_length) { - BigEndianToHost16(¶meter_type, message + offset); - offset += PARAMETER_TYPE_SIZE; - BigEndianToHost16(¶meter_length, message + offset); - offset += PARAMETER_LENGTH_SIZE; - switch (parameter_type) { - case ACCESS_CRITERIA: { - LOG(WARNING) << "Ignoring access_criteria parameter of " - << parameter_length << " bytes long"; - offset += parameter_length; - break; - } - case ECM_CHANNEL_ID: { - if (parameter_length != ECM_CHANNEL_ID_SIZE) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Invalid parameter length ", parameter_length, - " for parameter type ", parameter_type)); - } - BigEndianToHost16(¶meters->ecm_channel_id, message + offset); - offset += parameter_length; - break; - } - case ECM_STREAM_ID: { - if (parameter_length != ECM_STREAM_ID_SIZE) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Invalid parameter length ", parameter_length, - " for parameter type ", parameter_type)); - } - BigEndianToHost16(¶meters->ecm_stream_id, message + offset); - offset += parameter_length; - break; - } - case CP_CW_COMBINATION: { - if (current_cp_cw_combination_index > 2) { - // We can have at most 3 CP_CW_Combinations. - return util::Status(util::error::INVALID_ARGUMENT, - "We only support up to 2 control words in the " - "CW_provision message"); - } - EcmgCpCwCombination* combination = - ¶meters->cp_cw_combinations[current_cp_cw_combination_index++]; - BigEndianToHost16(&combination->cp, message + offset); - offset += CP_SIZE; - size_t cw_size = parameter_length - CP_SIZE; - combination->cw = std::string(message + offset, cw_size); - offset += cw_size; - // TODO(user): This is a temporary hack to let the ECM generator - // know how many keys to include in the ECM. - // CW_per_msg should have been set during channel set-up instead. - parameters->cw_per_msg = current_cp_cw_combination_index; - break; - } - case CP_DURATION: { - if (parameter_length != CP_DURATION_SIZE) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Invalid parameter length ", parameter_length, - " for parameter type ", parameter_type)); - } - BigEndianToHost16(¶meters->cp_duration, message + offset); - offset += parameter_length; - break; - } - case CP_NUMBER: { - if (parameter_length != CP_NUMBER_SIZE) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Invalid parameter length ", parameter_length, - " for parameter type ", parameter_type)); - } - BigEndianToHost16(¶meters->cp_number, message + offset); - offset += parameter_length; - break; - } - case CW_ENCRYPTION: { - LOG(WARNING) << "Ignoring CW_encryption parameter of " - << parameter_length << " bytes long"; - offset += parameter_length; - break; - } - case NOMINAL_CP_DURATION: { - if (parameter_length != NOMINAL_CP_DURATION_SIZE) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Invalid parameter length ", parameter_length, - " for parameter type ", parameter_type)); - } - BigEndianToHost16(¶meters->nominal_cp_duration, message + offset); - offset += parameter_length; - break; - } - default: { - return util::Status( - util::error::UNIMPLEMENTED, - absl::StrCat("No implementation yet to process parameter of type ", - parameter_type)); - break; - } - } - } - return util::OkStatus(); -} -} // namespace - -util::Status Ecmg::ProcessStreamSetupMessage(const char* message, - size_t message_length) { - DCHECK(message); - - EcmgParameters parameters; - util::Status status = ProcessParameters(message, message_length, ¶meters); - if (!status.ok()) { - return status; - } - if (parameters.ecm_channel_id == 0 || parameters.ecm_stream_id == 0 || - parameters.nominal_cp_duration == 0) { - return util::Status(util::error::INVALID_ARGUMENT, - "Missing required parameter"); - } - - if (channels_.find(parameters.ecm_channel_id) == channels_.end()) { - std::unique_ptr new_channel = absl::make_unique(); - channels_[parameters.ecm_channel_id] = std::move(new_channel); - } - EcmgChannel* channel = - channels_.find(parameters.ecm_channel_id)->second.get(); - auto stream_entry = channel->streams.find(parameters.ecm_stream_id); - if (stream_entry == channel->streams.end()) { - std::unique_ptr new_stream = absl::make_unique(); - new_stream->nominal_cp_duration = parameters.nominal_cp_duration; - channel->streams[parameters.ecm_stream_id] = std::move(new_stream); - } else { - EcmgStream* existing_stream = stream_entry->second.get(); - existing_stream->nominal_cp_duration = parameters.nominal_cp_duration; - } - - return util::OkStatus(); -} - -util::Status Ecmg::ProcessCwProvisionMessage(const char* message, - size_t message_length, - std::string* response) { - DCHECK(message); - DCHECK(response); - - EcmgParameters parameters; - util::Status status = ProcessParameters(message, message_length, ¶meters); - if (!status.ok()) { - return status; - } - if (parameters.ecm_channel_id == 0 || parameters.ecm_stream_id == 0 || - parameters.cp_number == 0 || parameters.cw_per_msg == 0) { - return util::Status(util::error::INVALID_ARGUMENT, - "Missing required parameter"); - } - - // TODO(user): Figure out what to do with ECM_channel_ID and ECM_stream_ID. - // - We certainly need to check the channel/stream has been setup - // - Retrieve config parameters such as lead_CW and CW_per_msg - // - In some config, we need to keep CW for previous CP to be included in the - // current ECM - // TODO(user): Remove debug loop below. - for (int i = 0; i < 3; i++) { - for (int j = 0; j < parameters.cp_cw_combinations[i].cw.size(); j++) { - printf("%x ", - static_cast(parameters.cp_cw_combinations[i].cw[j])); - } - std::cout << std::endl; - } - - bool key_rotation_enabled = parameters.cw_per_msg > 1; - - // Create an instance of CasEcm in order to set the entitlement keys. - // TODO(user): The section of code below for constructing CasEcm should - // be optimized. There should be a single instance of CasEcm for each stream. - // Right now, this is hard to do because CasEcmGenerator contains the CasEcm. - std::unique_ptr ecm = absl::make_unique(); - // TODO(user): Revisit this hardcoded ecm_init_params. - EcmInitParameters ecm_init_params; - ecm_init_params.content_iv_size = kIvSize8; - ecm_init_params.key_rotation_enabled = key_rotation_enabled; - // TODO(user): Allow caller to specify the crypto mode. - ecm_init_params.crypto_mode = CryptoMode::kAesCtr; - // Only encrypt one video track. - ecm_init_params.track_types.push_back(kDefaultTrackTypeSd); - std::string entitlement_request; - std::string entitlement_response; - // 'content_id' and 'provider' are used in entitlement key request/response - // only, NOT needed for generating ECM. - // So for initial demo, we can just use hardcoded value because we are using - // hardcoded entitlement key anyway. - // TODO(user): When we want to retrieve entitlement key from License Server - // we need to figure out a way to provide real 'content_id' and 'provder' - // to this function here from the Simulcrypt API. - if (!(status = ecm->Initialize(kDefaultContentId, kDefaultProvider, - ecm_init_params, &entitlement_request)) - .ok()) { - return status; - } - if (!(status = fixed_key_fetcher_.RequestEntitlementKey( - entitlement_request, &entitlement_response)) - .ok()) { - return status; - } - if (!(status = ecm->ProcessCasEncryptionResponse(entitlement_response)) - .ok()) { - return status; - } - - CasEcmGenerator ecm_generator; - ecm_generator.set_ecm(std::move(ecm)); - EcmParameters ecm_param; - ecm_param.rotation_enabled = key_rotation_enabled; - for (int i = 0; i <= parameters.cw_per_msg; i++) { - ecm_param.key_params.emplace_back(); - ecm_param.key_params[i].key_data = parameters.cp_cw_combinations[i].cw; - // TODO(user): MUST have a better way to derive/retrieve key_id. - // Currently set it to be the same as the key itself just for demo purpose. - ecm_param.key_params[i].key_id = ecm_param.key_params[i].key_data; - // TODO(user): MUST have a better way to generate/retrieve content_iv. - ecm_param.key_params[i].content_ivs.push_back( - std::string(kDefaultContentIv8Bytes)); - } - std::string serialized_ecm = ecm_generator.GenerateEcm(ecm_param); - std::cout << "serialized_ecm: " << serialized_ecm << std::endl; - for (int i = 0; i < serialized_ecm.size(); i++) { - printf("'\\x%x', ", static_cast(serialized_ecm.at(i))); - } - std::cout << std::endl; - LOG(INFO) << "ECM size: " << serialized_ecm.size(); - return util::OkStatus(); -} - -} // namespace cas -} // namespace widevine diff --git a/media_cas_packager_sdk/internal/ecmg.h b/media_cas_packager_sdk/internal/ecmg.h deleted file mode 100644 index 8c2bf7f..0000000 --- a/media_cas_packager_sdk/internal/ecmg.h +++ /dev/null @@ -1,94 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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_INTERNAL_ECMG_H_ -#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "common/status.h" -#include "media_cas_packager_sdk/internal/ecm.h" -#include "media_cas_packager_sdk/internal/fixed_key_fetcher.h" - -namespace widevine { -namespace cas { - -// A struct that represent a CP_CW_Combination. -struct EcmgCpCwCombination { - uint16_t cp = 0; // crypto period - std::string cw; // control word -}; - -// A struct that is used to hold all possible parameters for a ECMG message. -struct EcmgParameters { - // Default value of 0 for fields below is usually considered invalid. - // Hence checking against 0 is used to detect whether each parameter - // is set in the message. - uint8_t cw_per_msg = 0; - uint16_t ecm_channel_id = 0; - uint16_t ecm_stream_id = 0; - uint16_t nominal_cp_duration = 0; - uint16_t cp_number = 0; // crypto period number - uint16_t cp_duration = 0; // crypto period duration - // CW_per_msg could 1, 2, or 3, - // so there can be up to 3 CP_CW_Combinations - EcmgCpCwCombination cp_cw_combinations[3]; -}; - -// A struct that holds information about a ECMG stream within a channel. -struct EcmgStream { - uint16_t nominal_cp_duration = 0; -}; - -// A struct that holds information about a ECMG channel. -struct EcmgChannel { - // Map from ECM_stream_ID to an instance of EcmgStream. - std::map> streams; -}; - -// A class that process Simulcrypt ECMG messages. -// This class is NOT thread-safe. -class Ecmg { - public: - Ecmg() = default; - Ecmg(const Ecmg&) = delete; - Ecmg& operator=(const Ecmg&) = delete; - virtual ~Ecmg() = default; - - // Process |message| of length |message_length|. - // |message| is expected to be a Stream_set-up message. - // Any error during processing would be turned via util::Status. - util::Status ProcessStreamSetupMessage(const char* message, - size_t message_length); - - // Process |message| of length |message_length|. - // |message| is expected to be a CW_provision request message. - // ECM_response response message will be returned via |response|. - // Any error during processing would be turned via util::Status. - util::Status ProcessCwProvisionMessage(const char* message, - size_t message_length, - std::string* response); - - private: - // Keep track of all the channels. - std::map> channels_; - FixedKeyFetcher fixed_key_fetcher_; -}; - -} // namespace cas -} // namespace widevine - -#endif // MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_H_ diff --git a/media_cas_packager_sdk/internal/ecmg_client_handler.cc b/media_cas_packager_sdk/internal/ecmg_client_handler.cc new file mode 100644 index 0000000..59b1b51 --- /dev/null +++ b/media_cas_packager_sdk/internal/ecmg_client_handler.cc @@ -0,0 +1,619 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2018 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/internal/ecmg_client_handler.h" + +#include +#include +#include +#include +#include +#include + +#include "glog/logging.h" +#include "absl/memory/memory.h" +#include "absl/strings/str_cat.h" +#include "common/crypto_util.h" +#include "example/constants.h" +#include "media_cas_packager_sdk/internal/ecm_generator.h" +#include "media_cas_packager_sdk/internal/ecmg_constants.h" +#include "media_cas_packager_sdk/internal/mpeg2ts.h" +#include "media_cas_packager_sdk/internal/util.h" +#include "media_cas_packager_sdk/public/wv_cas_ecm.h" +#include "media_cas_packager_sdk/public/wv_cas_types.h" + +// '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. +// TODO(user): Understand the difference between the two formats. +static constexpr uint8_t kSectionTSpktFlag = 0x01; +// 'max_stream' parameter defines the max number of simultaneous opened streams +// suppported by an ECMG on a channel. +// A value of 0 means that this maximum is not known. +static constexpr uint16_t kMaxStream = 0; +// 'lead_CW' parameter defines the number of contro lwords required in +// advance to build an ECM. +// TODO(user): Support other values of 'lead_CW' in combination with +// other values for 'CW_per_msg'. +static constexpr uint8_t kLeadCw = 1; +// ' CW_per_msg' parameter defines the number of control words needed by the +// ECMG per control word provision message. +static constexpr uint8_t kCwPerMsg = 2; + +namespace widevine { +namespace cas { + +namespace { + +// Local helper function that processes all the params in an ECMG request. +Status HandleParameters(const char* const request, size_t request_length, + EcmgParameters* params) { + DCHECK(request); + DCHECK(params); + uint16_t param_type; + uint16_t param_length; + // 'offset' is used to track where we are within |request|. + size_t offset = 0; + // There could be CW_per_msg instances of CP_CW_combinations, + // so we need to track how many we have processed so far + // in order to know where to store the next CP_CW_combination. + int current_cp_cw_combination_index = 0; + while (offset != request_length) { + BigEndianToHost16(¶m_type, request + offset); + offset += PARAMETER_TYPE_SIZE; + BigEndianToHost16(¶m_length, request + offset); + offset += PARAMETER_LENGTH_SIZE; + switch (param_type) { + case ACCESS_CRITERIA: { + LOG(WARNING) << "Ignoring access_criteria parameter of " << param_length + << " bytes long"; + offset += param_length; + break; + } + case CP_CW_COMBINATION: { + if (current_cp_cw_combination_index > 2) { + // We can have at most 3 CP_CW_Combinations. + return Status(error::INVALID_ARGUMENT, + "We only support up to 2 control words in the " + "CW_provision request"); + } + EcmgCpCwCombination* combination = + ¶ms->cp_cw_combinations[current_cp_cw_combination_index++]; + BigEndianToHost16(&combination->cp, request + offset); + offset += CP_SIZE; + size_t cw_size = param_length - CP_SIZE; + combination->cw = std::string(request + offset, cw_size); + offset += cw_size; + // TODO(user): This is a temporary hack to let the ECM generator + // know how many keys to include in the ECM. + // CW_per_msg should have been set during channel set-up instead. + params->cw_per_msg = current_cp_cw_combination_index; + break; + } + case CP_DURATION: { + if (param_length != CP_DURATION_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost16(¶ms->cp_duration, request + offset); + offset += param_length; + break; + } + case CP_NUMBER: { + if (param_length != CP_NUMBER_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost16(¶ms->cp_number, request + offset); + offset += param_length; + break; + } + case CW_ENCRYPTION: { + LOG(WARNING) << "Ignoring CW_encryption parameter of " << param_length + << " bytes long"; + offset += param_length; + break; + } + case ECM_CHANNEL_ID: { + if (param_length != ECM_CHANNEL_ID_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost16(¶ms->ecm_channel_id, request + offset); + offset += param_length; + break; + } + case ECM_ID: { + if (param_length != ECM_ID_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost16(¶ms->ecm_id, request + offset); + offset += param_length; + break; + } + case ECM_STREAM_ID: { + if (param_length != ECM_STREAM_ID_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost16(¶ms->ecm_stream_id, request + offset); + offset += param_length; + break; + } + case NOMINAL_CP_DURATION: { + if (param_length != NOMINAL_CP_DURATION_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost16(¶ms->nominal_cp_duration, request + offset); + offset += param_length; + break; + } + case SUPER_CAS_ID: { + if (param_length != SUPER_CAS_ID_SIZE) { + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Invalid parameter length ", param_length, + " for parameter type ", param_type)); + } + BigEndianToHost32(¶ms->super_cas_id, request + offset); + offset += param_length; + break; + } + default: { + return Status( + error::UNIMPLEMENTED, + absl::StrCat("No implementation yet to process parameter of type ", + param_type)); + break; + } + } + } + return OkStatus(); +} + +// Add 'protocol_version', 'message_type', 'message_length' to the message. +// TODO(user): Per jfore@, consider pass in a pointer to a structure +// #pragma pack(push, 1) // exact fit - no padding +// struct MessageHeader{ +// uint8_t protocol_version; +// uint16_t message_type; +// uint16_t message_length; +// }; +// #pragma pack(pop) // restore previous pack +void BuildMessageHeader(uint16_t message_type, char* message, + size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + *message_length = 0; + message[*message_length] = ECMG_SCS_PROTOCOL_VERSION; + *message_length += PROTOCOL_VERSION_SIZE; + Host16ToBigEndian(message + *message_length, &message_type); + *message_length += MESSAGE_TYPE_SIZE; + // NOTE: 'message_length' needs to be updated later after we have added all + // the params so we know the exact length of the all the params. + // Use 0 for 'total_param_length' until we know the length of the message. + uint16_t total_param_length = 0; + Host16ToBigEndian(message + *message_length, &total_param_length); + *message_length += MESSAGE_LENGTH_SIZE; +} + +// Add a uint16_t parameter to the message. +void AddUint16Param(uint16_t param_type, uint16_t param_value, char* message, + size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + Host16ToBigEndian(message + *message_length, ¶m_type); + *message_length += 2; + uint16_t param_length = 2; + Host16ToBigEndian(message + *message_length, ¶m_length); + *message_length += 2; + Host16ToBigEndian(message + *message_length, ¶m_value); + *message_length += param_length; +} + +// Add a uint8_t parameter to the message. +void AddUint8Param(uint16_t param_type, uint8_t param_value, char* message, + size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + Host16ToBigEndian(message + *message_length, ¶m_type); + *message_length += 2; + uint16_t param_length = 1; + Host16ToBigEndian(message + *message_length, ¶m_length); + *message_length += 2; + memcpy(message + *message_length, ¶m_value, param_length); + *message_length += param_length; +} + +// Add a param that is |param_length| bytes long. +void AddParam(uint16_t param_type, uint8_t* param_value, uint16_t param_length, + char* message, size_t* message_length) { + DCHECK(param_value); + DCHECK(message); + DCHECK(message_length); + Host16ToBigEndian(message + *message_length, ¶m_type); + *message_length += 2; + Host16ToBigEndian(message + *message_length, ¶m_length); + *message_length += 2; + memcpy(message + *message_length, param_value, param_length); + *message_length += param_length; +} + +void BuildChannelError(uint16_t channel_id, uint16_t error_status, char* message, + size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + BuildMessageHeader(ECMG_CHANNEL_ERROR, message, message_length); + AddUint16Param(ECM_CHANNEL_ID, channel_id, message, message_length); + AddUint16Param(ERROR_STATUS, error_status, message, message_length); + // No setting Error_information parameter yet. + uint16_t total_param_length = *message_length - 5; + Host16ToBigEndian(message + 3, &total_param_length); +} + +void BuildChannelStatus(uint16_t channel_id, EcmgConfig* config, char* message, + size_t* message_length) { + DCHECK(config); + DCHECK(message); + DCHECK(message_length); + BuildMessageHeader(ECMG_CHANNEL_STATUS, message, message_length); + AddUint16Param(ECM_CHANNEL_ID, channel_id, message, message_length); + AddUint8Param(SECTION_TSPKT_FLAG, kSectionTSpktFlag, message, message_length); + // No setting AC_delay_start parameter yet. + // No setting AC_delay_stop parameter yet. + AddUint16Param(DELAY_START, config->delay_start, message, message_length); + AddUint16Param(DELAY_STOP, config->delay_stop, message, message_length); + // No setting transition_delay_start parameter yet. + // No setting transition_delay_stop parameter yet. + AddUint16Param(ECM_REP_PERIOD, config->ecm_rep_period, message, + message_length); + AddUint16Param(MAX_STREAMS, kMaxStream, message, message_length); + // min_CP_duration needs to be at least max_comp_time. So we just use + // max_comp_time here for now. + AddUint16Param(MIN_CP_DURATION, config->max_comp_time, message, + message_length); + AddUint8Param(LEAD_CW, kLeadCw, message, message_length); + AddUint8Param(CW_PER_MESSAGE, kCwPerMsg, message, message_length); + AddUint16Param(MAX_COMP_TIME, config->max_comp_time, message, message_length); + uint16_t total_param_length = *message_length - 5; + Host16ToBigEndian(message + 3, &total_param_length); +} + +void BuildStreamError(uint16_t channel_id, uint16_t stream_id, uint16_t error_status, + char* message, size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + BuildMessageHeader(ECMG_STREAM_ERROR, message, message_length); + AddUint16Param(ECM_CHANNEL_ID, channel_id, message, message_length); + AddUint16Param(ECM_STREAM_ID, stream_id, message, message_length); + AddUint16Param(ERROR_STATUS, error_status, message, message_length); + // No setting Error_information parameter yet. + uint16_t total_param_length = *message_length - 5; + Host16ToBigEndian(message + 3, &total_param_length); +} + +void BuildStreamStatus(uint16_t channel_id, uint16_t stream_id, uint16_t ecm_id, + uint8_t access_criteria_transfer_mode, char* message, + size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + BuildMessageHeader(ECMG_STREAM_STATUS, message, message_length); + AddUint16Param(ECM_CHANNEL_ID, channel_id, message, message_length); + AddUint16Param(ECM_STREAM_ID, stream_id, message, message_length); + AddUint16Param(ECM_ID, ecm_id, message, message_length); + AddUint8Param(ACCESS_CRITERIA_TRANSFER_MODE, access_criteria_transfer_mode, + message, message_length); + uint16_t total_param_length = *message_length - 5; + Host16ToBigEndian(message + 3, &total_param_length); +} + +void BuildStreamCloseResponse(uint16_t channel_id, uint16_t stream_id, + char* message, size_t* message_length) { + DCHECK(message); + DCHECK(message_length); + BuildMessageHeader(ECMG_STREAM_CLOSE_RESPONSE, message, message_length); + AddUint16Param(ECM_CHANNEL_ID, channel_id, message, message_length); + AddUint16Param(ECM_STREAM_ID, stream_id, message, message_length); + uint16_t total_param_length = *message_length - 5; + Host16ToBigEndian(message + 3, &total_param_length); +} + +void BuildEcmResponse(uint16_t channel_id, uint16_t stream_id, uint16_t cp_number, + uint8_t* ecm_datagram, char* message, + size_t* message_length) { + DCHECK(ecm_datagram); + DCHECK(message); + DCHECK(message_length); + BuildMessageHeader(ECMG_ECM_RESPONSE, message, message_length); + AddUint16Param(ECM_CHANNEL_ID, channel_id, message, message_length); + AddUint16Param(ECM_STREAM_ID, stream_id, message, message_length); + AddUint16Param(CP_NUMBER, cp_number, message, message_length); + AddParam(ECM_DATAGRAM, ecm_datagram, kTsPacketSize, message, message_length); + uint16_t total_param_length = *message_length - 5; + Host16ToBigEndian(message + 3, &total_param_length); +} + +} // namespace + +EcmgClientHandler::EcmgClientHandler(EcmgConfig* ecmg_config) { + DCHECK(ecmg_config); + ecmg_config_ = ecmg_config; + channel_id_set_ = false; +} + +void EcmgClientHandler::HandleRequest(const char* const request, char* response, + size_t* response_length) { + DCHECK(request); + DCHECK(response); + + uint8_t protocol_version; + uint16_t request_type; + uint16_t request_length; + // 'offset' is used to track where we are within |request|. + size_t offset = 0; + memcpy(&protocol_version, request, PROTOCOL_VERSION_SIZE); + if (protocol_version != ECMG_SCS_PROTOCOL_VERSION) { + // TODO(user): Should send an error response. + return; + } + offset += PROTOCOL_VERSION_SIZE; + BigEndianToHost16(&request_type, request + offset); + offset += MESSAGE_TYPE_SIZE; + BigEndianToHost16(&request_length, request + offset); + offset += MESSAGE_LENGTH_SIZE; + EcmgParameters params; + Status status = HandleParameters(request + offset, request_length, ¶ms); + if (!status.ok()) { + // TODO(user): Should send an error response. + return; + } + switch (request_type) { + case ECMG_CHANNEL_SETUP: { + HandleChannelSetup(params, response, response_length); + break; + } + case ECMG_CHANNEL_CLOSE: { + HandleChannelClose(params, response, response_length); + break; + } + case ECMG_STREAM_SETUP: { + HandleStreamSetup(params, response, response_length); + break; + } + case ECMG_STREAM_CLOSE_REQUEST: { + HandleStreamCloseRequest(params, response, response_length); + break; + } + case ECMG_CW_PROVISION: { + HandleCwProvision(params, response, response_length); + break; + } + default: { + // Unhandled or unknown request types. + break; + } + } +} + +void EcmgClientHandler::HandleChannelSetup(const EcmgParameters& params, + char* response, + size_t* response_length) { + DCHECK(response); + DCHECK(response_length); + // TODO(user): Check SUPER_CAS_ID, if it is unexpected, return + // UNKNOWN_SUPER_CAS_ID_VALUE error. + if (channel_id_set_) { + BuildChannelError(params.ecm_channel_id, INVAID_MESSAGE, response, + response_length); + return; + } + // TODO(user): To support multi-threading of serving concurrent clients, + // there needs to be a set of channel_ids shared by multiple client handlers + // threads. + // And here we need to check if the channel_id is already in the set, if + // yes, return an error. + channel_id_ = params.ecm_channel_id; + channel_id_set_ = true; + BuildChannelStatus(params.ecm_channel_id, ecmg_config_, response, + response_length); +} + +void EcmgClientHandler::HandleChannelClose(const EcmgParameters& params, + char* response, + size_t* response_length) { + DCHECK(response); + DCHECK(response_length); + if (channel_id_ != params.ecm_channel_id) { + BuildStreamError(params.ecm_channel_id, params.ecm_stream_id, + UNKNOWN_ECM_CHANNEL_ID_VALUE, response, response_length); + return; + } + channel_id_set_ = false; + streams_.clear(); + *response_length = 0; +} + +void EcmgClientHandler::HandleStreamSetup(const EcmgParameters& params, + char* response, + size_t* response_length) { + DCHECK(response); + DCHECK(response_length); + if (channel_id_ != params.ecm_channel_id) { + BuildStreamError(params.ecm_channel_id, params.ecm_stream_id, + UNKNOWN_ECM_CHANNEL_ID_VALUE, response, response_length); + return; + } + // TODO(user): To support multi-threading of serving concurrent clients, + // there needs to be a set of stream_ids shared by multiple client handlers + // threads. + // And here we need to check if the stream_id is already in the set, if + // yes, return an error. + if (streams_.count(params.ecm_stream_id) > 0) { + BuildStreamError(params.ecm_channel_id, params.ecm_stream_id, + ECM_STREAM_ID_VALUE_ALREADY_IN_USE, response, + response_length); + return; + } + // TODO(user): What do I do with the ECM_id here, currently not doing + // anything with it? + streams_[params.ecm_stream_id] = params.ecm_id; + BuildStreamStatus(params.ecm_channel_id, params.ecm_stream_id, params.ecm_id, + ecmg_config_->access_criteria_transfer_mode, response, + response_length); +} + +void EcmgClientHandler::HandleStreamCloseRequest(const EcmgParameters& params, + char* response, + size_t* response_length) { + DCHECK(response); + DCHECK(response_length); + if (channel_id_ != params.ecm_channel_id) { + BuildStreamError(params.ecm_channel_id, params.ecm_stream_id, + UNKNOWN_ECM_CHANNEL_ID_VALUE, response, response_length); + return; + } + if (streams_.count(params.ecm_stream_id) == 0) { + BuildStreamError(params.ecm_channel_id, params.ecm_stream_id, + UNKNOWN_ECM_STREAM_ID_VALUE, response, response_length); + return; + } + streams_.erase(params.ecm_stream_id); + BuildStreamCloseResponse(params.ecm_channel_id, params.ecm_stream_id, + response, response_length); +} + +void EcmgClientHandler::HandleCwProvision(const EcmgParameters& params, + char* response, + size_t* response_length) { + DCHECK(response); + DCHECK(response_length); + if (channel_id_ != params.ecm_channel_id) { + BuildChannelError(params.ecm_channel_id, UNKNOWN_ECM_CHANNEL_ID_VALUE, + response, response_length); + return; + } + if (streams_.count(params.ecm_stream_id) == 0) { + BuildChannelError(params.ecm_channel_id, UNKNOWN_ECM_STREAM_ID_VALUE, + response, response_length); + return; + } + if (params.cw_per_msg < kCwPerMsg) { + BuildChannelError(params.ecm_channel_id, + NOT_ENOUGH_CONTROL_WORDS_TO_COMPUTE_ECM, response, + response_length); + return; + } + uint8_t ecm_datagram[kTsPacketSize]; + BuildEcmDatagram(params, ecm_datagram); + BuildEcmResponse(params.ecm_channel_id, params.ecm_stream_id, + params.cp_number, ecm_datagram, response, response_length); +} + +void EcmgClientHandler::BuildEcmDatagram(const EcmgParameters& params, + uint8_t* ecm_datagram) { + DCHECK(ecm_datagram); + // TODO(user): Remove debug loop below. + for (int i = 0; i < 3; i++) { + std::cout << "CW: "; + for (int j = 0; j < params.cp_cw_combinations[i].cw.size(); j++) { + printf("'\\x%02x', ", + static_cast(params.cp_cw_combinations[i].cw[j])); + } + std::cout << std::endl; + } + + // Step 1: Generate entitlement keys. + bool key_rotation_enabled = params.cw_per_msg > 1; + // Create an instance of CasEcm in order to set the entitlement keys. + // TODO(user): The section of code below for constructing CasEcm should + // be optimized. There should be a single instance of CasEcm for each stream. + // Right now, this is hard to do because CasEcmGenerator contains the CasEcm. + std::unique_ptr ecm = absl::make_unique(); + // TODO(user): Revisit this hardcoded ecm_init_params. + EcmInitParameters ecm_init_params; + ecm_init_params.content_iv_size = kIvSize8; + ecm_init_params.key_rotation_enabled = key_rotation_enabled; + // TODO(user): Allow crypto mode to be set to different value? Via flag? + ecm_init_params.crypto_mode = CryptoMode::kDvbCsa2; + // Only encrypt one video track. + // TODO(user): Support multiple tracks? How? + ecm_init_params.track_types.push_back(kDefaultTrackTypeSd); + std::string entitlement_request; + std::string entitlement_response; + // 'content_id' and 'provider' are used in entitlement key request/response + // only, NOT needed for generating ECM. + // So for initial demo, we can just use hardcoded value because we are using + // hardcoded entitlement key anyway. + // TODO(user): When we want to retrieve entitlement key from License Server + // we need to figure out a way to provide real 'content_id' and 'provder' + // to this function here from the Simulcrypt API. + Status status; + if (!(status = ecm->Initialize(kDefaultContentId, kDefaultProvider, + ecm_init_params, &entitlement_request)) + .ok()) { + // TODO(user): Should send an error response. + return; + } + if (!(status = fixed_key_fetcher_.RequestEntitlementKey( + entitlement_request, &entitlement_response)) + .ok()) { + // TODO(user): Should send an error Channel_status. + return; + } + if (!(status = ecm->ProcessCasEncryptionResponse(entitlement_response)) + .ok()) { + // TODO(user): Should send an error Channel_status. + return; + } + + // Step 2: Generate serialized ECM. + CasEcmGenerator ecm_generator; + ecm_generator.set_ecm(std::move(ecm)); + EcmParameters ecm_param; + ecm_param.rotation_enabled = key_rotation_enabled; + for (int i = 0; i <= params.cw_per_msg; i++) { + ecm_param.key_params.emplace_back(); + ecm_param.key_params[i].key_data = params.cp_cw_combinations[i].cw; + ecm_param.key_params[i].key_id = widevine::crypto_util::DeriveKeyId( + ecm_param.key_params[i].key_data); + // TODO(user): How to derive this content_iv, maybe based on key? + std::string content_iv = "12345678"; + ecm_param.key_params[i].content_ivs.push_back(content_iv); + } + std::string serialized_ecm = ecm_generator.GenerateEcm(ecm_param); + std::cout << "serialized_ecm: " << serialized_ecm << std::endl; + for (int i = 0; i < serialized_ecm.size(); i++) { + printf("'\\x%x', ", static_cast(serialized_ecm.at(i))); + } + std::cout << std::endl; + LOG(INFO) << "ECM size: " << serialized_ecm.size(); + + // Step 3: Make a TS packet carrying the serialized ECM. + // TODO(user): Is it correct to set 'pid' using ECM_id? + // TODO(user): Where do I get the continuity_counter? + uint8_t continuity_counter = 0; + WvCasEcm wv_cas_ecm; + WvCasStatus cas_status = wv_cas_ecm.GenerateTsPacket( + serialized_ecm, params.ecm_id, + params.cp_number % 2 == 0 ? kTsPacketTableId80 : kTsPacketTableId81, + &continuity_counter, ecm_datagram); + if (cas_status != OK) { + // TODO(user): Should send an error Channel_status. + return; + } +} + +} // namespace cas +} // namespace widevine diff --git a/media_cas_packager_sdk/internal/ecmg_client_handler.h b/media_cas_packager_sdk/internal/ecmg_client_handler.h new file mode 100644 index 0000000..9095e6d --- /dev/null +++ b/media_cas_packager_sdk/internal/ecmg_client_handler.h @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2018 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_INTERNAL_ECMG_CLIENT_HANDLER_H_ +#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_CLIENT_HANDLER_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "common/status.h" +#include "media_cas_packager_sdk/internal/ecm.h" +#include "media_cas_packager_sdk/internal/fixed_key_fetcher.h" + +namespace widevine { +namespace cas { + +// A struct that captures the Ecmg configs. +struct EcmgConfig { + int16_t delay_start; + int16_t delay_stop; + uint16_t ecm_rep_period; + uint16_t max_comp_time; + uint8_t access_criteria_transfer_mode; +}; + +// A struct that represent a CP_CW_Combination. +struct EcmgCpCwCombination { + uint16_t cp; // crypto period + std::string cw; // control word +}; + +// A struct that is used to hold all possible params for a ECMG request. +struct EcmgParameters { + // CW_per_msg could 1, 2, or 3, + // so there can be up to 3 CP_CW_Combinations + EcmgCpCwCombination cp_cw_combinations[3]; + uint16_t cp_duration; // crypto period duration + uint16_t cp_number; // crypto period number + uint8_t cw_per_msg; + uint16_t ecm_channel_id; + uint16_t ecm_stream_id; + uint16_t ecm_id; + uint16_t nominal_cp_duration; + uint32_t super_cas_id; +}; + +// A class that handles one (and only one) ECMG client. +// This class is NOT thread-safe. +class EcmgClientHandler { + public: + explicit EcmgClientHandler(EcmgConfig* ecmg_config); + EcmgClientHandler(const EcmgClientHandler&) = delete; + EcmgClientHandler& operator=(const EcmgClientHandler&) = delete; + virtual ~EcmgClientHandler() = default; + + // Handle a |request| from the client. + // If any response is generated, it would returned via |response| + // and |response_length|. + void HandleRequest(const char* const request, char* response, + size_t* response_length); + + private: + void HandleChannelSetup(const EcmgParameters& params, char* response, + size_t* response_length); + // TODO(user): HandleChannelTest() + void HandleChannelClose(const EcmgParameters& params, char* response, + size_t* response_length); + void HandleStreamSetup(const EcmgParameters& params, char* response, + size_t* response_length); + // TODO(user): HandleStreamTest() + void HandleStreamCloseRequest(const EcmgParameters& params, char* response, + size_t* response_length); + void HandleCwProvision(const EcmgParameters& params, char* response, + size_t* response_length); + void BuildEcmDatagram(const EcmgParameters& params, uint8_t* ecm_datagram); + + EcmgConfig* ecmg_config_; + // Per spec, "There is always one (and only one) channel per TCP connection". + bool channel_id_set_; + uint16_t channel_id_; + // Map from ECM_stream_id to ECM_id. + std::unordered_map streams_; + FixedKeyFetcher fixed_key_fetcher_; +}; + +} // namespace cas +} // namespace widevine + +#endif // MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_CLIENT_HANDLER_H_ diff --git a/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc b/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc new file mode 100644 index 0000000..3220d90 --- /dev/null +++ b/media_cas_packager_sdk/internal/ecmg_client_handler_test.cc @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2018 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/internal/ecmg_client_handler.h" + +#include + +#include "testing/gmock.h" +#include "testing/gunit.h" +#include "absl/memory/memory.h" +#include "example/test_ecmg_messages.h" + +namespace widevine { +namespace cas { +namespace { + +#define BUFFER_SIZE (1024) + +class EcmgClientHandlerTest : public ::testing::Test { + protected: + EcmgClientHandlerTest() { + config_.delay_start = 200; + config_.delay_stop = 200; + config_.ecm_rep_period = 100; + config_.max_comp_time = 100; + config_.access_criteria_transfer_mode = 1; + client_handler_ = absl::make_unique(&config_); + } + + protected: + // Helper function for debugging the tests. + void PrintMessage(const std::string &description, const char *const message, + size_t length) { + printf("%s ", description.c_str()); + fflush(stdout); + for (size_t i = 0; i < length; i++) { + printf("'\\x%02x', ", static_cast(*(message + i))); + fflush(stdout); + } + printf("\n"); + fflush(stdout); + } + + EcmgConfig config_; + std::unique_ptr client_handler_; +}; + +// TODO(user): Add unit tests for error cases. + +TEST_F(EcmgClientHandlerTest, SuccessSequence) { + char response[BUFFER_SIZE]; + size_t response_length; + + client_handler_->HandleRequest(kTestChannelSetup, response, &response_length); + EXPECT_EQ(62, response_length); + EXPECT_EQ(0, memcmp(kTestChannelStatus, response, response_length)); + + client_handler_->HandleRequest(kTestStreamSetup, response, &response_length); + EXPECT_EQ(28, response_length); + EXPECT_EQ(0, memcmp(kTestStreamStatus, response, response_length)); + + client_handler_->HandleRequest(kTestCwProvision, response, &response_length); + EXPECT_EQ(215, response_length); + // Only comparing the bytes in front of the ECM_datagram, because + // random wrapping IV is generated each time causing the ECM_datagram + // to be non-deterministic. + EXPECT_EQ(0, memcmp(kTestEcmResponse, response, 27)); + + client_handler_->HandleRequest(kTestStreamCloseRequest, response, + &response_length); + EXPECT_EQ(17, response_length); + EXPECT_EQ(0, memcmp(kTestStreamCloseResponse, response, response_length)); + + client_handler_->HandleRequest(kTestChannelClose, response, &response_length); + EXPECT_EQ(0, response_length); +} + +} // namespace +} // namespace cas +} // namespace widevine diff --git a/media_cas_packager_sdk/internal/ecmg_constants.h b/media_cas_packager_sdk/internal/ecmg_constants.h index e5bd773..618021a 100644 --- a/media_cas_packager_sdk/internal/ecmg_constants.h +++ b/media_cas_packager_sdk/internal/ecmg_constants.h @@ -9,45 +9,95 @@ #ifndef MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_CONSTANTS_H_ #define MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_CONSTANTS_H_ -// ECMG <> SCS -// Parameter_type values -#define DVB_RESERVED 0x0000 -#define SUPER_CAS_ID 0x0001 -#define SECTION_TSPKT_FLAG 0x0002 -#define DELAY_START 0x0003 -#define DELAY_STOP 0x0004 -#define TRANSITION_DELAY_START 0x0005 -#define TRANSITION_DELAY_STOP 0x0006 -#define ECM_REP_PERIOD 0x0007 -#define MAX_STREAMS 0x0008 -#define MIN_CP_DURATION 0x0009 -#define LEAD_CW 0x000A -#define CW_PER_MESSAGE 0x000B -#define MAX_COMP_TIME 0x000C -#define ACCESS_CRITERIA 0x000D -#define ECM_CHANNEL_ID 0x000E -#define ECM_STREAM_ID 0x000F -#define NOMINAL_CP_DURATION 0x0010 -#define ACCESS_CRITERIA_TRANSFER_MODE 0x0011 -#define CP_NUMBER 0x0012 -#define CP_DURATION 0x0013 -#define CP_CW_COMBINATION 0x0014 -#define ECM_DATAGRAM 0x0015 -#define AC_DELAY_START 0x0016 -#define AC_DELAY_STOP 0x0017 -#define CW_ENCRYPTION 0x0018 -#define ECM_ID 0x0019 -#define ERROR_STATUS 0x7000 -#define ERROR_INFORMATION 0x7001 +// ECMG <=> SCS protocol_version. +#define ECMG_SCS_PROTOCOL_VERSION (0x03) + +// ECMG message type values. +// 0x0000 DVB reserved. +#define ECMG_CHANNEL_SETUP (0x0001) +#define ECMG_CHANNEL_TEST (0x0002) +#define ECMG_CHANNEL_STATUS (0x0003) +#define ECMG_CHANNEL_CLOSE (0x0004) +#define ECMG_CHANNEL_ERROR (0x0005) +// 0x0016 - 0x0100 DVB reserved. +#define ECMG_STREAM_SETUP (0x0101) +#define ECMG_STREAM_TEST (0x0102) +#define ECMG_STREAM_STATUS (0x0103) +#define ECMG_STREAM_CLOSE_REQUEST (0x0104) +#define ECMG_STREAM_CLOSE_RESPONSE (0x0105) +#define ECMG_STREAM_ERROR (0x0106) +// 0x0119 - 0x0200 DVB reserved. +#define ECMG_CW_PROVISION (0x0201) +#define ECMG_ECM_RESPONSE (0x0202) + +// ECMG parameter type values. +#define DVB_RESERVED (0x0000) +#define SUPER_CAS_ID (0x0001) +#define SECTION_TSPKT_FLAG (0x0002) +#define DELAY_START (0x0003) +#define DELAY_STOP (0x0004) +#define TRANSITION_DELAY_START (0x0005) +#define TRANSITION_DELAY_STOP (0x0006) +#define ECM_REP_PERIOD (0x0007) +#define MAX_STREAMS (0x0008) +#define MIN_CP_DURATION (0x0009) +#define LEAD_CW (0x000A) +#define CW_PER_MESSAGE (0x000B) +#define MAX_COMP_TIME (0x000C) +#define ACCESS_CRITERIA (0x000D) +#define ECM_CHANNEL_ID (0x000E) +#define ECM_STREAM_ID (0x000F) +#define NOMINAL_CP_DURATION (0x0010) +#define ACCESS_CRITERIA_TRANSFER_MODE (0x0011) +#define CP_NUMBER (0x0012) +#define CP_DURATION (0x0013) +#define CP_CW_COMBINATION (0x0014) +#define ECM_DATAGRAM (0x0015) +#define AC_DELAY_START (0x0016) +#define AC_DELAY_STOP (0x0017) +#define CW_ENCRYPTION (0x0018) +#define ECM_ID (0x0019) +#define ERROR_STATUS (0x7000) +#define ERROR_INFORMATION (0x7001) + +// ECMG protocol error values. +#define INVAID_MESSAGE (0x0001) +#define UNSUPPORTED_PROTOCOL_VERSION (0X0002) +#define UNKNOWN_MESSAGE_TYPE_VALUE (0X0003) +#define MESSAGE_TOO_LONG (0X0004) +#define UNKNOWN_SUPER_CAS_ID_VALUE (0X0005) +#define UNKNOWN_ECM_CHANNEL_ID_VALUE (0X0006) +#define UNKNOWN_ECM_STREAM_ID_VALUE (0X0007) +#define TOO_MANY_CHANNELS_ON_THIS_ECMG (0X0008) +#define TOO_MANY_ECM_STREAMS_ON_THIS_CHANNEL (0X0009) +#define TOO_MANY_ECM_STREAMS_ON_THIS_ECMG (0X000A) +#define NOT_ENOUGH_CONTROL_WORDS_TO_COMPUTE_ECM (0X000B) +#define ECMG_OUT_OF_STORAGE_CAPACITY (0X000C) +#define ECMG_OUT_OF_COMPUTATIONAL_RESOURCES (0X000D) +#define UNKNOWN_PARAMETER_TYPE_VALUE (0X000E) +#define INCONSISTENT_LENGTH_FOR_DVB_PARAMETER (0X000F) +#define MISSING_MANDATORY_DVB_PARAMETER (0X0010) +#define INVALID_VALUE_FOR_DVB_PARAMETER (0X0011) +#define UNKNOWN_ECM_ID_VALUE (0X0012) +#define ECM_CHANNEL_ID_VALUE_ALREADY_IN_USE (0X0013) +#define ECM_STREAM_ID_VALUE_ALREADY_IN_USE (0X0014) +#define ECM_ID_VALUE_ALREADY_IN_USE (0X0015) +#define UNKNOWN_ERROR (0X7000) +#define UNRECOVERABLE_ERROR (0X7001) // Size (in # of bytes) of various fields. -#define PARAMETER_TYPE_SIZE 2 -#define PARAMETER_LENGTH_SIZE 2 -#define ECM_CHANNEL_ID_SIZE 2 -#define ECM_STREAM_ID_SIZE 2 -#define NOMINAL_CP_DURATION_SIZE 2 -#define CP_NUMBER_SIZE 2 -#define CP_DURATION_SIZE 2 -#define CP_SIZE 2 +#define PROTOCOL_VERSION_SIZE (1) +#define MESSAGE_TYPE_SIZE (2) +#define MESSAGE_LENGTH_SIZE (2) +#define PARAMETER_TYPE_SIZE (2) +#define PARAMETER_LENGTH_SIZE (2) +#define SUPER_CAS_ID_SIZE (4) +#define ECM_CHANNEL_ID_SIZE (2) +#define ECM_ID_SIZE (2) +#define ECM_STREAM_ID_SIZE (2) +#define NOMINAL_CP_DURATION_SIZE (2) +#define CP_NUMBER_SIZE (2) +#define CP_DURATION_SIZE (2) +#define CP_SIZE (2) #endif // MEDIA_CAS_PACKAGER_SDK_INTERNAL_ECMG_CONSTANTS_H_ diff --git a/media_cas_packager_sdk/internal/fixed_key_fetcher.cc b/media_cas_packager_sdk/internal/fixed_key_fetcher.cc index 8550b75..ba963c4 100644 --- a/media_cas_packager_sdk/internal/fixed_key_fetcher.cc +++ b/media_cas_packager_sdk/internal/fixed_key_fetcher.cc @@ -14,8 +14,8 @@ namespace widevine { namespace cas { -util::Status FixedKeyFetcher::RequestEntitlementKey( - const std::string& request_string, std::string* signed_response_string) { +Status FixedKeyFetcher::RequestEntitlementKey(const std::string& request_string, + std::string* signed_response_string) { CasEncryptionRequest request; request.ParseFromString(request_string); @@ -49,7 +49,7 @@ util::Status FixedKeyFetcher::RequestEntitlementKey( SignedCasEncryptionResponse signed_response; signed_response.set_response(response_string); signed_response.SerializeToString(signed_response_string); - return util::OkStatus(); + return OkStatus(); } } // namespace cas diff --git a/media_cas_packager_sdk/internal/fixed_key_fetcher.h b/media_cas_packager_sdk/internal/fixed_key_fetcher.h index 4a079a6..2d8120e 100644 --- a/media_cas_packager_sdk/internal/fixed_key_fetcher.h +++ b/media_cas_packager_sdk/internal/fixed_key_fetcher.h @@ -49,8 +49,8 @@ class FixedKeyFetcher : public KeyFetcher { // |signed_response_string| a serialized SignedCasEncryptionResponse // message. It should be passed into // WvCasEcm::ProcessCasEncryptionResponse(). - util::Status RequestEntitlementKey(const std::string& request_string, - std::string* signed_response_string) override; + Status RequestEntitlementKey(const std::string& request_string, + std::string* signed_response_string) override; private: std::string even_entitlement_key_id_; diff --git a/media_cas_packager_sdk/internal/key_fetcher.h b/media_cas_packager_sdk/internal/key_fetcher.h index 00999e9..c2f0224 100644 --- a/media_cas_packager_sdk/internal/key_fetcher.h +++ b/media_cas_packager_sdk/internal/key_fetcher.h @@ -33,8 +33,8 @@ class KeyFetcher { // |signed_response_string| a serialized SignedCasEncryptionResponse // message. It should be passed into // WvCasEcm::ProcessCasEncryptionResponse(). - virtual util::Status RequestEntitlementKey( - const std::string& request_string, std::string* signed_response_string) = 0; + virtual Status RequestEntitlementKey(const std::string& request_string, + std::string* signed_response_string) = 0; }; } // namespace cas diff --git a/media_cas_packager_sdk/internal/simulcrypt.cc b/media_cas_packager_sdk/internal/simulcrypt.cc deleted file mode 100644 index 1e9b206..0000000 --- a/media_cas_packager_sdk/internal/simulcrypt.cc +++ /dev/null @@ -1,67 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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/internal/simulcrypt.h" - -#include -#include - -#include "glog/logging.h" -#include "absl/strings/str_cat.h" -#include "common/status.h" -#include "media_cas_packager_sdk/internal/ecmg.h" -#include "media_cas_packager_sdk/internal/simulcrypt_constants.h" -#include "media_cas_packager_sdk/internal/util.h" - -namespace widevine { -namespace cas { - -// TODO(user): Caller should check |message| is at lest 5 bytes long. -util::Status Simulcrypt::ProcessMessage(const char* message, std::string* response) { - DCHECK(message); - DCHECK(response); - - uint8_t protocol_version; - uint16_t message_type; - uint16_t message_length; - // 'offset' is used to track where we are within |message|. - size_t offset = 0; - memcpy(&protocol_version, message, PROTOCOL_VERSION_SIZE); - if (protocol_version != EXPECTED_PROTOCOL_VERSION) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Invalid protocol version ", protocol_version)); - } - offset += PROTOCOL_VERSION_SIZE; - BigEndianToHost16(&message_type, message + offset); - offset += MESSAGE_TYPE_SIZE; - BigEndianToHost16(&message_length, message + offset); - offset += MESSAGE_LENGTH_SIZE; - switch (message_type) { - case ECMG_STREAM_SETUP: { - return ecmg_.ProcessStreamSetupMessage(message + offset, message_length); - break; - } - case ECMG_CW_PROVISION: { - return ecmg_.ProcessCwProvisionMessage(message + offset, message_length, - response); - break; - } - default: { - return util::Status( - util::error::UNIMPLEMENTED, - absl::StrCat("No implementation yet to process message of type ", - message_type)); - break; - } - } - return util::OkStatus(); -} - -} // namespace cas -} // namespace widevine diff --git a/media_cas_packager_sdk/internal/simulcrypt.h b/media_cas_packager_sdk/internal/simulcrypt.h deleted file mode 100644 index c43c28e..0000000 --- a/media_cas_packager_sdk/internal/simulcrypt.h +++ /dev/null @@ -1,50 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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_INTERNAL_SIMULCRYPT_H_ -#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_SIMULCRYPT_H_ - -#include -#include -#include -#include -#include -#include - -#include -#include "common/status.h" -#include "media_cas_packager_sdk/internal/ecmg.h" - -namespace widevine { -namespace cas { - -// A class that handles Simulcrypt messages. -// The expected usage is by a TCP server that receives Simulcrypt message -// from the network then forward that message to an instance of this class -// for processing. -// This class is NOT thread-safe. -class Simulcrypt { - public: - Simulcrypt() = default; - Simulcrypt(const Simulcrypt&) = delete; - Simulcrypt& operator=(const Simulcrypt&) = delete; - virtual ~Simulcrypt() = default; - - // Process a Simulcrypt |message|. - // If any response is generated, it would returned via |response|. - // Any error during processing would be turned via util::Status. - util::Status ProcessMessage(const char* message, std::string* response); - - private: - Ecmg ecmg_; -}; - -} // namespace cas -} // namespace widevine - -#endif // MEDIA_CAS_PACKAGER_SDK_INTERNAL_SIMULCRYPT_H_ diff --git a/media_cas_packager_sdk/internal/simulcrypt_constants.h b/media_cas_packager_sdk/internal/simulcrypt_constants.h deleted file mode 100644 index f855975..0000000 --- a/media_cas_packager_sdk/internal/simulcrypt_constants.h +++ /dev/null @@ -1,55 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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_INTERNAL_SIMULCRYPT_CONSTANTS_H_ -#define MEDIA_CAS_PACKAGER_SDK_INTERNAL_SIMULCRYPT_CONSTANTS_H_ - -// Message_type Values -// 0x0000 DVB reserved. -#define ECMG_CHANNEL_SETUP 0x0001 -#define ECMG_CHANNEL_TEST 0x0002 -#define ECMG_CHANNEL_STATUS 0x0003 -#define ECMG_CHANNEL_CLOSE 0x0004 -#define ECMG_CHANNEL_ERROR 0x0005 -// 0x0006 - 0x0010 DVB reserved. -#define EMMG_CHANNEL_SETUP 0x0011 -#define EMMG_CHANNEL_TEST 0x0012 -#define EMMG_CHANNEL_STATUS 0x0013 -#define EMMG_CHANNEL_CLOSE 0x0014 -#define EMMG_CHANNEL_ERROR 0x0015 -// 0x0016 - 0x0100 DVB reserved. -#define ECMG_STREAM_SETUP 0x0101 -#define ECMG_STREAM_TEST 0x0102 -#define ECMG_STREAM_STATUS 0x0103 -#define ECMG_STREAM_CLOSE_REQUEST 0x0104 -#define ECMG_STREAM_CLOSE_RESPONSE 0x0105 -#define ECMG_STREAM_ERROR 0x0106 -// 0x0107 - 0x0110 DVB reserved. -#define EMMG_STREAM_SETUP 0x0111 -#define EMMG_STREAM_TEST 0x0112 -#define EMMG_STREAM_STATUS 0x0113 -#define EMMG_STREAM_CLOSE_REQUEST 0x0114 -#define EMMG_STREAM_CLOSE_RESPONSE 0x0115 -#define EMMG_STREAM_ERROR 0x0116 -#define EMMG_STREAM_BW_REQUEST 0x0117 -#define EMMG_STREAM_BW_ALLOCATION 0x0118 -// 0x0119 - 0x0200 DVB reserved. -#define ECMG_CW_PROVISION 0x0201 -#define ECMG_ECM_RESPONSE 0x0202 -// 0x0203 - 0x0210 DVB reserved. -#define EMMG_DATA_PROVISION 0x0211 -// 0x0212 - 0x0300 DVB reserved. - -#define EXPECTED_PROTOCOL_VERSION 0x01 - -// Size (in # of bytes) of various fields. -#define PROTOCOL_VERSION_SIZE 1 -#define MESSAGE_TYPE_SIZE 2 -#define MESSAGE_LENGTH_SIZE 2 - -#endif // MEDIA_CAS_PACKAGER_SDK_INTERNAL_SIMULCRYPT_CONSTANTS_H_ diff --git a/media_cas_packager_sdk/internal/simulcrypt_test.cc b/media_cas_packager_sdk/internal/simulcrypt_test.cc deleted file mode 100644 index 2a3af37..0000000 --- a/media_cas_packager_sdk/internal/simulcrypt_test.cc +++ /dev/null @@ -1,54 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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/internal/simulcrypt.h" - -#include - -#include "testing/gmock.h" -#include "testing/gunit.h" -#include "example/test_simulcrypt_messages.h" - -namespace widevine { -namespace cas { -namespace { - -class SimulcryptTest : public ::testing::Test { - protected: - SimulcryptTest() {} - - protected: - Simulcrypt simulcrypt_; -}; - -TEST_F(SimulcryptTest, ProcessEcmgStreamSetupMessage) { - std::string response = ""; - EXPECT_OK(simulcrypt_.ProcessMessage(kTestEcmgStreamSetupMessage, &response)); - - EXPECT_EQ("", response); -} - -TEST_F(SimulcryptTest, ProcessEcmgCwProvisionMessageWithOneCw) { - std::string response = ""; - EXPECT_OK(simulcrypt_.ProcessMessage(kTestEcmgCwProvisionMessageWithOneCw, - &response)); - - EXPECT_EQ("", response); -} - -TEST_F(SimulcryptTest, ProcessEcmgCwProvisionMessageWithTwoCw) { - std::string response = ""; - EXPECT_OK(simulcrypt_.ProcessMessage(kTestEcmgCwProvisionMessageWithTwoCw, - &response)); - - EXPECT_EQ("", response); -} - -} // namespace -} // namespace cas -} // namespace widevine diff --git a/media_cas_packager_sdk/internal/ts_packet.cc b/media_cas_packager_sdk/internal/ts_packet.cc index 11b9698..1db9c47 100644 --- a/media_cas_packager_sdk/internal/ts_packet.cc +++ b/media_cas_packager_sdk/internal/ts_packet.cc @@ -18,7 +18,7 @@ namespace widevine { namespace cas { -util::Status TsPacket::Write(std::string* output) const { +Status TsPacket::Write(std::string* output) const { DCHECK(output); output->resize(kTsPacketSize); @@ -32,8 +32,8 @@ util::Status TsPacket::Write(std::string* output) const { std::bitset<2> adaptation_field_control(adaptation_field_control_); std::bitset<4> continuity_counter(continuity_counter_); if (adaptation_field_control_ & kAdaptationFieldOnly) { - return util::Status(util::error::INTERNAL, - "TsPacket does NOT handle adaptation field yet"); + return Status(error::INTERNAL, + "TsPacket does NOT handle adaptation field yet"); } // Converts header bitset to string. @@ -43,29 +43,28 @@ util::Status TsPacket::Write(std::string* output) const { pid.to_string(), transport_scrambling_control.to_string(), adaptation_field_control.to_string(), continuity_counter.to_string()); if (header_bitset.size() != 4 * 8) { - return util::Status(util::error::INTERNAL, - absl::StrCat("TS packet header bitset incorret size: ", - header_bitset.size())); + return Status(error::INTERNAL, + absl::StrCat("TS packet header bitset incorret size: ", + header_bitset.size())); } std::string serialized_header; - util::Status status = string_util::BitsetStringToBinaryString( - header_bitset, &serialized_header); + Status status = string_util::BitsetStringToBinaryString(header_bitset, + &serialized_header); if (!status.ok()) { - return util::Status(util::error::INTERNAL, - "Failed to convert TS packet header bitset to std::string"); + return Status(error::INTERNAL, + "Failed to convert TS packet header bitset to std::string"); } // Write TsPacket payload. if (payload_.size() != CalculatePayloadSize()) { - return util::Status( - util::error::INVALID_ARGUMENT, - absl::StrCat("Incorrect payload size: ", payload_.size())); + return Status(error::INVALID_ARGUMENT, + absl::StrCat("Incorrect payload size: ", payload_.size())); } // Return header + payload as a TS packet. *output = serialized_header + payload_; - return util::OkStatus(); + return OkStatus(); } int32_t TsPacket::CalculatePayloadSize() const { diff --git a/media_cas_packager_sdk/internal/ts_packet.h b/media_cas_packager_sdk/internal/ts_packet.h index 797156e..b7f0cbd 100644 --- a/media_cas_packager_sdk/internal/ts_packet.h +++ b/media_cas_packager_sdk/internal/ts_packet.h @@ -63,7 +63,7 @@ class TsPacket { virtual ~TsPacket() = default; // Writes the packet into the provided output. Returns kOk on success. - virtual util::Status Write(std::string* output) const; + virtual Status Write(std::string* output) const; // Returns the size of payload data for the current TS packet configuration. int32_t CalculatePayloadSize() const; diff --git a/media_cas_packager_sdk/internal/util.cc b/media_cas_packager_sdk/internal/util.cc index 95c292b..301477c 100644 --- a/media_cas_packager_sdk/internal/util.cc +++ b/media_cas_packager_sdk/internal/util.cc @@ -9,8 +9,8 @@ #include "media_cas_packager_sdk/internal/util.h" #include -#include -#include +#include +#include #include "glog/logging.h" #include "media_cas_packager_sdk/internal/ts_packet.h" @@ -30,14 +30,36 @@ ContinuityCounter Increment(ContinuityCounter continuity_counter) { void BigEndianToHost16(uint16_t* destination, const void* source) { DCHECK(destination); DCHECK(source); - uint16_t big_endian_number; + uint16_t big_endian_number = 0; memcpy(&big_endian_number, source, 2); *destination = ntohs(big_endian_number); } -util::Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, - uint8_t table_id, ContinuityCounter* cc, - uint8_t* buffer, ssize_t* bytes_modified) { +void BigEndianToHost32(uint32_t* destination, const void* source) { + DCHECK(destination); + DCHECK(source); + uint32_t big_endian_number = 0; + memcpy(&big_endian_number, source, 4); + *destination = ntohl(big_endian_number); +} + +void Host16ToBigEndian(void* destination, const uint16_t* source) { + DCHECK(destination); + DCHECK(source); + uint16_t big_endian_number = htons(*source); + memcpy(destination, &big_endian_number, 2); +} + +void Host16ToBigEndian(void* destination, const int16_t* source) { + DCHECK(destination); + DCHECK(source); + uint16_t big_endian_number = htons(static_cast(*source)); + memcpy(destination, &big_endian_number, 2); +} + +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); @@ -75,7 +97,7 @@ util::Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, // And write the packet. std::string ecm_ts_packet; - util::Status status = ecm_packet.Write(&ecm_ts_packet); + Status status = ecm_packet.Write(&ecm_ts_packet); if (!status.ok()) { return status; } @@ -83,7 +105,7 @@ util::Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, memcpy(buffer + *bytes_modified, ecm_ts_packet.data(), ecm_ts_packet.size()); *bytes_modified += ecm_ts_packet.size(); - return util::OkStatus(); + return OkStatus(); } } // namespace cas diff --git a/media_cas_packager_sdk/internal/util.h b/media_cas_packager_sdk/internal/util.h index d55f6d8..2b6ba71 100644 --- a/media_cas_packager_sdk/internal/util.h +++ b/media_cas_packager_sdk/internal/util.h @@ -24,6 +24,16 @@ namespace cas { // the result in |destination|. void BigEndianToHost16(uint16_t* destination, const void* source); +// Read 32 bits (long int) from |source|, treat it as a big-endian number +// (network byte order), finally covert it to host endianness and return +// the result in |destination|. +void BigEndianToHost32(uint32_t* destination, const void* source); + +// Covert |source| to big-endian (network byte order) and copy it to +// |destination|. +void Host16ToBigEndian(void* destination, const uint16_t* source); +void Host16ToBigEndian(void* destination, const int16_t* source); + // Packages an ECM as a TS packet and inserts it into a buffer. // Args: // - |ecm| is the serialized ECM. @@ -42,9 +52,9 @@ void BigEndianToHost16(uint16_t* destination, const void* source); // the |buffer| and is used as an offset. // |bytes_modified| will be incremented by 188 if insertion of ECM into // |buffer| is successful. -util::Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, - uint8_t table_id, ContinuityCounter* cc, - uint8_t* buffer, ssize_t* bytes_modified); +Status InsertEcmAsTsPacket(const std::string& ecm, ProgramId pid, uint8_t table_id, + ContinuityCounter* cc, uint8_t* buffer, + ssize_t* bytes_modified); } // 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 48a2f7f..1f8c18b 100644 --- a/media_cas_packager_sdk/internal/util_test.cc +++ b/media_cas_packager_sdk/internal/util_test.cc @@ -58,6 +58,9 @@ constexpr char kExpectedEcmPacket[] = { namespace widevine { namespace cas { +// TODO(user): Add unit tests for BigEndianToHost16, BigEndianToHost32 and +// Host16ToBigEndian. + TEST(InsertEcmAsTsPacketTest, BasicHappyPath) { // declare variables used by InsertEcmAsTsPacket() ContinuityCounter ecm_cc_ = 0; diff --git a/media_cas_packager_sdk/public/BUILD b/media_cas_packager_sdk/public/BUILD index 089af6f..a4303b3 100644 --- a/media_cas_packager_sdk/public/BUILD +++ b/media_cas_packager_sdk/public/BUILD @@ -20,7 +20,9 @@ PUBLIC_COPTS = ["-fvisibility=default"] filegroup( name = "binary_release_files", - srcs = glob(["*.h"]), + srcs = glob(["*.h"]) + [ + ":wv_ecmg", + ], ) cc_binary( @@ -49,15 +51,6 @@ cc_library( ], ) -cc_binary( - name = "simulcrypt_server", - srcs = ["simulcrypt_server.cc"], - deps = [ - "//base", - "@abseil_repo//absl/base:core_headers", - ], -) - cc_library( name = "wv_cas_ca_descriptor", srcs = ["wv_cas_ca_descriptor.cc"], @@ -97,8 +90,8 @@ cc_library( "@abseil_repo//absl/base:core_headers", # buildcleaner: keep "@abseil_repo//absl/memory", # buildcleaner: keep "@abseil_repo//absl/strings", # buildcleaner: keep - "//common:status", "//common:crypto_util", + "//common:status", "//example:constants", "//media_cas_packager_sdk/internal:ecm", "//media_cas_packager_sdk/internal:ecm_generator", @@ -134,7 +127,6 @@ cc_library( "@abseil_repo//absl/base:core_headers", "@abseil_repo//absl/strings", "@curl_repo//:curl", - "//common:status", "//common:signature_util", "//media_cas_packager_sdk/internal:key_fetcher", "//protos/public:media_cas_encryption_proto", @@ -153,7 +145,6 @@ cc_test( "//external:protobuf", "//testing:gunit_main", "@abseil_repo//absl/strings", - "//common:status", "//protos/public:media_cas_encryption_proto", ], ) @@ -175,3 +166,14 @@ cc_test( "//testing:gunit_main", ], ) + +cc_binary( + name = "wv_ecmg", + srcs = ["wv_ecmg.cc"], + deps = [ + "//base", + "@abseil_repo//absl/base:core_headers", + "@abseil_repo//absl/strings", + "//media_cas_packager_sdk/internal:ecmg_client_handler", + ], +) diff --git a/media_cas_packager_sdk/public/simulcrypt_server.cc b/media_cas_packager_sdk/public/simulcrypt_server.cc deleted file mode 100644 index 4dac5ae..0000000 --- a/media_cas_packager_sdk/public/simulcrypt_server.cc +++ /dev/null @@ -1,82 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 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 server that listens on a port for Simulcrypt API messages. - -#include -#include -#include -#include -#include -#include -#include - -#include "gflags/gflags.h" -#include "glog/logging.h" - -DEFINE_int32(port, 0, "Server port number"); - -constexpr uint32_t kBufferSize = 256; -constexpr uint32_t kLicenseBacklog = 5; -constexpr uint32_t kWriteChunkSize = 18; - -int main(int argc, char **argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - CHECK(FLAGS_port != 0) << "need --port"; - - struct sockaddr_in server_address; - bzero(reinterpret_cast(&server_address), sizeof(server_address)); - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl(INADDR_ANY); - server_address.sin_port = htons(FLAGS_port); - - int listen_socket_fd = socket(AF_INET, SOCK_STREAM, /* protocol= */ 0); - CHECK(listen_socket_fd >= 0) << "failed to open socket"; - CHECK(bind(listen_socket_fd, (struct sockaddr *)&server_address, - sizeof(server_address)) >= 0) - << "error on binding"; - std::cout << "Server listening ..." << std::endl << std::flush; - int return_val = listen(listen_socket_fd, kLicenseBacklog); - switch (return_val) { - case EADDRINUSE: - LOG(FATAL) << "Another socket is already listening on the same port."; - break; - case EBADF: - LOG(FATAL) << "The argument sockfd is not a valid descriptor."; - break; - case ENOTSOCK: - LOG(FATAL) << "The argument sockfd is not a socket."; - break; - case EOPNOTSUPP: - LOG(FATAL) << "The socket is not of a type that supports the listen() " - "operation."; - default: - break; - } - - struct sockaddr_in client_address; - socklen_t clilet_address_size = sizeof(client_address); - int client_socket_fd = accept( - listen_socket_fd, reinterpret_cast(&client_address), - &clilet_address_size); - CHECK(client_socket_fd >= 0) << "error on accept"; - - char buffer[kBufferSize]; - bzero(buffer, kBufferSize); - if (read(client_socket_fd, buffer, kBufferSize - 1) < 0) { - LOG(FATAL) << "ERROR reading from socket"; - } - printf("Here is the message: %s", buffer); - if (write(client_socket_fd, "I got your message", kWriteChunkSize) < 0) { - LOG(FATAL) << "ERROR writing to socket"; - } - - close(client_socket_fd); - close(listen_socket_fd); - return 0; -} diff --git a/media_cas_packager_sdk/public/wv_cas_ca_descriptor.cc b/media_cas_packager_sdk/public/wv_cas_ca_descriptor.cc index 678f657..9557715 100644 --- a/media_cas_packager_sdk/public/wv_cas_ca_descriptor.cc +++ b/media_cas_packager_sdk/public/wv_cas_ca_descriptor.cc @@ -95,7 +95,7 @@ WvCasStatus WvCasCaDescriptor::GenerateCaDescriptor( return INTERNAL; } std::string descriptor; - util::Status status = + Status status = string_util::BitsetStringToBinaryString(descriptor_bitset, &descriptor); *serialized_ca_desc = descriptor; diff --git a/media_cas_packager_sdk/public/wv_cas_ecm.cc b/media_cas_packager_sdk/public/wv_cas_ecm.cc index 9f83c5d..4bad37a 100644 --- a/media_cas_packager_sdk/public/wv_cas_ecm.cc +++ b/media_cas_packager_sdk/public/wv_cas_ecm.cc @@ -13,10 +13,10 @@ #include #include "glog/logging.h" -#include "common/status.h" #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "common/crypto_util.h" +#include "common/status.h" #include "example/constants.h" #include "media_cas_packager_sdk/internal/ecm.h" #include "media_cas_packager_sdk/internal/ecm_generator.h" @@ -154,7 +154,7 @@ WvCasStatus WvCasEcm::GenerateEcm( // TODO(user): When we want to retrieve entitlement key from License Server // we need to figure out a way to provide real 'content_id' and 'provder' // to this function here. - util::Status status; + Status status; if (!(status = cas_ecm->Initialize(kDefaultContentId, kDefaultProvider, ecm_init_params, &entitlement_request)) .ok()) { @@ -265,7 +265,7 @@ WvCasStatus WvCasEcm::GenerateSingleKeyEcm( // TODO(user): When we want to retrieve entitlement key from License Server // we need to figure out a way to provide real 'content_id' and 'provder' // to this function here. - util::Status status; + Status status; if (!(status = cas_ecm->Initialize(kDefaultContentId, kDefaultProvider, ecm_init_params, &entitlement_request)) .ok()) { @@ -319,8 +319,8 @@ WvCasStatus WvCasEcm::GenerateTsPacket(const std::string& ecm, uint16_t pid, uint8_t* continuity_counter, uint8_t* packet) { ssize_t bytes_modified = 0; - util::Status status = InsertEcmAsTsPacket( - ecm, pid, table_id, continuity_counter, packet, &bytes_modified); + Status status = InsertEcmAsTsPacket(ecm, pid, table_id, continuity_counter, + packet, &bytes_modified); if (!status.ok() || bytes_modified != kTsPacketSize) { memset(packet, 0, kTsPacketSize); LOG(ERROR) << "Failed to generate TS packet: " << status; 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 db239f7..6e4be17 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.cc @@ -20,7 +20,6 @@ #include "absl/strings/string_view.h" #include "curl/curl.h" #include "curl/easy.h" -#include "common/status.h" #include "common/signature_util.h" #include "protos/public/media_cas_encryption.pb.h" @@ -41,12 +40,12 @@ DEFINE_string(signing_iv, "", namespace widevine { namespace cas { -util::Status WvCasKeyFetcher::RequestEntitlementKey( - const std::string& request_string, std::string* signed_response_string) { +Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string, + std::string* signed_response_string) { if (FLAGS_signing_provider.empty() || FLAGS_signing_key.empty() || FLAGS_signing_iv.empty()) { - return util::Status( - util::error::INVALID_ARGUMENT, + return Status( + error::INVALID_ARGUMENT, "Flag 'signing_provider', 'signing_key' or 'signing_iv' is empty"); } @@ -63,8 +62,8 @@ util::Status WvCasKeyFetcher::RequestEntitlementKey( // NOTE: MessageToJsonString will automatically converts 'bytes' type fields // to base64. For example content ID '21140844' becomes 'MjExNDA4NDQ='. if (!MessageToJsonString(request, &request_json, print_options).ok()) { - return util::Status(util::error::INTERNAL, - "Failed to convert request message to json."); + return Status(error::INTERNAL, + "Failed to convert request message to json."); } LOG(INFO) << "Json CasEncryptionRequest: " << request_json; @@ -76,7 +75,7 @@ util::Status WvCasKeyFetcher::RequestEntitlementKey( request_json, absl::HexStringToBytes(FLAGS_signing_key), absl::HexStringToBytes(FLAGS_signing_iv), &signature) .ok()) { - return util::Status(util::error::INTERNAL, "Failed to sign the request."); + return Status(error::INTERNAL, "Failed to sign the request."); } signed_request.set_signature(signature); signed_request.set_signer(FLAGS_signing_provider); @@ -85,23 +84,22 @@ util::Status WvCasKeyFetcher::RequestEntitlementKey( // 'signature' fields in SignedCasEncryptionRequest to base64, because they // are of type 'bytes'. if (!MessageToJsonString(signed_request, &signed_request_json).ok()) { - return util::Status(util::error::INTERNAL, - "Failed to convert signed request message to json."); + return Status(error::INTERNAL, + "Failed to convert signed request message to json."); } LOG(INFO) << "Json SignedCasEncryptionRequest: " << signed_request_json; // Makes HTTP request against License Server. std::string http_response_json; - util::Status status = - MakeHttpRequest(signed_request_json, &http_response_json); + Status status = MakeHttpRequest(signed_request_json, &http_response_json); if (!status.ok()) { return status; } LOG(INFO) << "Json HTTP response: " << http_response_json; HttpResponse http_response; if (!JsonStringToMessage(http_response_json, &http_response).ok()) { - return util::Status(util::error::INTERNAL, - "Failed to convert http response json to message."); + return Status(error::INTERNAL, + "Failed to convert http response json to message."); } // Processes signed response. @@ -110,13 +108,13 @@ util::Status WvCasKeyFetcher::RequestEntitlementKey( LOG(INFO) << "Json CasEncryptionResponse: " << http_response.response(); CasEncryptionResponse response; if (!JsonStringToMessage(http_response.response(), &response).ok()) { - return util::Status(util::error::INTERNAL, - "Failed to convert response json to message."); + return Status(error::INTERNAL, + "Failed to convert response json to message."); } SignedCasEncryptionResponse signed_response; signed_response.set_response(response.SerializeAsString()); signed_response.SerializeToString(signed_response_string); - return util::OkStatus(); + return OkStatus(); } size_t AppendToString(void* ptr, size_t size, size_t count, std::string* output) { @@ -125,12 +123,11 @@ size_t AppendToString(void* ptr, size_t size, size_t count, std::string* output) return data.size(); } -util::Status WvCasKeyFetcher::MakeHttpRequest( - const std::string& signed_request_json, std::string* http_response_json) const { +Status WvCasKeyFetcher::MakeHttpRequest(const std::string& signed_request_json, + std::string* http_response_json) const { CHECK(http_response_json); if (FLAGS_license_server.empty()) { - return util::Status(util::error::INVALID_ARGUMENT, - "Flag 'license_server' is empty"); + return Status(error::INVALID_ARGUMENT, "Flag 'license_server' is empty"); } CURL* curl; CURLcode curl_code; @@ -145,15 +142,14 @@ util::Status WvCasKeyFetcher::MakeHttpRequest( (int64_t)strlen(signed_request_json.c_str())); curl_code = curl_easy_perform(curl); if (curl_code != CURLE_OK) { - return util::Status(util::error::INTERNAL, - "curl_easy_perform() failed: " + - std::string(curl_easy_strerror(curl_code))); + return Status(error::INTERNAL, "curl_easy_perform() failed: " + + std::string(curl_easy_strerror(curl_code))); } curl_easy_cleanup(curl); } else { - return util::Status(util::error::INTERNAL, "curl_easy_init() failed"); + return Status(error::INTERNAL, "curl_easy_init() failed"); } - return util::OkStatus(); + return OkStatus(); } } // namespace cas 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 03eddec..f91dbd6 100644 --- a/media_cas_packager_sdk/public/wv_cas_key_fetcher.h +++ b/media_cas_packager_sdk/public/wv_cas_key_fetcher.h @@ -12,7 +12,6 @@ #include #include "gflags/gflags.h" -#include "common/status.h" #include "media_cas_packager_sdk/internal/key_fetcher.h" DECLARE_string(license_server); @@ -41,15 +40,15 @@ class WvCasKeyFetcher : public KeyFetcher { // |signed_response_string| a serialized SignedCasEncryptionResponse // message. It should be passed into // widevine::cas::Ecm::ProcessCasEncryptionResponse(). - virtual util::Status RequestEntitlementKey(const std::string& request_string, - std::string* signed_response_string); + Status RequestEntitlementKey(const std::string& request_string, + std::string* signed_response_string) override; protected: // Makes a HTTP request to License Server for entitlement key(s). // Returns the HTTP response in Json format in |http_response_json|. // Protected visibility to support unit testing. - virtual util::Status MakeHttpRequest(const std::string& signed_request_json, - std::string* http_response_json) const; + virtual Status MakeHttpRequest(const std::string& signed_request_json, + std::string* http_response_json) const; }; } // namespace cas 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 651d569..3574705 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 @@ -14,7 +14,6 @@ #include "testing/gmock.h" #include "testing/gunit.h" #include "absl/strings/escaping.h" -#include "common/status.h" #include "protos/public/media_cas_encryption.pb.h" using testing::_; @@ -55,9 +54,8 @@ class MockWvCasKeyFetcher : public WvCasKeyFetcher { public: MockWvCasKeyFetcher() : WvCasKeyFetcher() {} ~MockWvCasKeyFetcher() override {} - MOCK_CONST_METHOD2(MakeHttpRequest, - util::Status(const std::string& signed_request_json, - std::string* http_response_json)); + MOCK_CONST_METHOD2(MakeHttpRequest, Status(const std::string& signed_request_json, + std::string* http_response_json)); }; class WvCasKeyFetcherTest : public ::testing::Test { @@ -93,7 +91,7 @@ TEST_F(WvCasKeyFetcherTest, TestRequestEntitlementKey) { EXPECT_CALL(mock_key_fetcher_, MakeHttpRequest(kSignedCasEncryptionRequest, _)) .WillOnce(DoAll(SetArgumentPointee<1>(std::string(kHttpResponse)), - Return(util::OkStatus()))); + Return(OkStatus()))); std::string actual_signed_response; EXPECT_OK(mock_key_fetcher_.RequestEntitlementKey( diff --git a/media_cas_packager_sdk/public/wv_ecmg.cc b/media_cas_packager_sdk/public/wv_ecmg.cc new file mode 100644 index 0000000..056eafc --- /dev/null +++ b/media_cas_packager_sdk/public/wv_ecmg.cc @@ -0,0 +1,190 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2018 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 server that listens on a port for Simulcrypt API messages. + +#include +#include +#include +#include +#include +#include +#include + +#include "gflags/gflags.h" +#include "glog/logging.h" +#include "absl/strings/str_cat.h" +#include "media_cas_packager_sdk/internal/ecmg_client_handler.h" + +static constexpr int32_t kDefaultDelayStart = 200; +static constexpr int32_t kDefaultDelayStop = 200; +static constexpr int32_t kDefaultEcmRepPeriod = 100; +static constexpr int32_t kDefaultMaxCompTime = 100; +static constexpr int32_t kAccessCriteriaTransferMode = 1; + +DEFINE_int32(port, 0, "Server port number"); + +// ECMG related flags. +// TODO(user): Consider adding flags 'ac_delay_start', 'ac_delay_stop', +// 'transition_delay_start', 'transition_delay_stop'. +DEFINE_int32(delay_start, kDefaultDelayStart, + absl::StrCat("This flag sets the DVB SimulCrypt delay_start " + "parameter, in milliseconds. Default: ", + kDefaultDelayStart, " ms") + .c_str()); +DEFINE_int32(delay_stop, kDefaultDelayStop, + absl::StrCat("This flag sets the DVB SimulCrypt delay_stop " + "parameter, in milliseconds. Default: ", + kDefaultDelayStop, " ms") + .c_str()); +DEFINE_int32(ecm_rep_period, kDefaultEcmRepPeriod, + absl::StrCat("It sets the DVB SimulCrypt parameter " + "ECM_rep_period, in milliseconds. Default: ", + kDefaultEcmRepPeriod, " ms") + .c_str()); +DEFINE_int32(max_comp_time, kDefaultMaxCompTime, + absl::StrCat("It sets the DVB SimulCrypt parameter max_comp_time, " + "in milliseconds. Default: ", + kDefaultMaxCompTime, " ms") + .c_str()); +DEFINE_int32(access_criteria_transfer_mode, kAccessCriteriaTransferMode, + absl::StrCat("It sets the DVB SimulCrypt parameter " + "access_criteria_transfer_mode. Default: ", + kAccessCriteriaTransferMode) + .c_str()); + +#define LISTEN_QUEUE_SIZE (20) +#define BUFFER_SIZE (1024) + +using widevine::cas::EcmgClientHandler; +using widevine::cas::EcmgConfig; + +void BuildEcmgConfig(EcmgConfig* config) { + DCHECK(config); + config->delay_start = FLAGS_delay_start; + config->delay_stop = FLAGS_delay_stop; + config->ecm_rep_period = FLAGS_ecm_rep_period; + config->max_comp_time = FLAGS_max_comp_time; + config->access_criteria_transfer_mode = FLAGS_access_criteria_transfer_mode; +} + +void PrintMessage(const std::string& description, const char* const message, + size_t length) { + LOG(INFO) << description; + for (size_t i = 0; i < length; i++) { + printf("'\\x%02x', ", static_cast(*(message + i))); + fflush(stdout); + } + printf("\n"); + fflush(stdout); +} + +void ServeClient(int socket_fd, EcmgClientHandler* ecmg) { + DCHECK(ecmg); + char request[BUFFER_SIZE]; + char response[BUFFER_SIZE]; + while (true) { + bzero(request, BUFFER_SIZE); + bzero(response, BUFFER_SIZE); + size_t response_length = 0; + size_t request_length = recv(socket_fd, request, BUFFER_SIZE, 0); + if (request_length == 0) { + LOG(ERROR) << "No more request from client"; + return; + } + if (request_length < 0) { + LOG(ERROR) << "Failed to receive request from client"; + return; + } + PrintMessage("Request", request, request_length); + ecmg->HandleRequest(request, response, &response_length); + PrintMessage("Response", response, response_length); + if (send(socket_fd, response, response_length, 0) < 0) { + LOG(INFO) << "Failed to send response to client"; + return; + } + } +} + +int main(int argc, char** argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + CHECK(FLAGS_port != 0) << "need --port"; + + EcmgConfig ecmg_config; + BuildEcmgConfig(&ecmg_config); + + // Server address. + struct sockaddr_in server_address; + bzero(reinterpret_cast(&server_address), sizeof(server_address)); + server_address.sin_family = AF_INET; + server_address.sin_addr.s_addr = htonl(INADDR_ANY); + server_address.sin_port = htons(FLAGS_port); + + // Create a listening socket. + int listen_socket_fd = socket(AF_INET, SOCK_STREAM, /* protocol= */ 0); + CHECK(listen_socket_fd >= 0) << "Failed to open listening socket"; + + // Set SO_REUSEADDR on a socket to true (1). + int optval = 1; + setsockopt(listen_socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval, + sizeof(optval)); + + // Bind address. + CHECK(bind(listen_socket_fd, (struct sockaddr*)&server_address, + sizeof(server_address)) >= 0) + << "Failed to bind on server socket"; + + // Listen for connection from clients. + std::cout << "Server listening ..." << std::endl << std::flush; + int return_val = listen(listen_socket_fd, LISTEN_QUEUE_SIZE); + switch (return_val) { + case EADDRINUSE: + LOG(FATAL) << "Another socket is already listening on the same port."; + break; + case EBADF: + LOG(FATAL) << "The argument sockfd is not a valid descriptor."; + break; + case ENOTSOCK: + LOG(FATAL) << "The argument sockfd is not a socket."; + break; + case EOPNOTSUPP: + LOG(FATAL) << "The socket is not of a type that supports the listen() " + "operation."; + default: + break; + } + + // A single client handler, allow only 1 TCP connection / 1 channel at a time. + EcmgClientHandler client_handler(&ecmg_config); + + // While loop to serve different client connections. + while (true) { + struct sockaddr_in client_address; + socklen_t client_address_size = sizeof(client_address); + int client_socket_fd = accept( + listen_socket_fd, reinterpret_cast(&client_address), + &client_address_size); + LOG(INFO) << "\nTCP connection start\n"; + if (client_socket_fd < 0) { + LOG(ERROR) << "Failed to accept connection request from client"; + } else { + // TODO(user): Support multi-threading of serving concurrent clients. + // TODO(user): Per jfore@ suggestion, look into using + // http://man7.org/linux/man-pages/man7/epoll.7.html + ServeClient(client_socket_fd, &client_handler); + } + LOG(INFO) << "\nTCP connection closed\n"; + close(client_socket_fd); + usleep(1000); + } + + // Close listening socket. + close(listen_socket_fd); + + return 0; +} diff --git a/protos/public/media_cas.proto b/protos/public/media_cas.proto index 60e4f2e..928c3ce 100644 --- a/protos/public/media_cas.proto +++ b/protos/public/media_cas.proto @@ -11,13 +11,6 @@ syntax = "proto2"; package widevine.cas; -// Encrypt/decrypt mode. -enum CasCryptoMode { - CRYPTO_MODE_UNSPECIFIED = 0; - CTR = 1; - CBC = 2; -}; - // Widevine private data in the CA descriptor. message CaDescriptorPrivateData { // Provider name. diff --git a/testing/gunit.h b/testing/gunit.h index 671dd49..1cb0e96 100644 --- a/testing/gunit.h +++ b/testing/gunit.h @@ -11,9 +11,7 @@ #include -#define EXPECT_OK(expression) \ - EXPECT_EQ(util::error::OK, expression.error_code()) -#define ASSERT_OK(expression) \ - ASSERT_EQ(util::error::OK, expression.error_code()) +#define EXPECT_OK(expression) EXPECT_EQ(error::OK, expression.error_code()) +#define ASSERT_OK(expression) ASSERT_EQ(error::OK, expression.error_code()) #endif // TESTING_GUNIT_H_ diff --git a/zlib.BUILD b/zlib.BUILD deleted file mode 100644 index 64834f5..0000000 --- a/zlib.BUILD +++ /dev/null @@ -1,48 +0,0 @@ -################################################################################ -# Copyright 2018 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. -################################################################################ - -# Build file for zlib. - -package(default_visibility = ["//visibility:public"]) - -cc_library( - name = "zlib", - srcs = [ - "adler32.c", - "compress.c", - "crc32.c", - "crc32.h", - "deflate.c", - "deflate.h", - "gzclose.c", - "gzguts.h", - "gzlib.c", - "gzread.c", - "gzwrite.c", - "infback.c", - "inffast.c", - "inffast.h", - "inffixed.h", - "inflate.c", - "inflate.h", - "inftrees.c", - "inftrees.h", - "trees.c", - "trees.h", - "uncompr.c", - "zconf.h", - "zutil.c", - "zutil.h", - ], - hdrs = ["zlib.h"], - copts = [ - "-Wno-shift-negative-value", - "-Wno-implicit-function-declaration", - ], - includes = ["."], -)