//////////////////////////////////////////////////////////////////////////////// // Copyright 2019 Google LLC. // // This software is licensed under the terms defined in the Widevine Master // License Agreement. For a copy of this agreement, please contact // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// #include "common/client_cert.h" #include #include "testing/gmock.h" #include "testing/gunit.h" #include "absl/strings/escaping.h" #include "common/ec_test_keys.h" #include "common/error_space.h" #include "common/keybox_client_cert.h" #include "common/rsa_key.h" #include "common/rsa_test_keys.h" #include "common/sha_util.h" #include "common/status.h" #include "common/test_drm_certificates.h" #include "common/wvm_test_keys.h" #include "protos/public/drm_certificate.pb.h" #include "protos/public/errors.pb.h" #include "protos/public/signed_drm_certificate.pb.h" using widevine::ClientCert; using widevine::ClientIdentification; using widevine::Status; namespace widevine { const DrmCertificate::Type kNoSigner = DrmCertificate::ROOT; const DrmCertificate::Type kDeviceModelSigner = DrmCertificate::DEVICE_MODEL; const DrmCertificate::Type kProvisionerSigner = DrmCertificate::PROVISIONER; // TODO(user): Change these tests to use on-the-fly generated intermediate // and device certificates based on RsaTestKeys. // TODO(user): Add testcase(s) CreateSignature, // and GenerateSigningKey. class ClientCertTest : public ::testing::TestWithParam { public: ~ClientCertTest() override = default; void SetUp() override { if (!setup_preprov_keys_) { KeyboxClientCert::SetPreProvisioningKeys( wvm_test_keys::GetPreprovKeyMultimap()); setup_preprov_keys_ = true; } ASSERT_OK( DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); } protected: // Simple container struct for test value and expected keys. class TestTokenAndKeys { public: const std::string token_; uint32_t expected_system_id_; const std::string expected_serial_number_; const std::string expected_device_key_; TestTokenAndKeys(const std::string& token, uint32_t expected_system_id, const std::string& expected_serial_number, const std::string& expected_device_key) : token_(token), expected_system_id_(expected_system_id), expected_serial_number_(expected_serial_number), expected_device_key_(expected_device_key) {} }; class TestCertificateAndData { public: const std::string certificate_; const std::string expected_serial_number_; uint32_t expected_system_id_; Status expected_status_; TestCertificateAndData(const std::string& certificate, const std::string& expected_serial_number, uint32_t expected_system_id, Status expected_status) : certificate_(certificate), expected_serial_number_(expected_serial_number), expected_system_id_(expected_system_id), expected_status_(expected_status) {} }; void TestBasicValidation(const TestTokenAndKeys& expectation, const bool expect_success, const bool compare_device_key); void TestBasicValidationDrmCertificate( const TestCertificateAndData& expectation, const bool compare_data); void GenerateSignature(const std::string& message, const std::string& private_key, std::string* signature); SignedDrmCertificate* SignCertificate(const DrmCertificate& certificate, SignedDrmCertificate* signer, const std::string& private_key); DrmCertificate* GenerateProvisionerCertificate( uint32_t system_id, const std::string& serial_number, const std::string& provider_id); SignedDrmCertificate* GenerateSignedProvisionerCertificate( uint32_t system_id, const std::string& serial_number, const std::string& service_id); DrmCertificate* GenerateIntermediateCertificate( uint32_t system_id, const std::string& serial_number); SignedDrmCertificate* GenerateSignedIntermediateCertificate( SignedDrmCertificate* signer, uint32_t system_id, const std::string& serial_number, DrmCertificate::Type signer_cert_type); DrmCertificate* GenerateDrmCertificate( uint32_t system_id, const std::string& serial_number, DrmCertificate::Algorithm = DrmCertificate::RSA); SignedDrmCertificate* GenerateSignedDrmCertificate( SignedDrmCertificate* signer, uint32_t system_id, const std::string& serial_number, DrmCertificate::Algorithm = DrmCertificate::RSA); std::string GetPublicKeyByCertType(DrmCertificate::Type cert_type); std::string GetPrivateKeyByCertType(DrmCertificate::Type cert_type); std::string GetECCPublicKey(DrmCertificate::Algorithm algorithm); RsaTestKeys test_rsa_keys_; TestDrmCertificates test_drm_certs_; std::unique_ptr root_cert_; static bool setup_preprov_keys_; }; bool ClientCertTest::setup_preprov_keys_(false); void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation, const bool expect_success, const bool compare_device_key) { // Test validation of a valid request. Status status; std::unique_ptr keybox_cert; status = ClientCert::Create(root_cert_.get(), ClientIdentification::KEYBOX, expectation.token_, &keybox_cert); if (expect_success) { ASSERT_EQ(OkStatus(), status); ASSERT_TRUE(keybox_cert.get()); EXPECT_EQ(expectation.expected_system_id_, keybox_cert->system_id()); EXPECT_EQ(expectation.expected_serial_number_, keybox_cert->serial_number()); if (compare_device_key) { EXPECT_EQ(expectation.expected_device_key_, keybox_cert->key()); } } else { EXPECT_NE(OkStatus(), status); EXPECT_FALSE(keybox_cert); } } void ClientCertTest::TestBasicValidationDrmCertificate( const TestCertificateAndData& expectation, const bool compare_data) { // Reset DRM certificate signature cache since some certificates get // re-generated. ASSERT_OK( DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); // Test validation of a valid request. Status status; std::unique_ptr drm_certificate_cert; status = ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, expectation.certificate_, &drm_certificate_cert); ASSERT_EQ(expectation.expected_status_, status); if (expectation.expected_status_.ok()) { ASSERT_TRUE(drm_certificate_cert.get()); if (compare_data) { ASSERT_EQ(expectation.expected_serial_number_, drm_certificate_cert->signer_serial_number()); ASSERT_EQ(expectation.expected_system_id_, drm_certificate_cert->system_id()); } } else { ASSERT_FALSE(drm_certificate_cert.get()); } } void ClientCertTest::GenerateSignature(const std::string& message, const std::string& private_key, std::string* signature) { std::unique_ptr rsa_private_key( RsaPrivateKey::Create(private_key)); ASSERT_TRUE(rsa_private_key != nullptr); rsa_private_key->GenerateSignature(message, signature); } // The caller relinquishes ownership of |signer|, which may also be nullptr. SignedDrmCertificate* ClientCertTest::SignCertificate( const DrmCertificate& certificate, SignedDrmCertificate* signer, const std::string& private_key) { std::unique_ptr signed_certificate( new SignedDrmCertificate); signed_certificate->set_drm_certificate(certificate.SerializeAsString()); GenerateSignature(signed_certificate->drm_certificate(), private_key, signed_certificate->mutable_signature()); if (signer != nullptr) { signed_certificate->set_allocated_signer(signer); } return signed_certificate.release(); } std::string ClientCertTest::GetPublicKeyByCertType( DrmCertificate::Type cert_type) { if (cert_type == DrmCertificate::DEVICE) { return test_rsa_keys_.public_test_key_3_2048_bits(); } else if (cert_type == DrmCertificate::DEVICE_MODEL) { return test_rsa_keys_.public_test_key_2_2048_bits(); } return test_rsa_keys_.public_test_key_1_3072_bits(); } std::string ClientCertTest::GetPrivateKeyByCertType( DrmCertificate::Type cert_type) { if (cert_type == DrmCertificate::DEVICE) { return test_rsa_keys_.private_test_key_3_2048_bits(); } else if (cert_type == DrmCertificate::DEVICE_MODEL) { return test_rsa_keys_.private_test_key_2_2048_bits(); } return test_rsa_keys_.private_test_key_1_3072_bits(); } std::string ClientCertTest::GetECCPublicKey( DrmCertificate::Algorithm algorithm) { ECTestKeys keys; switch (algorithm) { case DrmCertificate::ECC_SECP256R1: return keys.public_test_key_1_secp256r1(); case DrmCertificate::ECC_SECP384R1: return keys.public_test_key_1_secp384r1(); case DrmCertificate::ECC_SECP521R1: return keys.public_test_key_1_secp521r1(); default: return ""; } } DrmCertificate* ClientCertTest::GenerateIntermediateCertificate( uint32_t system_id, const std::string& serial_number) { std::unique_ptr intermediate_certificate(new DrmCertificate); intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL); intermediate_certificate->set_serial_number(serial_number); intermediate_certificate->set_public_key( GetPublicKeyByCertType(DrmCertificate::DEVICE_MODEL)); intermediate_certificate->set_system_id(system_id); intermediate_certificate->set_creation_time_seconds(1234); return intermediate_certificate.release(); } SignedDrmCertificate* ClientCertTest::GenerateSignedIntermediateCertificate( SignedDrmCertificate* signer, uint32_t system_id, const std::string& serial_number, DrmCertificate::Type signer_cert_type) { std::unique_ptr intermediate_certificate( GenerateIntermediateCertificate(system_id, serial_number)); // Must use the same key pair used by GenerateIntermediateCertificate(). return SignCertificate(*intermediate_certificate, signer, GetPrivateKeyByCertType(signer_cert_type)); } DrmCertificate* ClientCertTest::GenerateDrmCertificate( uint32_t system_id, const std::string& serial_number, DrmCertificate::Algorithm algorithm) { std::unique_ptr drm_certificate(new DrmCertificate); drm_certificate->set_type(DrmCertificate::DEVICE); drm_certificate->set_serial_number(serial_number); drm_certificate->set_system_id(system_id); drm_certificate->set_public_key( algorithm == DrmCertificate::RSA ? GetPublicKeyByCertType(DrmCertificate::DEVICE) : GetECCPublicKey(algorithm)); drm_certificate->set_creation_time_seconds(4321); drm_certificate->set_algorithm(algorithm); return drm_certificate.release(); } SignedDrmCertificate* ClientCertTest::GenerateSignedDrmCertificate( SignedDrmCertificate* signer, uint32_t system_id, const std::string& serial_number, DrmCertificate::Algorithm algorithm) { std::unique_ptr drm_certificate( GenerateDrmCertificate(system_id, serial_number, algorithm)); std::unique_ptr signed_drm_certificate( SignCertificate(*drm_certificate, signer, GetPrivateKeyByCertType(DrmCertificate::DEVICE_MODEL))); return signed_drm_certificate.release(); } DrmCertificate* ClientCertTest::GenerateProvisionerCertificate( uint32_t system_id, const std::string& serial_number, const std::string& provider_id) { std::unique_ptr provisioner_certificate(new DrmCertificate); provisioner_certificate->set_type(DrmCertificate::PROVISIONER); provisioner_certificate->set_serial_number(serial_number); provisioner_certificate->set_public_key( GetPublicKeyByCertType(DrmCertificate::DrmCertificate::PROVISIONER)); provisioner_certificate->set_system_id(system_id); provisioner_certificate->set_provider_id(provider_id); provisioner_certificate->set_creation_time_seconds(1234); return provisioner_certificate.release(); } SignedDrmCertificate* ClientCertTest::GenerateSignedProvisionerCertificate( uint32_t system_id, const std::string& serial_number, const std::string& service_id) { std::unique_ptr provisioner_certificate( GenerateProvisionerCertificate(system_id, serial_number, service_id)); return SignCertificate(*provisioner_certificate, nullptr, GetPrivateKeyByCertType(DrmCertificate::ROOT)); } TEST_F(ClientCertTest, BasicValidation) { const TestTokenAndKeys kValidTokenAndExpectedKeys[] = { TestTokenAndKeys( absl::HexStringToBytes( "00000002000001128e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" "2517a12f4922953e"), 274, absl::HexStringToBytes("8e1ebfe037828096ca6538b4f6f4bcb5"), absl::HexStringToBytes("4071197f1f8910d9bf10c6bc4c987638")), TestTokenAndKeys( absl::HexStringToBytes( "0000000200000112d906feebe1750c5886ff77c2dfa31bb40e002f3adbc0fa5b" "eb2486cf5f419549cdaa23230e5165ac2ffab56d53b692b7ba0c1857400c6add" "3af3ff3d5cb24985"), 274, absl::HexStringToBytes("d906feebe1750c5886ff77c2dfa31bb4"), absl::HexStringToBytes("42cfb1765201042302a404d1e0fac8ed"))}; for (size_t i = 0; i < ABSL_ARRAYSIZE(kValidTokenAndExpectedKeys); ++i) { SCOPED_TRACE("Test data: " + absl::StrCat(i)); TestBasicValidation(kValidTokenAndExpectedKeys[i], true, true); } EXPECT_EQ( wvm_test_keys::kTestSystemId, KeyboxClientCert::GetSystemId(kValidTokenAndExpectedKeys[0].token_)); } TEST_P(ClientCertTest, BasicCertValidation) { const uint32_t system_id = 1234; const std::string serial_number("serial_number"); std::unique_ptr signed_cert( GenerateSignedDrmCertificate( GenerateSignedIntermediateCertificate(nullptr, system_id, serial_number, kNoSigner), system_id, serial_number + "-device", GetParam())); const TestCertificateAndData kValidCertificateAndExpectedData( signed_cert->SerializeAsString(), serial_number, system_id, OkStatus()); const bool compare_data = true; TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData, compare_data); } INSTANTIATE_TEST_SUITE_P(BasicCertValidation, ClientCertTest, testing::Values(DrmCertificate::RSA, DrmCertificate::ECC_SECP256R1, DrmCertificate::ECC_SECP384R1, DrmCertificate::ECC_SECP521R1)); TEST_F(ClientCertTest, InvalidKeybox) { const TestTokenAndKeys kInvalidTokenAndExpectedKeys[] = { // This tests a malformed, but appropriately sized keybox. TestTokenAndKeys( absl::HexStringToBytes( "00000002000001129e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" "2517a12f4922953e"), 0, absl::HexStringToBytes(""), absl::HexStringToBytes("")), // This has a length and system_id, but nothing else. TestTokenAndKeys(absl::HexStringToBytes("0000000200000112"), 0, absl::HexStringToBytes(""), absl::HexStringToBytes("")), // This has only a byte. TestTokenAndKeys(absl::HexStringToBytes(""), 0, absl::HexStringToBytes(""), absl::HexStringToBytes("")), // This has an emptry std::string for the keybox. TestTokenAndKeys(absl::HexStringToBytes(""), 0, absl::HexStringToBytes(""), absl::HexStringToBytes(""))}; for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidTokenAndExpectedKeys); ++i) { SCOPED_TRACE("Test data: " + absl::StrCat(i)); TestBasicValidation(kInvalidTokenAndExpectedKeys[i], false, false); } } TEST_F(ClientCertTest, InvalidCertificate) { const uint32_t system_id(1234); const std::string device_sn("device-serial-number"); const std::string signer_sn("signer-serial-number"); std::unique_ptr dev_cert; std::unique_ptr signer_cert; std::unique_ptr signed_signer; // Invalid serialized device certificate. std::unique_ptr invalid_drm_cert( new SignedDrmCertificate); invalid_drm_cert->set_drm_certificate("bad-serialized-cert"); GenerateSignature(invalid_drm_cert->drm_certificate(), test_rsa_keys_.private_test_key_2_2048_bits(), invalid_drm_cert->mutable_signature()); invalid_drm_cert->set_allocated_signer(GenerateSignedIntermediateCertificate( nullptr, system_id, signer_sn, kNoSigner)); // Invalid device public key. dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); dev_cert->set_public_key("bad-device-public-key"); std::unique_ptr bad_device_public_key( SignCertificate(*dev_cert, GenerateSignedIntermediateCertificate( nullptr, system_id, signer_sn, kNoSigner), test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid serialized intermediate certificate. signed_signer.reset(GenerateSignedIntermediateCertificate( nullptr, system_id, signer_sn, kNoSigner)); signed_signer->set_drm_certificate("bad-serialized-cert"); GenerateSignature(signed_signer->drm_certificate(), test_rsa_keys_.private_test_key_1_3072_bits(), signed_signer->mutable_signature()); dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); std::unique_ptr invalid_signer( SignCertificate(*dev_cert, signed_signer.release(), 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)); signer_cert->set_public_key("bad-signer-public-key"); std::unique_ptr bad_signer_public_key(SignCertificate( *dev_cert, SignCertificate(*signer_cert, nullptr, test_rsa_keys_.private_test_key_1_3072_bits()), test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid device certificate signature. std::unique_ptr bad_device_signature( GenerateSignedDrmCertificate( GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn, kNoSigner), system_id, device_sn)); bad_device_signature->set_signature("bad-signature"); // Missing model system ID. dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn)); signer_cert->clear_system_id(); std::unique_ptr missing_model_sn(SignCertificate( *dev_cert, SignCertificate(*signer_cert, nullptr, test_rsa_keys_.private_test_key_1_3072_bits()), 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)); signer_cert->clear_serial_number(); std::unique_ptr missing_signer_sn(SignCertificate( *dev_cert, SignCertificate(*signer_cert, nullptr, test_rsa_keys_.private_test_key_1_3072_bits()), test_rsa_keys_.private_test_key_2_2048_bits())); // Invalid serialized intermediate certificate. dev_cert.reset(GenerateDrmCertificate(system_id, device_sn)); signed_signer.reset(GenerateSignedIntermediateCertificate( nullptr, system_id, signer_sn, kNoSigner)); signed_signer->set_signature("bad-signature"); std::unique_ptr bad_signer_signature( SignCertificate(*dev_cert, signed_signer.release(), test_rsa_keys_.private_test_key_2_2048_bits())); const TestCertificateAndData kInvalidCertificate[] = { TestCertificateAndData("f", "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signed-drm-certificate")), TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate")), TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "drm-certificate-public-key-failed")), TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signer-certificate")), TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-leaf-signer-public-key")), TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0, Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature")), TestCertificateAndData(missing_model_sn->SerializeAsString(), "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "model-certificate-missing-system-id")), TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0, Status(error_space, INVALID_DRM_CERTIFICATE, "missing-signer-serial-number")), TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0, Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature")), }; for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) { TestBasicValidationDrmCertificate(kInvalidCertificate[i], false); } } TEST_F(ClientCertTest, MissingPreProvKey) { // system ID in token is 0x01234567 const std::string token(absl::HexStringToBytes( "00000002012345678e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98" "beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9" "2517a12f4922953e")); std::unique_ptr client_cert_ptr; Status status = ClientCert::Create( root_cert_.get(), ClientIdentification::KEYBOX, token, &client_cert_ptr); ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code()); } TEST_F(ClientCertTest, ValidProvisionerDeviceCert) { const uint32_t system_id = 5000; const std::string service_id("widevine_test.com"); const std::string device_serial_number("device-serial-number"); const std::string intermediate_serial_number("intermediate-serial-number"); const std::string provisioner_serial_number("provisioner-serial-number"); std::unique_ptr signed_provisioner_cert( GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, service_id)); std::unique_ptr signed_intermediate_cert( GenerateSignedIntermediateCertificate( signed_provisioner_cert.release(), system_id, intermediate_serial_number, kProvisionerSigner)); std::unique_ptr signed_device_cert( GenerateSignedDrmCertificate(signed_intermediate_cert.release(), system_id, device_serial_number)); std::string serialized_cert; signed_device_cert->SerializeToString(&serialized_cert); std::unique_ptr drm_cert; EXPECT_OK(ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, serialized_cert, &drm_cert)); ASSERT_TRUE(drm_cert); EXPECT_EQ(service_id, drm_cert->service_id()); EXPECT_EQ(device_serial_number, drm_cert->serial_number()); EXPECT_EQ(intermediate_serial_number, drm_cert->signer_serial_number()); EXPECT_EQ(system_id, drm_cert->system_id()); } TEST_F(ClientCertTest, InvalidProvisionerDeviceCertEmptyServiceId) { const uint32_t system_id = 4890; const std::string service_id(""); const std::string device_serial_number("device-serial-number"); const std::string intermediate_serial_number("intermediate-serial-number"); const std::string provisioner_serial_number("provisioner-serial-number"); std::unique_ptr signed_provisioner_cert( GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, service_id)); std::unique_ptr signed_intermediate_cert( GenerateSignedIntermediateCertificate( signed_provisioner_cert.release(), system_id, intermediate_serial_number, kProvisionerSigner)); std::unique_ptr signed_device_cert( GenerateSignedDrmCertificate(signed_intermediate_cert.release(), system_id, device_serial_number)); std::string serialized_cert; signed_device_cert->SerializeToString(&serialized_cert); std::unique_ptr client_cert_ptr; EXPECT_EQ("missing-provisioning-service-id", ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, serialized_cert, &client_cert_ptr) .error_message()); EXPECT_FALSE(client_cert_ptr); } TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) { const uint32_t system_id = 4890; const uint32_t system_id2 = 4892; const std::string service_id("widevine_test.com"); const std::string device_serial_number("device-serial-number"); const std::string intermediate_serial_number("intermediate-serial-number"); const std::string intermediate_serial_number2("intermediate-serial-number-2"); std::unique_ptr signed_intermediate_cert2( GenerateSignedIntermediateCertificate( nullptr, system_id2, intermediate_serial_number2, kNoSigner)); // Instead of using a provisioner certificate to sign this intermediate // certificate, use another intermediate certificate. This is an invalid // chain and should generate an error when trying to create a client // certificate. std::unique_ptr signed_intermediate_cert( GenerateSignedIntermediateCertificate( signed_intermediate_cert2.release(), system_id, intermediate_serial_number, kDeviceModelSigner)); std::unique_ptr signed_device_cert( GenerateSignedDrmCertificate(signed_intermediate_cert.release(), system_id, device_serial_number)); std::string serialized_cert; signed_device_cert->SerializeToString(&serialized_cert); std::unique_ptr client_cert_ptr; ASSERT_EQ("expected-provisioning-provider-certificate-type", ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, serialized_cert, &client_cert_ptr) .error_message()); EXPECT_FALSE(client_cert_ptr); } TEST_F(ClientCertTest, InvalidDeviceCertChainSize_TooLong) { const uint32_t system_id = 5000; const std::string service_id("widevine_test.com"); const std::string device_serial_number("device-serial-number"); const std::string intermediate_serial_number1("intermediate-serial-number-1"); const std::string intermediate_serial_number2("intermediate-serial-number-2"); const std::string provisioner_serial_number("provisioner-serial-number"); std::unique_ptr signed_provisioner_cert( GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, service_id)); std::unique_ptr signed_intermediate_cert1( GenerateSignedIntermediateCertificate( signed_provisioner_cert.release(), system_id, intermediate_serial_number1, kProvisionerSigner)); std::unique_ptr signed_intermediate_cert2( GenerateSignedIntermediateCertificate( signed_intermediate_cert1.release(), system_id, intermediate_serial_number2, kDeviceModelSigner)); std::unique_ptr signed_device_cert( GenerateSignedDrmCertificate(signed_intermediate_cert2.release(), system_id, device_serial_number)); std::string serialized_cert; signed_device_cert->SerializeToString(&serialized_cert); std::unique_ptr client_cert_ptr = nullptr; ASSERT_EQ("certificate-chain-size-exceeded", ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, serialized_cert, &client_cert_ptr) .error_message()); EXPECT_FALSE(client_cert_ptr); } TEST_F(ClientCertTest, DeviceCertTypeNotLeaf) { const uint32_t system_id = 5000; const std::string service_id("widevine_test.com"); const std::string intermediate_serial_number("intermediate-serial-number"); const std::string provisioner_serial_number("provisioner-serial-number"); const std::string drm_serial_number("drm-serial-number"); std::unique_ptr signed_provisioner_cert( GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, service_id)); // Use a DEVICE certificate as the intermediate certificate. std::unique_ptr signed_intermediate_cert( GenerateSignedDrmCertificate(signed_provisioner_cert.release(), system_id, intermediate_serial_number)); std::unique_ptr signed_drm_cert( GenerateSignedDrmCertificate(signed_intermediate_cert.release(), system_id, drm_serial_number)); std::string serialized_cert; signed_drm_cert->SerializeToString(&serialized_cert); std::unique_ptr client_cert_ptr; EXPECT_EQ("device-cert-must-be-leaf", ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, serialized_cert, &client_cert_ptr) .error_message()); EXPECT_FALSE(client_cert_ptr); } TEST_F(ClientCertTest, InvalidLeafCertificateType) { const uint32_t system_id = 5000; const std::string service_id("widevine_test.com"); const std::string intermediate_serial_number("intermediate-serial-number"); const std::string provisioner_serial_number("provisioner-serial-number"); std::unique_ptr signed_provisioner_cert( GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number, service_id)); std::unique_ptr signed_intermediate_cert( GenerateSignedIntermediateCertificate( signed_provisioner_cert.release(), system_id, intermediate_serial_number, kProvisionerSigner)); std::string serialized_cert; signed_intermediate_cert->SerializeToString(&serialized_cert); std::unique_ptr client_cert_ptr; // Leaf certificate must be a device certificate. EXPECT_EQ("expected-device-certificate-type", ClientCert::Create(root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, serialized_cert, &client_cert_ptr) .error_message()); EXPECT_FALSE(client_cert_ptr); } TEST_F(ClientCertTest, Protocol21WithDrmCert) { const char message[] = "A weekend wasted is a weekend well spent."; std::unique_ptr client_cert; ASSERT_OK(ClientCert::Create( root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, test_drm_certs_.test_user_device_certificate(), &client_cert)); std::unique_ptr private_key( RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits())); ASSERT_TRUE(private_key); // Success std::string signature; ASSERT_TRUE(private_key->GenerateSignature(message, &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)); std::unique_ptr client_cert; ASSERT_OK(ClientCert::Create( root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE, test_drm_certs_.test_user_device_certificate(), &client_cert)); std::unique_ptr private_key( RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits())); ASSERT_TRUE(private_key); // Success std::string signature; ASSERT_TRUE(private_key->GenerateSignature(message_hash, &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