//////////////////////////////////////////////////////////////////////////////// // Copyright 2013 Google LLC. // // This software is licensed under the terms defined in the Widevine Master // License Agreement. For a copy of this agreement, please contact // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// #include "common/drm_service_certificate.h" #include #include "glog/logging.h" #include "google/protobuf/util/message_differencer.h" #include "testing/gmock.h" #include "testing/gunit.h" #include "absl/strings/escaping.h" #include "common/aes_cbc_util.h" #include "common/drm_root_certificate.h" #include "common/rsa_key.h" #include "common/rsa_test_keys.h" #include "common/rsa_util.h" #include "common/test_drm_certificates.h" #include "protos/public/client_identification.pb.h" #include "protos/public/drm_certificate.pb.h" #include "protos/public/errors.pb.h" // IWYU pragma: keep #include "protos/public/license_server_sdk.pb.h" #include "protos/public/signed_drm_certificate.pb.h" namespace widevine { const char kPrivacyKey[] = "f7538b38acc78ec68c732ac665c55c65"; const char kIv[] = "09e9cda133ff5140bd2793173a04b5a3"; const char kPassphrase[] = "passphrase"; class DrmServiceCertificateTest : public ::testing::Test { public: DrmServiceCertificateTest() : privacy_key_(absl::HexStringToBytes(kPrivacyKey)), iv_(absl::HexStringToBytes(kIv)), root_private_key_( RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())) { EXPECT_TRUE(root_private_key_); EXPECT_OK( DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_)); client_id_.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE); client_id_.set_token(test_certs_.test_user_device_certificate()); } void SetUp() override { DrmServiceCertificate::ResetServiceCertificates(); } protected: std::string GenerateDrmServiceCertificate(const std::string& serial_number, const std::string& provider_id, uint32_t creation_time_seconds, const std::string& public_key) { DrmCertificate cert; cert.set_type(DrmCertificate::SERVICE); cert.set_serial_number(serial_number); cert.set_provider_id(provider_id); cert.set_public_key(public_key); cert.set_creation_time_seconds(creation_time_seconds); SignedDrmCertificate signed_cert; cert.SerializeToString(signed_cert.mutable_drm_certificate()); root_private_key_->GenerateSignature(signed_cert.drm_certificate(), signed_cert.mutable_signature()); std::string serialized_cert; signed_cert.SerializeToString(&serialized_cert); return serialized_cert; } Status SetDefaultDrmServiceCertificate(const std::string& serial_number, const std::string& provider_id, uint32_t creation_time_seconds) { std::string signed_cert(GenerateDrmServiceCertificate( serial_number, provider_id, creation_time_seconds, test_keys_.public_test_key_2_2048_bits())); std::string encrypted_private_key; if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( test_keys_.private_test_key_2_2048_bits(), kPassphrase, &encrypted_private_key)) { return Status(error::INTERNAL, ""); } return DrmServiceCertificate::SetDefaultDrmServiceCertificate( root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase); } Status AddDrmServiceCertificate(const std::string& serial_number, const std::string& provider_id, uint32_t creation_time_seconds) { std::string signed_cert(GenerateDrmServiceCertificate( serial_number, provider_id, creation_time_seconds, test_keys_.public_test_key_2_2048_bits())); std::string encrypted_private_key; if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo( test_keys_.private_test_key_2_2048_bits(), kPassphrase, &encrypted_private_key)) { return Status(error::INTERNAL, ""); } return DrmServiceCertificate::AddDrmServiceCertificate( root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase); } void EncryptClientIdentification( const std::string& serial_number, const std::string& provider_id, const std::string& public_key, EncryptedClientIdentification* encrypted_client_id) { CHECK(encrypted_client_id); encrypted_client_id->set_provider_id(provider_id); encrypted_client_id->set_service_certificate_serial_number(serial_number); std::string serial_client_id; client_id_.SerializeToString(&serial_client_id); encrypted_client_id->set_encrypted_client_id( crypto_util::EncryptAesCbc(privacy_key_, iv_, serial_client_id)); encrypted_client_id->set_encrypted_client_id_iv(iv_); std::unique_ptr rsa_key(RsaPublicKey::Create(public_key)); ASSERT_TRUE(rsa_key.get()); rsa_key->Encrypt(privacy_key_, encrypted_client_id->mutable_encrypted_privacy_key()); } RsaTestKeys test_keys_; TestDrmCertificates test_certs_; std::string privacy_key_; std::string iv_; std::unique_ptr root_private_key_; std::unique_ptr root_cert_; ClientIdentification client_id_; }; TEST_F(DrmServiceCertificateTest, BasicClientIdDecrypt) { std::string serial_number("serial_number"); std::string provider_id("someservice.com"); uint32_t creation_time_seconds(1234); EXPECT_OK(AddDrmServiceCertificate(serial_number, provider_id, creation_time_seconds)); EncryptedClientIdentification encrypted_client_id; EncryptClientIdentification(serial_number, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); } TEST_F(DrmServiceCertificateTest, NoDefaultDrmServiceCertificate) { ASSERT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate()); const auto& get_default_sc_or_die = []() { DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie(); }; EXPECT_DEATH(get_default_sc_or_die(), "Service Certificate not set!"); } TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificates) { std::string serial_number1("serial_number1"); std::string provider_id1("someservice.com"); uint32_t creation_time_seconds1(1234); std::string serial_number2("serial_number2"); uint32_t creation_time_seconds2(1234); std::string bogus_serial_number("bogus-serial-number2"); EXPECT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate()); EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id1, creation_time_seconds1)); // Expect this to pass because the serial number is allowed to change as long // as the service Id is the same as before. EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id1, creation_time_seconds2)); EncryptedClientIdentification encrypted_client_id; EncryptClientIdentification(serial_number1, provider_id1, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; EXPECT_OK(DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); EncryptClientIdentification(serial_number2, provider_id1, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); EXPECT_OK(DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); EncryptClientIdentification(bogus_serial_number, provider_id1, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); EXPECT_EQ(SERVICE_CERTIFICATE_NOT_FOUND, DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id) .error_code()); } TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) { std::string serial_number1("serial_number1"); std::string serial_number2("serial_number2"); std::string serial_number3("serial_number3"); std::string serial_number4("serial_number4"); std::string provider_id("someservice.com"); uint32_t creation_time_seconds(1234); EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id, creation_time_seconds)); EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id, creation_time_seconds + 1)); EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id, creation_time_seconds - 1)); EncryptedClientIdentification encrypted_client_id; EncryptClientIdentification(serial_number1, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); EncryptClientIdentification(serial_number2, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); EncryptClientIdentification(serial_number3, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); const DrmServiceCertificate* default_cert( DrmServiceCertificate::GetDefaultDrmServiceCertificate()); ASSERT_TRUE(default_cert); SignedDrmCertificate signed_cert; ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate())); DrmCertificate drm_cert; ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate())); EXPECT_EQ(serial_number1, drm_cert.serial_number()); EXPECT_OK(SetDefaultDrmServiceCertificate(serial_number4, provider_id, creation_time_seconds)); default_cert = DrmServiceCertificate::GetDefaultDrmServiceCertificate(); ASSERT_TRUE(default_cert); ASSERT_TRUE(signed_cert.ParseFromString(default_cert->certificate())); ASSERT_TRUE(drm_cert.ParseFromString(signed_cert.drm_certificate())); EXPECT_EQ(serial_number4, drm_cert.serial_number()); } TEST_F(DrmServiceCertificateTest, DrmServiceCertificateNotFound) { std::string serial_number("serial_number"); std::string provider_id("someservice.com"); uint32_t creation_time_seconds(1234); EXPECT_OK(AddDrmServiceCertificate(serial_number, provider_id, creation_time_seconds)); EncryptedClientIdentification encrypted_client_id; EncryptClientIdentification("invalid_serial_number", provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; EXPECT_EQ(SERVICE_CERTIFICATE_NOT_FOUND, DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id) .error_code()); } TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) { std::string serial_number("serial_number"); std::string provider_id("someservice.com"); uint32_t creation_time_seconds(1234); ASSERT_OK(AddDrmServiceCertificate(serial_number, provider_id, creation_time_seconds)); EncryptedClientIdentification encrypted_client_id; EncryptClientIdentification(serial_number, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); EncryptedClientIdentification invalid; invalid = encrypted_client_id; invalid.clear_encrypted_privacy_key(); EXPECT_EQ( "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " "missing-encrypted-privacy-key", DrmServiceCertificate::DecryptClientIdentification(invalid, &decrypted_client_id) .ToString()); invalid = encrypted_client_id; ++(*invalid.mutable_encrypted_client_id_iv())[4]; EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( invalid, &decrypted_client_id)); invalid.clear_encrypted_client_id_iv(); EXPECT_EQ( "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " "missing-encrypted-client-id-iv", DrmServiceCertificate::DecryptClientIdentification(invalid, &decrypted_client_id) .ToString()); invalid = encrypted_client_id; ++(*invalid.mutable_encrypted_client_id())[0]; EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( invalid, &decrypted_client_id)); invalid.clear_encrypted_client_id(); EXPECT_EQ( "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " "missing-encrypted-client-id", DrmServiceCertificate::DecryptClientIdentification(invalid, &decrypted_client_id) .ToString()); } TEST_F(DrmServiceCertificateTest, PrivateKeyDecryptError) { std::string serial_number("serial_number"); std::string provider_id("someservice.com"); uint32_t creation_time_seconds(1234); ASSERT_OK(AddDrmServiceCertificate(serial_number, provider_id, creation_time_seconds)); EncryptedClientIdentification encrypted_client_id; EncryptClientIdentification(serial_number, provider_id, test_keys_.public_test_key_2_2048_bits(), &encrypted_client_id); ClientIdentification decrypted_client_id; ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification( encrypted_client_id, &decrypted_client_id)); ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_, decrypted_client_id)); EncryptedClientIdentification corrupted; corrupted = encrypted_client_id; ++(*corrupted.mutable_encrypted_privacy_key())[20]; EXPECT_EQ( "Errors::INVALID_ENCRYPTED_CLIENT_IDENTIFICATION: " "privacy-key-decryption-failed", DrmServiceCertificate::DecryptClientIdentification(corrupted, &decrypted_client_id) .ToString()); } // TODO(user): Add more unit tests for various fail cases (bad keys having // to do with bad keys and bad certs). } // namespace widevine