Files
media_cas_packager_sdk_source/common/client_cert_test.cc
2020-07-24 18:17:12 -07:00

868 lines
38 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// 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 <memory>
#include <tuple>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/ec_key.h"
#include "common/ec_test_keys.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/hash_algorithm_util.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;
const HashAlgorithm kSha256 = HashAlgorithm::kSha256;
// 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<
std::tuple<DrmCertificate::Algorithm, DrmCertificate::Algorithm>> {
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 encryption_certificate_;
const std::string expected_serial_number_;
uint32_t expected_system_id_;
Status expected_status_;
SignedMessage::SessionKeyType expected_key_type_;
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),
expected_key_type_(SignedMessage::WRAPPED_AES_KEY) {}
TestCertificateAndData(const std::string& certificate,
const std::string& encryption_certificate,
const std::string& expected_serial_number,
uint32_t expected_system_id, Status expected_status,
SignedMessage::SessionKeyType expected_key_type)
: certificate_(certificate),
encryption_certificate_(encryption_certificate),
expected_serial_number_(expected_serial_number),
expected_system_id_(expected_system_id),
expected_status_(expected_status),
expected_key_type_(expected_key_type) {}
};
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,
HashAlgorithm hash_algorithm, std::string* signature);
std::unique_ptr<SignedDrmCertificate> SignCertificate(
const DrmCertificate& certificate, const SignedDrmCertificate* signer,
const std::string& private_key);
std::unique_ptr<DrmCertificate> GenerateProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& provider_id);
std::unique_ptr<SignedDrmCertificate> GenerateSignedProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& service_id);
std::unique_ptr<DrmCertificate> GenerateIntermediateCertificate(
uint32_t system_id, const std::string& serial_number);
std::unique_ptr<SignedDrmCertificate> GenerateSignedIntermediateCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number, DrmCertificate::Type signer_cert_type);
std::unique_ptr<DrmCertificate> GenerateDrmCertificate(
uint32_t system_id, const std::string& serial_number,
DrmCertificate::Algorithm = DrmCertificate::RSA);
std::unique_ptr<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 GetECCPrivateKey(DrmCertificate::Algorithm algorithm);
std::string GetECCPublicKey(DrmCertificate::Algorithm algorithm);
RsaTestKeys test_rsa_keys_;
TestDrmCertificates test_drm_certs_;
std::unique_ptr<DrmRootCertificate> 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<ClientCert> keybox_cert;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::KEYBOX);
client_id.set_token(expectation.token_);
status = ClientCert::Create(root_cert_.get(), client_id, &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<ClientCert> drm_certificate_cert;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(expectation.certificate_);
if (!expectation.encryption_certificate_.empty()) {
client_id.mutable_device_credentials()->set_token(
expectation.encryption_certificate_);
client_id.mutable_device_credentials()->set_type(
ClientIdentification::DRM_DEVICE_CERTIFICATE);
}
status =
ClientCert::Create(root_cert_.get(), client_id, &drm_certificate_cert);
ASSERT_EQ(expectation.expected_status_, status);
if (expectation.expected_status_.ok()) {
ASSERT_TRUE(drm_certificate_cert.get());
if (!expectation.encryption_certificate_.empty()) {
ASSERT_TRUE(drm_certificate_cert->using_dual_certificate());
}
ASSERT_EQ(expectation.expected_key_type_, drm_certificate_cert->key_type());
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,
HashAlgorithm hash_algorithm,
std::string* signature) {
std::unique_ptr<RsaPrivateKey> rsa_private_key(
RsaPrivateKey::Create(private_key));
ASSERT_TRUE(rsa_private_key != nullptr);
rsa_private_key->GenerateSignature(message, hash_algorithm, signature);
}
// The caller retains ownership of |signer|, which may also be nullptr.
std::unique_ptr<SignedDrmCertificate> ClientCertTest::SignCertificate(
const DrmCertificate& certificate, const SignedDrmCertificate* signer,
const std::string& private_key) {
std::unique_ptr<SignedDrmCertificate> signed_certificate(
new SignedDrmCertificate);
signed_certificate->set_drm_certificate(certificate.SerializeAsString());
GenerateSignature(
signed_certificate->drm_certificate(), private_key,
HashAlgorithmProtoToEnum(signed_certificate->hash_algorithm()),
signed_certificate->mutable_signature());
if (signer != nullptr) {
*(signed_certificate->mutable_signer()) = *signer;
}
return signed_certificate;
}
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::GetECCPrivateKey(
DrmCertificate::Algorithm algorithm) {
ECTestKeys keys;
switch (algorithm) {
case DrmCertificate::ECC_SECP256R1:
return keys.private_test_key_1_secp256r1();
case DrmCertificate::ECC_SECP384R1:
return keys.private_test_key_1_secp384r1();
case DrmCertificate::ECC_SECP521R1:
return keys.private_test_key_1_secp521r1();
default:
return "";
}
}
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 "";
}
}
std::unique_ptr<DrmCertificate> ClientCertTest::GenerateIntermediateCertificate(
uint32_t system_id, const std::string& serial_number) {
std::unique_ptr<DrmCertificate> 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;
}
std::unique_ptr<SignedDrmCertificate>
ClientCertTest::GenerateSignedIntermediateCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number, DrmCertificate::Type signer_cert_type) {
std::unique_ptr<DrmCertificate> 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));
}
std::unique_ptr<DrmCertificate> ClientCertTest::GenerateDrmCertificate(
uint32_t system_id, const std::string& serial_number,
DrmCertificate::Algorithm algorithm) {
std::unique_ptr<DrmCertificate> 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;
}
std::unique_ptr<SignedDrmCertificate>
ClientCertTest::GenerateSignedDrmCertificate(
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number, DrmCertificate::Algorithm algorithm) {
std::unique_ptr<DrmCertificate> drm_certificate(
GenerateDrmCertificate(system_id, serial_number, algorithm));
std::unique_ptr<SignedDrmCertificate> signed_drm_certificate(
SignCertificate(*drm_certificate, signer,
GetPrivateKeyByCertType(DrmCertificate::DEVICE_MODEL)));
return signed_drm_certificate;
}
std::unique_ptr<DrmCertificate> ClientCertTest::GenerateProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& provider_id) {
std::unique_ptr<DrmCertificate> 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;
}
std::unique_ptr<SignedDrmCertificate>
ClientCertTest::GenerateSignedProvisionerCertificate(
uint32_t system_id, const std::string& serial_number,
const std::string& service_id) {
std::unique_ptr<DrmCertificate> 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<SignedDrmCertificate> intermediate_certificate =
GenerateSignedIntermediateCertificate(nullptr, system_id, serial_number,
kNoSigner);
std::unique_ptr<SignedDrmCertificate> signed_cert =
GenerateSignedDrmCertificate(intermediate_certificate.get(), system_id,
serial_number + "-device1",
std::get<0>(GetParam()));
SignedMessage::SessionKeyType expected_key_type =
std::get<0>(GetParam()) != DrmCertificate::RSA
? SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY
: SignedMessage::WRAPPED_AES_KEY;
std::unique_ptr<SignedDrmCertificate> encryption_certificate;
if (std::get<1>(GetParam()) != DrmCertificate::UNKNOWN_ALGORITHM) {
encryption_certificate = GenerateSignedDrmCertificate(
intermediate_certificate.get(), system_id, serial_number + "-device2",
std::get<1>(GetParam()));
expected_key_type = std::get<1>(GetParam()) != DrmCertificate::RSA
? SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY
: SignedMessage::WRAPPED_AES_KEY;
}
const TestCertificateAndData kValidCertificateAndExpectedData(
signed_cert->SerializeAsString(),
encryption_certificate == nullptr
? std::string()
: encryption_certificate->SerializeAsString(),
serial_number, system_id, OkStatus(), expected_key_type);
const bool compare_data = true;
TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData,
compare_data);
}
INSTANTIATE_TEST_SUITE_P(
BasicCertValidation, ClientCertTest,
testing::Combine(testing::Values(DrmCertificate::RSA,
DrmCertificate::ECC_SECP256R1,
DrmCertificate::ECC_SECP384R1,
DrmCertificate::ECC_SECP521R1),
testing::Values(DrmCertificate::UNKNOWN_ALGORITHM,
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<DrmCertificate> dev_cert;
std::unique_ptr<DrmCertificate> signer_cert;
std::unique_ptr<SignedDrmCertificate> signed_signer;
// Invalid serialized device certificate.
std::unique_ptr<SignedDrmCertificate> 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(),
HashAlgorithmProtoToEnum(invalid_drm_cert->hash_algorithm()),
invalid_drm_cert->mutable_signature());
invalid_drm_cert->set_allocated_signer(
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn,
kNoSigner)
.release());
// Invalid device public key.
dev_cert = GenerateDrmCertificate(system_id, device_sn);
dev_cert->set_public_key("bad-device-public-key");
std::unique_ptr<SignedDrmCertificate> bad_device_public_key =
SignCertificate(*dev_cert,
GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner)
.get(),
test_rsa_keys_.private_test_key_2_2048_bits());
// Invalid serialized intermediate certificate.
signed_signer = 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(),
HashAlgorithmProtoToEnum(signed_signer->hash_algorithm()),
signed_signer->mutable_signature());
dev_cert = GenerateDrmCertificate(system_id, device_sn);
std::unique_ptr<SignedDrmCertificate> invalid_signer(
SignCertificate(*dev_cert, signed_signer.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid signer public key.
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signer_cert = GenerateIntermediateCertificate(system_id, signer_sn);
signer_cert->set_public_key("bad-signer-public-key");
std::unique_ptr<SignedDrmCertificate> bad_signer_public_key(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_rsa_keys_.private_test_key_1_3072_bits())
.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid device certificate signature.
std::unique_ptr<SignedDrmCertificate> bad_device_signature(
GenerateSignedDrmCertificate(GenerateSignedIntermediateCertificate(
nullptr, system_id, signer_sn, kNoSigner)
.get(),
system_id, device_sn));
bad_device_signature->set_signature("bad-signature");
// Missing model system ID.
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signer_cert = GenerateIntermediateCertificate(system_id, signer_sn);
signer_cert->clear_system_id();
std::unique_ptr<SignedDrmCertificate> missing_model_sn(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_rsa_keys_.private_test_key_1_3072_bits())
.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Missing signer serial number.
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signer_cert = GenerateIntermediateCertificate(system_id, signer_sn);
signer_cert->clear_serial_number();
std::unique_ptr<SignedDrmCertificate> missing_signer_sn(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_rsa_keys_.private_test_key_1_3072_bits())
.get(),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid serialized intermediate certificate.
dev_cert = GenerateDrmCertificate(system_id, device_sn);
signed_signer = GenerateSignedIntermediateCertificate(nullptr, system_id,
signer_sn, kNoSigner);
signed_signer->set_signature("bad-signature");
std::unique_ptr<SignedDrmCertificate> bad_signer_signature(
SignCertificate(*dev_cert, signed_signer.get(),
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<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::KEYBOX);
client_id.set_token(token);
Status status =
ClientCert::Create(root_cert_.get(), client_id, &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<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.get(), system_id, intermediate_serial_number,
kProvisionerSigner);
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> drm_cert;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
EXPECT_OK(ClientCert::Create(root_cert_.get(), client_id, &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<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert(
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.get(), system_id, intermediate_serial_number,
kProvisionerSigner));
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
EXPECT_EQ("missing-provisioning-service-id",
ClientCert::Create(root_cert_.get(), client_id, &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<SignedDrmCertificate> 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<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedIntermediateCertificate(
signed_intermediate_cert2.get(), system_id,
intermediate_serial_number, kDeviceModelSigner);
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
ASSERT_EQ("expected-provisioning-provider-certificate-type",
ClientCert::Create(root_cert_.get(), client_id, &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<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert1 =
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.get(), system_id, intermediate_serial_number1,
kProvisionerSigner);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert2 =
GenerateSignedIntermediateCertificate(
signed_intermediate_cert1.get(), system_id,
intermediate_serial_number2, kDeviceModelSigner);
std::unique_ptr<SignedDrmCertificate> signed_device_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert2.get(), system_id,
device_serial_number);
std::string serialized_cert;
signed_device_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr = nullptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
ASSERT_EQ("certificate-chain-size-exceeded",
ClientCert::Create(root_cert_.get(), client_id, &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<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id);
// Use a DEVICE certificate as the intermediate certificate.
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedDrmCertificate(signed_provisioner_cert.get(), system_id,
intermediate_serial_number);
std::unique_ptr<SignedDrmCertificate> signed_drm_cert =
GenerateSignedDrmCertificate(signed_intermediate_cert.get(), system_id,
drm_serial_number);
std::string serialized_cert;
signed_drm_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
EXPECT_EQ("device-cert-must-be-leaf",
ClientCert::Create(root_cert_.get(), client_id, &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<SignedDrmCertificate> signed_provisioner_cert =
GenerateSignedProvisionerCertificate(system_id, provisioner_serial_number,
service_id);
std::unique_ptr<SignedDrmCertificate> signed_intermediate_cert =
GenerateSignedIntermediateCertificate(
signed_provisioner_cert.get(), system_id, intermediate_serial_number,
kProvisionerSigner);
std::string serialized_cert;
signed_intermediate_cert->SerializeToString(&serialized_cert);
std::unique_ptr<ClientCert> client_cert_ptr;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(serialized_cert);
// Leaf certificate must be a device certificate.
EXPECT_EQ("expected-device-certificate-type",
ClientCert::Create(root_cert_.get(), client_id, &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<ClientCert> client_cert;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(test_drm_certs_.test_user_device_certificate());
ASSERT_OK(ClientCert::Create(root_cert_.get(), client_id, &client_cert));
std::unique_ptr<RsaPrivateKey> 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, kSha256, &signature));
EXPECT_OK(
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_1));
// Failure
ASSERT_EQ(256, signature.size());
++signature[127];
EXPECT_FALSE(
client_cert->VerifySignature(message, kSha256, 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<ClientCert> client_cert;
ClientIdentification client_id;
client_id.set_type(ClientIdentification::DRM_DEVICE_CERTIFICATE);
client_id.set_token(test_drm_certs_.test_user_device_certificate());
ASSERT_OK(ClientCert::Create(root_cert_.get(), client_id, &client_cert));
std::unique_ptr<RsaPrivateKey> 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, kSha256, &signature));
EXPECT_OK(
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_2));
// Failure
ASSERT_EQ(256, signature.size());
++signature[127];
EXPECT_FALSE(
client_cert->VerifySignature(message, kSha256, signature, VERSION_2_2)
.ok());
}
} // namespace widevine