Files
media_cas_proxy_sdk_source/common/drm_service_certificate_test.cc
2018-12-11 10:51:52 -08:00

369 lines
16 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// 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 <memory>
#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_service_certificate.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
#include "common/test_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())) {
CHECK(root_private_key_ != nullptr);
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;
}
util::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 util::Status(util::error::INTERNAL, "");
}
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
test_keys_.public_test_key_1_3072_bits(), signed_cert,
encrypted_private_key, kPassphrase);
}
util::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 util::Status(util::error::INTERNAL, "");
}
return DrmServiceCertificate::AddDrmServiceCertificate(
test_keys_.public_test_key_1_3072_bits(), 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<RsaPublicKey> 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_;
TestCertificates test_certs_;
std::string privacy_key_;
std::string iv_;
std::unique_ptr<RsaPrivateKey> root_private_key_;
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(util::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 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(util::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_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_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_number2, 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_number2, 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(util::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(util::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(util::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(util::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