diff --git a/BUILD b/BUILD index fe9863c..18b9493 100644 --- a/BUILD +++ b/BUILD @@ -15,6 +15,8 @@ pkg_tar( strip_prefix = "/", files = [ "//common:binary_release_files", + "//example:binary_release_files", + "//protos/public:binary_release_files", "//media_cas_proxy_sdk/external/common/wvpl:binary_release_files", "//sdk/external/common/wvpl:binary_release_files", "//util:binary_release_files", diff --git a/common/BUILD b/common/BUILD index 4eaf5ad..cfec22a 100644 --- a/common/BUILD +++ b/common/BUILD @@ -16,6 +16,8 @@ filegroup( name = "binary_release_files", srcs = [ "certificate_type.h", + "drm_root_certificate.h", + "status.h", ], ) @@ -31,6 +33,27 @@ cc_library( hdrs = ["certificate_type.h"], ) +cc_library( + name = "status", + srcs = ["status.cc"], + hdrs = ["status.h"], + deps = [ + "//base", + "@abseil_repo//absl/base:core_headers", + "@abseil_repo//absl/strings", + "//util:error_space", + ], +) + +cc_test( + name = "status_test", + srcs = ["status_test.cc"], + deps = [ + ":status", + "//testing:gunit_main", + ], +) + cc_library( name = "client_cert", srcs = ["client_cert.cc"], @@ -41,7 +64,9 @@ cc_library( ":error_space", ":random_util", ":rsa_key", + ":sha_util", ":signing_key_util", + ":status", ":wvm_token_handler", "//base", "//strings", @@ -49,7 +74,6 @@ cc_library( "@abseil_repo//absl/synchronization", "@abseil_repo//absl/time", "//util/gtl:map_util", - "//util:status", "//protos/public:client_identification_proto", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", @@ -65,6 +89,8 @@ cc_test( ":client_cert", ":drm_root_certificate", ":error_space", + ":sha_util", + ":test_drm_certificates", ":wvm_test_keys", "//base", "//strings", @@ -88,15 +114,16 @@ cc_library( ":client_cert", ":crypto_util", ":drm_root_certificate", + ":drm_service_certificate", ":error_space", ":random_util", ":rsa_key", ":signing_key_util", + ":status", "//base", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", "//util/gtl:map_util", - "//util:status", "//protos/public:client_identification_proto", "//protos/public:device_certificate_status_proto", "//protos/public:errors_proto", @@ -132,12 +159,12 @@ cc_library( ":error_space", ":rsa_key", ":sha_util", + ":status", "//base", "@abseil_repo//absl/memory", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", "//external:openssl", - "//util:status", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", "//protos/public:signed_drm_certificate_proto", @@ -171,9 +198,9 @@ cc_library( ":aes_cbc_util", ":drm_service_certificate", ":error_space", + ":status", "//base", "@abseil_repo//absl/strings", - "//util:status", "//protos/public:client_identification_proto", "//protos/public:errors_proto", ], @@ -393,8 +420,8 @@ cc_library( ":aes_cbc_util", ":rsa_key", ":sha_util", + ":status", "//base", - "//util:status", ], ) @@ -442,12 +469,12 @@ cc_library( ":aes_cbc_util", ":ecb_util", ":sha_util", + ":status", "//base", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", "//util/endian", "//util/gtl:map_util", - "//util:status", ], ) @@ -481,7 +508,7 @@ cc_library( srcs = ["error_space.cc"], hdrs = ["error_space.h"], deps = [ - "//util:status", + "//util:error_space", "//util:proto_status", "//protos/public:errors_proto", ], @@ -496,11 +523,11 @@ cc_library( ":drm_service_certificate", ":error_space", ":rsa_key", + ":status", ":x509_cert", "//base", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", - "//util:status", "//protos/public:client_identification_proto", "//protos/public:errors_proto", "//protos/public:remote_attestation_proto", @@ -518,11 +545,11 @@ cc_library( ":error_space", ":rsa_key", ":rsa_util", + ":status", "//base", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", "//util/gtl:map_util", - "//util:status", "//protos/public:client_identification_proto", "//protos/public:drm_certificate_proto", "//protos/public:errors_proto", @@ -559,10 +586,10 @@ cc_library( srcs = ["verified_media_pipeline.cc"], hdrs = ["verified_media_pipeline.h"], deps = [ + ":status", ":vmp_checker", "//base", "@abseil_repo//absl/strings", - "//util:status", "//protos/public:license_protocol_proto", ], ) @@ -572,13 +599,14 @@ cc_library( srcs = ["x509_cert.cc"], hdrs = ["x509_cert.h"], deps = [ + ":error_space", ":openssl_util", ":rsa_key", + ":status", "//base", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", "//external:openssl", - "//util:status", ], ) @@ -588,9 +616,9 @@ cc_library( srcs = ["test_utils.cc"], hdrs = ["test_utils.h"], deps = [ + ":status", "//base", "//external:openssl", - "//util:status", ], ) @@ -616,9 +644,9 @@ cc_library( ":certificate_type", ":error_space", ":rsa_key", + ":status", ":x509_cert", "//base", - "//util:status", "//protos/public:errors_proto", "//protos/public:verified_media_pipeline_proto", ], @@ -644,8 +672,8 @@ cc_library( srcs = ["string_util.cc"], hdrs = ["string_util.h"], deps = [ + ":status", "//base", - "//util:status", ], ) diff --git a/common/client_cert.cc b/common/client_cert.cc index da0d33e..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 "util/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 11812af..b2dc786 100644 --- a/common/client_cert.h +++ b/common/client_cert.h @@ -13,8 +13,8 @@ #include #include -#include "util/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 1f0e8b1..6aef13d 100644 --- a/common/client_id_util.h +++ b/common/client_id_util.h @@ -14,7 +14,7 @@ #define COMMON_CLIENT_ID_UTIL_H_ #include "absl/strings/string_view.h" -#include "util/status.h" +#include "common/status.h" #include "protos/public/client_identification.pb.h" namespace widevine { @@ -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 1e6de42..da97d3f 100644 --- a/common/device_status_list.cc +++ b/common/device_status_list.cc @@ -21,6 +21,7 @@ #include "absl/synchronization/mutex.h" #include "util/gtl/map_util.h" #include "common/client_cert.h" +#include "common/drm_service_certificate.h" #include "common/error_space.h" #include "common/rsa_key.h" #include "protos/public/client_identification.pb.h" @@ -51,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_); @@ -105,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()); @@ -154,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() != @@ -174,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, @@ -246,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."); } @@ -283,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 { @@ -294,28 +295,68 @@ 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(); } +Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( + const std::string& version, + std::string* signed_device_certificate_status_list_request) { + if (version.empty()) { + return Status(error_space, error::INVALID_ARGUMENT, "SDK version is empty"); + } + DCHECK(signed_device_certificate_status_list_request); + if (signed_device_certificate_status_list_request == nullptr) { + return Status(error_space, error::INVALID_ARGUMENT, + "Signed_device_certificate_status_list_request is empty"); + } + // Construct SignedDeviceCertificateStatusListRequest. + DeviceCertificateStatusListRequest request; + request.set_sdk_version(version); + request.set_sdk_time_seconds(DeviceStatusList::Instance()->GetCurrentTime()); + std::string device_certificate_status_list_request; + request.SerializeToString(&device_certificate_status_list_request); + SignedDeviceCertificateStatusListRequest signed_request; + signed_request.set_device_certificate_status_list_request( + device_certificate_status_list_request); + const DrmServiceCertificate* sc = + DrmServiceCertificate::GetDefaultDrmServiceCertificate(); + if (sc == nullptr) { + signed_device_certificate_status_list_request->clear(); + return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE, + "Drm service certificate is not loaded."); + } + const RsaPrivateKey* private_key = sc->private_key(); + if (private_key == nullptr) { + 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, + &signature); + signed_request.set_signature(signature); + signed_request.SerializeToString( + signed_device_certificate_status_list_request); + return OkStatus(); +} } // namespace widevine diff --git a/common/device_status_list.h b/common/device_status_list.h index 5bdd4c0..13782c7 100644 --- a/common/device_status_list.h +++ b/common/device_status_list.h @@ -16,7 +16,7 @@ #include "base/macros.h" #include "absl/synchronization/mutex.h" -#include "util/status.h" +#include "common/status.h" #include "protos/public/device_certificate_status.pb.h" #include "protos/public/provisioned_device_info.pb.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,9 +85,19 @@ 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); + /** + * Constructs signed device certificate status list request string. + * + * @param signed_device_certificate_status_list_request + * @param version + * @return Status - Status::OK if success, else error. + */ + static Status GenerateSignedDeviceCertificateStatusListRequest( + const std::string& version, + std::string* signed_device_certificate_status_list_request); private: // Returns true if the system ID is allowed to be revoked. 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 a18ae44..e786351 100644 --- a/common/drm_root_certificate.h +++ b/common/drm_root_certificate.h @@ -19,7 +19,7 @@ #include #include "base/macros.h" -#include "util/status.h" +#include "common/status.h" #include "common/certificate_type.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 69a3036..fec6055 100644 --- a/common/drm_service_certificate.h +++ b/common/drm_service_certificate.h @@ -18,9 +18,9 @@ #include #include "base/macros.h" -#include "util/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 34be518..40462ce 100644 --- a/common/remote_attestation_verifier.h +++ b/common/remote_attestation_verifier.h @@ -19,7 +19,7 @@ #include "base/macros.h" #include "base/thread_annotations.h" #include "absl/synchronization/mutex.h" -#include "util/status.h" +#include "common/status.h" #include "common/x509_cert.h" #include "protos/public/client_identification.pb.h" #include "protos/public/remote_attestation.pb.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 b223233..1e80e09 100644 --- a/common/signature_util.cc +++ b/common/signature_util.cc @@ -11,55 +11,50 @@ #include #include -#include "util/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 f66693f..25238fb 100644 --- a/common/signature_util.h +++ b/common/signature_util.h @@ -11,7 +11,7 @@ #include -#include "util/status.h" +#include "common/status.h" namespace widevine { namespace signature_util { @@ -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 new file mode 100644 index 0000000..94513ef --- /dev/null +++ b/common/status.cc @@ -0,0 +1,74 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2017 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// + +#include "common/status.h" + +#include + +#include "absl/base/macros.h" +#include "absl/strings/str_cat.h" +#include "util/error_space.h" + +namespace widevine { + +namespace { + +const char* kGenericErrorStatusMessage[] = {"OK", + "unknown_error", + "unknown_error", + "invalid_argument", + "unknown_error", + "not_found", + "already_exists", + "permission_denied", + "unknown_error", + "unknown_error", + "unknown_error", + "unknown_error", + "unimplemented", + "internal", + "unavailable"}; + +} // namespace + +class GenericErrorSpace : public util::ErrorSpaceImpl { + public: + static std::string space_name(); + static std::string code_to_string(int code); +}; + +std::string GenericErrorSpace::space_name() { return "generic"; } + +std::string GenericErrorSpace::code_to_string(int code) { + static_assert( + ABSL_ARRAYSIZE(kGenericErrorStatusMessage) == error::NUM_ERRORS, + "mismatching generic error status message and generic error status."); + + if (code >= 0 && code < error::NUM_ERRORS) + return kGenericErrorStatusMessage[code]; + return std::to_string(code); +} + + + +const util::ErrorSpace* Status::canonical_space() { + return GenericErrorSpace::Get(); +} + +std::string Status::ToString() const { + if (status_code_ == error::OK) return "OK"; + return absl::StrCat("Errors::", error_space_->String(status_code_), ": ", + error_message_); +} + +std::ostream& operator<<(std::ostream& os, const Status& x) { + os << x.ToString(); + return os; +} + +} // namespace widevine diff --git a/util/status.h b/common/status.h similarity index 66% rename from util/status.h rename to common/status.h index c690692..1d6597b 100644 --- a/util/status.h +++ b/common/status.h @@ -6,15 +6,14 @@ // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// -#ifndef UTIL_STATUS_H_ -#define UTIL_STATUS_H_ +#ifndef COMMON_STATUS_H_ +#define COMMON_STATUS_H_ #include #include "util/error_space.h" namespace widevine { -namespace util { namespace error { enum StatusCode { @@ -54,66 +53,56 @@ enum StatusCode { } // namespace error -class GenericErrorSpace : public ErrorSpaceImpl { - public: - static std::string SpaceName(); - static std::string CodeToString(int code); -}; - class Status { public: - Status() : status_code_(error::OK) {} - ~Status() {} + + Status() = default; + + ~Status() = default; + explicit Status(error::StatusCode c) : status_code_(c) {} + Status(error::StatusCode c, const std::string& error_message) : status_code_(c), error_message_(error_message) {} - Status(const ErrorSpace* e, error::StatusCode c, - const std::string& error_message) { - SetError(e, c, error_message); - } - Status(const ErrorSpace* e, int error, const std::string& error_message) { - SetError(e, error, error_message); - } - void SetError(const ErrorSpace* e, int c, const std::string& error_message) { - error_space_ = e; - status_code_ = c; - error_message_ = error_message; - } + + Status(const util::ErrorSpace* e, error::StatusCode c, + const std::string& error_message) + : error_space_(e), status_code_(c), error_message_(error_message) {} + + Status(const util::ErrorSpace* e, int error, const std::string& error_message) + : error_space_(e), status_code_(error), error_message_(error_message) {} bool ok() const { return status_code_ == error::OK; } - const ErrorSpace* error_space() const { return error_space_; } - static const ErrorSpace* canonical_space() { - return GenericErrorSpace::Get(); - } + const util::ErrorSpace* error_space() const { return error_space_; } + static const util::ErrorSpace* canonical_space(); std::string ToString() const; std::string error_message() const { return error_message_; } int error_code() const { return status_code_; } private: - const ErrorSpace* error_space_ = GenericErrorSpace::Get(); - int status_code_; + const util::ErrorSpace* error_space_ = canonical_space(); + int status_code_ = error::OK; std::string error_message_; -}; // class Status +}; inline Status OkStatus() { return Status(); } -// Here error_message_ is ignored during comparison. inline bool operator==(const Status& s1, const Status& s2) { return s1.error_space() == s2.error_space() && - s1.error_code() == s2.error_code(); + s1.error_code() == s2.error_code() && + s1.error_message() == s2.error_message(); } inline bool operator!=(const Status& s1, const Status& s2) { - return s1.error_space() != s2.error_space() || - s1.error_code() != s2.error_code(); + return !(s1 == s2); } + // Prints a human-readable representation of 'x' to 'os'. std::ostream& operator<<(std::ostream& os, const Status& x); #define CHECK_OK(expression) CHECK(expression.ok()) << expression.ToString() -} // namespace util } // namespace widevine -#endif // UTIL_STATUS_H_ +#endif // COMMON_STATUS_H_ diff --git a/util/status_test.cc b/common/status_test.cc similarity index 86% rename from util/status_test.cc rename to common/status_test.cc index a91259a..e3fda01 100644 --- a/util/status_test.cc +++ b/common/status_test.cc @@ -6,12 +6,10 @@ // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// -#include "util/status.h" - +#include "common/status.h" #include "testing/gunit.h" namespace widevine { -namespace util { TEST(StatusTest, OK_Status) { // test case for ok status. @@ -27,13 +25,13 @@ TEST(StatusTest, OK_Status2) { TEST(StatusTest, ALREADY_EXISTS_Status) { Status status(error::ALREADY_EXISTS, "it is already exist"); - EXPECT_EQ("Errors::ALREADY_EXISTS: it is already exist", status.ToString()); + EXPECT_EQ("Errors::already_exists: it is already exist", status.ToString()); } // test case for status in boundary cases. TEST(StatusTest, UNAVAILABLE_Status) { Status status(error::UNAVAILABLE, "unavailable"); - EXPECT_EQ("Errors::UNAVAILABLE: unavailable", status.ToString()); + EXPECT_EQ("Errors::unavailable: unavailable", status.ToString()); } TEST(StatusTest, NoNameCode) { @@ -43,7 +41,7 @@ TEST(StatusTest, NoNameCode) { TEST(StatusTest, EQUAL_OPERATOR) { Status status1(error::ALREADY_EXISTS, "already exists 1"); - Status status2(error::ALREADY_EXISTS, "already exists 2"); + Status status2(error::ALREADY_EXISTS, "already exists 1"); EXPECT_EQ(status1, status2); } @@ -59,5 +57,5 @@ TEST(StatusTest, NOT_EQUAL_OPERATOR_NONE_MSG) { EXPECT_NE(status1, status2); } -} // namespace util + } // namespace widevine diff --git a/common/string_util.cc b/common/string_util.cc index e2d580b..84031bb 100644 --- a/common/string_util.cc +++ b/common/string_util.cc @@ -11,14 +11,14 @@ #include #include #include -#include "util/status.h" +#include "common/status.h" 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 57b3b6f..9c9922d 100644 --- a/common/string_util.h +++ b/common/string_util.h @@ -10,14 +10,14 @@ #define COMMON_STRING_UTIL_H_ #include -#include "util/status.h" +#include "common/status.h" namespace widevine { 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 e78ef12..9252f93 100644 --- a/common/test_utils.h +++ b/common/test_utils.h @@ -14,7 +14,7 @@ #include -#include "util/status.h" +#include "common/status.h" namespace widevine { @@ -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 64a9582..a6372ce 100644 --- a/common/verified_media_pipeline.h +++ b/common/verified_media_pipeline.h @@ -13,16 +13,15 @@ #define COMMON_VERIFIED_MEDIA_PIPELINE_H_ #include -#include "util/status.h" +#include "common/status.h" #include "protos/public/license_protocol.pb.h" 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 b16107c..54caf6f 100644 --- a/common/vmp_checker.h +++ b/common/vmp_checker.h @@ -16,8 +16,8 @@ #include #include -#include "util/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 99986cf..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 "util/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 0bd34d5..e300928 100644 --- a/common/wvm_token_handler.h +++ b/common/wvm_token_handler.h @@ -14,7 +14,7 @@ #include "base/macros.h" #include "absl/strings/string_view.h" -#include "util/status.h" +#include "common/status.h" namespace widevine { @@ -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 12cf3ed..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 { @@ -184,6 +181,24 @@ std::string X509Cert::GetSerialNumber() const { return result; } +bool X509Cert::GetNotBeforeSeconds(int64_t* valid_start_seconds) const { + if (openssl_cert_ == nullptr) { + return false; + } + return Asn1TimeToEpochSeconds(X509_get0_notBefore(openssl_cert_), + valid_start_seconds) + .ok(); +} + +bool X509Cert::GetNotAfterSeconds(int64_t* valid_end_seconds) const { + if (openssl_cert_ == nullptr) { + return false; + } + return Asn1TimeToEpochSeconds(X509_get0_notAfter(openssl_cert_), + valid_end_seconds) + .ok(); +} + bool X509Cert::IsCaCertificate() const { return X509_check_ca(openssl_cert_) != 0; } @@ -204,6 +219,38 @@ bool X509Cert::GetV3BooleanExtension(const std::string& oid, bool* value) const return true; } +Status X509Cert::Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, + int64_t* epoch_seconds) const { + if (asn1_time == nullptr) { + // This code is exported to shared source. The exported code does not yet + // support MakeStatus. + // NOLINTNEXTLINE + return Status(error::INVALID_ARGUMENT, "asn1_time cannot be null."); + } + + if (epoch_seconds == nullptr) { + // NOLINTNEXTLINE + return Status(error::INVALID_ARGUMENT, "epoch_seconds cannot be null."); + } + + ScopedAsn1Time epoch_time(ASN1_TIME_new()); + if (!ASN1_TIME_set(epoch_time.get(), 0)) { + // NOLINTNEXTLINE + return Status(error::INTERNAL, "Failed to set epoch time."); + } + + int day = 0; + int seconds = 0; + if (!ASN1_TIME_diff(&day, &seconds, epoch_time.get(), asn1_time)) { + // NOLINTNEXTLINE + return Status(error::INTERNAL, + "Failed to convert asn1 time to epoch time."); + } + + *epoch_seconds = 24L * 3600L * day + seconds; + return OkStatus(); +} + X509CertChain::~X509CertChain() { Reset(); } void X509CertChain::Reset() { @@ -213,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-----"; @@ -225,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; @@ -234,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) { @@ -252,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() { @@ -305,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) { @@ -354,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(), @@ -380,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; } @@ -395,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 4ef5c13..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 "util/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; @@ -70,6 +70,16 @@ class X509Cert { // if an error occurs. std::string GetSerialNumber() const; + // Gets the start of the validity period for the certificate in seconds + // since the epoch. |valid_start_seconds| must not be null. Returns true on + // success, false otherwise. + bool GetNotBeforeSeconds(int64_t* valid_start_seconds) const; + + // Gets the end of the validity period for the certificate in seconds + // since the epoch. |valid_end_seconds| must not be null. Returns true on + // success, false otherwise. + bool GetNotAfterSeconds(int64_t* valid_end_seconds) const; + // Returns true if the certificate is a CA (root or intermediate) certificate. bool IsCaCertificate() const; @@ -81,6 +91,8 @@ class X509Cert { private: explicit X509Cert(X509* openssl_cert); + Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, + int64_t* epoch_seconds) const; X509* openssl_cert_; std::string subject_name_; @@ -100,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. @@ -136,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 e60775f..efc9ee3 100644 --- a/common/x509_cert_test.cc +++ b/common/x509_cert_test.cc @@ -107,6 +107,9 @@ const char kTestPemCertSubjectField_CN[] = "stable id/emailAddress=tinskip@google.com"; const char kTestPemCertSerialNumber[] = "\002"; +const int64_t kTestPemCertNotBeforeSeconds = 1376689440; +const int64_t kTestPemCertNotAfterSeconds = 2007755040; + const char kTestPemCertChain[] = "-----BEGIN CERTIFICATE-----\n" "MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n" @@ -352,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)); @@ -381,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")); @@ -389,13 +392,29 @@ 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(OkStatus(), test_cert.LoadPem(kTestPemCert)); + int64_t not_before_seconds = 0; + ASSERT_TRUE(test_cert.GetNotBeforeSeconds(¬_before_seconds)); + EXPECT_EQ(kTestPemCertNotBeforeSeconds, not_before_seconds); +} + +TEST(X509CertTest, GetNotAfterSeconds) { + X509Cert test_cert; + ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert)); + int64_t not_after_seconds = 0; + ASSERT_TRUE(test_cert.GetNotAfterSeconds(¬_after_seconds)); + EXPECT_EQ(kTestPemCertNotAfterSeconds, not_after_seconds); +} + TEST(X509CertTest, CertChain) { X509CertChain test_chain; - ASSERT_EQ(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); @@ -404,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()); @@ -412,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(), @@ -499,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/example/BUILD b/example/BUILD new file mode 100644 index 0000000..802b6b2 --- /dev/null +++ b/example/BUILD @@ -0,0 +1,39 @@ +################################################################################ +# Copyright 2019 Google LLC. +# +# This software is licensed under the terms defined in the Widevine Master +# License Agreement. For a copy of this agreement, please contact +# widevine-licensing@google.com. +################################################################################ + +# Build file for the example code. + +package( + default_visibility = ["//visibility:public"], +) + + +filegroup( + name = "binary_release_files", + srcs = [ + "wvpl_cas_proxy_environment_example.cc", + "wvpl_cas_proxy_session_example.cc", + ":wvpl_cas_proxy_environment_example", + ":wvpl_cas_proxy_session_example", + ], +) + +cc_binary( + name = "wvpl_cas_proxy_environment_example", + srcs = ["wvpl_cas_proxy_environment_example.cc"], + deps = [ + "//media_cas_proxy_sdk/external/common/wvpl:wvpl_cas_proxy_environment", + "//media_cas_proxy_sdk/external/common/wvpl:wvpl_cas_proxy_session", # build_cleaner: keep + ], +) + +cc_binary( + name = "wvpl_cas_proxy_session_example", + srcs = ["wvpl_cas_proxy_session_example.cc"], + deps = ["//media_cas_proxy_sdk/external/common/wvpl:wvpl_cas_proxy_session"], +) diff --git a/example/wvpl_cas_proxy_environment_example.cc b/example/wvpl_cas_proxy_environment_example.cc new file mode 100644 index 0000000..70a7032 --- /dev/null +++ b/example/wvpl_cas_proxy_environment_example.cc @@ -0,0 +1,24 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2019 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// + +// Example of usage of wvpl_cas_proxy_environment. + +#include +#include +#include + +#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h" + +int main(int argc, char **argv) { + std::map config_values; + widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment environment( + config_values); + std::cout << "Hello world!" << std::endl; + + return 0; +} diff --git a/example/wvpl_cas_proxy_session_example.cc b/example/wvpl_cas_proxy_session_example.cc new file mode 100644 index 0000000..cbc4814 --- /dev/null +++ b/example/wvpl_cas_proxy_session_example.cc @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2019 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// + +// Example of usage of wvpl_cas_proxy_session. + +#include +#include + +#include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h" + +int main(int argc, char **argv) { + std::cout << "Session version: " + << widevine_server::wv_pl_sdk::WvPLCASProxySession:: + GetVersionString() + << std::endl; + + return 0; +} diff --git a/license_server_sdk/internal/BUILD b/license_server_sdk/internal/BUILD index e923a1a..b36f44d 100644 --- a/license_server_sdk/internal/BUILD +++ b/license_server_sdk/internal/BUILD @@ -41,7 +41,6 @@ cc_library( "@abseil_repo//absl/synchronization", "//util/endian", "//util/random:global_id", - "//util:status", "//common:aes_cbc_util", "//common:certificate_type", "//common:client_cert", @@ -51,9 +50,11 @@ cc_library( "//common:random_util", "//common:remote_attestation_verifier", "//common:drm_root_certificate", - "//common:rsa_key", "//common:drm_service_certificate", + "//common:rsa_key", + "//common:sha_util", "//common:signing_key_util", + "//common:status", "//common:verified_media_pipeline", "//common:vmp_checker", "//protos/public:client_identification_proto", @@ -86,7 +87,6 @@ cc_library( "//external:openssl", "//util/endian", "//util/gtl:map_util", - "//util:status", "//common:client_cert", "//common:crypto_util", "//common:device_status_list", @@ -96,6 +96,7 @@ cc_library( "//common:drm_root_certificate", "//common:drm_service_certificate", "//common:signing_key_util", + "//common:status", "//common:wvm_token_handler", "//sdk/external/common/wvpl:wvpl_types", "//protos/public:client_identification_proto", @@ -120,6 +121,7 @@ cc_test( "//base", "//external:protobuf", "//testing:gunit_main", + "@abseil_repo//absl/memory", "@abseil_repo//absl/strings", "//common:aes_cbc_util", "//common:client_cert", @@ -131,6 +133,7 @@ cc_test( "//common:rsa_key", "//common:rsa_test_keys", "//common:rsa_util", + "//common:sha_util", "//common:signing_key_util", "//common:test_drm_certificates", "//common:test_utils", diff --git a/license_server_sdk/internal/generate_error_response.cc b/license_server_sdk/internal/generate_error_response.cc index e5c7a14..7511346 100644 --- a/license_server_sdk/internal/generate_error_response.cc +++ b/license_server_sdk/internal/generate_error_response.cc @@ -16,7 +16,6 @@ #include "protos/public/errors.pb.h" #include "protos/public/license_protocol.pb.h" -namespace util = widevine::util; using widevine::DRM_DEVICE_CERTIFICATE_REVOKED; using widevine::DrmServiceCertificate; using widevine::EXPIRED_CERTIFICATE_STATUS_LIST; @@ -26,7 +25,7 @@ using widevine::SERVICE_CERTIFICATE_REQUEST_MESSAGE; using widevine::SignedMessage; namespace widevine { -bool GenerateErrorResponse(const util::Status& create_session_status, +bool GenerateErrorResponse(const Status& create_session_status, std::string* license_response) { DCHECK(license_response); @@ -61,9 +60,8 @@ bool GenerateErrorResponse(const util::Status& create_session_status, break; } } - if ((create_session_status.error_space() == - util::Status::canonical_space()) && - (create_session_status.error_code() == util::error::UNAVAILABLE)) { + if ((create_session_status.error_space() == Status::canonical_space()) && + (create_session_status.error_code() == error::UNAVAILABLE)) { error_proto.set_error_code(LicenseError::SERVICE_UNAVAILABLE); } if (!error_proto.has_error_code()) { diff --git a/license_server_sdk/internal/generate_error_response.h b/license_server_sdk/internal/generate_error_response.h index 9b02b3e..7931f3f 100644 --- a/license_server_sdk/internal/generate_error_response.h +++ b/license_server_sdk/internal/generate_error_response.h @@ -11,17 +11,16 @@ #include -#include "util/status.h" +#include "common/status.h" namespace widevine { // Generates a SignedMessage containing a message generated in response to // an error condition. |status| is a previous error status returned by the -// Session or util::Status(util::error::UNAVAILABLE, ...) to indicate that the +// Session or Status(error::UNAVAILABLE, ...) to indicate that the // backend is unavailable, |signed_message| points to a std::string to contain the // serialized SignedMessage, and may not be NULL. This method returns true if // there is an error license to be sent to the client, or false otherwise. // Example usage in the Session::Create comments above. -bool GenerateErrorResponse(const util::Status& status, - std::string* license_response); +bool GenerateErrorResponse(const Status& status, std::string* license_response); } // namespace widevine #endif // LICENSE_SERVER_SDK_INTERNAL_GENERATE_ERROR_RESPONSE_H_ diff --git a/license_server_sdk/internal/parse_content_id.cc b/license_server_sdk/internal/parse_content_id.cc index 9a9f5f7..abe87f8 100644 --- a/license_server_sdk/internal/parse_content_id.cc +++ b/license_server_sdk/internal/parse_content_id.cc @@ -37,19 +37,18 @@ void AddKeyIdIfNotFound(const std::string& key_id, entry->add_key_ids(key_id); } -util::Status AddWidevinePsshInfo( - const std::string& pssh_data, - ContentInfo::ContentInfoEntry* content_info_entry) { +Status AddWidevinePsshInfo(const std::string& pssh_data, + ContentInfo::ContentInfoEntry* content_info_entry) { if (pssh_data.empty()) { - return util::Status(error_space, INVALID_WIDEVINE_PSSH_DATA, - "widevine-pssh-data-is-empty"); + return Status(error_space, INVALID_WIDEVINE_PSSH_DATA, + "widevine-pssh-data-is-empty"); } if (!content_info_entry->mutable_pssh() ->mutable_widevine_data() ->ParseFromString(pssh_data)) { - return util::Status(error_space, INVALID_WIDEVINE_PSSH_DATA, - "invalid-widevine-pssh-data"); + return Status(error_space, INVALID_WIDEVINE_PSSH_DATA, + "invalid-widevine-pssh-data"); } content_info_entry->mutable_pssh()->set_system_id( std::string(kWidevineSystemId, kWidevineSystemId + sizeof(kWidevineSystemId))); @@ -58,39 +57,37 @@ util::Status AddWidevinePsshInfo( for (int idx = 0; idx < wv_pssh.key_ids_size(); ++idx) AddKeyIdIfNotFound(wv_pssh.key_ids(idx), content_info_entry); - return util::OkStatus(); + return OkStatus(); } -util::Status ParseCencId( - const LicenseRequest::ContentIdentification& content_id, - ContentInfo* content_info) { +Status ParseCencId(const LicenseRequest::ContentIdentification& content_id, + ContentInfo* content_info) { content_info->set_init_data_type( LicenseRequest::ContentIdentification::InitData::CENC); for (int idx = 0; idx < content_id.cenc_id_deprecated().pssh_size(); ++idx) { - util::Status status = + Status status = AddWidevinePsshInfo(content_id.cenc_id_deprecated().pssh(idx), content_info->add_content_info_entry()); if (!status.ok()) return status; } - return util::OkStatus(); + return OkStatus(); } -util::Status AddWebmKeyId(const std::string& key_id, ContentInfo* content_info) { +Status AddWebmKeyId(const std::string& key_id, ContentInfo* content_info) { content_info->set_init_data_type( LicenseRequest::ContentIdentification::InitData::WEBM); content_info->add_content_info_entry()->add_key_ids(key_id); - return util::OkStatus(); + return OkStatus(); } -util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_info) { +Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_info) { const uint32_t kPsshType = 0x70737368; const size_t kPsshSystemIdSize = 16; const size_t kKeyIdSize = 16; const size_t kMinPsshSize = kPsshSystemIdSize + 8; if (boxes.empty()) { - return util::Status(error_space, INVALID_CENC_INIT_DATA, - "init-data-is-empty"); + return Status(error_space, INVALID_CENC_INIT_DATA, "init-data-is-empty"); } const char* r_ptr = boxes.data(); @@ -100,8 +97,7 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in ContentInfo::ContentInfoEntry content_info_entry; if (r_ptr + 8 > end_ptr) - return util::Status(error_space, INVALID_CENC_INIT_DATA, - "init-data-too-short"); + return Status(error_space, INVALID_CENC_INIT_DATA, "init-data-too-short"); const char* box_start = r_ptr; uint64_t box_size = BigEndian::Load32(r_ptr); @@ -111,8 +107,8 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in if (box_size == 1) { if (r_ptr + 8 > end_ptr) { - return util::Status(error_space, INVALID_CENC_INIT_DATA, - "init-data-too-short"); + return Status(error_space, INVALID_CENC_INIT_DATA, + "init-data-too-short"); } box_size = BigEndian::Load64(r_ptr); r_ptr += 8; @@ -120,12 +116,10 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in const char* box_end = box_start + box_size; if (box_end > end_ptr) { - return util::Status(error_space, INVALID_CENC_INIT_DATA, - "init-data-too-short"); + return Status(error_space, INVALID_CENC_INIT_DATA, "init-data-too-short"); } if (box_end < r_ptr) { - return util::Status(error_space, INVALID_CENC_INIT_DATA, - "invalid-box-size"); + return Status(error_space, INVALID_CENC_INIT_DATA, "invalid-box-size"); } if (box_type != kPsshType) { @@ -134,15 +128,15 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in } if (r_ptr + kMinPsshSize > box_end) - return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); + return Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); const uint32_t version_and_flags = BigEndian::Load32(r_ptr); r_ptr += 4; const uint8_t version = static_cast(version_and_flags >> 24); if (version > 1) { - return util::Status(error_space, UNSUPPORTED_PSSH_VERSION, - absl::StrCat("unsupported-pssh-version ", version)); + return Status(error_space, UNSUPPORTED_PSSH_VERSION, + absl::StrCat("unsupported-pssh-version ", version)); } content_info_entry.mutable_pssh()->set_system_id( @@ -153,16 +147,14 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in if (version == 1) { if (r_ptr + 4 > box_end) { - return util::Status(error_space, INVALID_PSSH, - "pssh-contents-too-short"); + return Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); } const uint32_t num_key_ids = BigEndian::Load32(r_ptr); r_ptr += 4; if (r_ptr + (num_key_ids * kKeyIdSize) > box_end) { - return util::Status(error_space, INVALID_PSSH, - "pssh-contents-too-short"); + return Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); } for (uint32_t idx = 0; idx < num_key_ids; ++idx) { @@ -173,18 +165,18 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in } if (r_ptr + 4 > box_end) - return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); + return Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); uint32_t data_size = BigEndian::Load32(r_ptr); r_ptr += 4; if (r_ptr + data_size > box_end) - return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); + return Status(error_space, INVALID_PSSH, "pssh-contents-too-short"); if (r_ptr + data_size < box_end) - return util::Status(error_space, INVALID_PSSH, "pssh-contents-too-long"); + return Status(error_space, INVALID_PSSH, "pssh-contents-too-long"); if (is_widevine_pssh) { - util::Status status = AddWidevinePsshInfo( - std::string(r_ptr, r_ptr + data_size), &content_info_entry); + Status status = AddWidevinePsshInfo(std::string(r_ptr, r_ptr + data_size), + &content_info_entry); if (!status.ok()) return status; } else { content_info_entry.mutable_pssh()->set_raw_data( @@ -195,14 +187,13 @@ util::Status ParseIsoBmffBoxes(const std::string& boxes, ContentInfo* content_in *content_info->add_content_info_entry() = content_info_entry; } - return util::OkStatus(); + return OkStatus(); } -util::Status ParseInitData( - const LicenseRequest::ContentIdentification& content_id, - ContentInfo* content_info) { +Status ParseInitData(const LicenseRequest::ContentIdentification& content_id, + ContentInfo* content_info) { if (!content_id.init_data().has_init_data()) - return util::Status(error_space, MISSING_INIT_DATA, "missing-init-data"); + return Status(error_space, MISSING_INIT_DATA, "missing-init-data"); if (content_id.init_data().init_data_type() == LicenseRequest::ContentIdentification::InitData::CENC) { @@ -212,15 +203,13 @@ util::Status ParseInitData( LicenseRequest::ContentIdentification::InitData::WEBM) { return AddWebmKeyId(content_id.init_data().init_data(), content_info); } - return util::Status(error_space, UNKNOWN_INIT_DATA_TYPE, - "unknown-init-data-type"); + return Status(error_space, UNKNOWN_INIT_DATA_TYPE, "unknown-init-data-type"); } } // namespace -util::Status ParseContentId( - const LicenseRequest::ContentIdentification& content_id, - ContentInfo* content_info) { +Status ParseContentId(const LicenseRequest::ContentIdentification& content_id, + ContentInfo* content_info) { DCHECK(content_info); content_info->Clear(); @@ -235,8 +224,8 @@ util::Status ParseContentId( default: break; } - return util::Status(error_space, INVALID_CONTENT_ID_TYPE, - "invalid-content-id-type"); + return Status(error_space, INVALID_CONTENT_ID_TYPE, + "invalid-content-id-type"); } } // namespace widevine diff --git a/license_server_sdk/internal/parse_content_id.h b/license_server_sdk/internal/parse_content_id.h index 6109a25..281ce62 100644 --- a/license_server_sdk/internal/parse_content_id.h +++ b/license_server_sdk/internal/parse_content_id.h @@ -9,7 +9,7 @@ #ifndef LICENSE_SERVER_SDK_INTERNAL_PARSE_CONTENT_ID_H__ #define LICENSE_SERVER_SDK_INTERNAL_PARSE_CONTENT_ID_H__ -#include "util/status.h" +#include "common/status.h" #include "protos/public/license_protocol.pb.h" namespace widevine { @@ -20,9 +20,8 @@ class ContentInfo; // the ContentInfo message passed into |content_info|. This function deep parses // PSSH boxes and the Widevine PSSH Data. |content_info| may not be NULL and the // caller retains ownership. -util::Status ParseContentId( - const LicenseRequest::ContentIdentification& content_id, - ContentInfo* content_info); +Status ParseContentId(const LicenseRequest::ContentIdentification& content_id, + ContentInfo* content_info); } // namespace widevine diff --git a/license_server_sdk/internal/parse_content_id_test.cc b/license_server_sdk/internal/parse_content_id_test.cc index f169d9a..e461444 100644 --- a/license_server_sdk/internal/parse_content_id_test.cc +++ b/license_server_sdk/internal/parse_content_id_test.cc @@ -107,7 +107,7 @@ void MakeInitDataWebmContentId( void VerifyWebmContentId( const LicenseRequest::ContentIdentification& content_id) { ContentInfo content_info; - ASSERT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info)); + ASSERT_EQ(OkStatus(), ParseContentId(content_id, &content_info)); ASSERT_EQ(LicenseRequest::ContentIdentification::InitData::WEBM, content_info.init_data_type()); ASSERT_EQ(1, content_info.content_info_entry_size()); @@ -140,7 +140,7 @@ void MakeExistingLicenseContentId( void VerifyCencContentId( const LicenseRequest::ContentIdentification& content_id) { ContentInfo content_info; - ASSERT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info)); + ASSERT_EQ(OkStatus(), ParseContentId(content_id, &content_info)); ASSERT_EQ(LicenseRequest::ContentIdentification::InitData::CENC, content_info.init_data_type()); ASSERT_EQ(1, content_info.content_info_entry_size()); @@ -194,7 +194,7 @@ TEST(ParseContentIdTest, PsshV1) { MakeInitDataCencContentId(std::string(kWvPsshV1, kWvPsshV1 + sizeof(kWvPsshV1)), &content_id); ContentInfo content_info; - EXPECT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info)); + EXPECT_EQ(OkStatus(), ParseContentId(content_id, &content_info)); EXPECT_EQ(LicenseRequest::ContentIdentification::InitData::CENC, content_info.init_data_type()); ASSERT_EQ(1, content_info.content_info_entry_size()); @@ -210,9 +210,9 @@ TEST(ParseContentIdTest, ExistingLicense) { LicenseRequest::ContentIdentification content_id; ContentInfo content_info; MakeExistingLicenseContentId(&content_id); - EXPECT_EQ(util::Status(error_space, INVALID_CONTENT_ID_TYPE, - "invalid-content-id-type"), - ParseContentId(content_id, &content_info)); + EXPECT_EQ( + Status(error_space, INVALID_CONTENT_ID_TYPE, "invalid-content-id-type"), + ParseContentId(content_id, &content_info)); } TEST(ParseContentIdTest, MultipleBoxes) { @@ -227,7 +227,7 @@ TEST(ParseContentIdTest, MultipleBoxes) { std::string(kNonPsshBox, kNonPsshBox + sizeof(kNonPsshBox)), &content_id); ContentInfo content_info; - EXPECT_EQ(util::OkStatus(), ParseContentId(content_id, &content_info)); + EXPECT_EQ(OkStatus(), ParseContentId(content_id, &content_info)); EXPECT_EQ(LicenseRequest::ContentIdentification::InitData::CENC, content_info.init_data_type()); EXPECT_EQ(3, content_info.content_info_entry_size()); diff --git a/license_server_sdk/internal/session_impl.cc b/license_server_sdk/internal/session_impl.cc index 5027a89..0a3a615 100644 --- a/license_server_sdk/internal/session_impl.cc +++ b/license_server_sdk/internal/session_impl.cc @@ -35,6 +35,7 @@ #include "common/random_util.h" #include "common/remote_attestation_verifier.h" #include "common/rsa_key.h" +#include "common/sha_util.h" #include "common/signing_key_util.h" #include "common/verified_media_pipeline.h" #include "common/vmp_checker.h" @@ -49,8 +50,8 @@ namespace widevine { // TODO(user): These constants are also defined in public/session.cc. Fix the // duplicate definitions. -const char* SessionImpl::kEncryptionKeyLabel = "ENCRYPTION"; -const uint32_t SessionImpl::kEncryptionKeySizeBits = 128; +const char* SessionImpl::kWrappingKeyLabel = "ENCRYPTION"; +const uint32_t SessionImpl::kWrappingKeySizeBits = 128; const char* SessionImpl::kSigningKeyLabel = "AUTHENTICATION"; const uint32_t SessionImpl::kSigningKeySizeBits = 256; bool SessionImpl::is_service_certificate_loaded_ = false; @@ -90,12 +91,12 @@ void SessionImpl::SetPreProvisioningKeys( KeyboxClientCert::SetPreProvisioningKeys(keys); } -util::Status SessionImpl::SetCertificateStatusList( +Status SessionImpl::SetCertificateStatusList( const DrmRootCertificate* root_cert, const std::string& certificate_status_list, uint32_t expiration_period_seconds, bool allow_unknown_devices) { CHECK(root_cert); - util::Status status = DeviceStatusList::Instance()->UpdateStatusList( + Status status = DeviceStatusList::Instance()->UpdateStatusList( root_cert->public_key(), certificate_status_list, expiration_period_seconds); if (!status.ok()) { @@ -104,16 +105,16 @@ util::Status SessionImpl::SetCertificateStatusList( DeviceStatusList::Instance()->set_allow_unknown_devices( allow_unknown_devices); - return util::OkStatus(); + return OkStatus(); } -util::Status SessionImpl::AddDrmServiceCertificate( +Status SessionImpl::AddDrmServiceCertificate( const DrmRootCertificate* root_cert, const std::string& service_certificate, const std::string& service_private_key, const std::string& service_private_key_passphrase) { CHECK(root_cert); - util::Status status = DrmServiceCertificate::AddDrmServiceCertificate( + Status status = DrmServiceCertificate::AddDrmServiceCertificate( root_cert, service_certificate, service_private_key, service_private_key_passphrase); if (!status.ok()) { @@ -134,24 +135,24 @@ void SessionImpl::AllowRevokedDevices(const std::string& system_id_list) { DeviceStatusList::Instance()->AllowRevokedDevices(system_id_list); } -util::Status SessionImpl::Create(const DrmRootCertificate* root_cert, - const std::string& signed_license_request, - SessionImpl** session) { +Status SessionImpl::Create(const DrmRootCertificate* root_cert, + const std::string& signed_license_request, + SessionImpl** session) { if (!is_service_certificate_loaded_) { - return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, ""); + return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND, ""); } return SessionImpl::Create(root_cert, signed_license_request, session, nullptr); } -util::Status SessionImpl::Create(const DrmRootCertificate* root_cert, - const std::string& signed_license_request, - SessionImpl** session, - LicenseRequest* parsed_request_out) { +Status SessionImpl::Create(const DrmRootCertificate* root_cert, + const std::string& signed_license_request, + SessionImpl** session, + LicenseRequest* parsed_request_out) { CHECK(root_cert); DCHECK(session); - util::Status status; + Status status; LicenseRequest* request_ptr = new LicenseRequest(); SignedMessage* signed_message_ptr = new SignedMessage(); @@ -168,7 +169,7 @@ util::Status SessionImpl::Create(const DrmRootCertificate* root_cert, } if (request->has_encrypted_client_id()) { if (request->has_client_id()) { - status = util::Status(error_space, MULTIPLE_CLIENT_ID, ""); + status = Status(error_space, MULTIPLE_CLIENT_ID, ""); return status; } status = DrmServiceCertificate::DecryptClientIdentification( @@ -200,12 +201,12 @@ util::Status SessionImpl::Create(const DrmRootCertificate* root_cert, return status; } -util::Status SessionImpl::CreateForProxy( +Status SessionImpl::CreateForProxy( const DrmRootCertificate* root_cert, const std::string& signed_license_request, const PlatformVerificationStatus platform_verification_status, const ClientIdentification* client_id, SessionImpl** session, LicenseRequest* parsed_request_out) { - util::Status status(util::OkStatus()); + Status status(OkStatus()); DCHECK(session); DCHECK(*session == nullptr); @@ -248,13 +249,13 @@ util::Status SessionImpl::CreateForProxy( return status; } -util::Status SessionImpl::LoadKeyControlNonce(const LicenseRequest& request, - bool* has_key_control_nonce, - uint32_t* key_control_nonce) { +Status SessionImpl::LoadKeyControlNonce(const LicenseRequest& request, + bool* has_key_control_nonce, + uint32_t* key_control_nonce) { DCHECK(has_key_control_nonce); DCHECK(key_control_nonce); - util::Status status; + Status status; *has_key_control_nonce = false; if (request.has_key_control_nonce()) { // Newer type uint32_t nonce. @@ -269,39 +270,38 @@ util::Status SessionImpl::LoadKeyControlNonce(const LicenseRequest& request, kc_nonce_string.resize(nul_pos); } if (!absl::SimpleAtoi(kc_nonce_string, key_control_nonce)) { - return util::Status(error_space, INVALID_KEY_CONTROL_NONCE, - request.key_control_nonce_deprecated()); + return Status(error_space, INVALID_KEY_CONTROL_NONCE, + request.key_control_nonce_deprecated()); } *has_key_control_nonce = true; } - return util::OkStatus(); + return OkStatus(); } -util::Status SessionImpl::CheckLicenseRequestFields( - const LicenseRequest& request) { +Status SessionImpl::CheckLicenseRequestFields(const LicenseRequest& request) { if (request.type() == LicenseRequest::NEW) { if (!request.has_client_id()) { - return util::Status(error_space, MISSING_CLIENT_ID, - "new-license-missing-client-id"); + return Status(error_space, MISSING_CLIENT_ID, + "new-license-missing-client-id"); } } else { if (!request.has_content_id()) { - return util::Status(error_space, MISSING_CONTENT_ID, - "renew-release-license-missing-content-id"); + return Status(error_space, MISSING_CONTENT_ID, + "renew-release-license-missing-content-id"); } if (!request.content_id().has_existing_license()) { - return util::Status(error_space, MISSING_LICENSE_ID, - "renew-release-license-missing-existing-license"); + return Status(error_space, MISSING_LICENSE_ID, + "renew-release-license-missing-existing-license"); } if (!request.content_id().existing_license().has_license_id()) { - return util::Status(error_space, MISSING_LICENSE_ID, - "renew-release-license-missing-license-id"); + return Status(error_space, MISSING_LICENSE_ID, + "renew-release-license-missing-license-id"); } } - return util::OkStatus(); + return OkStatus(); } -util::Status SessionImpl::ParseLicenseRequestFromString( +Status SessionImpl::ParseLicenseRequestFromString( const std::string& signed_license_request, SignedMessage* signed_message, LicenseRequest* license_request) { DCHECK(signed_message); @@ -309,21 +309,20 @@ util::Status SessionImpl::ParseLicenseRequestFromString( // Deserialize the signed message if (!signed_message->ParseFromString(signed_license_request)) { - return util::Status(error_space, SIGNED_MESSAGE_PARSE_ERROR, ""); + return Status(error_space, SIGNED_MESSAGE_PARSE_ERROR, ""); } if (signed_message->type() == SignedMessage::SERVICE_CERTIFICATE_REQUEST) { - return util::Status(error_space, SERVICE_CERTIFICATE_REQUEST_MESSAGE, - std::string()); + return Status(error_space, SERVICE_CERTIFICATE_REQUEST_MESSAGE, std::string()); } if (signed_message->type() != SignedMessage::LICENSE_REQUEST && signed_message->type() != SignedMessage::CAS_LICENSE_REQUEST) { - return util::Status(error_space, INVALID_MESSAGE_TYPE, std::string()); + return Status(error_space, INVALID_MESSAGE_TYPE, std::string()); } if (!license_request->ParseFromString(signed_message->msg())) { - return util::Status(error_space, LICENSE_REQUEST_PARSE_ERROR, ""); + return Status(error_space, LICENSE_REQUEST_PARSE_ERROR, ""); } - return util::OkStatus(); + return OkStatus(); } std::string SessionImpl::DeriveKey(const std::string& key, const std::string& label, @@ -347,12 +346,12 @@ SessionImpl::SessionImpl(SignedMessage* message, LicenseRequest* request, SessionImpl::~SessionImpl() {} -util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) { +Status SessionImpl::Init(const DrmRootCertificate* root_cert) { if (license_request_->has_client_id()) { // Check the client token and verify the message signature. ClientCert* client_cert_ptr = NULL; - util::Status status = ClientCert::Create( + Status status = ClientCert::Create( root_cert, license_request_->client_id().type(), license_request_->client_id().token(), &client_cert_ptr); client_cert_.reset(client_cert_ptr); @@ -365,8 +364,8 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) { if (!client_cert_->service_id().empty() && DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie() ->provider_id() == client_cert_->service_id()) { - status = util::Status(error_space, PROVIDER_ID_MISMATCH, - "client-cert-service-cert-id-mismatch"); + status = Status(error_space, PROVIDER_ID_MISMATCH, + "client-cert-service-cert-id-mismatch"); return status; } provisioned_device_info_.reset(new ProvisionedDeviceInfo); @@ -381,7 +380,7 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) { // Generate/Derive a new signing key if one does not previously exist. client_cert_->GenerateSigningKey(signed_message_->msg(), license_request_->protocol_version()); - util::Status status = client_cert_->VerifySignature( + Status status = client_cert_->VerifySignature( signed_message_->msg(), signed_message_->signature(), license_request_->protocol_version()); if (!status.ok()) { @@ -393,7 +392,7 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) { // proxy. platform_verification_status_ would either be set at the proxy // or as result of calling VerifyPlatform(). if (platform_verification_status_ == PLATFORM_NO_VERIFICATION) { - util::Status status = VerifyPlatform(); + Status status = VerifyPlatform(); if (!status.ok()) { LOG(ERROR) << "Platform verification failed. Status: " << status << ", License Request: " @@ -401,7 +400,7 @@ util::Status SessionImpl::Init(const DrmRootCertificate* root_cert) { return status; } } - return util::OkStatus(); + return OkStatus(); } const std::string& SessionImpl::GetSessionId() { @@ -428,75 +427,76 @@ bool SessionImpl::GetProvisionedDeviceInfo( return false; } -util::Status SessionImpl::GetRequestId(std::string* request_id) const { +Status SessionImpl::GetRequestId(std::string* request_id) const { DCHECK(request_id); DCHECK(license_request_); if (!license_request_->has_content_id()) - return util::Status(error_space, MISSING_CONTENT_ID, "missing-content-id"); + return Status(error_space, MISSING_CONTENT_ID, "missing-content-id"); const LicenseRequest::ContentIdentification& content_id = license_request_->content_id(); if (content_id.has_init_data()) { *request_id = content_id.init_data().request_id(); - return util::OkStatus(); + return OkStatus(); } if (content_id.has_cenc_id_deprecated()) { *request_id = content_id.cenc_id_deprecated().request_id(); - return util::OkStatus(); + return OkStatus(); } if (content_id.has_webm_id_deprecated()) { *request_id = content_id.webm_id_deprecated().request_id(); - return util::OkStatus(); + return OkStatus(); } - return util::Status(error_space, INVALID_CONTENT_ID_TYPE, - "invalid-content-id-type"); + return Status(error_space, INVALID_CONTENT_ID_TYPE, + "invalid-content-id-type"); } -util::Status SessionImpl::GetLicenseType(LicenseType* license_type) const { +Status SessionImpl::GetLicenseType(LicenseType* license_type) const { DCHECK(license_type); if (!license_request_->has_content_id()) - return util::Status(error_space, MISSING_CONTENT_ID, "missing-content-id"); + return Status(error_space, MISSING_CONTENT_ID, "missing-content-id"); const LicenseRequest::ContentIdentification& content_id = license_request_->content_id(); if (content_id.has_init_data()) { *license_type = content_id.init_data().license_type(); - return util::OkStatus(); + return OkStatus(); } if (content_id.has_cenc_id_deprecated()) { *license_type = content_id.cenc_id_deprecated().license_type(); - return util::OkStatus(); + return OkStatus(); } if (content_id.has_webm_id_deprecated()) { *license_type = content_id.webm_id_deprecated().license_type(); - return util::OkStatus(); + return OkStatus(); } if (content_id.has_existing_license()) { *license_type = content_id.existing_license().license_id().type(); - return util::OkStatus(); + return OkStatus(); } - return util::Status(error_space, INVALID_CONTENT_ID_TYPE, - "invalid-content-id-type"); + return Status(error_space, INVALID_CONTENT_ID_TYPE, + "invalid-content-id-type"); } -util::Status SessionImpl::GetContentInfo(ContentInfo* content_info) const { +Status SessionImpl::GetContentInfo(ContentInfo* content_info) const { DCHECK(content_info); if (!license_request_->has_content_id()) - return util::Status(error_space, MISSING_CONTENT_ID, "missing-content-id"); + return Status(error_space, MISSING_CONTENT_ID, "missing-content-id"); return ParseContentId(license_request_->content_id(), content_info); } -util::Status SessionImpl::GenerateNewLicenseInfo( - const SessionInit* session_init, LicenseIdentification* new_id, - std::string* renewal_signing_key, std::string* signing_key) { +Status SessionImpl::GenerateNewLicenseInfo(const SessionInit* session_init, + LicenseIdentification* new_id, + std::string* renewal_signing_key, + std::string* signing_key) { DCHECK(new_id); DCHECK(renewal_signing_key); DCHECK(signing_key); std::string request_id; - util::Status status = GetRequestId(&request_id); + Status status = GetRequestId(&request_id); if (!status.ok()) return status; new_id->set_request_id(request_id); @@ -512,7 +512,7 @@ util::Status SessionImpl::GenerateNewLicenseInfo( // GetSessionID(). if (session_init && session_init->has_session_id()) { if (!session_id_.empty() && (session_id_ != session_init->session_id())) { - status = util::Status(error_space, SESSION_ID_MISMATCH, ""); + status = Status(error_space, SESSION_ID_MISMATCH, ""); } else { new_id->set_session_id(session_init->session_id()); } @@ -540,12 +540,12 @@ util::Status SessionImpl::GenerateNewLicenseInfo( if (!status.ok()) return status; uint32_t signing_key_material_size_bytes = - SigningKeyMaterialSize(license_request_->protocol_version()) / 8; + SigningKeyMaterialSizeBits(license_request_->protocol_version()) / 8; if (session_init) { if (session_init->has_signing_key()) { if (session_init->signing_key().size() != signing_key_material_size_bytes) { - status = util::Status(error_space, INVALID_SIGNING_KEY_SIZE, ""); + status = Status(error_space, INVALID_SIGNING_KEY_SIZE, ""); return status; } *renewal_signing_key = session_init->signing_key(); @@ -555,35 +555,37 @@ util::Status SessionImpl::GenerateNewLicenseInfo( } else if (session_init->has_master_signing_key()) { if (session_init->master_signing_key().size() != kMasterSigningKeySizeBytes) { - status = - util::Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, ""); + status = Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, ""); return status; } std::string context; if (new_id->SerializeToString(&context)) { *renewal_signing_key = DeriveKey( session_init->master_signing_key(), std::string(kSigningKeyLabel), - context, - SigningKeyMaterialSize(license_request_->protocol_version())); + license_request_->protocol_version() < VERSION_2_2 + ? context + : Sha512_Hash(context), + SigningKeyMaterialSizeBits(license_request_->protocol_version())); } } } using crypto_util::kSigningKeySizeBytes; if (!renewal_signing_key->empty() && renewal_signing_key->size() != signing_key_material_size_bytes) { - status = util::Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, ""); + status = Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, ""); } new_id->set_version(0); *signing_key = client_cert_->signing_key(); return status; } -util::Status SessionImpl::GeneratePriorLicenseInfo( - const SessionInit* session_init, SessionState* session_state, - LicenseIdentification* new_id, std::string* signing_key) { +Status SessionImpl::GeneratePriorLicenseInfo(const SessionInit* session_init, + SessionState* session_state, + LicenseIdentification* new_id, + std::string* signing_key) { DCHECK(new_id); DCHECK(signing_key); - util::Status status; + Status status; if (session_state) { // If the session_state is provided, we expect to have the previous // LicenseIdentification to compare against. @@ -600,7 +602,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( !google::protobuf::util::MessageDifferencer::Equals( license_request_->content_id().existing_license().license_id(), session_state->license_id())) { - status = util::Status(error_space, RENEWAL_LICENSE_ID_MISMATCH, ""); + status = Status(error_space, RENEWAL_LICENSE_ID_MISMATCH, ""); return status; } } @@ -619,18 +621,17 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( } else if (session_init) { if (session_init->has_signing_key()) { uint32_t signing_key_material_size_bytes = - SigningKeyMaterialSize(license_request_->protocol_version()) / 8; + SigningKeyMaterialSizeBits(license_request_->protocol_version()) / 8; if (session_init->signing_key().size() != signing_key_material_size_bytes) { - status = util::Status(error_space, INVALID_SIGNING_KEY_SIZE, ""); + status = Status(error_space, INVALID_SIGNING_KEY_SIZE, ""); return status; } *signing_key = session_init->signing_key(); } else if (session_init->has_master_signing_key()) { if (session_init->master_signing_key().size() != kMasterSigningKeySizeBytes) { - status = - util::Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, ""); + status = Status(error_space, INVALID_MASTER_SIGNING_KEY_SIZE, ""); return status; } LicenseIdentification id; @@ -641,20 +642,22 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( if (id.SerializeToString(&context)) { *signing_key = DeriveKey( session_init->master_signing_key(), std::string(kSigningKeyLabel), - context, - SigningKeyMaterialSize(license_request_->protocol_version())); + license_request_->protocol_version() < VERSION_2_2 + ? context + : Sha512_Hash(context), + SigningKeyMaterialSizeBits(license_request_->protocol_version())); } } } if (signing_key->empty()) { - status = util::Status(error_space, MISSING_RENEWAL_SIGNING_KEY, ""); + status = Status(error_space, MISSING_RENEWAL_SIGNING_KEY, ""); return status; } uint32_t signing_key_material_size_bytes = - SigningKeyMaterialSize(license_request_->protocol_version()) / 8; + SigningKeyMaterialSizeBits(license_request_->protocol_version()) / 8; if (signing_key->size() < signing_key_material_size_bytes) { - status = util::Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, ""); + status = Status(error_space, INVALID_RENEWAL_SIGNING_KEY_SIZE, ""); return status; } signing_key->resize(signing_key_material_size_bytes); @@ -662,7 +665,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( GetClientSigningKey(*signing_key, license_request_->protocol_version()), signed_message_->signature(), signed_message_->msg())) { - status = util::Status(error_space, INVALID_RENEWAL_SIGNATURE, ""); + status = Status(error_space, INVALID_RENEWAL_SIGNATURE, ""); return status; } @@ -676,8 +679,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( .existing_license() .session_usage_table_entry(); if (session_usage.size() <= kSha1SignatureSizeBytes) { - status = - util::Status(error_space, INVALID_SESSION_USAGE_TABLE_ENTRY, ""); + status = Status(error_space, INVALID_SESSION_USAGE_TABLE_ENTRY, ""); return status; } if (!crypto_util::VerifySignatureHmacSha1( @@ -685,7 +687,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( license_request_->protocol_version()), session_usage.substr(0, kSha1SignatureSizeBytes), session_usage.substr(kSha1SignatureSizeBytes))) { - status = util::Status(error_space, INVALID_SESSION_USAGE_SIGNATURE, ""); + status = Status(error_space, INVALID_SESSION_USAGE_SIGNATURE, ""); return status; } } @@ -700,8 +702,8 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( system_id = client_cert_->system_id(); } if (system_id && !DeviceStatusList::Instance()->IsSystemIdActive(system_id)) { - status = util::Status(error_space, UNSUPPORTED_SYSTEM_ID, - "system-id-for-renewal-not-active"); + status = Status(error_space, UNSUPPORTED_SYSTEM_ID, + "system-id-for-renewal-not-active"); return status; } *new_id = license_request_->content_id().existing_license().license_id(); @@ -709,7 +711,7 @@ util::Status SessionImpl::GeneratePriorLicenseInfo( return status; } -util::Status SessionImpl::GenerateSignedLicense( +Status SessionImpl::GenerateSignedLicense( const License::Policy* policy, const std::list* key_container, const SessionInit* session_init, SessionState* session_state, @@ -717,14 +719,13 @@ util::Status SessionImpl::GenerateSignedLicense( DCHECK(signed_message_bytes); *signed_message_bytes = ""; - util::Status status; + Status status; LicenseIdentification new_id; std::string signing_key, renewal_signing_key; if (license_request_->type() != LicenseRequest::NEW) { if (key_container && !key_container->empty()) { - status = util::Status(error_space, - RENEWAL_WITH_CONTENT_KEYS_NOT_ALLOWED, ""); + status = Status(error_space, RENEWAL_WITH_CONTENT_KEYS_NOT_ALLOWED, ""); return status; } status = GeneratePriorLicenseInfo(session_init, session_state, &new_id, @@ -736,7 +737,7 @@ util::Status SessionImpl::GenerateSignedLicense( if (!status.ok()) return status; if (signing_key.empty()) { - status = util::Status(error_space, MISSING_SIGNING_KEY, ""); + status = Status(error_space, MISSING_SIGNING_KEY, ""); return status; } // Build up the license using the information passed in. @@ -766,33 +767,35 @@ util::Status SessionImpl::GenerateSignedLicense( VLOG(3) << "Renewal Signing Key before encryption: " << absl::BytesToHexString(renewal_signing_key); } else if (license.policy().can_renew()) { - status = - util::Status(error_space, MISSING_RENEWAL_SIGNING_KEY, - "required for NEW license with can_renew = true."); + status = Status(error_space, MISSING_RENEWAL_SIGNING_KEY, + "required for NEW license with can_renew = true."); return status; } if ((license.id().type() == OFFLINE) && !license.policy().can_persist()) { - status = util::Status(error_space, INVALID_OFFLINE_CAN_PERSIST, ""); + status = Status(error_space, INVALID_OFFLINE_CAN_PERSIST, ""); return status; } } else if (license_request_->type() == LicenseRequest::RELEASE) { if (license.has_policy() && license.policy().can_play()) { // Invalid RELEASE response. can_play should be false. - status = util::Status(error_space, INVALID_RELEASE_CAN_PLAY_VALUE, ""); + status = Status(error_space, INVALID_RELEASE_CAN_PLAY_VALUE, ""); return status; } } - std::string encryption_key; + std::string wrapping_key; if (key_container && !key_container->empty()) { if (!client_cert_.get()) { - status = util::Status(error_space, MISSING_CLIENT_CERT, ""); + status = Status(error_space, MISSING_CLIENT_CERT, ""); return status; } - encryption_key = DeriveKey(client_cert_->key(), std::string(kEncryptionKeyLabel), - signed_message_->msg(), kEncryptionKeySizeBits); - if (encryption_key.empty()) { - status = util::Status(error_space, MISSING_ENCRYPTION_KEY, ""); + wrapping_key = DeriveKey(client_cert_->key(), kWrappingKeyLabel, + license_request_->protocol_version() < VERSION_2_2 + ? signed_message_->msg() + : Sha512_Hash(signed_message_->msg()), + kWrappingKeySizeBits); + if (wrapping_key.empty()) { + status = Status(error_space, MISSING_ENCRYPTION_KEY, ""); return status; } for (std::list::const_iterator iter = @@ -801,23 +804,22 @@ util::Status SessionImpl::GenerateSignedLicense( *license.add_key() = *iter; } } + std::string provider_client_token = + GetProviderClientToken(*session_init, license_request_->client_id()); + if (session_state) { + if (!provider_client_token.empty()) { + session_state->set_provider_client_token(provider_client_token); + } else if (license_request_->client_id().has_provider_client_token()) { + session_state->set_provider_client_token( + license_request_->client_id().provider_client_token()); + } + session_state->set_license_counter( + license_request_->client_id().license_counter()); + } if (license_request_->type() == LicenseRequest::NEW) { - std::string provider_client_token = - GetProviderClientToken(*session_init, license_request_->client_id()); if (!provider_client_token.empty()) { license.set_provider_client_token(provider_client_token); } - if (session_state) { - if (license.has_provider_client_token()) { - session_state->set_provider_client_token( - license.provider_client_token()); - } else if (license_request_->client_id().has_provider_client_token()) { - session_state->set_provider_client_token( - license_request_->client_id().provider_client_token()); - } - session_state->set_license_counter( - license_request_->client_id().license_counter()); - } // Put the protection scheme contained in the PSSH into the license. ContentInfo content_info; if (ParseContentId(license_request_->content_id(), &content_info).ok()) { @@ -847,8 +849,8 @@ util::Status SessionImpl::GenerateSignedLicense( std::unique_ptr rsa_public_key; rsa_public_key.reset(RsaPublicKey::Create(client_cert_->public_key())); if (rsa_public_key == nullptr) { - return util::Status(error_space, INVALID_DRM_CERTIFICATE, - "create-device-public-key-failed"); + return Status(error_space, INVALID_DRM_CERTIFICATE, + "create-device-public-key-failed"); } } } @@ -868,8 +870,8 @@ util::Status SessionImpl::GenerateSignedLicense( license.id().has_provider_session_token(), session_init, license.id().type(), system_id, kcb.mutable_key_control_block())) { - status = util::Status(error_space, KEYCONTROL_GENERATION_ERROR, - "Could not generate key control block."); + status = Status(error_space, KEYCONTROL_GENERATION_ERROR, + "Could not generate key control block."); return status; } if (license.key(i).has_key() && @@ -879,14 +881,18 @@ util::Status SessionImpl::GenerateSignedLicense( // encrypted. kcb.set_iv(Random16Bytes()); kcb.set_key_control_block( - crypto_util::EncryptAesCbc(license.key(i).key().substr(0, 16), - kcb.iv(), kcb.key_control_block())); + license_request_->protocol_version() < VERSION_2_2 + ? crypto_util::EncryptAesCbc(license.key(i).key().substr(0, 16), + kcb.iv(), kcb.key_control_block()) + : crypto_util::EncryptAesCbcNoPad( + license.key(i).key().substr(0, 16), kcb.iv(), + kcb.key_control_block())); } } if (license.key(i).has_key()) { if (license.key(i).type() == License::KeyContainer::CONTENT) { if (license.key(i).key().size() != kContentKeySize) { - return util::Status( + return Status( error_space, INVALID_KEY_SIZE, absl::StrCat( "content key size in license is wrong. Key size should be ", @@ -894,29 +900,29 @@ util::Status SessionImpl::GenerateSignedLicense( } } else if (license.key(i).type() == License::KeyContainer::ENTITLEMENT) { if (license.key(i).key().size() != kEntitlementKeySize) { - return util::Status(error_space, INVALID_KEY_SIZE, - "invalid-entitlement-key-size"); + return Status(error_space, INVALID_KEY_SIZE, + "invalid-entitlement-key-size"); } } license.mutable_key(i)->set_iv(Random16Bytes()); - license.mutable_key(i)->set_key(crypto_util::EncryptAesCbc( - encryption_key, license.key(i).iv(), license.key(i).key())); + license.mutable_key(i)->set_key( + license_request_->protocol_version() < VERSION_2_2 + ? crypto_util::EncryptAesCbc(wrapping_key, license.key(i).iv(), + license.key(i).key()) + : crypto_util::EncryptAesCbcNoPad( + wrapping_key, license.key(i).iv(), license.key(i).key())); if (license.key(i).key().empty()) { - return util::Status(error_space, ENCRYPT_ERROR, "key-encrypt-failed"); + return Status(error_space, ENCRYPT_ERROR, "key-encrypt-failed"); } } } - switch (platform_verification_status_) { - case PLATFORM_NO_VERIFICATION: - break; - case PLATFORM_HARDWARE_VERIFIED: - // TODO(b/65054419): Deprecate remote_attestation_verified altogether. - license.set_remote_attestation_verified(true); - ABSL_FALLTHROUGH_INTENDED; - default: - license.set_platform_verification_status(platform_verification_status_); - break; + if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) { + license.set_platform_verification_status(platform_verification_status_); + } + // TODO(b/65054419): Deprecate remote_attestation_verified altogether. + if (remote_attestation_verified_) { + license.set_remote_attestation_verified(true); } @@ -955,7 +961,7 @@ util::Status SessionImpl::GenerateSignedLicense( return status; } -bool SessionImpl::GenerateErrorResponse(const util::Status& status, +bool SessionImpl::GenerateErrorResponse(const Status& status, std::string* signed_message_bytes) { return widevine::GenerateErrorResponse(status, signed_message_bytes); } @@ -1027,9 +1033,9 @@ bool SessionImpl::ShouldSetProviderSessionToken( return false; } -util::Status SessionImpl::VerifyPlatform() { +Status SessionImpl::VerifyPlatform() { if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) { - return util::OkStatus(); + return OkStatus(); } // Verify the platform only if it has not been verified at the proxy. This // verification can be performed by content providers who host their own @@ -1039,7 +1045,7 @@ util::Status SessionImpl::VerifyPlatform() { ProvisionedDeviceInfo::LEVEL_1) { platform_verification_status_ = PLATFORM_HARDWARE_VERIFIED; } else { - util::Status status = VerifyRemoteAttestation(); + Status status = VerifyRemoteAttestation(); if (!status.ok()) { VLOG(1) << "Remote Attestation Failure: " << status << ", license request: " << license_request_->ShortDebugString(); @@ -1048,9 +1054,8 @@ util::Status SessionImpl::VerifyPlatform() { } if (platform_verification_status_ == PLATFORM_UNVERIFIED && license_request_ && !license_request_->client_id().vmp_data().empty()) { - util::Status status = - VerifyVmpData(license_request_->client_id().vmp_data(), - &platform_verification_status_); + Status status = VerifyVmpData(license_request_->client_id().vmp_data(), + &platform_verification_status_); if (!status.ok()) { VLOG(1) << "Platform Verification Failure: " << status << ", license request: " << license_request_->ShortDebugString(); @@ -1058,7 +1063,7 @@ util::Status SessionImpl::VerifyPlatform() { } } - return util::OkStatus(); + return OkStatus(); } std::string SessionImpl::GetDrmDeviceId() const { @@ -1071,10 +1076,10 @@ std::string SessionImpl::GetDrmDeviceId() const { return std::string(); } -util::Status SessionImpl::VerifyDeviceCapabilities( +Status SessionImpl::VerifyDeviceCapabilities( const ClientIdentification::ClientCapabilities& device_capabilities, const License::KeyContainer::OutputProtection& output_protection) const { - util::Status status(util::OkStatus()); + Status status(OkStatus()); if (output_protection.has_hdcp() && device_capabilities.has_max_hdcp_version()) { // TODO(user): Implement the HDCP use case. @@ -1087,26 +1092,26 @@ util::Status SessionImpl::VerifyDeviceCapabilities( device_capabilities.analog_output_capabilities() != ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE) && !device_capabilities.can_disable_analog_output()) { - return util::Status(util::error::PERMISSION_DENIED, - "Analog output must be disabled."); + return Status(error::PERMISSION_DENIED, + "Analog output must be disabled."); } } if (output_protection.cgms_flags() != License::KeyContainer::OutputProtection::CGMS_NONE) { if (device_capabilities.analog_output_capabilities() == ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED) { - return util::Status(util::error::PERMISSION_DENIED, - "Analog output must support CGMS-A."); + return Status(error::PERMISSION_DENIED, + "Analog output must support CGMS-A."); } } return status; } -util::Status SessionImpl::CheckProviderSessionToken(const std::string& pst_src) { +Status SessionImpl::CheckProviderSessionToken(const std::string& pst_src) { if (pst_src.size() > kProviderSessionTokenSizeBytes) { - return util::Status(error_space, INVALID_PROVIDER_SESSION_TOKEN_SIZE, ""); + return Status(error_space, INVALID_PROVIDER_SESSION_TOKEN_SIZE, ""); } - return util::OkStatus(); + return OkStatus(); } @@ -1114,19 +1119,18 @@ PlatformVerificationStatus SessionImpl::GetPlatformVerificationStatus() const { return platform_verification_status_; } -util::Status SessionImpl::VerifyRemoteAttestation() { +Status SessionImpl::VerifyRemoteAttestation() { platform_verification_status_ = PLATFORM_UNVERIFIED; if (signed_message_ != nullptr && signed_message_->has_remote_attestation()) { if (!signed_message_->has_msg()) { - return util::Status(error_space, INVALID_MESSAGE, - "SignedMessage-msg-missing"); + return Status(error_space, INVALID_MESSAGE, "SignedMessage-msg-missing"); } - util::Status status = - RemoteAttestationVerifier::get().VerifyRemoteAttestation( - signed_message_->msg(), signed_message_->remote_attestation(), - &remote_attestation_cert_serial_number_); + Status status = RemoteAttestationVerifier::get().VerifyRemoteAttestation( + signed_message_->msg(), signed_message_->remote_attestation(), + &remote_attestation_cert_serial_number_); if (status.ok()) { platform_verification_status_ = PLATFORM_HARDWARE_VERIFIED; + remote_attestation_verified_ = true; } else if ((status.error_space() == error_space) && (status.error_code() == REMOTE_ATTESTATION_FAILED)) { platform_verification_status_ = PLATFORM_TAMPERED; @@ -1135,7 +1139,7 @@ util::Status SessionImpl::VerifyRemoteAttestation() { } } - return util::OkStatus(); + return OkStatus(); } // TODO(user): add check to get client_id from EncryptedClientIdentification. @@ -1158,4 +1162,11 @@ std::string SessionImpl::GetDrmDeviceServiceId() const { return std::string(); } +Status SessionImpl::GenerateDeviceStatusListRequest( + std::string* signed_device_certificate_status_list_request) { + std::string version = GetSdkVersionString(); + return DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( + version, signed_device_certificate_status_list_request); +} + } // namespace widevine diff --git a/license_server_sdk/internal/session_impl.h b/license_server_sdk/internal/session_impl.h index 55fc2c5..c14eb2e 100644 --- a/license_server_sdk/internal/session_impl.h +++ b/license_server_sdk/internal/session_impl.h @@ -16,8 +16,8 @@ #include #include "base/macros.h" -#include "util/status.h" #include "absl/synchronization/mutex.h" +#include "common/status.h" #include "protos/public/client_identification.pb.h" #include "protos/public/license_protocol.pb.h" #include "protos/public/license_server_sdk.pb.h" @@ -65,8 +65,8 @@ std::string GetProviderClientToken(const SessionInit& session_init, // std::string signed_license_request; // // assign signed_license_request to incoming license request. // Session* session = NULL; -// util::Status status = Session::Create(root_cert, signed_license_request, -// &session); +// Status status = Session::Create(root_cert, signed_license_request, +// &session); // if (!status.ok()) { // std::string error_license; // if (Session::GenerateErrorResponse(status, &error_license)) { @@ -112,10 +112,10 @@ class SessionImpl { // certificate_status_list expires after its creation time // (creation_time_seconds). If |allow_unknown_devices| is false, an error is // returned if the device does not appear in the certificate_status_list. - static util::Status SetCertificateStatusList( - const DrmRootCertificate* root_cert, - const std::string& certificate_status_list, uint32_t expiration_period_seconds, - bool allow_unknown_devices); + static Status SetCertificateStatusList(const DrmRootCertificate* root_cert, + const std::string& certificate_status_list, + uint32_t expiration_period_seconds, + bool allow_unknown_devices); // Add a service certificate system-wide. |root_cert| is the root certificate // which signed the service certificate; @@ -124,7 +124,7 @@ class SessionImpl { // |service_private_key| is the encrypted PKCS#8 private RSA key corresponding // to the service certificate; and |service_private_key_passphrase| is the // password required to decrypt |service_private_key|. - static util::Status AddDrmServiceCertificate( + static Status AddDrmServiceCertificate( const DrmRootCertificate* root_cert, const std::string& service_certificate, const std::string& service_private_key, const std::string& service_private_key_passphrase); @@ -143,13 +143,13 @@ class SessionImpl { // |signed_license_request| is the serialized SignedMessage received from the // client. |session| points to a Session*, which must be initialized to NULL // on entry, but |session| itself may not be NULL. The new Session object will - // be owned by the caller. This method returns util::Status::OK if successful, + // be owned by the caller. This method returns Status::OK if successful, // or an appropriate error status, in which case // Session::GenerateErrorResponse should be invoked. // Example usage: // Session* session = NULL; - // util::Status status = Session::Create(root_cert, request_from_client, - // &session); + // Status status = Session::Create(root_cert, request_from_client, + // &session); // if (!status.ok()) { // std::string error_license; // if (Session::GenerateErrorResponse(status, &error_license)) { @@ -160,16 +160,16 @@ class SessionImpl { // return ... // } // // Create license, invoke GenerateSignedLicense, etc. - static util::Status Create(const DrmRootCertificate* root_cert, - const std::string& signed_license_request, - SessionImpl** session); + static Status Create(const DrmRootCertificate* root_cert, + const std::string& signed_license_request, + SessionImpl** session); // Variation of Session::Create which also fills in the parsed LicenseRequest, // for use in logging or debugging. - static util::Status Create(const DrmRootCertificate* root_cert, - const std::string& signed_license_request, - SessionImpl** session, - LicenseRequest* parsed_request_out); + static Status Create(const DrmRootCertificate* root_cert, + const std::string& signed_license_request, + SessionImpl** session, + LicenseRequest* parsed_request_out); // Same as Create(), but caller can specify the ClientIdentification // message and/or PlatformVerificationStatus. If ClientIdentification is @@ -184,7 +184,7 @@ class SessionImpl { // platform verification. The provider will specify the // clear client identification in |client_id| and the platform verification // in |platform_verification_status|. - static util::Status CreateForProxy( + static Status CreateForProxy( const DrmRootCertificate* root_cert, const std::string& signed_license_request, const PlatformVerificationStatus platform_verification_status, const ClientIdentification* client_id, SessionImpl** session, @@ -192,12 +192,12 @@ class SessionImpl { // Generates a SignedMessage containing a message generated in response to // an error condition. |status| is a previous error status returned by the - // Session or util::Status(util::error::UNAVAILABLE, ...) to indicate that the + // Session or Status(error::UNAVAILABLE, ...) to indicate that the // backend is unavailable, |signed_message| points to a std::string to contain the // serialized SignedMessage, and may not be NULL. This method returns true if // there is an error license to be sent to the client, or false otherwise. // Example usage in the Session::Create comments above. - static bool GenerateErrorResponse(const util::Status& status, + static bool GenerateErrorResponse(const Status& status, std::string* signed_message_bytes); // DeriveKey uses the NIST 800-108 KDF recommendation, using AES-CMAC PRF. @@ -217,8 +217,8 @@ class SessionImpl { return is_service_certificate_loaded_; } - static const char* kEncryptionKeyLabel; // NOLINT - static const uint32_t kEncryptionKeySizeBits; + static const char* kWrappingKeyLabel; // NOLINT + static const uint32_t kWrappingKeySizeBits; static const char* kSigningKeyLabel; // NOLINT static const uint32_t kSigningKeySizeBits; @@ -239,13 +239,13 @@ class SessionImpl { // places in the liciense request protcol buffer. Use this method instead // of accessing directly. |request_id| is a pointer to a std::string to contain // the request ID upon successful return. - virtual util::Status GetRequestId(std::string* request_id) const; + virtual Status GetRequestId(std::string* request_id) const; // Accessor for license_type field which may be encoded in one of multiple // places in the license request protcol buffer. Use this method instead // of accessing directly. |license_type| is a pointer to a value to contain // the license type upon successful return. - virtual util::Status GetLicenseType(LicenseType* license_type) const; + virtual Status GetLicenseType(LicenseType* license_type) const; // Method used to get ContentIdentification in a consistent message regardless // of the type or version of initialization data contained in the content_id @@ -253,7 +253,7 @@ class SessionImpl { // fields of ContentIdentification directly. |content_info| is a pointer to a // message to contain the parsed values from content_id upon successful // return. - virtual util::Status GetContentInfo(ContentInfo* content_info) const; + virtual Status GetContentInfo(ContentInfo* content_info) const; // Returns the serial number of certificate associated with this device and // content provider. @@ -271,7 +271,7 @@ class SessionImpl { // are necessary to fulfill the request (such as the case with license // renewal), |policy| and/or |key_container| may be NULL. // The response is expected to be sent to the Widevine CDM. - virtual util::Status GenerateSignedLicense( + virtual Status GenerateSignedLicense( /*IN*/ const License::Policy* policy, /*IN*/ const std::list* key_container, /*IN*/ const SessionInit* session_init, @@ -280,7 +280,7 @@ class SessionImpl { // Verify the required |output_protection| can be satisified based on the // |device_capabilities| specified by the client. - virtual util::Status VerifyDeviceCapabilities( + virtual Status VerifyDeviceCapabilities( const ClientIdentification::ClientCapabilities& device_capabilities, const License::KeyContainer::OutputProtection& output_protection) const; @@ -294,10 +294,17 @@ class SessionImpl { // false. virtual bool HasKeyControlNonce() const { return has_key_control_nonce_; } + // Generate a signed request to be sent to Widevine Certificate Provisioning + // Server to retrieve 'DeviceCertificateStatusList'. + virtual Status GenerateDeviceStatusListRequest( + std::string* signed_device_certificate_status_list_request); + protected: friend class Session; + PlatformVerificationStatus platform_verification_status_ = PLATFORM_NO_VERIFICATION; + bool remote_attestation_verified_ = false; // For testing only. This allows unit tests to define a mock Session class. SessionImpl(); @@ -310,12 +317,12 @@ class SessionImpl { uint32_t nonce, widevine::ProvisionedDeviceInfo* device_info); // Called by the SessionImpl::Create factory to initialize a new session. - util::Status Init(const DrmRootCertificate* root_cert); - util::Status GenerateNewLicenseInfo(/*IN*/ const SessionInit* session_init, - /*OUT*/ LicenseIdentification* new_id, - /*OUT*/ std::string* renewal_signing_key, - /*OUT*/ std::string* signing_key); - util::Status GeneratePriorLicenseInfo( + Status Init(const DrmRootCertificate* root_cert); + Status GenerateNewLicenseInfo(/*IN*/ const SessionInit* session_init, + /*OUT*/ LicenseIdentification* new_id, + /*OUT*/ std::string* renewal_signing_key, + /*OUT*/ std::string* signing_key); + Status GeneratePriorLicenseInfo( /*IN*/ const SessionInit* session_init, /*INOUT*/ SessionState* session_state, /*OUT*/ LicenseIdentification* new_id, @@ -324,7 +331,7 @@ class SessionImpl { // Verifies remote attestation in the license request and sets // |platform_verification_status_|. - virtual util::Status VerifyRemoteAttestation(); + virtual Status VerifyRemoteAttestation(); // Return true if the provider session token should get included in the // license response. static bool ShouldSetProviderSessionToken( @@ -334,25 +341,25 @@ class SessionImpl { // Verifies the platform by platform-specific means such as Remote Attestion // or host code verification. Only meaningful for Widevine Level 2-3, as // Level 1 devices are verified by default. - virtual util::Status VerifyPlatform(); + virtual Status VerifyPlatform(); // Extracts the nonce from |request| and populates |key_control_nonce|. Sets // |key_control_nonce| to true if the nonce is found. - static util::Status LoadKeyControlNonce(const LicenseRequest& request, - bool* has_key_control_nonce, - uint32_t* key_control_nonce); + static Status LoadKeyControlNonce(const LicenseRequest& request, + bool* has_key_control_nonce, + uint32_t* key_control_nonce); // Validates required fields are set in the license |request|. - static util::Status CheckLicenseRequestFields(const LicenseRequest& request); + static Status CheckLicenseRequestFields(const LicenseRequest& request); // De-serialize the license request from the |signed_license_request| // into |license_request| and |signed_message|. - static util::Status ParseLicenseRequestFromString( + static Status ParseLicenseRequestFromString( const std::string& signed_license_request, SignedMessage* signed_message, LicenseRequest* license_request); // Validates the Provider Session Token from |pst_src|. - static util::Status CheckProviderSessionToken(const std::string& pst_src); + static Status CheckProviderSessionToken(const std::string& pst_src); std::unique_ptr signed_message_; std::unique_ptr license_request_; diff --git a/license_server_sdk/internal/session_impl_test.cc b/license_server_sdk/internal/session_impl_test.cc index d561e32..bccc04c 100644 --- a/license_server_sdk/internal/session_impl_test.cc +++ b/license_server_sdk/internal/session_impl_test.cc @@ -22,17 +22,20 @@ #include "strings/serialize.h" #include "testing/gmock.h" #include "testing/gunit.h" +#include "absl/memory/memory.h" #include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "common/aes_cbc_util.h" #include "common/client_cert.h" #include "common/crypto_util.h" +#include "common/device_status_list.h" #include "common/drm_root_certificate.h" #include "common/error_space.h" #include "common/remote_attestation_verifier.h" #include "common/rsa_key.h" #include "common/rsa_test_keys.h" #include "common/rsa_util.h" +#include "common/sha_util.h" #include "common/signing_key_util.h" #include "common/test_drm_certificates.h" #include "common/test_utils.h" @@ -52,7 +55,8 @@ using google::protobuf::TextFormat; using testing::Eq; using testing::Return; - +using widevine::DeviceCertificateStatusListRequest; +using widevine::SignedDeviceCertificateStatusListRequest; // TODO(user): Add test case for generateSignedLicense. namespace widevine { namespace { @@ -80,10 +84,12 @@ const char* kPriorGeneratedSignedMessage = "f78a051a20acc012accd1aac9f11aa84bfd16f01448ad500b8602e269dd2717e0b265531" "83"; const uint32_t kSystemId = 0x112; -const uint32_t kProtocolVersion2_1KeySizeWithPadding = 80; -const uint32_t kProtocolVersion2_0KeySizeWithPadding = 48; -const uint32_t kEncryptionKeySizeBytes = 32; -const uint32_t kEntitlementKeySizeBytes = 48; + +const size_t kContentKeySizeBytes = 16; +const size_t kEntitlementKeySizeBytes = 32; +const size_t kKeyControlBlockSizeBytes = 16; +const size_t kKeyPaddingSizeBytes = 16; +const size_t kKeyControlBlockPaddingSizeBytes = 16; const uint32_t kValidSystemId = 100; const uint32_t kRevokedSystemId = 101; @@ -407,7 +413,7 @@ class MockCDPush {}; class MockSessionImpl : public SessionImpl { public: - MOCK_METHOD0(VerifyRemoteAttestation, util::Status()); + MOCK_METHOD0(VerifyRemoteAttestation, Status()); }; // The REGISTER_MODULE_INITIALIZER macro does not parse the template type @@ -444,7 +450,7 @@ class SessionTest : public ::testing::Test { pst_provided, client_supports_pst, level, oem_crypto_version); } - util::Status VerifyDeviceCapabilities( + Status VerifyDeviceCapabilities( const ClientIdentification::ClientCapabilities& device_capabilities, const License::KeyContainer::OutputProtection& output_protection) const { SessionImpl session; @@ -452,11 +458,11 @@ class SessionTest : public ::testing::Test { output_protection); } - util::Status CheckProviderSessionToken(const std::string& pst_src) { + Status CheckProviderSessionToken(const std::string& pst_src) { return SessionImpl::CheckProviderSessionToken(pst_src); } - util::Status VerifyPlatform() { return session_impl_.VerifyPlatform(); } + Status VerifyPlatform() { return session_impl_.VerifyPlatform(); } void RemoteAttestationSuccess() { RemoteAttestationVerifier::get().EnableTestDrmCertificates(true); @@ -553,7 +559,7 @@ class SessionTest : public ::testing::Test { std::string serialized_status_list; ASSERT_TRUE(status_list.SerializeToString(&serialized_status_list)); uint32_t expiration_period_seconds = 0; - EXPECT_EQ(util::OkStatus(), + EXPECT_EQ(OkStatus(), SessionImpl::SetCertificateStatusList( test_root_.get(), serialized_status_list, expiration_period_seconds, allow_unknown_devices)); @@ -635,6 +641,18 @@ class SessionTest : public ::testing::Test { return signed_drm_certificate.SerializeAsString(); } + void GenerateInitialRequestSignature(ProtocolVersion protocol_version, + const RsaPrivateKey* private_key, + const std::string& message, + std::string* signature) { + CHECK(private_key); + CHECK(signature); + + private_key->GenerateSignature( + protocol_version < VERSION_2_2 ? message : Sha512_Hash(message), + signature); + } + std::string GenerateBasicLicenseRequest( ProtocolVersion protocol_version, bool deprecated_nonce, LicenseType license_type, uint32_t request_time, @@ -689,8 +707,10 @@ class SessionTest : public ::testing::Test { std::string signing_key = SessionImpl::DeriveKey( absl::HexStringToBytes(kKey), SessionImpl::kSigningKeyLabel, - signed_request_message.msg(), - SigningKeyMaterialSize(request.protocol_version())); + request.protocol_version() < VERSION_2_2 + ? signed_request_message.msg() + : Sha512_Hash(signed_request_message.msg()), + SigningKeyMaterialSizeBits(request.protocol_version())); signed_request_message.set_signature(crypto_util::CreateSignatureHmacSha256( GetClientSigningKey(signing_key, request.protocol_version()), signed_request_message.msg())); @@ -701,12 +721,15 @@ class SessionTest : public ::testing::Test { std::string GenerateStreamingRequestDrmCert( ProtocolVersion protocol_version, uint32_t system_id, const std::string& serial_number, LicenseRequest::RequestType request_type, - bool set_key_control_nonce) { + bool set_key_control_nonce, + const ClientIdentification::ClientCapabilities& client_capabilities) { LicenseRequest request; request.mutable_client_id()->set_type( ClientIdentification::DRM_DEVICE_CERTIFICATE); request.mutable_client_id()->set_token( GenerateSignedDrmCertificate(system_id, serial_number, false)); + *request.mutable_client_id()->mutable_client_capabilities() = + client_capabilities; request.mutable_content_id()->mutable_webm_id_deprecated()->set_header( "0123456789ABCDEF"); @@ -733,9 +756,9 @@ class SessionTest : public ::testing::Test { std::unique_ptr rsa_private_key( RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits())); - rsa_private_key->GenerateSignature( - signed_request_message.msg(), - signed_request_message.mutable_signature()); + GenerateInitialRequestSignature(protocol_version, rsa_private_key.get(), + signed_request_message.msg(), + signed_request_message.mutable_signature()); return signed_request_message.SerializeAsString(); } @@ -770,10 +793,9 @@ class SessionTest : public ::testing::Test { std::unique_ptr rsa_private_key( RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits())); - rsa_private_key->GenerateSignature( - signed_request_message.msg(), - signed_request_message.mutable_signature()); - + GenerateInitialRequestSignature(VERSION_2_1, rsa_private_key.get(), + signed_request_message.msg(), + signed_request_message.mutable_signature()); return signed_request_message.SerializeAsString(); } @@ -782,7 +804,7 @@ class SessionTest : public ::testing::Test { const ClientIdentification::ClientCapabilities& client_capabilities, const LicenseRequest::ContentIdentification::InitData::InitDataType init_data_type, - MockCDPush* cdpush) { + MockCDPush* cdpush, License* license) { // Parse LicenseRequest from request_msg for comparison // the one returned from SessionImpl::Create(). SignedMessage signed_request; @@ -790,21 +812,20 @@ class SessionTest : public ::testing::Test { LicenseRequest expected_request_proto; ASSERT_TRUE(expected_request_proto.ParseFromString(signed_request.msg())); - LicenseRequest actual_request_proto; + LicenseRequest request; SessionImpl* session_ptr = nullptr; - util::Status status = SessionImpl::Create( - test_root_.get(), request_msg, &session_ptr, &actual_request_proto); + Status status = SessionImpl::Create(test_root_.get(), request_msg, + &session_ptr, &request); std::unique_ptr session(session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); ASSERT_TRUE(session.get()); - ASSERT_EQ(expected_request_proto.DebugString(), - actual_request_proto.DebugString()); + ASSERT_EQ(expected_request_proto.DebugString(), request.DebugString()); if (session->request().client_id().type() == ClientIdentification::DRM_DEVICE_CERTIFICATE) { EXPECT_EQ(kValidSerialNumber, session->GetDrmDeviceId()); } - if (actual_request_proto.has_key_control_nonce()) { + if (request.has_key_control_nonce()) { EXPECT_TRUE(session->HasKeyControlNonce()); } else { EXPECT_FALSE(session->HasKeyControlNonce()); @@ -884,93 +905,107 @@ class SessionTest : public ::testing::Test { init.set_master_signing_key("0123456789012345"); status = session->GenerateSignedLicense(&policies, &keys, &init, &cache, &signed_license_bytes); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); SignedMessage signed_message; - CHECK(signed_message.ParseFromString(signed_license_bytes)); + ASSERT_TRUE(signed_message.ParseFromString(signed_license_bytes)); ASSERT_EQ(signed_message.signature().size(), 32); // Yep, SHA-256 was used! - License license; - ASSERT_TRUE(license.ParseFromString(signed_message.msg())); + std::unique_ptr local_license; + if (license == nullptr) { + local_license = absl::make_unique(); + license = local_license.get(); + } + ASSERT_TRUE(license->ParseFromString(signed_message.msg())); // Strip out the signing key, since it's random, but also assert we see it // (and there's only one). bool signing_key_seen = false; int num_content_keys_found = 0; int num_entitlement_keys_found = 0; - for (int i = 0; i < license.key_size(); ++i) { - if (license.key(i).type() == License::KeyContainer::CONTENT) { - if (license.key(i).id() == kKeyId1 || license.key(i).id() == kKeyId2 || - license.key(i).id() == kKeyId3) { - num_content_keys_found++; + for (int i = 0; i < license->key_size(); ++i) { + switch (license->key(i).type()) { + case License::KeyContainer::CONTENT: { + if (license->key(i).id() == kKeyId1 || + license->key(i).id() == kKeyId2 || + license->key(i).id() == kKeyId3) { + EXPECT_EQ( + kContentKeySizeBytes + (request.protocol_version() < VERSION_2_2 + ? kKeyPaddingSizeBytes + : 0), + license->key(i).key().size()); + num_content_keys_found++; + } + break; } - ASSERT_EQ(kEncryptionKeySizeBytes, license.key(i).key().size()) - << " for content key: " << license.key(i).id(); - } else if (license.key(i).type() == License::KeyContainer::SIGNING) { - // Check signing key size. Should be 256 bits for version 2.0 and - // 512 bits for version 2.1. - if (session->request().protocol_version() >= VERSION_2_1) { - ASSERT_EQ(std::string(license.key(i).key()).size(), - kProtocolVersion2_1KeySizeWithPadding); - } else { - ASSERT_EQ(std::string(license.key(i).key()).size(), - kProtocolVersion2_0KeySizeWithPadding); + case License::KeyContainer::ENTITLEMENT: { + if (license->key(i).id() == kEntitlementKeyId1 || + license->key(i).id() == kEntitlementKeyId2 || + license->key(i).id() == kEntitlementKeyId3) { + EXPECT_EQ(kEntitlementKeySizeBytes + + (request.protocol_version() < VERSION_2_2 + ? kKeyPaddingSizeBytes + : 0), + license->key(i).key().size()); + num_entitlement_keys_found++; + } + break; } - ASSERT_FALSE(signing_key_seen); - signing_key_seen = true; - license.mutable_key()->DeleteSubrange(i--, 1); - } else if (license.key(i).type() == License::KeyContainer::ENTITLEMENT) { - if (license.key(i).id() == kEntitlementKeyId1 || - license.key(i).id() == kEntitlementKeyId2 || - license.key(i).id() == kEntitlementKeyId3) { - num_entitlement_keys_found++; - ASSERT_EQ(kEntitlementKeySizeBytes, license.key(i).key().size()) - << " for entitlement key: " << license.key(i).id(); + case License::KeyContainer::SIGNING: { + EXPECT_EQ( + (SigningKeyMaterialSizeBits(request.protocol_version()) / 8) + + ((request.protocol_version() < VERSION_2_2) + ? kKeyPaddingSizeBytes + : 0), + license->key(i).key().size()); + ASSERT_FALSE(signing_key_seen); + signing_key_seen = true; + break; } - } else { - license.mutable_key(i)->clear_iv(); - license.mutable_key(i)->clear_key(); + default: + break; } } ASSERT_TRUE(signing_key_seen); ASSERT_EQ(3, num_content_keys_found); ASSERT_EQ(expected_num_entitlement_keys, num_entitlement_keys_found); - ASSERT_TRUE(license.has_license_start_time()); - license.clear_license_start_time(); + ASSERT_TRUE(license->has_license_start_time()); + license->clear_license_start_time(); - ASSERT_TRUE(license.has_id()); - ASSERT_TRUE(license.id().has_session_id()); - license.mutable_id()->clear_session_id(); + ASSERT_TRUE(license->has_id()); + ASSERT_TRUE(license->id().has_session_id()); + license->mutable_id()->clear_session_id(); if (init_data_type == LicenseRequest::ContentIdentification::InitData::WEBM) { - EXPECT_EQ("myCoolRequest, Dude!", license.id().request_id()); - EXPECT_FALSE(license.has_protection_scheme()); + EXPECT_EQ("myCoolRequest, Dude!", license->id().request_id()); + EXPECT_FALSE(license->has_protection_scheme()); } else { - EXPECT_EQ("myCool-CENC-Request, Dude!", license.id().request_id()); - EXPECT_EQ(kProtectionScheme, license.protection_scheme()); + EXPECT_EQ("myCool-CENC-Request, Dude!", license->id().request_id()); + EXPECT_EQ(kProtectionScheme, license->protection_scheme()); } - EXPECT_EQ("Purchases!", license.id().purchase_id()); - EXPECT_EQ(STREAMING, license.id().type()); - EXPECT_EQ(0, license.id().version()); - EXPECT_EQ(true, license.policy().can_play()); - EXPECT_EQ(true, license.policy().can_renew()); - EXPECT_FALSE(license.remote_attestation_verified()); - EXPECT_EQ(PLATFORM_UNVERIFIED, license.platform_verification_status()); + EXPECT_EQ("Purchases!", license->id().purchase_id()); + EXPECT_EQ(STREAMING, license->id().type()); + EXPECT_EQ(0, license->id().version()); + EXPECT_EQ(true, license->policy().can_play()); + EXPECT_EQ(true, license->policy().can_renew()); + EXPECT_FALSE(license->remote_attestation_verified()); + EXPECT_EQ(PLATFORM_UNVERIFIED, license->platform_verification_status()); EXPECT_EQ(client_capabilities.client_token(), - license.has_provider_client_token()); + license->has_provider_client_token()); ASSERT_EQ(client_capabilities.session_token(), - license.id().has_provider_session_token()); + license->id().has_provider_session_token()); if (client_capabilities.session_token()) { - EXPECT_EQ(kProviderSessionToken, license.id().provider_session_token()); + EXPECT_EQ(kProviderSessionToken, license->id().provider_session_token()); } if (session->request().client_id().has_provider_client_token()) { EXPECT_EQ(session->request().client_id().provider_client_token(), cache.provider_client_token()); - } else if (license.has_provider_client_token()) { - EXPECT_EQ(license.provider_client_token(), cache.provider_client_token()); + } else if (license->has_provider_client_token()) { + EXPECT_EQ(license->provider_client_token(), + cache.provider_client_token()); } } @@ -982,7 +1017,8 @@ class SessionTest : public ::testing::Test { init_data_type) { ValidateBasicRequestResponse(request_msg, client_capabilities, init_data_type, - /* cdpush= */ nullptr); + /* cdpush= */ nullptr, + /* license= */ nullptr); } enum SessionUsageTestMode { @@ -995,7 +1031,8 @@ class SessionTest : public ::testing::Test { void LicenseRenewalTest(const std::string& request_msg_bytes, bool use_valid_key_expect_success, bool release_license, - SessionUsageTestMode session_usage_mode) { + SessionUsageTestMode session_usage_mode, + bool is_client_token_supported) { License::Policy policies; policies.set_can_play(true); policies.set_can_renew(true); @@ -1016,9 +1053,9 @@ class SessionTest : public ::testing::Test { SessionImpl* session_ptr = nullptr; SessionImpl::AllowDevelopmentClients(true); SessionImpl::AllowRevokedDevices(kAllowedRevokedSystemIdValue); - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg_bytes, &session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); std::unique_ptr session(session_ptr); ASSERT_TRUE(session.get()); @@ -1038,8 +1075,19 @@ class SessionTest : public ::testing::Test { std::string license_bytes; status = session->GenerateSignedLicense(&policies, &keys, &init, &session_state, &license_bytes); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); ASSERT_FALSE(license_bytes.empty()); + if (is_client_token_supported) { + EXPECT_FALSE(session_state.provider_client_token().empty()); + if (kExistingProviderClientToken != + session_state.provider_client_token()) { + EXPECT_EQ(init.provider_client_token(), + session_state.provider_client_token()); + } else { + EXPECT_EQ(kExistingProviderClientToken, + session_state.provider_client_token()); + } + } if (!use_valid_key_expect_success) { session_state.set_keybox_system_id(kRevokedSystemId); @@ -1048,15 +1096,15 @@ class SessionTest : public ::testing::Test { // Use license from original license request to create a Session instance // for license renewal request. SignedMessage signed_message; - CHECK(signed_message.ParseFromString(license_bytes)); - CHECK_EQ(signed_message.signature().size(), 32); + ASSERT_TRUE(signed_message.ParseFromString(license_bytes)); + EXPECT_EQ(signed_message.signature().size(), 32); License license; - CHECK(license.ParseFromString(signed_message.msg())); + ASSERT_TRUE(license.ParseFromString(signed_message.msg())); license.ParseFromString(signed_message.msg()); SignedMessage request_message; - CHECK(request_message.ParseFromString(request_msg_bytes)); + ASSERT_TRUE(request_message.ParseFromString(request_msg_bytes)); std::string device_key; if (session->request().client_id().type() == @@ -1069,13 +1117,21 @@ class SessionTest : public ::testing::Test { device_key = absl::HexStringToBytes(kKey); } std::string encrypt_key = SessionImpl::DeriveKey( - device_key, SessionImpl::kEncryptionKeyLabel, request_message.msg(), - SessionImpl::kEncryptionKeySizeBits); + device_key, SessionImpl::kWrappingKeyLabel, + session->request().protocol_version() < VERSION_2_2 + ? request_message.msg() + : Sha512_Hash(request_message.msg()), + SessionImpl::kWrappingKeySizeBits); std::string signing_key; for (int i = 0; i < license.key_size(); ++i) { if (license.key(i).type() == License::KeyContainer::SIGNING) { - signing_key = crypto_util::DecryptAesCbc( - encrypt_key, license.key(i).iv(), license.key(i).key()); + if (session->request().protocol_version() < VERSION_2_2) { + signing_key = crypto_util::DecryptAesCbc( + encrypt_key, license.key(i).iv(), license.key(i).key()); + } else { + signing_key = crypto_util::DecryptAesCbcNoPad( + encrypt_key, license.key(i).iv(), license.key(i).key()); + } uint32_t signing_key_size_bytes = SessionImpl::kSigningKeySizeBits / 8; if (signing_key.size() > signing_key_size_bytes) { // Protocol v2.1 signing key. Retain only server portion. @@ -1123,14 +1179,15 @@ class SessionTest : public ::testing::Test { } SignedMessage signed_request_message; - CHECK(renewal.SerializeToString(signed_request_message.mutable_msg())); + ASSERT_TRUE( + renewal.SerializeToString(signed_request_message.mutable_msg())); signed_request_message.set_signature(crypto_util::CreateSignatureHmacSha256( signing_key, signed_request_message.msg())); session_ptr = nullptr; status = SessionImpl::Create(test_root_.get(), signed_request_message.SerializeAsString(), &session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); std::unique_ptr renewal_session(session_ptr); if (use_valid_key_expect_success && release_license) { @@ -1139,10 +1196,32 @@ class SessionTest : public ::testing::Test { status = renewal_session->GenerateSignedLicense( &policies, nullptr, &init, &session_state, &license_bytes); EXPECT_EQ(INVALID_RELEASE_CAN_PLAY_VALUE, status.error_code()); + if (is_client_token_supported) { + EXPECT_FALSE(session_state.provider_client_token().empty()); + if (kExistingProviderClientToken != + session_state.provider_client_token()) { + EXPECT_EQ(init.provider_client_token(), + session_state.provider_client_token()); + } else { + EXPECT_EQ(kExistingProviderClientToken, + session_state.provider_client_token()); + } + } } std::list renewal_keys; status = renewal_session->GenerateSignedLicense( nullptr, &renewal_keys, &init, &session_state, &license_bytes); + if (is_client_token_supported) { + EXPECT_FALSE(session_state.provider_client_token().empty()); + if (kExistingProviderClientToken != + session_state.provider_client_token()) { + EXPECT_EQ(init.provider_client_token(), + session_state.provider_client_token()); + } else { + EXPECT_EQ(kExistingProviderClientToken, + session_state.provider_client_token()); + } + } SessionUsage expected_session_usage; SessionUsage session_usage; switch (session_usage_mode) { @@ -1171,11 +1250,11 @@ class SessionTest : public ::testing::Test { return; } - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); ASSERT_FALSE(license_bytes.empty()); SignedMessage signed_renew_message; - CHECK(signed_renew_message.ParseFromString(license_bytes)); + ASSERT_TRUE(signed_renew_message.ParseFromString(license_bytes)); License renew_license; ASSERT_TRUE(renew_license.ParseFromString(signed_renew_message.msg())); @@ -1208,6 +1287,17 @@ class SessionTest : public ::testing::Test { status = renewal_session->GenerateSignedLicense( nullptr, &keys, &init, &session_state, &license_bytes); EXPECT_EQ(RENEWAL_WITH_CONTENT_KEYS_NOT_ALLOWED, status.error_code()); + if (is_client_token_supported) { + EXPECT_FALSE(session_state.provider_client_token().empty()); + if (kExistingProviderClientToken != + session_state.provider_client_token()) { + EXPECT_EQ(init.provider_client_token(), + session_state.provider_client_token()); + } else { + EXPECT_EQ(kExistingProviderClientToken, + session_state.provider_client_token()); + } + } } void LicenseTestFailed(const std::string& request_msg_bytes, bool release_license, @@ -1231,7 +1321,7 @@ class SessionTest : public ::testing::Test { SessionImpl* session_ptr = nullptr; SessionImpl::AllowDevelopmentClients(true); - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg_bytes, &session_ptr); ASSERT_EQ(DRM_DEVICE_CERTIFICATE_REVOKED, status.error_code()); std::unique_ptr session(session_ptr); @@ -1240,9 +1330,9 @@ class SessionTest : public ::testing::Test { void SigningCheckTest(std::string* signed_license_request) { SessionImpl* session_ptr = nullptr; - util::Status status = SessionImpl::Create( - test_root_.get(), *signed_license_request, &session_ptr); - ASSERT_EQ(util::OkStatus(), status); + Status status = SessionImpl::Create(test_root_.get(), + *signed_license_request, &session_ptr); + ASSERT_EQ(OkStatus(), status); std::unique_ptr session(session_ptr); ASSERT_TRUE(session.get()); ASSERT_EQ(LicenseRequest::NEW, session->request().type()); @@ -1256,7 +1346,7 @@ class SessionTest : public ::testing::Test { session_ptr = nullptr; status = SessionImpl::Create(test_root_.get(), *signed_license_request, &session_ptr); - ASSERT_NE(util::OkStatus(), status); + ASSERT_NE(OkStatus(), status); ASSERT_FALSE(session_ptr); std::swap((*signed_license_request)[i], tmp); // Test that perturbing any single bit in the request invalidates it. @@ -1273,7 +1363,7 @@ class SessionTest : public ::testing::Test { // type. delete session_ptr; } else { - ASSERT_NE(util::OkStatus(), status); + ASSERT_NE(OkStatus(), status); ASSERT_FALSE(session_ptr); } (*signed_license_request)[i] ^= 1 << bit; @@ -1283,16 +1373,16 @@ class SessionTest : public ::testing::Test { status = SessionImpl::Create(test_root_.get(), *signed_license_request, &session_ptr); session.reset(session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); ASSERT_TRUE(session.get()); } void TestKeyControlBlocks(const std::string& request_msg) { SessionImpl* session_ptr = nullptr; - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); std::unique_ptr session(session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); ASSERT_TRUE(session.get()); License::KeyContainer key; key.set_id("content"); @@ -1323,10 +1413,10 @@ class SessionTest : public ::testing::Test { std::string signed_license_bytes; status = session->GenerateSignedLicense(&policies, &keys, &init, &cache, &signed_license_bytes); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); SignedMessage signed_message; - CHECK(signed_message.ParseFromString(signed_license_bytes)); + ASSERT_TRUE(signed_message.ParseFromString(signed_license_bytes)); License license; ASSERT_TRUE(license.ParseFromString(signed_message.msg())); ASSERT_EQ(2, license.key_size()); @@ -1340,8 +1430,19 @@ class SessionTest : public ::testing::Test { const License::KeyContainer::KeyControl& kc = key.key_control(); ASSERT_TRUE(kc.has_key_control_block()); ASSERT_TRUE(kc.has_iv()); - std::string kcb(crypto_util::DecryptAesCbc(key_list[idx], kc.iv(), - kc.key_control_block())); + EXPECT_EQ(kKeyControlBlockSizeBytes + + (session->request().protocol_version() < VERSION_2_2 + ? kKeyControlBlockPaddingSizeBytes + : 0), + kc.key_control_block().size()); + std::string kcb; + if (session->request().protocol_version() < VERSION_2_2) { + kcb = crypto_util::DecryptAesCbc(key_list[idx], kc.iv(), + kc.key_control_block()); + } else { + kcb = crypto_util::DecryptAesCbcNoPad(key_list[idx], kc.iv(), + kc.key_control_block()); + } ASSERT_EQ(16, kcb.size()); EXPECT_EQ('k', kcb[0]); EXPECT_EQ('c', kcb[1]); @@ -1377,10 +1478,10 @@ class SessionTest : public ::testing::Test { void TestOfflineLicense(const std::string& request_msg) { SessionImpl* session_ptr = nullptr; - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); std::unique_ptr session(session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); ASSERT_TRUE(session.get()); License::KeyContainer key; key.set_id("content"); @@ -1441,16 +1542,16 @@ class SessionTest : public ::testing::Test { ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( test_keys_.private_test_key_2_2048_bits(), passphrase, &encrypted_private_key)); - ASSERT_EQ(util::OkStatus(), SessionImpl::AddDrmServiceCertificate( - test_root_.get(), signed_cert, - encrypted_private_key, passphrase)); + ASSERT_EQ(OkStatus(), SessionImpl::AddDrmServiceCertificate( + test_root_.get(), signed_cert, + encrypted_private_key, passphrase)); } void EncryptClientIdentification( const ClientIdentification& client_id, const std::string& serial_number, const std::string& provider_id, EncryptedClientIdentification* encrypted_client_id) { - CHECK(encrypted_client_id); + ASSERT_TRUE(encrypted_client_id); std::string privacy_key("aabbccddeeffgghh"); std::string iv("0011223344556677"); @@ -1480,9 +1581,9 @@ class SessionTest : public ::testing::Test { kRaServiceId, ra->mutable_certificate()); std::string salt("Ye are the salt of the earth"); std::string message_signed = signed_message->msg() + salt; - ASSERT_EQ(util::OkStatus(), GenerateRsaSignatureSha256Pkcs1( - ra_cert_private_key, message_signed, - ra->mutable_signature())); + ASSERT_EQ(OkStatus(), GenerateRsaSignatureSha256Pkcs1( + ra_cert_private_key, message_signed, + ra->mutable_signature())); ra->set_salt(salt); } @@ -1556,12 +1657,12 @@ TEST_F(SessionTest, BasicRequestResponse_ClientDoesNotSupportSessionToken) { } TEST_F(SessionTest, BasicRequestDrmCertificateResponseProtocolVersion_2_0) { - std::string request_msg(GenerateStreamingRequestDrmCert( - VERSION_2_0, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, - true)); ClientIdentification::ClientCapabilities client_capabilities; client_capabilities.set_client_token(false); client_capabilities.set_session_token(false); + std::string request_msg(GenerateStreamingRequestDrmCert( + VERSION_2_0, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, + true, client_capabilities)); SetCertificateStatusList(kAllowUnknownDevices); ValidateBasicRequestResponse( request_msg, client_capabilities, @@ -1585,13 +1686,27 @@ TEST_F(SessionTest, BasicRequestResponseProtocolVersion2_1) { } TEST_F(SessionTest, BasicRequestDrmCertificateResponseProtocolVersion_2_1) { - std::string request_msg(GenerateStreamingRequestDrmCert( - VERSION_2_1, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, - true)); ClientIdentification::ClientCapabilities client_capabilities; client_capabilities.set_client_token(false); client_capabilities.set_session_token(false); client_capabilities.set_anti_rollback_usage_table(false); + std::string request_msg(GenerateStreamingRequestDrmCert( + VERSION_2_1, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, + true, client_capabilities)); + SetCertificateStatusList(kAllowUnknownDevices); + ValidateBasicRequestResponse( + request_msg, client_capabilities, + LicenseRequest::ContentIdentification::InitData::WEBM); +} + +TEST_F(SessionTest, BasicRequestDrmCertificateResponseProtocolVersion_2_2) { + ClientIdentification::ClientCapabilities client_capabilities; + client_capabilities.set_client_token(false); + client_capabilities.set_session_token(false); + client_capabilities.set_anti_rollback_usage_table(false); + std::string request_msg(GenerateStreamingRequestDrmCert( + VERSION_2_2, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, + true, client_capabilities)); SetCertificateStatusList(kAllowUnknownDevices); ValidateBasicRequestResponse( request_msg, client_capabilities, @@ -1615,8 +1730,8 @@ TEST_F(SessionTest, BasicRequestDrmCertificateResponseEmptyToken) { request.set_request_time(time(nullptr)); SignedMessage signed_request_message; - CHECK(request.SerializeToString(signed_request_message.mutable_msg())); - util::Status status = SessionImpl::Create( + ASSERT_TRUE(request.SerializeToString(signed_request_message.mutable_msg())); + Status status = SessionImpl::Create( test_root_.get(), signed_request_message.SerializeAsString(), &session_ptr); ASSERT_EQ(SERVICE_CERTIFICATE_NOT_FOUND, status.error_code()); @@ -1644,7 +1759,7 @@ TEST_F(SessionTest, BasicRequestCheckRequestTime) { VERSION_2_0, kNoDeprecatedNonce, STREAMING, kShortRequestTime, client_capabilities, client_token_in_request, LicenseRequest::ContentIdentification::InitData::WEBM)); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), SessionImpl::Create(test_root_.get(), signed_request_message, &session_ptr)); std::unique_ptr session(session_ptr); @@ -1667,7 +1782,7 @@ TEST_F(SessionTest, BasicRequestCheckRequestTime) { SessionState cache; std::string signed_license_bytes; - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), session->GenerateSignedLicense(&policies, &keys, &init, &cache, &signed_license_bytes)); SignedMessage signed_message; @@ -1675,7 +1790,7 @@ TEST_F(SessionTest, BasicRequestCheckRequestTime) { License license; license.ParseFromString(signed_message.msg()); ASSERT_TRUE(license.has_license_start_time()); - CHECK_EQ(kShortRequestTime, license.license_start_time()); + EXPECT_EQ(kShortRequestTime, license.license_start_time()); } TEST_F(SessionTest, BasicRequestCheckTokens) { @@ -1690,7 +1805,7 @@ TEST_F(SessionTest, BasicRequestCheckTokens) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kShortRequestTime, client_capabilities, client_token_in_request, LicenseRequest::ContentIdentification::InitData::WEBM)); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), SessionImpl::Create(test_root_.get(), signed_request_message, &session_ptr)); std::unique_ptr session(session_ptr); @@ -1716,7 +1831,7 @@ TEST_F(SessionTest, BasicRequestCheckTokens) { SessionState cache; std::string signed_license_bytes; - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), session->GenerateSignedLicense(&policies, &keys, &init, &cache, &signed_license_bytes)); SignedMessage signed_message; @@ -1819,10 +1934,22 @@ TEST_F(SessionTest, SignatureCheckProtocolVersion2_1) { SigningCheckTest(&signed_message_string); } +TEST_F(SessionTest, SignatureCheckProtocolVersion2_2) { + ClientIdentification::ClientCapabilities client_capabilities; + client_capabilities.set_client_token(true); + client_capabilities.set_session_token(true); + client_capabilities.set_anti_rollback_usage_table(false); + std::string signed_message_string = GenerateBasicLicenseRequest( + VERSION_2_2, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, + client_capabilities, kIncludeProviderToken, + LicenseRequest::ContentIdentification::InitData::WEBM); + SigningCheckTest(&signed_message_string); +} + TEST_F(SessionTest, ResultStatus) { std::string empty_request; SessionImpl* session_ptr = nullptr; - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), empty_request, &session_ptr); EXPECT_GT(status.ToString().size(), 0); } @@ -1832,10 +1959,11 @@ TEST_F(SessionTest, NewLicenseFailedWithRevokedSystemId) { client_capabilities.set_client_token(true); client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); - LicenseTestFailed(GenerateStreamingRequestDrmCert( - VERSION_2_1, kAllowedRevokedSystemId, - kAllowedRevokedSerialNumber, LicenseRequest::NEW, true), - kLicenseRelease, kNoSessionUsage); + LicenseTestFailed( + GenerateStreamingRequestDrmCert( + VERSION_2_1, kAllowedRevokedSystemId, kAllowedRevokedSerialNumber, + LicenseRequest::NEW, true, client_capabilities), + kLicenseRelease, kNoSessionUsage); } class SessionTestRenewal : public SessionTest, @@ -1853,9 +1981,9 @@ TEST_P(SessionTestRenewal, RenewalLicenseFailedWithRevokedSystemId) { client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); LicenseTestFailed( - GenerateStreamingRequestDrmCert(VERSION_2_1, kAllowedRevokedSystemId, - kAllowedRevokedSerialNumber, - LicenseRequest::RENEWAL, false), + GenerateStreamingRequestDrmCert( + VERSION_2_1, kAllowedRevokedSystemId, kAllowedRevokedSerialNumber, + LicenseRequest::RENEWAL, false, client_capabilities), kLicenseRelease, kNoSessionUsage); } @@ -1865,9 +1993,9 @@ TEST_P(SessionTestRenewal, ReleaseLicenseFailedWithRevokedSystemId) { client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); LicenseTestFailed( - GenerateStreamingRequestDrmCert(VERSION_2_1, kAllowedRevokedSystemId, - kAllowedRevokedSerialNumber, - LicenseRequest::RELEASE, false), + GenerateStreamingRequestDrmCert( + VERSION_2_1, kAllowedRevokedSystemId, kAllowedRevokedSerialNumber, + LicenseRequest::RELEASE, false, client_capabilities), kLicenseRelease, kNoSessionUsage); } @@ -1881,7 +2009,7 @@ TEST_P(SessionTestRenewal, LicenseRenewal) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalProtocolVersion2_0) { @@ -1894,7 +2022,7 @@ TEST_P(SessionTestRenewal, LicenseRenewalProtocolVersion2_0) { VERSION_2_0, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalProtocolVersion2_1) { @@ -1907,7 +2035,7 @@ TEST_P(SessionTestRenewal, LicenseRenewalProtocolVersion2_1) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalDrmCertProtocolVersion2_0) { @@ -1917,8 +2045,8 @@ TEST_P(SessionTestRenewal, LicenseRenewalDrmCertProtocolVersion2_0) { client_capabilities.set_anti_rollback_usage_table(false); LicenseRenewalTest(GenerateStreamingRequestDrmCert( VERSION_2_0, kValidSystemId, kValidSerialNumber, - LicenseRequest::NEW, true), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + LicenseRequest::NEW, true, client_capabilities), + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalDrmCertProtocolVersion2_1) { @@ -1927,9 +2055,20 @@ TEST_P(SessionTestRenewal, LicenseRenewalDrmCertProtocolVersion2_1) { client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); LicenseRenewalTest(GenerateStreamingRequestDrmCert( - VERSION_2_0, kValidSystemId, kValidSerialNumber, - LicenseRequest::NEW, true), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + VERSION_2_1, kValidSystemId, kValidSerialNumber, + LicenseRequest::NEW, true, client_capabilities), + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); +} + +TEST_P(SessionTestRenewal, LicenseRenewalDrmCertProtocolVersion2_2) { + ClientIdentification::ClientCapabilities client_capabilities; + client_capabilities.set_client_token(true); + client_capabilities.set_session_token(true); + client_capabilities.set_anti_rollback_usage_table(false); + LicenseRenewalTest(GenerateStreamingRequestDrmCert( + VERSION_2_2, kValidSystemId, kValidSerialNumber, + LicenseRequest::NEW, true, client_capabilities), + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalUnknownDevice) { @@ -1939,8 +2078,8 @@ TEST_P(SessionTestRenewal, LicenseRenewalUnknownDevice) { client_capabilities.set_anti_rollback_usage_table(false); LicenseRenewalTest(GenerateStreamingRequestDrmCert( VERSION_2_1, kUnknownSystemId, kUnknownSerialNumber, - LicenseRequest::NEW, true), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + LicenseRequest::NEW, true, client_capabilities), + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalAllowedDevice) { @@ -1949,10 +2088,10 @@ TEST_P(SessionTestRenewal, LicenseRenewalAllowedDevice) { client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); LicenseRenewalTest( - GenerateStreamingRequestDrmCert(VERSION_2_1, kAllowedRevokedSystemId, - kAllowedRevokedSerialNumber, - LicenseRequest::NEW, true), - GetParam(), kNoLicenseRelease, kNoSessionUsage); + GenerateStreamingRequestDrmCert( + VERSION_2_1, kAllowedRevokedSystemId, kAllowedRevokedSerialNumber, + LicenseRequest::NEW, true, client_capabilities), + GetParam(), kNoLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRelease) { @@ -1965,7 +2104,7 @@ TEST_P(SessionTestRenewal, LicenseRelease) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kLicenseRelease, kNoSessionUsage); + GetParam(), kLicenseRelease, kNoSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalInvalidSessionUsage) { @@ -1978,7 +2117,7 @@ TEST_P(SessionTestRenewal, LicenseRenewalInvalidSessionUsage) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kNoLicenseRelease, kInvalidSessionUsage); + GetParam(), kNoLicenseRelease, kInvalidSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalInvalidSessionUsageSignature) { @@ -1991,7 +2130,7 @@ TEST_P(SessionTestRenewal, LicenseRenewalInvalidSessionUsageSignature) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kNoLicenseRelease, kInvalidSessionUsageSignature); + GetParam(), kNoLicenseRelease, kInvalidSessionUsageSignature, true); } TEST_P(SessionTestRenewal, LicenseReleaseValidSessionUsage) { @@ -2004,15 +2143,16 @@ TEST_P(SessionTestRenewal, LicenseReleaseValidSessionUsage) { VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, client_capabilities, kIncludeProviderToken, LicenseRequest::ContentIdentification::InitData::WEBM), - GetParam(), kLicenseRelease, kValidSessionUsage); + GetParam(), kLicenseRelease, kValidSessionUsage, true); } TEST_P(SessionTestRenewal, LicenseRenewalWithSerialNumber) { + ClientIdentification::ClientCapabilities client_capabilities; std::string request_msg = GenerateStreamingRequestDrmCert( VERSION_2_0, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, - true); + true, client_capabilities); LicenseRenewalTest(request_msg, GetParam(), kLicenseRelease, - kValidSessionUsage); + kValidSessionUsage, false); } INSTANTIATE_TEST_CASE_P(SystemIdVariations, SessionTestRenewal, @@ -2024,7 +2164,7 @@ TEST_F(SessionTest, InvalidRenewalKeySigningKey_2_0) { client_capabilities.set_client_token(true); client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), SessionImpl::Create( test_root_.get(), GenerateBasicLicenseRequest( @@ -2065,7 +2205,7 @@ TEST_F(SessionTest, InvalidRenewalKeySigningKey_2_1) { client_capabilities.set_client_token(true); client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), SessionImpl::Create( test_root_.get(), GenerateBasicLicenseRequest( @@ -2106,7 +2246,7 @@ TEST_F(SessionTest, ValidRenewalLongSigningKey) { client_capabilities.set_client_token(true); client_capabilities.set_session_token(true); client_capabilities.set_anti_rollback_usage_table(false); - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), SessionImpl::Create( test_root_.get(), GenerateBasicLicenseRequest( @@ -2136,7 +2276,7 @@ TEST_F(SessionTest, ValidRenewalLongSigningKey) { SessionState cache; std::string signed_license_bytes; - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), session->GenerateSignedLicense(&policies, &keys, &init, &cache, &signed_license_bytes)); } @@ -2200,15 +2340,16 @@ TEST_F(SessionTest, OfflineLicenseCreate) { TEST_F(SessionTest, DISABLED_RenewLicenseWithKeyControlBlock) {} TEST_F(SessionTest, DrmCertificateNotSupported) { + ClientIdentification::ClientCapabilities client_capabilities; std::string request_msg(GenerateStreamingRequestDrmCert( VERSION_2_0, kUnknownSystemId, kValidSerialNumber, LicenseRequest::NEW, - true)); + true, client_capabilities)); SessionImpl* session_ptr = nullptr; SetCertificateStatusList(kDontAllowUnknownDevices); // Cannot create a session if the certificate system id // does not exist in the device status list and allow_unknown_device // is false. - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); std::unique_ptr session(session_ptr); ASSERT_EQ(DRM_DEVICE_CERTIFICATE_UNKNOWN, status.error_code()); @@ -2217,37 +2358,40 @@ TEST_F(SessionTest, DrmCertificateNotSupported) { // The system Id is found, but the intermediate status has a different // serial number. Perhaps the intermediate certificate was regenerated. TEST_F(SessionTest, DrmCertificateIntermediateStatusChangedSerialNumber) { + ClientIdentification::ClientCapabilities client_capabilities; std::string request_msg(GenerateStreamingRequestDrmCert( VERSION_2_0, kValidSystemId, kRevokedSerialNumber, LicenseRequest::NEW, - true)); + true, client_capabilities)); SessionImpl* session_ptr = nullptr; SetCertificateStatusList(kAllowUnknownDevices); - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); std::unique_ptr session(session_ptr); ASSERT_EQ(INVALID_DRM_CERTIFICATE, status.error_code()); } TEST_F(SessionTest, DrmCertificateRevoked) { + ClientIdentification::ClientCapabilities client_capabilities; std::string request_msg(GenerateStreamingRequestDrmCert( VERSION_2_0, kRevokedSystemId, kValidSerialNumber, LicenseRequest::NEW, - true)); + true, client_capabilities)); SessionImpl* session_ptr = nullptr; SetCertificateStatusList(kAllowUnknownDevices); - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); std::unique_ptr session(session_ptr); ASSERT_EQ(DRM_DEVICE_CERTIFICATE_REVOKED, status.error_code()); } TEST_F(SessionTest, DrmCertificateReportingSerialNumberWithRenewal) { + ClientIdentification::ClientCapabilities client_capabilities; std::string request_msg(GenerateStreamingRequestDrmCert( VERSION_2_0, kValidSystemId, kValidSerialNumber, LicenseRequest::NEW, - true)); + true, client_capabilities)); SessionImpl* session_ptr = nullptr; - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); - ASSERT_EQ(util::OkStatus(), status); + ASSERT_EQ(OkStatus(), status); std::unique_ptr session(session_ptr); ASSERT_TRUE(session.get()); } @@ -2262,10 +2406,9 @@ TEST_F(SessionTest, SetCertificateStatusListFail) { std::string serialized_status_list; ASSERT_TRUE(status_list.SerializeToString(&serialized_status_list)); const uint32_t expiration_seconds = 0; - EXPECT_EQ(util::OkStatus(), - SessionImpl::SetCertificateStatusList( - test_root_.get(), serialized_status_list, expiration_seconds, - kDontAllowUnknownDevices)); + EXPECT_EQ(OkStatus(), SessionImpl::SetCertificateStatusList( + test_root_.get(), serialized_status_list, + expiration_seconds, kDontAllowUnknownDevices)); // Use different certificate for validation (other than kCertificateTypeTest). EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST, SessionImpl::SetCertificateStatusList( @@ -2299,10 +2442,9 @@ TEST_F(SessionTest, SetCertificateStatusList) { ASSERT_TRUE(status_list.SerializeToString(&serialized_status_list)); const uint32_t expiration_seconds = 0; SetCertificateStatusList(kAllowUnknownDevices); - EXPECT_EQ(util::OkStatus(), - SessionImpl::SetCertificateStatusList( - test_root_.get(), serialized_status_list, expiration_seconds, - kDontAllowUnknownDevices)); + EXPECT_EQ(OkStatus(), SessionImpl::SetCertificateStatusList( + test_root_.get(), serialized_status_list, + expiration_seconds, kDontAllowUnknownDevices)); // Use different certificate for validation (other than kCertificateTypeTest). EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST, SessionImpl::SetCertificateStatusList( @@ -2350,9 +2492,9 @@ TEST_F(SessionTest, SetCertificateStatusList) { "93d2ae8af907b14d692d32086f603420ddd9e3b4498a98726d6d7e5a1b5f2143ff4089e4" "617423d57b2d1f1f9cb6ddfe056bdc74ea9830142cae45f3b6ba7d59ffe28e3e"; std::string signed_list = absl::HexStringToBytes(hex_signed_list); - EXPECT_EQ(util::OkStatus(), SessionImpl::SetCertificateStatusList( - prod_root_.get(), signed_list, - expiration_seconds, kAllowUnknownDevices)); + EXPECT_EQ(OkStatus(), SessionImpl::SetCertificateStatusList( + prod_root_.get(), signed_list, expiration_seconds, + kAllowUnknownDevices)); } void VerifyErrorLicense(const std::string& error_license, @@ -2369,26 +2511,23 @@ void VerifyErrorLicense(const std::string& error_license, TEST_F(SessionTest, ErrorLicense) { std::string error_license; - EXPECT_FALSE( - SessionImpl::GenerateErrorResponse(util::OkStatus(), &error_license)); + EXPECT_FALSE(SessionImpl::GenerateErrorResponse(OkStatus(), &error_license)); EXPECT_FALSE(SessionImpl::GenerateErrorResponse( - util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, ""), - &error_license)); + Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, ""), &error_license)); EXPECT_FALSE(SessionImpl::GenerateErrorResponse( - util::Status(error_space, INVALID_DRM_CERTIFICATE, ""), &error_license)); + Status(error_space, INVALID_DRM_CERTIFICATE, ""), &error_license)); VerifyErrorLicense(error_license, LicenseError::INVALID_DRM_DEVICE_CERTIFICATE); EXPECT_FALSE(SessionImpl::GenerateErrorResponse( - util::Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, ""), - &error_license)); + Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, ""), &error_license)); VerifyErrorLicense(error_license, LicenseError::REVOKED_DRM_DEVICE_CERTIFICATE); EXPECT_FALSE(SessionImpl::GenerateErrorResponse( - util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, ""), + Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST, ""), &error_license)); VerifyErrorLicense(error_license, LicenseError::SERVICE_UNAVAILABLE); EXPECT_FALSE(SessionImpl::GenerateErrorResponse( - util::Status(util::error::UNAVAILABLE, ""), &error_license)); + Status(error::UNAVAILABLE, ""), &error_license)); VerifyErrorLicense(error_license, LicenseError::SERVICE_UNAVAILABLE); } @@ -2442,9 +2581,8 @@ TEST_F(SessionTest, EncryptedClientIdentification) { signed_request_message.msg(), signed_request_message.mutable_signature()); ASSERT_TRUE(signed_request_message.SerializeToString(&request_msg_bytes)); AddDrmServiceCertificate(serial_number, provider_id, 123); - ASSERT_EQ( - util::OkStatus(), - SessionImpl::Create(test_root_.get(), request_msg_bytes, &session_ptr)); + ASSERT_EQ(OkStatus(), SessionImpl::Create(test_root_.get(), request_msg_bytes, + &session_ptr)); std::unique_ptr session(session_ptr); EXPECT_EQ(license_counter, session->request().client_id().license_counter()); @@ -2454,11 +2592,10 @@ TEST_F(SessionTest, EncryptedClientIdentification) { client_id.set_license_counter(updated_license_counter); PlatformVerificationStatus platform_verification_status = PLATFORM_NO_VERIFICATION; - EXPECT_EQ(util::OkStatus(), - SessionImpl::CreateForProxy(test_root_.get(), request_msg_bytes, - platform_verification_status, - &client_id, &session_ptr_with_client_id, - &parsed_request)); + EXPECT_EQ(OkStatus(), SessionImpl::CreateForProxy( + test_root_.get(), request_msg_bytes, + platform_verification_status, &client_id, + &session_ptr_with_client_id, &parsed_request)); std::unique_ptr session_with_client_id( session_ptr_with_client_id); // Verify the license is using the client_id specified when creating a session @@ -2482,7 +2619,7 @@ TEST_F(SessionTest, DrmServiceCertificateRequest) { std::string request_msg_bytes; ASSERT_TRUE(signed_request_message.SerializeToString(&request_msg_bytes)); SessionImpl* session_ptr(nullptr); - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg_bytes, &session_ptr); ASSERT_EQ(SERVICE_CERTIFICATE_REQUEST_MESSAGE, status.error_code()); std::string error_license; @@ -2758,7 +2895,7 @@ TEST_F(SessionTest, DISABLED_VerifyDeviceHdcpCapabilities) { TEST_F(SessionTest, ProviderSessionTokenSize) { std::string pst_src; - for (int i = 0; i < kProviderSessionTokenSizeBytes; i++) { + for (uint32_t i = 0; i < kProviderSessionTokenSizeBytes; i++) { pst_src.append("a"); } EXPECT_OK(CheckProviderSessionToken(pst_src)); @@ -2790,7 +2927,7 @@ TEST_P(SessionVmpTest, VmpVerifiedAndTampered) { } SessionImpl* session_ptr(nullptr); if (kPlatformVerificationStatus != PLATFORM_TAMPERED) { - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), SessionImpl::Create(test_root_.get(), request_msg, &session_ptr)); std::unique_ptr session(session_ptr); if (kPlatformVerificationStatus != PLATFORM_NO_VERIFICATION) { @@ -2810,7 +2947,7 @@ TEST_P(SessionVmpTest, VmpVerifiedAndTampered) { init.set_master_signing_key("0123456789abcdef"); SessionState cache; std::string signed_license_bytes; - ASSERT_EQ(util::OkStatus(), + ASSERT_EQ(OkStatus(), session->GenerateSignedLicense(&policies, &keys, &init, &cache, &signed_license_bytes)); SignedMessage signed_message; @@ -2824,9 +2961,9 @@ TEST_P(SessionVmpTest, VmpVerifiedAndTampered) { } } else { // Platform verification status is tampered. - util::Status status = + Status status = SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); - ASSERT_EQ(util::error::INTERNAL, status.error_code()); + ASSERT_EQ(error::INTERNAL, status.error_code()); } } @@ -2880,7 +3017,7 @@ TEST_F(SessionTest, AnalogOutputNotAllowed_DeviceWithAnalogOutput) { client_capabilities.set_analog_output_capabilities( ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED); client_capabilities.set_can_disable_analog_output(false); - EXPECT_EQ(util::error::PERMISSION_DENIED, + EXPECT_EQ(error::PERMISSION_DENIED, VerifyDeviceCapabilities(client_capabilities, output_protection) .error_code()); // Client has the ability to disable it's analog output. @@ -2896,7 +3033,7 @@ TEST_F(SessionTest, CGMSRequired) { ClientIdentification::ClientCapabilities client_capabilities; client_capabilities.set_analog_output_capabilities( ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED); - EXPECT_EQ(util::error::PERMISSION_DENIED, + EXPECT_EQ(error::PERMISSION_DENIED, VerifyDeviceCapabilities(client_capabilities, output_protection) .error_code()); client_capabilities.set_analog_output_capabilities( @@ -2919,6 +3056,22 @@ TEST_F(SessionTest, BasicRequestResponse_OEMVersion14) { LicenseRequest::ContentIdentification::InitData::WEBM); } +TEST_F(SessionTest, GenerateDeviceStatusListRequest) { + std::string signed_device_certificate_status_list; + Status status = session_impl_.GenerateDeviceStatusListRequest( + &signed_device_certificate_status_list); + EXPECT_TRUE(status.ok()); + SignedDeviceCertificateStatusListRequest signed_request; + signed_request.ParseFromString(signed_device_certificate_status_list); + std::string device_certificate_status_list = + signed_request.device_certificate_status_list_request(); + DeviceCertificateStatusListRequest request; + request.ParseFromString(device_certificate_status_list); + EXPECT_EQ(request.sdk_version(), SessionImpl::GetSdkVersionString()); + EXPECT_EQ(DeviceStatusList::Instance()->GetCurrentTime(), + request.sdk_time_seconds()); +} + INSTANTIATE_TEST_CASE_P(SessionVmpTests, SessionVmpTest, ::testing::Values(PLATFORM_NO_VERIFICATION, diff --git a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.cc b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.cc index 776decc..e838a8b 100644 --- a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.cc +++ b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.cc @@ -13,11 +13,12 @@ #include "common/error_space.h" #include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h" -namespace util = widevine::util; using widevine::error_space; using widevine::kCertificateTypeDevelopment; using widevine::kCertificateTypeTesting; +namespace error = widevine::error; + namespace widevine_server { namespace wv_pl_sdk { @@ -32,6 +33,7 @@ WvPLCASProxyEnvironment::WvPLCASProxyEnvironment( if (it != config_values.end()) { provider_ = (*it).second; } + it = config_values.find(kProviderIv); if (it != config_values.end()) { provider_iv_ = new std::string(absl::HexStringToBytes((*it).second)); } @@ -49,20 +51,17 @@ WvPLStatus WvPLCASProxyEnvironment::Initialize() { WvPLStatus WvPLCASProxyEnvironment::CreateSession( const std::string& cas_license_request, WvPLCASProxySession** cas_proxy_session) { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (cas_proxy_session == nullptr) { - return WvPLStatus(error_space, util::error::INTERNAL, - "proxy_session is NULL"); + return WvPLStatus(error_space, error::INTERNAL, "proxy_session is NULL"); } if (*cas_proxy_session != nullptr) { - return WvPLStatus(error_space, util::error::INTERNAL, + return WvPLStatus(error_space, error::INTERNAL, "*proxy_session is not NULL"); } std::unique_ptr wvpl_cas_proxy_session( new WvPLCASProxySession(drm_root_certificate_.get(), cas_license_request)); - // TODO(user): Complete the license request parsing in WvPLCASProxySession. - // status = wvpl_cas_proxy_session->ParseLicenseRequest(); if (status.ok()) { *cas_proxy_session = wvpl_cas_proxy_session.release(); } diff --git a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h index 45edf1e..982cdc7 100644 --- a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h +++ b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_environment.h @@ -17,6 +17,34 @@ namespace wv_pl_sdk { class WvPLCASProxySession; +/** + * Sets up an environment for partners who are using the Widevine CAS License + * Proxy SDK. This environment *must* be successfully created in order to work + * with the SDK API. + * + * Implements the following public API: + * - CreateSession() + * - SetDeviceCertificateStatusList() + * + * Example Usage: + * map config_values; + * config_values.insert(std::make_pair(kDrmCertificateType, "prod"); + * config_values.insert(std::make_pair(kProvider, "TEST_PROVIDER"); + * config_values.insert(std::make_pair(kProviderIv, "TEST_IV")); + * config_values.insert(std::make_pair(kProviderKey, "TEST_KEY")); + * WvPLCASProxyEnvironment* wv_cas_proxy_environment = + * new WvPLCASProxyEnvironment(config_values); + * // This is the DeviceCertificateStatusList returned from a query to the + * // Widevine Certificate Provisioning Service (List API). + * std::string certificate_status_list = "TEST_CERTIFICATE_STATUS_LIST"; + * wvpl_status = wvpl_cas_proxy_environment->SetDeviceCertificateStatusList( + * certificate_status_list); + * WvPLCASProxySession** wvpl_cas_proxy_session = nullptr; + * std::string license_request_from_cdm = "TEST_LICENSE_REQUEST"; + * wvpl_status = wvpl_cas_proxy_environment->CreateSession( + * license_request_from_cdm, &wvpl_cas_proxy_session); + */ + class WvPLCASProxyEnvironment : public WvPLSDKEnvironment { public: /** diff --git a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.cc b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.cc index d0c6613..a447270 100644 --- a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.cc +++ b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.cc @@ -9,8 +9,6 @@ #include "media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h" #include -namespace util = widevine::util; - namespace widevine_server { namespace wv_pl_sdk { @@ -30,12 +28,5 @@ WvPLCASProxySession::WvPLCASProxySession( const std::string& cas_license_request_from_cdm) : WvPLSDKSession(drm_root_certificate) {} -WvPLStatus WvPLCASProxySession::ParsePsshData( - WvPLWidevinePsshData* wvpl_widevine_pssh_data) const { - // TODO(user): Implement this functionality in WvPLSdk and remove the - // implementation in the classes derived from WvPLSdk. - return util::OkStatus(); -} - } // namespace wv_pl_sdk } // namespace widevine_server diff --git a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h index 0991b6f..6043777 100644 --- a/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h +++ b/media_cas_proxy_sdk/external/common/wvpl/wvpl_cas_proxy_session.h @@ -76,9 +76,6 @@ class WvPLCASProxySession : public WvPLSDKSession { WvPLCASProxySession( const widevine::DrmRootCertificate* drm_root_certificate, const std::string& cas_license_request_from_cdm); - - WvPLStatus ParsePsshData( - WvPLWidevinePsshData* wvpl_widevine_pssh_data) const override; }; } // namespace wv_pl_sdk diff --git a/protos/public/drm_certificate.proto b/protos/public/drm_certificate.proto index a9122a0..e03a74b 100644 --- a/protos/public/drm_certificate.proto +++ b/protos/public/drm_certificate.proto @@ -27,7 +27,9 @@ message DrmCertificate { SERVICE = 3; PROVISIONER = 4; } - + enum ServiceType { + UNKNOWN = 0; LICENSE_SERVER_SDK = 1; LICENSE_SERVER_PROXY_SDK = 2; + } // Type of certificate. Required. optional Type type = 1; // 128-bit globally unique serial number of certificate. @@ -47,4 +49,7 @@ message DrmCertificate { // Service identifier (web origin) for the provider which owns the // certificate. Required for service and provisioner certificates. optional string provider_id = 7; + // This field is used only when type = SERVICE to specify which SDK uses + // service certificate. + optional ServiceType service_type = 8 [default = UNKNOWN]; } diff --git a/protos/public/license_protocol.proto b/protos/public/license_protocol.proto index ae26cab..ddc7346 100644 --- a/protos/public/license_protocol.proto +++ b/protos/public/license_protocol.proto @@ -191,6 +191,8 @@ message License { optional HdcpSrmRule hdcp_srm_rule = 3 [default = HDCP_SRM_RULE_NONE]; // Optional requirement to indicate analog output is not allowed. optional bool disable_analog_output = 4 [default = false]; + // Optional requirement to indicate digital output is not allowed. + optional bool disable_digital_output = 5 [default = false]; } message VideoResolutionConstraint { @@ -273,6 +275,7 @@ message License { enum ProtocolVersion { VERSION_2_0 = 20; VERSION_2_1 = 21; + VERSION_2_2 = 22; } message LicenseRequest { diff --git a/sdk/external/common/wvpl/BUILD b/sdk/external/common/wvpl/BUILD index bd82701..ede58eb 100644 --- a/sdk/external/common/wvpl/BUILD +++ b/sdk/external/common/wvpl/BUILD @@ -23,7 +23,7 @@ cc_library( "wvpl_types.h", ], deps = [ - "//util:status", + "//common:status", ], ) @@ -40,12 +40,13 @@ cc_library( # TODO(user): Refactor these deps as classes that derive from WvPLSDKSession may not rely on license SDK(s). ":wvpl_types", "//base", - "//util:status", + "@abseil_repo//absl/memory", "//common:client_cert", - "//common:error_space", - "//common:remote_attestation_verifier", "//common:drm_root_certificate", "//common:drm_service_certificate", + "//common:error_space", + "//common:remote_attestation_verifier", + "//common:status", "//common:verified_media_pipeline", "//license_server_sdk/internal:sdk", "//protos/public:client_identification_proto", @@ -54,6 +55,7 @@ cc_library( "//protos/public:license_protocol_proto", "//protos/public:license_server_sdk_proto", "//protos/public:provisioned_device_info_proto", + "//protos/public:widevine_pssh_proto", ], ) @@ -71,13 +73,13 @@ cc_library( "//base", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", - "//util:status", "//common:aes_cbc_util", "//common:device_status_list", "//common:drm_root_certificate", "//common:error_space", "//common:drm_service_certificate", "//common:sha_util", + "//common:status", "//license_server_sdk/internal:sdk", "//protos/public:device_certificate_status_proto", "//protos/public:errors_proto", @@ -96,9 +98,9 @@ cc_library( deps = [ ":wvpl_types", "//base", + "@abseil_repo//absl/memory", "@abseil_repo//absl/strings", "@abseil_repo//absl/synchronization", - "//util:status", "//common:aes_cbc_util", "//common:client_cert", "//common:device_status_list", @@ -107,6 +109,7 @@ cc_library( "//common:error_space", "//common:remote_attestation_verifier", "//common:sha_util", + "//common:status", "//common:verified_media_pipeline", "//license_server_sdk/internal:sdk", "//protos/public:client_identification_proto", @@ -115,5 +118,6 @@ cc_library( "//protos/public:license_protocol_proto", "//protos/public:license_server_sdk_proto", "//protos/public:provisioned_device_info_proto", + "//protos/public:widevine_pssh_proto", ], ) diff --git a/sdk/external/common/wvpl/wvpl_sdk_environment.cc b/sdk/external/common/wvpl/wvpl_sdk_environment.cc index fbf7738..298df6c 100644 --- a/sdk/external/common/wvpl/wvpl_sdk_environment.cc +++ b/sdk/external/common/wvpl/wvpl_sdk_environment.cc @@ -10,16 +10,15 @@ #include "glog/logging.h" #include "absl/strings/escaping.h" #include "absl/synchronization/mutex.h" -#include "util/status.h" #include "common/aes_cbc_util.h" #include "common/device_status_list.h" #include "common/drm_service_certificate.h" #include "common/error_space.h" #include "common/sha_util.h" +#include "common/status.h" #include "license_server_sdk/internal/generate_error_response.h" #include "protos/public/errors.pb.h" -namespace util = widevine::util; using widevine::DeviceCertificateStatus; using widevine::DeviceCertificateStatusList; using widevine::DeviceStatusList; @@ -32,6 +31,8 @@ using widevine::ProvisionedDeviceInfo; using widevine::SignedDeviceCertificateStatusList; using widevine::crypto_util::EncryptAesCbc; +namespace error = widevine::error; + namespace widevine_server { namespace wv_pl_sdk { @@ -93,9 +94,9 @@ bool WvPLSDKEnvironment::GenerateErrorResponse( WvPLStatus WvPLSDKEnvironment::LookupDeviceInfo( uint32_t system_id, ProvisionedDeviceInfo* provisioned_device_info) { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (provisioned_device_info == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "provisioned_device_info should not be null"); } const ProvisionedDeviceInfoMap& device_info_map = @@ -114,7 +115,7 @@ WvPLStatus WvPLSDKEnvironment::LookupDeviceInfo( WvPLStatus WvPLSDKEnvironment::UpdateProvisionedDeviceInfoMap( const DeviceCertificateStatusList& certificate_status_list) { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; for (const DeviceCertificateStatus& cert_status : certificate_status_list.certificate_status()) { if (cert_status.has_device_info()) { @@ -145,11 +146,11 @@ WvPLStatus WvPLSDKEnvironment::GenerateSignature(const std::string& plain_text, std::string* signature) { DCHECK(signature); if (plain_text.empty()) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "Plain_text for signature is empty."); } if (signature == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "Signature must not be null."); } const std::map* config_values = GetConfigValue(); @@ -161,31 +162,30 @@ WvPLStatus WvPLSDKEnvironment::GenerateSignature(const std::string& plain_text, if (it != config_values->end()) { provider_iv = absl::HexStringToBytes((*it).second); if (provider_iv.empty()) { - return WvPLStatus(error_space, util::error::NOT_FOUND, - "Provider IV is empty."); + return WvPLStatus(error_space, error::NOT_FOUND, "Provider IV is empty."); } } it = config_values->find(kProviderKey); if (it != config_values->end()) { provider_key = absl::HexStringToBytes((*it).second); if (provider_key.empty()) { - return WvPLStatus(error_space, util::error::NOT_FOUND, + return WvPLStatus(error_space, error::NOT_FOUND, "Provider Key is empty."); } } std::string hashed_text = widevine::Sha1_Hash(plain_text); if (hashed_text.empty()) { - return util::Status(error_space, util::error::INVALID_ARGUMENT, - "Hash for signature is empty."); + return WvPLStatus(error_space, error::INVALID_ARGUMENT, + "Hash for signature is empty."); } else { *signature = EncryptAesCbc(provider_key, provider_iv, hashed_text); if (signature->empty()) { - return util::Status(error_space, util::error::INVALID_ARGUMENT, - "Generated signature failed"); + return WvPLStatus(error_space, error::INVALID_ARGUMENT, + "Generated signature failed"); } } - return util::OkStatus(); + return WvPLStatus(); } std::map* WvPLSDKEnvironment::config_values_ = new std::map(); @@ -200,7 +200,7 @@ void WvPLSDKEnvironment::SetConfigValue( WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList( const std::string& cert_list) const { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; SignedDeviceCertificateStatusList device_certificate_status_list; std::string decoded_certificate_status_list; std::string device_certicate_status_list; @@ -210,9 +210,9 @@ WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList( if (!status.ok()) return status; DeviceCertificateStatusList certificate_status_list; if (!certificate_status_list.ParseFromString(device_certicate_status_list)) { - return util::Status(error_space, - widevine::INVALID_CERTIFICATE_STATUS_LIST, - "certificate status list parse error"); + return WvPLStatus(error_space, + widevine::INVALID_CERTIFICATE_STATUS_LIST, + "certificate status list parse error"); } status = DeviceStatusList::Instance()->UpdateStatusList( drm_root_certificate_->public_key(), decoded_certificate_status_list, diff --git a/sdk/external/common/wvpl/wvpl_sdk_session.cc b/sdk/external/common/wvpl/wvpl_sdk_session.cc index 4a8a994..2a0e9e3 100644 --- a/sdk/external/common/wvpl/wvpl_sdk_session.cc +++ b/sdk/external/common/wvpl/wvpl_sdk_session.cc @@ -8,21 +8,24 @@ #include "sdk/external/common/wvpl/wvpl_sdk_session.h" #include "glog/logging.h" -#include "util/status.h" #include "absl/memory/memory.h" #include "common/client_cert.h" #include "common/drm_service_certificate.h" #include "common/error_space.h" #include "common/remote_attestation_verifier.h" +#include "common/status.h" #include "common/verified_media_pipeline.h" +#include "license_server_sdk/internal/parse_content_id.h" #include "sdk/external/common/wvpl/wvpl_sdk_environment.h" #include "sdk/external/common/wvpl/wvpl_types.h" #include "protos/public/errors.pb.h" +#include "protos/public/license_protocol.pb.h" #include "protos/public/provisioned_device_info.pb.h" +#include "protos/public/widevine_pssh.pb.h" // TODO(user): Mark getProvisionedDeviceInfo as deprecated, move the -// implementation of isChromeCDM, getcontentid, parsePsshdata in wvpl_session -// and wvpl_proxy_session to base class. +// implementation of isChromeCDM in wvpl_session and wvpl_proxy_session to base +// class. // TODO(user): Set SerialNumber and ServiceId field of WvPLDeviceInfo in // getDeviceInfo function. // TODO(user): Move the related Copy* function test cases to @@ -31,23 +34,27 @@ // signed_message_request_from_cdm_ when create session. // TODO(user): Move all the protected memeber variables to private and use // getter and setter to access it. -// TODO(user): Try to avoid virtual private function like parsepsshdata. // TODO(user): (b/119566765) Refactor ParseLicenseRequest and break it into // different classes. -namespace util = widevine::util; using widevine::ClientCert; using widevine::ClientIdentification; +using widevine::ContentInfo; using widevine::DrmRootCertificate; using widevine::DrmServiceCertificate; using widevine::error_space; using widevine::KeyboxClientCert; using widevine::License; using widevine::LicenseRequest; +using widevine::LicenseType; +using widevine::OkStatus; using widevine::ProvisionedDeviceInfo; using widevine::RemoteAttestationVerifier; using widevine::SessionInit; using widevine::SignedMessage; +using widevine::WidevinePsshData; + +namespace error = widevine::error; namespace widevine_server { namespace wv_pl_sdk { @@ -59,7 +66,7 @@ WvPLSDKSession::~WvPLSDKSession() {} WvPLStatus WvPLSDKSession::AddKey(const WvPLKey& key) { keys_.push_back(key); - return util::OkStatus(); + return OkStatus(); } void WvPLSDKSession::CopyPlaybackPolicy(const WvPLPlaybackPolicy& wvpl_policy, @@ -227,6 +234,11 @@ void WvPLSDKSession::CopyHDCP( output_protection->set_hdcp( License::KeyContainer::OutputProtection::HDCP_NONE); break; + case HDCP_NO_DIGITAL_OUTPUT: + output_protection->set_hdcp( + License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT); + output_protection->set_disable_digital_output(true); + break; default: break; } @@ -306,23 +318,40 @@ void WvPLSDKSession::CopyOutputProtection( CopyHDCP(wvpl_key.output_protection().hdcp(), sdk_key_container->mutable_required_protection()); - // Transfer HDCP from requested output protection value. - CopyHDCP(wvpl_key.requested_output_protection().hdcp(), - sdk_key_container->mutable_requested_protection()); - CopySecurityLevel(wvpl_key.output_protection(), wvpl_key.track_type(), sdk_key_container); - sdk_key_container->mutable_requested_protection()->set_disable_analog_output( + sdk_key_container->mutable_required_protection()->set_disable_analog_output( wvpl_key.output_protection().disable_analog_output()); + sdk_key_container->mutable_required_protection()->set_disable_digital_output( + wvpl_key.output_protection().disable_digital_output()); + if (wvpl_key.output_protection().disable_digital_output()) { sdk_key_container->mutable_required_protection()->set_hdcp( License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT); } - CopyCGMS(wvpl_key.output_protection().cgms(), - sdk_key_container->mutable_requested_protection()); + // Transfer HDCP from requested output protection value. + CopyCGMS(wvpl_key.output_protection().cgms(), + sdk_key_container->mutable_required_protection()); + if (wvpl_key.requested_output_protection().hdcp() != HDCP_NONE) { + CopyHDCP(wvpl_key.requested_output_protection().hdcp(), + sdk_key_container->mutable_requested_protection()); + } + if (wvpl_key.requested_output_protection().disable_analog_output()) { + sdk_key_container->mutable_requested_protection() + ->set_disable_analog_output( + wvpl_key.requested_output_protection().disable_analog_output()); + } + if (wvpl_key.requested_output_protection().disable_digital_output()) { + sdk_key_container->mutable_requested_protection()->set_hdcp( + License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT); + } + if (wvpl_key.requested_output_protection().cgms() != CGMS_NONE) { + CopyCGMS(wvpl_key.requested_output_protection().cgms(), + sdk_key_container->mutable_requested_protection()); + } // Transfer Video resultion constraints. const std::vector& video_constraints = wvpl_key.video_resolution_constraints(); @@ -400,7 +429,7 @@ void WvPLSDKSession::CopyProvisionedDeviceInfo( } WvPLStatus WvPLSDKSession::ParseLicenseRequest() { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (license_request_from_cdm_.empty() && sdk_license_request_ == nullptr) { return WvPLStatus(error_space, widevine::SIGNED_MESSAGE_PARSE_ERROR, "License request from cdm is empty or null"); @@ -491,7 +520,7 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() { } request_type_ = sdk_license_request_->type(); } - return util::OkStatus(); + return OkStatus(); } bool WvPLSDKSession::IsChromeCDM() const { @@ -503,9 +532,9 @@ bool WvPLSDKSession::IsChromeCDM() const { } WvPLStatus WvPLSDKSession::GetClientInfo(WvPLClientInfo* client_info) const { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (client_info == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "client_info is NULL"); } if (!has_client_id_) { @@ -557,11 +586,11 @@ WvPLStatus WvPLSDKSession::GetClientInfo(WvPLClientInfo* client_info) const { WvPLStatus WvPLSDKSession::VerifyRemoteAttestation() { DCHECK(signed_message_request_from_cdm_); if (!signed_message_request_from_cdm_->has_remote_attestation()) { - return WvPLStatus(error_space, util::error::INTERNAL, + return WvPLStatus(error_space, error::INTERNAL, "Remote Attestation not specified"); } else if (!signed_message_request_from_cdm_->remote_attestation() .has_certificate()) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "Remote Attestation Certificate not specified"); } else { WvPLStatus ra_status = @@ -570,14 +599,14 @@ WvPLStatus WvPLSDKSession::VerifyRemoteAttestation() { signed_message_request_from_cdm_->remote_attestation(), &remote_attestation_cert_serial_number_); } - return util::OkStatus(); + return OkStatus(); } WvPLStatus WvPLSDKSession::GetClientCapabilities( WvPLClientCapabilities* client_capabilities) const { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (client_capabilities == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "client_capabilities is NULL"); } if (!has_client_id_) { @@ -592,9 +621,9 @@ WvPLStatus WvPLSDKSession::GetClientCapabilities( WvPLStatus WvPLSDKSession::GetWvPLClientCapabilities( const widevine::ClientIdentification& client_id, WvPLClientCapabilities* client_capabilities) const { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (client_capabilities == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "client_capabilities is NULL"); } @@ -653,22 +682,86 @@ WvPLStatus WvPLSDKSession::GetPsshData( WvPLWidevinePsshData* wvpl_widevine_pssh_data) const { DCHECK(wvpl_widevine_pssh_data); if (wvpl_widevine_pssh_data == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "wvpl_widevine_pssh_data is null"); } if (!has_pssh_data_) { - // TODO(b/115784237): Fix calling ParsePsshData within base class. - WvPLStatus status = ParsePsshData(wvpl_widevine_pssh_data); - return status; + DCHECK(sdk_license_request_); + if (sdk_license_request_ == nullptr) { + return WvPLStatus(error_space, error::INVALID_ARGUMENT, + "sdk_license_request_ is null"); + } + if (request_type() == LicenseRequest::NEW) { + ContentInfo content_info; + WvPLStatus status = widevine::ParseContentId( + sdk_license_request_->content_id(), &content_info); + if (!status.ok()) { + return WvPLStatus(error_space, error::INTERNAL, + "Failed to get pssh data. GetContentInfo() failed."); + } + if (content_info.content_info_entry().empty()) { + return WvPLStatus(error_space, error::INTERNAL, + "Failed to get pssh data. ContentInfo is empty."); + } + WidevinePsshData wv_pssh; + if (content_info.init_data_type() == + LicenseRequest::ContentIdentification::InitData::CENC) { + for (size_t i = 0; i < content_info.content_info_entry().size(); ++i) { + if (!content_info.content_info_entry(i).has_pssh()) { + return WvPLStatus(error_space, + widevine::INVALID_WIDEVINE_PSSH_DATA, + "wvpl_widevine_pssh_data is empty"); + } + if (content_info.content_info_entry(i).pssh().has_widevine_data()) { + wv_pssh = content_info.content_info_entry(i).pssh().widevine_data(); + } + if (wv_pssh.has_content_id()) { + wvpl_widevine_pssh_data->set_content_id(wv_pssh.content_id()); + } + for (int idx = 0; idx < wv_pssh.key_ids().size(); ++idx) { + wvpl_widevine_pssh_data->set_key_id(wv_pssh.key_ids(idx)); + } + for (int idx = 0; idx < wv_pssh.entitled_keys().size(); ++idx) { + WvPLEntitledKey wvpl_entitled_key; + wvpl_entitled_key.set_entitlement_key_id( + wv_pssh.entitled_keys(idx).entitlement_key_id()); + wvpl_entitled_key.set_key_id(wv_pssh.entitled_keys(idx).key_id()); + wvpl_entitled_key.set_key_bytes(wv_pssh.entitled_keys(idx).key()); + wvpl_entitled_key.set_entitlement_key_iv( + wv_pssh.entitled_keys(idx).iv()); + wvpl_entitled_key.set_entitlement_key_size_bytes( + wv_pssh.entitled_keys(idx).entitlement_key_size_bytes()); + wvpl_widevine_pssh_data->add_entitled_key(wvpl_entitled_key); + } + } + return status; + } else if (content_info.init_data_type() == + LicenseRequest::ContentIdentification::InitData::WEBM) { + for (size_t i = 0; i < content_info.content_info_entry().size(); ++i) { + for (int idx = 0; + idx < content_info.content_info_entry(i).key_ids().size(); + ++idx) { + wvpl_widevine_pssh_data->set_key_id( + content_info.content_info_entry(i).key_ids(idx)); + } + } + } else { + return WvPLStatus(error_space, error::INVALID_ARGUMENT, + "Failed to get pssh data. Widevine PSSH not found."); + } + } + // A PSSH with the widevine header wasn't found, so return error. + return WvPLStatus(error_space, error::NOT_FOUND, + "Failed to get pssh data. Widevine PSSH not found."); } *wvpl_widevine_pssh_data = pssh_data_; - return util::OkStatus(); + return OkStatus(); } WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const { - WvPLStatus status = util::OkStatus(); + WvPLStatus status; if (device_info == nullptr) { - return WvPLStatus(error_space, util::error::INVALID_ARGUMENT, + return WvPLStatus(error_space, error::INVALID_ARGUMENT, "device_info is NULL"); } if (!HasSystemId()) { @@ -733,5 +826,31 @@ uint32_t WvPLSDKSession::GetSystemId() const { CHECK(system_id_); return *system_id_; } + +bool WvPLSDKSession::is_offline_license() const { + DCHECK(sdk_license_request_); + if (sdk_license_request_ == nullptr) return false; + + if (!sdk_license_request_->has_content_id()) return false; + const LicenseRequest::ContentIdentification& content_id = + sdk_license_request_->content_id(); + if (content_id.has_init_data()) { + return content_id.init_data().license_type() == widevine::OFFLINE; + } + if (content_id.has_cenc_id_deprecated()) { + return content_id.cenc_id_deprecated().license_type() == + widevine::OFFLINE; + } + if (content_id.has_webm_id_deprecated()) { + return content_id.webm_id_deprecated().license_type() == + widevine::OFFLINE; + } + if (content_id.has_existing_license()) { + return content_id.existing_license().license_id().type() == + widevine::OFFLINE; + } + return false; +} + } // namespace wv_pl_sdk } // namespace widevine_server diff --git a/sdk/external/common/wvpl/wvpl_sdk_session.h b/sdk/external/common/wvpl/wvpl_sdk_session.h index 21e8335..8cf5d19 100644 --- a/sdk/external/common/wvpl/wvpl_sdk_session.h +++ b/sdk/external/common/wvpl/wvpl_sdk_session.h @@ -105,6 +105,13 @@ class WvPLSDKSession { return request_type_; } + /** + * Returns true if the license type is offline, otherwise return false. + * + * @return bool. + */ + virtual bool is_offline_license() const; + protected: const widevine::DrmRootCertificate* drm_root_certificate_; std::string user_agent_; @@ -206,14 +213,6 @@ class WvPLSDKSession { private: std::unique_ptr system_id_; - - /** - * Parses WvPLWidevinePsshData in the new license request. - * - * @return WvPLStatus - Status::OK if success, else error. - */ - virtual WvPLStatus ParsePsshData( - WvPLWidevinePsshData* wvpl_widevine_pssh_data) const = 0; }; } // namespace wv_pl_sdk diff --git a/sdk/external/common/wvpl/wvpl_types.h b/sdk/external/common/wvpl/wvpl_types.h index 9fe5236..0431ea6 100644 --- a/sdk/external/common/wvpl/wvpl_types.h +++ b/sdk/external/common/wvpl/wvpl_types.h @@ -15,7 +15,7 @@ #include #include -#include "util/status.h" +#include "common/status.h" // TODO(user) Split wvpl_types.h into wvpl_common_types.h , // wvpl_license_sdk_types.h, wvpl_proxy_sdk_types.h and @@ -23,7 +23,7 @@ namespace widevine_server { namespace wv_pl_sdk { -typedef widevine::util::Status WvPLStatus; +typedef widevine::Status WvPLStatus; typedef uint32_t uint32_t; typedef int64_t int64_t; diff --git a/testing/BUILD b/testing/BUILD index bad30ce..9fd8c49 100644 --- a/testing/BUILD +++ b/testing/BUILD @@ -18,7 +18,6 @@ cc_library( ], deps = [ "//external:gtest", - "//util:status", ], ) 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/util/BUILD b/util/BUILD index 714b6ef..d40db8b 100644 --- a/util/BUILD +++ b/util/BUILD @@ -15,22 +15,6 @@ filegroup( name = "binary_release_files", srcs = [ "error_space.h", - "status.h", - ], -) - -cc_library( - name = "status", - srcs = [ - "status.cc", - ], - hdrs = [ - "status.h", - ], - deps = [ - ":error_space", - "//base", - "@abseil_repo//absl/strings", ], ) @@ -43,17 +27,8 @@ cc_library( name = "proto_status", hdrs = ["proto_status.h"], deps = [ - ":status", "//external:protobuf", - ], -) - -cc_test( - name = "status_test", - srcs = ["status_test.cc"], - deps = [ - ":status", - "//testing:gunit_main", + "//util:error_space", ], ) diff --git a/util/error_space.h b/util/error_space.h index 68c093a..2e66a39 100644 --- a/util/error_space.h +++ b/util/error_space.h @@ -49,11 +49,11 @@ class ErrorSpaceImpl : public ErrorSpace { // pointer to stateless static methods, so that clients of ErrorSpaceImpl are // safe to have constexpr global instances. static std::string SpaceNameImpl(const ErrorSpace* /*space*/) { - return T::SpaceName(); + return T::space_name(); } static std::string CodeToStringImpl(const ErrorSpace* /*space*/, int code) { - return T::CodeToString(code); + return T::code_to_string(code); } }; diff --git a/util/error_space_test.cc b/util/error_space_test.cc index a32d339..47f547f 100644 --- a/util/error_space_test.cc +++ b/util/error_space_test.cc @@ -16,14 +16,16 @@ namespace { class Space1 : public util::ErrorSpaceImpl { public: - static std::string SpaceName() { return "Space1"; } - static std::string CodeToString(int code) { return "Test" + std::to_string(code); } + static std::string space_name() { return "Space1"; } + static std::string code_to_string(int code) { + return "Test" + std::to_string(code); + } }; TEST(ErrorSpaceTest, Basic) { const ErrorSpace* space1 = Space1::Get(); EXPECT_EQ("Space1", space1->SpaceName()); - EXPECT_EQ(Space1::CodeToString(23), space1->String(23)); + EXPECT_EQ(Space1::code_to_string(23), space1->String(23)); } } // namespace diff --git a/util/proto_status.h b/util/proto_status.h index 2205db4..1878bc2 100644 --- a/util/proto_status.h +++ b/util/proto_status.h @@ -11,24 +11,26 @@ #include "google/protobuf/descriptor.h" #include "google/protobuf/generated_enum_reflection.h" -#include "util/status.h" +#include "util/error_space.h" namespace widevine { namespace util { template -class ProtoEnumErrorSpace : public ErrorSpaceImpl> { +class ProtoEnumErrorSpace + : public util::ErrorSpaceImpl> { public: - static std::string SpaceName() { + static std::string space_name() { return google::protobuf::GetEnumDescriptor()->full_name(); } - static std::string CodeToString(int code) { + static std::string code_to_string(int code) { const google::protobuf::EnumValueDescriptor* v = google::protobuf::GetEnumDescriptor()->FindValueByNumber(code); if (v) return v->name(); return std::to_string(code); } + }; } // namespace util diff --git a/util/proto_status_test.cc b/util/proto_status_test.cc index ea84e04..052caf2 100644 --- a/util/proto_status_test.cc +++ b/util/proto_status_test.cc @@ -9,6 +9,7 @@ #include "util/proto_status.h" #include "testing/gunit.h" +#include "common/status.h" #include "protos/public/errors.pb.h" namespace widevine { @@ -31,10 +32,18 @@ TEST(StatusTest, Same) { Status status1(ProtoEnumErrorSpace::Get(), PROVIDER_ID_MISMATCH, "provider_id_mismatch"); Status status2(ProtoEnumErrorSpace::Get(), PROVIDER_ID_MISMATCH, - "this is a provider_id_mismatch error"); + "provider_id_mismatch"); EXPECT_EQ(status1, status2); } +TEST(StatusTest, ErrorMessageMismatch) { + Status status1(ProtoEnumErrorSpace::Get(), PROVIDER_ID_MISMATCH, + "provider_id_mismatch"); + Status status2(ProtoEnumErrorSpace::Get(), PROVIDER_ID_MISMATCH, + "this is a provider_id_mismatch error"); + EXPECT_NE(status1, status2); +} + TEST(StatusTest, NotTheSameStatus) { Status status1(ProtoEnumErrorSpace::Get(), PROVIDER_ID_MISMATCH, "provider_id_mismatch"); diff --git a/util/status.cc b/util/status.cc deleted file mode 100644 index 2936549..0000000 --- a/util/status.cc +++ /dev/null @@ -1,62 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2017 Google LLC. -// -// This software is licensed under the terms defined in the Widevine Master -// License Agreement. For a copy of this agreement, please contact -// widevine-licensing@google.com. -//////////////////////////////////////////////////////////////////////////////// - -#include - -#include "base/macros.h" -#include "absl/strings/str_cat.h" -#include "util/status.h" - -namespace widevine { -namespace util { -namespace { - -const char* kLicenseServerStatusMessage[] = {"OK", - "UNKNOWN_ERROR", - "UNKNOWN_ERROR", - "INVALID_ARGUMENT", - "UNKNOWN_ERROR", - "NOT_FOUND", - "ALREADY_EXISTS", - "PERMISSION_DENIED", - "UNKNOWN_ERROR", - "UNKNOWN_ERROR", - "UNKNOWN_ERROR", - "UNKNOWN_ERROR", - "UNIMPLEMENTED", - "INTERNAL", - "UNAVAILABLE"}; - -} // namespace - -std::string GenericErrorSpace::SpaceName() { return "generic"; } - -std::string GenericErrorSpace::CodeToString(int code) { - static_assert( - arraysize(kLicenseServerStatusMessage) == error::NUM_ERRORS, - "mismatching license_server_sdk status message and license_server_sdk " - "status."); - - if (code >= 0 && code < error::NUM_ERRORS) - return kLicenseServerStatusMessage[code]; - return std::to_string(code); -} - -std::string Status::ToString() const { - if (status_code_ == error::OK) return "OK"; - return absl::StrCat("Errors::", error_space_->String(status_code_), ": ", - error_message_); -} - -std::ostream& operator<<(std::ostream& os, const Status& x) { - os << x.ToString(); - return os; -} - -} // namespace util -} // namespace widevine