Add EMMG to carry fingerprinting and service blocking info

This commit is contained in:
Lu Chen
2020-09-15 09:16:59 -07:00
parent 3d8f585313
commit 1ce468e5ba
143 changed files with 2316 additions and 17450 deletions

View File

@@ -113,6 +113,7 @@ cc_test(
"//testing:gunit_main",
"@abseil_repo//absl/memory",
"//protos/public:device_common_cc_proto",
"//protos/public:device_security_profile_data_cc_proto",
"//protos/public:security_profile_cc_proto",
],
)
@@ -429,6 +430,7 @@ cc_test(
timeout = "short",
srcs = ["rsa_key_test.cc"],
deps = [
":hash_algorithm",
":rsa_key",
":rsa_test_keys",
":rsa_util",
@@ -515,6 +517,7 @@ cc_test(
":ec_key",
":ec_test_keys",
":ec_util",
":hash_algorithm",
":random_util",
"//testing:gunit",
"//testing:gunit_main",
@@ -887,6 +890,7 @@ cc_library(
"//protos/public:client_identification_cc_proto",
"//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_cc_proto",
"//protos/public:external_license_cc_proto",
"//protos/public:signed_drm_certificate_cc_proto",
],
)
@@ -911,6 +915,7 @@ cc_test(
"//protos/public:client_identification_cc_proto",
"//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_cc_proto",
"//protos/public:external_license_cc_proto",
"//protos/public:license_server_sdk_cc_proto",
"//protos/public:signed_drm_certificate_cc_proto",
],
@@ -1130,10 +1135,22 @@ cc_library(
hdrs = ["core_message_util.h"],
deps = [
":sha_util",
"//base",
"@abseil_repo//absl/strings",
"//common/oemcrypto_core_message/odk:kdo",
],
)
cc_test(
name = "core_message_util_test",
srcs = ["core_message_util_test.cc"],
deps = [
":core_message_util",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "hash_algorithm",
hdrs = ["hash_algorithm.h"],

View File

@@ -1,166 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/aes_cbc_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
namespace {
const uint8_t kKey[] = {
0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e,
0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b,
};
const uint8_t kIv[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
};
} // namespace
namespace widevine {
namespace crypto_util {
TEST(CryptoUtilTest, EncryptAndDecryptAesCbc) {
std::string plain_text("Foo");
std::string ciphertext =
EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), plain_text);
std::string expected_ciphertext(
"\xCF\x1A\x3\x1C\x9C\x8C\xB9Z\xEC\xC0\x17\xDCRxX\xD7");
ASSERT_EQ(0, ciphertext.size() % 16);
ASSERT_GT(ciphertext.size(), plain_text.size());
ASSERT_EQ(expected_ciphertext, ciphertext);
std::string decrypted =
DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ciphertext);
ASSERT_EQ(plain_text, decrypted);
}
TEST(CryptoUtilTest, DecryptAesCbcNoPad) {
const uint8_t kKey[] = {
0xdd, 0x71, 0x39, 0xea, 0xfa, 0xce, 0xed, 0x7c,
0xda, 0x9f, 0x25, 0xda, 0x8a, 0xa9, 0x15, 0xea,
};
const uint8_t kIv[] = {
0x5d, 0x16, 0x44, 0xea, 0xec, 0x11, 0xf9, 0x83,
0x14, 0x75, 0x41, 0xe4, 0x6e, 0xeb, 0x27, 0x74,
};
const uint8_t kCiphertext[] = {
0x6d, 0xa6, 0xda, 0xe4, 0xee, 0x40, 0x09, 0x17,
0x54, 0x7b, 0xba, 0xa5, 0x27, 0xb8, 0x82, 0x1b,
};
const uint8_t kExpectedPlaintext[] = {
0xb3, 0x49, 0xd4, 0x80, 0x9e, 0x91, 0x06, 0x87,
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10,
};
const uint8_t kExpectedPlaintextEmptyIv[] = {
0xee, 0x5f, 0x90, 0x6a, 0x72, 0x80, 0xff, 0x04,
0x14, 0x75, 0x41, 0xa4, 0x6e, 0xeb, 0x27, 0x64,
};
std::string decrypted = DecryptAesCbcNoPad(
std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)),
std::string(kCiphertext, kCiphertext + sizeof(kCiphertext)));
ASSERT_EQ(std::string(kExpectedPlaintext,
kExpectedPlaintext + sizeof(kExpectedPlaintext)),
decrypted);
std::string dummy_iv;
decrypted = DecryptAesCbcNoPad(
std::string(kKey, kKey + sizeof(kKey)), dummy_iv,
std::string(kCiphertext, kCiphertext + sizeof(kCiphertext)));
ASSERT_EQ(std::string(
kExpectedPlaintextEmptyIv,
kExpectedPlaintextEmptyIv + sizeof(kExpectedPlaintextEmptyIv)),
decrypted);
}
TEST(CryptoUtilTest, TestFailedEncrypt) {
// Test with bogus initialization vector.
std::string plain_text("Foo");
std::string bogus_iv("bogus");
std::string ciphertext = EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
bogus_iv, plain_text);
ASSERT_EQ(ciphertext.size(), 0);
// Test with bogus key.
std::string bogus_key("bogus");
ciphertext =
EncryptAesCbc(bogus_key, std::string(kIv, kIv + sizeof(kIv)), plain_text);
ASSERT_EQ(ciphertext.size(), 0);
}
TEST(CryptoUtilTest, TestFailedEncryptNoPad) {
std::string plaintext("0123456789abcdef");
std::string key(kKey, kKey + sizeof(kKey));
std::string iv(kIv, kIv + sizeof(kIv));
// Control.
std::string ciphertext = EncryptAesCbcNoPad(key, iv, plaintext);
ASSERT_EQ(plaintext.size(), ciphertext.size());
// Bogus key.
std::string bogus_key("bogus");
ciphertext = EncryptAesCbcNoPad(bogus_key, iv, plaintext);
EXPECT_EQ(ciphertext.size(), 0);
// Bogus IV.
std::string bogus_iv("bogus");
ciphertext = EncryptAesCbcNoPad(key, bogus_iv, plaintext);
EXPECT_EQ(ciphertext.size(), 0);
// Incorrectly-sized plaintext.
std::string bad_plaintext("Foo");
ciphertext = EncryptAesCbcNoPad(key, iv, bad_plaintext);
EXPECT_EQ(ciphertext.size(), 0);
}
TEST(CryptoUtilTest, TestFailedDecrypt) {
// First, encrypt the data.
std::string plain_text("Foo");
std::string ciphertext =
EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), plain_text);
ASSERT_NE(ciphertext.size(), 0);
// Test Decrypt with bogus iv.
std::string bogus_iv("bogus");
plain_text = DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)), bogus_iv,
ciphertext);
ASSERT_EQ(plain_text.size(), 0);
// Test Decrypt with bogus key.
std::string bogus_key("bogus");
plain_text =
DecryptAesCbc(bogus_key, std::string(kIv, kIv + sizeof(kIv)), ciphertext);
ASSERT_EQ(plain_text.size(), 0);
}
TEST(CryptoUtilTest, TestEmptyEncrypt) {
EXPECT_EQ("\xDBx\xD9\x91\xE8\x1D\xD9\x19\x80r\x12\x89\xD7Kp\xEB",
EncryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ""));
}
TEST(CryptoUtilTest, TestEmptyDecryptAesCbc) {
EXPECT_EQ("", DecryptAesCbc(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ""));
}
TEST(CryptoUtilTest, TestEmptyDecryptAesCbcNoPad) {
EXPECT_EQ("", DecryptAesCbcNoPad(std::string(kKey, kKey + sizeof(kKey)),
std::string(kIv, kIv + sizeof(kIv)), ""));
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -1,280 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/certificate_client_cert.h"
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "common/crypto_util.h"
#include "common/ec_key.h"
#include "common/ec_util.h"
#include "common/error_space.h"
#include "common/openssl_util.h"
#include "common/random_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "common/signing_key_util.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/license_protocol.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
using EllipticCurve = ECPrivateKey::EllipticCurve;
ECPrivateKey::EllipticCurve CertificateAlgorithmToCurve(
DrmCertificate::Algorithm algorithm) {
switch (algorithm) {
case DrmCertificate::ECC_SECP256R1:
return ECPrivateKey::SECP256R1;
case DrmCertificate::ECC_SECP384R1:
return ECPrivateKey::SECP384R1;
case DrmCertificate::ECC_SECP521R1:
return ECPrivateKey::SECP521R1;
default:
return ECPrivateKey::UNDEFINED_CURVE;
}
}
class ClientCertAlgorithmRSA : public ClientCertAlgorithm {
public:
ClientCertAlgorithmRSA() {}
~ClientCertAlgorithmRSA() override {}
ClientCertAlgorithmRSA(const ClientCertAlgorithmRSA&) = delete;
ClientCertAlgorithmRSA& operator=(const ClientCertAlgorithmRSA&) = delete;
Status Initialize(const std::string& public_key,
DrmCertificate::Algorithm /*not_used*/) override {
rsa_public_key_ =
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key));
if (!rsa_public_key_) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-public-key-failed");
}
session_key_ = Random16Bytes();
if (!rsa_public_key_->Encrypt(session_key_, &wrapped_session_key_)) {
return Status(error_space, ENCRYPT_ERROR,
"drm-certificate-failed-encrypt-session-key");
}
return OkStatus();
}
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const override {
CHECK(rsa_public_key_);
if (!rsa_public_key_->VerifySignature(message, hash_algorithm, signature)) {
return Status(error_space, INVALID_SIGNATURE, "");
}
return OkStatus();
}
const std::string& session_key() const override { return session_key_; }
const std::string& wrapped_session_key() const override {
return wrapped_session_key_;
}
SignedMessage::SessionKeyType session_key_type() const override {
return SignedMessage::WRAPPED_AES_KEY;
}
private:
std::unique_ptr<RsaPublicKey> rsa_public_key_;
std::string session_key_;
std::string wrapped_session_key_;
};
// ClientCertAlgorithmECC implements the Widevine protocol using ECC. It
// verifies an ECC based request and generates keys for use in building a
// license. The curve type value is contained in |algorithm|.
class ClientCertAlgorithmECC : public ClientCertAlgorithm {
public:
ClientCertAlgorithmECC() = default;
~ClientCertAlgorithmECC() override = default;
ClientCertAlgorithmECC(const ClientCertAlgorithmECC&) = delete;
ClientCertAlgorithmECC& operator=(const ClientCertAlgorithmECC&) = delete;
Status Initialize(const std::string& public_key,
DrmCertificate::Algorithm algorithm) override {
ECPrivateKey::EllipticCurve curve_id =
CertificateAlgorithmToCurve(algorithm);
if (curve_id == ECPrivateKey::UNDEFINED_CURVE) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-unknown-curve");
}
// Parse the certifcate ECC public key.
client_ecc_public_key_ = ECPublicKey::Create(public_key);
if (client_ecc_public_key_ == nullptr) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-public-key-failed");
}
// Generate an ephemeral ecc key pair with the same curve as used by the
// certificate public key.
ScopedECKEY key = ec_util::GenerateKeyWithCurve(curve_id);
auto new_private_key = absl::make_unique<ECPrivateKey>(std::move(key));
if (new_private_key == nullptr) {
return Status(error_space, DRM_DEVICE_CERTIFICATE_ECC_KEYGEN_FAILED,
"drm-certificate-ephemeral-private-key-failed");
}
// Serialize the ephemeral public key for inclusion in a license response.
std::unique_ptr<ECPublicKey> new_public_key = new_private_key->PublicKey();
if (new_public_key == nullptr ||
!new_public_key->SerializedKey(&ephemeral_public_key_)) {
return Status(error_space, DRM_DEVICE_CERTIFICATE_ECC_KEYGEN_FAILED,
"drm-certificate-ephemeral-public-key-failed");
}
// Generate the session key from the ephemeral private key and the
// certificate public key.
if (!new_private_key->DeriveSharedSessionKey(*client_ecc_public_key_,
&derived_session_key_)) {
return Status(error_space, DRM_DEVICE_CERTIFICATE_ECC_KEYGEN_FAILED,
"drm-certificate-shared-key-gen-failed");
}
return OkStatus();
}
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const override {
CHECK(client_ecc_public_key_);
if (!client_ecc_public_key_->VerifySignature(message, hash_algorithm,
signature)) {
return Status(error_space, INVALID_SIGNATURE, "");
}
return OkStatus();
}
// Returns an aes key generated from the sha256 hash of the shared ecc secret.
// This key is used for key derivation.
const std::string& session_key() const override {
return derived_session_key_;
}
// Returns an ephemeral serialized ecc public key. This key is added to a
// license response in the SignedMessage::session_key field. The client will
// use this key to generate the shared secret and derived session key.
const std::string& wrapped_session_key() const override {
return ephemeral_public_key_;
}
SignedMessage::SessionKeyType session_key_type() const override {
return SignedMessage::EPHEMERAL_ECC_PUBLIC_KEY;
}
private:
std::unique_ptr<ECPublicKey> client_ecc_public_key_;
std::string ephemeral_public_key_;
std::string derived_session_key_;
};
Status CertificateClientCert::Initialize(
const DrmRootCertificate* root_certificate,
const std::string& serialized_certificate) {
CHECK(root_certificate);
if (is_initialized_) {
return Status(error_space, INVALID_PARAMETER,
"certificate-is-already-initialized");
}
SignedDrmCertificate signed_device_cert;
Status status = root_certificate->VerifyCertificate(
serialized_certificate, &signed_device_cert, &device_cert_);
if (!status.ok()) {
return status;
}
if (device_cert_.type() != DrmCertificate::DEVICE ||
device_cert_.public_key().empty()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"expected-device-certificate-type");
}
const SignedDrmCertificate& device_cert_signer = signed_device_cert.signer();
if (!model_certificate_.ParseFromString(
device_cert_signer.drm_certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-invalid-signer");
}
if (model_certificate_.type() != DrmCertificate::DEVICE_MODEL) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"expected-device-model-certificate-type");
}
if (!model_certificate_.has_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).
if (device_cert_signer.has_signer()) {
if (!provisioner_certificate_.ParseFromString(
device_cert_signer.signer().drm_certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-invalid-signer");
}
if (provisioner_certificate_.type() != DrmCertificate::PROVISIONER) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"expected-provisioning-provider-certificate-type");
}
if (!provisioner_certificate_.has_provider_id() ||
provisioner_certificate_.provider_id().empty()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-provisioning-service-id");
}
signed_by_provisioner_ = true;
}
if (!model_certificate_.has_system_id()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-missing-system-id");
}
switch (device_cert_.algorithm()) {
case DrmCertificate::RSA:
algorithm_ = absl::make_unique<ClientCertAlgorithmRSA>();
break;
case DrmCertificate::ECC_SECP256R1:
case DrmCertificate::ECC_SECP384R1:
case DrmCertificate::ECC_SECP521R1:
algorithm_ = absl::make_unique<ClientCertAlgorithmECC>();
break;
default:
return Status(error_space, INVALID_DRM_CERTIFICATE,
"unsupported-certificate-algorithm");
}
status = algorithm_->Initialize(device_cert_.public_key(),
device_cert_.algorithm());
if (!status.ok()) {
return status;
}
is_initialized_ = true;
return OkStatus();
}
Status CertificateClientCert::VerifySignature(
const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature, ProtocolVersion protocol_version) const {
return algorithm_->VerifySignature(
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
hash_algorithm, signature);
}
void CertificateClientCert::GenerateSigningKey(
const std::string& message, ProtocolVersion protocol_version) {
signing_key_ = crypto_util::DeriveKey(
key(), crypto_util::kSigningKeyLabel,
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
SigningKeyMaterialSizeBits(protocol_version));
}
} // namespace widevine

View File

@@ -1,114 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CERTIFICATE_CLIENT_CERT_H_
#define COMMON_CERTIFICATE_CLIENT_CERT_H_
#include "common/client_cert.h"
#include "common/hash_algorithm.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
class ClientCertAlgorithm {
public:
ClientCertAlgorithm() = default;
virtual ~ClientCertAlgorithm() = default;
ClientCertAlgorithm(const ClientCertAlgorithm&) = delete;
ClientCertAlgorithm& operator=(const ClientCertAlgorithm&) = delete;
// Initialize the algorithm module using the |public_key| from the drm
// certificate. The |algorithm| value provides additional information needed
// by the ECC implementation of this interface.
virtual Status Initialize(const std::string& public_key,
DrmCertificate::Algorithm algorithm) = 0;
// Verify the |signature| of an incoming request |message| using the public
// key from the drm certificate.
virtual Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const = 0;
// Returns the key to be used in key derivation of the license
// protocol.
virtual const std::string& session_key() const = 0;
// Returns a byte std::string to be included in the SignedMessage::session_key
// field of a license response. This key may be either an encrypted aes key,
// or the bytes of an ephemeral public key.
virtual const std::string& wrapped_session_key() const = 0;
// Returns information on the type session key used in this format. This value
// is intended to be included in the SignedMessage::session_key_type field of
// a license response.
virtual SignedMessage::SessionKeyType session_key_type() const = 0;
};
class CertificateClientCert : public ClientCert {
public:
CertificateClientCert() {}
~CertificateClientCert() override {}
CertificateClientCert(const CertificateClientCert&) = delete;
CertificateClientCert& operator=(const CertificateClientCert&) = delete;
Status Initialize(const DrmRootCertificate* root_certificate,
const std::string& serialized_certificate);
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const override;
void GenerateSigningKey(const std::string& message,
ProtocolVersion protocol_version) override;
const std::string& encrypted_key() const override {
return algorithm_->wrapped_session_key();
}
const std::string& key() const override { return algorithm_->session_key(); }
SignedMessage::SessionKeyType key_type() const override {
return algorithm_->session_key_type();
}
bool using_dual_certificate() const override { return false; }
const std::string& serial_number() const override {
return device_cert_.serial_number();
}
const std::string& service_id() const override {
return provisioner_certificate_.provider_id();
}
const std::string& signing_key() const override { return signing_key_; }
const std::string& signer_serial_number() const override {
return model_certificate_.serial_number();
}
uint32_t signer_creation_time_seconds() const override {
return model_certificate_.creation_time_seconds();
}
bool signed_by_provisioner() const override { return signed_by_provisioner_; }
uint32_t system_id() const override { return model_certificate_.system_id(); }
widevine::ClientIdentification::TokenType type() const override {
return ClientIdentification::DRM_DEVICE_CERTIFICATE;
}
const std::string& encrypted_unique_id() const override {
return device_cert_.rot_id().encrypted_unique_id();
}
const std::string& unique_id_hash() const override {
return device_cert_.rot_id().unique_id_hash();
}
private:
std::unique_ptr<ClientCertAlgorithm> algorithm_;
bool signed_by_provisioner_ = false;
std::string signing_key_;
DrmCertificate model_certificate_;
DrmCertificate device_cert_;
DrmCertificate provisioner_certificate_;
bool is_initialized_ = false;
};
} // namespace widevine
#endif // COMMON_CERTIFICATE_CLIENT_CERT_H_

View File

@@ -1,22 +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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CERTIFICATE_TYPE_H_
#define COMMON_CERTIFICATE_TYPE_H_
namespace widevine {
enum CertificateType {
kCertificateTypeTesting,
kCertificateTypeDevelopment,
kCertificateTypeProduction,
};
} // namespace widevine
#endif // COMMON_CERTIFICATE_TYPE_H_

View File

@@ -1,130 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <cstddef>
#include <memory>
#include <string>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "absl/strings/escaping.h"
#include "common/certificate_client_cert.h"
#include "common/crypto_util.h"
#include "common/dual_certificate_client_cert.h"
#include "common/error_space.h"
#include "common/keybox_client_cert.h"
#include "common/random_util.h"
#include "common/rsa_key.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"
namespace widevine {
void KeyboxClientCert::SetPreProvisioningKeys(
const std::multimap<uint32_t, std::string>& keymap) {
std::vector<WvmTokenHandler::PreprovKey> keyvector;
keyvector.reserve(keymap.size());
for (std::multimap<uint32_t, std::string>::const_iterator it = keymap.begin();
it != keymap.end(); ++it) {
std::string key = absl::HexStringToBytes(it->second);
DCHECK_EQ(key.size(), 16);
keyvector.push_back(WvmTokenHandler::PreprovKey(it->first, key));
}
WvmTokenHandler::SetPreprovKeys(keyvector);
}
bool KeyboxClientCert::IsSystemIdKnown(const uint32_t system_id) {
return WvmTokenHandler::IsSystemIdKnown(system_id);
}
uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
return WvmTokenHandler::GetSystemId(keybox_bytes);
}
Status ClientCert::Create(const DrmRootCertificate* root_certificate,
const widevine::ClientIdentification& client_id,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(client_cert);
switch (client_id.type()) {
case ClientIdentification::KEYBOX:
return CreateWithKeybox(client_id.token(), client_cert);
case ClientIdentification::DRM_DEVICE_CERTIFICATE:
if (!client_id.has_device_credentials()) {
return CreateWithDrmCertificate(root_certificate, client_id.token(),
client_cert);
}
// Assumes |client_id.token| is the signing cert and
// |client_id.device_credentials().token| is the encryption cert.
if (client_id.device_credentials().type() !=
ClientIdentification::DRM_DEVICE_CERTIFICATE)
return Status(error_space, INVALID_DRM_CERTIFICATE,
"unsupported-encryption-certificate");
return CreateWithDualDrmCertificates(
root_certificate, client_id.token(),
client_id.device_credentials().token(), client_cert);
default:
return Status(error_space, error::UNIMPLEMENTED,
"client-type-not-implemented");
}
return OkStatus();
}
// Creates a Device Certificate based ClientCert. The |client_cert| is a
// caller supplied unique_ptr to receive the new ClientCert.
Status ClientCert::CreateWithDrmCertificate(
const DrmRootCertificate* root_certificate,
const std::string& drm_certificate,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(root_certificate);
CHECK(client_cert);
auto device_cert = absl::make_unique<CertificateClientCert>();
Status status = device_cert->Initialize(root_certificate, drm_certificate);
if (status.ok()) {
*client_cert = std::move(device_cert);
}
return status;
}
Status ClientCert::CreateWithDualDrmCertificates(
const DrmRootCertificate* root_certificate,
const std::string& signing_drm_certificate,
const std::string& encryption_drm_certificate,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(root_certificate);
CHECK(client_cert);
auto device_cert = absl::make_unique<DualCertificateClientCert>();
Status status = device_cert->Initialize(
root_certificate, signing_drm_certificate, encryption_drm_certificate);
if (status.ok()) {
*client_cert = std::move(device_cert);
}
return status;
}
Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
std::unique_ptr<ClientCert>* client_cert) {
CHECK(client_cert);
auto kbx_cert = absl::make_unique<KeyboxClientCert>();
Status status = kbx_cert->Initialize(keybox_token);
if (status.ok()) {
*client_cert = std::move(kbx_cert);
}
return status;
}
} // namespace widevine

View File

@@ -1,99 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CLIENT_CERT_H__
#define COMMON_CLIENT_CERT_H__
#include <memory>
#include "common/drm_root_certificate.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
// Handler class for LicenseRequests; validates requests and encrypts licenses.
class ClientCert {
protected:
ClientCert() = default;
public:
// Creates a Device Certificate from the supplied |client_id|.
static Status Create(const DrmRootCertificate* root_certificate,
const widevine::ClientIdentification& client_id,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Device Certificate based ClientCert.
static Status CreateWithDrmCertificate(
const DrmRootCertificate* root_certificate,
const std::string& drm_certificate,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Device Certificate using the supplied certificates.
// The|signing_drm_certificate| will be used to verify an incoming request.
// The |encryption_drm_certificate| will be used to define the session key
// used to protect a response message.
static Status CreateWithDualDrmCertificates(
const DrmRootCertificate* root_certificate,
const std::string& signing_drm_certificate,
const std::string& encryption_drm_certificate,
std::unique_ptr<ClientCert>* client_cert);
// Creates a Keybox based ClientCert. The |client_cert| is a caller supplied
// unique_ptr to receive the new ClientCert.
static Status CreateWithKeybox(const std::string& keybox_token,
std::unique_ptr<ClientCert>* client_cert);
virtual ~ClientCert() = default;
ClientCert(const ClientCert&) = delete;
ClientCert& operator=(const ClientCert&) = delete;
// 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 Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const = 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,
ProtocolVersion protocol_version) = 0;
virtual const std::string& encrypted_key() const = 0;
virtual const std::string& key() const = 0;
virtual SignedMessage::SessionKeyType key_type() const = 0;
virtual bool using_dual_certificate() const = 0;
virtual const std::string& serial_number() const = 0;
virtual const std::string& service_id() const = 0;
virtual const std::string& signing_key() const = 0;
virtual const std::string& signer_serial_number() const = 0;
virtual uint32_t signer_creation_time_seconds() const = 0;
virtual bool signed_by_provisioner() const = 0;
virtual uint32_t system_id() const = 0;
virtual widevine::ClientIdentification::TokenType type() const = 0;
virtual const std::string& encrypted_unique_id() const = 0;
virtual const std::string& unique_id_hash() const = 0;
virtual Status SystemIdUnknownError() const {
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
}
virtual Status SystemIdRevokedError() const {
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"device-certificate-revoked");
}
};
} // namespace widevine
#endif // COMMON_CLIENT_CERT_H__

View File

@@ -1,867 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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

View File

@@ -1,126 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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_id_util.h"
#include "glog/logging.h"
#include "common/aes_cbc_util.h"
#include "common/client_cert.h"
#include "common/drm_service_certificate.h"
#include "common/error_space.h"
#include "common/keybox_client_cert.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
const char kModDrmMake[] = "company_name";
const char kModDrmModel[] = "model_name";
const char kModDrmDeviceName[] = "device_name";
const char kModDrmProductName[] = "product_name";
const char kModDrmBuildInfo[] = "build_info";
const char kModDrmOemCryptoSecurityPatchLevel[] =
"oem_crypto_security_patch_level";
void AddClientInfo(ClientIdentification* client_id, absl::string_view name,
absl::string_view value) {
ClientIdentification_NameValue* nv = client_id->add_client_info();
nv->set_name(std::string(name));
nv->set_value(std::string(value));
}
bool SetClientInfo(ClientIdentification* client_id, absl::string_view name,
absl::string_view value) {
int n = client_id->client_info_size();
for (int i = 0; i < n; i++) {
if (client_id->client_info(i).name() == name) {
client_id->mutable_client_info(i)->set_value(std::string(value));
return true;
}
}
AddClientInfo(client_id, name, value);
return false;
}
std::string GetClientInfo(const ClientIdentification& client_id,
absl::string_view name) {
return GetClientInfo(client_id, name, std::string());
}
std::string GetClientInfo(const ClientIdentification& client_id,
absl::string_view name,
const std::string& default_value) {
for (const auto& nv : client_id.client_info()) {
if (nv.name() == name) {
return nv.value();
}
}
return default_value;
}
Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id,
client_id);
}
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 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 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 Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return OkStatus();
}
uint32_t GetSystemId(const ClientIdentification& client_id) {
uint32_t system_id = 0;
if (client_id.has_token()) {
switch (client_id.type()) {
case ClientIdentification::KEYBOX:
system_id = KeyboxClientCert::GetSystemId(client_id.token());
break;
case ClientIdentification::DRM_DEVICE_CERTIFICATE: {
SignedDrmCertificate signed_drm_certificate;
if (signed_drm_certificate.ParseFromString(client_id.token())) {
DrmCertificate drm_certificate;
if (drm_certificate.ParseFromString(
signed_drm_certificate.drm_certificate())) {
system_id = drm_certificate.system_id();
}
}
} break;
default:
break;
}
}
return system_id;
}
} // namespace widevine

View File

@@ -1,71 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Utilities for manipulating the ClientIdentification proto.
// ClientIdentification.client_info() contains a sequence of
// arbitrary name-value pairs; this code consolidates the
// accessors for them in one place.
#ifndef COMMON_CLIENT_ID_UTIL_H_
#define COMMON_CLIENT_ID_UTIL_H_
#include "absl/strings/string_view.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
namespace widevine {
extern const char kModDrmMake[];
extern const char kModDrmModel[];
extern const char kModDrmDeviceName[];
extern const char kModDrmProductName[];
extern const char kModDrmBuildInfo[];
extern const char kModDrmOemCryptoSecurityPatchLevel[];
// Append the given name/value pair to client_id->client_info(). Does not
// check for duplicates.
void AddClientInfo(ClientIdentification* client_id, absl::string_view name,
absl::string_view value);
// Append the given name/value pair to client_id->client_info(). If the
// given name already had a value, replaces it and returns true.
bool SetClientInfo(ClientIdentification* client_id, absl::string_view name,
absl::string_view value);
// Return the value from client_id.client_info() matching the given name,
// or the empty std::string if not found.
std::string GetClientInfo(const ClientIdentification& client_id,
absl::string_view name);
// Return the value from client_id.client_info() matching the given name,
// or the given default value if not found.
std::string GetClientInfo(const ClientIdentification& client_id,
absl::string_view name,
const std::string& default_value);
// Decrypts the encrypted client identification in |encrypted_client_id| into
// |client_id| using the private key for the service certificate which was
// used to encrypt the information.
// |client_id| is owned by caller.
// 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 Status::OK, if successful, else an error.
Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
const std::string& privacy_key, ClientIdentification* client_id);
uint32_t GetSystemId(const ClientIdentification& client_id);
} // namespace widevine
#endif // COMMON_CLIENT_ID_UTIL_H_

View File

@@ -1,83 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/content_id_util.h"
#include "glog/logging.h"
#include "common/error_space.h"
#include "common/status.h"
#include "license_server_sdk/internal/parse_content_id.h"
#include "protos/public/errors.pb.h"
#include "protos/public/external_license.pb.h"
#include "protos/public/license_protocol.pb.h"
#include "protos/public/license_server_sdk.pb.h"
#include "protos/public/widevine_pssh.pb.h"
namespace widevine {
Status GetContentIdFromExternalLicenseRequest(
const ExternalLicenseRequest& external_license_request,
std::string* content_id) {
WidevinePsshData pssh_data;
Status status = ParsePsshData(external_license_request, &pssh_data);
*content_id = pssh_data.content_id();
return OkStatus();
}
Status GetContentIdFromSignedExternalLicenseRequest(
const SignedMessage& signed_message, std::string* content_id) {
if (signed_message.type() != SignedMessage::EXTERNAL_LICENSE_REQUEST) {
return Status(
error_space, error::INVALID_ARGUMENT,
"Unexpected SignedMessage Type. EXTERNAL_LICENSE_REQUEST expected");
}
ExternalLicenseRequest external_license_request;
if (!external_license_request.ParseFromString(signed_message.msg())) {
return Status(error_space, EXTERNAL_LICENSE_REQUEST_PARSE_ERROR,
"Unable to parse into External License Request");
}
return GetContentIdFromExternalLicenseRequest(external_license_request,
content_id);
}
Status ParsePsshData(ExternalLicenseRequest external_license_request,
WidevinePsshData* widevine_pssh_data) {
if (!external_license_request.has_content_id()) {
std::string error = "ExternalLicenseRequest does not include ContentId";
LOG(ERROR) << error
<< ", request = " << external_license_request.ShortDebugString();
return Status(error_space, MISSING_CONTENT_ID, error);
}
ContentInfo content_info;
Status status =
ParseContentId(external_license_request.content_id(), &content_info);
if (!status.ok()) {
std::string error =
"Unable to retrieve ContentId from ExternalLicenseRequest";
LOG(ERROR) << error << ", status = " << status
<< ", request = " << external_license_request.ShortDebugString();
return Status(error_space, MISSING_CONTENT_ID, error);
}
switch (external_license_request.content_id().init_data().init_data_type()) {
case LicenseRequest::ContentIdentification::InitData::WEBM:
widevine_pssh_data->ParseFromString(
content_info.content_info_entry(0).key_ids(0));
break;
default:
*widevine_pssh_data =
content_info.content_info_entry(0).pssh().widevine_data();
break;
}
if (widevine_pssh_data->content_id().empty()) {
std::string error =
"Missing ContentId within Pssh data for ExternalLicenseRequest";
LOG(ERROR) << error
<< ", request = " << external_license_request.ShortDebugString();
return Status(error_space, MISSING_CONTENT_ID, error);
}
return OkStatus();
}
} // namespace widevine

View File

@@ -1,37 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CONTENT_ID_UTIL_H_
#define COMMON_CONTENT_ID_UTIL_H_
#include "common/status.h"
#include "protos/public/external_license.pb.h"
#include "protos/public/license_protocol.pb.h"
#include "protos/public/widevine_pssh.pb.h"
namespace widevine {
// Get content identifier as a std::string from a SignedMessage that includes a
// serialized ExternalLicenseRequest.
Status GetContentIdFromSignedExternalLicenseRequest(
const SignedMessage& signed_message, std::string* content_id);
// Get content identifier as a std::string from an ExternalLicenseRequest.
Status GetContentIdFromExternalLicenseRequest(
const ExternalLicenseRequest& external_license_request,
std::string* content_id);
// Returns OK if successful and |widevine_pssh_data| will be populated by
// parsing |external_license_request|. Else, error and |widevine_pssh_data|
// will not be set within this method.
Status ParsePsshData(ExternalLicenseRequest external_license_request,
WidevinePsshData* widevine_pssh_data);
} // namespace widevine
#endif // COMMON_CONTENT_ID_UTIL_H_

View File

@@ -1,82 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/content_id_util.h"
#include <stddef.h>
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "protos/public/errors.pb.h"
#include "protos/public/external_license.pb.h"
#include "protos/public/license_protocol.pb.h"
#include "protos/public/widevine_pssh.pb.h"
namespace {
const char kContentId[] = "TestContentId";
const char kPlayReadyChallenge[] = "<TestPRChallenge></TestPRChallenge>";
} // namespace
namespace widevine {
// Builds a SignedMessage that includes an ExternalLicenseRequest.
SignedMessage BuildSignedExternalLicenseRequest(const ExternalLicenseType type,
const std::string& request,
const std::string& content_id) {
ExternalLicenseRequest external_license_request;
external_license_request.set_request_type(type);
external_license_request.set_request(request);
LicenseRequest::ContentIdentification::WidevinePsshData* cenc_id =
external_license_request.mutable_content_id()
->mutable_widevine_pssh_data();
WidevinePsshData widevine_pssh_data;
widevine_pssh_data.set_content_id(content_id);
std::string widevine_pssh_string;
widevine_pssh_data.SerializeToString(&widevine_pssh_string);
cenc_id->add_pssh_data(widevine_pssh_string);
SignedMessage signed_message;
signed_message.set_type(SignedMessage::EXTERNAL_LICENSE_REQUEST);
EXPECT_TRUE(
external_license_request.SerializeToString(signed_message.mutable_msg()));
return signed_message;
}
TEST(ContentIdUtil, GetContentId) {
std::string content_id;
EXPECT_OK(GetContentIdFromSignedExternalLicenseRequest(
BuildSignedExternalLicenseRequest(PLAYREADY_LICENSE_NEW,
kPlayReadyChallenge, kContentId),
&content_id));
EXPECT_EQ(kContentId, content_id);
}
TEST(ContentIdUtil, GetContentIdFailureWithIncorrectType) {
std::string content_id;
SignedMessage signed_message = BuildSignedExternalLicenseRequest(
PLAYREADY_LICENSE_NEW, kPlayReadyChallenge, kContentId);
signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST);
Status status =
GetContentIdFromSignedExternalLicenseRequest(signed_message, &content_id);
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
EXPECT_TRUE(content_id.empty());
}
TEST(ContentIdUtil, GetContentIdFailureWithInvalidExternalLicenseRequest) {
std::string content_id;
SignedMessage signed_message = BuildSignedExternalLicenseRequest(
PLAYREADY_LICENSE_NEW, kPlayReadyChallenge, kContentId);
signed_message.set_msg("Invalid payload");
Status status =
GetContentIdFromSignedExternalLicenseRequest(signed_message, &content_id);
EXPECT_EQ(EXTERNAL_LICENSE_REQUEST_PARSE_ERROR, status.error_code());
EXPECT_TRUE(content_id.empty());
}
} // namespace widevine

View File

@@ -1,78 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/core_message_util.h"
#include "common/oemcrypto_core_message/odk/include/core_message_deserialize.h"
#include "common/oemcrypto_core_message/odk/include/core_message_serialize.h"
#include "common/oemcrypto_core_message/odk/include/core_message_serialize_proto.h"
#include "common/sha_util.h"
using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
using oemcrypto_core_message::serialize::CreateCoreLicenseResponseFromProto;
using oemcrypto_core_message::serialize::
CreateCoreProvisioningResponseFromProto;
using oemcrypto_core_message::serialize::CreateCoreRenewalResponse;
using widevine::Sha256_Hash;
namespace widevine {
namespace core_message_util {
bool GetCoreProvisioningResponse(
const std::string& serialized_provisioning_response,
const std::string& request_core_message,
std::string* response_core_message) {
if (request_core_message.empty()) {
return false;
}
oemcrypto_core_message::ODK_ProvisioningRequest odk_provisioning_request;
if (CoreProvisioningRequestFromMessage(request_core_message,
&odk_provisioning_request)) {
return CreateCoreProvisioningResponseFromProto(
serialized_provisioning_response, odk_provisioning_request,
response_core_message);
}
return false;
}
bool GetCoreRenewalOrReleaseLicenseResponse(
uint64_t renewal_duration_seconds, const std::string& request_core_message,
std::string* response_core_message) {
oemcrypto_core_message::ODK_RenewalRequest odk_renewal_request;
if (request_core_message.empty()) {
return false;
}
if (!CoreRenewalRequestFromMessage(request_core_message,
&odk_renewal_request)) {
return false;
}
return CreateCoreRenewalResponse(
odk_renewal_request, renewal_duration_seconds, response_core_message);
}
bool GetCoreNewLicenseResponse(const std::string& license,
const std::string& request_core_message,
const bool nonce_required,
std::string* response_core_message) {
if (request_core_message.empty()) {
return false;
}
oemcrypto_core_message::ODK_LicenseRequest odk_license_request;
if (!CoreLicenseRequestFromMessage(request_core_message,
&odk_license_request)) {
return false;
}
std::string core_request_sha256 = Sha256_Hash(request_core_message);
return CreateCoreLicenseResponseFromProto(license, odk_license_request,
core_request_sha256, nonce_required,
response_core_message);
}
} // namespace core_message_util
} // namespace widevine

View File

@@ -1,40 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CORE_MESSAGE_UTIL_H_
#define COMMON_CORE_MESSAGE_UTIL_H_
#include <string>
namespace widevine {
namespace core_message_util {
// Gets the |response_core_message| by parsing |request_core_message| and
// |serialized_provisioning_response|. The output is held in
// |response_core_message|.
bool GetCoreProvisioningResponse(
const std::string& serialized_provisioning_response,
const std::string& request_core_message,
std::string* response_core_message);
// Gets the |response_core_message| by parsing |request_core_message| for
// release and renewal response. The output is held in |response_core_message|.
bool GetCoreRenewalOrReleaseLicenseResponse(
uint64_t renewal_duration_seconds, const std::string& request_core_message,
std::string* response_core_message);
// Gets the |response_core_message| by parsing |request_core_message| and
// |license| for new license response. The output is held in
// |response_core_message|.
bool GetCoreNewLicenseResponse(const std::string& license,
const std::string& request_core_message,
const bool nonce_required,
std::string* response_core_message);
} // namespace core_message_util
} // namespace widevine
#endif // COMMON_CORE_MESSAGE_UTIL_H_

View File

@@ -1,318 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Unit tests for the crypto_util helper functions.
#include "common/crypto_util.h"
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "openssl/aes.h"
namespace widevine {
namespace crypto_util {
const char kCENCStr[] = "cenc";
const char kCBC1Str[] = "cbc1";
const char kCENSStr[] = "cens";
const char kCBCSStr[] = "cbcs";
static unsigned char kAes128KeyData[] = {0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82,
0x32, 0x9e, 0x6b, 0x3b, 0x4e, 0x29,
0xfa, 0x3b, 0x00, 0x4b};
static unsigned char kAes256KeyData[] = {
0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e, 0x6b, 0x3b, 0x4e,
0x29, 0xfa, 0x3b, 0x00, 0x4b, 0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82,
0x32, 0x9e, 0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b};
static unsigned char kAes128IvData[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};
class CryptoUtilTest : public ::testing::Test {
public:
CryptoUtilTest()
: aes_128_key_(kAes128KeyData, kAes128KeyData + sizeof(kAes128KeyData)),
aes_256_key_(kAes256KeyData, kAes256KeyData + sizeof(kAes256KeyData)),
iv_128_(kAes128IvData, kAes128IvData + sizeof(kAes128IvData)) {}
protected:
std::string aes_128_key_;
std::string aes_256_key_;
std::string iv_128_;
};
TEST_F(CryptoUtilTest, DeriveAes128MasterKeyTest) {
unsigned char label[] = { 0x16, 0xf1, 0xa4, 0x32, 0x9f, 0x94, 0x55, 0xc1,
0x92, 0xa0, 0x34, 0x8a, 0x8b, 0x6b, 0x77, 0x08,
0xbc, 0x23, 0x70, 0x16, 0xbc, 0xda, 0xfb, 0x60,
0xd1, 0xcf, 0x6a, 0x4d, 0x40, 0xa1, 0xe3, 0xfe,
0xd3, 0xe9, 0xa6, 0x58, 0x4c, 0xd4, 0xad, 0xa4,
0xa2 };
unsigned char context[] = { 0x4c, 0x53, 0xc0, 0xe9, 0x9e, 0x7f, 0x7d, 0x6d,
0x0a, 0x76, 0x7c, 0xc7, 0x25, 0xb5, 0x5b, 0x80,
0x81, 0x91, 0xff };
unsigned char output0[] = { 0xd5, 0xad, 0x2d, 0xb1, 0x5a, 0x06, 0xcb, 0x50,
0xf2, 0x59, 0x5a, 0xb2, 0xb2, 0x0d, 0x44, 0x4e };
unsigned char output1[] = { 0xdf, 0x38, 0x45, 0x97, 0x5d, 0x7a, 0x81, 0xb4,
0x94, 0x86, 0xaf, 0x0c, 0xdc, 0x4d, 0xeb, 0x62,
0x31, 0x39, 0x67, 0x8f, 0xff, 0x5d, 0x68, 0x35,
0xdc, 0x89, 0x5f, 0x47, 0xca, 0xe0, 0x2d, 0x3a,
0x10, 0x24, 0xf8, 0x7e, 0x5b, 0x70, 0xe1, 0xa3,
0x4a, 0x47, 0x2f, 0x04, 0xe0, 0x34, 0x75, 0x22 };
std::string label_str(label, label + sizeof(label));
std::string context_str(context, context + sizeof(context));
std::string result = DeriveKey(aes_128_key_, label_str, context_str, 128);
std::string output_128(output0, output0 + sizeof(output0));
ASSERT_EQ(result, output_128);
result = DeriveKey(aes_128_key_, label_str, context_str, 384);
std::string output_384(output1, output1 + sizeof(output1));
ASSERT_EQ(result, output_384);
}
TEST_F(CryptoUtilTest, DeriveAes256MasterKeyTest) {
const unsigned char label[] = {
0x16, 0xf1, 0xa4, 0x32, 0x9f, 0x94, 0x55, 0xc1, 0x92, 0xa0, 0x34,
0x8a, 0x8b, 0x6b, 0x77, 0x08, 0xbc, 0x23, 0x70, 0x16, 0xbc, 0xda,
0xfb, 0x60, 0xd1, 0xcf, 0x6a, 0x4d, 0x40, 0xa1, 0xe3, 0xfe, 0xd3,
0xe9, 0xa6, 0x58, 0x4c, 0xd4, 0xad, 0xa4, 0xa2};
const unsigned char context[] = {0x4c, 0x53, 0xc0, 0xe9, 0x9e, 0x7f, 0x7d,
0x6d, 0x0a, 0x76, 0x7c, 0xc7, 0x25, 0xb5,
0x5b, 0x80, 0x81, 0x91, 0xff};
const unsigned char expected_128[] = {0x76, 0x36, 0x33, 0x0e, 0x0b, 0x2c,
0x38, 0xc2, 0x9e, 0x53, 0x23, 0x8d,
0x2e, 0xc6, 0x3a, 0x46};
const std::string label_str(label, label + sizeof(label));
const std::string context_str(context, context + sizeof(context));
std::string result = DeriveKey(aes_256_key_, label_str, context_str, 128);
EXPECT_EQ(std::string(expected_128, expected_128 + sizeof(expected_128)),
result)
<< absl::BytesToHexString(result);
const unsigned char expected_256[] = {
0xfb, 0x8f, 0xdf, 0x0e, 0x22, 0xfe, 0xf7, 0x2b, 0xd1, 0x9a, 0x1d,
0xd2, 0xcb, 0xb0, 0x11, 0x5c, 0x6c, 0xa7, 0xe1, 0x7f, 0x72, 0xce,
0x3a, 0x60, 0x34, 0x89, 0x6d, 0x08, 0xef, 0xde, 0x19, 0x45};
result = DeriveKey(aes_256_key_, label_str, context_str, 256);
EXPECT_EQ(std::string(expected_256, expected_256 + sizeof(expected_256)),
result)
<< absl::BytesToHexString(result);
const unsigned char expected_384[] = {
0x65, 0xbc, 0xe3, 0xf3, 0xfb, 0xfa, 0xce, 0x1d, 0x24, 0x63, 0x9c, 0x8f,
0x48, 0x0e, 0xbd, 0x76, 0xd1, 0x14, 0x0b, 0xb1, 0x3a, 0x3d, 0x6e, 0x30,
0xa9, 0xf4, 0x40, 0x35, 0x0d, 0x6b, 0xc5, 0x1e, 0x9c, 0xa9, 0x5f, 0xf9,
0xde, 0x96, 0xa0, 0xa4, 0x22, 0x62, 0x21, 0xc5, 0xd6, 0xd4, 0xf4, 0x6f};
result = DeriveKey(aes_256_key_, label_str, context_str, 384);
EXPECT_EQ(std::string(expected_384, expected_384 + sizeof(expected_384)),
result)
<< absl::BytesToHexString(result);
}
TEST_F(CryptoUtilTest, DeriveAesInvalidSizeModulus) {
// This is the control case that we correctly derive 128 bits.
EXPECT_NE("", DeriveKey(aes_128_key_, "foo", "bar", 128));
EXPECT_EQ("", DeriveKey(aes_128_key_, "foo", "bar", 127));
}
TEST_F(CryptoUtilTest, DeriveAesMaxBlocks) {
EXPECT_EQ(
255 * AES_BLOCK_SIZE,
DeriveKey(aes_128_key_, "foo", "bar", AES_BLOCK_SIZE * 8 * 255).size());
}
TEST_F(CryptoUtilTest, DeriveAesTooManyBlocks) {
EXPECT_EQ("",
DeriveKey(aes_128_key_, "foo", "bar", AES_BLOCK_SIZE * 8 * 256));
}
TEST_F(CryptoUtilTest, DeriveAes128InvalidKeySize) {
EXPECT_EQ("", DeriveKey(aes_128_key_.substr(0, 15), "foo", "bar", 128));
}
TEST_F(CryptoUtilTest, DeriveAes256InvalidKeySize) {
EXPECT_EQ("", DeriveKey(aes_256_key_.substr(0, 31), "foo", "bar", 128));
}
TEST_F(CryptoUtilTest, DeriveGroupSesionKey) {
unsigned char output[] = { 0x92, 0x6c, 0x2f, 0x5, 0xa6, 0x4f, 0xff, 0xb1,
0x86, 0x4a, 0x1a, 0x14, 0x95, 0xeb, 0xb0, 0xf1 };
std::string group_session_key = DeriveGroupSessionKey("test_group_id", 128);
EXPECT_EQ(crypto_util::kAes128KeySizeBytes, group_session_key.size());
const std::string output_128(output, output + sizeof(output));
ASSERT_EQ(output_128, group_session_key);
}
TEST_F(CryptoUtilTest, TestCreateAndVerifySignatureHmacSha256) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53,
0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2,
0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91,
0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde,
0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f,
0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5,
0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54,
0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda };
std::string message(message_data, message_data + sizeof(message_data));
std::string signature(CreateSignatureHmacSha256(aes_128_key_, message));
ASSERT_EQ(signature.size(), 32);
ASSERT_TRUE(VerifySignatureHmacSha256(aes_128_key_, signature, message));
}
TEST_F(CryptoUtilTest, TestFailCreateAndVerifyHmacSha256) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53,
0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2,
0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91,
0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde,
0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f,
0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5,
0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54,
0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda };
std::string message(message_data, message_data + sizeof(message_data));
// Test with bogus key;
std::string bogus_key("bogus");
std::string signature(CreateSignatureHmacSha256(bogus_key, message));
// This should still produce an hmac signature.
ASSERT_EQ(signature.size(), 32);
// Create valid signature to compare.
signature = CreateSignatureHmacSha256(aes_128_key_, message);
// Test with bogus key.
ASSERT_FALSE(VerifySignatureHmacSha256(bogus_key, signature, message));
// Test with munged signature.
signature[0] = 0xFF;
ASSERT_FALSE(VerifySignatureHmacSha256(aes_128_key_, signature, message));
// Test with bogus signature.
ASSERT_FALSE(VerifySignatureHmacSha256(aes_128_key_, "bogus", message));
}
TEST_F(CryptoUtilTest, TestCreateAndVerifySignatureHmacSha1) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53,
0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2,
0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91,
0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde,
0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f,
0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5,
0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54,
0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda };
std::string message(message_data, message_data + sizeof(message_data));
std::string signature(CreateSignatureHmacSha1(aes_128_key_, message));
ASSERT_EQ(20, signature.size());
ASSERT_TRUE(VerifySignatureHmacSha1(aes_128_key_, signature, message));
}
TEST_F(CryptoUtilTest, TestFailCreateAndVerifyHmacSha1) {
unsigned char message_data[] = {
0xd9, 0x24, 0x2d, 0x03, 0x93, 0x6f, 0x22, 0x53,
0x99, 0x7a, 0x7d, 0x9b, 0x0c, 0xcf, 0xfd, 0xb2,
0x66, 0x0d, 0xaf, 0xdb, 0xa2, 0xad, 0x23, 0x91,
0x8a, 0xdf, 0x01, 0x80, 0xa3, 0x35, 0xf9, 0xde,
0xf6, 0x5b, 0xa2, 0x85, 0x0e, 0x2d, 0x93, 0x6f,
0x99, 0x7a, 0x63, 0x47, 0x2e, 0x54, 0x35, 0xb5,
0xf7, 0x45, 0xed, 0x6b, 0xcf, 0xe8, 0xf2, 0x54,
0x97, 0x69, 0x23, 0x74, 0x34, 0x9a, 0x34, 0xda };
std::string message(message_data, message_data + sizeof(message_data));
// Test with bogus key;
std::string bogus_key("bogus");
std::string signature(CreateSignatureHmacSha1(bogus_key, message));
// This should still produce an hmac signature.
ASSERT_EQ(20, signature.size());
// Create valid signature to compare.
signature = CreateSignatureHmacSha1(aes_128_key_, message);
// Test with bogus key.
ASSERT_FALSE(VerifySignatureHmacSha1(bogus_key, signature, message));
// Test with munged signature.
signature[0] = 0xFF;
ASSERT_FALSE(VerifySignatureHmacSha1(aes_128_key_, signature, message));
// Test with bogus signature.
ASSERT_FALSE(VerifySignatureHmacSha1(aes_128_key_, "bogus", message));
}
TEST_F(CryptoUtilTest, DeriveIv) {
// First value in the pair is the key_id, second value is the expected IV.
std::pair<std::string, std::string> id_iv_pairs[] = {
{"1234567890123456", "3278234c7682d1a2e153af4912975f5f"},
{"0987654321098765", "cf09abd30f04b60544910791a6b904cf"}};
for (const auto& id_iv_pair : id_iv_pairs) {
SCOPED_TRACE(absl::StrCat("test case:", id_iv_pair.first));
EXPECT_EQ(id_iv_pair.second,
absl::BytesToHexString(DeriveIv(id_iv_pair.first)));
// Repeat same call to verify derivied result is repeatable.
EXPECT_EQ(id_iv_pair.second,
absl::BytesToHexString(DeriveIv(id_iv_pair.first)));
}
}
TEST_F(CryptoUtilTest, DeriveKeyId) {
// First value in the pair is the context, second value is the expected id.
std::pair<std::string, std::string> context_id_pairs[] = {
{"1234567890123456", "a3c4a8c0d0e24e96f38f492254186a9d"},
{"0987654321098765", "084fc6bece9688ccce6b1672d9b47e22"}};
for (const auto& context_id_pair : context_id_pairs) {
SCOPED_TRACE(absl::StrCat("test case:", context_id_pair.first));
EXPECT_EQ(context_id_pair.second,
absl::BytesToHexString(DeriveKeyId(context_id_pair.first)));
// Repeat same call to verify derivied result is repeatable.
EXPECT_EQ(context_id_pair.second,
absl::BytesToHexString(DeriveKeyId(context_id_pair.first)));
}
}
TEST_F(CryptoUtilTest, Verify4CCEncryptionIDFromBadString) {
uint32_t cc_code;
ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("garbage", &cc_code));
ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("junk", &cc_code));
ASSERT_FALSE(FourCCEncryptionSchemeIDFromString("cencc", &cc_code));
}
TEST_F(CryptoUtilTest, Verify4CCEncryptionIDFromString) {
uint32_t cc_code = 0;
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENCStr, &cc_code));
ASSERT_EQ(kCENCSchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBC1Str, &cc_code));
ASSERT_EQ(kCBC1SchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENSStr, &cc_code));
ASSERT_EQ(kCENSSchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBCSStr, &cc_code));
ASSERT_EQ(kCBCSSchemeID, cc_code);
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -1,135 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
// Implementation of the DefaultDeviceSecurityProfileList class.
#include "common/default_device_security_profile_list.h"
#include <vector>
#include "glog/logging.h"
#include "google/protobuf/text_format.h"
#include "common/client_id_util.h"
#include "common/device_status_list.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
using ClientCapabilities = ClientIdentification::ClientCapabilities;
const char kWidevine[] = "widevine";
// Definition of Widevine default device security profiles.
// TODO(user): Add an OWNER file with per-file access to restrict changes to the
// profile definition.
const char kWidevineProfileMin[] =
(" name: \"minimum\""
" min_output_requirements {"
" hdcp_version: HDCP_NONE"
" analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 0"
" security_level: LEVEL_3"
" resource_rating_tier: 0"
" vulnerability_level: VULNERABILITY_HIGH"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileLow[] =
(" name: \"low\""
" min_output_requirements {"
" hdcp_version: HDCP_NONE"
" analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 8"
" security_level: LEVEL_3"
" resource_rating_tier: 1"
" vulnerability_level: VULNERABILITY_MEDIUM"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileMed[] =
(" name: \"medium\""
" min_output_requirements {"
" hdcp_version: HDCP_V1"
" analog_output_capabilities: ANALOG_OUTPUT_UNKNOWN"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 12"
" security_level: LEVEL_3"
" resource_rating_tier: 1"
" vulnerability_level: VULNERABILITY_LOW"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileHigh[] =
(" name: \"high\""
" min_output_requirements {"
" hdcp_version: HDCP_V1"
" analog_output_capabilities: ANALOG_OUTPUT_SUPPORTS_CGMS_A"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 12"
" security_level: LEVEL_1"
" resource_rating_tier: 2"
" vulnerability_level: VULNERABILITY_NONE"
" }"
" owner: \"Widevine\"");
const char kWidevineProfileStrict[] =
(" name: \"strict\""
" min_output_requirements {"
" hdcp_version: HDCP_V2_2"
" analog_output_capabilities: ANALOG_OUTPUT_SUPPORTS_CGMS_A"
" }"
" min_security_requirements {"
" oemcrypto_api_version: 12"
" security_level: LEVEL_1"
" resource_rating_tier: 3"
" vulnerability_level: VULNERABILITY_NONE"
" }"
" owner: \"Widevine\"");
DefaultDeviceSecurityProfileList::DefaultDeviceSecurityProfileList()
: SecurityProfileList(kWidevine) {}
int DefaultDeviceSecurityProfileList::Init() { return AddDefaultProfiles(); }
int DefaultDeviceSecurityProfileList::AddDefaultProfiles() {
std::vector<std::string> default_profile_strings;
GetDefaultProfileStrings(&default_profile_strings);
for (auto& profile_string : default_profile_strings) {
SecurityProfile profile;
if (!google::protobuf::TextFormat::ParseFromString(profile_string, &profile)) {
LOG(ERROR) << "Unable to load default profile: " << profile.name();
ClearAllProfiles();
return 0;
}
InsertProfile(profile);
}
return NumProfiles();
}
int DefaultDeviceSecurityProfileList::GetDefaultProfileStrings(
std::vector<std::string>* default_profile_strings) const {
if (default_profile_strings == nullptr) {
return 0;
}
default_profile_strings->push_back(kWidevineProfileMin);
default_profile_strings->push_back(kWidevineProfileLow);
default_profile_strings->push_back(kWidevineProfileMed);
default_profile_strings->push_back(kWidevineProfileHigh);
default_profile_strings->push_back(kWidevineProfileStrict);
return default_profile_strings->size();
}
} // namespace widevine

View File

@@ -1,39 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Container of Widevine default security profiless.
#ifndef COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
#define COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
#include "common/security_profile_list.h"
namespace widevine {
class DefaultDeviceSecurityProfileList : public SecurityProfileList {
public:
DefaultDeviceSecurityProfileList();
~DefaultDeviceSecurityProfileList() override {}
// Initialize the security profile list. The list is initially empty, this
// function will populate the list with default profiles. The size of the
// list is returned.
int Init() override;
private:
// Initialize the list with Widevine default profiles. The size of the
// profile list after the additions is returned.
virtual int AddDefaultProfiles();
virtual int GetDefaultProfileStrings(
std::vector<std::string>* default_profile_strings) const;
};
} // namespace widevine
#endif // COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_

View File

@@ -1,186 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/default_device_security_profile_list.h"
#include "glog/logging.h"
#include "google/protobuf/util/message_differencer.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "common/client_id_util.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
namespace security_profile {
const uint32_t kResourceTierLow = 1;
const uint32_t kResourceTierMed = 2;
const uint32_t kResourceTierHigh = 3;
const char kMinProfileName[] = "minimum";
const char kLowProfileName[] = "low";
const char kMedProfileName[] = "medium";
const char kHighProfileName[] = "high";
const char kStrictProfileName[] = "strict";
class DefaultDeviceSecurityProfileListTest : public ::testing::Test {
public:
DefaultDeviceSecurityProfileListTest() {}
~DefaultDeviceSecurityProfileListTest() override {}
void SetUp() override {
SecurityProfile profile;
std::string profile_namespace = "widevine";
profile_list_ = absl::make_unique<DefaultDeviceSecurityProfileList>();
const int kNumWidevineProfiles = 5;
ASSERT_EQ(kNumWidevineProfiles, profile_list_->Init());
}
// Configure |client_id| and |device_info| with minimum settings.
void SetupMinDrmParams(ClientIdentification* client_id,
ProvisionedDeviceInfo* device_info) {
client_id->mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_NONE);
client_id->mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_UNKNOWN);
client_id->mutable_client_capabilities()->set_oem_crypto_api_version(0);
client_id->mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierLow);
device_info->set_security_level(ProvisionedDeviceInfo::LEVEL_3);
}
// Configure |client_id| and |device_info| with maximum settings.
void SetupMaxDrmParams(ClientIdentification* client_id,
ProvisionedDeviceInfo* device_info) {
client_id->mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_3);
client_id->mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
client_id->mutable_client_capabilities()->set_oem_crypto_api_version(16);
client_id->mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
device_info->set_security_level(ProvisionedDeviceInfo::LEVEL_1);
}
std::unique_ptr<SecurityProfileList> profile_list_;
};
TEST_F(DefaultDeviceSecurityProfileListTest, QualifiedProfiles) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMinDrmParams(&client_id, &device_info);
std::vector<std::string> qualified_profiles;
// Should only return the minimum profile.
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the low profile.
client_id.mutable_client_capabilities()->set_oem_crypto_api_version(8);
ASSERT_EQ(2, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the med profile.
client_id.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V1);
client_id.mutable_client_capabilities()->set_oem_crypto_api_version(12);
ASSERT_EQ(3, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMedProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the high profile.
device_info.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
client_id.mutable_client_capabilities()->set_analog_output_capabilities(
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
client_id.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierMed);
ASSERT_EQ(4, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMedProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kHighProfileName) != qualified_profiles.end());
// Increase the device capabilities to include the strict profile.
client_id.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_2);
client_id.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
ASSERT_EQ(5, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kLowProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMedProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kHighProfileName) != qualified_profiles.end());
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kStrictProfileName) != qualified_profiles.end());
}
TEST_F(DefaultDeviceSecurityProfileListTest,
DeviceQualifiedProfilesForLowEndDevice) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMinDrmParams(&client_id, &device_info);
// Only 1 profile should qualify for this device.
std::vector<std::string> qualified_profiles;
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
EXPECT_TRUE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
kMinProfileName) != qualified_profiles.end());
}
TEST_F(DefaultDeviceSecurityProfileListTest,
QualifiedProfilesForHighEndDevice) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMaxDrmParams(&client_id, &device_info);
// All 5 default profiles should qualify for this device.
std::vector<std::string> qualified_profiles;
ASSERT_EQ(5, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
}
// TODO(b/160019477): Add test once provisioned device info supports known
// vulnerability.
TEST_F(DefaultDeviceSecurityProfileListTest,
DISABLED_QualifiedProfilesByVunerabilityLevel) {
ClientIdentification client_id;
ProvisionedDeviceInfo device_info;
SetupMaxDrmParams(&client_id, &device_info);
std::vector<std::string> qualified_profiles;
ASSERT_EQ(0, profile_list_->GetQualifiedProfiles(client_id, device_info,
&qualified_profiles));
}
} // namespace security_profile
} // namespace widevine

View File

@@ -1,42 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Implements the device info helper function.
#include "common/device_info_util.h"
#include "absl/strings/ascii.h"
#include "protos/public/device_common.pb.h"
namespace widevine {
bool IsMatchedMakeModel(const std::string& expected_make,
const std::string& expected_model,
const std::string& make_from_client,
const std::string& model_from_client) {
return absl::AsciiStrToLower(expected_make) ==
absl::AsciiStrToLower(make_from_client) &&
absl::AsciiStrToLower(expected_model) ==
absl::AsciiStrToLower(model_from_client);
}
bool VerifyMakeModel(const ProvisionedDeviceInfo& device_info,
const std::string& make_from_client,
const std::string& model_from_client) {
if (IsMatchedMakeModel(device_info.manufacturer(), device_info.model(),
make_from_client, model_from_client)) {
return true;
}
for (const DeviceModel& product_info : device_info.model_info()) {
if (IsMatchedMakeModel(product_info.manufacturer(),
product_info.model_name(), make_from_client,
model_from_client)) {
return true;
}
}
return false;
}
} // namespace widevine

View File

@@ -1,30 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_DEVICE_INFO_UTIL_H_
#define COMMON_DEVICE_INFO_UTIL_H_
#include <string>
#include "protos/public/provisioned_device_info.pb.h"
namespace widevine {
// Helpers function to compare the expected and actual make model field.
bool IsMatchedMakeModel(const std::string& expected_make,
const std::string& expected_model,
const std::string& make_from_client,
const std::string& model_from_client);
/**
* Return true if make/model from client in device_info matches any of the
* registered makes/models.
*/
bool VerifyMakeModel(const ProvisionedDeviceInfo& device_info,
const std::string& make_from_client,
const std::string& model_from_client);
} // namespace widevine
#endif // COMMON_DEVICE_INFO_UTIL_H_

View File

@@ -1,598 +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.
////////////////////////////////////////////////////////////////////////////////
// Implements the DeviceStatusList class.
#include "common/device_status_list.h"
#include <time.h>
#include <map>
#include <memory>
#include <cstdint>
#include "glog/logging.h"
#include "absl/strings/ascii.h"
#include "absl/strings/escaping.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#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/hash_algorithm_util.h"
#include "common/keybox_client_cert.h"
#include "common/rsa_key.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_device_info.pb.h"
using ::widevine::DeviceCertificateStatusListRequest;
using ::widevine::SignedDeviceInfo;
using ::widevine::SignedDeviceInfoRequest;
namespace widevine {
namespace {
const char kSignedListTerminator[] = "}";
const char kSignedList[] = "signedList\":";
const std::size_t kSignedListLen = strlen(kSignedList);
} // namespace
DeviceStatusList* DeviceStatusList::Instance() {
// TODO(user): This is "ok" according to Google's Coding for Dummies, but
// we should inject the status list into the sessions. This will require
// exposing additional objects in the public interface.
static DeviceStatusList* device_status_list(nullptr);
if (!device_status_list) device_status_list = new DeviceStatusList;
return device_status_list;
}
DeviceStatusList::DeviceStatusList() {}
DeviceStatusList::~DeviceStatusList() {}
Status DeviceStatusList::UpdateStatusList(
const std::string& root_certificate_public_key,
const std::string& serialized_device_certificate_status_list,
HashAlgorithm hash_algorithm, const std::string& signature,
uint32_t expiration_period_seconds) {
if (serialized_device_certificate_status_list.empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
}
if (signature.empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list-signature");
}
std::unique_ptr<RsaPublicKey> root_key(
RsaPublicKey::Create(root_certificate_public_key));
if (root_key == nullptr) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
}
if (!root_key->VerifySignature(serialized_device_certificate_status_list,
hash_algorithm, signature)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"invalid-status-list-signature");
}
DeviceCertificateStatusList certificate_status_list;
if (!certificate_status_list.ParseFromString(
serialized_device_certificate_status_list)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
if (expiration_period_seconds &&
(GetCurrentTime() > (certificate_status_list.creation_time_seconds() +
expiration_period_seconds))) {
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
}
absl::WriterMutexLock lock(&status_map_lock_);
device_status_map_.clear();
for (int i = 0, n = certificate_status_list.certificate_status_size(); i < n;
i++) {
const DeviceCertificateStatus& cert_status =
certificate_status_list.certificate_status(i);
if (cert_status.has_device_info()) {
const ProvisionedDeviceInfo& device_info = cert_status.device_info();
if (device_info.has_system_id()) {
device_status_map_[device_info.system_id()] = cert_status;
} else {
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 OkStatus();
}
Status DeviceStatusList::GetCertStatus(
const ClientCert& client_cert, const std::string& make,
const std::string& provider, bool allow_revoked_system_id,
DeviceCertificateStatus* device_certificate_status) {
CHECK(device_certificate_status);
absl::ReaderMutexLock lock(&status_map_lock_);
if (expiration_period_seconds_ &&
(GetCurrentTime() >
(creation_time_seconds_ + expiration_period_seconds_))) {
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());
if (device_cert_status == nullptr) {
if (allow_unknown_devices_) {
return OkStatus();
}
return client_cert.SystemIdUnknownError();
}
*device_certificate_status = *device_cert_status;
if (device_cert_status->status() == DeviceCertificateStatus::STATUS_REVOKED) {
if (IsRevokedSystemIdAllowed(client_cert.system_id()) ||
allow_revoked_system_id) {
LOG(WARNING) << "Allowing REVOKED device: "
<< device_cert_status->device_info().ShortDebugString();
} else {
return client_cert.SystemIdRevokedError();
}
}
// The remainder of this function is for DRM certificates.
if (client_cert.type() == ClientIdentification::KEYBOX) {
return OkStatus();
}
// DRM certificate checks.
if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"device-certificate-unsupported-token-type");
}
if ((device_cert_status->status() ==
DeviceCertificateStatus::STATUS_TEST_ONLY) &&
!allow_test_only_devices_) {
if (IsTestOnlyDeviceAllowedByMake(client_cert.system_id(), make) &&
IsTestOnlyDeviceAllowedByProvider(client_cert.system_id(), provider)) {
LOG(WARNING) << "Allowing TEST_ONLY device with systemId = "
<< client_cert.system_id() << ", make = " << make
<< ", provider = " << provider << ", device info = "
<< device_cert_status->device_info().ShortDebugString();
} else {
VLOG(2) << "Not allowing TEST ONLY device with systemId = "
<< client_cert.system_id() << ", provider = " << provider
<< ", device info = "
<< device_cert_status->device_info().ShortDebugString();
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() !=
device_cert_status->drm_serial_number())) {
// Widevine-provisioned device, and the intermediate certificate serial
// number does not match that in the status list. If the status list is
// newer than the certificate, indicate an invalid certificate, so that
// the device re-provisions. If, on the other hand, the certificate status
// list is older than the certificate, the certificate is for all purposes
// unknown.
if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"intermediate-certificate-serial-number-mismatch");
}
return client_cert.SystemIdUnknownError();
}
return OkStatus();
}
bool DeviceStatusList::GetDeviceInfo(const ClientCert& client_cert,
ProvisionedDeviceInfo* device_info) {
CHECK(device_info);
absl::ReaderMutexLock lock(&status_map_lock_);
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, client_cert.system_id());
if (device_cert_status != nullptr) {
*device_info = device_cert_status->device_info();
return true;
}
return false;
}
bool DeviceStatusList::GetRevokedIdentifiers(
uint32_t system_id,
DeviceCertificateStatus::RevokedIdentifiers* revoked_identifiers) {
CHECK(revoked_identifiers);
absl::ReaderMutexLock lock(&status_map_lock_);
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, system_id);
if (device_cert_status) {
*revoked_identifiers = device_cert_status->revoked_identifiers();
return true;
}
return false;
}
bool DeviceStatusList::IsSystemIdActive(uint32_t system_id) {
absl::ReaderMutexLock lock(&status_map_lock_);
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, system_id);
if (!device_cert_status) {
return allow_unknown_devices_ ||
KeyboxClientCert::IsSystemIdKnown(system_id);
}
if (device_cert_status->status() ==
DeviceCertificateStatus::STATUS_TEST_ONLY) {
return allow_test_only_devices_;
}
if (device_cert_status) {
ProvisionedDeviceInfo device_info = device_cert_status->device_info();
if (device_cert_status->status() ==
DeviceCertificateStatus::STATUS_REVOKED) {
if (IsRevokedSystemIdAllowed(system_id)) {
LOG(WARNING) << "REVOKED system_id: " << system_id
<< " is allowed to be active";
return true;
}
}
}
return device_cert_status->status() !=
DeviceCertificateStatus::STATUS_REVOKED;
}
uint32_t DeviceStatusList::GetCurrentTime() const { return time(nullptr); }
void DeviceStatusList::AllowRevokedDevices(const std::string& system_id_list) {
for (absl::string_view sp : absl::StrSplit(system_id_list, ',')) {
allowed_revoked_devices_.push_back(std::stoi(std::string(sp)));
}
std::sort(allowed_revoked_devices_.begin(), allowed_revoked_devices_.end());
}
void DeviceStatusList::AllowTestOnlyDevicesByMake(
const std::string& device_list_by_make) {
absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_);
if (device_list_by_make.empty()) {
allowed_test_only_devices_by_make_.clear();
return;
}
for (absl::string_view device : absl::StrSplit(device_list_by_make, ',')) {
const std::pair<absl::string_view, absl::string_view> device_split =
absl::StrSplit(device, ':');
if (device_split.second.empty() || device_split.second == "*") {
allowed_test_only_devices_by_make_.emplace(
std::stoi(std::string(device_split.first)), "*");
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first)) << ", make *";
} else {
allowed_test_only_devices_by_make_.emplace(
std::stoi(std::string(device_split.first)),
absl::AsciiStrToUpper(device_split.second));
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first))
<< ", make = " << absl::AsciiStrToUpper(device_split.second);
}
}
}
void DeviceStatusList::AllowTestOnlyDevicesByProvider(
const std::string& device_list_by_provider) {
absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_);
if (device_list_by_provider.empty()) {
allowed_test_only_devices_by_provider_.clear();
return;
}
for (absl::string_view device :
absl::StrSplit(device_list_by_provider, ',')) {
const std::pair<absl::string_view, absl::string_view> device_split =
absl::StrSplit(device, ':');
if (device_split.second.empty() || device_split.second == "*") {
allowed_test_only_devices_by_provider_.emplace(
std::stoi(std::string(device_split.first)), "*");
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first)) << ", provider *";
} else {
allowed_test_only_devices_by_provider_.emplace(
std::stoi(std::string(device_split.first)),
absl::AsciiStrToUpper(device_split.second));
VLOG(2) << "Allowing TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first))
<< ", provider = " << absl::AsciiStrToUpper(device_split.second);
}
}
}
bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) {
auto it = std::binary_search(allowed_revoked_devices_.begin(),
allowed_revoked_devices_.end(), system_id);
return it;
}
bool DeviceStatusList::IsTestOnlyDeviceAllowedByMake(
uint32_t system_id, const std::string& manufacturer) {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
std::pair<std::multimap<uint32_t, std::string>::iterator,
std::multimap<uint32_t, std::string>::iterator>
allowed_makes = allowed_test_only_devices_by_make_.equal_range(system_id);
for (auto it = allowed_makes.first; it != allowed_makes.second; ++it) {
std::string allowed_makes = (*it).second;
if (allowed_makes == "*" ||
allowed_makes == absl::AsciiStrToUpper(manufacturer)) {
return true;
}
}
return false;
}
bool DeviceStatusList::IsTestOnlyDeviceAllowedByProvider(
uint32_t system_id, const std::string& provider) {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
std::pair<std::multimap<uint32_t, std::string>::iterator,
std::multimap<uint32_t, std::string>::iterator>
allowed_providers =
allowed_test_only_devices_by_provider_.equal_range(system_id);
for (auto it = allowed_providers.first; it != allowed_providers.second;
++it) {
std::string allowed_provider = (*it).second;
if (allowed_provider == "*" ||
allowed_provider == absl::AsciiStrToUpper(provider)) {
return true;
}
}
return false;
}
Status DeviceStatusList::DetermineAndDeserializeServiceResponse(
const std::string& service_response,
DeviceCertificateStatusList* certificate_status_list,
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
if (certificate_status_list == nullptr) {
return Status(error_space, error::INVALID_ARGUMENT,
"certificate_status_list is empty");
} else if (serialized_certificate_status_list == nullptr) {
return Status(error_space, error::INVALID_ARGUMENT,
"serialized_certificate_status_list is empty");
} else if (signature == nullptr) {
return Status(error_space, error::INVALID_ARGUMENT, "signature is empty");
}
// We support three types of payload parsing. The legacy path checks for a
// JSON encoded payload as well as just a plain base64 (web safe or normal)
// payload. If that doesn't match, then the method will try to parse the
// serialized PublishedDeviceInfo proto.
Status status = ExtractPublishedDevicesInfo(
service_response, serialized_certificate_status_list, hash_algorithm,
signature);
// If the payload was not correctly parsed as a PublishedDevices proto.
// then attempt to parse it as a legacy payload.
if (!status.ok()) {
status = ExtractLegacyDeviceList(service_response,
serialized_certificate_status_list,
hash_algorithm, signature);
// The payload could not be parsed in either format, return the failure
// information.
if (!status.ok()) {
return status;
}
}
if (!certificate_status_list->ParseFromString(
*serialized_certificate_status_list)) {
return Status(error_space, widevine::INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
}
return OkStatus();
}
Status DeviceStatusList::ExtractLegacyDeviceList(
const std::string& raw_certificate_provisioning_service_response,
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
// First, attempt to extract the legacy JSON response. Example legacy format.
// "signedList":"<b64 encoded data>"
// where the b64 encoded data is a DeviceCertificateStatusListResponse.
size_t b64_list_response_start =
raw_certificate_provisioning_service_response.find(kSignedList);
std::string serialized_signed_certificate_status_list;
if (b64_list_response_start != std::string::npos) {
size_t b64_list_response_end =
raw_certificate_provisioning_service_response.find(
kSignedListTerminator, b64_list_response_start);
if (b64_list_response_end == std::string::npos) {
return Status(
error_space, error::INVALID_ARGUMENT,
"Unable to parse the certificate_provisioning_service_response. "
"SignedList not terminated.");
}
std::string signed_list(
raw_certificate_provisioning_service_response.begin() +
b64_list_response_start + kSignedListLen,
raw_certificate_provisioning_service_response.begin() +
b64_list_response_end);
// Strip off quotes.
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\"'),
signed_list.end());
// Strip off spaces.
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), ' '),
signed_list.end());
// Strip off newlines.
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\n'),
signed_list.end());
// Strip off carriage return (the control-M character)
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\r'),
signed_list.end());
if (!absl::WebSafeBase64Unescape(
signed_list, &serialized_signed_certificate_status_list)) {
if (!absl::Base64Unescape(signed_list,
&serialized_signed_certificate_status_list)) {
return Status(error_space, error::INVALID_ARGUMENT,
"Base64 decode of signedlist failed.");
}
}
} else {
// If this was not a legacy JSON response, attempt to deserialize the base64
// response.
if (!absl::WebSafeBase64Unescape(
raw_certificate_provisioning_service_response,
&serialized_signed_certificate_status_list)) {
if (!absl::Base64Unescape(raw_certificate_provisioning_service_response,
&serialized_signed_certificate_status_list)) {
return Status(error_space, error::INVALID_ARGUMENT,
"Base64 decode of certList failed.");
}
}
}
// Attempt to parse the legacy serialized signed status list into the proto
// and extract the serialized status list and signature.
return ParseLegacySignedDeviceCertificateStatusList(
serialized_signed_certificate_status_list,
serialized_certificate_status_list, hash_algorithm, signature);
}
Status DeviceStatusList::ExtractPublishedDevicesInfo(
const std::string& serialized_published_devices,
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
// TODO(b/139067045): Change from using the SignedDeviceInfo proto
// to using the correct proto from the API. This duplicate, wire-compatible
// proto was a temporary way to workaround Proto2/Proto3 compatibility issues.
SignedDeviceInfo devices_info;
if (!devices_info.ParseFromString(serialized_published_devices)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"published-devices-info-parse-error");
}
*serialized_certificate_status_list =
devices_info.device_certificate_status_list();
*hash_algorithm = HashAlgorithmProtoToEnum(devices_info.hash_algorithm());
*signature = devices_info.signature();
return OkStatus();
}
Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
const std::string& version,
const std::string& serialized_service_certificate,
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());
request.set_service_certificate(serialized_service_certificate);
std::string device_certificate_status_list_request;
request.SerializeToString(&device_certificate_status_list_request);
SignedDeviceInfoRequest 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::SERVICE_CERTIFICATE_NOT_FOUND,
"Drm service certificate is not loaded.");
}
const RsaPrivateKey* private_key = sc->private_key();
if (private_key == nullptr) {
return Status(error_space, widevine::INVALID_SERVICE_PRIVATE_KEY,
"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();
}
Status DeviceStatusList::ParseLegacySignedDeviceCertificateStatusList(
const std::string& serialized_signed_device_certificate_status_list,
std::string* serialized_device_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature) {
// Parse the serialized_signed_device_certificate_status_list to extract the
// serialized_device_certificate_status_list
SignedDeviceCertificateStatusList signed_device_list;
if (!signed_device_list.ParseFromString(
serialized_signed_device_certificate_status_list)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
if (signed_device_list.certificate_status_list().empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
}
if (signed_device_list.signature().empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list-signature");
}
*serialized_device_certificate_status_list =
signed_device_list.certificate_status_list();
*hash_algorithm =
HashAlgorithmProtoToEnum(signed_device_list.hash_algorithm());
*signature = signed_device_list.signature();
return OkStatus();
}
void DeviceStatusList::RevokedDrmCertificateSerialNumbers(
const std::string& drm_certificate_serial_numbers) {
for (absl::string_view drm_certificate_serial_number :
absl::StrSplit(drm_certificate_serial_numbers, ',')) {
revoked_drm_certificate_serial_numbers_.insert(
std::string(drm_certificate_serial_number));
}
}
bool DeviceStatusList::IsDrmCertificateRevoked(
const std::string& device_certificate_serial_number) {
if (revoked_drm_certificate_serial_numbers_.find(
device_certificate_serial_number) !=
revoked_drm_certificate_serial_numbers_.end()) {
return true;
}
return false;
}
Status DeviceStatusList::GetDeviceCertificateStatusBySystemId(
uint32_t system_id, DeviceCertificateStatus* device_certificate_status) {
absl::ReaderMutexLock lock(&status_map_lock_);
if (expiration_period_seconds_ &&
(GetCurrentTime() >
(creation_time_seconds_ + expiration_period_seconds_))) {
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
}
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, system_id);
if (device_cert_status == nullptr) {
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
} else {
*device_certificate_status = *device_cert_status;
}
return OkStatus();
}
} // namespace widevine

View File

@@ -1,279 +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.
////////////////////////////////////////////////////////////////////////////////
// DeviceStatusList class header.
#ifndef COMMON_DEVICE_STATUS_LIST_H__
#define COMMON_DEVICE_STATUS_LIST_H__
#include <map>
#include <set>
#include <string>
#include "absl/synchronization/mutex.h"
#include "common/hash_algorithm.h"
#include "common/status.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
namespace widevine {
class ClientCert;
// Manages the certificate status of devices. The list of
// DeviceCertificateStatus is provided by the DRM server. Each license
// request is checked to ensure the certificate in the request is valid and
// not revoked. Also checks to see if the intermediate certificates were
// updated where the system Id is the same, but the serial number changes.
// This case should cause the clients to re-provision.
class DeviceStatusList {
public:
// Returns a pointer to a singleton DeviceStatusList.
static DeviceStatusList* Instance();
DeviceStatusList();
DeviceStatusList(const DeviceStatusList&) = delete;
DeviceStatusList& operator=(const DeviceStatusList&) = delete;
virtual ~DeviceStatusList();
// Takes |serialized_device_certificate_status_list| and copies to an
// internal map of device certificate status list. The internal map is used
// to verify a device was not revoked. Returns true is the list was
// successfully parsed.
Status UpdateStatusList(
const std::string& root_certificate_public_key,
const std::string& serialized_device_certificate_status_list,
HashAlgorithm hash_algorithm, const std::string& signature,
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) {
allow_test_only_devices_ = allow;
}
bool allow_test_only_devices() const { return allow_test_only_devices_; }
// Checks the device status list and handles the case when a TEST_ONLY device
// made the request. Returns one of
// OK
// UNSUPPORTED_SYSTEM_ID
// INVALID_DRM_CERTIFICATE
// DRM_DEVICE_CERTIFICATE_REVOKED
// DRM_DEVICE_CERTIFICATE_UNKNOWN
// DEVELOPMENT_CERTIFICATE_NOT_ALLOWED
// |provider| is the service provider making the license request.
// If status is OK, a copy of the device certificate status is copied
// into |device_certificate_status|. Caller owns |device_certificate_status|
// and it must not be null.
Status GetCertStatus(
const ClientCert& client_cert, const std::string& make,
const std::string& provider, bool allow_revoked_system_id,
widevine::DeviceCertificateStatus* device_certificate_status);
// 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);
// Returns true if the system ID
// Returns true is a ProvisionedDeviceInfo exist based on <client_cert>.
// Caller owns <device_info> and it must not be null.
bool GetDeviceInfo(const ClientCert& client_cert,
widevine::ProvisionedDeviceInfo* device_info);
// Returns true if device certificate status list contains revoked_identifiers
// with specific |system_id|.
// Caller owns <revoked_identifiers> and it must not be null.
bool GetRevokedIdentifiers(
uint32_t system_id,
DeviceCertificateStatus::RevokedIdentifiers* revoked_identifiers);
// Returns the current POSIX time.
virtual uint32_t GetCurrentTime() const;
// Enable delivery of licenses to revoked client devices. |system_id_list| is
// a comma separated list of systems Ids to allow even if revoked.
virtual void AllowRevokedDevices(const std::string& system_id_list);
// Enable delivery of licenses to TEST_ONLY client devices. |device_list| is
// a comma separated list of devices to allow even if the device state is
// TEST_ONLY. Each device is specified by a colon separated system_id and
// manufacturer. If the manufacturer is not specified, all manufacturers for
// that system_id are allowed.
// 'device_list' is expected to be of the format <device>,<device>..., and
// each 'device' will contain a 'system_id' and 'manufacturer' OR will contain
// only a 'system_id'.
// 'device' is expected to be of the format <system_id>:<manufacturer> OR
// of the format <system_id>:
// Example usage:
// const std::string device_list = "4121:LG,7912:*"
// AllowTestOnlyDevicesByMake(device_list_by_make);
virtual void AllowTestOnlyDevicesByMake(
const std::string& device_list_by_make);
// Same as above, except by providers instead of by manufacturers.
// Example usage:
// const std::string device_list = "4121:YouTube,4121:AndroidVideo"
// AllowTestOnlyDevicesByProvider(device_list);
virtual void AllowTestOnlyDevicesByProvider(
const std::string& device_list_by_provider);
// A comma separated list of DRM Certificate Serial Numbers that are revoked.
virtual void RevokedDrmCertificateSerialNumbers(
const std::string& drm_certificate_serial_numbers);
// Return true, if the specified |device_certificate_serial_number| was
// revoked ... else, false.
bool IsDrmCertificateRevoked(
const std::string& device_certificate_serial_number);
// Returns OK if |system_id| was found in the device certificate status list
// and |device_certificate_status| is populated. If |system_id| is not found,
// this call returns an error.
virtual Status GetDeviceCertificateStatusBySystemId(
uint32_t system_id, DeviceCertificateStatus* device_certificate_status);
// Parses the serialized certificate status list and the signature from the
// service_response. The service_response is the JSON payload that comes
// in the response to a certificate status list request. Both the legacy
// format and the newer SignedDeviceInfo format are supported.
//
// |service_response| is the response provided from the Widevine API that
// produces the certificate list. The response can be in one of a few
// formats:
// 1) The JSON response from the legacy API.
// 2) The Base 64 encoded payload within the JSON response that contains
// the serialized certificate list (Web safe or regular base64).
// 3) The raw bytes of the serialized PublishedDevices proto returned from
// the new Widevine API that generates the serialized certificate list.
// The |certificate_status_list| is the deserialized list from the
// service_response.
// The |serialized_certificate_status_list| is the binary serialized status
// list. This is an out parameter which allows the caller to verify the
// serialized proto against the |signature|.
// The |signature| is the signature of the serialized_certificate_status_list
// using RSASSA-PSS signed with the root certificate private key.
// The |hash_algorithm| is the hash algorithm used in signature.
// Returns WvPLStatus - Status::OK if success, else error.
static Status DetermineAndDeserializeServiceResponse(
const std::string& service_response,
DeviceCertificateStatusList* certificate_status_list,
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
/**
* 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,
const std::string& serialized_service_certificate,
std::string* signed_device_certificate_status_list_request);
// Returns true if the system ID is allowed to be revoked.
// Caller owns |system_id|. They must not be null.
bool IsRevokedSystemIdAllowed(uint32_t system_id);
// Returns true if the device, which is identified by system_id and
// device_manufacturer, is present in |allowed_test_only_devices_by_make_|.
bool IsTestOnlyDeviceAllowedByMake(uint32_t system_id,
const std::string& device_manufacturer);
// Returns true if the device, which is identified by system_id and
// provider, is present in |allowed_test_only_devices_by_provider_|.
bool IsTestOnlyDeviceAllowedByProvider(uint32_t system_id,
const std::string& provider);
private:
friend class DeviceStatusListTest;
/**
* Parses the serialized legacy device certificate status list and signature.
* The certificate_provisioning_service_response is the JSON payload that
* comes in the response to a certificate status list request.
*
* @param legacy_certificate_provisioning_service_response
* @param serialized_certificate_status_list
* @param hash_algorithm
* @param signature
* @return WvPLStatus - Status::OK if success, else error.
*/
static Status ExtractLegacyDeviceList(
const std::string& raw_certificate_provisioning_service_response,
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
/**
* Parses the serialized published devices response.
* The published_devices_info_response is the JSON payload that comes in the
* response to a PublishedDevices request.
*
* @param published_devices_response the serialized PublishedDevices proto
* containing the certificate status list.
* @param serialized_certificate_status_list
* @param hash_algorithm
* @param signature
* @return WvPLStatus - Status::OK if success, else error.
*/
static Status ExtractPublishedDevicesInfo(
const std::string& serialized_published_devices,
std::string* serialized_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
/**
* Returns a |serialized_device_certificate_status_list| in its output
* parameter by parsing |serialized_signed_device_certificate_status_list|
* returned from Widevine Certificate Provisioning Server.
*
* @param serialized_signed_device_certificate_status_list
* @param serialized_device_certificate_status_list
* @param hash_algorithm
* @return Status - Status::OK if success, else error.
*/
static Status ParseLegacySignedDeviceCertificateStatusList(
const std::string& serialized_signed_device_certificate_status_list,
std::string* serialized_device_certificate_status_list,
HashAlgorithm* hash_algorithm, std::string* signature);
virtual size_t allowed_test_only_devices_by_make_size() {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
return allowed_test_only_devices_by_make_.size();
}
virtual size_t allowed_test_only_devices_by_provider_size() {
absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
return allowed_test_only_devices_by_provider_.size();
}
mutable absl::Mutex status_map_lock_;
// Key is the system id for the device.
std::map<uint32_t, widevine::DeviceCertificateStatus> device_status_map_
ABSL_GUARDED_BY(status_map_lock_);
uint32_t creation_time_seconds_ = 0;
uint32_t expiration_period_seconds_ = 0;
bool allow_unknown_devices_ = false;
bool allow_test_only_devices_ = false;
// Contains the list of system_id values that are allowed to succeed even if
// revoked.
std::vector<uint32_t> allowed_revoked_devices_;
mutable absl::Mutex allowed_test_only_devices_mutex_;
// Contains a map of 'system_id' to 'manufacturer'. If manufacturer value is
// "*", any manufacturer using that system_id is allowed.
std::multimap<uint32_t, std::string> allowed_test_only_devices_by_make_
ABSL_GUARDED_BY(allowed_test_only_devices_mutex_);
// Contains a map of 'system_id' to 'provider'. If provider value is "*", any
// provider using that system_id is allowed.
std::multimap<uint32_t, std::string> allowed_test_only_devices_by_provider_
ABSL_GUARDED_BY(allowed_test_only_devices_mutex_);
// Revoked DRM certificate serial numbers.
std::set<std::string> revoked_drm_certificate_serial_numbers_;
};
} // namespace widevine
#endif // COMMON_DEVICE_STATUS_LIST_H__

View File

@@ -1,918 +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 "common/device_status_list.h"
#include <stddef.h>
#include <memory>
#include <type_traits>
#include <utility>
#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 "absl/strings/str_cat.h"
#include "common/client_cert.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/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_device_info.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace {
const char kTestSystemId_1[] = "4121";
const char kTestSystemId_2[] = "8242";
const char kTestSystemId_3[] = "6556";
const char kTestManufacturer[] = "TestManufacturer";
const char kTestProvider[] = "TestProvider";
const char kRevokedManufacturer[] = "RevokedManufacturer";
const widevine::HashAlgorithm kHashAlgorithm =
widevine::HashAlgorithm::kSha256;
} // namespace
namespace widevine {
using ::testing::Return;
using ::testing::ReturnRef;
const uint32_t kValidCertSystemId = 100;
const uint32_t kRevokedCertSystemId = 101;
const uint32_t kValidPpkSystemId = 102;
const uint32_t kTestOnlyCertSystemId = 103;
const uint32_t kRevokedAllowedDeviceCertSystemId = 104;
const uint32_t kUnknownSystemId = 666;
const char kValidSerialNumber[] = "valid-serial-number";
const char kRevokedSerialNumber[] = "revoked-serial-number";
const char kRevokedAllowDeviceSerialNumber[] =
"revoked-allow-device-serial-number";
const char kRevokedDeviceCertificateSerialNumber1[] = "revoked-serial-number_1";
const char kRevokedDeviceCertificateSerialNumber2[] = "revoked-serial-number_2";
const char kRevokedDeviceCertificateSerialNumber3[] = "revoked-serial-number_3";
const char kRevokedUniqueIdentifiers[] = "revoked-unique-identifiers";
const char kTestOnlySerialNumber[] = "test_only-serial-number";
const char kMismatchSerialNumber[] = "mismatch-serial-number";
const char kDeviceModel[] = "device-model-x";
const char kRevokedDeviceModel[] = "device-model-revoked";
const char kTestPreprovKey[] = "00112233445566778899aabbccddeeff";
const uint32_t kStatusListCreationTime = 17798001;
const uint32_t kDefaultExpirePeriod = 0;
const bool kDenyRevokedDevice = false;
const bool kAllowRevokedDevice = true;
class MockClientCert : public ClientCert {
public:
MockClientCert() {}
~MockClientCert() override {}
MOCK_METHOD(uint32_t, system_id, (), (const, override));
MOCK_METHOD(std::string &, signer_serial_number, (), (const, override));
MOCK_METHOD(uint32_t, signer_creation_time_seconds, (), (const, override));
MOCK_METHOD(ClientIdentification::TokenType, type, (), (const, override));
MOCK_METHOD(const std::string &, encrypted_unique_id, (), (const, override));
MOCK_METHOD(const std::string &, unique_id_hash, (), (const, override));
MOCK_METHOD(bool, signed_by_provisioner, (), (const, override));
MOCK_METHOD(Status, VerifySignature,
(const std::string &message, HashAlgorithm hash_algorithm,
const std::string &signature, ProtocolVersion protocol_version),
(const, override));
MOCK_METHOD(void, GenerateSigningKey,
(const std::string &message, ProtocolVersion protocol_version),
(override));
MOCK_METHOD(const std::string &, serial_number, (), (const, override));
MOCK_METHOD(const std::string &, key, (), (const, override));
MOCK_METHOD(SignedMessage::SessionKeyType, key_type, (), (const, override));
MOCK_METHOD(bool, using_dual_certificate, (), (const override));
MOCK_METHOD(const std::string &, service_id, (), (const, override));
MOCK_METHOD(const std::string &, encrypted_key, (), (const, override));
MOCK_METHOD(const std::string &, signing_key, (), (const, override));
MOCK_METHOD(Status, SystemIdUnknownError, (), (const, override));
MOCK_METHOD(Status, SystemIdRevokedError, (), (const, override));
};
class DeviceStatusListTest : public ::testing::Test {
public:
~DeviceStatusListTest() override {}
void SetUp() override {
DeviceCertificateStatus *cert_status;
// Device cert with status RELEASED.
cert_status = cert_status_list_.add_certificate_status();
cert_status->mutable_device_info()->set_system_id(kValidCertSystemId);
cert_status->set_drm_serial_number(kValidSerialNumber);
cert_status->mutable_device_info()->set_model(kDeviceModel);
cert_status->set_status(DeviceCertificateStatus::STATUS_RELEASED);
cert_status->mutable_revoked_identifiers()->add_revoked_unique_id_hashes(
kRevokedUniqueIdentifiers);
cert_status->mutable_revoked_identifiers()
->add_revoked_certificate_serial_numbers(kRevokedSerialNumber);
// Device cert with status REVOKED.
cert_status = cert_status_list_.add_certificate_status();
cert_status->mutable_device_info()->set_system_id(kRevokedCertSystemId);
cert_status->set_drm_serial_number(kRevokedSerialNumber);
cert_status->mutable_device_info()->set_model(kRevokedDeviceModel);
cert_status->set_status(DeviceCertificateStatus::STATUS_REVOKED);
// Device cert with status REVOKED ALLOWED DEVICE.
cert_status = cert_status_list_.add_certificate_status();
cert_status->mutable_device_info()->set_system_id(
kRevokedAllowedDeviceCertSystemId);
cert_status->set_drm_serial_number(kRevokedAllowDeviceSerialNumber);
cert_status->set_status(DeviceCertificateStatus::STATUS_REVOKED);
device_status_list_.AllowRevokedDevices(
absl::StrCat(kRevokedAllowedDeviceCertSystemId));
// Device cert with status TEST_ONLY.
cert_status = cert_status_list_.add_certificate_status();
cert_status->mutable_device_info()->set_system_id(kTestOnlyCertSystemId);
cert_status->set_drm_serial_number(kTestOnlySerialNumber);
cert_status->set_status(DeviceCertificateStatus::STATUS_TEST_ONLY);
cert_status_list_.set_creation_time_seconds(kStatusListCreationTime);
// Generate the serialized list and signature.
std::unique_ptr<RsaPrivateKey> root_key(
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits()));
ASSERT_TRUE(root_key);
cert_status_list_.SerializeToString(&serialized_cert_status_list_);
ASSERT_TRUE(root_key->GenerateSignature(serialized_cert_status_list_,
kHashAlgorithm,
&cert_status_list_signature_));
// Update the device_status_list_ with the serialized status list
// and signature.
ASSERT_EQ(OkStatus(),
device_status_list_.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, kDefaultExpirePeriod));
}
void GenerateTrivialValidStatusList(std::string *serialized_cert_status_list,
HashAlgorithm hash_algorithm,
std::string *signature) {
DeviceCertificateStatusList cert_status_list;
DeviceCertificateStatus *cert_status;
// Device cert with status RELEASED.
cert_status = cert_status_list.add_certificate_status();
cert_status->mutable_device_info()->set_system_id(kValidCertSystemId);
cert_status->set_drm_serial_number(kValidSerialNumber);
cert_status->mutable_device_info()->set_model(kDeviceModel);
cert_status->set_status(DeviceCertificateStatus::STATUS_RELEASED);
cert_status_list.set_creation_time_seconds(kStatusListCreationTime);
// Generate the serialized list and signature.
std::unique_ptr<RsaPrivateKey> root_key(
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits()));
ASSERT_TRUE(root_key);
cert_status_list.SerializeToString(serialized_cert_status_list);
ASSERT_TRUE(root_key->GenerateSignature(*serialized_cert_status_list,
hash_algorithm, signature));
}
int AllowedTestOnlyDevicesByMakeSize() {
return device_status_list_.allowed_test_only_devices_by_make_size();
}
int AllowedTestOnlyDevicesByProviderSize() {
return device_status_list_.allowed_test_only_devices_by_provider_size();
}
bool IsTestOnlyDeviceAllowedByMake(uint32_t system_id,
const std::string &make) {
return device_status_list_.IsTestOnlyDeviceAllowedByMake(system_id, make);
}
bool IsTestOnlyDeviceAllowedByProvider(uint32_t system_id,
const std::string &provider) {
return device_status_list_.IsTestOnlyDeviceAllowedByProvider(system_id,
provider);
}
int VerifyRevokedDeviceCertificatesCount() {
return device_status_list_.revoked_drm_certificate_serial_numbers_.size();
}
bool VerifyIsDeviceCertificateRevoked(
std::string device_certificate_serial_number) {
return device_status_list_.IsDrmCertificateRevoked(
device_certificate_serial_number);
}
DeviceStatusList device_status_list_;
RsaTestKeys test_keys_;
DeviceCertificateStatusList cert_status_list_;
std::string serialized_cert_status_list_;
std::string cert_status_list_signature_;
};
TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) {
// Test case where the Certificate status is set to Valid.
DeviceCertificateStatus device_certificate_status;
MockClientCert valid_client_cert;
std::string valid_drm_serial_number(kValidSerialNumber);
EXPECT_CALL(valid_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(valid_client_cert, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(valid_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(
valid_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
EXPECT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
// Test case where the Certificate status is Revoked.
MockClientCert revoked_client_cert;
std::string revoked_drm_serial_number(kRevokedSerialNumber);
EXPECT_CALL(revoked_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(revoked_client_cert, system_id())
.WillRepeatedly(Return(kRevokedCertSystemId));
EXPECT_CALL(revoked_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(revoked_drm_serial_number));
EXPECT_CALL(revoked_client_cert, SystemIdRevokedError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, "")));
EXPECT_EQ(
DRM_DEVICE_CERTIFICATE_REVOKED,
device_status_list_
.GetCertStatus(revoked_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
// Test case where the revoked cert is allowed.
device_status_list_.AllowRevokedDevices(absl::StrCat(kRevokedCertSystemId));
EXPECT_OK(device_status_list_.GetCertStatus(
revoked_client_cert, kTestManufacturer, kTestProvider, kDenyRevokedDevice,
&device_certificate_status));
}
TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) {
DeviceCertificateStatus device_certificate_status;
MockClientCert test_only_client_cert;
std::string test_only_drm_serial_number(kTestOnlySerialNumber);
EXPECT_CALL(test_only_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(test_only_client_cert, system_id())
.WillRepeatedly(Return(kTestOnlyCertSystemId));
EXPECT_CALL(test_only_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
EXPECT_EQ(DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
device_status_list_
.GetCertStatus(test_only_client_cert, kTestManufacturer,
kTestProvider, kDenyRevokedDevice,
&device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest, GetRevokedIfentifiers) {
DeviceCertificateStatus::RevokedIdentifiers revoked_identifiers;
ASSERT_TRUE(device_status_list_.GetRevokedIdentifiers(kValidCertSystemId,
&revoked_identifiers));
EXPECT_EQ(kRevokedSerialNumber,
revoked_identifiers.revoked_certificate_serial_numbers(0));
EXPECT_EQ(kRevokedUniqueIdentifiers,
revoked_identifiers.revoked_unique_id_hashes(0));
ASSERT_FALSE(device_status_list_.GetRevokedIdentifiers(kUnknownSystemId,
&revoked_identifiers));
}
TEST_F(DeviceStatusListTest, TestOnlyCertAllowed) {
DeviceCertificateStatus device_certificate_status;
MockClientCert test_only_client_cert;
std::string test_only_drm_serial_number(kTestOnlySerialNumber);
device_status_list_.set_allow_test_only_devices(true);
EXPECT_CALL(test_only_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(test_only_client_cert, system_id())
.WillRepeatedly(Return(kTestOnlyCertSystemId));
EXPECT_CALL(test_only_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(
test_only_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
}
TEST_F(DeviceStatusListTest, RevokedSystemIdAllowed) {
DeviceCertificateStatus device_certificate_status;
MockClientCert revoked_client_cert;
std::string revoked_drm_serial_number(kRevokedSerialNumber);
EXPECT_CALL(revoked_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(revoked_client_cert, system_id())
.WillRepeatedly(Return(kRevokedCertSystemId));
EXPECT_CALL(revoked_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(revoked_drm_serial_number));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(
revoked_client_cert, kRevokedManufacturer, kTestProvider,
kAllowRevokedDevice, &device_certificate_status));
}
// Test case where the Certificate status is set to Valid.
TEST_F(DeviceStatusListTest, ValidKeybox) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(std::make_pair(kValidCertSystemId, kTestPreprovKey));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
DeviceCertificateStatus device_certificate_status;
MockClientCert valid_client_keybox;
std::string valid_drm_serial_number(kValidSerialNumber);
EXPECT_CALL(valid_client_keybox, type())
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(valid_client_keybox, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(
valid_client_keybox, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
ASSERT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
}
// Test case where the keybox was not loaded into the pre-prov list.
TEST_F(DeviceStatusListTest, UnknownKeybox) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(std::make_pair(kValidCertSystemId, kTestPreprovKey));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
DeviceCertificateStatus device_certificate_status;
MockClientCert unknown_client_keybox;
EXPECT_CALL(unknown_client_keybox, type())
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(unknown_client_keybox, system_id())
.WillRepeatedly(Return(kUnknownSystemId));
EXPECT_CALL(unknown_client_keybox, SystemIdUnknownError())
.WillRepeatedly(Return(Status(error_space, UNSUPPORTED_SYSTEM_ID, "")));
EXPECT_EQ(UNSUPPORTED_SYSTEM_ID,
device_status_list_
.GetCertStatus(unknown_client_keybox, kTestManufacturer,
kTestProvider, kDenyRevokedDevice,
&device_certificate_status)
.error_code());
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
ASSERT_FALSE(device_info.has_model());
}
// Test case where the keybox was loaded into the pre-prov list but it's
// certificate status is REVOKED.
TEST_F(DeviceStatusListTest, RevokedKeybox) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(std::make_pair(kRevokedCertSystemId, kTestPreprovKey));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
DeviceCertificateStatus device_certificate_status;
MockClientCert revoked_client_keybox;
EXPECT_CALL(revoked_client_keybox, type())
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(revoked_client_keybox, system_id())
.WillRepeatedly(Return(kRevokedCertSystemId));
EXPECT_CALL(revoked_client_keybox, SystemIdRevokedError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED, "")));
EXPECT_EQ(DRM_DEVICE_CERTIFICATE_REVOKED,
device_status_list_
.GetCertStatus(revoked_client_keybox, kTestManufacturer,
kTestProvider, kDenyRevokedDevice,
&device_certificate_status)
.error_code());
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
ASSERT_TRUE(device_info.has_model());
EXPECT_EQ(kRevokedDeviceModel, device_info.model());
}
TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
device_status_list_.set_allow_unknown_devices(true);
// Test case where the signer certificate is older than the current status
// list.
MockClientCert older_client_cert;
DeviceCertificateStatus device_certificate_status;
std::string mismatch_drm_serial_number(kMismatchSerialNumber);
EXPECT_CALL(older_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(older_client_cert, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(older_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(mismatch_drm_serial_number));
EXPECT_CALL(older_client_cert, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime - 1));
EXPECT_EQ(
INVALID_DRM_CERTIFICATE,
device_status_list_
.GetCertStatus(older_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
// 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(OkStatus(), device_status_list_.GetCertStatus(
older_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
ProvisionedDeviceInfo device_info = device_certificate_status.device_info();
EXPECT_TRUE(device_info.has_system_id());
EXPECT_EQ(kValidCertSystemId, device_info.system_id());
// Test case where the signer certificate is newer than the current status
// list, and unknown devices are allowed.
device_certificate_status.Clear();
MockClientCert newer_client_cert1;
EXPECT_CALL(newer_client_cert1, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(newer_client_cert1, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(newer_client_cert1, signer_serial_number())
.WillRepeatedly(ReturnRef(mismatch_drm_serial_number));
EXPECT_CALL(newer_client_cert1, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime));
EXPECT_CALL(newer_client_cert1, SystemIdUnknownError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, "")));
EXPECT_EQ(
DRM_DEVICE_CERTIFICATE_UNKNOWN,
device_status_list_
.GetCertStatus(newer_client_cert1, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
// Test case where the signer certificate is newer than the current status
// list, and unknown devices are not allowed.
device_certificate_status.Clear();
device_status_list_.set_allow_unknown_devices(false);
MockClientCert newer_client_cert2;
EXPECT_CALL(newer_client_cert2, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(newer_client_cert2, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(newer_client_cert2, signer_serial_number())
.WillRepeatedly(ReturnRef(mismatch_drm_serial_number));
EXPECT_CALL(newer_client_cert2, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime + 1));
EXPECT_CALL(newer_client_cert2, SystemIdUnknownError())
.WillRepeatedly(
Return(Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN, "")));
EXPECT_EQ(
DRM_DEVICE_CERTIFICATE_UNKNOWN,
device_status_list_
.GetCertStatus(newer_client_cert2, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest, InvalidStatusList) {
EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST,
device_status_list_
.UpdateStatusList(test_keys_.public_test_key_2_2048_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 0)
.error_code());
++(serialized_cert_status_list_)[4];
EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST,
device_status_list_
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 0)
.error_code());
}
class MockDeviceStatusList : public DeviceStatusList {
public:
MOCK_METHOD(uint32_t, GetCurrentTime, (), (const, override));
};
TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) {
MockDeviceStatusList mock_device_status_list;
EXPECT_CALL(mock_device_status_list, GetCurrentTime())
.Times(2)
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100));
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100)
.error_code());
}
TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
MockDeviceStatusList mock_device_status_list;
EXPECT_CALL(mock_device_status_list, GetCurrentTime())
.Times(3)
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100));
DeviceCertificateStatus device_certificate_status;
MockClientCert valid_client_cert;
std::string valid_drm_serial_number(kValidSerialNumber);
EXPECT_CALL(valid_client_cert, type())
.WillRepeatedly(Return(ClientIdentification::DRM_DEVICE_CERTIFICATE));
EXPECT_CALL(valid_client_cert, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(valid_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
EXPECT_CALL(valid_client_cert, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime - 1));
EXPECT_EQ(OkStatus(), mock_device_status_list.GetCertStatus(
valid_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status));
EXPECT_EQ(
EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.GetCertStatus(valid_client_cert, kTestManufacturer, kTestProvider,
kDenyRevokedDevice, &device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest, IsSystemIdActive) {
std::multimap<uint32_t, std::string> preprov_keys;
preprov_keys.insert(
std::make_pair(kValidPpkSystemId, "00112233445566778899aabbccddeeff"));
KeyboxClientCert::SetPreProvisioningKeys(preprov_keys);
device_status_list_.set_allow_unknown_devices(false);
EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidCertSystemId));
EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidPpkSystemId));
EXPECT_FALSE(device_status_list_.IsSystemIdActive(kRevokedCertSystemId));
EXPECT_FALSE(device_status_list_.IsSystemIdActive(kUnknownSystemId));
device_status_list_.set_allow_unknown_devices(true);
EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidCertSystemId));
EXPECT_TRUE(device_status_list_.IsSystemIdActive(kValidPpkSystemId));
EXPECT_FALSE(device_status_list_.IsSystemIdActive(kRevokedCertSystemId));
EXPECT_TRUE(device_status_list_.IsSystemIdActive(kUnknownSystemId));
EXPECT_TRUE(
device_status_list_.IsSystemIdActive(kRevokedAllowedDeviceCertSystemId));
}
TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowedByMake) {
const char kTestManufacturer_AA[] = "AA";
const char kTestManufacturer_AAA[] = "AAA";
const char kTestManufacturer_BBB[] = "BBB";
const char kTestManufacturer_BbB[] = "BbB";
const char kTestManufacturer_bbb[] = "bbb";
const char kTestManufacturer_CCC[] = "CCC";
const char kTestManufacturer_DDD[] = "AAA";
std::string allowed_device_list =
std::string(kTestSystemId_1) + ":" + std::string(kTestManufacturer_AA);
allowed_device_list += "," + std::string(kTestSystemId_2) + ":" +
std::string(kTestManufacturer_BBB);
allowed_device_list += "," + std::string(kTestSystemId_3) + ":";
allowed_device_list += ", " + std::string(kTestSystemId_1) + ":" +
std::string(kTestManufacturer_AAA);
device_status_list_.AllowTestOnlyDevicesByMake(allowed_device_list);
EXPECT_EQ(4, AllowedTestOnlyDevicesByMakeSize());
// Verify that device with system_id = kTestSystemId_1 and
// manufacturer AA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_1),
kTestManufacturer_AA));
// Verify that device with system_id = kTestSystemId_1 and
// manufacturer AAA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_1),
kTestManufacturer_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// manufacturer AAA is not allowed.
// This is because this combination is not in the allowed list.
EXPECT_FALSE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// manufacturer BBB is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_BBB));
// Verifes that device with mixed case succeeds.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_BbB));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_2),
kTestManufacturer_bbb));
// Verify that device with system_id = kTestSystemId_3 and
// any manufacturer is allowed. This checks that any manufacturer is
// allowed for this system_id.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_3),
kTestManufacturer_CCC));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByMake(std::stoi(kTestSystemId_3),
kTestManufacturer_DDD));
uint32_t unknown_system_id = 7890;
// Verify that device with system_id = unknown_system_id and
// manufacturer CCC is not allowed.
EXPECT_FALSE(
IsTestOnlyDeviceAllowedByMake(unknown_system_id, kTestManufacturer_CCC));
}
TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowedByProvider) {
const char kTestProvider_AA[] = "AA";
const char kTestProvider_AAA[] = "AAA";
const char kTestProvider_BBB[] = "BBB";
const char kTestProvider_BbB[] = "BbB";
const char kTestProvider_bbb[] = "bbb";
const char kTestProvider_CCC[] = "CCC";
std::string allowed_device_list =
std::string(kTestSystemId_1) + ":" + std::string(kTestProvider_AA);
allowed_device_list +=
"," + std::string(kTestSystemId_2) + ":" + std::string(kTestProvider_BBB);
allowed_device_list += "," + std::string(kTestSystemId_3) + ":";
allowed_device_list += ", " + std::string(kTestSystemId_1) + ":" +
std::string(kTestProvider_AAA);
device_status_list_.AllowTestOnlyDevicesByProvider(allowed_device_list);
EXPECT_EQ(4, AllowedTestOnlyDevicesByProviderSize());
// Verify that device with system_id = kTestSystemId_1 and
// provider AA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_1),
kTestProvider_AA));
// Verify that device with system_id = kTestSystemId_1 and
// provider AAA is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_1),
kTestProvider_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// provider AAA is not allowed.
// This is because this combination is not 'whitelisted'.
EXPECT_FALSE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_AAA));
// Verify that device with system_id = kTestSystemId_2 and
// provider BBB is allowed.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_BBB));
// Verifes that device with mixed case succeeds.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_BbB));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_2),
kTestProvider_bbb));
// Verify that device with system_id = kTestSystemId_3 and
// any provider is allowed. This checks that any provider is
// allowed for this system_id.
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_3),
kTestProvider_CCC));
EXPECT_TRUE(IsTestOnlyDeviceAllowedByProvider(std::stoi(kTestSystemId_3),
kTestProvider_AAA));
uint32_t unknown_system_id = 7890;
// Verify that device with system_id = unknown_system_id and
// provider CCC is not allowed.
EXPECT_FALSE(
IsTestOnlyDeviceAllowedByProvider(unknown_system_id, kTestProvider_CCC));
}
TEST_F(DeviceStatusListTest, IsDrmDeviceCertificateRevoked) {
std::string revoked_device_certificate_serial_numbers =
std::string(kRevokedDeviceCertificateSerialNumber1);
revoked_device_certificate_serial_numbers +=
"," + std::string(kRevokedDeviceCertificateSerialNumber2);
revoked_device_certificate_serial_numbers +=
"," + std::string(kRevokedDeviceCertificateSerialNumber3);
device_status_list_.RevokedDrmCertificateSerialNumbers(
revoked_device_certificate_serial_numbers);
EXPECT_EQ(3, VerifyRevokedDeviceCertificatesCount());
// Verify that device certificates with serial number,
// 'kRevokedDeviceCertificateSerialNumber1',
// 'kRevokedDeviceCertificateSerialNumber2',
// 'kRevokedDeviceCertificateSerialNumber3' are revoked.
EXPECT_TRUE(
VerifyIsDeviceCertificateRevoked(kRevokedDeviceCertificateSerialNumber1));
EXPECT_TRUE(
VerifyIsDeviceCertificateRevoked(kRevokedDeviceCertificateSerialNumber2));
EXPECT_TRUE(
VerifyIsDeviceCertificateRevoked(kRevokedDeviceCertificateSerialNumber3));
const std::string unrevoked_device_certificate_serial_number =
"unrevoked_device_certificate_serial_number";
EXPECT_FALSE(VerifyIsDeviceCertificateRevoked(
unrevoked_device_certificate_serial_number));
}
TEST_F(DeviceStatusListTest, DetermineAndDeserializeServiceResponseSuccess) {
SignedDeviceInfo published_devices;
GenerateTrivialValidStatusList(
published_devices.mutable_device_certificate_status_list(),
HashAlgorithmProtoToEnum(published_devices.hash_algorithm()),
published_devices.mutable_signature());
std::string serialized_published_devices;
ASSERT_TRUE(
published_devices.SerializeToString(&serialized_published_devices));
DeviceCertificateStatusList actual_cert_status_list;
std::string actual_serialized_cert_status_list;
std::string actual_signature;
HashAlgorithm hash_algorithm;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
serialized_published_devices, &actual_cert_status_list,
&actual_serialized_cert_status_list, &hash_algorithm,
&actual_signature));
EXPECT_EQ(published_devices.device_certificate_status_list(),
actual_serialized_cert_status_list);
EXPECT_EQ(published_devices.signature(), actual_signature);
EXPECT_EQ(HashAlgorithmProtoToEnum(published_devices.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(expected_cert_status_list.ParseFromString(
published_devices.device_certificate_status_list()));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_cert_status_list, actual_cert_status_list));
}
TEST_F(DeviceStatusListTest,
DetermineAndDeserializeServiceResponseLegacySuccess) {
std::string serialized_cert_status_list;
std::string signature;
SignedDeviceCertificateStatusList legacy_signed_cert_status_list;
GenerateTrivialValidStatusList(
&serialized_cert_status_list,
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
&signature);
*(legacy_signed_cert_status_list.mutable_certificate_status_list()) =
serialized_cert_status_list;
*(legacy_signed_cert_status_list.mutable_signature()) = signature;
std::string serialized_signed_cert_status_list;
ASSERT_TRUE(legacy_signed_cert_status_list.SerializeToString(
&serialized_signed_cert_status_list));
std::string websafe_b64_serialized_signed_cert_status_list;
absl::WebSafeBase64Escape(serialized_signed_cert_status_list,
&websafe_b64_serialized_signed_cert_status_list);
std::string server_response = absl::StrCat(
"{\n"
" \"kind\": \"certificateprovisioning#certificateStatusListResponse\"\n"
" \"signedList\": \"",
websafe_b64_serialized_signed_cert_status_list, "\"\n}\n");
std::string actual_serialized_cert_status_list;
std::string actual_signature;
DeviceCertificateStatusList actual_cert_status_list;
HashAlgorithm hash_algorithm;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
server_response, &actual_cert_status_list,
&actual_serialized_cert_status_list, &hash_algorithm,
&actual_signature));
EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list);
EXPECT_EQ(signature, actual_signature);
EXPECT_EQ(
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(
expected_cert_status_list.ParseFromString(serialized_cert_status_list));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_cert_status_list, actual_cert_status_list));
}
TEST_F(DeviceStatusListTest,
DetermineAndDeserializeServiceResponseLegacyWebSafeBase64Success) {
std::string serialized_cert_status_list;
std::string signature;
SignedDeviceCertificateStatusList legacy_signed_cert_status_list;
GenerateTrivialValidStatusList(
&serialized_cert_status_list,
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
&signature);
*(legacy_signed_cert_status_list.mutable_certificate_status_list()) =
serialized_cert_status_list;
*(legacy_signed_cert_status_list.mutable_signature()) = signature;
std::string serialized_signed_cert_status_list;
ASSERT_TRUE(legacy_signed_cert_status_list.SerializeToString(
&serialized_signed_cert_status_list));
std::string websafe_b64_serialized_signed_cert_status_list;
absl::WebSafeBase64Escape(serialized_signed_cert_status_list,
&websafe_b64_serialized_signed_cert_status_list);
std::string actual_serialized_cert_status_list;
std::string actual_signature;
HashAlgorithm hash_algorithm;
DeviceCertificateStatusList actual_cert_status_list;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
websafe_b64_serialized_signed_cert_status_list,
&actual_cert_status_list, &actual_serialized_cert_status_list,
&hash_algorithm, &actual_signature));
EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list);
EXPECT_EQ(signature, actual_signature);
EXPECT_EQ(
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(
expected_cert_status_list.ParseFromString(serialized_cert_status_list));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_cert_status_list, actual_cert_status_list));
}
TEST_F(DeviceStatusListTest,
DetermineAndDeserializeServiceResponseLegacyBase64Success) {
std::string serialized_cert_status_list;
std::string signature;
SignedDeviceCertificateStatusList legacy_signed_cert_status_list;
GenerateTrivialValidStatusList(
&serialized_cert_status_list,
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
&signature);
*(legacy_signed_cert_status_list.mutable_certificate_status_list()) =
serialized_cert_status_list;
*(legacy_signed_cert_status_list.mutable_signature()) = signature;
std::string serialized_signed_cert_status_list;
ASSERT_TRUE(legacy_signed_cert_status_list.SerializeToString(
&serialized_signed_cert_status_list));
std::string websafe_b64_serialized_signed_cert_status_list;
absl::WebSafeBase64Escape(serialized_signed_cert_status_list,
&websafe_b64_serialized_signed_cert_status_list);
std::string actual_serialized_cert_status_list;
std::string actual_signature;
HashAlgorithm hash_algorithm;
DeviceCertificateStatusList actual_cert_status_list;
ASSERT_EQ(OkStatus(),
DeviceStatusList::DetermineAndDeserializeServiceResponse(
websafe_b64_serialized_signed_cert_status_list,
&actual_cert_status_list, &actual_serialized_cert_status_list,
&hash_algorithm, &actual_signature));
EXPECT_EQ(serialized_cert_status_list, actual_serialized_cert_status_list);
EXPECT_EQ(signature, actual_signature);
EXPECT_EQ(
HashAlgorithmProtoToEnum(legacy_signed_cert_status_list.hash_algorithm()),
hash_algorithm);
DeviceCertificateStatusList expected_cert_status_list;
ASSERT_TRUE(
expected_cert_status_list.ParseFromString(serialized_cert_status_list));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_cert_status_list, actual_cert_status_list));
}
TEST_F(DeviceStatusListTest,
GetDeviceCertificateStatusBySystemIdExpiredDeviceCertificateStatusList) {
MockDeviceStatusList mock_device_status_list;
EXPECT_CALL(mock_device_status_list, GetCurrentTime())
.Times(3)
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_cert_status_list_, kHashAlgorithm,
cert_status_list_signature_, 100));
DeviceCertificateStatus device_certificate_status;
EXPECT_EQ(OkStatus(),
mock_device_status_list.GetDeviceCertificateStatusBySystemId(
kValidCertSystemId, &device_certificate_status));
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.GetDeviceCertificateStatusBySystemId(
kValidCertSystemId, &device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest,
GetDeviceCertificateStatusBySystemIdUnknownDevice) {
DeviceCertificateStatus device_certificate_status;
uint32_t unknown_system_id = 2000;
EXPECT_EQ(DRM_DEVICE_CERTIFICATE_UNKNOWN,
device_status_list_
.GetDeviceCertificateStatusBySystemId(
unknown_system_id, &device_certificate_status)
.error_code());
}
TEST_F(DeviceStatusListTest, GetDeviceCertificateStatusBySystemIdOk) {
DeviceCertificateStatus device_certificate_status;
EXPECT_OK(device_status_list_.GetDeviceCertificateStatusBySystemId(
kValidCertSystemId, &device_certificate_status));
}
} // namespace widevine

View File

@@ -1,574 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// common_typos_disable. Successful / successfull.
#include "common/drm_root_certificate.h"
#include <memory>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "common/ec_key.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "common/signer_public_key.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
namespace {
const char kDevelopmentString[] = "dev"; // QA systems.
const char kProductionString[] = "prod"; // Production.
const char kTestingString[] = "test"; // Code development / unit tests.
const bool kUseCache = true;
// Restrict the certificate chain size. All leaf DRM certificates must be a
// DEVICE certificate. The DEVICE certificate must be signed by a MODEL
// certificate. The MODEL certificate can be signed by Widevine or by a
// PROVISIONER certificate which is signed by Widevine. Do not allow any
// additional links.
const uint32_t kMaxCertificateChainSize = 3;
// From common::TestDrmCertificates.
// TODO(user): common::test_certificates is a testonly target, consider
// how to use instead of dupliciating the test cert here.
static const unsigned char kTestRootCertificate[] = {
0x0a, 0x99, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xb9, 0x60, 0x22,
0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5,
0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78,
0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f,
0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca,
0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b,
0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46,
0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01,
0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c,
0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14,
0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd,
0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6,
0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde,
0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31,
0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a,
0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90,
0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49,
0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f,
0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda,
0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17,
0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30,
0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf,
0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16,
0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42,
0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9,
0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4,
0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a,
0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72,
0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde,
0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04,
0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b,
0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33,
0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67,
0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02,
0x03, 0x01, 0x00, 0x01, 0x12, 0x80, 0x03, 0x7f, 0x83, 0xde, 0xf0, 0x6a,
0x07, 0x2b, 0x8c, 0xd7, 0x0c, 0xb8, 0x75, 0x50, 0xce, 0xe8, 0xa9, 0x35,
0xcb, 0x9d, 0xe3, 0x83, 0x89, 0xe6, 0x78, 0xb2, 0x12, 0x12, 0x16, 0xfe,
0x62, 0xf9, 0xed, 0x1d, 0x1d, 0xda, 0x82, 0x67, 0x82, 0x30, 0xf8, 0x49,
0xc2, 0x49, 0x65, 0x3b, 0xa3, 0x69, 0xaa, 0xd4, 0xaa, 0xfa, 0x74, 0xa6,
0xf1, 0xc3, 0xd8, 0xd0, 0x84, 0x27, 0x00, 0xa2, 0xec, 0xbd, 0xcf, 0x58,
0xf2, 0xf6, 0x60, 0x00, 0xeb, 0x50, 0xae, 0x06, 0x9e, 0x5c, 0xd2, 0xce,
0xc0, 0xbc, 0x73, 0xdb, 0x66, 0xc4, 0x93, 0x39, 0x22, 0x92, 0x92, 0x27,
0x71, 0x3c, 0x25, 0x66, 0x96, 0x2e, 0xda, 0x66, 0x65, 0xbc, 0x38, 0xf5,
0x4e, 0x8e, 0x68, 0x4d, 0x5f, 0x8f, 0xf5, 0x90, 0xcc, 0xfb, 0xf3, 0x8c,
0x63, 0x3f, 0xe2, 0xf9, 0x4a, 0x37, 0xec, 0x68, 0x0b, 0x00, 0xcd, 0x0e,
0x13, 0x66, 0x06, 0x2f, 0x37, 0xc7, 0x3a, 0xa3, 0x7a, 0x1e, 0xb8, 0x12,
0x1d, 0xf4, 0x09, 0xba, 0xfc, 0x55, 0x1d, 0xa8, 0x54, 0x4a, 0x4c, 0x54,
0xda, 0x32, 0xe3, 0x4c, 0xa2, 0x03, 0xae, 0x65, 0xf0, 0x81, 0x4a, 0xe8,
0xc7, 0x93, 0x78, 0xdf, 0xc0, 0x3d, 0xc5, 0x24, 0xdc, 0x45, 0x27, 0xe1,
0xba, 0xc8, 0xe2, 0x1f, 0x27, 0x7c, 0x61, 0xba, 0x1b, 0x31, 0xc0, 0xf1,
0xad, 0x13, 0xdd, 0x61, 0x31, 0xf4, 0xc0, 0xe9, 0x0e, 0x8c, 0x8e, 0xe8,
0xd1, 0xf8, 0xdb, 0x76, 0xdf, 0x3f, 0x1a, 0x25, 0x28, 0x46, 0xc4, 0xf4,
0xdb, 0x8a, 0x3b, 0x03, 0x16, 0x96, 0x6b, 0x28, 0x0f, 0x05, 0xe6, 0xa9,
0xcb, 0x0d, 0x95, 0x57, 0x89, 0x3e, 0x4c, 0x70, 0xed, 0x84, 0x45, 0xdd,
0x88, 0x43, 0x4b, 0xc1, 0x9e, 0x52, 0xb3, 0x3a, 0xa1, 0xd9, 0xd4, 0xf9,
0x68, 0x08, 0x0b, 0x83, 0x35, 0x75, 0xf1, 0x2a, 0xa7, 0xce, 0xf6, 0x3f,
0x4a, 0x84, 0xd0, 0x0c, 0xfa, 0xf2, 0x0f, 0x42, 0x28, 0x1a, 0x1a, 0x92,
0xa7, 0x7d, 0x6f, 0xad, 0x57, 0x82, 0x44, 0x1a, 0x6d, 0x35, 0x85, 0x15,
0x2c, 0xd4, 0x28, 0xb4, 0x7c, 0xde, 0x66, 0x3b, 0xeb, 0x6d, 0x32, 0xc0,
0x30, 0xdf, 0x16, 0x99, 0x2e, 0xce, 0x8d, 0x23, 0x43, 0x06, 0x00, 0xe9,
0xb1, 0x94, 0x20, 0x42, 0x2a, 0xf5, 0xf1, 0x79, 0x4f, 0x2c, 0xd9, 0xe1,
0xc7, 0x2e, 0xd4, 0x8a, 0x31, 0x5a, 0x80, 0x27, 0x57, 0xa6, 0xfc, 0xb2,
0x47, 0x4c, 0x5b, 0x05, 0x22, 0x82, 0x77, 0x76, 0xbe, 0xd4, 0x23, 0x8c,
0xdf, 0xfc, 0xe9, 0xbc, 0x01, 0xc0, 0x16, 0x60, 0xff, 0x00, 0x45, 0x36,
0x2f, 0x29, 0x5f, 0x5f, 0xa8, 0x83, 0x8a, 0x55, 0xc2, 0x39, 0x72, 0x35,
0xc2, 0xb4, 0x81, 0xf7, 0xd7, 0x40, 0x15, 0x0c, 0xf1, 0xef, 0x58, 0xe7,
0xc4, 0xc1, 0x23, 0x47, 0x92, 0x29, 0x44};
static const unsigned char kDevRootCertificate[] = {
0x0a, 0x9c, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xc3, 0x94, 0x88,
0x8b, 0x05, 0x22, 0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01,
0x81, 0x00, 0xc0, 0x00, 0x36, 0x6f, 0x8e, 0xe9, 0xcf, 0x86, 0xdb, 0xcd,
0xdd, 0x4e, 0xfd, 0xcd, 0x45, 0xbf, 0x6d, 0x96, 0x05, 0x00, 0xb8, 0x72,
0xff, 0x9c, 0xb4, 0x39, 0xa8, 0xd8, 0xc0, 0x09, 0x73, 0xc0, 0x24, 0x6a,
0x39, 0x4d, 0x36, 0x3f, 0x9a, 0xe4, 0xb8, 0x76, 0xdc, 0x34, 0xe3, 0xee,
0x5f, 0xdd, 0x13, 0x20, 0x08, 0xdc, 0x4e, 0x6f, 0x4e, 0x9f, 0xc0, 0x36,
0xf9, 0xce, 0xc6, 0xb7, 0xdb, 0xe0, 0x51, 0x2d, 0x30, 0x0b, 0xae, 0x0a,
0x20, 0xd2, 0x29, 0x3c, 0x2c, 0x1d, 0x87, 0x65, 0xeb, 0x5f, 0x93, 0xd7,
0x3f, 0x12, 0x08, 0x50, 0x0e, 0x55, 0xf3, 0xf1, 0x19, 0xee, 0x18, 0x21,
0x6e, 0xea, 0xb6, 0x0a, 0x4a, 0x0b, 0x9c, 0x72, 0x37, 0xeb, 0x0b, 0x68,
0xfc, 0x52, 0x46, 0x62, 0xd0, 0xa2, 0x99, 0x66, 0xe2, 0x2b, 0x74, 0xdd,
0x5c, 0xaf, 0x9a, 0x03, 0xc4, 0x5d, 0x93, 0xfb, 0xcd, 0x45, 0x9a, 0xee,
0xfb, 0x7b, 0x18, 0x94, 0xc1, 0x8c, 0x82, 0x34, 0x7f, 0x02, 0x12, 0x21,
0xfc, 0x40, 0xc1, 0x50, 0xc9, 0xf4, 0x7c, 0xd5, 0x96, 0xbe, 0x55, 0x7f,
0x3c, 0x1d, 0x70, 0x34, 0xb4, 0xa2, 0x03, 0xc4, 0x3f, 0x89, 0x60, 0xe4,
0x24, 0x09, 0x1a, 0x74, 0xc4, 0xb6, 0x39, 0xf0, 0x34, 0x60, 0x8e, 0xa7,
0x5f, 0x02, 0x7f, 0xb9, 0x2a, 0xc5, 0xaa, 0xb2, 0x4c, 0x34, 0xd3, 0x5a,
0x5d, 0xfa, 0x07, 0xf2, 0xb9, 0xb3, 0xc1, 0xba, 0xab, 0xbe, 0x89, 0x99,
0xe3, 0x6d, 0x9b, 0xa9, 0xd3, 0xaf, 0x2a, 0x08, 0x76, 0xf3, 0x0e, 0xc9,
0xe0, 0xb3, 0xbf, 0x51, 0x0c, 0xc5, 0xf4, 0xf3, 0x15, 0x7b, 0x08, 0x11,
0x8f, 0x61, 0x1f, 0x61, 0x64, 0xdb, 0x15, 0x84, 0x5b, 0x8a, 0xd1, 0x28,
0x40, 0xde, 0xc5, 0x32, 0xb5, 0xad, 0xad, 0x65, 0x4c, 0xf5, 0xf7, 0xd1,
0x90, 0x14, 0x5d, 0xc2, 0x85, 0x98, 0xcc, 0xe9, 0xe6, 0x95, 0x42, 0xe1,
0x3e, 0xfc, 0x7f, 0xc4, 0x49, 0xed, 0x9c, 0xe4, 0x49, 0x3f, 0x03, 0x1b,
0x0d, 0xa0, 0xfb, 0xf5, 0x38, 0x49, 0xd2, 0xdf, 0xa3, 0x88, 0xb2, 0x76,
0x93, 0x08, 0x20, 0x18, 0xfe, 0xdc, 0x72, 0x6c, 0x6e, 0xbf, 0x61, 0x37,
0x03, 0xdb, 0xe5, 0x72, 0x68, 0xe0, 0x99, 0x2f, 0xb9, 0xe0, 0x2e, 0xbb,
0x9f, 0x96, 0x36, 0x61, 0xaa, 0x2d, 0xa4, 0x93, 0xe8, 0x50, 0x58, 0xe6,
0x61, 0xe1, 0x14, 0xcf, 0xac, 0x86, 0x98, 0x7f, 0x3c, 0x67, 0x16, 0xce,
0xb8, 0x70, 0x90, 0x3a, 0x5a, 0xd4, 0xe1, 0xe2, 0x35, 0x98, 0xbf, 0x93,
0x41, 0x11, 0xb2, 0x44, 0xb2, 0x64, 0xc2, 0xe7, 0x09, 0x45, 0xb7, 0x6f,
0xb0, 0xbd, 0x6e, 0xe8, 0x67, 0xfa, 0x8d, 0xd4, 0xfa, 0x4b, 0xef, 0xa8,
0x9d, 0x8a, 0x0a, 0xd9, 0x14, 0x77, 0x09, 0x11, 0x9e, 0xc3, 0x50, 0x14,
0x6c, 0x45, 0x02, 0x03, 0x01, 0x00, 0x01, 0x12, 0x80, 0x03, 0x17, 0x01,
0x60, 0x24, 0xe1, 0xfd, 0x75, 0x60, 0x17, 0x5c, 0x5e, 0x6f, 0x9f, 0x7f,
0xdf, 0xee, 0xf0, 0xf7, 0x7d, 0xb2, 0x50, 0x65, 0x36, 0x26, 0x14, 0x19,
0x01, 0x5e, 0x98, 0x94, 0x65, 0x97, 0x83, 0xaa, 0x4a, 0x2b, 0x98, 0x2e,
0x02, 0xf3, 0xb2, 0xc9, 0xb2, 0xed, 0xd3, 0x1b, 0x20, 0x27, 0x9e, 0xe1,
0x25, 0xc7, 0x86, 0xf0, 0x66, 0x68, 0x5d, 0xd2, 0x3d, 0xa7, 0xbb, 0xbc,
0x22, 0xfc, 0x29, 0xfa, 0x17, 0x16, 0xf4, 0xa2, 0x00, 0x10, 0x87, 0xb4,
0x5d, 0x51, 0x45, 0x6b, 0xc8, 0xf4, 0x6b, 0xcc, 0x92, 0x91, 0xe7, 0xa7,
0x93, 0xbc, 0xc7, 0x2e, 0xdc, 0xac, 0x82, 0x2b, 0x85, 0x56, 0x7b, 0xae,
0xf2, 0xd8, 0xda, 0xa6, 0xd7, 0xfa, 0x6d, 0x70, 0x2a, 0x2e, 0xcf, 0x69,
0xef, 0x57, 0x91, 0xa7, 0xaa, 0x40, 0x15, 0x4a, 0x49, 0x1b, 0xbc, 0x36,
0xbb, 0x1c, 0x94, 0x33, 0x36, 0x61, 0x22, 0x9d, 0x22, 0x66, 0xf0, 0x88,
0x5e, 0x7c, 0x3c, 0xa5, 0xff, 0x81, 0xcf, 0x1a, 0x44, 0xa1, 0x2b, 0xdf,
0xc9, 0x3d, 0xd5, 0xc7, 0xc7, 0x3a, 0x75, 0xac, 0x29, 0xfa, 0xfd, 0x5b,
0xda, 0xf5, 0x8f, 0xd9, 0xdf, 0x08, 0xa4, 0x8d, 0x19, 0x4a, 0xa4, 0x79,
0x6e, 0x47, 0xf6, 0x07, 0xe0, 0xbd, 0xbf, 0x30, 0x3a, 0xf9, 0xf5, 0xc0,
0x90, 0x6d, 0x70, 0x27, 0x44, 0xa8, 0x5e, 0x70, 0xcd, 0x43, 0x3e, 0xaf,
0xf0, 0xd7, 0x20, 0xd3, 0x5e, 0x97, 0x2d, 0x32, 0x1a, 0x3d, 0x2d, 0x0f,
0x0f, 0xcf, 0xac, 0x4e, 0x88, 0x75, 0x98, 0x6c, 0xfa, 0xe8, 0x42, 0x58,
0x99, 0xaa, 0x45, 0x0c, 0x41, 0x0c, 0x6e, 0x27, 0x58, 0x57, 0xd2, 0x5b,
0x82, 0x3d, 0x75, 0x2f, 0x9e, 0xf3, 0xe4, 0x00, 0xcf, 0x91, 0x48, 0x25,
0xca, 0x98, 0xf2, 0x91, 0x6b, 0x41, 0xa5, 0xe8, 0xcd, 0x64, 0xa7, 0x2e,
0x78, 0xc7, 0x76, 0x82, 0x3f, 0xf8, 0x57, 0x8a, 0x9d, 0x78, 0x25, 0xad,
0xf3, 0x1a, 0x8b, 0xfc, 0x83, 0x9a, 0x98, 0x87, 0xe4, 0x55, 0x3e, 0x1c,
0xa7, 0x80, 0x8f, 0xd6, 0x76, 0xab, 0x03, 0xc7, 0x05, 0x66, 0xc3, 0xa0,
0x4c, 0x33, 0x1f, 0x39, 0x74, 0x1b, 0x2a, 0xbf, 0xe6, 0xb0, 0x9f, 0x6b,
0xc1, 0xd6, 0xd3, 0xf4, 0x46, 0x9b, 0xf3, 0xab, 0xca, 0x2e, 0x88, 0x3d,
0x84, 0x5f, 0xc9, 0x9b, 0x47, 0xbb, 0x57, 0x64, 0x08, 0x0e, 0x18, 0x74,
0x83, 0x44, 0xd4, 0xc3, 0x18, 0x97, 0xcf, 0x89, 0x6a, 0x49, 0x51, 0xc6,
0xff, 0x8d, 0x39, 0xc5, 0x23, 0xf9, 0xd5, 0x01, 0xd7, 0x2f, 0xa9, 0xa5,
0x5d, 0xa9, 0xf3, 0xc9, 0xfd, 0xc4, 0x52, 0x19, 0x7d, 0xf6, 0xa4, 0x2c,
0x0c, 0xa0, 0x07, 0xdf, 0x7b, 0x44, 0xd7, 0xe5, 0xbf, 0x57, 0x87, 0xc9,
0x8c, 0xfe, 0x30, 0xb2, 0x89, 0x5d, 0x00, 0x03, 0x3b, 0xe5};
static const unsigned char kProdRootCertificate[] = {
0x0a, 0x9c, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xdd, 0x94, 0x88,
0x8b, 0x05, 0x22, 0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01,
0x81, 0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90, 0x03, 0xdb, 0x3c, 0x11,
0x97, 0x09, 0xe8, 0x68, 0xcd, 0xf2, 0xc3, 0x5e, 0x9b, 0xf2, 0xe7, 0x4d,
0x23, 0xb1, 0x10, 0xdb, 0x87, 0x65, 0xdf, 0xdc, 0xfb, 0x9f, 0x35, 0xa0,
0x57, 0x03, 0x53, 0x4c, 0xf6, 0x6d, 0x35, 0x7d, 0xa6, 0x78, 0xdb, 0xb3,
0x36, 0xd2, 0x3f, 0x9c, 0x40, 0xa9, 0x95, 0x26, 0x72, 0x7f, 0xb8, 0xbe,
0x66, 0xdf, 0xc5, 0x21, 0x98, 0x78, 0x15, 0x16, 0x68, 0x5d, 0x2f, 0x46,
0x0e, 0x43, 0xcb, 0x8a, 0x84, 0x39, 0xab, 0xfb, 0xb0, 0x35, 0x80, 0x22,
0xbe, 0x34, 0x23, 0x8b, 0xab, 0x53, 0x5b, 0x72, 0xec, 0x4b, 0xb5, 0x48,
0x69, 0x53, 0x3e, 0x47, 0x5f, 0xfd, 0x09, 0xfd, 0xa7, 0x76, 0x13, 0x8f,
0x0f, 0x92, 0xd6, 0x4c, 0xdf, 0xae, 0x76, 0xa9, 0xba, 0xd9, 0x22, 0x10,
0xa9, 0x9d, 0x71, 0x45, 0xd6, 0xd7, 0xe1, 0x19, 0x25, 0x85, 0x9c, 0x53,
0x9a, 0x97, 0xeb, 0x84, 0xd7, 0xcc, 0xa8, 0x88, 0x82, 0x20, 0x70, 0x26,
0x20, 0xfd, 0x7e, 0x40, 0x50, 0x27, 0xe2, 0x25, 0x93, 0x6f, 0xbc, 0x3e,
0x72, 0xa0, 0xfa, 0xc1, 0xbd, 0x29, 0xb4, 0x4d, 0x82, 0x5c, 0xc1, 0xb4,
0xcb, 0x9c, 0x72, 0x7e, 0xb0, 0xe9, 0x8a, 0x17, 0x3e, 0x19, 0x63, 0xfc,
0xfd, 0x82, 0x48, 0x2b, 0xb7, 0xb2, 0x33, 0xb9, 0x7d, 0xec, 0x4b, 0xba,
0x89, 0x1f, 0x27, 0xb8, 0x9b, 0x88, 0x48, 0x84, 0xaa, 0x18, 0x92, 0x0e,
0x65, 0xf5, 0xc8, 0x6c, 0x11, 0xff, 0x6b, 0x36, 0xe4, 0x74, 0x34, 0xca,
0x8c, 0x33, 0xb1, 0xf9, 0xb8, 0x8e, 0xb4, 0xe6, 0x12, 0xe0, 0x02, 0x98,
0x79, 0x52, 0x5e, 0x45, 0x33, 0xff, 0x11, 0xdc, 0xeb, 0xc3, 0x53, 0xba,
0x7c, 0x60, 0x1a, 0x11, 0x3d, 0x00, 0xfb, 0xd2, 0xb7, 0xaa, 0x30, 0xfa,
0x4f, 0x5e, 0x48, 0x77, 0x5b, 0x17, 0xdc, 0x75, 0xef, 0x6f, 0xd2, 0x19,
0x6d, 0xdc, 0xbe, 0x7f, 0xb0, 0x78, 0x8f, 0xdc, 0x82, 0x60, 0x4c, 0xbf,
0xe4, 0x29, 0x06, 0x5e, 0x69, 0x8c, 0x39, 0x13, 0xad, 0x14, 0x25, 0xed,
0x19, 0xb2, 0xf2, 0x9f, 0x01, 0x82, 0x0d, 0x56, 0x44, 0x88, 0xc8, 0x35,
0xec, 0x1f, 0x11, 0xb3, 0x24, 0xe0, 0x59, 0x0d, 0x37, 0xe4, 0x47, 0x3c,
0xea, 0x4b, 0x7f, 0x97, 0x31, 0x1c, 0x81, 0x7c, 0x94, 0x8a, 0x4c, 0x7d,
0x68, 0x15, 0x84, 0xff, 0xa5, 0x08, 0xfd, 0x18, 0xe7, 0xe7, 0x2b, 0xe4,
0x47, 0x27, 0x12, 0x11, 0xb8, 0x23, 0xec, 0x58, 0x93, 0x3c, 0xac, 0x12,
0xd2, 0x88, 0x6d, 0x41, 0x3d, 0xc5, 0xfe, 0x1c, 0xdc, 0xb9, 0xf8, 0xd4,
0x51, 0x3e, 0x07, 0xe5, 0x03, 0x6f, 0xa7, 0x12, 0xe8, 0x12, 0xf7, 0xb5,
0xce, 0xa6, 0x96, 0x55, 0x3f, 0x78, 0xb4, 0x64, 0x82, 0x50, 0xd2, 0x33,
0x5f, 0x91, 0x02, 0x03, 0x01, 0x00, 0x01, 0x12, 0x80, 0x03, 0x58, 0xf1,
0xd6, 0x4d, 0x04, 0x09, 0x7b, 0xdf, 0xd7, 0xef, 0x5d, 0x3b, 0x02, 0x39,
0x17, 0xfa, 0x14, 0x36, 0x75, 0x4a, 0x38, 0x67, 0x85, 0x57, 0x12, 0xa7,
0x14, 0xee, 0x35, 0x16, 0xd5, 0x3d, 0xbf, 0x42, 0x86, 0xf6, 0x69, 0x00,
0x76, 0xcd, 0x93, 0xf4, 0x7c, 0xb2, 0xdf, 0x9e, 0x44, 0xcd, 0x4c, 0xd4,
0xae, 0x09, 0x18, 0x53, 0x44, 0x32, 0xec, 0xe0, 0x61, 0x1b, 0xe5, 0xda,
0x13, 0xd3, 0x55, 0xc5, 0xdd, 0x1a, 0xcb, 0x90, 0x1e, 0x7e, 0x5b, 0xc6,
0xe9, 0x0f, 0x22, 0x9f, 0xbe, 0x85, 0x02, 0xfe, 0x90, 0x31, 0xcc, 0x6b,
0x03, 0x84, 0xbd, 0x22, 0xc4, 0x55, 0xfa, 0xf5, 0xf2, 0x08, 0xcd, 0x65,
0x41, 0x58, 0xe8, 0x7d, 0x29, 0xda, 0x04, 0x58, 0x82, 0xf5, 0x37, 0x69,
0xbc, 0xf3, 0x5a, 0x57, 0x84, 0x17, 0x7b, 0x32, 0x87, 0x70, 0xb2, 0xb0,
0x76, 0x9c, 0xb2, 0xc3, 0x15, 0xd1, 0x11, 0x26, 0x2a, 0x23, 0x75, 0x99,
0x3e, 0xb9, 0x77, 0x22, 0x32, 0x0d, 0xbc, 0x1a, 0x19, 0xc1, 0xd5, 0x65,
0x90, 0x76, 0x55, 0x74, 0x0f, 0x0e, 0x69, 0x4d, 0x5f, 0x4d, 0x8f, 0x19,
0xaf, 0xdf, 0xd6, 0x16, 0x31, 0x94, 0xa8, 0x92, 0x5f, 0x4f, 0xbc, 0x7a,
0x31, 0xf8, 0xae, 0x8e, 0xad, 0x33, 0xb7, 0xe9, 0x30, 0xd0, 0x8c, 0x0a,
0x8a, 0x6c, 0x83, 0x35, 0xf8, 0x8a, 0x81, 0xb2, 0xfe, 0x1c, 0x88, 0xac,
0x2a, 0x66, 0xc5, 0xff, 0xbd, 0xe6, 0x17, 0xd0, 0x62, 0x0b, 0xdc, 0x8a,
0x45, 0xf7, 0xb0, 0x3e, 0x5a, 0xc8, 0x1e, 0x4a, 0x24, 0x2f, 0x6c, 0xa5,
0xe3, 0x1c, 0x88, 0x14, 0x83, 0xd5, 0xc5, 0xef, 0x5e, 0x9f, 0x3d, 0x85,
0x45, 0x73, 0xe2, 0x6b, 0x50, 0x52, 0x57, 0x4c, 0xfb, 0x92, 0x6c, 0x66,
0x75, 0x8a, 0xd6, 0x0d, 0x1b, 0xae, 0xf3, 0xec, 0xaf, 0x51, 0x22, 0x03,
0x5d, 0x0a, 0x2e, 0x63, 0x93, 0x9c, 0x0b, 0x01, 0x20, 0xa8, 0xa9, 0x84,
0x2e, 0x17, 0xca, 0xae, 0x73, 0xec, 0x22, 0x1b, 0x79, 0xae, 0xf6, 0xa0,
0x72, 0x2c, 0xdf, 0x07, 0x47, 0xdb, 0x88, 0x86, 0x30, 0x14, 0x78, 0x21,
0x11, 0x22, 0x88, 0xac, 0xd7, 0x54, 0x74, 0xf9, 0xf3, 0x26, 0xc2, 0xa5,
0x56, 0xc8, 0x56, 0x4f, 0x00, 0x29, 0x1d, 0x08, 0x7b, 0x7a, 0xfb, 0x95,
0x89, 0xc3, 0xee, 0x98, 0x54, 0x9e, 0x3c, 0x6b, 0x94, 0x05, 0x13, 0x12,
0xf6, 0x71, 0xb9, 0xab, 0x13, 0xc3, 0x0c, 0x9b, 0x46, 0x08, 0x7b, 0x3d,
0x32, 0x6a, 0x68, 0xca, 0x1e, 0x9c, 0x90, 0x62, 0xc5, 0xed, 0x10, 0xb9,
0x1f, 0x17, 0x25, 0xce, 0x90, 0xb9, 0x6d, 0xcd, 0xc4, 0x46, 0xf5, 0xa3,
0x62, 0x13, 0x74, 0x02, 0xa7, 0x62, 0xa4, 0xfa, 0x55, 0xd9, 0xde, 0xcf,
0xa2, 0xe6, 0x80, 0x74, 0x55, 0x06, 0x49, 0xd5, 0x02, 0x0c};
} // namespace
// Caches an individual signature for a certificate with a specific serial
// number (signer).
struct VerifiedCertSignature {
VerifiedCertSignature(const std::string& cert, const std::string& sig,
const std::string& signer_sn,
const std::string& signer_pub_key)
: signed_cert(cert),
signature(sig),
signer_serial(signer_sn),
signer_public_key(signer_pub_key) {}
std::string signed_cert;
std::string signature;
std::string signer_serial;
std::string signer_public_key;
};
// Map of certificate serial number to its signature.
typedef std::map<std::string, VerifiedCertSignature> VerifiedCertSignatures;
class VerifiedCertSignatureCache {
public:
explicit VerifiedCertSignatureCache(const RsaKeyFactory* key_factory)
: key_factory_(key_factory) {}
// Checks cache, on miss, uses public key. If successful, adds to
// cache.
Status VerifySignature(const std::string& cert,
const std::string& serial_number,
HashAlgorithm hash_algorithm,
const std::string& signature,
const DrmCertificate& signer) {
{
VerifiedCertSignatures::iterator cached_signature;
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
cached_signature = signature_cache_.find(serial_number);
if (cached_signature != signature_cache_.end()) {
if (cert != cached_signature->second.signed_cert) {
return Status(error_space, INVALID_SIGNATURE, "cached-cert-mismatch");
}
if (signature != cached_signature->second.signature) {
return Status(error_space, INVALID_SIGNATURE,
"cached-signature-mismatch");
}
if (signer.serial_number() != cached_signature->second.signer_serial) {
return Status(error_space, INVALID_SIGNATURE,
"cached-serial-number-mismatch");
}
if (signer.public_key() != cached_signature->second.signer_public_key) {
return Status(error_space, INVALID_SIGNATURE,
"cached-signer-public-key-mismatch");
}
return OkStatus();
}
}
// Cache miss. Verify signature.
std::unique_ptr<SignerPublicKey> signer_public_key =
SignerPublicKey::Create(signer.public_key(), signer.algorithm());
if (signer_public_key == nullptr) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-public-key");
}
if (!signer_public_key->VerifySignature(cert, hash_algorithm, signature)) {
return Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
// Add signature to cache.
absl::WriterMutexLock write_lock(&signature_cache_mutex_);
signature_cache_.emplace(
serial_number,
VerifiedCertSignature(cert, signature, signer.serial_number(),
signer.public_key()));
return OkStatus();
}
private:
VerifiedCertSignatures signature_cache_
ABSL_GUARDED_BY(&signature_cache_mutex_);
absl::Mutex signature_cache_mutex_;
const RsaKeyFactory* key_factory_;
};
Status DrmRootCertificate::CreateByType(
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
return Create(cert_type, absl::make_unique<RsaKeyFactory>(), cert);
}
std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
CertificateType cert_type, Status* status) {
CHECK(status);
std::unique_ptr<DrmRootCertificate> new_root_cert;
*status = CreateByType(cert_type, &new_root_cert);
return new_root_cert;
}
Status DrmRootCertificate::CreateByTypeString(
const std::string& cert_type_string,
std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
CertificateType cert_type;
if (cert_type_string == kDevelopmentString) {
cert_type = kCertificateTypeDevelopment;
} else if (cert_type_string == kProductionString) {
cert_type = kCertificateTypeProduction;
} else if (cert_type_string == kTestingString) {
cert_type = kCertificateTypeTesting;
} else {
return Status(error_space, INVALID_PARAMETER,
absl::StrCat("invalid-certificate-type ", cert_type_string));
}
return CreateByType(cert_type, cert);
}
Status DrmRootCertificate::Create(CertificateType cert_type,
std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert) {
DCHECK(cert);
std::string serialized_certificate;
switch (cert_type) {
case kCertificateTypeProduction: {
serialized_certificate.assign(
kProdRootCertificate,
kProdRootCertificate + sizeof(kProdRootCertificate));
break;
}
case kCertificateTypeDevelopment: {
serialized_certificate.assign(
kDevRootCertificate,
kDevRootCertificate + sizeof(kDevRootCertificate));
break;
}
case kCertificateTypeTesting: {
serialized_certificate.assign(
kTestRootCertificate,
kTestRootCertificate + sizeof(kTestRootCertificate));
break;
}
default:
return Status(error_space, INVALID_PARAMETER, "invalid-certificate-type");
}
SignedDrmCertificate signed_root_cert;
if (!signed_root_cert.ParseFromString(serialized_certificate)) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"signed-root-cert-deserialize-fail");
}
DrmCertificate root_cert;
if (!signed_root_cert.has_drm_certificate()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-device-certificate");
}
if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"root-cert-deserialize-fail");
}
if (!root_cert.has_public_key()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-cert-public-key");
}
if (!signed_root_cert.has_signature()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-certificate-signature");
}
std::unique_ptr<SignerPublicKey> public_key =
SignerPublicKey::Create(root_cert.public_key(), root_cert.algorithm());
if (public_key == nullptr) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
}
if (!public_key->VerifySignature(
signed_root_cert.drm_certificate(),
HashAlgorithmProtoToEnum(signed_root_cert.hash_algorithm()),
signed_root_cert.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 OkStatus();
}
DrmRootCertificate::DrmRootCertificate(
CertificateType type, const std::string& serialized_certificate,
const std::string& serial_number, const std::string& public_key,
std::unique_ptr<RsaKeyFactory> key_factory)
: type_(type),
serialized_certificate_(serialized_certificate),
key_factory_(std::move(key_factory)),
signature_cache_(new VerifiedCertSignatureCache(key_factory_.get())) {
root_cert_.set_public_key(public_key);
root_cert_.set_serial_number(serial_number);
}
DrmRootCertificate::~DrmRootCertificate() {}
std::string DrmRootCertificate::GetDigest() const {
return absl::BytesToHexString(Sha256_Hash(serialized_certificate_));
}
Status DrmRootCertificate::VerifyCertificate(
const std::string& serialized_certificate,
SignedDrmCertificate* signed_certificate,
DrmCertificate* certificate) const {
std::unique_ptr<SignedDrmCertificate> local_signed_certificate;
if (!signed_certificate) {
local_signed_certificate = absl::make_unique<SignedDrmCertificate>();
signed_certificate = local_signed_certificate.get();
}
if (!signed_certificate->ParseFromString(serialized_certificate)) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate");
}
std::unique_ptr<DrmCertificate> local_certificate;
if (!certificate) {
local_certificate = absl::make_unique<DrmCertificate>();
certificate = local_certificate.get();
}
if (signed_certificate->drm_certificate().empty() ||
!certificate->ParseFromString(signed_certificate->drm_certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate");
}
if (certificate->serial_number().empty()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-serial-number");
}
if (!certificate->has_creation_time_seconds()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-creation-time");
}
if (certificate->public_key().empty()) {
return Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key");
}
// Verify signature chain, but do not use cache for leaf certificates.
uint32_t certs_in_chain = 0;
return VerifySignatures(*signed_certificate, certificate->serial_number(),
!kUseCache, &certs_in_chain);
}
// Recursively verifies certificates with their signing certs or the root.
// use_cache should be false when initially called so that signatures do not
// cached leaf certificates not signed with the root certificate, such as for
// 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.
Status DrmRootCertificate::VerifySignatures(
const SignedDrmCertificate& signed_cert,
const std::string& cert_serial_number, bool use_cache,
uint32_t* certs_in_chain) const {
CHECK(certs_in_chain);
if (++(*certs_in_chain) > kMaxCertificateChainSize) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"certificate-chain-size-exceeded");
}
if (!signed_cert.has_signer()) {
// Always use cache for root-signed certificates.
return signature_cache_->VerifySignature(
signed_cert.drm_certificate(), cert_serial_number,
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.signature(), root_cert_);
}
DrmCertificate signer;
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate");
}
// Signer cannot be a device certificate.
if (signer.type() == DrmCertificate::DEVICE) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"device-cert-must-be-leaf");
}
// Verify the signer before verifying signed_cert.
Status status = VerifySignatures(signed_cert.signer(), signer.serial_number(),
kUseCache, certs_in_chain);
if (!status.ok()) {
return status;
}
if (use_cache) {
status = signature_cache_->VerifySignature(
signed_cert.drm_certificate(), cert_serial_number,
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.signature(), signer);
if (!status.ok()) {
return status;
}
} else {
std::unique_ptr<SignerPublicKey> signer_public_key =
SignerPublicKey::Create(signer.public_key(), signer.algorithm());
if (signer_public_key == nullptr) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key");
}
if (!signer_public_key->VerifySignature(
signed_cert.drm_certificate(),
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
signed_cert.signature())) {
return Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
}
return OkStatus();
}
} // namespace widevine

View File

@@ -1,111 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Root device certificate holder class which deserializes, validates,
// and extracts the root certificate public key.
#ifndef COMMON_DRM_ROOT_CERTIFICATE_H_
#define COMMON_DRM_ROOT_CERTIFICATE_H_
// common_typos_disable. Successful / successfull.
#include <memory>
#include <string>
#include "common/certificate_type.h"
#include "common/signer_public_key.h"
#include "common/status.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
class DrmCertificate;
class RsaKeyFactory;
class RsaPublicKey;
class SignedDrmCertificate;
class VerifiedCertSignatureCache;
// Root certificate and certificate chain verifier with internal caching.
// This object is thread-safe.
class DrmRootCertificate {
public:
DrmRootCertificate(const DrmRootCertificate&) = delete;
DrmRootCertificate& operator=(const DrmRootCertificate&) = delete;
virtual ~DrmRootCertificate();
// Creates a DrmRootCertificate object given a certificate type.
// |cert| may not be nullptr, and it points to a
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
// created const DrmRootCertificate* if successful. The caller assumes
// ownership of the new DrmRootCertificate. This method returns
// Status::OK on success, or appropriate error status otherwise.
static Status CreateByType(CertificateType cert_type,
std::unique_ptr<DrmRootCertificate>* cert);
// Variant on the method above to make CLIF happy until b/110539622 is fixed.
static std::unique_ptr<DrmRootCertificate> CreateByType(
CertificateType cert_type, Status* status);
// Creates a DrmRootCertificate object given a certificate type std::string, which
// must be one of "prod", "qa", or "test".
// |cert| may not be nullptr, and it points to a
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
// created const DrmRootCertificate* if successful. The caller assumes
// ownership of the new DrmRootCertificate. This method returns
// Status::OK on success, or appropriate error status otherwise.
static Status CreateByTypeString(const std::string& cert_type_string,
std::unique_ptr<DrmRootCertificate>* cert);
// |certificate| will contgain the DRM certificate upon successful return.
// May be null.
// 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;
const CertificateType type() const { return type_; }
virtual const std::string& public_key() const {
return root_cert_.public_key();
}
protected:
DrmRootCertificate(CertificateType cert_type,
const std::string& serialized_certificate,
const std::string& serial_number,
const std::string& public_key,
std::unique_ptr<RsaKeyFactory> key_factory);
private:
friend class DrmRootCertificateTest;
static Status Create(CertificateType cert_type,
std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert);
Status VerifySignatures(const SignedDrmCertificate& signed_cert,
const std::string& cert_serial_number, bool use_cache,
uint32_t* certs_in_chain) const;
CertificateType type_;
std::string serialized_certificate_;
DrmCertificate root_cert_;
// TODO(b/143309971): Either add an ec key_factory object, or drop the rsa
// |key_factory_|.
std::unique_ptr<RsaKeyFactory> key_factory_;
mutable std::unique_ptr<VerifiedCertSignatureCache> signature_cache_;
};
} // namespace widevine
#endif // COMMON_DRM_ROOT_CERTIFICATE_H_

View File

@@ -1,415 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit tests for drm_root_certificate.cc
#include "common/drm_root_certificate.h"
#include <memory>
#include "glog/logging.h"
#include "google/protobuf/util/message_differencer.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.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/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "common/test_drm_certificates.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
using google::protobuf::util::MessageDifferencer;
using ::testing::Values;
namespace widevine {
TEST(DrmRootCertificateCreateTest, TestCertificate) {
const std::string kTestCertificateHash(
"49f917b1bdfed78002a58e799a58e940"
"1fffaaed9d8d80752782b066757e2c8c");
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest());
}
TEST(DrmRootCertificateCreateTest, DevCertificate) {
const std::string kDevelopmentCertificateHash(
"0e25ee95476a770f30b98ac5ef778b3f"
"137b66c29385b84f547a361b4724b17d");
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeDevelopment, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest());
}
TEST(DrmRootCertificateCreateTest, ProdCertificate) {
const std::string kProductionCertificateHash(
"d62fdabc9286648a81f7d3bedaf2f5a5"
"27bbad39bc38da034ba98a21569adb9b");
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeProduction, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest());
}
TEST(DrmRootCertificateTestCertificatesTest, Success) {
TestDrmCertificates test_certs;
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_TRUE(
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert)
.ok());
EXPECT_TRUE(root_cert
->VerifyCertificate(test_certs.test_root_certificate(),
nullptr, nullptr)
.ok());
EXPECT_TRUE(
root_cert
->VerifyCertificate(test_certs.test_intermediate_certificate(),
nullptr, nullptr)
.ok());
EXPECT_TRUE(root_cert
->VerifyCertificate(test_certs.test_user_device_certificate(),
nullptr, nullptr)
.ok());
EXPECT_TRUE(
root_cert
->VerifyCertificate(test_certs.test_service_certificate_no_type(),
nullptr, nullptr)
.ok());
}
TEST(DrmRootCertificateTestCertificatesTest, NonWidevineRootSigner) {
// TODO(b/138929855): Add test to verify certificate chain is signed by
// Widevine.
}
class SignerPrivateKey {
public:
virtual ~SignerPrivateKey() {}
virtual bool GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const = 0;
virtual DrmCertificate::Algorithm algorithm() const = 0;
static std::unique_ptr<SignerPrivateKey> Create(
const std::string& private_key,
widevine::DrmCertificate::Algorithm algorithm);
protected:
SignerPrivateKey() {}
};
template <typename T>
class SignerPrivateKeyImpl : public SignerPrivateKey {
public:
SignerPrivateKeyImpl(std::unique_ptr<T> private_key,
DrmCertificate::Algorithm algorithm)
: private_key_(std::move(private_key)), algorithm_(algorithm) {}
~SignerPrivateKeyImpl() override {}
bool GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const override {
return private_key_->GenerateSignature(message, hash_algorithm, signature);
}
DrmCertificate::Algorithm algorithm() const override { return algorithm_; }
private:
std::unique_ptr<T> private_key_;
DrmCertificate::Algorithm algorithm_;
};
std::unique_ptr<SignerPrivateKey> SignerPrivateKey::Create(
const std::string& private_key,
widevine::DrmCertificate::Algorithm algorithm) {
DCHECK(algorithm != DrmCertificate::UNKNOWN_ALGORITHM);
switch (algorithm) {
case DrmCertificate::RSA: {
auto rsa_key =
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key));
CHECK(rsa_key);
std::unique_ptr<SignerPrivateKey> new_rsa_signer_private_key =
absl::make_unique<SignerPrivateKeyImpl<RsaPrivateKey>>(
std::move(rsa_key), algorithm);
CHECK(new_rsa_signer_private_key);
return new_rsa_signer_private_key;
}
case DrmCertificate::ECC_SECP256R1:
case DrmCertificate::ECC_SECP384R1:
case DrmCertificate::ECC_SECP521R1: {
auto ec_key = ECPrivateKey::Create(private_key);
CHECK(ec_key);
std::unique_ptr<SignerPrivateKey> new_ec_signer_private_key =
absl::make_unique<SignerPrivateKeyImpl<ECPrivateKey>>(
std::move(ec_key), algorithm);
CHECK(new_ec_signer_private_key);
return new_ec_signer_private_key;
}
default:
break;
}
return nullptr;
}
static const int kDrmRootKey = 0;
static const int kInterMediateKey = 1;
static const int kClientKey = 2;
class DrmRootCertificateTest : public testing::TestWithParam<const char*> {
protected:
DrmRootCertificateTest() {}
void SetUp() override {
bool algorithm_status = false;
std::string algorithm(GetParam());
if (algorithm == "RSA") {
RsaTestSetup();
algorithm_status = true;
}
if (algorithm == "ECC") {
EcTestSetup();
algorithm_status = true;
}
CHECK(algorithm_status);
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert_));
}
void RsaTestSetup() {
private_keys_.resize(3);
private_keys_[kDrmRootKey] =
SignerPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits(),
widevine::DrmCertificate::RSA);
drm_certificates_[kDrmRootKey].set_serial_number("level 0");
drm_certificates_[kDrmRootKey].set_creation_time_seconds(0);
drm_certificates_[kDrmRootKey].set_public_key(
rsa_test_keys_.public_test_key_1_3072_bits());
private_keys_[kInterMediateKey] =
SignerPrivateKey::Create(rsa_test_keys_.private_test_key_2_2048_bits(),
widevine::DrmCertificate::RSA);
drm_certificates_[kInterMediateKey].set_serial_number("level 1");
drm_certificates_[kInterMediateKey].set_creation_time_seconds(1);
drm_certificates_[kInterMediateKey].set_public_key(
rsa_test_keys_.public_test_key_2_2048_bits());
private_keys_[kClientKey] =
SignerPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits(),
widevine::DrmCertificate::RSA);
drm_certificates_[kClientKey].set_serial_number("level 2");
drm_certificates_[kClientKey].set_creation_time_seconds(2);
drm_certificates_[kClientKey].set_public_key(
rsa_test_keys_.public_test_key_3_2048_bits());
}
void EcTestSetup() {
private_keys_.resize(3);
private_keys_[kDrmRootKey] =
SignerPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits(),
widevine::DrmCertificate::RSA);
drm_certificates_[kDrmRootKey].set_serial_number("level 0");
drm_certificates_[kDrmRootKey].set_creation_time_seconds(0);
drm_certificates_[kDrmRootKey].set_public_key(
rsa_test_keys_.public_test_key_1_3072_bits());
private_keys_[kInterMediateKey] =
SignerPrivateKey::Create(ec_test_keys_.private_test_key_1_secp521r1(),
DrmCertificate::ECC_SECP521R1);
drm_certificates_[kInterMediateKey].set_serial_number("level 1");
drm_certificates_[kInterMediateKey].set_creation_time_seconds(1);
drm_certificates_[kInterMediateKey].set_public_key(
ec_test_keys_.public_test_key_1_secp521r1());
drm_certificates_[kInterMediateKey].set_algorithm(
DrmCertificate::ECC_SECP521R1);
private_keys_[kClientKey] =
SignerPrivateKey::Create(ec_test_keys_.private_test_key_1_secp256r1(),
DrmCertificate::ECC_SECP256R1);
drm_certificates_[kClientKey].set_serial_number("level 2");
drm_certificates_[kClientKey].set_creation_time_seconds(2);
drm_certificates_[kClientKey].set_public_key(
ec_test_keys_.public_test_key_1_secp256r1());
drm_certificates_[kClientKey].set_algorithm(DrmCertificate::ECC_SECP256R1);
// Client certificate.
// Intermediate certificate.
}
void GenerateSignedDrmCertificate() {
SignedDrmCertificate* current_sc(&signed_drm_certificate_);
drm_certificates_[kClientKey].set_algorithm(
private_keys_[kClientKey]->algorithm());
ASSERT_TRUE(drm_certificates_[kClientKey].SerializeToString(
current_sc->mutable_drm_certificate()));
ASSERT_TRUE(private_keys_[kInterMediateKey]->GenerateSignature(
current_sc->drm_certificate(),
HashAlgorithmProtoToEnum(current_sc->hash_algorithm()),
current_sc->mutable_signature()));
current_sc = current_sc->mutable_signer();
drm_certificates_[kInterMediateKey].set_algorithm(
private_keys_[kInterMediateKey]->algorithm());
ASSERT_TRUE(drm_certificates_[kInterMediateKey].SerializeToString(
current_sc->mutable_drm_certificate()));
ASSERT_TRUE(private_keys_[kDrmRootKey]->GenerateSignature(
current_sc->drm_certificate(),
HashAlgorithmProtoToEnum(current_sc->hash_algorithm()),
current_sc->mutable_signature()));
current_sc = current_sc->mutable_signer();
drm_certificates_[kDrmRootKey].set_algorithm(
private_keys_[kDrmRootKey]->algorithm());
ASSERT_TRUE(drm_certificates_[kDrmRootKey].SerializeToString(
current_sc->mutable_drm_certificate()));
ASSERT_TRUE(private_keys_[kDrmRootKey]->GenerateSignature(
current_sc->drm_certificate(),
HashAlgorithmProtoToEnum(current_sc->hash_algorithm()),
current_sc->mutable_signature()));
}
RsaTestKeys rsa_test_keys_;
ECTestKeys ec_test_keys_;
std::vector<std::unique_ptr<SignerPrivateKey>> private_keys_;
SignedDrmCertificate signed_drm_certificate_;
DrmCertificate drm_certificates_[3];
std::unique_ptr<DrmRootCertificate> root_cert_;
};
INSTANTIATE_TEST_SUITE_P(SuccessNoOutput, DrmRootCertificateTest,
Values("RSA", "ECC"));
TEST_P(DrmRootCertificateTest, SuccessNoOutput) {
GenerateSignedDrmCertificate();
ASSERT_EQ(OkStatus(),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, SuccessWithOutput) {
GenerateSignedDrmCertificate();
SignedDrmCertificate out_signed_cert;
DrmCertificate 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_P(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate"),
root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, InvalidSignerCertificate) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage");
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, MissingDrmCertificate) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.clear_drm_certificate();
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, InvalidDrmCertificate) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.set_drm_certificate("junk");
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, InvalidPublicKey) {
drm_certificates_[0].set_public_key("rubbish");
GenerateSignedDrmCertificate();
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signer-public-key"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, MissingPublicKey) {
drm_certificates_[2].clear_public_key();
GenerateSignedDrmCertificate();
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, MissingCreationTime) {
drm_certificates_[2].clear_creation_time_seconds();
GenerateSignedDrmCertificate();
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "missing-creation-time"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, MissingSerialNumber) {
drm_certificates_[2].set_serial_number("");
GenerateSignedDrmCertificate();
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "missing-serial-number"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, InvalidSignatureWithNoCache) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.mutable_signer()->set_signature(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
EXPECT_EQ(
Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_P(DrmRootCertificateTest, InvalidSignatureWithCache) {
GenerateSignedDrmCertificate();
// Verify and cache.
ASSERT_EQ(OkStatus(),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
// Verify success using cache.
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(Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
} // namespace widevine

View File

@@ -1,316 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <map>
#include <memory>
#include <utility>
#include "glog/logging.h"
#include "absl/base/thread_annotations.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "util/gtl/map_util.h"
#include "common/aes_cbc_util.h"
#include "common/certificate_type.h"
#include "common/drm_root_certificate.h"
#include "common/error_space.h"
#include "common/rsa_util.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
namespace {
// Class used to hold global service certificate map.
class DrmServiceCertificateMap {
public:
DrmServiceCertificateMap();
~DrmServiceCertificateMap();
DrmServiceCertificateMap(const DrmServiceCertificateMap&) = delete;
DrmServiceCertificateMap& operator=(const DrmServiceCertificateMap&) = delete;
void Reset();
void AddCert(std::unique_ptr<DrmServiceCertificate> new_cert);
void ClearDefaultDrmServiceCertificate();
const DrmServiceCertificate* GetDefaultCert();
const DrmServiceCertificate* GetCertBySerialNumber(
const std::string& serial_number);
const DrmServiceCertificate* GetCertByProvider(
const std::string& provider_id);
static DrmServiceCertificateMap* GetInstance();
private:
absl::Mutex mutex_;
// Certificate serial number to certificate map.
std::map<std::string, std::unique_ptr<DrmServiceCertificate>> map_
ABSL_GUARDED_BY(mutex_);
DrmServiceCertificate* default_cert_ ABSL_GUARDED_BY(mutex_);
};
DrmServiceCertificateMap::DrmServiceCertificateMap() : default_cert_(nullptr) {}
DrmServiceCertificateMap::~DrmServiceCertificateMap() { Reset(); }
void DrmServiceCertificateMap::Reset() {
absl::WriterMutexLock lock(&mutex_);
map_.clear();
default_cert_ = nullptr;
}
void DrmServiceCertificateMap::AddCert(
std::unique_ptr<DrmServiceCertificate> new_cert) {
absl::WriterMutexLock lock(&mutex_);
std::unique_ptr<DrmServiceCertificate>* previous_cert =
gtl::FindOrNull(map_, new_cert->serial_number());
if (previous_cert != nullptr) {
if (default_cert_ == previous_cert->get()) {
default_cert_ = nullptr;
}
}
if (default_cert_ == nullptr) {
default_cert_ = new_cert.get();
}
const std::string& serial_number = new_cert->serial_number();
map_[serial_number] = std::move(new_cert);
}
void DrmServiceCertificateMap::ClearDefaultDrmServiceCertificate() {
absl::WriterMutexLock lock(&mutex_);
default_cert_ = nullptr;
}
const DrmServiceCertificate* DrmServiceCertificateMap::GetDefaultCert() {
absl::ReaderMutexLock lock(&mutex_);
return default_cert_;
}
const DrmServiceCertificate* DrmServiceCertificateMap::GetCertBySerialNumber(
const std::string& serial_number) {
absl::ReaderMutexLock lock(&mutex_);
return map_[serial_number].get();
}
const DrmServiceCertificate* DrmServiceCertificateMap::GetCertByProvider(
const std::string& provider_id) {
absl::ReaderMutexLock lock(&mutex_);
DrmServiceCertificate* provider_drm_cert = nullptr;
for (const auto& drm_cert : map_) {
if (drm_cert.second->provider_id() == provider_id) {
if (provider_drm_cert == nullptr) {
provider_drm_cert = drm_cert.second.get();
} else if (drm_cert.second->creation_time_seconds() >
provider_drm_cert->creation_time_seconds()) {
// Use the newest cert.
provider_drm_cert = drm_cert.second.get();
}
}
}
return provider_drm_cert;
}
DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
static auto* const kInstance = new DrmServiceCertificateMap();
return kInstance;
}
} // namespace
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;
Status status =
root_drm_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
if (!status.ok()) {
return status;
}
if (drm_cert.type() != DrmCertificate::SERVICE) {
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"not-service-certificate");
}
if (drm_cert.provider_id().empty()) {
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-service-id");
}
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(drm_cert.public_key()));
if (!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 Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"key-decryption-failed");
}
std::unique_ptr<RsaPrivateKey> private_key(RsaPrivateKey::Create(pkcs1_key));
if (private_key == nullptr) {
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"invalid-private-key");
}
std::unique_ptr<DrmServiceCertificate> new_cert(new DrmServiceCertificate(
service_certificate, drm_cert.provider_id(), drm_cert.serial_number(),
drm_cert.creation_time_seconds(), std::move(public_key),
std::move(private_key)));
DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert));
return OkStatus();
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDefaultDrmServiceCertificate() {
return DrmServiceCertificateMap::GetInstance()->GetDefaultCert();
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie() {
const DrmServiceCertificate* default_cert =
DrmServiceCertificateMap::GetInstance()->GetDefaultCert();
CHECK(default_cert) << "Service Certificate not set!";
return default_cert;
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
const std::string& serial_number) {
return DrmServiceCertificateMap::GetInstance()->GetCertBySerialNumber(
serial_number);
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDrmServiceCertificateByProvider(
const std::string& provider) {
return DrmServiceCertificateMap::GetInstance()->GetCertByProvider(provider);
}
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) {
DrmServiceCertificateMap::GetInstance()->ClearDefaultDrmServiceCertificate();
return AddDrmServiceCertificate(root_drm_cert, service_certificate,
service_private_key,
service_private_key_passphrase);
}
Status DrmServiceCertificate::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
DCHECK(client_id);
if (encrypted_client_id.service_certificate_serial_number().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-certificate-serial-number");
}
if (encrypted_client_id.provider_id().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-id");
}
if (encrypted_client_id.encrypted_client_id().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-privacy-key");
}
std::string privacy_key;
std::string provider_id;
const DrmServiceCertificate* cert = GetDrmServiceCertificateBySerialNumber(
encrypted_client_id.service_certificate_serial_number());
if (!cert) {
return Status(
error_space, SERVICE_CERTIFICATE_NOT_FOUND,
"service-certificate-not-found (SN " +
absl::BytesToHexString(
encrypted_client_id.service_certificate_serial_number()) +
")");
}
if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(),
&privacy_key)) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"privacy-key-decryption-failed");
}
if (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 Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return OkStatus();
}
void DrmServiceCertificate::ResetServiceCertificates() {
DrmServiceCertificateMap::GetInstance()->Reset();
}
Status DrmServiceCertificate::ValidateDrmServiceCertificate() {
const DrmServiceCertificate* service_certificate =
GetDefaultDrmServiceCertificate();
if (!service_certificate) {
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 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 Status(error_space, INVALID_DRM_CERTIFICATE,
"Drm service certificate is failed to parse.");
}
if (!drm_cert.has_creation_time_seconds()) {
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 OkStatus();
}
DrmServiceCertificate::DrmServiceCertificate(
const std::string& service_certificate, const std::string& provider_id,
const std::string& serial_number, const uint32_t creation_time_seconds,
std::unique_ptr<RsaPublicKey> public_key,
std::unique_ptr<RsaPrivateKey> private_key)
: certificate_(service_certificate),
provider_id_(provider_id),
serial_number_(serial_number),
creation_time_seconds_(creation_time_seconds),
public_key_(std::move(public_key)),
private_key_(std::move(private_key)) {}
} // namespace widevine

View File

@@ -1,144 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Service certificate holder used to decrypt encrypted client credentials.
#ifndef COMMON_DRM_SERVICE_CERTIFICATE_H_
#define COMMON_DRM_SERVICE_CERTIFICATE_H_
#include <map>
#include <memory>
#include <string>
#include <cstdint>
#include "common/certificate_type.h"
#include "common/rsa_key.h"
#include "common/status.h"
namespace widevine {
class RequestInspectorTest;
} // namespace widevine
namespace widevine {
class ClientIdentification;
class DrmRootCertificate;
class EncryptedClientIdentification;
// TODO(user): Add a DrmCertificateList class to provide the static method
// functionality.
class DrmServiceCertificate {
public:
DrmServiceCertificate(const DrmServiceCertificate&) = delete;
DrmServiceCertificate& operator=(const DrmServiceCertificate&) = delete;
// Create a new DrmServiceCertificate object and add it to the list of valid
// service certificates. |drm_root_cert| is the root certificate for the type
// of certifiate being added. |service_certificate| is a
// Google-generated certificate used to authenticate the service provider for
// purposes of device privacy, |service_private_key| is the encrypted PKCS#8
// private RSA key corresponding to the service certificate,
// |service_private_key_passphrase| is the password required to decrypt
// |service_private_key|.
// Returns status::OK if successful, or appropriate error code otherwise.
// If the default service certificate is not set, this certificate will be
// used as the default service certificate.
// This method is thread-safe.
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);
// 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 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);
// Returns the default service certificate. Will return null if no default
// Service Certificate is set. This method is thread-safe.
static const DrmServiceCertificate* GetDefaultDrmServiceCertificate();
// Returns the default service certificate. Will abort if no default Service
// Certificate is set. This method is thread-safe.
static const DrmServiceCertificate* GetDefaultDrmServiceCertificateOrDie();
// Returns the service certificate with the given |cert_serial_number|, or
// null otherwise.
static const DrmServiceCertificate* GetDrmServiceCertificateBySerialNumber(
const std::string& cert_serial_number);
// Returns the service certificate with the given |provider_id|, or
// null otherwise. If multple certificates exist for the provider, the
// newest certificate is returned.
static const DrmServiceCertificate* GetDrmServiceCertificateByProvider(
const std::string& provider_id);
// Decrypts the EncryptedClientIdentification message passed in
// |encrypted_client_id| into |client_id| using the private key for the
// 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 Status DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
const std::string& certificate() const { return certificate_; }
const std::string& provider_id() const { return provider_id_; }
const std::string& serial_number() const { return serial_number_; }
uint32_t creation_time_seconds() const { return creation_time_seconds_; }
const RsaPrivateKey* const private_key() const { return private_key_.get(); }
const RsaPublicKey* const public_key() const { return public_key_.get(); }
// Returns the validation result of drm service certificate. Returns
// 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 Status ValidateDrmServiceCertificate();
private:
friend class DrmServiceCertificateTest;
friend class widevine::RequestInspectorTest;
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 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);
DrmServiceCertificate(const std::string& service_certificate,
const std::string& provider_id,
const std::string& serial_number,
const uint32_t creation_time_seconds,
std::unique_ptr<RsaPublicKey> public_key,
std::unique_ptr<RsaPrivateKey> private_key);
static void ResetServiceCertificates();
std::string certificate_;
std::string provider_id_;
std::string serial_number_;
uint32_t creation_time_seconds_;
std::unique_ptr<RsaPublicKey> public_key_;
std::unique_ptr<RsaPrivateKey> private_key_;
};
} // namespace widevine
#endif // COMMON_DRM_SERVICE_CERTIFICATE_H_

View File

@@ -1,428 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <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_root_certificate.h"
#include "common/hash_algorithm_util.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(),
HashAlgorithmProtoToEnum(signed_cert.hash_algorithm()),
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<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_;
TestDrmCertificates test_certs_;
std::string privacy_key_;
std::string iv_;
std::unique_ptr<RsaPrivateKey> root_private_key_;
std::unique_ptr<DrmRootCertificate> 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 serial_number3("serial_number3");
std::string provider_id3("service3.com");
uint32_t creation_time_seconds3(1235);
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));
EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id3,
creation_time_seconds3));
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, MultipleDrmServiceCertificatesLookup) {
std::string serial_number1("serial_number1");
std::string provider_id1("service1.com");
uint32_t creation_time_seconds1(1231);
std::string serial_number2("serial_number2");
std::string provider_id2("service2.com");
uint32_t creation_time_seconds2(1232);
std::string serial_number3("serial_number3");
std::string provider_id3("service3.com");
uint32_t creation_time_seconds3(1234);
std::string serial_number4("serial_number4");
std::string bogus_serial_number("bogus-serial-number");
EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id1,
creation_time_seconds1));
EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id2,
creation_time_seconds2));
EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id3,
creation_time_seconds3));
EXPECT_EQ(provider_id1,
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
serial_number1)
->provider_id());
EXPECT_EQ(provider_id2,
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
serial_number2)
->provider_id());
EXPECT_EQ(provider_id3,
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
serial_number3)
->provider_id());
EXPECT_EQ(
serial_number1,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id1)
->serial_number());
EXPECT_EQ(
serial_number2,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id2)
->serial_number());
EXPECT_EQ(
serial_number3,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id3)
->serial_number());
// Add a second cert for provider 3.
EXPECT_OK(AddDrmServiceCertificate(serial_number4, provider_id3,
creation_time_seconds3 + 60));
EXPECT_EQ(
serial_number4,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id3)
->serial_number());
}
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

View File

@@ -1,113 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/dual_certificate_client_cert.h"
#include "common/error_space.h"
#include "common/status.h"
#include "protos/public/errors.pb.h"
namespace widevine {
Status DualCertificateClientCert::Initialize(
const DrmRootCertificate* root_certificate,
const std::string& serialized_signing_certificate,
const std::string& serialized_encryption_certificate) {
Status status = signing_certificate_.Initialize(
root_certificate, serialized_signing_certificate);
if (!status.ok()) {
return status;
}
status = encryption_certificate_.Initialize(
root_certificate, serialized_encryption_certificate);
if (!status.ok()) {
return status;
}
if (encryption_certificate_.signer_serial_number() !=
signing_certificate_.signer_serial_number()) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"certificate_signer_mismatch");
}
if ((encryption_certificate_.system_id() !=
signing_certificate_.system_id()) ||
(encryption_certificate_.service_id() !=
signing_certificate_.service_id()) ||
(encryption_certificate_.signer_creation_time_seconds() !=
signing_certificate_.signer_creation_time_seconds()) ||
(encryption_certificate_.signed_by_provisioner() !=
signing_certificate_.signed_by_provisioner())) {
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid_certificate_pair");
}
return OkStatus();
}
Status DualCertificateClientCert::VerifySignature(
const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature, ProtocolVersion protocol_version) const {
return signing_certificate_.VerifySignature(message, hash_algorithm,
signature, protocol_version);
}
void DualCertificateClientCert::GenerateSigningKey(
const std::string& message, ProtocolVersion protocol_version) {
encryption_certificate_.GenerateSigningKey(message, protocol_version);
}
const std::string& DualCertificateClientCert::encrypted_key() const {
return encryption_certificate_.encrypted_key();
}
const std::string& DualCertificateClientCert::key() const {
return encryption_certificate_.key();
}
SignedMessage::SessionKeyType DualCertificateClientCert::key_type() const {
return encryption_certificate_.key_type();
}
// TODO(b/155979840): Support revocation check for the encryption certificate.
const std::string& DualCertificateClientCert::serial_number() const {
return signing_certificate_.serial_number();
}
const std::string& DualCertificateClientCert::service_id() const {
return signing_certificate_.service_id();
}
const std::string& DualCertificateClientCert::signing_key() const {
return encryption_certificate_.signing_key();
}
const std::string& DualCertificateClientCert::signer_serial_number() const {
return signing_certificate_.signer_serial_number();
}
uint32_t DualCertificateClientCert::signer_creation_time_seconds() const {
return signing_certificate_.signer_creation_time_seconds();
}
bool DualCertificateClientCert::signed_by_provisioner() const {
return signing_certificate_.signed_by_provisioner();
}
uint32_t DualCertificateClientCert::system_id() const {
return signing_certificate_.system_id();
}
// TODO(b/155979840): Support revocation check for the encryption certificate.
const std::string& DualCertificateClientCert::encrypted_unique_id() const {
return signing_certificate_.encrypted_unique_id();
}
// TODO(b/155979840): Support revocation check for the encryption certificate.
const std::string& DualCertificateClientCert::unique_id_hash() const {
return signing_certificate_.unique_id_hash();
}
} // namespace widevine

View File

@@ -1,57 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_
#define COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_
#include "common/certificate_client_cert.h"
namespace widevine {
class DualCertificateClientCert : public ClientCert {
public:
DualCertificateClientCert() = default;
~DualCertificateClientCert() override = default;
DualCertificateClientCert(const DualCertificateClientCert&) = delete;
DualCertificateClientCert& operator=(const DualCertificateClientCert&) =
delete;
Status Initialize(const DrmRootCertificate* root_certificate,
const std::string& serialized_signing_certificate,
const std::string& serialized_encryption_certificate);
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const override;
void GenerateSigningKey(const std::string& message,
ProtocolVersion protocol_version) override;
const std::string& encrypted_key() const override;
const std::string& key() const override;
SignedMessage::SessionKeyType key_type() const override;
bool using_dual_certificate() const override { return true; }
const std::string& serial_number() const override;
const std::string& service_id() const override;
const std::string& signing_key() const override;
const std::string& signer_serial_number() const override;
uint32_t signer_creation_time_seconds() const override;
bool signed_by_provisioner() const override;
uint32_t system_id() const override;
widevine::ClientIdentification::TokenType type() const override {
return ClientIdentification::DRM_DEVICE_CERTIFICATE;
}
const std::string& encrypted_unique_id() const override;
const std::string& unique_id_hash() const override;
private:
CertificateClientCert signing_certificate_;
CertificateClientCert encryption_certificate_;
};
} // namespace widevine
#endif // COMMON_DUAL_CERTIFICATE_CLIENT_CERT_H_

View File

@@ -143,39 +143,6 @@ bool ECPrivateKey::DeriveSharedSessionKey(
return true;
}
bool ECPrivateKey::GenerateSignature(const std::string& message,
std::string* signature) const {
if (message.empty()) {
LOG(ERROR) << "|message| cannot be empty";
return false;
}
if (signature == nullptr) {
LOG(ERROR) << "|signature| cannot be nullptr";
return false;
}
std::string message_digest = Sha256_Hash(message);
size_t max_signature_size = ECDSA_size(key());
if (max_signature_size == 0) {
LOG(ERROR) << "key_ does not have a group set";
return false;
}
signature->resize(max_signature_size);
unsigned int bytes_written = 0;
int result = ECDSA_sign(
0 /* unused type */,
reinterpret_cast<const uint8_t*>(message_digest.data()),
message_digest.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
&bytes_written, key());
if (result != 1) {
LOG(ERROR) << "Could not calculate signature: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
signature->resize(bytes_written);
return true;
}
bool ECPrivateKey::GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
std::string* signature) const {
@@ -287,31 +254,6 @@ std::unique_ptr<ECPublicKey> ECPublicKey::CreateFromKeyPoint(
return absl::make_unique<ECPublicKey>(scoped_ec_key.release());
}
bool ECPublicKey::VerifySignature(const std::string& message,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "|message| cannot be empty";
return false;
}
if (signature.empty()) {
LOG(ERROR) << "|signature| cannot be empty";
return false;
}
std::string message_digest = Sha256_Hash(message);
int result = ECDSA_verify(
0 /* unused type */,
reinterpret_cast<const uint8_t*>(message_digest.data()),
message_digest.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature.data())),
signature.size(), key());
if (result != 1) {
LOG(ERROR) << "Could not verify signature: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool ECPublicKey::VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const {

View File

@@ -61,19 +61,6 @@ class ECPrivateKey {
const ECPublicKey& public_key,
std::string* derived_shared_session_key) const;
// Given a message, calculates a signature using ECDSA with the key_.
// |message| is the message to be signed.
// |signature| will contain the resulting signature. This will be an ASN.1
// DER-encoded signature.
// Caller retains ownership of all pointers.
// Returns true on success and false on error.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Given a message, calculates a signature using ECDSA with the key_.
// |message| is the message to be signed.
// |hash_algorithm| specifies the hash algorithm.
@@ -122,18 +109,6 @@ class ECPublicKey {
static std::unique_ptr<ECPublicKey> CreateFromKeyPoint(
ECPrivateKey::EllipticCurve curve, const std::string& key_point);
// Given a message and a signature, verifies that the signature was created
// using the private key associated with key_.
// |message| is the message that was signed.
// |signature| is an ASN.1 DER-encoded signature.
// Returns true on success and false on error.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Given a message and a signature, verifies that the signature was created
// using the private key associated with key_.
// |message| is the message that was signed.

View File

@@ -1,43 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Declaration for abstract EC key generation class.
#ifndef COMMON_EC_KEY_SOURCE_H_
#define COMMON_EC_KEY_SOURCE_H_
#include <string>
#include "common/ec_key.h"
namespace widevine {
class ECKeySource {
public:
ECKeySource() = default;
virtual ~ECKeySource() = default;
// Get an EC key pair given a specific curve defined by EllipticCurve.
// Parameter |curve| is a standard curve which defines the parameters of the
// key generation.
// Parameter |private_key| is the serialized EC private key.
// Parameter |public_key| is the serialized EC public key.
// Caller retains ownership of all pointers and they cannot be nullptr.
// Returns true if successful, false otherwise.
virtual bool GetECKey(ECPrivateKey::EllipticCurve curve,
std::string* private_key, std::string* public_key) = 0;
private:
ECKeySource(const ECKeySource&) = delete;
ECKeySource& operator=(const ECKeySource&) = delete;
};
} // namespace widevine
#endif // COMMON_EC_KEY_SOURCE_H_

View File

@@ -1,315 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit tests for the ECPrivateKey and ECPublicKey classes.
#include "common/ec_key.h"
#include <memory>
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "openssl/sha.h"
#include "common/ec_test_keys.h"
#include "common/ec_util.h"
#include "common/random_util.h"
using ::testing::IsNull;
namespace widevine {
class ECKeyTest : public ::testing::Test {
public:
static std::vector<std::tuple<std::string, std::string> > GetTestKeyList() {
std::vector<std::tuple<std::string, std::string> > test_key_list;
ECTestKeys test_keys;
test_key_list.push_back(
std::make_tuple(test_keys.private_test_key_1_secp521r1(),
test_keys.public_test_key_1_secp521r1()));
test_key_list.push_back(
std::make_tuple(test_keys.private_test_key_1_secp384r1(),
test_keys.public_test_key_1_secp384r1()));
test_key_list.push_back(
std::make_tuple(test_keys.private_test_key_1_secp256r1(),
test_keys.public_test_key_1_secp256r1()));
return test_key_list;
}
protected:
ECKeyTest() { plaintext_message_ = "This is a plaintext message."; }
void GenerateEphemeralKeyPair(ECPrivateKey::EllipticCurve curve) {
ASSERT_NE(curve, ECPrivateKey::UNDEFINED_CURVE);
bssl::UniquePtr<EC_KEY> ephemeral_key_pair(
EC_KEY_new_by_curve_name(ec_util::CurveToNid(curve)));
ASSERT_TRUE(ephemeral_key_pair != nullptr);
ASSERT_TRUE(EC_KEY_generate_key(ephemeral_key_pair.get()));
// Separate them out into their private and public parts.
std::string private_key;
std::string public_key;
ASSERT_TRUE(
ec_util::SerializeECPrivateKey(ephemeral_key_pair.get(), &private_key));
ASSERT_TRUE(
ec_util::SerializeECPublicKey(ephemeral_key_pair.get(), &public_key));
ephemeral_private_key_ = ECPrivateKey::Create(private_key);
ephemeral_public_key_ = ECPublicKey::Create(public_key);
}
std::unique_ptr<ECPrivateKey> ephemeral_private_key_;
std::unique_ptr<ECPublicKey> ephemeral_public_key_;
std::string plaintext_message_;
};
TEST_F(ECKeyTest, KeyCurve) {
ECTestKeys test_keys;
EXPECT_EQ(
ECPrivateKey::Create(test_keys.private_test_key_1_secp521r1())->Curve(),
ECPrivateKey::SECP521R1);
EXPECT_EQ(
ECPrivateKey::Create(test_keys.private_test_key_1_secp384r1())->Curve(),
ECPrivateKey::SECP384R1);
EXPECT_EQ(
ECPrivateKey::Create(test_keys.private_test_key_1_secp256r1())->Curve(),
ECPrivateKey::SECP256R1);
EXPECT_EQ(
ECPublicKey::Create(test_keys.public_test_key_1_secp521r1())->Curve(),
ECPrivateKey::SECP521R1);
EXPECT_EQ(
ECPublicKey::Create(test_keys.public_test_key_1_secp384r1())->Curve(),
ECPrivateKey::SECP384R1);
EXPECT_EQ(
ECPublicKey::Create(test_keys.public_test_key_1_secp256r1())->Curve(),
ECPrivateKey::SECP256R1);
}
TEST_F(ECKeyTest, KeyPointEncodingNullDeath) {
EXPECT_DEATH(ephemeral_public_key_->GetPointEncodedKey(nullptr), "");
}
class ECKeyTestKeyPairs : public ECKeyTest,
public ::testing::WithParamInterface<
std::tuple<std::string, std::string> > {
protected:
ECKeyTestKeyPairs() {
test_private_key_ = std::get<0>(GetParam());
test_public_key_ = std::get<1>(GetParam());
private_key_ = ECPrivateKey::Create(test_private_key_);
public_key_ = ECPublicKey::Create(test_public_key_);
}
std::string test_private_key_;
std::string test_public_key_;
std::unique_ptr<ECPrivateKey> private_key_;
std::unique_ptr<ECPublicKey> public_key_;
};
// Death test naming convention. See below link for details:
// go/gunitadvanced#death-test-naming
using ECKeyTestKeyPairsDeathTest = ECKeyTestKeyPairs;
TEST_P(ECKeyTestKeyPairs, CreateWrongKey) {
EXPECT_EQ(ECPrivateKey::Create(test_public_key_), nullptr);
EXPECT_EQ(ECPublicKey::Create(test_private_key_), nullptr);
}
TEST_P(ECKeyTestKeyPairs, InvalidKeyConstructorParameters) {
EXPECT_DEATH(ECPrivateKey(nullptr), "");
EXPECT_DEATH(ECPublicKey(nullptr), "");
EC_KEY* key;
ASSERT_TRUE(ec_util::DeserializeECPrivateKey(test_private_key_, &key));
// Brace initialization to avoid most vexing parse.
EXPECT_DEATH(ECPublicKey{key}, "");
EC_KEY_free(key);
ASSERT_TRUE(ec_util::DeserializeECPublicKey(test_public_key_, &key));
EXPECT_DEATH(ECPrivateKey{key}, "");
EC_KEY_free(key);
}
TEST_P(ECKeyTestKeyPairs, KeyMatch) {
EXPECT_TRUE(private_key_->MatchesPrivateKey(*private_key_));
EXPECT_TRUE(private_key_->MatchesPublicKey(*public_key_));
EXPECT_TRUE(public_key_->MatchesPrivateKey(*private_key_));
EXPECT_TRUE(public_key_->MatchesPublicKey(*public_key_));
}
TEST_P(ECKeyTestKeyPairs, DeriveSharedSessionKey) {
std::string derived_shared_session_key_1;
// Generate a temporary key pair as part of ECDH.
GenerateEphemeralKeyPair(private_key_->Curve());
EXPECT_TRUE(private_key_->DeriveSharedSessionKey(
*ephemeral_public_key_, &derived_shared_session_key_1));
EXPECT_EQ(derived_shared_session_key_1.size(), SHA256_DIGEST_LENGTH);
std::string derived_shared_session_key_2;
EXPECT_TRUE(ephemeral_private_key_->DeriveSharedSessionKey(
*public_key_, &derived_shared_session_key_2));
EXPECT_EQ(derived_shared_session_key_1, derived_shared_session_key_2);
}
TEST_P(ECKeyTestKeyPairs, InvalidDeriveSharedSessionKeyParameters) {
GenerateEphemeralKeyPair(private_key_->Curve());
EXPECT_FALSE(
private_key_->DeriveSharedSessionKey(*ephemeral_public_key_, nullptr));
EXPECT_FALSE(
ephemeral_private_key_->DeriveSharedSessionKey(*public_key_, nullptr));
}
TEST_P(ECKeyTestKeyPairs, SignVerify) {
std::string signature;
EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature));
EXPECT_TRUE(public_key_->VerifySignature(plaintext_message_, signature));
}
TEST_P(ECKeyTestKeyPairs, SignVerifySha1) {
std::string signature;
EXPECT_FALSE(private_key_->GenerateSignature(
plaintext_message_, HashAlgorithm::kSha1, &signature));
EXPECT_FALSE(public_key_->VerifySignature(plaintext_message_,
HashAlgorithm::kSha1, signature));
}
TEST_P(ECKeyTestKeyPairs, SignVerifySha256) {
std::string signature;
ASSERT_TRUE(private_key_->GenerateSignature(
plaintext_message_, HashAlgorithm::kSha256, &signature));
ASSERT_TRUE(public_key_->VerifySignature(plaintext_message_,
HashAlgorithm::kSha256, signature));
}
TEST_P(ECKeyTestKeyPairs, SignVerifyUnspecified) {
std::string signature;
ASSERT_TRUE(private_key_->GenerateSignature(
plaintext_message_, HashAlgorithm::kUnspecified, &signature));
ASSERT_TRUE(public_key_->VerifySignature(
plaintext_message_, HashAlgorithm::kUnspecified, signature));
}
TEST_P(ECKeyTestKeyPairsDeathTest, SignVerifyUnexpected) {
std::string signature;
HashAlgorithm unexpected_hash_algorithm = static_cast<HashAlgorithm>(1234);
EXPECT_DEATH(private_key_->GenerateSignature(
plaintext_message_, unexpected_hash_algorithm, &signature),
"Unexpected hash algorithm: 1234");
EXPECT_FALSE(public_key_->VerifySignature(
plaintext_message_, unexpected_hash_algorithm, signature));
}
TEST_P(ECKeyTestKeyPairs, InvalidSignVerifyParameters) {
std::string signature;
EXPECT_FALSE(private_key_->GenerateSignature("", &signature));
EXPECT_FALSE(public_key_->VerifySignature("", "signature"));
EXPECT_FALSE(private_key_->GenerateSignature(plaintext_message_, nullptr));
EXPECT_FALSE(public_key_->VerifySignature(plaintext_message_, ""));
}
TEST_P(ECKeyTestKeyPairs, KeyMismatch) {
GenerateEphemeralKeyPair(private_key_->Curve());
EXPECT_FALSE(private_key_->MatchesPrivateKey(*ephemeral_private_key_));
EXPECT_FALSE(private_key_->MatchesPublicKey(*ephemeral_public_key_));
EXPECT_FALSE(public_key_->MatchesPrivateKey(*ephemeral_private_key_));
EXPECT_FALSE(public_key_->MatchesPublicKey(*ephemeral_public_key_));
}
TEST_P(ECKeyTestKeyPairs, SignVerifyKeyMismatch) {
std::string signature;
GenerateEphemeralKeyPair(private_key_->Curve());
EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature));
EXPECT_FALSE(
ephemeral_public_key_->VerifySignature(plaintext_message_, signature));
}
TEST_P(ECKeyTestKeyPairs, KeyPointEncodingCreateBadKeyPoint) {
ASSERT_THAT(ECPublicKey::CreateFromKeyPoint(public_key_->Curve(), ""),
IsNull());
}
TEST_P(ECKeyTestKeyPairs, KeyPointEncodingCreateBadCurve) {
std::string serialized_key_point;
ASSERT_TRUE(public_key_->GetPointEncodedKey(&serialized_key_point));
ASSERT_THAT(ECPublicKey::CreateFromKeyPoint(ECPrivateKey::UNDEFINED_CURVE,
serialized_key_point),
IsNull());
}
TEST_P(ECKeyTestKeyPairs, KeyPointEncodingSuccess) {
std::string serialized_key_point;
ASSERT_TRUE(public_key_->GetPointEncodedKey(&serialized_key_point));
ASSERT_EQ(ec_util::GetPublicKeyPointSize(public_key_->Curve()),
serialized_key_point.size());
// Check that the leading byte indicates uncompressed.
ASSERT_EQ(4, serialized_key_point[0]);
std::unique_ptr<ECPublicKey> new_public_key = ECPublicKey::CreateFromKeyPoint(
public_key_->Curve(), serialized_key_point);
ASSERT_THAT(new_public_key, testing::NotNull());
EXPECT_TRUE(new_public_key->MatchesPublicKey(*public_key_));
EXPECT_TRUE(new_public_key->MatchesPrivateKey(*private_key_));
};
INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairs, ECKeyTestKeyPairs,
::testing::ValuesIn(ECKeyTest::GetTestKeyList()));
INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairsDeathTest, ECKeyTestKeyPairsDeathTest,
::testing::ValuesIn(ECKeyTest::GetTestKeyList()));
class ECKeyTestCurveMismatch
: public ECKeyTest,
public ::testing::WithParamInterface<
std::tuple<std::tuple<std::string, std::string>,
std::tuple<std::string, std::string> > > {
protected:
ECKeyTestCurveMismatch() {
private_key_ = ECPrivateKey::Create(std::get<0>(std::get<0>(GetParam())));
public_key_ = ECPublicKey::Create(std::get<1>(std::get<0>(GetParam())));
wrong_curve_private_key_ =
ECPrivateKey::Create(std::get<0>(std::get<1>(GetParam())));
wrong_curve_public_key_ =
ECPublicKey::Create(std::get<1>(std::get<1>(GetParam())));
}
void SetUp() override {
// Only run combinations where the two curves differ.
if (std::get<0>(GetParam()) == std::get<1>(GetParam())) GTEST_SKIP();
}
std::unique_ptr<ECPrivateKey> private_key_;
std::unique_ptr<ECPublicKey> public_key_;
std::unique_ptr<ECPrivateKey> wrong_curve_private_key_;
std::unique_ptr<ECPublicKey> wrong_curve_public_key_;
};
TEST_P(ECKeyTestCurveMismatch, CurveMismatch) {
EXPECT_FALSE(private_key_->MatchesPrivateKey(*wrong_curve_private_key_));
EXPECT_FALSE(private_key_->MatchesPublicKey(*wrong_curve_public_key_));
EXPECT_FALSE(public_key_->MatchesPrivateKey(*wrong_curve_private_key_));
EXPECT_FALSE(public_key_->MatchesPublicKey(*wrong_curve_public_key_));
}
TEST_P(ECKeyTestCurveMismatch, DeriveSharedSessionKeyCurveMismatch) {
std::string derived_shared_session_key;
EXPECT_FALSE(private_key_->DeriveSharedSessionKey(
*wrong_curve_public_key_, &derived_shared_session_key));
}
TEST_P(ECKeyTestCurveMismatch, SignVerifyCurveMismatch) {
std::string signature;
EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature));
EXPECT_FALSE(
wrong_curve_public_key_->VerifySignature(plaintext_message_, signature));
}
INSTANTIATE_TEST_SUITE_P(
ECKeyTestCurveMismatch, ECKeyTestCurveMismatch,
::testing::Combine(::testing::ValuesIn(ECKeyTest::GetTestKeyList()),
::testing::ValuesIn(ECKeyTest::GetTestKeyList())));
} // namespace widevine

View File

@@ -1,202 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit tests for ec_util.
#include "common/ec_util.h"
#include <stddef.h>
#include <memory>
#include "glog/logging.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/ec_test_keys.h"
#include "common/openssl_util.h"
namespace widevine {
namespace ec_util {
class ECUtilTest : public ::testing::Test {
protected:
ECTestKeys test_keys_;
// Given serialization and deserialization methods for an EC_KEY and a test
// key, this checks that that those methods can deserialize to a valid EC_KEY
// and serialize to the same test key.
template <bool (*SerializeECKey)(const EC_KEY*, std::string*),
bool (*DeserializeECKey)(const std::string&, EC_KEY** private_key)>
void SerializeDeserializeECKeyCheck(const std::string& test_key) {
EC_KEY* key = nullptr;
std::string serialized_key;
EXPECT_TRUE(DeserializeECKey(test_key, &key));
ASSERT_TRUE(key != nullptr);
EXPECT_TRUE(SerializeECKey(key, &serialized_key));
EXPECT_EQ(serialized_key, test_key);
EXPECT_EQ(EC_KEY_check_key(key), 1);
EC_KEY_free(key);
}
// Given serialization and deserialization methods for an EC_KEY and a test
// key, this method checks that deserialization fails for a bad input std::string
// and both serialization and deserialization fail on nullptrs.
template <bool (*SerializeECKey)(const EC_KEY*, std::string*),
bool (*DeserializeECKey)(const std::string&, EC_KEY** private_key)>
void SerializeDeserializeECKeyValidateInput(const std::string& test_key) {
EC_KEY* key = nullptr;
// Invalid key
EXPECT_FALSE(DeserializeECKey("this is a bad key", &key));
EXPECT_EQ(key, nullptr);
// Invalid pointers
EXPECT_TRUE(DeserializeECKey(test_key, &key));
EXPECT_FALSE(SerializeECKey(key, nullptr));
EC_KEY_free(key);
EXPECT_FALSE(DeserializeECKey(test_key, nullptr));
}
};
TEST_F(ECUtilTest, SerializeDeserializePrivateKey) {
SerializeDeserializeECKeyCheck<SerializeECPrivateKey,
DeserializeECPrivateKey>(
test_keys_.private_test_key_1_secp521r1());
SerializeDeserializeECKeyCheck<SerializeECPrivateKey,
DeserializeECPrivateKey>(
test_keys_.private_test_key_1_secp384r1());
SerializeDeserializeECKeyCheck<SerializeECPrivateKey,
DeserializeECPrivateKey>(
test_keys_.private_test_key_1_secp256r1());
SerializeDeserializeECKeyValidateInput<SerializeECPrivateKey,
DeserializeECPrivateKey>(
test_keys_.private_test_key_1_secp521r1());
}
TEST_F(ECUtilTest, SerializeDeserializePublicKey) {
SerializeDeserializeECKeyCheck<SerializeECPublicKey, DeserializeECPublicKey>(
test_keys_.public_test_key_1_secp521r1());
SerializeDeserializeECKeyCheck<SerializeECPublicKey, DeserializeECPublicKey>(
test_keys_.public_test_key_1_secp384r1());
SerializeDeserializeECKeyCheck<SerializeECPublicKey, DeserializeECPublicKey>(
test_keys_.public_test_key_1_secp256r1());
SerializeDeserializeECKeyValidateInput<SerializeECPublicKey,
DeserializeECPublicKey>(
test_keys_.public_test_key_1_secp521r1());
}
TEST_F(ECUtilTest, PublicKeyExtraction) {
EC_KEY* private_key = nullptr;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeECPrivateKey(test_keys_.private_test_key_1_secp521r1(),
&private_key));
ASSERT_TRUE(private_key != nullptr);
EXPECT_TRUE(SerializeECPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_secp521r1());
EC_KEY_free(private_key);
private_key = nullptr;
// Key 2
EXPECT_TRUE(DeserializeECPrivateKey(test_keys_.private_test_key_1_secp384r1(),
&private_key));
ASSERT_TRUE(private_key != nullptr);
EXPECT_TRUE(SerializeECPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_secp384r1());
EC_KEY_free(private_key);
private_key = nullptr;
// Key 3
EXPECT_TRUE(DeserializeECPrivateKey(test_keys_.private_test_key_1_secp256r1(),
&private_key));
ASSERT_TRUE(private_key != nullptr);
EXPECT_TRUE(SerializeECPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_secp256r1());
EC_KEY_free(private_key);
}
TEST_F(ECUtilTest, GetPublicKeyPointSizeAll) {
ASSERT_GT(ec_util::GetPublicKeyPointSize(ECPrivateKey::SECP256R1), 0);
ASSERT_GT(ec_util::GetPublicKeyPointSize(ECPrivateKey::SECP384R1), 0);
ASSERT_GT(ec_util::GetPublicKeyPointSize(ECPrivateKey::SECP521R1), 0);
ASSERT_EQ(0, ec_util::GetPublicKeyPointSize(ECPrivateKey::UNDEFINED_CURVE));
}
TEST_F(ECUtilTest, GetPublicKeyFromKeyPointDeath) {
EXPECT_DEATH(GetPublicKeyFromKeyPoint(ECPrivateKey::SECP256R1, "", nullptr),
"");
}
class ECKeyPointTest : public ::testing::Test,
public ::testing::WithParamInterface<std::string> {
public:
static std::vector<std::string> GetTestKeyList() {
ECTestKeys test_keys;
return {test_keys.public_test_key_1_secp256r1(),
test_keys.public_test_key_1_secp384r1(),
test_keys.public_test_key_1_secp521r1()};
}
void SetUp() override {
serialized_public_key_ = GetParam();
EC_KEY* public_key = nullptr;
ASSERT_TRUE(DeserializeECPublicKey(serialized_public_key_, &public_key));
ASSERT_TRUE(public_key != nullptr);
ec_public_key_.reset(public_key);
curve_ = NidToCurve(
EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_public_key_.get())));
}
protected:
std::string serialized_public_key_;
ScopedECKEY ec_public_key_;
ECPrivateKey::EllipticCurve curve_;
};
INSTANTIATE_TEST_SUITE_P(ECUtilKeyPointTest, ECKeyPointTest,
::testing::ValuesIn(ECKeyPointTest::GetTestKeyList()));
TEST_P(ECKeyPointTest, GetPublicKeyPointDeath) {
EXPECT_DEATH(GetPublicKeyPoint(ec_public_key_.get(), nullptr), "");
}
TEST_P(ECKeyPointTest, GetPublicKeyFromKeyPointInvalidCurve) {
std::string encoded_key;
ASSERT_TRUE(GetPublicKeyPoint(ec_public_key_.get(), &encoded_key));
EC_KEY* new_public_key = nullptr;
EXPECT_FALSE(GetPublicKeyFromKeyPoint(ECPrivateKey::UNDEFINED_CURVE,
encoded_key, &new_public_key));
}
TEST_P(ECKeyPointTest, GetPublicKeyFromKeyPointInvalidSize) {
EC_KEY* new_public_key = nullptr;
EXPECT_FALSE(GetPublicKeyFromKeyPoint(curve_, "", &new_public_key));
}
TEST_P(ECKeyPointTest, PublicKeyPointFormatTest) {
std::string encoded_key;
ASSERT_TRUE(GetPublicKeyPoint(ec_public_key_.get(), &encoded_key));
ASSERT_FALSE(encoded_key.empty());
EXPECT_EQ(4, encoded_key[0]);
EXPECT_EQ(GetPublicKeyPointSize(curve_), encoded_key.size());
// Create a new EC key from the key point.
EC_KEY* ec_key = nullptr;
ASSERT_TRUE(GetPublicKeyFromKeyPoint(curve_, encoded_key, &ec_key));
ASSERT_TRUE(ec_key != nullptr);
ScopedECKEY new_public_key(ec_key);
// EC_POINT_cmp returns 0 if the keys match.
ASSERT_EQ(
0, EC_POINT_cmp(EC_KEY_get0_group(ec_public_key_.get()),
EC_KEY_get0_public_key(ec_public_key_.get()),
EC_KEY_get0_public_key(new_public_key.get()), nullptr));
}
} // namespace ec_util
} // namespace widevine

View File

@@ -1,117 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Implementation of ecb crypto routines used by Widevine services.
#include "common/ecb_util.h"
#include "glog/logging.h"
#include "absl/strings/string_view.h"
#include "openssl/aes.h"
#include "openssl/des.h"
namespace widevine {
namespace crypto_util {
const int kWvmDESKeySizeBytes = 16;
static bool EncryptOrDecrypt3DesCbc(absl::string_view key,
absl::string_view src, std::string* dst,
bool encrypt) {
CHECK(dst);
if (key.size() != kWvmDESKeySizeBytes) {
LOG(WARNING) << "Invalid 3DES key size (" << key.size() << "!=16).";
dst->clear();
return false;
}
const int data_size = src.size();
if (data_size % DES_KEY_SZ != 0) {
// Data must be a multiple of block size
LOG(WARNING) << "3DES data is not a multiple of 8 bytes.";
dst->clear();
return false;
}
const int data_size_blocks = data_size / DES_KEY_SZ;
DES_key_schedule schedule[2];
// const_DES_cblock (the type of the first argument to DES_ecb3_encrypt) isn't
// actually const, so we have to cast away const.
DES_cblock* keyblock =
const_cast<DES_cblock*>(reinterpret_cast<const DES_cblock*>(key.data()));
DES_set_key(keyblock + 0, schedule + 1);
DES_set_key(keyblock + 1, schedule + 0);
DES_cblock* srcblock =
const_cast<DES_cblock*>(reinterpret_cast<const DES_cblock*>(src.data()));
dst->resize(data_size);
DES_cblock* dstblock = reinterpret_cast<DES_cblock*>(&*dst->begin());
for (int i = 0; i < data_size_blocks; i++) {
DES_ecb3_encrypt(srcblock + i, dstblock + i, schedule + 0, schedule + 1,
schedule + 0, encrypt);
}
return true;
}
bool Encrypt3DesEcb(absl::string_view key, absl::string_view src,
std::string* dst) {
return EncryptOrDecrypt3DesCbc(key, src, dst, DES_ENCRYPT);
}
bool Decrypt3DesEcb(absl::string_view key, absl::string_view src,
std::string* dst) {
return EncryptOrDecrypt3DesCbc(key, src, dst, DES_DECRYPT);
}
bool EncryptAesEcb(absl::string_view key, absl::string_view src,
std::string* dst) {
CHECK(dst);
dst->clear();
if (src.size() % 16 != 0) {
LOG(WARNING) << "AES-ECB data is not a multiple of 16 bytes.";
return false;
}
int num_bits = key.size() * 8;
AES_KEY aes_key;
int aes_result = AES_set_encrypt_key(
reinterpret_cast<const uint8_t*>(key.data()), num_bits, &aes_key);
if (aes_result != 0) {
LOG(WARNING) << "AES result is not zero.";
return false;
}
dst->resize(src.size());
for (int i = 0; i < src.size(); i += AES_BLOCK_SIZE) {
AES_encrypt(reinterpret_cast<const uint8_t*>(src.data() + i),
reinterpret_cast<uint8_t*>(&(*dst)[i]), &aes_key);
}
return true;
}
bool DecryptAesEcb(absl::string_view key, absl::string_view src,
std::string* dst) {
CHECK(dst);
dst->clear();
if (src.size() % 16 != 0) {
LOG(WARNING) << "AES-ECB data is not a multiple of 16 bytes.";
return false;
}
int num_bits = key.size() * 8;
AES_KEY aes_key;
int aes_result = AES_set_decrypt_key(
reinterpret_cast<const uint8_t*>(key.data()), num_bits, &aes_key);
if (aes_result != 0) {
LOG(WARNING) << "AES result is not zero.";
return false;
}
dst->resize(src.size());
for (int i = 0; i < src.size(); i += AES_BLOCK_SIZE) {
AES_decrypt(reinterpret_cast<const uint8_t*>(src.data() + i),
reinterpret_cast<uint8_t*>(&(*dst)[i]), &aes_key);
}
return true;
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -1,63 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Contains ecb crypto routines for widevine protocols. These routines are used
// as part of licensing and provisioning request handling.
#ifndef COMMON_ECB_UTIL_H_
#define COMMON_ECB_UTIL_H_
#include <string>
#include "absl/strings/string_view.h"
namespace widevine {
namespace crypto_util {
// Encrypts |src| into |dst| using 3DES ECB2 mode with the given key. This is
// used for protecting content keys on some older Widevine keyboxes, and is not
// intended for any other purpose. Returns false and sets *|dst|="" if
// unsuccessful. Key should be 16 bytes. The first 8 are key2 of the 3DES key
// bundle, and the last 8 bytes are key1 and key3. |src| must be a multiple of
// 8 bytes.
bool Encrypt3DesEcb(absl::string_view key, absl::string_view src,
std::string* dst);
// Decrypts |src| into |dst| using 3DES ECB2 mode with the given (16-byte)
// key. This is used for protecting content keys on some older Widevine
// keyboxes, and is not intended for any other purpose.
// Returns false and sets *|dst|="" if unsuccessful. Note that it can only
// fail if invalid key or data sizes are passed in.
// Key should be 16 bytes. The first 8 are key2 of the 3DES key bundle,
// and the last 8 bytes are key1 and key3. |src| must be a multiple of
// 8 bytes.
bool Decrypt3DesEcb(absl::string_view key, absl::string_view src,
std::string* dst);
// Encrypts |src| into |dst| using AES ECB mode with the given
// key. This is used for protecting content keys on Widevine devices,
// and is not intended for any other purpose.
// Returns false and sets *|dst|="" if unsuccessful. Note that it can only
// fail if invalid key or data sizes are passed in.
// Key must be 16 bytes, and src must be a multiple of 16 bytes.
bool EncryptAesEcb(absl::string_view key, absl::string_view src,
std::string* dst);
// Decrypts |src| into |dst| using AES ECB mode with the given
// key. This is used for protecting content keys on Widevine devices,
// and is not intended for any other purpose.
// Returns false and sets *|dst|="" if unsuccessful. Note that it can only
// fail if invalid key or data sizes are passed in.
// Key must be 16 bytes, and src must be a multiple of 16 bytes.
bool DecryptAesEcb(absl::string_view key, absl::string_view src,
std::string* dst);
} // namespace crypto_util
} // namespace widevine
#endif // COMMON_ECB_UTIL_H_

View File

@@ -1,90 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Unit tests for the ecb_util functions.
#include <string>
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "common/ecb_util.h"
namespace widevine {
namespace crypto_util {
TEST(CryptoUtilTest, TestEncrypt3DesEcb) {
// Test vector generated by (Python):
// c = M2Crypto.EVP.Cipher('des_ede3_ecb', '89abcdef0123456789abcdef',
// iv='', op=1, padding=False)
// (c.update('This is a test message. ')+c.final()).encode('hex')
// TODO(user): find some Widevine test vectors and use those
std::string key = "0123456789abcdef";
std::string plain = "This is a test message. ";
std::string cipher;
std::string decrypted;
EXPECT_TRUE(Encrypt3DesEcb(key, plain, &cipher));
EXPECT_EQ("ae7c7accaf99a973e7f89bb7f6dc61a9aa9e226a5ba17376",
absl::BytesToHexString(cipher));
EXPECT_TRUE(Decrypt3DesEcb(key, cipher, &decrypted));
EXPECT_EQ(plain, decrypted);
}
TEST(CryptoUtilTest, TestEncrypt3DesEcbFail) {
// Verify that 3DES fails with invalid key or data size
std::string badkey = "0123456789abcde"; // 15 bytes
std::string badplain = "This is a test message."; // 23 bytes
std::string goodkey = "0123456789abcdef"; // 16 bytes
std::string goodplain = "This is a test message. "; // 24 bytes
// Encryption failure should leave 'decrypted' as empty std::string
std::string out = "Not empty";
EXPECT_FALSE(Encrypt3DesEcb(badkey, goodplain, &out));
EXPECT_TRUE(out.empty());
out = "Not empty";
EXPECT_FALSE(Decrypt3DesEcb(goodkey, badplain, &out));
EXPECT_TRUE(out.empty());
}
TEST(CryptoUtilTest, TestEncryptAesEcb) {
// Test vector generated by (Python):
// c = M2Crypto.EVP.Cipher('aes_128_ecb', key, '', 1, padding=False)
// encrypted = c.update(data) + c.final();
// TODO(user): find some Widevine test vectors and use those
std::string key = "0123456789abcdef";
std::string plaintext = "This message has 32 bytes in it.";
std::string encrypted;
std::string decrypted;
EXPECT_TRUE(EncryptAesEcb(key, plaintext, &encrypted));
EXPECT_EQ("1f6a7d63e0645de25c56c6b39ba7723d640129d65f41e96b87be812bc94ad8a9",
absl::BytesToHexString(encrypted));
EXPECT_TRUE(DecryptAesEcb(key, encrypted, &decrypted));
EXPECT_EQ(plaintext, decrypted);
}
TEST(CryptoUtilTest, TestEncryptAesEcbFail) {
// Verify that EncryptAesEcb fails with invalid key or data size
std::string badkey = "0123456789abcde"; // 15 bytes
std::string badplain = "This message has 31 bytes in it";
std::string goodkey = "0123456789abcdef"; // 16 bytes
std::string goodplain = "This message has 32 bytes in it.";
// Encryption failure should leave 'decrypted' as empty std::string
std::string out = "Not empty";
EXPECT_FALSE(EncryptAesEcb(badkey, goodplain, &out));
EXPECT_TRUE(out.empty());
out = "Not empty";
EXPECT_FALSE(EncryptAesEcb(goodkey, badplain, &out));
EXPECT_TRUE(out.empty());
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -1,239 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/ecies_crypto.h"
#include <memory>
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "openssl/ec.h"
#include "common/aes_cbc_util.h"
#include "common/crypto_util.h"
#include "common/ec_key.h"
#include "common/ec_util.h"
#include "common/openssl_util.h"
namespace {
const char kZeroIv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const size_t kMacSizeBytes = 32;
const size_t kMasterKeySizeBytes = 32;
const size_t kEncryptionKeySizeBytes = kMasterKeySizeBytes;
const size_t kSigningKeySizeBytes = kMasterKeySizeBytes;
const size_t kEncryptionKeySizeBits = kEncryptionKeySizeBytes * 8;
const size_t kSigningKeySizeBits = kSigningKeySizeBytes * 8;
const char kWrappingKeyLabel[] = "ECIESEncryptionLabel";
const char kSigningKeyLabel[] = "ECIESSigningLabel";
bool DeriveWrappingAndSigningKeys(const std::string& key,
const std::string& context,
std::string* wrapping_key,
std::string* signing_key) {
if (wrapping_key == nullptr || signing_key == nullptr) return false;
if (key.size() != kMasterKeySizeBytes) {
LOG(ERROR) << "Invalid master key size";
return false;
}
*wrapping_key = widevine::crypto_util::DeriveKey(
key, kWrappingKeyLabel, context, kEncryptionKeySizeBits);
if (wrapping_key->empty()) {
LOG(WARNING) << "Failed to derive encryption key.";
return false;
}
*signing_key = widevine::crypto_util::DeriveKey(
key, kSigningKeyLabel, context, kSigningKeySizeBits);
if (signing_key->empty()) {
LOG(WARNING) << "Failed to derive sigining key.";
return false;
}
return true;
}
} // anonymous namespace
namespace widevine {
EciesEncryptor::EciesEncryptor(std::unique_ptr<ECPublicKey> public_key,
ECKeySource* key_source)
: public_key_(std::move(public_key)), key_source_(key_source) {}
std::unique_ptr<EciesEncryptor> EciesEncryptor::Create(
const std::string& serialized_public_key, ECKeySource* key_source) {
if (key_source == nullptr) {
return nullptr;
}
std::unique_ptr<ECPublicKey> ec_key =
ECPublicKey::Create(serialized_public_key);
if (ec_key == nullptr) {
return nullptr;
}
std::unique_ptr<EciesEncryptor> encryptor(
new EciesEncryptor(std::move(ec_key), key_source));
return encryptor;
}
bool EciesEncryptor::Encrypt(const std::string& plaintext,
const std::string& context,
std::string* ecies_message) const {
if (ecies_message == nullptr) {
LOG(ERROR) << "ecies_message cannot be null";
return false;
}
std::string serialized_private_key;
std::string serialized_public_key;
if (!key_source_->GetECKey(public_key_->Curve(), &serialized_private_key,
&serialized_public_key)) {
LOG(WARNING) << "Failed to get key pair from key source.";
return false;
}
// Convert the ephemeral public key to an encoded EC point.
std::unique_ptr<ECPublicKey> ephemeral_public_key =
ECPublicKey::Create(serialized_public_key);
std::string encoded_public_key;
if (!ephemeral_public_key->GetPointEncodedKey(&encoded_public_key)) {
LOG(ERROR) << "Could not encode the public key. ";
return false;
}
// This condition is just an indication that the serialized_public_key doesn't
// match our size expectations. It shouldn't block the encryption operation.
size_t expected_size = ec_util::GetPublicKeyPointSize(public_key_->Curve());
if (encoded_public_key.size() != expected_size) {
LOG(WARNING) << "Unexpected key size for public key. "
<< "Curve " << public_key_->Curve() << ". Expected "
<< expected_size << ". Found " << encoded_public_key.size()
<< ".";
}
std::unique_ptr<ECPrivateKey> ephemeral_private_key =
ECPrivateKey::Create(serialized_private_key);
std::string session_key;
if (!ephemeral_private_key->DeriveSharedSessionKey(*public_key_,
&session_key)) {
LOG(WARNING) << "Failed to derive shared session key.";
return false;
}
std::string encryption_key;
std::string signing_key;
if (!DeriveWrappingAndSigningKeys(session_key, context, &encryption_key,
&signing_key)) {
return false;
}
std::string zero_iv(kZeroIv, sizeof(kZeroIv));
std::string ciphertext =
crypto_util::EncryptAesCbc(encryption_key, zero_iv, plaintext);
if (ciphertext.empty()) {
LOG(WARNING) << "Failed to encrypt plaintext.";
return false;
}
std::string signature =
crypto_util::CreateSignatureHmacSha256(signing_key, ciphertext);
if (signature.empty()) {
LOG(WARNING) << "Failed to sign plaintext.";
return false;
}
*ecies_message = encoded_public_key + ciphertext + signature;
return true;
}
std::unique_ptr<EciesDecryptor> EciesDecryptor::Create(
const std::string& serialized_private_key) {
std::unique_ptr<ECPrivateKey> ec_key =
ECPrivateKey::Create(serialized_private_key);
if (ec_key == nullptr) {
return nullptr;
}
std::unique_ptr<EciesDecryptor> decryptor(
new EciesDecryptor(std::move(ec_key)));
if (decryptor == nullptr) {
LOG(ERROR) << "Failed to create EciesDecryptor.";
}
return decryptor;
}
EciesDecryptor::EciesDecryptor(std::unique_ptr<ECPrivateKey> private_key)
: private_key_(std::move(private_key)) {}
bool EciesDecryptor::Decrypt(const std::string& ecies_message,
const std::string& context,
std::string* plaintext) const {
if (plaintext == nullptr) {
LOG(ERROR) << "plaintext cannot be null";
return false;
}
// Check the minimum std::string size.
size_t key_size = ec_util::GetPublicKeyPointSize(private_key_->Curve());
if (key_size + kMacSizeBytes > ecies_message.size()) {
LOG(ERROR) << "The size of the message is too small. Expected > "
<< key_size + kMacSizeBytes << ". found "
<< ecies_message.size();
return false;
}
std::string ciphertext = ecies_message.substr(
key_size, ecies_message.size() - kMacSizeBytes - key_size);
std::string signature =
ecies_message.substr(ecies_message.size() - kMacSizeBytes, kMacSizeBytes);
std::unique_ptr<ECPublicKey> public_key = ECPublicKey::CreateFromKeyPoint(
private_key_->Curve(), ecies_message.substr(0, key_size));
if (public_key == nullptr) {
LOG(WARNING) << "Failed to deserialize public key.";
return false;
}
std::string session_key;
if (!private_key_->DeriveSharedSessionKey(*public_key, &session_key)) {
LOG(WARNING) << "Failed to derive shared session key.";
return false;
}
std::string encryption_key;
std::string signing_key;
if (!DeriveWrappingAndSigningKeys(session_key, context, &encryption_key,
&signing_key)) {
LOG(WARNING) << "Failed to derive shared wrapping and signing keys.";
return false;
}
if (!crypto_util::VerifySignatureHmacSha256(signing_key, signature,
ciphertext)) {
LOG(WARNING) << "Failed to verify signature on ciphertext.";
return false;
}
std::string zero_iv(kZeroIv, sizeof(kZeroIv));
// In theory, we should be able to decrypt a cipher block that was originally
// the empty string. But DecryptAesCbc uses an empty std::string to indicate an
// error. This means that we can't distinguish between an error and correctly
// decrypted empty string.
*plaintext = crypto_util::DecryptAesCbc(encryption_key, zero_iv, ciphertext);
if (plaintext->empty()) {
LOG(WARNING) << "Failed to decrypt plaintext.";
return false;
}
return true;
}
} // namespace widevine.

View File

@@ -1,82 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_ECIES_CRYPTO_H_
#define COMMON_ECIES_CRYPTO_H_
#include <memory>
#include <string>
#include "common/ec_key.h"
#include "common/ec_key_source.h"
namespace widevine {
class EciesEncryptor {
public:
static std::unique_ptr<EciesEncryptor> Create(const std::string& public_key,
ECKeySource* key_source);
virtual ~EciesEncryptor() = default;
EciesEncryptor(const EciesEncryptor&) = delete;
EciesEncryptor& operator=(const EciesEncryptor&) = delete;
// Generates an encrypted EC-IES message using the public key, an ephemeral
// private key and context. This function uses AES 256 bit encryption with a
// master key derived from EC shared key generated from the public key and
// ephemeral private key.
// |plaintext| is the value to be encrypted.
// |context| is used as part of the key derivation.
// |ecies_message| is the concatenation of
// 1) the ephemeral public key.
// 2) the plaintext encrypted with the derived AES key using AES CBC,
// PKCS7 padding and a zerio iv.
// 3) The HMAC SHA256 of the cipher text.
// Returns false if there is a problem encrypting the content, true otherwise.
virtual bool Encrypt(const std::string& plaintext, const std::string& context,
std::string* ecies_message) const;
protected:
// Creates the EciesEncryptor with a given ECKey. This is protected in order
// to support mock tests.
EciesEncryptor(std::unique_ptr<ECPublicKey> public_key,
ECKeySource* key_source);
private:
std::unique_ptr<ECPublicKey> public_key_;
ECKeySource* key_source_;
};
class EciesDecryptor {
public:
static std::unique_ptr<EciesDecryptor> Create(
const std::string& serialized_private_key);
virtual ~EciesDecryptor() = default;
EciesDecryptor(const EciesDecryptor&) = delete;
EciesDecryptor& operator=(const EciesDecryptor&) = delete;
// Decrypts and verifies an EC-IES message using the private key, the
// ephemeral public key embedded in |ecies_message| and the |context|.
// This function uses a master AES key to decrypt the content and validate the
// signature. The content is encrypted with AES CBC, PKCS7 padded with a
// zero iv.
// |plaintext| will be populated iff decryption is successful and the
// signature is valid.
// Returns false if there is a problem decrypting the content, true otherwise.
virtual bool Decrypt(const std::string& ecies_message,
const std::string& context,
std::string* plaintext) const;
private:
explicit EciesDecryptor(std::unique_ptr<ECPrivateKey> private_key);
std::unique_ptr<ECPrivateKey> private_key_;
};
} // namespace widevine
#endif // COMMON_ECIES_CRYPTO_H_

View File

@@ -1,259 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/ecies_crypto.h"
#include <cstddef>
#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_key_source.h"
#include "common/ec_test_keys.h"
#include "common/ec_util.h"
#include "common/fake_ec_key_source.h"
using ::testing::_;
using ::testing::Return;
namespace {
const size_t kMacSizeBytes = 32;
} // anonymous namespace
namespace widevine {
class EciesCryptoTest
: public ::testing::Test,
public ::testing::WithParamInterface<
std::tuple<std::string, std::string, std::string, std::string> > {
public:
static std::vector<
std::tuple<std::string, std::string, std::string, std::string> >
GetTestKeyList() {
ECTestKeys test_keys;
std::vector<std::tuple<std::string, std::string, std::string, std::string> >
keys({std::make_tuple(test_keys.private_test_key_1_secp521r1(),
test_keys.public_test_key_1_secp521r1(),
test_keys.private_test_key_2_secp521r1(),
test_keys.public_test_key_2_secp521r1()),
std::make_tuple(test_keys.private_test_key_1_secp384r1(),
test_keys.public_test_key_1_secp384r1(),
test_keys.private_test_key_2_secp384r1(),
test_keys.public_test_key_2_secp384r1()),
std::make_tuple(test_keys.private_test_key_1_secp256r1(),
test_keys.public_test_key_1_secp256r1(),
test_keys.private_test_key_2_secp256r1(),
test_keys.public_test_key_2_secp256r1())});
return keys;
}
protected:
EciesCryptoTest() {
test_private_key_ = std::get<0>(GetParam());
test_public_key_ = std::get<1>(GetParam());
test_ephemeral_private_key_ = std::get<2>(GetParam());
test_ephemeral_public_key_ = std::get<3>(GetParam());
private_key_ = ECPrivateKey::Create(test_private_key_);
public_key_ = ECPublicKey::Create(test_public_key_);
ephemeral_private_key_ = ECPrivateKey::Create(test_ephemeral_private_key_);
ephemeral_public_key_ = ECPublicKey::Create(test_ephemeral_public_key_);
}
std::string test_private_key_;
std::string test_public_key_;
std::string test_ephemeral_private_key_;
std::string test_ephemeral_public_key_;
std::unique_ptr<ECPrivateKey> private_key_;
std::unique_ptr<ECPublicKey> public_key_;
std::unique_ptr<ECPrivateKey> ephemeral_private_key_;
std::unique_ptr<ECPublicKey> ephemeral_public_key_;
};
TEST_P(EciesCryptoTest, EciesEncryptSuccess) {
std::string serialized_public_key;
const std::string context = "test context";
const std::string plaintext = "test plaintext";
std::string ecies_message;
// Use the test ephemeral key in the key source.
FakeECKeySource fake_key_source;
ASSERT_TRUE(fake_key_source.SetKey(ephemeral_public_key_->Curve(),
test_ephemeral_private_key_,
test_ephemeral_public_key_));
std::unique_ptr<EciesEncryptor> encryptor =
EciesEncryptor::Create(test_public_key_, &fake_key_source);
ASSERT_TRUE(encryptor->Encrypt(plaintext, context, &ecies_message));
EXPECT_TRUE(ecies_message.find(plaintext) == std::string::npos);
// Verify the decrypted_message.
std::string decrypted_message;
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(test_private_key_);
ASSERT_TRUE(decryptor != nullptr);
ASSERT_TRUE(decryptor->Decrypt(ecies_message, context, &decrypted_message));
EXPECT_EQ(plaintext, decrypted_message);
}
TEST_P(EciesCryptoTest, EciesDecryptShortEciesMessage) {
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(test_private_key_);
ASSERT_NE(nullptr, decryptor.get());
std::string decrypted_message;
std::string short_message(
ec_util::GetPublicKeyPointSize(private_key_->Curve()) + kMacSizeBytes - 1,
'a');
ASSERT_FALSE(
decryptor->Decrypt(short_message, "test context", &decrypted_message));
}
TEST_P(EciesCryptoTest, EciesDecryptBadSignature) {
std::string serialized_public_key;
const std::string context = "test context";
const std::string plaintext = "test plaintext";
std::string ecies_message;
// Use the test ephemeral key in the key source.
FakeECKeySource fake_key_source;
ASSERT_TRUE(fake_key_source.SetKey(ephemeral_public_key_->Curve(),
test_ephemeral_private_key_,
test_ephemeral_public_key_));
std::unique_ptr<EciesEncryptor> encryptor =
EciesEncryptor::Create(test_public_key_, &fake_key_source);
ASSERT_TRUE(encryptor->Encrypt(plaintext, context, &ecies_message));
// Corrupt the signature (at end of message) and verify that decryption fails.
ecies_message[ecies_message.size() - 1]++;
std::string decrypted_message;
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(test_private_key_);
ASSERT_TRUE(decryptor != nullptr);
ASSERT_FALSE(decryptor->Decrypt(ecies_message, context, &decrypted_message));
EXPECT_EQ("", decrypted_message);
}
TEST_P(EciesCryptoTest, EciesEncryptMismatchContext) {
std::string serialized_public_key;
const std::string context = "test context";
const std::string bogus_context = "bogus_context";
const std::string plaintext = "test plaintext";
std::string ecies_message;
// Use the test ephemeral key in the key source.
FakeECKeySource fake_key_source;
ASSERT_TRUE(fake_key_source.SetKey(ephemeral_public_key_->Curve(),
test_ephemeral_private_key_,
test_ephemeral_public_key_));
std::unique_ptr<EciesEncryptor> encryptor =
EciesEncryptor::Create(test_public_key_, &fake_key_source);
ASSERT_TRUE(encryptor != nullptr);
ASSERT_TRUE(encryptor->Encrypt(plaintext, context, &ecies_message));
EXPECT_GT(
ecies_message.size(),
kMacSizeBytes + ec_util::GetPublicKeyPointSize(public_key_->Curve()));
// Verify the decrypted_message using the invalid context.
std::string decrypted_message;
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(test_private_key_);
ASSERT_TRUE(decryptor != nullptr);
ASSERT_FALSE(
decryptor->Decrypt(ecies_message, bogus_context, &decrypted_message));
EXPECT_TRUE(decrypted_message.empty());
}
INSTANTIATE_TEST_SUITE_P(
EciesCryptoTest, EciesCryptoTest,
::testing::ValuesIn(EciesCryptoTest::GetTestKeyList()));
TEST(EciesEncryptorTest, EciesEncryptBadPublicKey) {
// Use the test ephemeral key in the key source.
FakeECKeySource fake_key_source;
std::unique_ptr<EciesEncryptor> encryptor =
EciesEncryptor::Create("bad public key.", &fake_key_source);
ASSERT_TRUE(encryptor == nullptr);
}
TEST(EciesEncryptorTest, EciesEncryptNullKeySource) {
std::unique_ptr<EciesEncryptor> encryptor =
EciesEncryptor::Create("bad public key.", nullptr);
ASSERT_TRUE(encryptor == nullptr);
}
class MockEcKeySource : public ECKeySource {
public:
MockEcKeySource() = default;
MOCK_METHOD(bool, GetECKey,
(ECPrivateKey::EllipticCurve curve, std::string* private_key,
std::string* public_key),
(override));
};
TEST(EciesEncryptorTest, EciesEncryptKeysourceFail) {
MockEcKeySource mock_ec_key_source;
EXPECT_CALL(mock_ec_key_source, GetECKey(_, _, _)).WillOnce(Return(false));
ECTestKeys test_keys;
std::unique_ptr<EciesEncryptor> encryptor = EciesEncryptor::Create(
test_keys.public_test_key_1_secp256r1(), &mock_ec_key_source);
ASSERT_TRUE(encryptor != nullptr);
std::string ecies_message;
ASSERT_FALSE(
encryptor->Encrypt("test plaintext", "test context", &ecies_message));
}
TEST(EciesEncryptorTest, EciesEncryptNullEciesMessage) {
FakeECKeySource fake_key_source;
ECTestKeys test_keys;
std::unique_ptr<EciesEncryptor> encryptor = EciesEncryptor::Create(
test_keys.public_test_key_1_secp256r1(), &fake_key_source);
ASSERT_TRUE(encryptor != nullptr);
ASSERT_FALSE(encryptor->Encrypt("test plaintext", "test context", nullptr));
}
TEST(EciesDecryptorTest, EciesDecryptBadPrivateKey) {
ECTestKeys test_keys;
std::string invalid_private_key(test_keys.private_test_key_1_secp521r1());
invalid_private_key[0]++;
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(invalid_private_key);
ASSERT_TRUE(decryptor == nullptr);
}
TEST(EciesDecryptorTest, EciesDecryptEmptyEciesMessage) {
ECTestKeys test_keys;
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(test_keys.private_test_key_1_secp521r1());
ASSERT_NE(nullptr, decryptor);
std::string decrypted_message;
ASSERT_FALSE(decryptor->Decrypt("", "test context", &decrypted_message));
}
TEST(EciesDecryptorTest, EciesDecryptNullPlaintext) {
ECTestKeys test_keys;
std::unique_ptr<EciesDecryptor> decryptor =
EciesDecryptor::Create(test_keys.private_test_key_1_secp521r1());
ASSERT_NE(nullptr, decryptor);
std::string decrypted_message;
ASSERT_FALSE(decryptor->Decrypt("foo", "test context", nullptr));
}
} // namespace widevine

View File

@@ -1,19 +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 "common/error_space.h"
#include "util/proto_status.h"
#include "protos/public/errors.pb.h"
namespace widevine {
const util::ErrorSpace* error_space =
util::ProtoEnumErrorSpace<Errors>::Get();
} // namespace widevine

View File

@@ -1,20 +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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_ERROR_SPACE_H_
#define COMMON_ERROR_SPACE_H_
#include "util/error_space.h"
namespace widevine {
extern const util::ErrorSpace* error_space;
} // namespace widevine
#endif // COMMON_ERROR_SPACE_H_

View File

@@ -1,78 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Implementation of fake EC key generator. Returns precomputed test keys.
#include "common/fake_ec_key_source.h"
#include <memory>
#include <string>
#include <utility>
#include "glog/logging.h"
#include "common/ec_key.h"
#include "common/ec_test_keys.h"
namespace widevine {
FakeECKeySource::FakeECKeySource() {
ECTestKeys ec_test_keys;
CHECK(SetKey(ECPrivateKey::SECP256R1,
ec_test_keys.private_test_key_1_secp256r1(),
ec_test_keys.public_test_key_1_secp256r1()));
CHECK(SetKey(ECPrivateKey::SECP384R1,
ec_test_keys.private_test_key_1_secp384r1(),
ec_test_keys.public_test_key_1_secp384r1()));
CHECK(SetKey(ECPrivateKey::SECP521R1,
ec_test_keys.private_test_key_1_secp521r1(),
ec_test_keys.public_test_key_1_secp521r1()));
}
bool FakeECKeySource::SetKey(ECPrivateKey::EllipticCurve curve,
const std::string& private_key,
const std::string& public_key) {
std::unique_ptr<ECPrivateKey> pri_key = ECPrivateKey::Create(private_key);
std::unique_ptr<ECPublicKey> pub_key = ECPublicKey::Create(public_key);
if (pub_key == nullptr || pri_key == nullptr) {
LOG(ERROR) << "public key or private key was null.";
return false;
}
if (!pri_key->MatchesPublicKey(*pub_key)) {
LOG(ERROR) << "Public and private keys do not match.";
return false;
}
if (pri_key->Curve() != curve) {
LOG(ERROR) << "Curve does not match specified curve.";
return false;
}
test_keys_[curve] = std::make_pair(private_key, public_key);
return true;
}
bool FakeECKeySource::GetECKey(ECPrivateKey::EllipticCurve curve,
std::string* private_key,
std::string* public_key) {
CHECK(private_key);
CHECK(public_key);
const auto keys = test_keys_.find(curve);
if (keys == test_keys_.end()) {
return false;
}
std::tie(*private_key, *public_key) = keys->second;
return true;
}
} // namespace widevine

View File

@@ -1,53 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Declaration for fake EC key source used for testing.
#ifndef COMMON_FAKE_EC_KEY_SOURCE_H_
#define COMMON_FAKE_EC_KEY_SOURCE_H_
#include <map>
#include <string>
#include "common/ec_key_source.h"
#include "common/ec_test_keys.h"
namespace widevine {
// This is a fake implementation of the ECKeySource. It returns the values
// specified in ec_test_keys.h.
class FakeECKeySource : public ECKeySource {
public:
FakeECKeySource();
FakeECKeySource(const FakeECKeySource&) = delete;
FakeECKeySource& operator=(const FakeECKeySource&) = delete;
// This method allows a caller to specify which keys to return from GetKeys.
// This overrides the default test keys.
bool SetKey(ECPrivateKey::EllipticCurve curve, const std::string& private_key,
const std::string& public_key);
// Gets precomputed test keys based on |curve|.
// Parameter |curve| is a standard curve which defines the parameters of the
// key generation.
// Parameter |private_key| is the serialized EC private key.
// Parameter |public_key| is the serialized EC public key.
// Caller retains ownership of all pointers and they cannot be nullptr.
// Returns true if successful, false otherwise.
bool GetECKey(ECPrivateKey::EllipticCurve curve, std::string* private_key,
std::string* public_key) override;
private:
std::map<ECPrivateKey::EllipticCurve, std::pair<std::string, std::string>>
test_keys_;
};
} // namespace widevine
#endif // COMMON_FAKE_EC_KEY_SOURCE_H_

View File

@@ -1,63 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/file_util.h"
#include <stddef.h>
#include <stdio.h>
#include "glog/logging.h"
namespace widevine {
bool GetContents(const std::string& file_name, std::string* contents) {
if (file_name.empty()) {
LOG(WARNING) << "File name is empty.";
return false;
}
FILE* file = fopen(file_name.c_str(), "r");
if (!file) {
LOG(WARNING) << "Unable to open file " << file_name;
return false;
}
contents->clear();
const size_t kReadSize = 0x1000;
char buffer[kReadSize];
while (true) {
size_t size_read = fread(buffer, sizeof(char), kReadSize, file);
if (size_read == 0) break;
contents->append(buffer, size_read);
}
const bool eof = feof(file);
fclose(file);
if (!eof) {
LOG(WARNING) << "Failed to read all file contents.";
return false;
}
return true;
}
bool SetContents(const std::string& file_name, const std::string& contents) {
if (file_name.empty()) {
LOG(WARNING) << "File name is empty.";
return false;
}
FILE* file = fopen(file_name.c_str(), "w");
if (!file) {
LOG(WARNING) << "Unable to open file " << file_name;
return false;
}
const size_t size_written =
fwrite(contents.data(), sizeof(char), contents.size(), file);
if (size_written != contents.size())
LOG(WARNING) << "Failed to write to " << file_name;
fclose(file);
return size_written == contents.size();
}
} // namespace widevine

View File

@@ -1,27 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// File util wrapper to be used in partner sdks. Implemented using generic file
// apis.
#ifndef COMMON_FILE_UTIL_H_
#define COMMON_FILE_UTIL_H_
#include <string>
namespace widevine {
// Read file to string.
bool GetContents(const std::string& file_name, std::string* contents);
// Write file.
bool SetContents(const std::string& file_name, const std::string& contents);
} // namespace widevine
#endif // COMMON_FILE_UTIL_H_

View File

@@ -1,31 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/file_util.h"
#include "testing/gunit.h"
#include "absl/strings/str_cat.h"
namespace widevine {
TEST(FileUtilTest, EmptyFileName) {
std::string contents;
EXPECT_FALSE(GetContents("", &contents));
EXPECT_FALSE(SetContents("", "test content"));
}
TEST(FileUtilTest, BasicTest) {
const std::string file_path =
absl::StrCat("/tmp", "/file_util_test");
EXPECT_TRUE(SetContents(file_path, "test content"));
std::string contents;
EXPECT_TRUE(GetContents(file_path, &contents));
EXPECT_EQ("test content", contents);
}
} // namespace widevine

View File

@@ -1,51 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/hash_algorithm_util.h"
#include "glog/logging.h"
#include "protos/public/hash_algorithm.pb.h"
namespace widevine {
HashAlgorithm HashAlgorithmProtoToEnum(
HashAlgorithmProto hash_algorithm_proto) {
switch (hash_algorithm_proto) {
case HASH_ALGORITHM_UNSPECIFIED:
return HashAlgorithm::kUnspecified;
case HASH_ALGORITHM_SHA_1:
return HashAlgorithm::kSha1;
case HASH_ALGORITHM_SHA_256:
return HashAlgorithm::kSha256;
default:
// See below link for using proto3 enum in switch statement:
// http://shortn/_ma9MY7V9wh
if (HashAlgorithmProto_IsValid(hash_algorithm_proto)) {
LOG(ERROR) << "Unsupported value " << hash_algorithm_proto;
} else {
LOG(WARNING) << "Unexpected value " << hash_algorithm_proto;
}
return HashAlgorithm::kUnspecified;
}
}
HashAlgorithmProto HashAlgorithmEnumToProto(HashAlgorithm hash_algorithm) {
switch (hash_algorithm) {
case HashAlgorithm::kUnspecified:
return HASH_ALGORITHM_UNSPECIFIED;
case HashAlgorithm::kSha1:
return HASH_ALGORITHM_SHA_1;
case HashAlgorithm::kSha256:
return HASH_ALGORITHM_SHA_256;
}
LOG(WARNING) << "Unexpected hash algorithm "
<< static_cast<int>(hash_algorithm);
return HASH_ALGORITHM_UNSPECIFIED;
}
} // namespace widevine

View File

@@ -1,23 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_HASH_ALGORITHM_UTIL_H_
#define COMMON_HASH_ALGORITHM_UTIL_H_
#include "common/hash_algorithm.h"
#include "protos/public/hash_algorithm.pb.h"
namespace widevine {
HashAlgorithm HashAlgorithmProtoToEnum(HashAlgorithmProto hash_algorithm_proto);
HashAlgorithmProto HashAlgorithmEnumToProto(HashAlgorithm hash_algorithm);
} // namespace widevine
#endif // COMMON_HASH_ALGORITHM_UTIL_H_

View File

@@ -1,58 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/hash_algorithm_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/hash_algorithm.h"
namespace widevine {
TEST(HashAlgorithmTest, ProtoToEnumUnspecified) {
EXPECT_EQ(HashAlgorithm::kUnspecified,
HashAlgorithmProtoToEnum(HASH_ALGORITHM_UNSPECIFIED));
}
TEST(HashAlgorithmTest, ProtoToEnumSha1) {
EXPECT_EQ(HashAlgorithm::kSha1,
HashAlgorithmProtoToEnum(HASH_ALGORITHM_SHA_1));
}
TEST(HashAlgorithmTest, ProtoToEnumSha256) {
EXPECT_EQ(HashAlgorithm::kSha256,
HashAlgorithmProtoToEnum(HASH_ALGORITHM_SHA_256));
}
TEST(HashAlgorithmTest, ProtoToEnumUnsupported) {
EXPECT_EQ(HashAlgorithm::kUnspecified,
HashAlgorithmProtoToEnum(static_cast<HashAlgorithmProto>(1234)));
}
TEST(HashAlgorithmTest, EnumToProtoUnspecified) {
EXPECT_EQ(HASH_ALGORITHM_UNSPECIFIED,
HashAlgorithmEnumToProto(HashAlgorithm::kUnspecified));
}
TEST(HashAlgorithmTest, EnumToProtoSha1) {
EXPECT_EQ(HASH_ALGORITHM_SHA_1,
HashAlgorithmEnumToProto(HashAlgorithm::kSha1));
}
TEST(HashAlgorithmTest, EnumToProtoSha256) {
EXPECT_EQ(HASH_ALGORITHM_SHA_256,
HashAlgorithmEnumToProto(HashAlgorithm::kSha256));
}
TEST(HashAlgorithmTest, EnumToProtoUnexpected) {
int some_value = 1234;
EXPECT_EQ(HASH_ALGORITHM_UNSPECIFIED,
HashAlgorithmEnumToProto(static_cast<HashAlgorithm>(some_value)));
}
} // namespace widevine

View File

@@ -1,58 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/keybox_client_cert.h"
#include "glog/logging.h"
#include "common/crypto_util.h"
#include "common/error_space.h"
#include "common/sha_util.h"
#include "common/signing_key_util.h"
#include "common/wvm_token_handler.h"
#include "protos/public/errors.pb.h"
namespace widevine {
Status KeyboxClientCert::Initialize(const std::string& keybox_token) {
system_id_ = WvmTokenHandler::GetSystemId(keybox_token);
serial_number_ = WvmTokenHandler::GetEncryptedUniqueId(keybox_token);
bool insecure_keybox = false;
Status status = WvmTokenHandler::DecryptDeviceKey(keybox_token, &device_key_,
nullptr, &insecure_keybox);
if (!status.ok()) {
Errors new_code = status.error_code() == error::NOT_FOUND
? MISSING_PRE_PROV_KEY
: KEYBOX_DECRYPT_ERROR;
return Status(error_space, new_code, status.error_message());
}
return OkStatus();
}
// |hash_algorithm| is needed for function inheritance.
// For KeyBoxClientCert, we always use HMAC-SHA256 in signature verification.
Status KeyboxClientCert::VerifySignature(
const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature, ProtocolVersion protocol_version) const {
DCHECK(!signing_key_.empty());
using crypto_util::VerifySignatureHmacSha256;
if (!VerifySignatureHmacSha256(
GetClientSigningKey(signing_key_, protocol_version), signature,
message)) {
return Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
}
return OkStatus();
}
void KeyboxClientCert::GenerateSigningKey(const std::string& message,
ProtocolVersion protocol_version) {
signing_key_ = crypto_util::DeriveKey(
key(), crypto_util::kSigningKeyLabel,
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
SigningKeyMaterialSizeBits(protocol_version));
}
} // namespace widevine

View File

@@ -1,85 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_KEYBOX_CLIENT_CERT_H_
#define COMMON_KEYBOX_CLIENT_CERT_H_
#include "common/client_cert.h"
#include "common/error_space.h"
#include "common/hash_algorithm.h"
#include "protos/public/errors.pb.h"
namespace widevine {
class KeyboxClientCert : public ClientCert {
public:
KeyboxClientCert() {}
~KeyboxClientCert() override {}
KeyboxClientCert(const KeyboxClientCert&) = delete;
KeyboxClientCert& operator=(const KeyboxClientCert&) = delete;
Status Initialize(const std::string& keybox_token);
Status VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature,
ProtocolVersion protocol_version) const override;
void GenerateSigningKey(const std::string& message,
ProtocolVersion protocol_version) override;
const std::string& encrypted_key() const override { return unimplemented_; }
const std::string& key() const override { return device_key_; }
SignedMessage::SessionKeyType key_type() const override {
return SignedMessage::WRAPPED_AES_KEY;
}
bool using_dual_certificate() const override { return false; }
const std::string& serial_number() const override { return serial_number_; }
const std::string& service_id() const override { return unimplemented_; }
const std::string& signing_key() const override { return signing_key_; }
const std::string& signer_serial_number() const override {
return unimplemented_;
}
uint32_t signer_creation_time_seconds() const override { return 0; }
bool signed_by_provisioner() const override { return false; }
uint32_t system_id() const override { return system_id_; }
widevine::ClientIdentification::TokenType type() const override {
return ClientIdentification::KEYBOX;
}
const std::string& encrypted_unique_id() const override {
return unimplemented_;
}
const std::string& unique_id_hash() const override { return unimplemented_; }
// Set the system-wide pre-provisioning keys; argument must be human-readable
// hex digits.
// Must be called before any other method of this class is called, unless
// created by ClientCert::CreateWithPreProvisioningKey(...).
static void SetPreProvisioningKeys(
const std::multimap<uint32_t, std::string>& keymap);
static bool IsSystemIdKnown(const uint32_t system_id);
static uint32_t GetSystemId(const std::string& keybox_bytes);
Status SystemIdUnknownError() const override {
return Status(error_space, UNSUPPORTED_SYSTEM_ID,
"keybox-unsupported-system-id");
}
Status SystemIdRevokedError() const override {
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"keybox-system-id-revoked");
}
private:
std::string unimplemented_;
std::string device_key_;
uint32_t system_id_;
std::string serial_number_;
std::string signing_key_;
};
} // namespace widevine
#endif // COMMON_KEYBOX_CLIENT_CERT_H_

View File

@@ -1,50 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Implementation of local EC key generator.
#include "common/local_ec_key_source.h"
#include <memory>
#include <string>
#include "glog/logging.h"
#include "openssl/ec.h"
#include "openssl/nid.h"
#include "common/ec_key.h"
#include "common/ec_util.h"
using widevine::ec_util::SerializeECPrivateKey;
using widevine::ec_util::SerializeECPublicKey;
namespace widevine {
bool LocalECKeySource::GetECKey(ECPrivateKey::EllipticCurve curve,
std::string* private_key,
std::string* public_key) {
DCHECK(private_key);
DCHECK(public_key);
int nid = ec_util::CurveToNid(curve);
if (nid <= 0) {
return false;
}
bssl::UniquePtr<EC_KEY> key_pair(EC_KEY_new_by_curve_name(nid));
if (key_pair == nullptr || !EC_KEY_generate_key(key_pair.get())) {
return false;
}
if (!SerializeECPrivateKey(key_pair.get(), private_key) ||
!SerializeECPublicKey(key_pair.get(), public_key)) {
return false;
}
return true;
}
} // namespace widevine

View File

@@ -1,42 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Class to generate EC keys locally.
#ifndef COMMON_LOCAL_EC_KEY_SOURCE_H_
#define COMMON_LOCAL_EC_KEY_SOURCE_H_
#include "common/ec_key.h"
#include "common/ec_key_source.h"
namespace widevine {
// Class which generates new EC keys.
class LocalECKeySource : public ECKeySource {
public:
LocalECKeySource() = default;
// Creates an EC key pair using openssl and |curve|.
// Parameter |curve| is a standard curve which defines the parameters of the
// key generation.
// Parameter |private_key| is the serialized EC private key.
// Parameter |public_key| is the serialized EC public key.
// Caller retains ownership of all pointers and they cannot be nullptr.
// Returns true if successful, false otherwise.
bool GetECKey(ECPrivateKey::EllipticCurve curve, std::string* private_key,
std::string* public_key) override;
private:
LocalECKeySource(const LocalECKeySource&) = delete;
LocalECKeySource& operator=(const LocalECKeySource&) = delete;
};
} // namespace widevine
#endif // COMMON_LOCAL_EC_KEY_SOURCE_H_

View File

@@ -1,64 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit tests for LocalECKeySource.
#include "common/local_ec_key_source.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "common/ec_test_keys.h"
#include "common/ec_util.h"
namespace widevine {
using ec_util::DeserializeECPrivateKey;
using ec_util::DeserializeECPublicKey;
using ec_util::SerializeECPublicKey;
class LocalECKeySourceTest : public ::testing::Test {
public:
void ValidateKeyPair(ECPrivateKey::EllipticCurve curve,
const std::string& private_key,
const std::string& public_key) {
EC_KEY* ec_key;
std::string expected_public_key;
int nid = ec_util::CurveToNid(curve);
ASSERT_GT(nid, 0);
EXPECT_TRUE(DeserializeECPrivateKey(private_key, &ec_key));
ASSERT_TRUE(ec_key != nullptr);
EXPECT_EQ(nid, EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)));
EXPECT_TRUE(SerializeECPublicKey(ec_key, &expected_public_key));
EXPECT_EQ(expected_public_key, public_key);
EC_KEY_free(ec_key);
ec_key = nullptr;
EXPECT_TRUE(DeserializeECPublicKey(public_key, &ec_key));
ASSERT_TRUE(ec_key != nullptr);
EC_KEY_free(ec_key);
}
};
TEST_F(LocalECKeySourceTest, GenerateKeys) {
LocalECKeySource key_source;
std::string private_key;
std::string public_key;
std::vector<ECPrivateKey::EllipticCurve> curves = {ECPrivateKey::SECP256R1,
ECPrivateKey::SECP384R1,
ECPrivateKey::SECP521R1};
for (auto curve : curves) {
ASSERT_TRUE(key_source.GetECKey(curve, &private_key, &public_key));
ValidateKeyPair(curve, private_key, public_key);
}
}
} // namespace widevine

View File

@@ -1,97 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_MOCK_RSA_KEY_H_
#define COMMON_MOCK_RSA_KEY_H_
#include <string>
#include "testing/gmock.h"
#include "common/hash_algorithm.h"
#include "common/rsa_key.h"
namespace widevine {
class MockRsaPrivateKey : public RsaPrivateKey {
public:
MockRsaPrivateKey() : RsaPrivateKey(RSA_new()) {}
~MockRsaPrivateKey() override {}
MOCK_METHOD(bool, Decrypt,
(const std::string& encrypted_message,
std::string* decrypted_message),
(const, override));
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
MOCK_METHOD(bool, GenerateSignature,
(const std::string& message, std::string* signature),
(const, override));
MOCK_METHOD(bool, GenerateSignature,
(const std::string& message, HashAlgorithm hash_algorithm,
std::string* signature),
(const, override));
MOCK_METHOD(bool, MatchesPrivateKey, (const RsaPrivateKey& private_key),
(const, override));
MOCK_METHOD(bool, MatchesPublicKey, (const RsaPublicKey& public_key),
(const, override));
private:
MockRsaPrivateKey(const MockRsaPrivateKey&) = delete;
MockRsaPrivateKey& operator=(const MockRsaPrivateKey&) = delete;
};
class MockRsaPublicKey : public RsaPublicKey {
public:
MockRsaPublicKey() : RsaPublicKey(RSA_new()) {}
~MockRsaPublicKey() override {}
MOCK_METHOD(bool, Encrypt,
(const std::string& clear_message,
std::string* encrypted_message),
(const, override));
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
MOCK_METHOD(bool, VerifySignature,
(const std::string& message, const std::string& signature),
(const, override));
MOCK_METHOD(bool, VerifySignature,
(const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature),
(const, override));
MOCK_METHOD(bool, MatchesPrivateKey, (const RsaPrivateKey& private_key),
(const, override));
MOCK_METHOD(bool, MatchesPublicKey, (const RsaPublicKey& public_key),
(const, override));
private:
MockRsaPublicKey(const MockRsaPublicKey&) = delete;
MockRsaPublicKey& operator=(const MockRsaPublicKey&) = delete;
};
class MockRsaKeyFactory : public RsaKeyFactory {
public:
MockRsaKeyFactory() {}
~MockRsaKeyFactory() override {}
MOCK_METHOD(std::unique_ptr<RsaPrivateKey>, CreateFromPkcs1PrivateKey,
(const std::string& private_key), (const, override));
MOCK_METHOD(std::unique_ptr<RsaPrivateKey>, CreateFromPkcs8PrivateKey,
(const std::string& private_key,
const std::string& private_key_passphrase),
(const, override));
MOCK_METHOD(std::unique_ptr<RsaPublicKey>, CreateFromPkcs1PublicKey,
(const std::string& public_key), (const, override));
private:
MockRsaKeyFactory(const MockRsaKeyFactory&) = delete;
MockRsaKeyFactory& operator=(const MockRsaKeyFactory&) = delete;
};
} // namespace widevine
#endif // COMMON_MOCK_RSA_KEY_H_

View File

@@ -1,54 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/output_protection_util.h"
namespace widevine {
namespace op_util {
Status VerifyDeviceCapabilities(
const ClientIdentification::ClientCapabilities& device_capabilities,
const License::KeyContainer::OutputProtection& output_protection,
bool* should_disable_analog_output) {
bool device_has_analog_output =
device_capabilities.analog_output_capabilities() !=
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE &&
device_capabilities.analog_output_capabilities() !=
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_UNKNOWN;
if (should_disable_analog_output != nullptr) {
*should_disable_analog_output = false;
}
if (device_has_analog_output) {
if (output_protection.disable_analog_output() &&
!device_capabilities.can_disable_analog_output()) {
return Status(error::PERMISSION_DENIED,
"Analog out cannot be disabled on this device.");
}
if (output_protection.cgms_flags() !=
License::KeyContainer::OutputProtection::CGMS_NONE) {
if (device_capabilities.analog_output_capabilities() !=
ClientIdentification::ClientCapabilities::
ANALOG_OUTPUT_SUPPORTS_CGMS_A) {
if (!device_capabilities.can_disable_analog_output()) {
return Status(
error::PERMISSION_DENIED,
"Analog out cannot be disabled on this device, no CGMS.");
}
// This device does not have support for CGMS protections.
if (should_disable_analog_output != nullptr) {
*should_disable_analog_output = true;
}
}
}
}
return OkStatus();
}
} // namespace op_util
} // namespace widevine

View File

@@ -1,31 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_OUTPUT_PROTECTION_UTIL_H_
#define COMMON_OUTPUT_PROTECTION_UTIL_H_
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
namespace op_util {
// Verify the device meets the provider's output requirements. Set
// |should_disable_analog_output| to true if device does not meet analog output
// requirements, otherwise |should_disable_analog_error| is false including
// error cases.
Status VerifyDeviceCapabilities(
const ClientIdentification::ClientCapabilities& device_capabilities,
const License::KeyContainer::OutputProtection& output_protection,
bool* should_disable_analog_output);
} // namespace op_util
} // namespace widevine
#endif // COMMON_OUTPUT_PROTECTION_UTIL_H_

View File

@@ -1,155 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/output_protection_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
namespace widevine {
namespace op_util {
TEST(OutputProtectionUtilTest, AnalogOutputAllowed_DeviceWithoutAnalogOutput) {
License::KeyContainer::OutputProtection output_protection;
output_protection.set_disable_analog_output(false);
ClientIdentification::ClientCapabilities client_capabilities;
client_capabilities.set_analog_output_capabilities(
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_UNKNOWN);
bool should_disable_output_protection = true;
ASSERT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection,
&should_disable_output_protection));
EXPECT_FALSE(should_disable_output_protection);
}
TEST(OutputProtectionUtilTest,
AnalogOutputNotAllowed_DeviceWithoutAnalogOutput) {
License::KeyContainer::OutputProtection output_protection;
output_protection.set_disable_analog_output(true);
ClientIdentification::ClientCapabilities client_capabilities;
client_capabilities.set_analog_output_capabilities(
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_NONE);
bool should_disable_output_protection = true;
ASSERT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection,
&should_disable_output_protection));
EXPECT_FALSE(should_disable_output_protection);
}
TEST(OutputProtectionUtilTest, AnalogOutputNotAllowed_DeviceWithAnalogOutput) {
License::KeyContainer::OutputProtection output_protection;
output_protection.set_disable_analog_output(true);
ClientIdentification::ClientCapabilities client_capabilities;
client_capabilities.set_analog_output_capabilities(
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED);
client_capabilities.set_can_disable_analog_output(false);
bool should_disable_output_protection = true;
ASSERT_EQ(error::PERMISSION_DENIED,
VerifyDeviceCapabilities(client_capabilities, output_protection,
&should_disable_output_protection)
.error_code());
EXPECT_FALSE(should_disable_output_protection);
// Client has the ability to disable it's analog output.
client_capabilities.set_can_disable_analog_output(true);
EXPECT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection,
&should_disable_output_protection));
}
TEST(OutputProtectionUtilTest, CGMSRequired) {
License::KeyContainer::OutputProtection output_protection;
output_protection.set_disable_analog_output(false);
output_protection.set_cgms_flags(
License::KeyContainer::OutputProtection::COPY_NEVER);
ClientIdentification::ClientCapabilities client_capabilities;
client_capabilities.set_analog_output_capabilities(
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTED);
bool should_disable_output_protection = true;
EXPECT_EQ(error::PERMISSION_DENIED,
VerifyDeviceCapabilities(client_capabilities, output_protection,
&should_disable_output_protection)
.error_code());
client_capabilities.set_analog_output_capabilities(
ClientIdentification::ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
ASSERT_OK(VerifyDeviceCapabilities(client_capabilities, output_protection,
&should_disable_output_protection));
EXPECT_FALSE(should_disable_output_protection);
}
// TODO(user): enable this test.
TEST(OutputProtectionUtilTest, DISABLED_VerifyDeviceHdcpCapabilities) {
ClientIdentification::ClientCapabilities device_capabilities;
License::KeyContainer::OutputProtection required;
// Device capabilities was not specified by the client.
device_capabilities.clear_max_hdcp_version();
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_NONE);
bool should_disable_output_protection;
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V1);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_1);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_2);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
// Device capabilities are too low for any HDCP. Only fail if the required
// protection is HDCP_NO_DIGITAL_OUTPUT.
device_capabilities.set_max_hdcp_version(
ClientIdentification::ClientCapabilities::HDCP_NONE);
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_NONE);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V1);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
EXPECT_EQ(error::PERMISSION_DENIED,
VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection)
.error_code());
// Device does not have any digital output ports. In this case, the CDM
// cannot enforce this situation. For now, allow all HDCP requests, the KCB
// will enforce the HDCP settings.
device_capabilities.set_max_hdcp_version(
ClientIdentification::ClientCapabilities::HDCP_NO_DIGITAL_OUTPUT);
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_NONE);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V1);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_1);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(License::KeyContainer::OutputProtection::HDCP_V2_2);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
required.set_hdcp(
License::KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
EXPECT_OK(VerifyDeviceCapabilities(device_capabilities, required,
&should_disable_output_protection));
}
} // namespace op_util
} // namespace widevine

View File

@@ -1,42 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_PLAYREADY_INTERFACE_H_
#define COMMON_PLAYREADY_INTERFACE_H_
#include <string>
#include "util/error_space.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
class PlayReadyInterface {
public:
PlayReadyInterface() {}
virtual ~PlayReadyInterface() {}
// Sends to a PlayReady Service running the PlayReady license server on
// Windows .
// Args:
// - |challenge| is a std::string which contains PlayReadyLicenseRequest.
// - |policy| is a std::string which contains the PlayReady Policy Setting.
// - |license| is a std::string of PlayReadyLicenseResponse returned from PlayReady
// Service.
// Returns:
// - status code from downstream components.
virtual util::Status SendToPlayReady(
const std::string& playready_challenge, const std::string& provider,
const std::string& content_id,
const std::list<License::KeyContainer>& keys,
const License::Policy& policy, std::string* playready_license) = 0;
};
} // namespace widevine
#endif // COMMON_PLAYREADY_INTERFACE_H_

View File

@@ -1,23 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/playready_sdk_impl.h"
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
#include "util/task/codes.pb.h"
namespace widevine {
// TODO(user): fill in SendToPlayReady function.
util::Status PlayReadySdkImpl::SendToPlayReady(
const std::string& playready_challenge, const std::string& provider,
const std::string& content_id, const std::list<License::KeyContainer>& keys,
const License::Policy& policy, std::string* playready_license) {
return OkStatus;
}
} // namespace widevine

View File

@@ -1,28 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_PLAYREADY_SDK_IMPL_H_
#define COMMON_PLAYREADY_SDK_IMPL_H_
#include "common/playready_interface.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
class PlayReadySdkImpl : public PlayReadyInterface {
public:
PlayReadySdkImpl() : PlayReadyInterface() {}
~PlayReadySdkImpl() override {}
util::Status SendToPlayReady(const std::string& playready_challenge,
const std::string& provider,
const std::string& content_id,
const std::list<License::KeyContainer>& keys,
const License::Policy& policy,
std::string* playready_license) override;
};
} // namespace widevine
#endif // COMMON_PLAYREADY_SDK_IMPL_H_

View File

@@ -1,28 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/random_util.h"
#include "testing/gunit.h"
namespace widevine {
TEST(RandomUtilTest, Test) {
std::string output;
ASSERT_TRUE(RandomBytes(16u, &output));
EXPECT_EQ(16u, output.size());
std::string output2;
ASSERT_TRUE(RandomBytes(16u, &output2));
EXPECT_EQ(16u, output2.size());
EXPECT_NE(output, output2);
ASSERT_TRUE(RandomBytes(10u, &output2));
EXPECT_EQ(10u, output2.size());
}
} // namespace widevine

View File

@@ -1,262 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/remote_attestation_verifier.h"
#include <stddef.h>
#include <memory>
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "common/client_id_util.h"
#include "common/drm_service_certificate.h"
#include "common/error_space.h"
#include "common/rsa_key.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/errors.pb.h"
namespace widevine {
const char kTestRootCaDerCert[] =
"30820403308202eba003020102020900a24f94af7ae6831f300d06092a86"
"4886f70d0101050500308197310b30090603550406130255533113301106"
"035504080c0a57617368696e67746f6e3111300f06035504070c084b6972"
"6b6c616e6431133011060355040a0c0a476f6f676c6520496e633111300f"
"060355040b0c085769646576696e653115301306035504030c0c54657374"
"20526f6f742043413121301f06092a864886f70d010901161274696e736b"
"697040676f6f676c652e636f6d301e170d3133303831363030353731305a"
"170d3333303831353030353731305a308197310b30090603550406130255"
"533113301106035504080c0a57617368696e67746f6e3111300f06035504"
"070c084b69726b6c616e6431133011060355040a0c0a476f6f676c652049"
"6e633111300f060355040b0c085769646576696e65311530130603550403"
"0c0c5465737420526f6f742043413121301f06092a864886f70d01090116"
"1274696e736b697040676f6f676c652e636f6d30820122300d06092a8648"
"86f70d01010105000382010f003082010a0282010100c6eee629d99f7736"
"2db5545ed1d6dfb3616c742c617d5fd48f2fbfcb3f2ec40a080bd04d551c"
"e519471a8bb4ec5c2c75bf8a2d2caf3f85d90e9e39391dfbdaae68051319"
"0da71b1b2ae4829a15c44bc1b19b17134844b94c6f06d9216333236574f3"
"f11b0d10c3c621410e42630c57ce9e901057eda5c3c2203ee2ad805a0d93"
"52fa91da45a6f4875b4524c193c42fd9048a10204e5b2c8203402ba760e7"
"e1b4126c3e2ab4258f2bf28cd3170de8c738a6a1f4cfcc0649fa95f1414f"
"d9d09dd4f511bc0a9bf3a5844a334d9e0a4b9525d2789be6abafe2d0cc20"
"79dcf030ffa9be8ae3fe2cab4ebdfa494d48aa8c63264d31e2208a9c28f7"
"3e0103ce164683bf0203010001a350304e301d0603551d0e041604144d30"
"ff181ac4f10da99e6a12c01e02accadf840a301f0603551d230418301680"
"144d30ff181ac4f10da99e6a12c01e02accadf840a300c0603551d130405"
"30030101ff300d06092a864886f70d01010505000382010100779e9b98d3"
"ec066f29862903a00e9c98259d987c04b9e6a2e6c3381ee59ec1dd0d7dee"
"79da612e4dfaa3465c8916993ed7adebb27340de20ca101067f8342b2124"
"ec0d5db531277b4653c3bc72b2a8daeae120e5348e1a338f6e68e7129436"
"026e78024f04d766b132252ec152402dcec28174346aa0ba997d7f1af140"
"ff025bec841f8039ba10d7cc098cf24554f8cbb2aa31875205c67df2f053"
"0d8784faf63c4f945e62da374cad6155e6ae44f597bcff4566ea2aac4258"
"e4ae81569c0eddd1df6929532b4538bd204b2ff5847cb46ac7383c96fe82"
"d22de9a13c5092c92c297021c51a2a0a5250cf26c271ff262f25a7738ae4"
"c270d87191c13aefdd177b";
const char kProdRootCaDerCert[] =
"30820408308202f0a003020102020101300d06092a864886f70d01010505"
"00307d311830160603550403130f5072697661637920434120526f6f7431"
"123010060355040b13094368726f6d65204f5331133011060355040a130a"
"476f6f676c6520496e63311630140603550407130d4d6f756e7461696e20"
"56696577311330110603550408130a43616c69666f726e6961310b300906"
"0355040613025553301e170d3133303231383130313334325a170d333330"
"3231333130313334325a307d311830160603550403130f50726976616379"
"20434120526f6f7431123010060355040b13094368726f6d65204f533113"
"3011060355040a130a476f6f676c6520496e63311630140603550407130d"
"4d6f756e7461696e2056696577311330110603550408130a43616c69666f"
"726e6961310b300906035504061302555330820122300d06092a864886f7"
"0d01010105000382010f003082010a0282010100e10ea6819d3d066b421d"
"d7612de3eef9599f5d9a2a24bfd09caab543511cf22f615e29f989425a65"
"7396bf33603747719cfb0b4240cd682c7c558fec0176b4793be440752246"
"83648f5b12d02a838a2a8e55a4b645ed0a4a52b19252a23d34bf64a17ac7"
"11fe93a889086d943211b17d670f96442c9f367d38026000da79664e600e"
"e9259348f4fd74108e973d561e624e9f5eda77a085a6eb15fadb2cc7787c"
"7f30ef3b196f2a416a76fa9eb30d65753f5039d97bea70e82431d2962396"
"a34864f33b74d60707fea794c03c82e547abc2407fa7bad67bd09cdab49b"
"26e68754994d12a3845dbeceffe18de0d51fc6fa78676d89ea1e0fcff931"
"59bfb809519b0203010001a3819230818f30290603551d0e042204204b1d"
"148aa5380938812ed6a763f5dc2c318610d5fa9604d609cb2e0d8cec3289"
"302b0603551d230424302280204b1d148aa5380938812ed6a763f5dc2c31"
"8610d5fa9604d609cb2e0d8cec3289300e0603551d0f0101ff0404030201"
"06300f0603551d130101ff040530030101ff30140603551d200101ff040a"
"300830060604551d2000300d06092a864886f70d01010505000382010100"
"c40d84bc8d609b1b68b3caa7e841021838d7e392557d40debab3e0685e72"
"80541092dc913b0aa6150228d8fe5ab08cceefbac56952fa00ba614294d1"
"ba4fa170c86b27f9bf58666c46940f740c4be2795501b25e40b9702af07c"
"884926bd8beed036c503e5e42a223ff36271404ca4360a93dec92a02fd8d"
"ae8f756fc68aaa647e2159f0a7a95d1446e92362bd512f59daec02c5d152"
"c301b9807db998ba70c616364762a0a497aaa92eb7d92f3635169d3f74c6"
"40c738941759a8ab43677b80329d015bdcf8922b779a80f85f1e4a677659"
"c60de80152e8c526a7de46cac143a75af58f0806de81e15c97f616e1bffa"
"1c1c6b0d2438543bdfb2a21bd9bc7ae4";
const char kServiceIdFieldName[] = "OU";
const char kDeviceModeFieldName[] = "O";
const char kExpectedDeviceMode[] = "Chrome Device Content Protection";
RemoteAttestationVerifier& RemoteAttestationVerifier::get() {
static RemoteAttestationVerifier instance;
return instance;
}
void RemoteAttestationVerifier::EnableTestDrmCertificates(bool enable) {
absl::WriterMutexLock lock(&ca_mutex_);
enable_test_certificates_ = enable;
ca_.reset();
}
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 (Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
}
if (!remote_attestation.has_salt()) {
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
}
if (!remote_attestation.has_signature()) {
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;
Status status = DrmServiceCertificate::DecryptClientIdentification(
remote_attestation.certificate(), &client_id);
if (!status.ok()) return status;
if (client_id.type() !=
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
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);
}
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 (Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
}
if (!remote_attestation.has_salt()) {
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
}
if (!remote_attestation.has_signature()) {
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;
Status status = DecryptEncryptedClientIdentification(
remote_attestation.certificate(), privacy_key, &client_id);
if (!status.ok()) return status;
if (client_id.type() !=
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
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);
}
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 (Status(error_space, INVALID_MESSAGE,
"remote-attestation-token-missing"));
}
// Load and verify the certificate chain.
std::unique_ptr<X509CertChain> cert_chain(new X509CertChain);
Status status = cert_chain->LoadPem(client_id.token());
if (!status.ok()) return status;
if (cert_chain->GetNumCerts() < 1) {
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 (Status(error_space, REMOTE_ATTESTATION_FAILED,
std::string("remote-attestation-device-not-verified (") +
device_mode_string + " / " + kDeviceModeFieldName +
")"));
}
ca_mutex_.ReaderLock();
if (ca_ == NULL) {
ca_mutex_.ReaderUnlock();
status = LoadCa();
if (!status.ok()) return status;
ca_mutex_.ReaderLock();
}
status = ca_->VerifyCertChain(*cert_chain);
ca_mutex_.ReaderUnlock();
if (!status.ok()) {
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<RsaPublicKey> leaf_key;
std::string message_with_salt = message + remote_attestation.salt();
for (size_t idx = 0; idx < cert_chain->GetNumCerts(); ++idx) {
if (!cert_chain->GetCert(idx)->IsCaCertificate()) {
leaf_key = cert_chain->GetCert(idx)->GetRsaPublicKey();
break;
}
}
if (!leaf_key) {
return Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-cert-chain-no-leaf");
}
if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt,
remote_attestation.signature())) {
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-signature-verification-failed: "));
}
*remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber();
return OkStatus();
}
Status RemoteAttestationVerifier::LoadCa() {
absl::WriterMutexLock lock(&ca_mutex_);
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
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 OkStatus();
}
} // namespace widevine

View File

@@ -1,94 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Functionality used to verifier ChromeOS remote attestation.
#ifndef COMMON_REMOTE_ATTESTATION_VERIFIER_H_
#define COMMON_REMOTE_ATTESTATION_VERIFIER_H_
#include <map>
#include <memory>
#include <string>
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "common/status.h"
#include "common/x509_cert.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/remote_attestation.pb.h"
namespace widevine {
// Singleton class used to do remote attestation. Access singleton instance via
// the get() method.
// TODO(user): This class is tested as part of the Session unit tests, but
// finer unit tests should be implemented for the failure cases.
class RemoteAttestationVerifier {
public:
RemoteAttestationVerifier() : enable_test_certificates_(false) {}
RemoteAttestationVerifier(const RemoteAttestationVerifier&) = delete;
RemoteAttestationVerifier& operator=(const RemoteAttestationVerifier&) =
delete;
virtual ~RemoteAttestationVerifier() {}
// Singleton accessor.
static RemoteAttestationVerifier& get();
// Call to use the test (non-production) remote attestation root certificate.
// This method is thread-safe.
void EnableTestDrmCertificates(bool enable);
// Call to verify a RemoteAttestation challenge response, used in licensing
// protocol.
// |message| is the challenge message,
// |remote_attestation| is the remote attestation response to verify,
// |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.
// This method is thread-safe.
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.
// |message| is the challenge message,
// |remote_attestation| is the remote attestation response to verify,
// |privacy_key| is used to decrypt the EncryptedClientIdentification within
// the |remote_attestation| message.
// This method is thread-safe.
Status VerifyRemoteAttestation(const std::string& message,
const RemoteAttestation& remote_attestation,
const std::string& privacy_key);
private:
// Common subroutine to perform the verification.
// |message| is the challenge message,
// |remote_attestation| is the remote attestation response to verify,
// |client_id| is the decrypted client identification carrying the token,
// |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.
Status VerifyRemoteAttestation(const std::string& message,
const RemoteAttestation& remote_attestation,
const ClientIdentification& client_id,
std::string* remote_attestation_cert_sn);
Status LoadCa();
bool enable_test_certificates_;
absl::Mutex ca_mutex_;
std::unique_ptr<X509CA> ca_ ABSL_GUARDED_BY(ca_mutex_);
};
} // namespace widevine
#endif // COMMON_REMOTE_ATTESTATION_VERIFIER_H_

View File

@@ -1,130 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Classes for generating and decrypting the root of trust id which is
// included in generated DRM Certificates.
#include "common/rot_id_generator.h"
#include <memory>
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "common/crypto_util.h"
#include "common/ec_key.h"
#include "common/rot_id_util.h"
#include "common/sha_util.h"
#include "common/status.h"
#include "protos/public/drm_certificate.pb.h"
namespace {
constexpr char kRotIdLabel[] = "ROOT_OF_TRUST_ID ENCRYPTION LABEL";
constexpr int32_t kKeyId = 0;
std::string GenerateContext(uint32_t system_id) {
return absl::StrCat(kRotIdLabel, system_id);
}
} // anonymous namespace
namespace widevine {
Status RootOfTrustIdGenerator::Generate(uint32_t system_id,
const std::string& unique_id,
RootOfTrustId* root_of_trust_id) const {
CHECK(root_of_trust_id != nullptr) << "root_of_trust_id was null.";
if (system_id == 0) {
return Status(error::INVALID_ARGUMENT, "system id should not be 0.");
}
if (unique_id.empty()) {
return Status(error::INVALID_ARGUMENT,
"The unique id should not be empty.");
}
root_of_trust_id->set_version(
widevine::RootOfTrustId::ROOT_OF_TRUST_ID_VERSION_1);
root_of_trust_id->set_key_id(kKeyId);
if (!ecies_encryptor_->Encrypt(
unique_id, GenerateContext(system_id),
root_of_trust_id->mutable_encrypted_unique_id())) {
root_of_trust_id->Clear();
return Status(error::INTERNAL, "Encrypt failed.");
}
std::string unique_id_hash = GenerateUniqueIdHash(unique_id);
if (unique_id_hash.empty()) {
root_of_trust_id->Clear();
return Status(error::INTERNAL, "Could not generate unique id hash.");
}
root_of_trust_id->set_unique_id_hash(GenerateRotIdHash(
root_of_trust_id->encrypted_unique_id(), system_id, unique_id_hash));
if (root_of_trust_id->unique_id_hash().empty()) {
root_of_trust_id->Clear();
return Status(error::INTERNAL, "Failed to generate revoked id hash.");
}
return OkStatus();
}
std::string RootOfTrustIdGenerator::GenerateUniqueIdHash(
const std::string& unique_id) const {
return widevine::GenerateUniqueIdHash(unique_id, wv_shared_salt_);
}
Status RootOfTrustIdDecryptor::DecryptUniqueId(
uint32_t system_id, const std::string& rot_encrypted_id,
std::string* unique_id) const {
CHECK(unique_id != nullptr) << "unique_id was null.";
if (system_id == 0) {
return Status(error::INVALID_ARGUMENT, "system id should not be 0.");
}
if (rot_encrypted_id.empty()) {
return Status(error::INVALID_ARGUMENT,
"The rot_encrypted_id should not be empty.");
}
if (!ecies_decryptor_->Decrypt(rot_encrypted_id, GenerateContext(system_id),
unique_id)) {
return Status(error::INTERNAL, "Failed to decrypt rot_encrypted_id");
}
return OkStatus();
}
Status RootOfTrustIdDecryptor::VerifyAndExtractAllValues(
uint32_t system_id, const RootOfTrustId& root_of_trust_id,
std::string* device_unique_id, std::string* device_unique_id_hash) const {
CHECK(device_unique_id != nullptr) << "device_unique_id was null.";
CHECK(device_unique_id_hash != nullptr) << "device_unique_id_hash was null.";
Status status = DecryptUniqueId(
system_id, root_of_trust_id.encrypted_unique_id(), device_unique_id);
if (!status.ok()) {
return status;
}
*device_unique_id_hash =
widevine::GenerateUniqueIdHash(*device_unique_id, wv_shared_salt_);
std::string revocation_hash =
GenerateRotIdHash(root_of_trust_id.encrypted_unique_id(), system_id,
*device_unique_id_hash);
// This should not happen unless there's a bug in the way we issue root of
// trust ids.
if (revocation_hash != root_of_trust_id.unique_id_hash()) {
return Status(error::INVALID_ARGUMENT,
"The generated revocation hash did not match the one in the "
"root_of_trust_id");
}
return OkStatus();
}
} // namespace widevine

View File

@@ -1,103 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Classes for generating and decrypting the root of trust id which is
// included in generated DRM Certificates.
#ifndef COMMON_ROT_ID_GENERATOR_H_
#define COMMON_ROT_ID_GENERATOR_H_
#include <memory>
#include <utility>
#include <cstdint>
#include "common/ecies_crypto.h"
#include "common/rot_id_util.h"
#include "common/status.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
// The RootOfTrustIdGenerator is used to create a root of trust id that is
// associated with the keybox or OEM X.509 certificate that was used as
// authentication during provisioning.
class RootOfTrustIdGenerator {
public:
// The constructor for creating the RootOfTrustIdGenerator. |ecies_encryptor|
// is used to encrypt the unique identifier. It must not be null. The
// |wv_shared_salt| is a secret salt used in creating the hash
// component of the Root of Trust Id. The secret salt is stored securely. The
// same value is used as part of generating all Root of Trust Ids.
// The |wv_shared_salt| is also used for creating the unique id hash
// values. The unique id hash values identify revoked devices and are
// published in the DCSL and consumed by the License SDK.
RootOfTrustIdGenerator(std::unique_ptr<EciesEncryptor> ecies_encryptor,
const std::string& wv_shared_salt)
: ecies_encryptor_(std::move(ecies_encryptor)),
wv_shared_salt_(std::move(wv_shared_salt)) {}
virtual ~RootOfTrustIdGenerator() {}
// Creates the root of trust identifier. This fills the fields of the
// |root_of_trust_id|. The fields are generated per the spec at go/wv-kb-id.
// The |system_id| is required and must match the system id to which the
// |unique_id| belongs.
// Returns INVALID_ARGUMENT if |system_id| is 0, |unique_id| is empty.
// |roof_of_trust_id| is owned by the caller and must not be null.
virtual Status Generate(uint32_t system_id, const std::string& unique_id,
RootOfTrustId* root_of_trust_id) const;
// Generates the hash of the |unique_id| per the spec in go/wv-kb-id. This
// unique id hash (aka inner hash) is the identifier used when revoking an
// individual device. The result of this hash is one of the values used to
// generate Root of Trust Id Hash.
// |unique_id| should not be empty. If it is, an empty hash
// is returned.
std::string GenerateUniqueIdHash(const std::string& unique_id) const;
private:
std::unique_ptr<EciesEncryptor> ecies_encryptor_;
std::string wv_shared_salt_;
};
// The RootOfTrustIdDecryptor is used to decrypt the root of trust id. It
// requires an |ecies_decryptor| which must use the private key that matches
// the public key used with the RootOfTrustIdGenerator. |ecies_decryptor|
// must not be null. The RootOfTrustIdDecryptor will take ownership.
class RootOfTrustIdDecryptor {
public:
explicit RootOfTrustIdDecryptor(
std::unique_ptr<EciesDecryptor> ecies_decryptor,
const std::string& wv_shared_salt)
: ecies_decryptor_(std::move(ecies_decryptor)),
wv_shared_salt_(wv_shared_salt) {}
// Decrypts the |rot_encrypted_id| using the |system_id| as part of the
// context. |unique_id| contains the decrypted value on success.
// |rot_encrypted_id| must not be empty. |unique_id| must not be null.
// Returns true on success, false on failure.
Status DecryptUniqueId(uint32_t system_id, const std::string& rot_encrypted_id,
std::string* unique_id) const;
// Decrypts the encrypted id within the |root_of_trust_id|, extacting the
// |device_unique_id|, and generating the |device_unique_id_hash|. It then
// generates the rot id revocation hash and verifies that it matches the
// unique_id_hash from the root_of_trust_id.
Status VerifyAndExtractAllValues(uint32_t system_id,
const RootOfTrustId& root_of_trust_id,
std::string* device_unique_id,
std::string* device_unique_id_hash) const;
private:
std::unique_ptr<EciesDecryptor> ecies_decryptor_;
std::string wv_shared_salt_;
};
} // namespace widevine
#endif // COMMON_ROT_ID_GENERATOR_H_

View File

@@ -1,304 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit tests for RootOfTrustIdGenerator and RootO
#include "common/rot_id_generator.h"
#include <memory>
#include <vector>
#include "google/protobuf/util/message_differencer.h"
#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/ecies_crypto.h"
#include "common/fake_ec_key_source.h"
#include "common/rot_id_util.h"
#include "common/status.h"
#include "protos/public/drm_certificate.pb.h"
using ::testing::_;
using ::testing::NotNull;
using ::testing::Return;
namespace {
constexpr char kTestSharedSalt[] = "test shared salt";
constexpr char kTestUniqueId[] = "test unique id";
constexpr uint32_t kTestSystemId = 1234;
constexpr char kExpectedRotIdEncryptedIdHex[] =
"048aea3f16ff24a9bf03283015ee52509a551c60c7a7cc4b995b4055ce4619d4d45efde068"
"27ea78f3071f024a785244d3dfbeac5fa51c8a498da65aaca1252bd1f174166d9645b6ecd6"
"669aa0afb7b766682c02f794d67050f779ebd104a767bedef288be13d321ae79d7209b5cd3"
"4698";
constexpr char kExpectedRotIdHashHex[] =
"2c4dbc37092ab3e55897639d4f0dd3c824001d07eb69a3f9e6db3b846bf31828";
} // anonymous namespace
namespace widevine {
class RootOfTrustIdGeneratorTest : public ::testing::Test {
public:
RootOfTrustIdGeneratorTest() {
expected_root_of_trust_id_.set_encrypted_unique_id(
absl::HexStringToBytes(kExpectedRotIdEncryptedIdHex));
expected_root_of_trust_id_.set_unique_id_hash(
absl::HexStringToBytes(kExpectedRotIdHashHex));
expected_root_of_trust_id_.set_key_id(0);
expected_root_of_trust_id_.set_version(
RootOfTrustId::ROOT_OF_TRUST_ID_VERSION_1);
}
std::unique_ptr<EciesEncryptor> CreateEncryptor() {
return EciesEncryptor::Create(test_keys_.public_test_key_2_secp256r1(),
&fake_ec_key_source_);
}
std::unique_ptr<EciesDecryptor> CreateDecryptor() {
return EciesDecryptor::Create(test_keys_.private_test_key_2_secp256r1());
}
protected:
ECTestKeys test_keys_;
FakeECKeySource fake_ec_key_source_;
RootOfTrustId expected_root_of_trust_id_;
};
class MockEciesEncryptor : public EciesEncryptor {
public:
static MockEciesEncryptor* Create() {
ECTestKeys test_keys;
std::unique_ptr<ECPublicKey> ec_key =
ECPublicKey::Create(test_keys.public_test_key_1_secp256r1());
return new MockEciesEncryptor(std::move(ec_key));
}
MOCK_METHOD(bool, Encrypt,
(const std::string&, const std::string&, std::string*),
(const, override));
private:
explicit MockEciesEncryptor(std::unique_ptr<ECPublicKey> ec_key)
: EciesEncryptor(std::move(ec_key), &fake_ec_key_source_) {}
FakeECKeySource fake_ec_key_source_;
};
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdSuccess) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Verify decrypted unique id.
std::string decrypted_unique_id;
EXPECT_OK(decryptor.DecryptUniqueId(kTestSystemId,
root_of_trust_id.encrypted_unique_id(),
&decrypted_unique_id));
EXPECT_EQ(kTestUniqueId, decrypted_unique_id);
// Verify hashed unique id matches.
std::string unique_id_hash = generator.GenerateUniqueIdHash(kTestUniqueId);
EXPECT_TRUE(IsRotIdRevoked<std::vector<std::string>>(
root_of_trust_id.encrypted_unique_id(), kTestSystemId,
root_of_trust_id.unique_id_hash(), {unique_id_hash}));
}
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdUniqueSuccess) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
std::string rot_encrypted_id;
std::string rot_id_hash;
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Generate a second root of trust id for the same unique id.
// This must generate a different looking id.
// First, assign a new ephemeral to the fake key source.
fake_ec_key_source_.SetKey(ECPrivateKey::SECP256R1,
test_keys_.private_test_key_2_secp256r1(),
test_keys_.public_test_key_2_secp256r1());
RootOfTrustId second_root_of_trust_id;
ASSERT_OK(generator.Generate(kTestSystemId, kTestUniqueId,
&second_root_of_trust_id));
EXPECT_FALSE(second_root_of_trust_id.encrypted_unique_id().empty());
EXPECT_NE(kTestUniqueId, second_root_of_trust_id.encrypted_unique_id());
EXPECT_FALSE(second_root_of_trust_id.unique_id_hash().empty());
// Verify that the second id does not equal the first.
EXPECT_NE(root_of_trust_id.encrypted_unique_id(),
second_root_of_trust_id.encrypted_unique_id());
EXPECT_NE(root_of_trust_id.unique_id_hash(),
second_root_of_trust_id.unique_id_hash());
// Verify second decrypted unique id.
std::string decrypted_unique_id;
EXPECT_OK(decryptor.DecryptUniqueId(
kTestSystemId, second_root_of_trust_id.encrypted_unique_id(),
&decrypted_unique_id));
EXPECT_EQ(kTestUniqueId, decrypted_unique_id);
// Verify hashed unique id matches.
std::string unique_id_hash = generator.GenerateUniqueIdHash(kTestUniqueId);
EXPECT_TRUE(IsRotIdRevoked<std::vector<std::string>>(
second_root_of_trust_id.encrypted_unique_id(), kTestSystemId,
second_root_of_trust_id.unique_id_hash(), {unique_id_hash}));
}
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdFailedEncryption) {
MockEciesEncryptor* mock_encryptor = MockEciesEncryptor::Create();
ASSERT_THAT(mock_encryptor, NotNull());
RootOfTrustIdGenerator generator(
std::unique_ptr<EciesEncryptor>(mock_encryptor), kTestSharedSalt);
EXPECT_CALL(*mock_encryptor, Encrypt(_, _, _))
.Times(1)
.WillOnce(Return(false))
.RetiresOnSaturation();
std::string rot_encrypted_id;
std::string rot_id_hash;
// Attempt to generate the root of trust id.
RootOfTrustId root_of_trust_id;
EXPECT_EQ(error::INTERNAL,
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id)
.error_code());
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
RootOfTrustId::default_instance(), root_of_trust_id));
}
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdEmptyIdFail) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustId root_of_trust_id;
// Should fail because the id is blank.
EXPECT_EQ(
error::INVALID_ARGUMENT,
generator.Generate(kTestSystemId, "", &root_of_trust_id).error_code());
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
RootOfTrustId::default_instance(), root_of_trust_id));
}
TEST_F(RootOfTrustIdGeneratorTest, GenerateIdNullRotIdFail) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
// Should fail because the id is blank.
EXPECT_DEATH(generator.Generate(kTestSystemId, kTestUniqueId,
nullptr /* root of trust id*/),
"root_of_trust_id");
}
TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdMismatchFails) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Attempt to decrypt with different system id. Should fail.
std::string decrypted_unique_id;
EXPECT_EQ(error::INTERNAL,
decryptor
.DecryptUniqueId(kTestSystemId + 1,
root_of_trust_id.encrypted_unique_id(),
&decrypted_unique_id)
.error_code());
}
TEST_F(RootOfTrustIdGeneratorTest, DecryptorBlankUniqueId) {
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Attempt to decrypt empty encrypted id.
std::string decrypted_unique_id;
EXPECT_EQ(error::INVALID_ARGUMENT,
decryptor.DecryptUniqueId(kTestSystemId, "", &decrypted_unique_id)
.error_code());
}
TEST_F(RootOfTrustIdGeneratorTest, DecryptorSystemIdNullDecryptedIdFails) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Attempt to decrypt with a nullptr for the decrypted id.
std::string decrypted_unique_id;
EXPECT_DEATH(
decryptor.DecryptUniqueId(
kTestSystemId, root_of_trust_id.encrypted_unique_id(), nullptr),
"unique_id");
}
TEST_F(RootOfTrustIdGeneratorTest, VerifyAndExtractAllValuesSuccess) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Verify decrypted unique id.
std::string decrypted_unique_id;
std::string decrypted_unique_id_hash;
EXPECT_OK(decryptor.VerifyAndExtractAllValues(kTestSystemId, root_of_trust_id,
&decrypted_unique_id,
&decrypted_unique_id_hash));
EXPECT_EQ(kTestUniqueId, decrypted_unique_id);
EXPECT_EQ(generator.GenerateUniqueIdHash(kTestUniqueId),
decrypted_unique_id_hash);
}
TEST_F(RootOfTrustIdGeneratorTest, VerifyAndExtractAllValuesSystemIdMismatch) {
RootOfTrustIdGenerator generator(CreateEncryptor(), kTestSharedSalt);
RootOfTrustIdDecryptor decryptor(CreateDecryptor(), kTestSharedSalt);
// Generate the root of trust id.
RootOfTrustId root_of_trust_id;
ASSERT_OK(
generator.Generate(kTestSystemId, kTestUniqueId, &root_of_trust_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(
expected_root_of_trust_id_, root_of_trust_id));
// Verify decrypted unique id.
std::string decrypted_unique_id;
std::string decrypted_unique_id_hash;
EXPECT_EQ(error::INTERNAL,
decryptor
.VerifyAndExtractAllValues(kTestSystemId + 1, root_of_trust_id,
&decrypted_unique_id,
&decrypted_unique_id_hash)
.error_code());
}
} // namespace widevine

View File

@@ -1,45 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Helper methods for the Root of Trust Id.
#include "common/rot_id_util.h"
#include <memory>
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "common/crypto_util.h"
#include "common/ec_key.h"
#include "common/sha_util.h"
namespace widevine {
std::string GenerateRotIdHash(const std::string& salt, uint32_t system_id,
const std::string& unique_id_hash) {
if (salt.empty() || unique_id_hash.empty()) {
return "";
}
return Sha256_Hash(absl::StrCat(salt, system_id, unique_id_hash));
}
std::string GenerateUniqueIdHash(const std::string& unique_id,
const std::string& salt) {
if (unique_id.empty()) {
LOG(WARNING) << "unique_id should not be empty.";
return "";
}
if (salt.empty()) {
LOG(WARNING) << "salt should not be empty.";
return "";
}
return widevine::Sha256_Hash(absl::StrCat(unique_id, salt));
}
} // namespace widevine

View File

@@ -1,67 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Helper methods for the Root of Trust Id.
#ifndef COMMON_ROT_ID_UTIL_H_
#define COMMON_ROT_ID_UTIL_H_
#include <memory>
#include <vector>
#include <cstdint>
#include "common/ec_key.h"
#include "common/local_ec_key_source.h"
namespace widevine {
// Helper function that generates the unique id hash from the |unique_id| and
// the |salt|. |salt| is an internal secret.
//
// Returns the hash value on success.
// If |salt| or |unique_id| are empty, this will return an empty string.
std::string GenerateUniqueIdHash(const std::string& unique_id,
const std::string& salt);
// Helper function that generates the hash for the ROT id from the
// |unique_id_hash|, the |system_id| and the |salt|. |salt| is typically an
// encrypted unique id. Since we use an ephemeral eliptic curve key as part of
// the encrypted unique id, the value is effectively random can be used as a
// salt.
// Returns the hash value on success.
// If |salt| or |unique_id_hash| are empty, this will return an empty
// string.
std::string GenerateRotIdHash(const std::string& salt, uint32_t system_id,
const std::string& unique_id_hash);
// Helper function that compares the |rot_id_hash| to a hash of each of the
// |revoked_ids|. The |revoked_ids| are the unique id hash (aka inner hash)
// values as defined in the spec at go/wv-kb-id. The |encrypted_unique_id| and
// |system_id| are used to compute the hash of each of the |revoked_ids|.
// Returns true if any of the revoked_ids match.
template <typename V>
bool IsRotIdRevoked(const std::string& encrypted_unique_id, uint32_t system_id,
const std::string& rot_id_hash, const V& revoked_ids) {
// This could conceivably happen for legacy DRM certificates without a ROT id.
// No need to match if there's nothing to match against.
if (encrypted_unique_id.empty() || rot_id_hash.empty()) {
return false;
}
for (const auto& revoked_id : revoked_ids) {
if (GenerateRotIdHash(encrypted_unique_id, system_id, revoked_id) ==
rot_id_hash) {
return true;
}
}
return false;
}
} // namespace widevine
#endif // COMMON_ROT_ID_UTIL_H_

View File

@@ -1,85 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit tests for the rot_id_util helper methods.
#include "common/rot_id_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
namespace {
constexpr char kFakeEncryptedId[] = "fake encrypted id";
constexpr char kFakeUniqueIdHash[] = "fake unique_id hash";
constexpr char kFakeUniqueId[] = "fake unique_id";
constexpr char kFakeSecretSalt[] = "fake secret salt";
// This is the ROT ID Hash generated from the fake values.
constexpr char kRotIdHashHex[] =
"0a757dde0f1080b60f34bf8e46af573ce987b5ed1c831b44952e2feed5243a95";
// This is the unique id hash generated from the fake unique id value.
constexpr char kUniqueIdHashHex[] =
"da20922e84b48e52223496f44b07632a4db19d488cd71cf813de300b9d244e06";
constexpr uint32_t kFakeSystemId = 1234;
constexpr uint32_t kOtherFakeSystemId = 9876;
} // anonymous namespace
namespace widevine {
TEST(RotIdUtilTest, IsRotIdRevokedMatches) {
ASSERT_TRUE(IsRotIdRevoked<std::vector<std::string>>(
kFakeEncryptedId, kFakeSystemId, absl::HexStringToBytes(kRotIdHashHex),
{"NO MATCH UNIQUE ID HASH 1", kFakeUniqueIdHash}));
}
TEST(RotIdUtilTest, IsRotIdRevokedNoMatchSystemId) {
ASSERT_FALSE(IsRotIdRevoked<std::vector<std::string>>(
kFakeEncryptedId, kOtherFakeSystemId,
absl::HexStringToBytes(kRotIdHashHex),
{"NO MATCH UNIQUE ID HASH 1", kFakeUniqueIdHash}));
}
TEST(RotIdUtilTest, IsRotIdRevokedNoMatch) {
ASSERT_FALSE(IsRotIdRevoked<std::vector<std::string>>(
kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash,
{"NO MATCH UNIQUE ID HASH 1", "NO MATCH UNIQUE ID HASH 2"}));
}
TEST(RotIdUtilTest, IsRotIdRevokedEmptyList) {
ASSERT_FALSE(IsRotIdRevoked<std::vector<std::string>>(
kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash,
{/* Intentionally empty vector */}));
}
// This test really only ensures the stability of the implementation. If the
// hash ever changes, then it will introduce problems into the ecosystem.
TEST(RotIdUtilTest, GenerateRotIdHashSuccess) {
ASSERT_EQ(
absl::HexStringToBytes(kRotIdHashHex),
GenerateRotIdHash(kFakeEncryptedId, kFakeSystemId, kFakeUniqueIdHash));
}
// This test really only ensures the stability of the GenerateUniqueIdHash
// implementation. If the hash ever changes, then it will introduce problems
// into the ecosystem.
TEST(RotIdUtilTest, GenerateUniqueIdHashSuccess) {
ASSERT_EQ(absl::HexStringToBytes(kUniqueIdHashHex),
GenerateUniqueIdHash(kFakeUniqueId, kFakeSecretSalt));
}
TEST(RotIdUtilTest, GenerateUniqueIdHashEmptyValues) {
ASSERT_EQ("", GenerateUniqueIdHash(kFakeUniqueId, ""));
ASSERT_EQ("", GenerateUniqueIdHash("", kFakeSecretSalt));
}
} // namespace widevine

View File

@@ -117,41 +117,6 @@ bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
return true;
}
bool RsaPrivateKey::GenerateSignature(const std::string& message,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Message to be signed is empty";
return false;
}
// Hash the message using SHA1.
std::string message_digest = Sha1_Hash(message);
// Add PSS padding.
size_t rsa_size = RSA_size(key_);
std::string padded_digest(rsa_size, 0);
if (!RSA_padding_add_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&message_digest[0]), EVP_sha1(),
EVP_sha1(), kPssSaltLength)) {
LOG(ERROR) << "RSA padding failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
// Encrypt PSS padded digest.
signature->assign(rsa_size, 0);
if (RSA_private_encrypt(padded_digest.size(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
reinterpret_cast<unsigned char*>(&(*signature)[0]),
key_, RSA_NO_PADDING) !=
static_cast<int>(signature->size())) {
LOG(ERROR) << "RSA private encrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPrivateKey::GenerateSignature(const std::string& message,
HashAlgorithm hash_algorithm,
@@ -270,46 +235,6 @@ bool RsaPublicKey::Encrypt(const std::string& clear_message,
return true;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Signed message is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
if (signature.size() != rsa_size) {
LOG(ERROR) << "Message signature is of the wrong size (expected "
<< rsa_size << ", actual " << signature.size() << ")";
return false;
}
// Decrypt the signature.
std::string padded_digest(signature.size(), 0);
if (RSA_public_decrypt(
signature.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(signature.data())),
reinterpret_cast<unsigned char*>(&padded_digest[0]), key_,
RSA_NO_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public decrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
// Hash the message using SHA1.
std::string message_digest = Sha1_Hash(message);
// Verify PSS padding.
if (RSA_verify_PKCS1_PSS_mgf1(
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
EVP_sha1(), EVP_sha1(),
reinterpret_cast<unsigned char*>(&padded_digest[0]),
kPssSaltLength) == 0) {
LOG(ERROR) << "RSA Verify PSS padding failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
return true;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const {

View File

@@ -41,14 +41,6 @@ class RsaPrivateKey {
virtual bool Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) const;
// Generate RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if successful, false otherwise.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Generate RSSASSA-PSS signature. Caller retains ownership of all parameters.
// |hash_algorithm| indicates the hash algorithm used. Returns true if
@@ -109,14 +101,6 @@ class RsaPublicKey {
virtual bool Encrypt(const std::string& clear_message,
std::string* encrypted_message) const;
// Verify RSSASSA-PSS signature. Caller retains ownership of all parameters.
// Returns true if validation succeeds, false otherwise.
// TODO(b/155438325): remove this function after the below function is fully
// propagated.
ABSL_DEPRECATED(
"Use the below function with |hash_algorithm| argument instead.")
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Verify RSSASSA-PSS signature. Caller retains ownership of all parameters.
// |hash_algorithm| indicates the hash algorithm used. Returns true if

View File

@@ -1,268 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit test for rsa_key RSA encryption and signing.
#include "common/rsa_key.h"
#include <memory>
#include "testing/gunit.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
namespace widevine {
static const char kTestMessage[] =
"A fool thinks himself to be wise, but a wise man knows himself to be a "
"fool.";
class RsaKeyTest : public ::testing::Test {
protected:
void TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
void TestSigning(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
void TestSigningSha256Pkcs7(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key);
RsaTestKeys test_keys_;
RsaKeyFactory factory_;
};
TEST_F(RsaKeyTest, CopyConstructor) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
std::unique_ptr<RsaPrivateKey> private_key_copy(
new RsaPrivateKey(*private_key));
std::unique_ptr<RsaPublicKey> public_key_copy(new RsaPublicKey(*public_key));
EXPECT_TRUE(public_key_copy->MatchesPublicKey(*public_key));
EXPECT_TRUE(public_key_copy->MatchesPrivateKey(*private_key));
EXPECT_TRUE(private_key_copy->MatchesPublicKey(*public_key));
EXPECT_TRUE(private_key_copy->MatchesPrivateKey(*private_key));
}
void RsaKeyTest::TestEncryption(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string encrypted_message;
EXPECT_TRUE(public_key->Encrypt(kTestMessage, &encrypted_message));
std::string decrypted_message;
EXPECT_TRUE(private_key->Decrypt(encrypted_message, &decrypted_message));
EXPECT_EQ(kTestMessage, decrypted_message);
// Add a byte to the encrypted message.
std::string bad_enc_message(encrypted_message);
bad_enc_message += '\0';
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
// Remove a byte from the encrypted message.
bad_enc_message = encrypted_message.substr(0, encrypted_message.size() - 1);
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
// Change a byte in the encrypted message.
bad_enc_message = encrypted_message;
bad_enc_message[128] ^= 0x55;
EXPECT_FALSE(private_key->Decrypt(bad_enc_message, &decrypted_message));
}
void RsaKeyTest::TestSigning(std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string signature;
EXPECT_TRUE(private_key->GenerateSignature(kTestMessage, &signature));
EXPECT_TRUE(public_key->VerifySignature(kTestMessage, signature));
// Add a byte to the signature.
std::string bad_signature(signature);
bad_signature += '\0';
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
// Remove a byte from the signature.
bad_signature = signature.substr(0, signature.size() - 1);
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
// Change a byte in the signature.
bad_signature = signature;
bad_signature[32] ^= 0x55;
EXPECT_FALSE(public_key->VerifySignature(kTestMessage, bad_signature));
}
void RsaKeyTest::TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey> private_key,
std::unique_ptr<RsaPublicKey> public_key) {
ASSERT_TRUE(private_key);
ASSERT_TRUE(public_key);
std::string signature;
EXPECT_TRUE(
private_key->GenerateSignatureSha256Pkcs7(kTestMessage, &signature));
EXPECT_TRUE(public_key->VerifySignatureSha256Pkcs7(kTestMessage, signature));
// Add a byte to the signature.
std::string bad_signature(signature);
bad_signature += '\0';
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
// Remove a byte from the signature.
bad_signature = signature.substr(0, signature.size() - 1);
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
// Change a byte in the signature.
bad_signature = signature;
bad_signature[32] ^= 0x55;
EXPECT_FALSE(
public_key->VerifySignatureSha256Pkcs7(kTestMessage, bad_signature));
}
TEST_F(RsaKeyTest, BadKey) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create("bad_private_key"));
EXPECT_TRUE(!private_key);
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create("bad_public_key"));
EXPECT_TRUE(!public_key);
}
TEST_F(RsaKeyTest, EncryptAndDecrypt_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestEncryption(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestEncryption(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, EncryptAndDecrypt_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestEncryption(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestEncryption(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, RsaPublicKeyFromPrivateKey) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
ASSERT_TRUE(private_key);
std::unique_ptr<RsaPublicKey> public_key(new RsaPublicKey(*private_key));
ASSERT_TRUE(public_key);
EXPECT_TRUE(private_key->MatchesPublicKey(*public_key));
EXPECT_TRUE(public_key->MatchesPrivateKey(*private_key));
TestEncryption(std::move(private_key), std::move(public_key));
}
TEST_F(RsaKeyTest, SignAndVerify_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestSigning(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestSigning(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerify_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestSigning(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestSigning(factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_3072) {
const std::string& private_key = test_keys_.private_test_key_1_3072_bits();
const std::string& public_key = test_keys_.public_test_key_1_3072_bits();
TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
TestSigningSha256Pkcs7(factory_.CreateFromPkcs1PrivateKey(private_key),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, SignAndVerifySha256Pkcs7_2048) {
const std::string& private_key = test_keys_.private_test_key_2_2048_bits();
const std::string& public_key = test_keys_.public_test_key_2_2048_bits();
TestSigningSha256Pkcs7(
std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key)),
std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key)));
std::string pkcs8_key;
std::string passphrase("passphrase");
ASSERT_TRUE(rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
private_key, passphrase, &pkcs8_key));
TestSigningSha256Pkcs7(
factory_.CreateFromPkcs8PrivateKey(pkcs8_key, passphrase),
factory_.CreateFromPkcs1PublicKey(public_key));
ASSERT_TRUE(rsa_util::RsaPrivateKeyToPrivateKeyInfo(private_key, &pkcs8_key));
TestSigningSha256Pkcs7(
factory_.CreateFromPkcs8PrivateKey(pkcs8_key, std::string()),
factory_.CreateFromPkcs1PublicKey(public_key));
}
TEST_F(RsaKeyTest, KeySize) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
EXPECT_EQ(256, private_key->KeySize());
EXPECT_EQ(256, public_key->KeySize());
}
TEST_F(RsaKeyTest, RsaKeyMatch) {
std::unique_ptr<RsaPrivateKey> private_key2(
RsaPrivateKey::Create(test_keys_.private_test_key_2_2048_bits()));
std::unique_ptr<RsaPrivateKey> private_key3(
RsaPrivateKey::Create(test_keys_.private_test_key_3_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key2(
RsaPublicKey::Create(test_keys_.public_test_key_2_2048_bits()));
std::unique_ptr<RsaPublicKey> public_key3(
RsaPublicKey::Create(test_keys_.public_test_key_3_2048_bits()));
EXPECT_TRUE(public_key2->MatchesPublicKey(*public_key2));
EXPECT_FALSE(public_key2->MatchesPublicKey(*public_key3));
EXPECT_TRUE(public_key2->MatchesPrivateKey(*private_key2));
EXPECT_FALSE(public_key2->MatchesPrivateKey(*private_key3));
EXPECT_TRUE(private_key2->MatchesPublicKey(*public_key2));
EXPECT_FALSE(private_key2->MatchesPublicKey(*public_key3));
EXPECT_TRUE(private_key2->MatchesPrivateKey(*private_key2));
EXPECT_FALSE(private_key2->MatchesPrivateKey(*private_key3));
}
} // namespace widevine

View File

@@ -1,786 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA keys generated using fake_prng for purposes of testing.
#include "common/rsa_test_keys.h"
namespace widevine {
static const unsigned char kTestRsaPrivateKey1_3072[] = {
0x30, 0x82, 0x06, 0xe3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x81, 0x00,
0xa5, 0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0,
0x78, 0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3,
0x0f, 0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2,
0xca, 0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55,
0x1b, 0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29,
0x46, 0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17,
0x01, 0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37,
0x5c, 0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1,
0x14, 0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86,
0xcd, 0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3,
0xb6, 0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4,
0xde, 0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb,
0x31, 0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee,
0x3a, 0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb,
0x90, 0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca,
0x49, 0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0,
0x5f, 0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6,
0xda, 0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb,
0x17, 0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab,
0x30, 0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26,
0xaf, 0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10,
0x16, 0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b,
0x42, 0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21,
0xf9, 0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64,
0xe4, 0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05,
0x4a, 0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1,
0x72, 0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab,
0xde, 0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50,
0x04, 0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85,
0x1b, 0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0,
0x33, 0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b,
0x67, 0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87,
0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x80, 0x5a, 0x09, 0x3f,
0x9e, 0x2e, 0x4d, 0x26, 0x50, 0x7b, 0x70, 0x21, 0xb0, 0x0c, 0x25, 0x21,
0x1f, 0xd9, 0x89, 0x5a, 0xca, 0x35, 0x23, 0x0b, 0x58, 0xa9, 0x7d, 0xf6,
0x19, 0xc4, 0x29, 0x87, 0xc7, 0xd4, 0x94, 0x85, 0xb4, 0x2c, 0xaf, 0x62,
0xb1, 0xe8, 0x62, 0x5b, 0xda, 0xdb, 0x70, 0x40, 0x37, 0xb1, 0x4e, 0x0c,
0xc8, 0x62, 0xee, 0xa2, 0xfc, 0x3c, 0xd2, 0x39, 0x90, 0x15, 0x2c, 0xba,
0x20, 0x50, 0xb7, 0x82, 0x2a, 0xa0, 0x76, 0x83, 0x20, 0x7f, 0x56, 0x73,
0x43, 0x8a, 0x9b, 0xa7, 0x6c, 0x63, 0xb6, 0xad, 0x56, 0xb2, 0x8a, 0xb2,
0xbc, 0x8f, 0xe2, 0xef, 0x83, 0x9d, 0x98, 0x0b, 0xc7, 0x62, 0x0e, 0x51,
0x6e, 0x57, 0x1d, 0x1b, 0x0e, 0x3a, 0xea, 0x3b, 0x76, 0x63, 0x35, 0xd0,
0xd1, 0xcf, 0xbe, 0xad, 0xbb, 0x1d, 0xde, 0x0f, 0x05, 0x48, 0x55, 0x29,
0xc1, 0xbc, 0x21, 0xc7, 0x87, 0xf2, 0x75, 0x12, 0x7d, 0x92, 0x9e, 0xbf,
0xad, 0x04, 0x68, 0xc4, 0xc9, 0x9d, 0x35, 0xd6, 0xa8, 0x62, 0xc1, 0x69,
0x6a, 0xb6, 0x41, 0xb7, 0x37, 0x66, 0xdf, 0xb2, 0xb9, 0x8c, 0x8b, 0x15,
0x08, 0x4c, 0x3d, 0xf1, 0xed, 0x82, 0x0f, 0xe3, 0xd5, 0xff, 0x46, 0xbd,
0xf7, 0x85, 0x43, 0xc0, 0x8b, 0xba, 0x47, 0xf1, 0x41, 0x57, 0xc3, 0x7f,
0x8b, 0x0d, 0x48, 0xea, 0xc2, 0xed, 0xc0, 0x69, 0x84, 0xb6, 0x32, 0x08,
0x49, 0x74, 0x14, 0x84, 0xa4, 0x1b, 0x48, 0x5b, 0xec, 0xd3, 0x0b, 0x12,
0x2b, 0x4c, 0x9e, 0x5c, 0x01, 0x60, 0xad, 0xef, 0xcb, 0x2b, 0x56, 0x84,
0x07, 0xfa, 0x62, 0xc6, 0x08, 0x92, 0x98, 0x70, 0xc9, 0x5b, 0x18, 0xc8,
0xfa, 0x27, 0x0c, 0xe2, 0xbd, 0xfb, 0x3e, 0x43, 0xa5, 0xb7, 0x06, 0x2c,
0x4e, 0xf1, 0x07, 0x5d, 0x8d, 0xdd, 0x53, 0xc5, 0x8c, 0x4a, 0xf2, 0x2f,
0x8e, 0x80, 0x96, 0x16, 0xc0, 0xfc, 0xf9, 0x20, 0x4f, 0x35, 0xc7, 0x53,
0x8b, 0x2d, 0x37, 0x43, 0x93, 0x3d, 0x74, 0x3f, 0x63, 0xf7, 0x0b, 0xbd,
0x46, 0xe4, 0x51, 0x67, 0x33, 0x57, 0x15, 0xf5, 0x59, 0x27, 0x66, 0xe8,
0xe2, 0x4b, 0xa3, 0x93, 0x03, 0x8a, 0x9c, 0x05, 0x13, 0xf2, 0xcb, 0xf7,
0x9c, 0x68, 0xe7, 0x16, 0x4b, 0x8e, 0x59, 0x71, 0x2b, 0x73, 0x9b, 0xb9,
0xae, 0x50, 0xfa, 0xd7, 0xd3, 0x34, 0x17, 0x1d, 0x62, 0x88, 0xbd, 0x8c,
0xba, 0x5a, 0x6b, 0x6a, 0x5e, 0xb3, 0xa5, 0x80, 0xca, 0xbb, 0xb9, 0xb5,
0xa8, 0x2e, 0xb1, 0x61, 0x6e, 0xd5, 0xd6, 0x62, 0x98, 0x4a, 0xb0, 0xb8,
0x76, 0xa9, 0x19, 0x5c, 0xe2, 0xbe, 0xb3, 0x9b, 0x4a, 0x39, 0xf5, 0xe6,
0xbb, 0x11, 0x6e, 0x13, 0x13, 0x38, 0xb8, 0x1f, 0x21, 0x19, 0xf5, 0xa7,
0x76, 0x93, 0xb3, 0x56, 0xfa, 0xcc, 0x74, 0xbc, 0x19, 0x02, 0x81, 0xc1,
0x00, 0xd1, 0xd1, 0x72, 0x57, 0xe5, 0xb0, 0x1c, 0x09, 0x05, 0xbb, 0x55,
0x89, 0x3c, 0x4a, 0x81, 0x90, 0x9a, 0xf9, 0x32, 0x63, 0x41, 0xad, 0x6a,
0x5f, 0x65, 0x94, 0x92, 0xcc, 0xf7, 0xc7, 0x53, 0x93, 0xa0, 0xf7, 0xbe,
0x48, 0x82, 0x63, 0x31, 0x7b, 0xd0, 0x82, 0x09, 0xbb, 0x0a, 0xbc, 0x60,
0xc9, 0x4d, 0x83, 0xe4, 0x5d, 0x50, 0xe6, 0x5f, 0x8b, 0x47, 0x07, 0xa3,
0x3a, 0x36, 0x97, 0xaa, 0x21, 0x70, 0x7f, 0xd5, 0x6c, 0xb0, 0x56, 0xf5,
0x5c, 0x48, 0x74, 0x2a, 0xdd, 0xfe, 0x94, 0x83, 0x05, 0xe0, 0x3d, 0x5d,
0xdd, 0x5a, 0x05, 0xcb, 0x47, 0xd7, 0xf9, 0x89, 0x55, 0xaa, 0x0b, 0x21,
0xc0, 0x71, 0x5d, 0xe1, 0x4c, 0x6a, 0x45, 0x86, 0x86, 0xf2, 0xb9, 0x38,
0x6a, 0x56, 0x51, 0x0d, 0x7d, 0xac, 0x30, 0x31, 0xca, 0x2d, 0xaa, 0xaa,
0xba, 0xcc, 0x12, 0x40, 0xc1, 0x0d, 0xa6, 0xc1, 0x7d, 0x22, 0xec, 0xb6,
0x51, 0x45, 0xfe, 0x4e, 0xbb, 0x4a, 0xd2, 0xba, 0x9b, 0xa2, 0xcc, 0x28,
0x2b, 0x01, 0x53, 0x53, 0xf3, 0xa9, 0x5a, 0x8f, 0xeb, 0xb7, 0xb8, 0x62,
0x6b, 0x8a, 0x79, 0x24, 0xcc, 0x86, 0x34, 0x45, 0xe2, 0xad, 0x1d, 0xd0,
0x4c, 0xc9, 0x77, 0x2a, 0xf9, 0x1a, 0xe8, 0x58, 0x78, 0x51, 0x8a, 0xea,
0x3f, 0x90, 0x36, 0x46, 0x2a, 0xc0, 0x71, 0x41, 0x83, 0x2c, 0x48, 0xee,
0xc5, 0x02, 0x81, 0xc1, 0x00, 0xc9, 0xc8, 0xce, 0xc4, 0x50, 0xb2, 0x26,
0xcb, 0x35, 0x78, 0x55, 0x3c, 0xcc, 0xf0, 0x7e, 0xba, 0xad, 0xeb, 0x58,
0xe9, 0xb5, 0x78, 0x2f, 0x43, 0x5f, 0x07, 0x47, 0x56, 0x05, 0x41, 0x38,
0x71, 0xe1, 0x58, 0x62, 0xb1, 0x8e, 0xbc, 0xf9, 0x80, 0x04, 0x22, 0x39,
0x22, 0x24, 0x28, 0x86, 0x9c, 0x00, 0x44, 0x5f, 0xc4, 0x97, 0xe6, 0x71,
0x5f, 0x1f, 0x58, 0xea, 0x75, 0x18, 0x0c, 0x23, 0x63, 0x09, 0xc5, 0x98,
0xc4, 0x6d, 0x23, 0xc2, 0x2c, 0x93, 0x6a, 0x26, 0xe4, 0x3d, 0x8d, 0xa1,
0x39, 0x70, 0x34, 0x25, 0xcd, 0xbc, 0x82, 0x78, 0x2b, 0xf3, 0x7e, 0x81,
0xb6, 0x5f, 0xc5, 0x69, 0xd0, 0x81, 0x69, 0x50, 0x2f, 0x17, 0x0c, 0x17,
0x3c, 0x0b, 0x45, 0x38, 0xce, 0xe3, 0xbf, 0x8a, 0x50, 0x0a, 0x00, 0x74,
0x7e, 0x7a, 0xd8, 0x55, 0x52, 0x6b, 0x82, 0xfb, 0x34, 0x15, 0x73, 0x6a,
0xf4, 0x51, 0x9b, 0x9f, 0xa0, 0x45, 0xb9, 0x76, 0xe5, 0xd3, 0xd5, 0xf4,
0xa9, 0xa4, 0xcd, 0x42, 0x2f, 0x29, 0x89, 0xec, 0x28, 0x5f, 0x03, 0x45,
0x27, 0xaf, 0x8c, 0x39, 0x3e, 0x59, 0x9d, 0xaf, 0x27, 0x5d, 0x17, 0x53,
0x17, 0xeb, 0x8d, 0x7f, 0x3d, 0xb8, 0x2a, 0x50, 0x1e, 0xb5, 0xc5, 0x04,
0xab, 0x9c, 0xa7, 0xaa, 0x86, 0x41, 0xb9, 0x36, 0x29, 0x9e, 0xd2, 0xd8,
0xde, 0x5f, 0xde, 0x80, 0xdb, 0x02, 0x81, 0xc0, 0x03, 0xf3, 0x5f, 0xa5,
0xcc, 0x0b, 0x5e, 0xdb, 0xc4, 0xa1, 0xdc, 0x60, 0x73, 0x24, 0x2c, 0x00,
0x5f, 0x0a, 0xa6, 0x2a, 0x3c, 0x48, 0x59, 0xa2, 0x66, 0x35, 0x3f, 0xf6,
0x60, 0x0b, 0xfe, 0xc4, 0xde, 0xd9, 0x0b, 0x5a, 0x2e, 0x2a, 0x53, 0xfa,
0x32, 0xd8, 0xdf, 0xfa, 0x07, 0x9f, 0xb8, 0x6a, 0xd1, 0xec, 0xd3, 0xd5,
0xf5, 0xfa, 0x00, 0x7e, 0x8c, 0xdd, 0xd5, 0xf2, 0xf8, 0xa8, 0x2e, 0x69,
0xe6, 0xc6, 0x61, 0x6c, 0x64, 0x7d, 0x9e, 0xad, 0x18, 0x28, 0x27, 0xce,
0x7a, 0x46, 0xad, 0x98, 0xe4, 0xba, 0x03, 0x14, 0x71, 0xe7, 0x7e, 0x06,
0x62, 0x48, 0xae, 0x8f, 0x50, 0x5e, 0x59, 0x4a, 0x58, 0x58, 0x1e, 0x2f,
0xe4, 0x28, 0x5e, 0xfa, 0x17, 0x83, 0xe9, 0x4e, 0x07, 0x46, 0x0b, 0x6c,
0xfc, 0x5b, 0x03, 0xf4, 0xfc, 0x9b, 0x24, 0x0f, 0xd4, 0x5b, 0xdb, 0xa0,
0x46, 0xf3, 0x86, 0xdd, 0x26, 0x55, 0x32, 0xb1, 0xa1, 0x11, 0xc2, 0xc5,
0xc0, 0x08, 0xeb, 0xbe, 0x96, 0x78, 0x25, 0xa1, 0x79, 0xaa, 0xe9, 0xff,
0xc2, 0x86, 0x94, 0x03, 0x2a, 0x38, 0x6c, 0x91, 0xfd, 0xcf, 0x7e, 0x23,
0xe3, 0xbb, 0x04, 0x3d, 0xda, 0x68, 0x9f, 0x4d, 0x72, 0xd5, 0xad, 0x97,
0x77, 0x2c, 0x3c, 0xce, 0x37, 0x2a, 0xd8, 0x72, 0x4d, 0xf2, 0xd7, 0xab,
0x62, 0x68, 0x3f, 0x85, 0x8a, 0xc5, 0xec, 0xc9, 0x02, 0x81, 0xc1, 0x00,
0x92, 0x43, 0x0c, 0x1d, 0x20, 0xa1, 0x01, 0x9d, 0xaa, 0x54, 0x5e, 0xf4,
0x83, 0x58, 0x8f, 0x83, 0xa1, 0x2d, 0x46, 0x75, 0xa1, 0x24, 0x4c, 0x9d,
0xf8, 0xf3, 0xbd, 0xb1, 0x8c, 0x7d, 0x89, 0xfc, 0x81, 0xeb, 0x1f, 0x1e,
0xb4, 0xe8, 0x25, 0xb1, 0xb5, 0x4d, 0x59, 0x3c, 0x76, 0x19, 0x29, 0xf9,
0x49, 0xf8, 0x45, 0xb2, 0xaa, 0xa8, 0x4e, 0xe5, 0x34, 0x43, 0xaf, 0x2e,
0xd1, 0x0f, 0x7b, 0x56, 0xfe, 0x6e, 0x4c, 0x1d, 0x95, 0x3e, 0xa6, 0x30,
0xc9, 0x69, 0xd8, 0x66, 0xf8, 0x77, 0x00, 0xb6, 0x31, 0xae, 0x9a, 0xf8,
0x55, 0xfb, 0xfc, 0x3f, 0x5f, 0x70, 0x03, 0x75, 0xbe, 0x55, 0xca, 0x2d,
0x68, 0xa0, 0x7d, 0x8e, 0xa4, 0x96, 0x0f, 0x01, 0x66, 0xe9, 0xf6, 0x13,
0x80, 0xe2, 0x05, 0xcf, 0x9e, 0x70, 0x56, 0x00, 0x97, 0xea, 0xd7, 0x6d,
0xb6, 0xa0, 0x6a, 0x95, 0x86, 0x36, 0xf2, 0xff, 0xc5, 0x67, 0x98, 0x7d,
0x04, 0x0d, 0x3b, 0x31, 0xbc, 0x2b, 0x09, 0xfd, 0x2d, 0x87, 0xda, 0xc1,
0x74, 0xca, 0x94, 0x73, 0x6e, 0xeb, 0x5f, 0xe5, 0x34, 0x49, 0xdf, 0xf4,
0x61, 0xe0, 0xfa, 0x64, 0xfe, 0x05, 0x3a, 0x25, 0xcc, 0x87, 0xf4, 0x03,
0x38, 0xca, 0xf2, 0xe8, 0x4f, 0xb9, 0x4f, 0x79, 0x55, 0x43, 0xf3, 0x46,
0xfd, 0xbc, 0xd2, 0x95, 0xb8, 0x99, 0xfc, 0xb8, 0xb3, 0xa5, 0x04, 0xa1,
0x02, 0x81, 0xc0, 0x47, 0xc6, 0x9c, 0x18, 0x54, 0xe5, 0xbb, 0xf9, 0xf4,
0x38, 0xd2, 0xc0, 0xd1, 0x1a, 0xcc, 0xdb, 0x06, 0x87, 0x75, 0x1f, 0x13,
0xa2, 0x7f, 0x8b, 0x45, 0x54, 0xcb, 0x43, 0xf8, 0xbb, 0x94, 0xd6, 0x2e,
0x56, 0x5c, 0x69, 0x6d, 0x83, 0xb5, 0x45, 0x46, 0x68, 0x5c, 0x76, 0x1e,
0x6c, 0x0c, 0x53, 0x59, 0xcc, 0x19, 0xc7, 0x81, 0x62, 0x66, 0x92, 0x02,
0x8f, 0xa6, 0xdb, 0x50, 0x1c, 0x67, 0xfc, 0x82, 0x56, 0x2b, 0x4b, 0x1f,
0x97, 0x87, 0xc4, 0x7d, 0x20, 0xda, 0xd3, 0x3f, 0x28, 0xf9, 0x55, 0xfe,
0x84, 0x50, 0xc5, 0x3b, 0xd4, 0xaf, 0xf5, 0x3d, 0x43, 0xce, 0xdc, 0x55,
0x11, 0x87, 0xdb, 0x72, 0x66, 0xcc, 0x83, 0xc4, 0x8b, 0x20, 0xae, 0x59,
0x4d, 0xeb, 0xac, 0xb5, 0x4a, 0xec, 0x66, 0x09, 0x37, 0x55, 0x14, 0x21,
0x57, 0xff, 0x0a, 0xac, 0xda, 0xb1, 0xae, 0x31, 0xab, 0x41, 0x30, 0x65,
0x02, 0x83, 0xd1, 0xdb, 0x65, 0xb7, 0x52, 0xa7, 0x21, 0x9f, 0x1f, 0x8f,
0x69, 0x23, 0x3b, 0xb8, 0xf9, 0x6d, 0xe7, 0xc1, 0x53, 0x9f, 0x8f, 0x67,
0xfc, 0x6e, 0x20, 0x18, 0x31, 0x89, 0xe7, 0xbb, 0xd4, 0xc1, 0x03, 0x67,
0xd6, 0xa5, 0x76, 0xc9, 0xea, 0x97, 0x93, 0x02, 0xca, 0x44, 0x52, 0x55,
0x0f, 0xed, 0x55, 0xb5, 0x49, 0xd6, 0x94, 0x59, 0xee, 0xcc, 0x1b, 0x5a,
0x00, 0x3d, 0xcd};
static const unsigned char kTestRsaPublicKey1_3072[] = {
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5, 0x62, 0x07,
0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78, 0x76, 0xbe,
0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f, 0xe9, 0x61,
0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca, 0xe4, 0xdd,
0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b, 0x83, 0xbe,
0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46, 0xc2, 0x65,
0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01, 0xb5, 0x11,
0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c, 0xb4, 0x7a,
0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14, 0xf1, 0x22,
0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd, 0xa0, 0x0a,
0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6, 0x0e, 0x85,
0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde, 0xf2, 0x59,
0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31, 0xa0, 0xee,
0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a, 0xae, 0xb2,
0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90, 0x97, 0x2c,
0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49, 0x94, 0x53,
0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f, 0x07, 0x53,
0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda, 0xea, 0x1e,
0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17, 0xe8, 0xc9,
0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30, 0xb7, 0xf5,
0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf, 0x39, 0xf3,
0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16, 0x9c, 0xee,
0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42, 0x72, 0x85,
0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9, 0xa6, 0x82,
0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4, 0x3a, 0x3b,
0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a, 0xe9, 0x4c,
0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72, 0x71, 0x04,
0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde, 0x8f, 0xe1,
0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04, 0xb5, 0xd7,
0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b, 0x38, 0xff,
0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33, 0x61, 0x53,
0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67, 0xd5, 0xf0,
0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02, 0x03, 0x01,
0x00, 0x01};
static const unsigned char kTestRsaPrivateKey2_2048[] = {
0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4,
0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f,
0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e,
0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa,
0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7,
0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b,
0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68,
0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8,
0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2,
0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73,
0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e,
0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd,
0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88,
0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88,
0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8,
0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2,
0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e,
0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f,
0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29,
0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e,
0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f,
0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x5e, 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05, 0x45, 0x0f,
0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, 0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8,
0xac, 0x97, 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7, 0x3b, 0x5c,
0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, 0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a,
0x7e, 0xdc, 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c, 0x5e, 0x79,
0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, 0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e,
0x79, 0xf9, 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3, 0x68, 0x7b,
0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, 0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1,
0x71, 0xe7, 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75, 0xbe, 0x09,
0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, 0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1,
0xe8, 0x88, 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78, 0x25, 0x0b,
0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, 0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0,
0x37, 0x14, 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47, 0xde, 0x00,
0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, 0x68, 0x71, 0x17, 0x66, 0x12, 0x1a,
0x87, 0x27, 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d, 0x6f, 0x35,
0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, 0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7,
0xb6, 0x64, 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53, 0x1f, 0x51,
0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, 0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96,
0x07, 0x5f, 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29, 0xf6, 0x06,
0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, 0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e,
0xc9, 0x21, 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81, 0xb2, 0x51,
0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c,
0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, 0x78, 0xcc,
0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85,
0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, 0x84, 0x68,
0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86,
0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, 0x3a, 0x83,
0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7,
0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, 0x18, 0x6c,
0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a,
0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, 0x3c, 0x2d,
0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, 0x48, 0x16,
0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, 0x15, 0x43,
0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49,
0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, 0xcb, 0x43,
0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17,
0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, 0xa7, 0x5b,
0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d,
0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, 0xc1, 0xee,
0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d,
0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, 0x0d, 0x6c,
0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67,
0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, 0x53, 0xa8,
0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83,
0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, 0x0a, 0x2d,
0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b,
0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, 0xeb, 0xdb,
0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25,
0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, 0x37, 0x43,
0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d,
0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, 0xf9, 0xca,
0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71,
0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, 0xb1, 0x31,
0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, 0x40, 0x19,
0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, 0xcc, 0x3b,
0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c,
0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, 0x6a, 0xab,
0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec,
0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, 0x5f, 0xdf,
0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22,
0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, 0x77, 0xe6,
0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a,
0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, 0xd9, 0xbe,
0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96,
0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, 0xac, 0x21,
0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6,
0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, 0x28, 0x66,
0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9,
0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, 0x70, 0xcf,
0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6,
0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, 0x50, 0xcb,
0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7,
0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, 0xa2, 0x0d,
0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae,
0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, 0x72, 0x2c,
0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0,
0xdb, 0x03};
static const unsigned char kTestRsaPublicKey2_2048[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36,
0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94,
0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0,
0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f,
0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4,
0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9,
0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10,
0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a,
0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8,
0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a,
0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54,
0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82,
0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed,
0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66,
0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18,
0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2,
0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21,
0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce,
0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07,
0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97,
0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39,
0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a,
0x05, 0x02, 0x03, 0x01, 0x00, 0x01};
static const unsigned char kTestRsaPrivateKey3_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40,
0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7,
0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44,
0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91,
0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08,
0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10,
0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d,
0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94,
0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d,
0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68,
0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55,
0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8,
0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7,
0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35,
0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06,
0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21,
0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae,
0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c,
0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84,
0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87,
0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b,
0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x43, 0x8f, 0x19, 0x83, 0xb1, 0x27, 0x4e, 0xee, 0x98, 0xba, 0xcb,
0x54, 0xa0, 0x77, 0x11, 0x6d, 0xd4, 0x25, 0x31, 0x8c, 0xb0, 0x01, 0xcf,
0xe6, 0x80, 0x83, 0x14, 0x40, 0x67, 0x39, 0x33, 0x67, 0x03, 0x1e, 0xa0,
0x8b, 0xd1, 0x1d, 0xfd, 0x80, 0xa4, 0xb9, 0xe7, 0x57, 0x5e, 0xc8, 0x8e,
0x79, 0x71, 0xd5, 0x6b, 0x09, 0xe9, 0x2b, 0x41, 0xa0, 0x33, 0x64, 0xc9,
0x66, 0x33, 0xa1, 0xb1, 0x55, 0x07, 0x55, 0x98, 0x53, 0x10, 0xe6, 0xc0,
0x39, 0x6d, 0x61, 0xd9, 0xe8, 0x16, 0x52, 0x28, 0xe4, 0x2b, 0xda, 0x27,
0x01, 0xaf, 0x21, 0x4a, 0xe8, 0x55, 0x1d, 0x0b, 0xd1, 0x1c, 0xdc, 0xfd,
0xb3, 0x0b, 0xa6, 0x5c, 0xcc, 0x6e, 0x77, 0xb8, 0xe0, 0xd1, 0x4e, 0x0a,
0xd7, 0x7a, 0x5e, 0x18, 0xc3, 0xfb, 0xe9, 0xa1, 0x9c, 0xc3, 0x9c, 0xd4,
0x4a, 0x7e, 0x70, 0x72, 0x11, 0x18, 0x24, 0x56, 0x24, 0xdf, 0xf8, 0xba,
0xac, 0x5b, 0x54, 0xd3, 0xc4, 0x65, 0x69, 0xc8, 0x79, 0x94, 0x16, 0x88,
0x9a, 0x68, 0x1c, 0xbc, 0xd4, 0xca, 0xec, 0x5e, 0x07, 0x4a, 0xc9, 0x54,
0x7a, 0x4b, 0xdb, 0x19, 0x88, 0xf6, 0xbe, 0x50, 0x9d, 0x9e, 0x9d, 0x88,
0x5b, 0x4a, 0x23, 0x86, 0x2b, 0xa9, 0xa6, 0x6c, 0x70, 0x7d, 0xe1, 0x11,
0xba, 0xbf, 0x03, 0x2e, 0xf1, 0x46, 0x7e, 0x1b, 0xed, 0x06, 0x11, 0x57,
0xad, 0x4a, 0xcb, 0xe5, 0xb1, 0x11, 0x05, 0x0a, 0x30, 0xb1, 0x73, 0x79,
0xcd, 0x7a, 0x04, 0xcc, 0x70, 0xe9, 0x95, 0xe4, 0x27, 0xc2, 0xd5, 0x2d,
0x92, 0x44, 0xdf, 0xb4, 0x94, 0xa8, 0x73, 0xa1, 0x4a, 0xc3, 0xcc, 0xc4,
0x0e, 0x8d, 0xa1, 0x6a, 0xc2, 0xd8, 0x03, 0x7f, 0xfa, 0xa7, 0x76, 0x0d,
0xad, 0x87, 0x88, 0xa0, 0x77, 0xaf, 0x3b, 0x23, 0xd1, 0x66, 0x0b, 0x31,
0x2b, 0xaf, 0xef, 0xd5, 0x41, 0x02, 0x81, 0x81, 0x00, 0xdb, 0xc1, 0xe7,
0xdd, 0xba, 0x3c, 0x1f, 0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47,
0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2, 0x25, 0x64, 0x0a, 0x02,
0xbc, 0x7d, 0x7f, 0x50, 0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d,
0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9, 0x53, 0x0b, 0x5c, 0xa2,
0x71, 0x14, 0x02, 0xfd, 0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e,
0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8, 0x3d, 0xcf, 0x8c, 0x89,
0x65, 0x6c, 0x35, 0x19, 0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d,
0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43, 0xe5, 0xdd, 0x39, 0x3a,
0x78, 0x8f, 0x07, 0xb8, 0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02,
0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01, 0x90, 0x81, 0x29, 0x94,
0xad, 0x77, 0xeb, 0x86, 0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88,
0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32, 0x12, 0x5e, 0xdf, 0x28,
0x0c, 0x96, 0x0d, 0xa8, 0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb,
0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2, 0xf3, 0xf2, 0x95, 0xff,
0xd8, 0x33, 0x3f, 0x8c, 0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66,
0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1, 0xbc, 0xbe, 0x44, 0x09,
0xb4, 0xfe, 0x95, 0x06, 0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0,
0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8, 0xcc, 0xeb, 0x10, 0x4d,
0xa7, 0xd0, 0x4b, 0x46, 0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3,
0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b, 0x7b, 0xae, 0x6d, 0x08,
0x9f, 0x0c, 0x2a, 0xe1, 0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d,
0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80, 0x61, 0x73, 0x3d, 0x64,
0xff, 0xdf, 0x05, 0x8d, 0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53,
0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f, 0xae, 0x2b, 0x1a, 0x47,
0x87, 0xc7, 0x5b, 0x78, 0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c,
0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d, 0x40, 0xfe, 0x95, 0x32,
0x5b, 0xd3, 0x6f, 0x90, 0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7,
0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78, 0xad, 0x7e, 0xfe, 0xb6,
0xb1, 0x23, 0x63, 0x01, 0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1,
0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec, 0xcb, 0x0b, 0x43, 0xb8,
0x8e, 0x84, 0xb8, 0x09, 0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95,
0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f, 0x91, 0x17, 0x65, 0x4c,
0xff, 0x6e, 0xbc, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8,
0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7, 0xce, 0x72, 0x02, 0x38,
0xf2, 0x0f, 0x9c, 0x27, 0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19,
0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e, 0xe6, 0xb8, 0xfc, 0x07,
0x3c, 0xd1, 0x1b, 0x16, 0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd,
0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd, 0xf9, 0xdb, 0x4e, 0x48,
0x52, 0xd8, 0xe6, 0x4b, 0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3,
0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71, 0xd3, 0xcd, 0x6b, 0x8f,
0x79, 0x22, 0x83, 0x02, 0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8,
0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e, 0xa4, 0x89, 0xdc, 0xbf,
0xf9, 0x0d, 0x32, 0xc8, 0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e,
0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x35, 0x1b, 0x19,
0x75, 0x3f, 0x61, 0xf2, 0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a,
0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d, 0x1f, 0x86, 0x58, 0x4f,
0xd8, 0xee, 0xfa, 0x76, 0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62,
0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83, 0x07, 0xac, 0x8c, 0xa3,
0x7e, 0x18, 0xc0, 0x1c, 0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3,
0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43, 0x04, 0x36, 0xc8, 0x19,
0xbe, 0xdc, 0xa6, 0xe5, 0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3,
0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31, 0x44, 0x74, 0xfa, 0x7c,
0xb4, 0xea, 0xfc, 0x15, 0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b,
0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b, 0x21, 0xdc, 0x86, 0x17,
0x6e, 0xc8, 0xee, 0x24};
static const unsigned char kTestRsaPublicKey3_2048[] = {
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7,
0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89,
0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41,
0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44, 0xb3, 0x08, 0x05,
0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8,
0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10,
0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1,
0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b,
0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94, 0x40, 0x70, 0xac,
0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95,
0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68, 0x16, 0x31, 0xaa,
0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4,
0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf,
0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b,
0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66,
0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06, 0xd9, 0x84, 0x51,
0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd,
0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee,
0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89,
0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a,
0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1,
0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69,
0x6d, 0x02, 0x03, 0x01, 0x00, 0x01};
unsigned char kTestRsaPrivateKey2CarmichaelTotient_2048[] = {
0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, 0xb4,
0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f,
0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, 0x7e,
0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa,
0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, 0xf7,
0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b,
0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, 0x68,
0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8,
0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, 0xc2,
0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73,
0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, 0x4e,
0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd,
0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, 0x88,
0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88,
0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, 0xc8,
0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2,
0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, 0x2e,
0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f,
0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, 0x29,
0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e,
0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, 0x5f,
0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8, 0x2f, 0xef,
0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4, 0xe9, 0x65,
0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33, 0x8c, 0x30,
0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde, 0xb1, 0x13,
0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc, 0x6c, 0xdf,
0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4, 0x67, 0x75,
0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b, 0x6a, 0xdc,
0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40, 0xb2, 0xb4,
0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a, 0xeb, 0x90,
0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f, 0xa9, 0x47,
0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f, 0xfc, 0x19,
0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff, 0x45, 0xa2,
0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c, 0x37, 0x99,
0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8, 0xfa, 0x2d,
0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71, 0xbd, 0xff,
0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85, 0xfd, 0xd0,
0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a, 0x3f, 0xbf,
0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e, 0x51, 0x9f,
0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5, 0x97, 0x5f,
0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c, 0x94, 0x4b,
0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf, 0xa2, 0x9a,
0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c,
0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, 0x78, 0xcc,
0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85,
0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, 0x84, 0x68,
0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86,
0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, 0x3a, 0x83,
0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7,
0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, 0x18, 0x6c,
0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a,
0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, 0x3c, 0x2d,
0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, 0x48, 0x16,
0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, 0x15, 0x43,
0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49,
0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, 0xcb, 0x43,
0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17,
0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, 0xa7, 0x5b,
0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d,
0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, 0xc1, 0xee,
0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d,
0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, 0x0d, 0x6c,
0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67,
0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, 0x53, 0xa8,
0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83,
0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, 0x0a, 0x2d,
0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b,
0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, 0xeb, 0xdb,
0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25,
0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, 0x37, 0x43,
0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d,
0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, 0xf9, 0xca,
0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71,
0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, 0xb1, 0x31,
0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, 0x40, 0x19,
0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, 0xcc, 0x3b,
0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c,
0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, 0x6a, 0xab,
0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec,
0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, 0x5f, 0xdf,
0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22,
0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, 0x77, 0xe6,
0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a,
0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, 0xd9, 0xbe,
0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96,
0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, 0xac, 0x21,
0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6,
0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, 0x28, 0x66,
0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9,
0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, 0x70, 0xcf,
0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6,
0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, 0x50, 0xcb,
0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7,
0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, 0xa2, 0x0d,
0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae,
0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, 0x72, 0x2c,
0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0,
0xdb, 0x03};
static const unsigned char kTestRsaPrivateKey3CarmichaelTotient_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51, 0x99, 0xea, 0x40,
0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d, 0x0e, 0x83, 0xa7,
0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c, 0x61, 0x36, 0x44,
0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32, 0x3c, 0x9a, 0x91,
0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7, 0xc2, 0x75, 0x08,
0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3, 0x9d, 0x74, 0x10,
0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7, 0x15, 0xa3, 0x1d,
0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc, 0x95, 0x47, 0x94,
0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93, 0x36, 0x2b, 0x6d,
0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99, 0xee, 0x03, 0x68,
0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc, 0xf6, 0x20, 0x55,
0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6, 0xde, 0x6c, 0xe8,
0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a, 0x4c, 0xd5, 0xe7,
0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44, 0xab, 0xe0, 0x35,
0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec, 0x24, 0x05, 0x06,
0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea, 0x70, 0x2a, 0x21,
0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e, 0x29, 0x3d, 0xae,
0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94, 0x1d, 0x87, 0x3c,
0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8, 0x62, 0x6a, 0x84,
0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16, 0xa6, 0x8f, 0x87,
0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd, 0x49, 0x98, 0x7b,
0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x1a, 0x1a, 0xe3, 0xb4, 0x2d, 0x9b, 0xd0, 0x1d, 0xc4, 0x54, 0x50,
0xc4, 0x98, 0xeb, 0xae, 0xf4, 0xab, 0x95, 0x72, 0x78, 0x60, 0xbe, 0x2e,
0xfc, 0x88, 0x59, 0xc3, 0xff, 0x5f, 0xb4, 0x01, 0xfd, 0x2c, 0x06, 0x52,
0xfa, 0xa4, 0x5b, 0xfc, 0x29, 0xdf, 0x82, 0x67, 0x14, 0x52, 0x39, 0x67,
0xd5, 0x31, 0xc1, 0x41, 0x02, 0x76, 0x03, 0x5d, 0xd2, 0xc5, 0x74, 0x2c,
0x24, 0x26, 0xfe, 0xed, 0x46, 0x65, 0x97, 0x22, 0x74, 0xe7, 0xff, 0x63,
0x35, 0x3b, 0xd8, 0xad, 0x88, 0x2c, 0xe2, 0x50, 0xf3, 0x76, 0x14, 0xbe,
0x3a, 0x37, 0x1b, 0xf0, 0x21, 0x91, 0x8e, 0xdd, 0x43, 0xed, 0xb7, 0xab,
0xcd, 0xfb, 0x8a, 0x31, 0xa6, 0x26, 0xb4, 0xd5, 0x4b, 0x2c, 0x80, 0x7f,
0xfc, 0x39, 0x24, 0x33, 0x7d, 0x6d, 0xf3, 0x1c, 0x06, 0xdd, 0x21, 0x53,
0x70, 0x78, 0xe4, 0x07, 0x60, 0x2a, 0x3f, 0xb8, 0xd0, 0x47, 0xf6, 0x0e,
0xbd, 0xde, 0x31, 0xf3, 0x66, 0xfe, 0x6e, 0x4b, 0x50, 0x75, 0x0b, 0x49,
0x3a, 0x96, 0xeb, 0x63, 0xb9, 0x24, 0xbb, 0xfc, 0xcd, 0xf5, 0x49, 0x12,
0xa9, 0x6d, 0x39, 0xd4, 0x18, 0x15, 0x14, 0x50, 0x82, 0xa9, 0x75, 0xeb,
0x9f, 0x1a, 0xaa, 0x52, 0x1d, 0x0d, 0x55, 0x74, 0x30, 0x45, 0x3b, 0xd2,
0xd3, 0xe1, 0xdb, 0x8d, 0xec, 0x38, 0x2b, 0xb0, 0xdd, 0xda, 0x10, 0xe3,
0x40, 0x87, 0x27, 0xbe, 0x0b, 0xbf, 0x08, 0x9e, 0x25, 0x95, 0x14, 0xf4,
0xd7, 0xfe, 0x8c, 0x4f, 0x23, 0xfd, 0x1b, 0xad, 0x83, 0x6b, 0x05, 0x3a,
0x83, 0xfa, 0x65, 0x1e, 0x65, 0x12, 0xe3, 0x9f, 0xea, 0x52, 0xd7, 0xed,
0x01, 0x7d, 0xc5, 0xf1, 0x96, 0x2d, 0xf5, 0x4a, 0xa3, 0xcb, 0x69, 0x6c,
0x9a, 0x48, 0xe9, 0xf5, 0x01, 0xef, 0x1d, 0x2e, 0x90, 0x64, 0x6c, 0x0b,
0x79, 0xe0, 0xeb, 0x64, 0x29, 0x02, 0x81, 0x81, 0x00, 0xdb, 0xc1, 0xe7,
0xdd, 0xba, 0x3c, 0x1f, 0x9c, 0x64, 0xca, 0xa0, 0x63, 0xdb, 0xd2, 0x47,
0x5c, 0x6e, 0x8a, 0xa3, 0x16, 0xd5, 0xda, 0xc2, 0x25, 0x64, 0x0a, 0x02,
0xbc, 0x7d, 0x7f, 0x50, 0xab, 0xe0, 0x66, 0x03, 0x53, 0x7d, 0x77, 0x6d,
0x6c, 0x61, 0x58, 0x09, 0x73, 0xcd, 0x18, 0xe9, 0x53, 0x0b, 0x5c, 0xa2,
0x71, 0x14, 0x02, 0xfd, 0x55, 0xda, 0xe9, 0x77, 0x24, 0x7c, 0x2a, 0x4e,
0xb9, 0xd9, 0x5d, 0x58, 0xf6, 0x26, 0xd0, 0xd8, 0x3d, 0xcf, 0x8c, 0x89,
0x65, 0x6c, 0x35, 0x19, 0xb6, 0x63, 0xff, 0xa0, 0x71, 0x49, 0xcd, 0x6d,
0x5b, 0x3d, 0x8f, 0xea, 0x6f, 0xa9, 0xba, 0x43, 0xe5, 0xdd, 0x39, 0x3a,
0x78, 0x8f, 0x07, 0xb8, 0xab, 0x58, 0x07, 0xb7, 0xd2, 0xf8, 0x07, 0x02,
0x9b, 0x79, 0x26, 0x32, 0x22, 0x38, 0x91, 0x01, 0x90, 0x81, 0x29, 0x94,
0xad, 0x77, 0xeb, 0x86, 0xb9, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x29, 0x88,
0xbd, 0x96, 0x31, 0x33, 0x7b, 0x77, 0x5d, 0x32, 0x12, 0x5e, 0xdf, 0x28,
0x0c, 0x96, 0x0d, 0xa8, 0x22, 0xdf, 0xd3, 0x35, 0xd7, 0xb0, 0x41, 0xcb,
0xe7, 0x94, 0x8a, 0xa4, 0xed, 0xd2, 0xfb, 0xd2, 0xf3, 0xf2, 0x95, 0xff,
0xd8, 0x33, 0x3f, 0x8c, 0xd7, 0x65, 0xe4, 0x0c, 0xcc, 0xfe, 0x32, 0x66,
0xfa, 0x50, 0xe2, 0xcf, 0xf0, 0xbe, 0x05, 0xb1, 0xbc, 0xbe, 0x44, 0x09,
0xb4, 0xfe, 0x95, 0x06, 0x18, 0xd7, 0x59, 0xc6, 0xef, 0x2d, 0x22, 0xa0,
0x73, 0x5e, 0x77, 0xdf, 0x8d, 0x09, 0x2c, 0xb8, 0xcc, 0xeb, 0x10, 0x4d,
0xa7, 0xd0, 0x4b, 0x46, 0xba, 0x7d, 0x8b, 0x6a, 0x55, 0x47, 0x55, 0xd3,
0xd7, 0xb1, 0x88, 0xfd, 0x27, 0x3e, 0xf9, 0x5b, 0x7b, 0xae, 0x6d, 0x08,
0x9f, 0x0c, 0x2a, 0xe1, 0xdd, 0xb9, 0xe3, 0x55, 0x13, 0x55, 0xa3, 0x6d,
0x06, 0xbb, 0xe0, 0x1e, 0x55, 0x02, 0x81, 0x80, 0x61, 0x73, 0x3d, 0x64,
0xff, 0xdf, 0x05, 0x8d, 0x8e, 0xcc, 0xa4, 0x0f, 0x64, 0x3d, 0x7d, 0x53,
0xa9, 0xd9, 0x64, 0xb5, 0x0d, 0xa4, 0x72, 0x8f, 0xae, 0x2b, 0x1a, 0x47,
0x87, 0xc7, 0x5b, 0x78, 0xbc, 0x8b, 0xc0, 0x51, 0xd7, 0xc3, 0x8c, 0x0c,
0x91, 0xa6, 0x3e, 0x9a, 0xd1, 0x8a, 0x88, 0x7d, 0x40, 0xfe, 0x95, 0x32,
0x5b, 0xd3, 0x6f, 0x90, 0x11, 0x01, 0x92, 0xc9, 0xe5, 0x1d, 0xc5, 0xc7,
0x78, 0x72, 0x82, 0xae, 0xb5, 0x4b, 0xcb, 0x78, 0xad, 0x7e, 0xfe, 0xb6,
0xb1, 0x23, 0x63, 0x01, 0x94, 0x9a, 0x99, 0x05, 0x63, 0xda, 0xea, 0xf1,
0x98, 0xfd, 0x26, 0xd2, 0xd9, 0x8b, 0x35, 0xec, 0xcb, 0x0b, 0x43, 0xb8,
0x8e, 0x84, 0xb8, 0x09, 0x93, 0x81, 0xe8, 0xac, 0x6f, 0x3c, 0x7c, 0x95,
0x81, 0x45, 0xc4, 0xd9, 0x94, 0x08, 0x09, 0x8f, 0x91, 0x17, 0x65, 0x4c,
0xff, 0x6e, 0xbc, 0x51, 0x02, 0x81, 0x81, 0x00, 0xc1, 0x0d, 0x9d, 0xd8,
0xbd, 0xaf, 0x56, 0xe0, 0xe3, 0x1f, 0x85, 0xd7, 0xce, 0x72, 0x02, 0x38,
0xf2, 0x0f, 0x9c, 0x27, 0x9e, 0xc4, 0x1d, 0x60, 0x00, 0x8d, 0x02, 0x19,
0xe5, 0xdf, 0xdb, 0x8e, 0xc5, 0xfb, 0x61, 0x8e, 0xe6, 0xb8, 0xfc, 0x07,
0x3c, 0xd1, 0x1b, 0x16, 0x7c, 0x83, 0x3c, 0x37, 0xf5, 0x26, 0xb2, 0xbd,
0x22, 0xf2, 0x4d, 0x19, 0x33, 0x11, 0xc5, 0xdd, 0xf9, 0xdb, 0x4e, 0x48,
0x52, 0xd8, 0xe6, 0x4b, 0x15, 0x90, 0x68, 0xbe, 0xca, 0xc1, 0x7c, 0xd3,
0x51, 0x6b, 0x45, 0x46, 0x54, 0x11, 0x1a, 0x71, 0xd3, 0xcd, 0x6b, 0x8f,
0x79, 0x22, 0x83, 0x02, 0x08, 0x4f, 0xba, 0x6a, 0x98, 0xed, 0x32, 0xd8,
0xb4, 0x5b, 0x51, 0x88, 0x53, 0xec, 0x2c, 0x7e, 0xa4, 0x89, 0xdc, 0xbf,
0xf9, 0x0d, 0x32, 0xc8, 0xc3, 0xec, 0x6d, 0x2e, 0xf1, 0xbc, 0x70, 0x4e,
0xf6, 0x9e, 0xbc, 0x31, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x35, 0x1b, 0x19,
0x75, 0x3f, 0x61, 0xf2, 0x55, 0x03, 0xce, 0x25, 0xa9, 0xdf, 0x0c, 0x0a,
0x3b, 0x47, 0x42, 0xdc, 0x38, 0x4b, 0x13, 0x4d, 0x1f, 0x86, 0x58, 0x4f,
0xd8, 0xee, 0xfa, 0x76, 0x15, 0xfb, 0x6e, 0x55, 0x31, 0xf2, 0xd2, 0x62,
0x32, 0xa5, 0xc4, 0x23, 0x5e, 0x08, 0xa9, 0x83, 0x07, 0xac, 0x8c, 0xa3,
0x7e, 0x18, 0xc0, 0x1c, 0x57, 0x63, 0x8d, 0x05, 0x17, 0x47, 0x1b, 0xd3,
0x74, 0x73, 0x20, 0x04, 0xfb, 0xc8, 0x1a, 0x43, 0x04, 0x36, 0xc8, 0x19,
0xbe, 0xdc, 0xa6, 0xe5, 0x0f, 0x25, 0x62, 0x24, 0x96, 0x92, 0xb6, 0xb3,
0x97, 0xad, 0x57, 0x9a, 0x90, 0x37, 0x4e, 0x31, 0x44, 0x74, 0xfa, 0x7c,
0xb4, 0xea, 0xfc, 0x15, 0xa7, 0xb0, 0x51, 0xcc, 0xee, 0x1e, 0xed, 0x5b,
0x98, 0x18, 0x0e, 0x65, 0xb6, 0x4b, 0x69, 0x0b, 0x21, 0xdc, 0x86, 0x17,
0x6e, 0xc8, 0xee, 0x24};
static const unsigned char kTestRsaPrivateKey4CarmichaelTotient_2048[] = {
0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
0xb5, 0xed, 0x90, 0x77, 0xfe, 0xb4, 0xac, 0x2c, 0x7a, 0x53, 0x0a, 0xe0,
0x94, 0x87, 0xfe, 0xc7, 0xc4, 0xa8, 0x3f, 0x09, 0x5b, 0xdd, 0xa7, 0x6e,
0x70, 0xc9, 0xf0, 0xef, 0x9e, 0x47, 0xad, 0xcf, 0xbe, 0xdc, 0x9b, 0x89,
0xc7, 0xbd, 0xb5, 0x2f, 0xa9, 0x43, 0x97, 0xd5, 0x5b, 0xae, 0x73, 0x46,
0xa9, 0x10, 0x47, 0x67, 0x35, 0xa0, 0x6e, 0xfc, 0xfb, 0x45, 0xf8, 0x85,
0xb0, 0xf1, 0xd3, 0x67, 0x84, 0x91, 0x03, 0x1b, 0x90, 0xb1, 0x18, 0x12,
0xa4, 0x15, 0x7a, 0x65, 0xfa, 0x74, 0x4f, 0x73, 0x34, 0x70, 0x9b, 0x64,
0x91, 0x1f, 0x89, 0x4f, 0x40, 0x2d, 0x37, 0x2f, 0xbf, 0x2b, 0x1e, 0x54,
0x95, 0x7c, 0x16, 0x14, 0xd3, 0x60, 0xf4, 0xd7, 0x86, 0xf7, 0x0c, 0x2c,
0xbb, 0x3f, 0xe7, 0x49, 0xdf, 0x74, 0x8b, 0xc9, 0x8f, 0x7c, 0x22, 0x23,
0xd9, 0xbd, 0x2a, 0x57, 0xfe, 0xfb, 0x7a, 0x77, 0x91, 0xce, 0xa9, 0xd8,
0xa7, 0xfb, 0xf5, 0xe7, 0x39, 0xbe, 0xfb, 0xf5, 0x47, 0x57, 0x48, 0xe7,
0x71, 0x37, 0xda, 0x53, 0xe7, 0x89, 0xd3, 0x37, 0x31, 0x98, 0xba, 0xd8,
0xd0, 0xd9, 0x74, 0xb2, 0xda, 0x06, 0x99, 0x3b, 0x97, 0x87, 0xc4, 0x22,
0x3c, 0xf7, 0xa3, 0x13, 0x84, 0x49, 0x27, 0x74, 0x50, 0x03, 0x51, 0xea,
0xc9, 0x57, 0xeb, 0x16, 0xa9, 0x7a, 0xea, 0x3c, 0x26, 0xda, 0xcb, 0xc6,
0x86, 0x85, 0xfc, 0xd0, 0x73, 0x26, 0xce, 0xe8, 0xd9, 0x92, 0x09, 0xaf,
0x68, 0x0c, 0x01, 0x8d, 0x95, 0xfd, 0x8d, 0x01, 0xde, 0x26, 0x0f, 0x25,
0xb9, 0xd5, 0x80, 0x99, 0x62, 0xb1, 0x71, 0xcd, 0xa1, 0x5f, 0x52, 0xab,
0x97, 0x97, 0x3f, 0xa7, 0x93, 0x40, 0x89, 0x4f, 0xbc, 0x7d, 0x99, 0x7a,
0x7e, 0x35, 0xa5, 0xfc, 0x74, 0xfb, 0xe4, 0x5a, 0x0b, 0xed, 0xf0, 0xef,
0x65, 0xed, 0x22, 0x95, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
0x00, 0x35, 0x4a, 0x9d, 0x36, 0xa1, 0x3c, 0x50, 0x71, 0x08, 0xf6, 0x19,
0x6a, 0x16, 0xe8, 0x4d, 0x68, 0x3c, 0x41, 0xa2, 0x91, 0x7d, 0xc1, 0x0c,
0xa2, 0x2b, 0xd4, 0xe3, 0xc8, 0x75, 0x3f, 0x7e, 0xf9, 0x2b, 0x6a, 0x18,
0xff, 0xbf, 0xac, 0x61, 0x0e, 0x50, 0x91, 0x55, 0xc1, 0x30, 0x85, 0x86,
0x0c, 0x0d, 0x4b, 0x10, 0xf7, 0x79, 0x3c, 0x81, 0x36, 0x86, 0xee, 0x84,
0xb1, 0xb8, 0xd6, 0xe5, 0xbb, 0xdd, 0x97, 0xd2, 0xe6, 0xb8, 0xb8, 0x3f,
0x9a, 0x7a, 0x49, 0x36, 0x5c, 0xf8, 0x04, 0x29, 0x1f, 0xd0, 0x9d, 0x29,
0xcf, 0xc8, 0x39, 0x0a, 0x32, 0x56, 0x54, 0xc8, 0x65, 0x2a, 0xa5, 0x19,
0x51, 0xe2, 0xa6, 0x02, 0x1b, 0xe0, 0x9d, 0x76, 0xab, 0x49, 0xc4, 0x45,
0x63, 0x37, 0x08, 0xad, 0x9a, 0x34, 0xa4, 0x41, 0xac, 0x6d, 0xe5, 0x09,
0x65, 0x22, 0x0b, 0xa9, 0x03, 0x34, 0xd4, 0x7a, 0x97, 0x5c, 0x5d, 0xdc,
0xa3, 0xae, 0xfd, 0xe8, 0xd6, 0xe8, 0xf8, 0x52, 0x44, 0x9c, 0xf6, 0x00,
0xe3, 0x8e, 0xad, 0xee, 0xa3, 0x82, 0x8a, 0x85, 0x07, 0x8b, 0x46, 0x12,
0x0f, 0xa1, 0xca, 0x07, 0x0d, 0x50, 0x02, 0x96, 0x71, 0x2f, 0x1b, 0x2b,
0x59, 0x17, 0x95, 0xec, 0x90, 0xa6, 0xb9, 0x05, 0xff, 0xa2, 0x25, 0x75,
0xc5, 0x57, 0x42, 0x37, 0x12, 0xa0, 0xb6, 0x09, 0xa1, 0xe0, 0xef, 0x70,
0x85, 0xa7, 0x39, 0x47, 0xb1, 0x72, 0x78, 0x0d, 0xf4, 0x4a, 0xa7, 0xca,
0x92, 0x68, 0x2c, 0xe8, 0x53, 0x54, 0x52, 0xe2, 0x21, 0xce, 0xaf, 0x7e,
0x56, 0x05, 0x74, 0xe1, 0xb7, 0x18, 0xed, 0x7f, 0x83, 0xf6, 0x7d, 0x99,
0x33, 0xf9, 0x60, 0x24, 0xae, 0x59, 0x09, 0xc0, 0x95, 0x90, 0x5a, 0x19,
0x25, 0xb0, 0x79, 0xfd, 0x0b, 0x2c, 0x73, 0x85, 0xc5, 0xa0, 0xe5, 0x7b,
0x3a, 0x47, 0xce, 0x8d, 0x03, 0x02, 0x81, 0x81, 0x00, 0xe2, 0xd7, 0xeb,
0x7f, 0xc1, 0x1f, 0x13, 0x8f, 0x52, 0x49, 0xa2, 0x83, 0x22, 0xb7, 0x3d,
0x93, 0xfe, 0xe7, 0x20, 0x03, 0xf6, 0x6c, 0xd8, 0x95, 0x25, 0xef, 0x5f,
0xa4, 0xd4, 0x8f, 0xb1, 0x38, 0x39, 0x7c, 0xe0, 0xdd, 0xff, 0x56, 0xa7,
0xdf, 0x59, 0xe1, 0x26, 0x36, 0x72, 0x78, 0xdf, 0xd4, 0x19, 0xc0, 0x37,
0x58, 0x75, 0x85, 0xdd, 0x8b, 0x2e, 0x73, 0xfa, 0xf5, 0x65, 0x93, 0xc7,
0x36, 0x3d, 0xb7, 0x8e, 0xa9, 0x5e, 0x41, 0x71, 0x55, 0x1d, 0x22, 0x83,
0x13, 0x91, 0x76, 0xa4, 0x80, 0xa0, 0xac, 0xf6, 0xd5, 0xbb, 0x6a, 0xf3,
0x47, 0x01, 0x81, 0x3d, 0x34, 0xd6, 0x32, 0x49, 0xb2, 0xc9, 0xa7, 0xb3,
0x93, 0x64, 0x47, 0x6d, 0x30, 0x8b, 0x23, 0xbd, 0xf0, 0xe8, 0x3c, 0xb5,
0x4e, 0x33, 0x74, 0x4b, 0x60, 0x38, 0x25, 0x89, 0xaf, 0xf8, 0x86, 0x53,
0x73, 0x62, 0x74, 0x35, 0xb7, 0x02, 0x81, 0x81, 0x00, 0xcd, 0x4f, 0xbd,
0xe1, 0x43, 0xb4, 0xfe, 0x9a, 0x50, 0xb8, 0xeb, 0xf3, 0xd6, 0x3f, 0x2a,
0xbe, 0x19, 0x7a, 0x2c, 0xf4, 0x63, 0x35, 0x29, 0x47, 0x39, 0x17, 0xb4,
0xc7, 0x58, 0xc0, 0x5a, 0xbf, 0x5c, 0xa4, 0xcf, 0x9e, 0x4b, 0xad, 0x5a,
0x95, 0xfd, 0xfa, 0x50, 0xbe, 0x54, 0x12, 0xbe, 0xd8, 0x8e, 0xaf, 0x8b,
0xb2, 0x15, 0xa1, 0xb5, 0x78, 0x03, 0xa6, 0x3b, 0x18, 0x13, 0x1d, 0xfe,
0x38, 0xb7, 0x65, 0x1e, 0x20, 0x39, 0xa9, 0x25, 0x37, 0xed, 0xe8, 0x5b,
0xc7, 0xd0, 0x60, 0xe2, 0x1f, 0xf2, 0x06, 0x5d, 0x3c, 0x5c, 0x36, 0xe0,
0xc6, 0x83, 0x52, 0xd3, 0xd3, 0x3f, 0x7c, 0x43, 0x82, 0x4a, 0x13, 0xf8,
0x8d, 0x48, 0x03, 0x4f, 0xb8, 0xad, 0x64, 0x85, 0xa9, 0xee, 0xde, 0x3d,
0x0c, 0x23, 0xb6, 0xe9, 0x8d, 0xad, 0x02, 0x62, 0x32, 0x58, 0x39, 0xbf,
0x5f, 0x3c, 0x6c, 0x0a, 0x13, 0x02, 0x81, 0x80, 0x7f, 0x87, 0x3c, 0x12,
0x3a, 0x94, 0x29, 0xfe, 0xed, 0x18, 0x10, 0x91, 0x00, 0xb7, 0x5b, 0x9b,
0x14, 0x37, 0x03, 0xbc, 0xb6, 0x91, 0x42, 0xc1, 0xb6, 0xed, 0xf8, 0x2b,
0x46, 0x84, 0xf1, 0xf0, 0xd6, 0x00, 0xea, 0xba, 0x63, 0x8e, 0x68, 0x1a,
0x1d, 0x01, 0x82, 0xe6, 0x21, 0x3c, 0xeb, 0x38, 0xe6, 0xb1, 0x35, 0x6c,
0x39, 0xc5, 0xe4, 0x63, 0x16, 0xde, 0x85, 0x3b, 0xe8, 0xbb, 0x47, 0xc7,
0xaa, 0xb2, 0xc3, 0x35, 0x5c, 0x94, 0x16, 0x0e, 0xef, 0xae, 0x33, 0x5a,
0x90, 0xf0, 0xce, 0x52, 0xb2, 0x02, 0x0b, 0x52, 0xe5, 0x66, 0x9f, 0x16,
0x50, 0x36, 0x44, 0x1e, 0xac, 0x3c, 0xe1, 0x49, 0xee, 0x2c, 0xa5, 0xbc,
0x3b, 0x28, 0x1c, 0xae, 0xa9, 0xca, 0x92, 0x42, 0x19, 0x8d, 0xe7, 0xaf,
0xeb, 0x25, 0x7a, 0x2a, 0xc1, 0xe5, 0xf8, 0x9e, 0x41, 0x6d, 0xe3, 0x04,
0x7f, 0x59, 0x2d, 0xc9, 0x02, 0x81, 0x81, 0x00, 0xbe, 0xc3, 0x51, 0xdd,
0x25, 0x48, 0xdd, 0xab, 0xca, 0x47, 0x17, 0xcd, 0x57, 0x0b, 0x18, 0x0e,
0xcb, 0xa3, 0x4e, 0x73, 0xc0, 0x5e, 0x1b, 0xbd, 0x76, 0x99, 0xc5, 0x39,
0xd8, 0x07, 0xda, 0x09, 0xa5, 0xed, 0xe8, 0x8e, 0xdf, 0x27, 0xf2, 0x5c,
0x1d, 0x40, 0xe0, 0x97, 0x07, 0x8c, 0xe7, 0x50, 0x55, 0xbb, 0x5c, 0x24,
0x1a, 0x9f, 0x46, 0xfa, 0x7d, 0x01, 0x8e, 0x34, 0xbf, 0x46, 0x85, 0xf8,
0x72, 0xc6, 0x7c, 0x68, 0x5a, 0xcb, 0x03, 0xae, 0xe4, 0xd9, 0x99, 0xb5,
0x9d, 0xb2, 0xf7, 0x47, 0xd1, 0x5c, 0x02, 0x73, 0x5c, 0x07, 0x0d, 0x70,
0xc5, 0x82, 0x47, 0x19, 0x28, 0x0a, 0xb0, 0xbb, 0x35, 0x53, 0x3b, 0x05,
0x22, 0x9d, 0x19, 0x0c, 0xb1, 0xe7, 0x0d, 0x9e, 0xa8, 0x38, 0x4c, 0x26,
0xa4, 0x64, 0x86, 0xbb, 0x41, 0xbe, 0x4e, 0x39, 0x12, 0xea, 0x8d, 0x1a,
0xd3, 0x0c, 0x5b, 0x8b, 0x02, 0x81, 0x81, 0x00, 0xa9, 0x2d, 0x4b, 0x43,
0x55, 0x7f, 0x90, 0xb4, 0xea, 0xf9, 0xc2, 0x4c, 0x8c, 0x4d, 0xee, 0x62,
0x85, 0xd2, 0x58, 0x71, 0xc7, 0xb3, 0xfb, 0x80, 0x37, 0xd9, 0xc5, 0x20,
0x61, 0xeb, 0x39, 0x7f, 0x4d, 0x09, 0x7c, 0x32, 0x46, 0x8b, 0x49, 0xa4,
0xd6, 0x99, 0xb4, 0xdc, 0xb6, 0xe3, 0x2a, 0x77, 0x53, 0xa3, 0xee, 0xdb,
0x4d, 0xf9, 0x59, 0x20, 0x8a, 0x83, 0x94, 0x29, 0x72, 0x96, 0x76, 0x36,
0x63, 0xbe, 0xa1, 0xe8, 0x94, 0xf9, 0x50, 0x71, 0x56, 0xaa, 0xeb, 0x90,
0x06, 0xf2, 0x05, 0xb1, 0x19, 0xf0, 0x13, 0x89, 0x2d, 0x7b, 0x94, 0xb7,
0xf2, 0x18, 0xfa, 0x52, 0x09, 0x82, 0x99, 0x20, 0xe9, 0x7a, 0x1c, 0x68,
0xfe, 0x44, 0xe5, 0xf8, 0xc5, 0xd3, 0xc6, 0x66, 0x3d, 0xe3, 0x43, 0xc3,
0x63, 0x81, 0xff, 0x78, 0x91, 0x5c, 0x48, 0x16, 0xbe, 0x92, 0x90, 0x2f,
0x10, 0x9f, 0x2d, 0x17};
RsaTestKeys::RsaTestKeys()
: private_key_1_3072_bits_(std::begin(kTestRsaPrivateKey1_3072),
std::end(kTestRsaPrivateKey1_3072)),
public_key_1_3072_bits_(std::begin(kTestRsaPublicKey1_3072),
std::end(kTestRsaPublicKey1_3072)),
private_key_2_2048_bits_(std::begin(kTestRsaPrivateKey2_2048),
std::end(kTestRsaPrivateKey2_2048)),
public_key_2_2048_bits_(std::begin(kTestRsaPublicKey2_2048),
std::end(kTestRsaPublicKey2_2048)),
private_key_3_2048_bits_(std::begin(kTestRsaPrivateKey3_2048),
std::end(kTestRsaPrivateKey3_2048)),
public_key_3_2048_bits_(std::begin(kTestRsaPublicKey3_2048),
std::end(kTestRsaPublicKey3_2048)),
private_key_2_carmichael_totient_2048_bits_(
std::begin(kTestRsaPrivateKey2CarmichaelTotient_2048),
std::end(kTestRsaPrivateKey2CarmichaelTotient_2048)),
private_key_3_carmichael_totient_2048_bits_(
std::begin(kTestRsaPrivateKey3CarmichaelTotient_2048),
std::end(kTestRsaPrivateKey3CarmichaelTotient_2048)),
private_key_4_carmichael_totient_2048_bits_(
std::begin(kTestRsaPrivateKey4CarmichaelTotient_2048),
std::end(kTestRsaPrivateKey4CarmichaelTotient_2048)) {}
} // namespace widevine

View File

@@ -1,92 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// RSA keys generated using fake_prng for purposes of testing.
#ifndef COMMON_RSA_TEST_KEYS_H_
#define COMMON_RSA_TEST_KEYS_H_
#include <string>
namespace widevine {
// Container for test RSA keys
//
// Except for the keys noted below, these keys were generated using Euler's
// Totient.
//
class RsaTestKeys {
public:
RsaTestKeys();
// Returns 3072-bit private RSA test key 1
const std::string& private_test_key_1_3072_bits() const {
return private_key_1_3072_bits_;
}
// Returns 3072-bit public RSA test key 1
const std::string& public_test_key_1_3072_bits() const {
return public_key_1_3072_bits_;
}
// Returns 2048-bit private RSA test key 2
const std::string& private_test_key_2_2048_bits() const {
return private_key_2_2048_bits_;
}
// Returns 2048-bit public RSA test key 2
const std::string& public_test_key_2_2048_bits() const {
return public_key_2_2048_bits_;
}
// Returns 2048-bit private RSA test key 3
const std::string& private_test_key_3_2048_bits() const {
return private_key_3_2048_bits_;
}
// Returns 2048-bit public RSA test key 3
const std::string& public_test_key_3_2048_bits() const {
return public_key_3_2048_bits_;
}
// This key was converted to a Carmichael totient version from the original
// private_key_2_2048_bits_.
const std::string& private_test_key_2_carmichael_totient_2048_bits() const {
return private_key_2_carmichael_totient_2048_bits_;
}
// This key was converted to a Carmichael totient version from the original
// private_key_3_2048_bits_.
const std::string& private_test_key_3_carmichael_totient_2048_bits() const {
return private_key_3_carmichael_totient_2048_bits_;
}
// This key has been created using the Carmichael totient. This is
// useful for testing with some RSA implementations that had challenges
// with keys generated this way.
const std::string& private_test_key_4_carmichael_totient_2048_bits() const {
return private_key_4_carmichael_totient_2048_bits_;
}
private:
RsaTestKeys(const RsaTestKeys&) = delete;
RsaTestKeys& operator=(const RsaTestKeys&) = delete;
std::string private_key_1_3072_bits_;
std::string public_key_1_3072_bits_;
std::string private_key_2_2048_bits_;
std::string public_key_2_2048_bits_;
std::string private_key_3_2048_bits_;
std::string public_key_3_2048_bits_;
// Tests keys that use the Carmichael totient to calculate d.
std::string private_key_2_carmichael_totient_2048_bits_;
std::string private_key_3_carmichael_totient_2048_bits_;
std::string private_key_4_carmichael_totient_2048_bits_;
};
} // namespace widevine
#endif // COMMON_RSA_TEST_KEYS_H_

View File

@@ -1,353 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Unit test for rsa_util RSA utilties library.
#include <stddef.h>
#include <memory>
#include <cstdint>
#include "glog/logging.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "openssl/bn.h"
#include "common/rsa_test_keys.h"
#include "common/rsa_util.h"
using ::testing::NotNull;
namespace {
const uint32_t kRsaPublicExponent = 65537;
const int kTestRsaBits = 2048;
} // anonymous namespace
namespace widevine {
namespace rsa_util {
class RsaUtilTest : public ::testing::Test {
protected:
RsaTestKeys test_keys_;
};
TEST_F(RsaUtilTest, SerializeDeserializePrivateKey) {
RSA* private_key;
std::string serialized_private_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_1_3072_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_1_3072_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_2_2048_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_3_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPrivateKey(private_key, &serialized_private_key));
EXPECT_EQ(serialized_private_key, test_keys_.private_test_key_3_2048_bits());
EXPECT_EQ(RSA_check_key(private_key), 1);
RSA_free(private_key);
// Invalid key
EXPECT_FALSE(DeserializeRsaPrivateKey("this is a bad key", &private_key));
}
TEST_F(RsaUtilTest, SerializeDeserializePublicKey) {
RSA* public_key;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPublicKey(
test_keys_.public_test_key_1_3072_bits(), &public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits());
RSA_free(public_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPublicKey(
test_keys_.public_test_key_2_2048_bits(), &public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits());
RSA_free(public_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPublicKey(
test_keys_.public_test_key_3_2048_bits(), &public_key));
ASSERT_TRUE(public_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(public_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits());
RSA_free(public_key);
// Invalid key
EXPECT_FALSE(DeserializeRsaPublicKey("this is a bad key", &public_key));
}
TEST_F(RsaUtilTest, PublicKeyExtraction) {
RSA* private_key;
std::string serialized_public_key;
// Key 1
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_1_3072_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_1_3072_bits());
RSA_free(private_key);
// Key 2
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_2_2048_bits());
RSA_free(private_key);
// Key 3
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_3_2048_bits(), &private_key));
ASSERT_TRUE(private_key != NULL);
EXPECT_TRUE(SerializeRsaPublicKey(private_key, &serialized_public_key));
EXPECT_EQ(serialized_public_key, test_keys_.public_test_key_3_2048_bits());
RSA_free(private_key);
}
TEST_F(RsaUtilTest, Pkcs8PrivateKeyInfo) {
// The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8
// serialization/deserialization functionality , so we test those.
std::string serialized_pkcs8;
std::string serialized_pkcs1;
// Key 1
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_1_3072_bits(), &serialized_pkcs8));
EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1);
// Key 2
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), &serialized_pkcs8));
EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1);
// Key 3
EXPECT_TRUE(RsaPrivateKeyToPrivateKeyInfo(
test_keys_.private_test_key_3_2048_bits(), &serialized_pkcs8));
EXPECT_TRUE(PrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1);
}
TEST_F(RsaUtilTest, Pkcs8EncryptedPrivateKeyInfo) {
// The PKCS#1 <-> PKCS#8 conversion routines exercise all the PKCS#8
// serialization/deserialization functionality , so we test those.
std::string serialized_pkcs8;
std::string serialized_pkcs1;
std::string passphrase("passphrase");
// Key 1
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_1_3072_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
passphrase,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_1_3072_bits(), serialized_pkcs1);
// Key 2
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
passphrase,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), serialized_pkcs1);
// Key 3
EXPECT_TRUE(RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_3_2048_bits(), passphrase,
&serialized_pkcs8));
EXPECT_TRUE(EncryptedPrivateKeyInfoToRsaPrivateKey(serialized_pkcs8,
passphrase,
&serialized_pkcs1));
EXPECT_NE(serialized_pkcs1, serialized_pkcs8);
EXPECT_EQ(test_keys_.private_test_key_3_2048_bits(), serialized_pkcs1);
}
TEST_F(RsaUtilTest, FailOnInvalidParams) {
RSA* test_input_key = NULL;
RSA* test_output_key = NULL;
std::string test_string;
std::string pass("password");
ASSERT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &test_input_key));
ASSERT_TRUE(test_input_key != NULL);
EXPECT_FALSE(SerializeRsaPrivateKey(NULL, &test_string));
EXPECT_FALSE(SerializeRsaPrivateKey(test_input_key, NULL));
EXPECT_FALSE(SerializeRsaPublicKey(NULL, &test_string));
EXPECT_FALSE(SerializeRsaPublicKey(test_input_key, NULL));
EXPECT_FALSE(SerializePrivateKeyInfo(NULL, &test_string));
EXPECT_FALSE(SerializePrivateKeyInfo(test_input_key, NULL));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(NULL, pass, &test_string));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass, NULL));
EXPECT_FALSE(DeserializeRsaPrivateKey("", &test_output_key));
EXPECT_FALSE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializeRsaPublicKey("", &test_output_key));
EXPECT_FALSE(DeserializeRsaPublicKey(
test_keys_.public_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializePrivateKeyInfo("", &test_output_key));
EXPECT_FALSE(DeserializePrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), NULL));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo("", pass, &test_output_key));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), pass, NULL));
RSA_free(test_input_key);
}
TEST_F(RsaUtilTest, Pkcs8FailOnInvalidPassword) {
RSA* test_input_key = NULL;
RSA* test_output_key = NULL;
std::string serialized_pkcs8;
std::string pass("password");
ASSERT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &test_input_key));
EXPECT_FALSE(SerializeEncryptedPrivateKeyInfo(test_input_key, "",
&serialized_pkcs8));
ASSERT_TRUE(SerializeEncryptedPrivateKeyInfo(test_input_key, pass,
&serialized_pkcs8));
EXPECT_FALSE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass + "a",
&test_output_key));
EXPECT_TRUE(DeserializeEncryptedPrivateKeyInfo(serialized_pkcs8, pass,
&test_output_key));
RSA_free(test_input_key);
RSA_free(test_output_key);
}
TEST_F(RsaUtilTest, ConvertToCarmichaelTotient_ExistingKey_Success) {
bssl::UniquePtr<RSA> original_private_key;
RSA* original_key_ptr = nullptr;
EXPECT_TRUE(DeserializeRsaPrivateKey(
test_keys_.private_test_key_2_2048_bits(), &original_key_ptr));
original_private_key.reset(original_key_ptr);
ASSERT_THAT(original_private_key, NotNull());
bssl::UniquePtr<RSA> private_key(
RSAPrivateKey_dup(original_private_key.get()));
ASSERT_THAT(private_key, NotNull());
EXPECT_TRUE(ConvertToCarmichaelTotient(private_key.get()));
// Confirm that the key is valid and has changed from the original.
EXPECT_EQ(1, RSA_check_key(private_key.get()));
std::string serialized_carmichael_private_key;
EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(),
&serialized_carmichael_private_key));
EXPECT_NE(serialized_carmichael_private_key,
test_keys_.private_test_key_2_2048_bits());
// Convert back and make sure the serialized key matches the original.
EXPECT_TRUE(ConvertToEulerTotient(private_key.get()));
EXPECT_EQ(1, RSA_check_key(private_key.get()));
std::string serialized_euler_private_key;
EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(),
&serialized_euler_private_key));
EXPECT_EQ(serialized_euler_private_key,
test_keys_.private_test_key_2_2048_bits());
}
TEST_F(RsaUtilTest, ConvertToEulerTotient_NewKey_Success) {
bssl::UniquePtr<RSA> rsa;
bssl::UniquePtr<RSA> private_key;
bssl::UniquePtr<BIGNUM> exponent(BN_new());
ASSERT_TRUE(BN_set_word(exponent.get(), kRsaPublicExponent));
// It is possible that sometimes, the d value generated using carmichael
// and euler is the same. For this test, find a key where they are not the
// same (max 100 tries).
bool found_distinct_keys = false;
for (int i = 0; i < 100; i++) {
rsa.reset(RSA_new());
ASSERT_TRUE(RSA_generate_key_ex(rsa.get(), kTestRsaBits,
exponent.get(), nullptr));
private_key.reset(RSAPrivateKey_dup(rsa.get()));
EXPECT_TRUE(ConvertToEulerTotient(private_key.get()));
EXPECT_EQ(1, RSA_check_key(private_key.get()));
// If the values are different, break.
if (BN_cmp(private_key->d, rsa->d) != 0) {
found_distinct_keys = true;
break;
}
LOG(INFO) << "Euler and Carmichael d values are the same. Count: " << i;
}
ASSERT_TRUE(found_distinct_keys)
<< "Reached maximum attempts, but did not generate distinct keys";
EXPECT_EQ(1, RSA_check_key(private_key.get()));
// Sanity check that the serialized keys are distinct.
std::string serialized_carmichael_private_key;
std::string serialized_private_key;
EXPECT_TRUE(SerializeRsaPrivateKey(rsa.get(),
&serialized_carmichael_private_key));
EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(),
&serialized_private_key));
EXPECT_NE(serialized_carmichael_private_key, serialized_private_key);
// Convert back to Carmichael, validate, and confirm that the keys are the
// same.
EXPECT_TRUE(ConvertToCarmichaelTotient(private_key.get()));
EXPECT_EQ(1, RSA_check_key(private_key.get()));
EXPECT_TRUE(SerializeRsaPrivateKey(private_key.get(),
&serialized_private_key));
EXPECT_EQ(serialized_carmichael_private_key, serialized_private_key);
}
TEST_F(RsaUtilTest, ConvertToSerializedCarmichaelTotient_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToCarmichaelTotient(
test_keys_.private_test_key_2_2048_bits(), &private_key));
EXPECT_EQ(test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
private_key);
}
TEST_F(RsaUtilTest, ConvertToSerializedEulerTotient_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToEulerTotient(
test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
&private_key));
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), private_key);
}
TEST_F(RsaUtilTest, ConvertToEulerTotient_Idempotent_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToEulerTotient(test_keys_.private_test_key_2_2048_bits(),
&private_key));
EXPECT_EQ(test_keys_.private_test_key_2_2048_bits(), private_key);
}
TEST_F(RsaUtilTest, ConvertToCarmichaelTotient_Idempotent_Success) {
std::string private_key;
EXPECT_TRUE(ConvertToCarmichaelTotient(
test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
&private_key));
EXPECT_EQ(test_keys_.private_test_key_2_carmichael_totient_2048_bits(),
private_key);
}
} // namespace rsa_util
} // namespace widevine

View File

@@ -1,245 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
// Implementation of the SecurityProfileList class.
#include "common/security_profile_list.h"
#include <vector>
#include "glog/logging.h"
#include "google/protobuf/text_format.h"
#include "common/client_id_util.h"
#include "common/device_status_list.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
using ClientCapabilities = ClientIdentification::ClientCapabilities;
SecurityProfileList::SecurityProfileList(const std::string& profile_namespace)
: profile_namespace_(profile_namespace) {}
int SecurityProfileList::Init() { return 0; }
int SecurityProfileList::GetQualifiedProfilesFromSpecifiedProfiles(
const std::vector<std::string>& profiles_to_check,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* qualified_profiles) const {
if (qualified_profiles == nullptr) {
return 0;
}
qualified_profiles->clear();
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile_name : profiles_to_check) {
SecurityProfile profile;
if (GetProfileByName(profile_name, &profile)) {
if (DoesProfileQualify(profile, client_id, device_info)) {
qualified_profiles->push_back(profile.name());
}
}
}
return qualified_profiles->size();
}
int SecurityProfileList::GetQualifiedProfiles(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* qualified_profiles) const {
if (qualified_profiles == nullptr) {
return 0;
}
qualified_profiles->clear();
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile : security_profiles_) {
if (DoesProfileQualify(profile, client_id, device_info)) {
qualified_profiles->push_back(profile.name());
}
}
return qualified_profiles->size();
}
bool SecurityProfileList::GetDrmInfo(const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
SecurityProfile::DrmInfo* drm_info) const {
if (drm_info == nullptr) {
return false;
}
drm_info->mutable_output()->set_hdcp_version(
client_id.client_capabilities().max_hdcp_version());
drm_info->mutable_output()->set_analog_output_capabilities(
client_id.client_capabilities().analog_output_capabilities());
drm_info->mutable_security()->set_oemcrypto_api_version(
client_id.client_capabilities().oem_crypto_api_version());
drm_info->mutable_security()->set_resource_rating_tier(
client_id.client_capabilities().resource_rating_tier());
drm_info->mutable_security()->set_security_level(
device_info.security_level());
drm_info->mutable_request_model_info()->set_manufacturer(
GetClientInfo(client_id, kModDrmMake));
drm_info->mutable_request_model_info()->set_model_name(
GetClientInfo(client_id, kModDrmModel));
drm_info->mutable_request_model_info()->set_status(
DeviceModel::MODEL_STATUS_UNVERIFIED);
for (const auto& model_info : device_info.model_info()) {
if (model_info.manufacturer() ==
drm_info->request_model_info().manufacturer() &&
model_info.model_name() ==
drm_info->request_model_info().model_name()) {
drm_info->mutable_request_model_info()->set_status(model_info.status());
drm_info->mutable_request_model_info()->set_model_year(
model_info.model_year());
break;
}
}
drm_info->set_system_id(device_info.system_id());
SecurityProfile::ClientInfo* client_info = drm_info->mutable_client_info();
client_info->set_device_name(GetClientInfo(client_id, kModDrmDeviceName));
SecurityProfile::ClientInfo::ProductInfo* product_info =
client_info->mutable_product_info();
product_info->set_product_name(GetClientInfo(client_id, kModDrmProductName));
product_info->set_build_info(GetClientInfo(client_id, kModDrmBuildInfo));
product_info->set_oem_crypto_security_patch_level(
GetClientInfo(client_id, kModDrmOemCryptoSecurityPatchLevel));
// TODO(user): Figure out how to get device platform pushed into SPL API.
DeviceCertificateStatus device_certificate_status;
SecurityProfile::DeviceState device_model_state =
SecurityProfile::DEVICE_STATE_UNKNOWN;
Status status =
DeviceStatusList::Instance()->GetDeviceCertificateStatusBySystemId(
device_info.system_id(), &device_certificate_status);
if (status.ok() && device_certificate_status.has_status()) {
switch (device_certificate_status.status()) {
case DeviceCertificateStatus::STATUS_IN_TESTING:
device_model_state = SecurityProfile::IN_TESTING;
break;
case DeviceCertificateStatus::STATUS_RELEASED:
device_model_state = SecurityProfile::RELEASED;
break;
case DeviceCertificateStatus::STATUS_TEST_ONLY:
device_model_state = SecurityProfile::TEST_ONLY;
break;
case DeviceCertificateStatus::STATUS_REVOKED:
device_model_state = SecurityProfile::REVOKED;
break;
default:
break;
}
}
drm_info->set_device_model_state(device_model_state);
return true;
}
bool SecurityProfileList::GetProfileByName(
const std::string& name, SecurityProfile* security_profile) const {
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile : security_profiles_) {
if (profile.name() == name) {
if (security_profile != nullptr) {
*security_profile = profile;
}
return true;
}
}
return false;
}
bool SecurityProfileList::InsertProfile(
const SecurityProfile& profile_to_insert) {
// Check if profile already exist.
if (GetProfileByName(profile_to_insert.name(), nullptr)) {
LOG(ERROR) << "Unable to insert profile: " << profile_to_insert.name()
<< ". Name already exist.";
return false;
}
if (profile_to_insert.min_security_requirements().security_level() ==
ProvisionedDeviceInfo::LEVEL_UNSPECIFIED) {
LOG(ERROR) << "Unable to insert profile: " << profile_to_insert.name()
<< ". Security level not specified.";
return false;
}
absl::WriterMutexLock lock(&mutex_);
security_profiles_.push_back(profile_to_insert);
return true;
}
int SecurityProfileList::NumProfiles() const {
absl::ReaderMutexLock lock(&mutex_);
return security_profiles_.size();
}
void SecurityProfileList::ClearAllProfiles() {
absl::WriterMutexLock lock(&mutex_);
security_profiles_.clear();
}
bool SecurityProfileList::DoesProfileQualify(
const SecurityProfile& profile, const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info) const {
if (profile.min_security_requirements().security_level() <
device_info.security_level()) {
VLOG(1) << "Profile does not qualify <" << profile.name()
<< "> security level: "
<< profile.min_security_requirements().security_level()
<< ", device: " << device_info.security_level();
return false;
}
if (profile.min_security_requirements().oemcrypto_api_version() >
client_id.client_capabilities().oem_crypto_api_version()) {
VLOG(1) << "Profile does not qualify <" << profile.name()
<< "> oemcrypto version: "
<< profile.min_security_requirements().oemcrypto_api_version()
<< ", device: "
<< client_id.client_capabilities().oem_crypto_api_version();
return false;
}
if (profile.min_output_requirements().hdcp_version() >
client_id.client_capabilities().max_hdcp_version()) {
VLOG(1) << "profile does not qualify <" << profile.name()
<< "> hdcp_version: "
<< profile.min_output_requirements().hdcp_version() << ", device: "
<< client_id.client_capabilities().max_hdcp_version();
return false;
}
if (profile.min_output_requirements().analog_output_capabilities() >
client_id.client_capabilities().analog_output_capabilities()) {
VLOG(1) << "Profile idoes not qualify <" << profile.name()
<< "> analog output: "
<< profile.min_output_requirements().analog_output_capabilities()
<< ", device: "
<< client_id.client_capabilities().analog_output_capabilities();
return false;
}
if (profile.min_security_requirements().resource_rating_tier() >
client_id.client_capabilities().resource_rating_tier()) {
VLOG(1) << "Profile does not qualify <" << profile.name()
<< "> resource rating tier: "
<< profile.min_security_requirements().resource_rating_tier()
<< ", device: "
<< client_id.client_capabilities().resource_rating_tier();
return false;
}
return true;
}
void SecurityProfileList::GetProfileNames(
std::vector<std::string>* profile_names) const {
if (profile_names == nullptr) {
return;
}
absl::ReaderMutexLock lock(&mutex_);
for (auto& profile : security_profiles_) {
profile_names->push_back(profile.name());
}
}
} // namespace widevine

View File

@@ -1,93 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Container of device security profiles. Security profiles indicate rules
// to allow using the profile. The rules are based on DRM capabilities of a
// device.
#ifndef COMMON_SECURITY_PROFILE_LIST_H_
#define COMMON_SECURITY_PROFILE_LIST_H_
#include "absl/synchronization/mutex.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/device_security_profile_data.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
using ClientCapabilities = ClientIdentification::ClientCapabilities;
// The SecurityProfileList will hold all security profiles. During license
// acquisition, information from the client and information from the server are
// combined to deternmine the device's security profile level.
class SecurityProfileList {
public:
explicit SecurityProfileList(const std::string& profile_namespace);
virtual ~SecurityProfileList() {}
// Initialize the security profile list. The size of the profile list is
// returned.
virtual int Init();
// Add the specified profile to the existing list of profiles. Returns true
// if successfully inserted, false if unable to insert.
bool InsertProfile(const SecurityProfile& profile_to_insert);
// Populates |profiles_allow| with a list of profiles from the specified
// |profiles_to_check| list that meet the requirements for the this device.
// The number of profiles is returned.
virtual int GetQualifiedProfilesFromSpecifiedProfiles(
const std::vector<std::string>& profiles_to_check,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* qualified_profiles) const;
// Populates |profiles_to_allow| with a list of profiles that meet the
// requirements for the this device. The number of profiles is returned.
virtual int GetQualifiedProfiles(
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
std::vector<std::string>* qualified_profiles) const;
// Return true if a profile exist matching the specified |name|.
// |security_profile| is owned by the caller and is populated if a profile
// exist.
bool GetProfileByName(const std::string& name,
SecurityProfile* security_profile) const;
// Return the device security capabilities. |drm_info| is populated with
// data from |client_id| and |device_info|. |drm_info| must not be null and
// is owned by the caller.
bool GetDrmInfo(const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info,
SecurityProfile::DrmInfo* drm_info) const;
// Return the number of profiles in the list.
int NumProfiles() const;
// Return a list of profile names.
virtual void GetProfileNames(std::vector<std::string>* profile_names) const;
protected:
void ClearAllProfiles();
private:
bool DoesProfileQualify(const SecurityProfile& profile,
const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info) const;
mutable absl::Mutex mutex_;
// Security profiles
std::string profile_namespace_;
std::vector<SecurityProfile> security_profiles_ ABSL_GUARDED_BY(mutex_);
};
} // namespace widevine
#endif // COMMON_SECURITY_PROFILE_LIST_H_

View File

@@ -1,206 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 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/security_profile_list.h"
#include "glog/logging.h"
#include "google/protobuf/util/message_differencer.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "common/client_id_util.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
namespace security_profile {
const char kMakeName[] = "company_name";
const char kMakeValue[] = "Google";
const char kModelName[] = "model_name";
const char kModelValue[] = "model1";
const char kDeviceNameValue[] = "TestDeviceName";
const char kProductNameValue[] = "TestProductName";
const char kBuildInfoValue[] = "TestBuildInfo";
const char kOemCryptoSecurityPatchLevelValue[] =
"TestOemCryptoSecurityPatchLevel";
const char kDefaultContentOwnerName[] = "Widevine";
const uint32_t kSystemId = 1234;
const uint32_t kResourceTierLow = 1;
const uint32_t kResourceTierMed = 2;
const uint32_t kResourceTierHigh = 3;
class SecurityProfileListTest : public ::testing::Test {
public:
SecurityProfileListTest() {}
~SecurityProfileListTest() override {}
void SetUp() override {
const uint32_t oemcrypto_12 = 12;
SecurityProfile profile;
std::string profile_namespace = "widevine";
profile_list_ = absl::make_unique<SecurityProfileList>(profile_namespace);
AddClientInfo(&client_id_, kMakeName, kMakeValue);
AddClientInfo(&client_id_, kModelName, kModelValue);
AddClientInfo(&client_id_, kModDrmDeviceName, kDeviceNameValue);
AddClientInfo(&client_id_, kModDrmProductName, kProductNameValue);
AddClientInfo(&client_id_, kModDrmBuildInfo, kBuildInfoValue);
AddClientInfo(&client_id_, kModDrmOemCryptoSecurityPatchLevel,
kOemCryptoSecurityPatchLevelValue);
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(
oemcrypto_12);
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_2);
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
device_info_.set_system_id(kSystemId);
}
std::unique_ptr<SecurityProfileList> profile_list_;
ClientIdentification client_id_;
ProvisionedDeviceInfo device_info_;
};
TEST_F(SecurityProfileListTest, InsertProfile) {
// Insert test profile1 into the list.
SecurityProfileList profile_list("widevine-test");
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_TRUE(profile_list.InsertProfile(profile1));
// Verify the list still has one profile.
EXPECT_EQ(1, profile_list.NumProfiles());
// Should not allow insert if existing profile has the same name.
SecurityProfile profile2;
profile2.set_name(profile1.name());
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_FALSE(profile_list.InsertProfile(profile2));
// Verify the list still has one profile.
EXPECT_EQ(1, profile_list.NumProfiles());
// Should allow insert since this profile has a different name.
profile2.set_name("profile2");
EXPECT_TRUE(profile_list.InsertProfile(profile2));
EXPECT_EQ(2, profile_list.NumProfiles());
}
TEST_F(SecurityProfileListTest, GetDrmInfo) {
SecurityProfile::DrmInfo drm_info;
DeviceModel* device_model = device_info_.add_model_info();
device_model->set_manufacturer(GetClientInfo(client_id_, kModDrmMake));
device_model->set_model_name(GetClientInfo(client_id_, kModDrmModel));
device_model->set_status(DeviceModel::MODEL_STATUS_VERIFIED);
const uint32_t model_launch_year = 2015;
device_model->set_model_year(model_launch_year);
ASSERT_TRUE(profile_list_->GetDrmInfo(client_id_, device_info_, &drm_info));
EXPECT_EQ(client_id_.client_capabilities().max_hdcp_version(),
drm_info.output().hdcp_version());
EXPECT_EQ(client_id_.client_capabilities().analog_output_capabilities(),
drm_info.output().analog_output_capabilities());
EXPECT_EQ(client_id_.client_capabilities().oem_crypto_api_version(),
drm_info.security().oemcrypto_api_version());
EXPECT_EQ(client_id_.client_capabilities().resource_rating_tier(),
drm_info.security().resource_rating_tier());
EXPECT_EQ(device_info_.security_level(),
drm_info.security().security_level());
EXPECT_EQ(device_info_.system_id(), drm_info.system_id());
EXPECT_EQ(kMakeValue, drm_info.request_model_info().manufacturer());
EXPECT_EQ(kModelValue, drm_info.request_model_info().model_name());
EXPECT_EQ(DeviceModel::MODEL_STATUS_VERIFIED,
drm_info.request_model_info().status());
EXPECT_EQ(model_launch_year, drm_info.request_model_info().model_year());
EXPECT_EQ(kDeviceNameValue, drm_info.client_info().device_name());
EXPECT_EQ(kProductNameValue,
drm_info.client_info().product_info().product_name());
EXPECT_EQ(kBuildInfoValue,
drm_info.client_info().product_info().build_info());
EXPECT_EQ(
kOemCryptoSecurityPatchLevelValue,
drm_info.client_info().product_info().oem_crypto_security_patch_level());
}
TEST_F(SecurityProfileListTest, QualifiedProfiles) {
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
profile1.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V1);
profile_list_->InsertProfile(profile1);
SecurityProfile profile2;
profile2.set_name("profile2");
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_1);
profile2.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V2);
profile_list_->InsertProfile(profile2);
// Both profiles should qualify based on client_info and device_info from the
// Setup function.
std::vector<std::string> qualified_profiles;
EXPECT_EQ(2, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile2.name()));
// Reduce the DRM capabilities of the device so profile2 will not qualify.
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V1);
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
}
TEST_F(SecurityProfileListTest, FindProfile) {
SecurityProfileList profile_list("widevine-test");
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_EQ(kDefaultContentOwnerName, profile1.owner());
SecurityProfile profile2;
profile2.set_name("profile2");
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
// Override the default owner name.
profile2.set_owner("owner2");
// Insert profiles 1 & 2.
EXPECT_TRUE(profile_list.InsertProfile(profile1));
EXPECT_TRUE(profile_list.InsertProfile(profile2));
EXPECT_EQ(2, profile_list.NumProfiles());
// Find the profile by its name.
SecurityProfile profile;
EXPECT_TRUE(profile_list.GetProfileByName(profile1.name(), &profile));
EXPECT_EQ(profile1.name(), profile.name());
EXPECT_EQ(profile1.level(), profile.level());
EXPECT_EQ(profile1.owner(), profile.owner());
EXPECT_TRUE(profile_list.GetProfileByName(profile2.name(), &profile));
EXPECT_EQ(profile2.name(), profile.name());
EXPECT_EQ(profile2.level(), profile.level());
EXPECT_EQ(profile2.owner(), profile.owner());
EXPECT_FALSE(
profile_list.GetProfileByName("you-should-not-find-me", &profile));
}
} // namespace security_profile
} // namespace widevine

View File

@@ -1,74 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/sha_util.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
namespace widevine {
TEST(ShaUtilTest, Sha1Empty) {
const uint8_t kExpected[] = {
0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha1_Hash(""));
}
TEST(ShaUtilTest, Sha256Empty) {
const uint8_t kExpected[] = {
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha256_Hash(""));
}
TEST(ShaUtilTest, Sha1) {
const uint8_t kExpected[] = {
0x6b, 0x63, 0xa5, 0xe3, 0x6b, 0xfe, 0x54, 0x19, 0x4e, 0xfe,
0x9f, 0xe0, 0x29, 0x7e, 0xd8, 0x11, 0x0f, 0x10, 0x0d, 0x1d,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha1_Hash("random data"));
}
TEST(ShaUtilTest, Sha256) {
const uint8_t kExpected[] = {
0x62, 0x4b, 0x56, 0xb3, 0x38, 0x1b, 0xbc, 0xe0, 0x4f, 0x58, 0x88,
0x83, 0xb4, 0x2f, 0x4e, 0x27, 0xfe, 0xc0, 0x95, 0x56, 0xf8, 0x61,
0xcf, 0x94, 0x49, 0xe6, 0x5f, 0x26, 0xea, 0x70, 0xad, 0x88,
};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
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");
std::string name = "some seed value";
EXPECT_EQ("730621a55c675c4086be38e72aefa03e",
absl::BytesToHexString(GenerateSha1Uuid(name_space, name)));
}
} // namespace widevine

View File

@@ -1,70 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/signer_public_key.h"
#include "absl/memory/memory.h"
#include "common/ec_key.h"
#include "common/rsa_key.h"
namespace widevine {
// SignerPublicKeyImpl is a generic implementation of SignerPublicKey. The
// initialization details are in the SignerPublicKey factory method.
template <typename T>
class SignerPublicKeyImpl : public SignerPublicKey {
public:
explicit SignerPublicKeyImpl(std::unique_ptr<T> signer_public_key)
: signer_public_key_(std::move(signer_public_key)) {}
~SignerPublicKeyImpl() override {}
SignerPublicKeyImpl(const SignerPublicKeyImpl&) = delete;
SignerPublicKeyImpl& operator=(const SignerPublicKeyImpl&) = delete;
bool VerifySignature(const std::string& message, HashAlgorithm hash_algorithm,
const std::string& signature) const override {
if (!signer_public_key_->VerifySignature(message, hash_algorithm,
signature)) {
return false;
}
return true;
}
private:
std::unique_ptr<T> signer_public_key_;
};
std::unique_ptr<SignerPublicKey> SignerPublicKey::Create(
const std::string& signer_public_key, DrmCertificate::Algorithm algorithm) {
switch (algorithm) {
case DrmCertificate::RSA: {
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(signer_public_key));
if (public_key == nullptr) {
return nullptr;
}
return absl::make_unique<SignerPublicKeyImpl<RsaPublicKey>>(
std::move(public_key));
}
// All supported ECC curves are specified here.
case DrmCertificate::ECC_SECP256R1:
case DrmCertificate::ECC_SECP384R1:
case DrmCertificate::ECC_SECP521R1: {
std::unique_ptr<ECPublicKey> public_key =
ECPublicKey::Create(signer_public_key);
if (public_key == nullptr) {
return nullptr;
}
return absl::make_unique<SignerPublicKeyImpl<ECPublicKey>>(
std::move(public_key));
}
default:
return nullptr;
}
}
} // namespace widevine

View File

@@ -1,42 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_SIGNER_PUBLIC_KEY_H_
#define COMMON_SIGNER_PUBLIC_KEY_H_
#include <string>
#include "common/hash_algorithm.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
// SignerPublicKey is implemented for each provisioning key type that are
// defined in video/widevine/proto/public.drm_certificate.proto.
class SignerPublicKey {
public:
SignerPublicKey() = default;
virtual ~SignerPublicKey() = default;
SignerPublicKey(const SignerPublicKey&) = delete;
SignerPublicKey& operator=(const SignerPublicKey&) = delete;
// Verify message using |signer_public_key_| and |hash_algorithm|.
virtual bool VerifySignature(const std::string& message,
HashAlgorithm hash_algorithm,
const std::string& signature) const = 0;
// A factory method to create a SignerPublicKey. The |algorithm| is used to
// create an appropriate SignerPublicKey for the key type.
// The returned pointer is a nullptr if the key cannot be deserialized.
static std::unique_ptr<SignerPublicKey> Create(
const std::string& signer_public_key,
DrmCertificate::Algorithm algorithm);
};
} // namespace widevine
#endif // COMMON_SIGNER_PUBLIC_KEY_H_

View File

@@ -1,82 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/signer_public_key.h"
#include <memory>
#include "testing/gunit.h"
#include "common/ec_key.h"
#include "common/ec_test_keys.h"
#include "common/hash_algorithm.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine {
static const char kMessage[] = "The rain in Spain falls mainly in the blank?";
const HashAlgorithm kHashAlgorithm = HashAlgorithm::kSha256;
class SignerPublicKeyTest : public ::testing::Test {
public:
RsaTestKeys rsa_test_keys_;
ECTestKeys ec_test_keys_;
};
TEST_F(SignerPublicKeyTest, RSA) {
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(rsa_test_keys_.private_test_key_1_3072_bits()));
std::string signature;
ASSERT_TRUE(
private_key->GenerateSignature(kMessage, kHashAlgorithm, &signature));
std::unique_ptr<SignerPublicKey> public_key = SignerPublicKey::Create(
rsa_test_keys_.public_test_key_1_3072_bits(), DrmCertificate::RSA);
ASSERT_NE(public_key, nullptr);
EXPECT_TRUE(public_key->VerifySignature(kMessage, kHashAlgorithm, signature));
}
TEST_F(SignerPublicKeyTest, ECC) {
std::unique_ptr<ECPrivateKey> private_key =
ECPrivateKey::Create(ec_test_keys_.private_test_key_1_secp521r1());
std::string signature;
ASSERT_TRUE(
private_key->GenerateSignature(kMessage, kHashAlgorithm, &signature));
std::unique_ptr<SignerPublicKey> public_key =
SignerPublicKey::Create(ec_test_keys_.public_test_key_1_secp521r1(),
DrmCertificate::ECC_SECP521R1);
ASSERT_NE(public_key, nullptr);
EXPECT_TRUE(public_key->VerifySignature(kMessage, kHashAlgorithm, signature));
}
TEST_F(SignerPublicKeyTest, IncorrectAlgorithm) {
std::unique_ptr<SignerPublicKey> rsa_public_key =
SignerPublicKey::Create(rsa_test_keys_.public_test_key_1_3072_bits(),
DrmCertificate::ECC_SECP521R1);
ASSERT_EQ(rsa_public_key, nullptr);
std::unique_ptr<SignerPublicKey> ec_public_key = SignerPublicKey::Create(
ec_test_keys_.public_test_key_1_secp521r1(), DrmCertificate::RSA);
ASSERT_EQ(ec_public_key, nullptr);
}
TEST_F(SignerPublicKeyTest, BadKey) {
std::unique_ptr<SignerPublicKey> rsa_public_key =
SignerPublicKey::Create("GobbletyGook", DrmCertificate::RSA);
ASSERT_EQ(rsa_public_key, nullptr);
std::unique_ptr<SignerPublicKey> ec_public_key = SignerPublicKey::Create(
"MoreGobbletyGook", DrmCertificate::ECC_SECP521R1);
ASSERT_EQ(ec_public_key, nullptr);
}
} // namespace widevine

View File

@@ -1,44 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/signing_key_util.h"
#include "glog/logging.h"
#include "common/crypto_util.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
using crypto_util::kSigningKeySizeBits;
uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version) {
if (protocol_version <= VERSION_2_0) {
return kSigningKeySizeBits;
} else {
return kSigningKeySizeBits * 2;
}
}
using crypto_util::kSigningKeySizeBytes;
std::string GetClientSigningKey(const std::string& derived_key,
ProtocolVersion protocol_version) {
if (protocol_version == VERSION_2_0) {
DCHECK(derived_key.size() >= kSigningKeySizeBytes);
return derived_key.substr(0, kSigningKeySizeBytes);
} else {
DCHECK(derived_key.size() >= kSigningKeySizeBytes * 2);
return derived_key.substr(kSigningKeySizeBytes, kSigningKeySizeBytes);
}
}
std::string GetServerSigningKey(const std::string& derived_key) {
DCHECK(derived_key.size() >= kSigningKeySizeBytes);
return derived_key.substr(0, kSigningKeySizeBytes);
}
} // namespace widevine

View File

@@ -1,54 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
// Contains functions that are used to create and parse derived keys created
// using the NIST 800-108 KDF recommendation, using AES-CMAC PRF.
// NIST 800-108:
// http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf
// AES-CMAC:
// http://tools.ietf.org/html/rfc4493
//
// Example usage:
// using video::widevine::common::crypto_util::DeriveKey;
// using widevine_server::sdk::VERSION_2_1;
//
// std::string derived_key = DeriveKey(key_str,
// label,
// context,
// 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_
#define COMMON_SIGNING_KEY_UTIL_H_
#include <string>
#include "protos/public/license_protocol.pb.h"
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 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
// are assumed to be version 2.1 keys. The last 256 bits of those
// keys are returned. Keys that are 256 bits in length are returned
// in there entirety, version 2.0 keys.
std::string GetClientSigningKey(const std::string& derived_key,
ProtocolVersion protocol_version);
// Returns the server portion of the derived_key. The server portion
// is the first 256 bits of the key.
std::string GetServerSigningKey(const std::string& derived_key);
} // namespace widevine
#endif // COMMON_SIGNING_KEY_UTIL_H_

View File

@@ -1,66 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/signing_key_util.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/crypto_util.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
namespace signing_key_util {
namespace {
const char* kFrontKeyHex =
"0a1a2a3a4a5a6a7a8a9a0b1b2b3b4b5b0a1a2a3a4a5a6a7a8a9a0b1b2b3b4b5b";
const char* kBackKeyHex =
"0c1c2c3c4c5c6c7c8c9c0d1d2d3d4d5d0c1c2c3c4c5c6c7c8c9c0d1d2d3d4d5d";
std::string GenerateDerivedKey(
widevine::ProtocolVersion protocol_version) {
if (protocol_version == widevine::VERSION_2_0) {
return absl::HexStringToBytes(kFrontKeyHex);
} else {
return absl::HexStringToBytes(kFrontKeyHex) +
absl::HexStringToBytes(kBackKeyHex);
}
}
} // namespace
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_0) {
ASSERT_EQ(crypto_util::kSigningKeySizeBits,
SigningKeyMaterialSizeBits(VERSION_2_0));
}
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_1) {
ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2,
SigningKeyMaterialSizeBits(VERSION_2_1));
}
TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_1) {
ASSERT_EQ(kFrontKeyHex, absl::BytesToHexString(GetServerSigningKey(
GenerateDerivedKey(VERSION_2_1))));
}
TEST(DerivedKeyUtilTest, GetClientSigningKeyProtocolVersion2_1) {
ASSERT_EQ(kBackKeyHex, absl::BytesToHexString(GetClientSigningKey(
GenerateDerivedKey(VERSION_2_1), VERSION_2_1)));
}
TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_0) {
ASSERT_EQ(kFrontKeyHex, absl::BytesToHexString(GetServerSigningKey(
GenerateDerivedKey(VERSION_2_0))));
}
TEST(DerivedKeyUtilTest, GetClientSigningKeyProtocolVersion2_0) {
ASSERT_EQ(kFrontKeyHex, absl::BytesToHexString(GetClientSigningKey(
GenerateDerivedKey(VERSION_2_0), VERSION_2_0)));
}
} // namespace signing_key_util
} // namespace widevine

View File

@@ -1,61 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2007 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 "testing/gunit.h"
namespace widevine {
TEST(StatusTest, OK_Status) {
// test case for ok status.
Status status(error::OK);
EXPECT_EQ("OK", status.ToString());
}
TEST(StatusTest, OK_Status2) {
// test case for ok status.
Status status;
EXPECT_EQ("OK", status.ToString());
}
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());
}
// test case for status in boundary cases.
TEST(StatusTest, UNAVAILABLE_Status) {
Status status(error::UNAVAILABLE, "unavailable");
EXPECT_EQ("Errors::unavailable: unavailable", status.ToString());
}
TEST(StatusTest, NoNameCode) {
Status status(static_cast<error::StatusCode>(101), "Unknown error");
EXPECT_EQ("Errors::101: Unknown error", status.ToString());
}
TEST(StatusTest, EQUAL_OPERATOR) {
Status status1(error::ALREADY_EXISTS, "already exists 1");
Status status2(error::ALREADY_EXISTS, "already exists 1");
EXPECT_EQ(status1, status2);
}
TEST(StatusTest, NOT_EQUAL_OPERATOR) {
Status status1(error::ALREADY_EXISTS, "already exists");
Status status2(error::UNAVAILABLE, "unavailable");
EXPECT_NE(status1, status2);
}
TEST(StatusTest, NOT_EQUAL_OPERATOR_NONE_MSG) {
Status status1(error::ALREADY_EXISTS);
Status status2(error::UNAVAILABLE);
EXPECT_NE(status1, status2);
}
} // namespace widevine

View File

@@ -1,27 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2018 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/string_util.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
namespace widevine {
namespace string_util {
TEST(StringUtilTest, BitsetStringToBinaryString) {
std::string input = "01110100011001010111001101110100";
std::string output;
EXPECT_OK(BitsetStringToBinaryString(input, &output));
EXPECT_EQ("test", output);
}
} // namespace string_util
} // namespace widevine

View File

@@ -1,720 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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/test_drm_certificates.h"
namespace widevine {
static const unsigned char kTestRootCertificate[] = {
0x0a, 0x9b, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00, 0x18, 0xb9, 0x60, 0x22,
0x8e, 0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xa5,
0x62, 0x07, 0xdf, 0xc8, 0x84, 0x74, 0xe1, 0x2a, 0xb7, 0xbb, 0xc0, 0x78,
0x76, 0xbe, 0x13, 0x3b, 0xe6, 0x2c, 0x09, 0x9d, 0x35, 0x3f, 0xf3, 0x0f,
0xe9, 0x61, 0x96, 0x20, 0x53, 0x6e, 0x78, 0x62, 0xe0, 0x10, 0xd2, 0xca,
0xe4, 0xdd, 0xd5, 0x96, 0xaf, 0x9a, 0xd7, 0x08, 0x47, 0xe4, 0x55, 0x1b,
0x83, 0xbe, 0x10, 0x66, 0x74, 0x08, 0xf2, 0x49, 0x79, 0xea, 0x29, 0x46,
0xc2, 0x65, 0x97, 0xa6, 0xcc, 0x4b, 0xa4, 0x08, 0xc3, 0x04, 0x17, 0x01,
0xb5, 0x11, 0x53, 0xe9, 0x68, 0x34, 0x3c, 0x26, 0x56, 0x44, 0x37, 0x5c,
0xb4, 0x7a, 0x1d, 0x5d, 0x6c, 0x58, 0xc2, 0x82, 0xa0, 0x92, 0xf1, 0x14,
0xf1, 0x22, 0xff, 0x64, 0xde, 0xdf, 0xb3, 0x3d, 0x9d, 0xa5, 0x86, 0xcd,
0xa0, 0x0a, 0x63, 0x08, 0xdd, 0x60, 0x5d, 0xfd, 0xa4, 0x01, 0xe3, 0xb6,
0x0e, 0x85, 0xe4, 0xc3, 0x37, 0x61, 0xd0, 0xe7, 0x12, 0xe9, 0xc4, 0xde,
0xf2, 0x59, 0x11, 0xe3, 0x5b, 0x02, 0x9f, 0x24, 0xb9, 0xb0, 0xbb, 0x31,
0xa0, 0xee, 0x6a, 0x2c, 0xb4, 0x30, 0xff, 0xe0, 0xf0, 0x93, 0xee, 0x3a,
0xae, 0xb2, 0x2e, 0x84, 0xa0, 0x47, 0x42, 0x51, 0xbb, 0xfa, 0xbb, 0x90,
0x97, 0x2c, 0x77, 0x45, 0xee, 0x2c, 0xfb, 0xec, 0x5d, 0xd8, 0xca, 0x49,
0x94, 0x53, 0x5d, 0x37, 0xaf, 0x86, 0x47, 0xda, 0xe2, 0xbd, 0xf0, 0x5f,
0x07, 0x53, 0x8a, 0x10, 0xd0, 0x9a, 0xd0, 0x7f, 0xe9, 0xef, 0xf6, 0xda,
0xea, 0x1e, 0x2e, 0x54, 0xec, 0x44, 0xde, 0x3a, 0xe1, 0xc8, 0xdb, 0x17,
0xe8, 0xc9, 0x3a, 0x81, 0x11, 0x4d, 0xb7, 0x2d, 0x09, 0x83, 0xab, 0x30,
0xb7, 0xf5, 0x1b, 0x03, 0x86, 0x21, 0xa9, 0xf5, 0xca, 0x15, 0x26, 0xaf,
0x39, 0xf3, 0x5d, 0x01, 0x7d, 0xe3, 0x19, 0x54, 0xd1, 0x2e, 0x10, 0x16,
0x9c, 0xee, 0xc3, 0xbd, 0xcc, 0xdb, 0x02, 0x82, 0xd0, 0x60, 0x0b, 0x42,
0x72, 0x85, 0xec, 0xdc, 0x41, 0x7c, 0xf1, 0x34, 0xd8, 0x27, 0x21, 0xf9,
0xa6, 0x82, 0x40, 0xd3, 0xc5, 0xc9, 0xf9, 0x6b, 0xc9, 0x12, 0x64, 0xe4,
0x3a, 0x3b, 0xc9, 0x8f, 0x3c, 0xd0, 0x2c, 0xb8, 0xb8, 0xf3, 0x05, 0x4a,
0xe9, 0x4c, 0x46, 0x2b, 0xb6, 0xe1, 0xed, 0x82, 0xb2, 0xf0, 0xd1, 0x72,
0x71, 0x04, 0x35, 0x19, 0xc1, 0x16, 0x17, 0xd6, 0x75, 0xe0, 0xab, 0xde,
0x8f, 0xe1, 0xc1, 0x49, 0x68, 0x0c, 0xc8, 0xce, 0x6d, 0x87, 0x50, 0x04,
0xb5, 0xd7, 0x24, 0xf4, 0x2e, 0x0c, 0x11, 0x35, 0xb2, 0x67, 0x85, 0x1b,
0x38, 0xff, 0x2f, 0x71, 0xf5, 0x30, 0x18, 0x1e, 0x6f, 0xd7, 0xf0, 0x33,
0x61, 0x53, 0x7e, 0x55, 0x7f, 0x0d, 0x60, 0x83, 0xf3, 0x8a, 0x2b, 0x67,
0xd5, 0xf0, 0x2e, 0x23, 0x23, 0x60, 0x0b, 0x83, 0x9c, 0xc2, 0x87, 0x02,
0x03, 0x01, 0x00, 0x01, 0x48, 0x01, 0x12, 0x80, 0x03, 0x45, 0x3d, 0x03,
0x60, 0xd1, 0x13, 0x9e, 0xcd, 0x69, 0x5f, 0xd5, 0xa7, 0x62, 0x12, 0x28,
0x49, 0x4a, 0x73, 0x05, 0x1b, 0xf3, 0xd4, 0x4e, 0x54, 0x3f, 0x5f, 0x43,
0x2c, 0x17, 0x56, 0xbf, 0xc3, 0xb9, 0xe1, 0xb8, 0xb7, 0xc7, 0xd6, 0x52,
0x8e, 0xfb, 0x1c, 0x24, 0x9b, 0x84, 0x13, 0x08, 0xec, 0x0b, 0xd9, 0xfa,
0xe3, 0x9d, 0x37, 0x55, 0x72, 0x69, 0xfc, 0x39, 0x50, 0xbb, 0x49, 0x86,
0xe2, 0x85, 0x01, 0x20, 0x3e, 0x08, 0x2c, 0xdc, 0xee, 0x36, 0x04, 0xff,
0x24, 0x50, 0x88, 0x17, 0xfb, 0x8e, 0x86, 0xf6, 0xc5, 0xd6, 0xc5, 0x5b,
0x32, 0xe1, 0x3f, 0xff, 0x9c, 0x23, 0xd8, 0x84, 0x61, 0x26, 0x1d, 0x46,
0x82, 0x99, 0x3f, 0x1a, 0x5a, 0xc7, 0xd5, 0x97, 0x6d, 0xdb, 0x3a, 0x80,
0xef, 0x80, 0x2d, 0x11, 0x06, 0xf2, 0x14, 0x2b, 0x40, 0x61, 0x6f, 0x91,
0xea, 0x8a, 0xc5, 0xde, 0xad, 0x68, 0x31, 0xda, 0x11, 0x82, 0x11, 0x2b,
0x19, 0x3c, 0x89, 0xbc, 0x4a, 0xed, 0x87, 0x44, 0x1b, 0x79, 0xa9, 0x22,
0xb7, 0x81, 0xb3, 0xa9, 0xa2, 0x9b, 0x77, 0xf9, 0x40, 0x31, 0x4a, 0x9a,
0x5a, 0x9d, 0x56, 0xf9, 0x81, 0x2f, 0x9b, 0xe1, 0xd1, 0xca, 0xe7, 0xc5,
0xdc, 0x43, 0x92, 0x96, 0x5a, 0x22, 0x07, 0xcd, 0x0e, 0xec, 0x70, 0xe8,
0xd7, 0xdb, 0x52, 0xbe, 0x23, 0x23, 0x4c, 0xb8, 0x9e, 0x0a, 0x94, 0x64,
0xa7, 0xc8, 0xd8, 0x30, 0x78, 0xb9, 0x31, 0x8f, 0x5f, 0x98, 0x71, 0x24,
0xbd, 0xc2, 0xdc, 0x52, 0xf5, 0x0a, 0xf7, 0x0d, 0x48, 0x58, 0x6b, 0xdd,
0xa9, 0x95, 0xc6, 0x03, 0x13, 0x39, 0x87, 0xf8, 0x7a, 0x0e, 0x32, 0xd5,
0x77, 0x46, 0x59, 0x12, 0xae, 0x52, 0xd1, 0x48, 0xdf, 0x4c, 0xdd, 0xbf,
0xd7, 0xcc, 0x38, 0x1e, 0x07, 0x35, 0x3f, 0x1b, 0xe5, 0xa4, 0x2a, 0x01,
0x77, 0x22, 0xe6, 0x02, 0x90, 0x4d, 0x8b, 0x02, 0x75, 0x07, 0x36, 0xb0,
0xfa, 0x82, 0xf6, 0x7e, 0x74, 0xde, 0xba, 0xfa, 0x0e, 0x5a, 0x9a, 0x70,
0x50, 0xf4, 0x42, 0x05, 0xb1, 0xca, 0xc7, 0x18, 0xb7, 0x76, 0xff, 0x04,
0x8e, 0x2e, 0xe3, 0x44, 0x41, 0x38, 0x16, 0xa4, 0x34, 0x84, 0x66, 0x72,
0x0f, 0xc8, 0x2f, 0x9c, 0xe1, 0x5f, 0xe6, 0x35, 0x79, 0x64, 0x67, 0xa0,
0x53, 0x89, 0x4c, 0x51, 0xc8, 0x34, 0x6e, 0x70, 0xba, 0xfe, 0xdd, 0xca,
0xc2, 0xc6, 0x91, 0x8b, 0x08, 0x5e, 0x25, 0x96, 0xd0, 0x0d, 0xe7, 0xee,
0x25, 0x92, 0x39, 0xa3, 0xba, 0xa4, 0x0b, 0xab, 0xa4, 0x2e, 0x16, 0xfc,
0xad, 0xed, 0xcf, 0x12, 0xda, 0x9b, 0xe9, 0x67, 0x4d, 0xb2, 0x4e, 0xe9,
0xb3, 0xe8, 0x53, 0xc8, 0x5a, 0xc7, 0xbd, 0x69, 0xa7, 0x12, 0x4e, 0x43,
0x20, 0x62, 0x34, 0xb0, 0xbd, 0xb2, 0xea, 0x95, 0xf6,
};
const unsigned char kTestIntermediateCertificate[] = {
0x0a, 0xb1, 0x02, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18,
0xb2, 0x92, 0x04, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a,
0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd,
0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67,
0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d,
0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f,
0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f,
0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf,
0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73,
0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5,
0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13,
0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad,
0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57,
0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24,
0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06,
0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61,
0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8,
0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb,
0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b,
0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b,
0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d,
0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb,
0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01,
0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, 0x01, 0x12, 0x80, 0x03, 0x06,
0xe2, 0xc2, 0x94, 0x0e, 0x81, 0x87, 0x59, 0xe3, 0xe8, 0x15, 0x7f, 0xc6,
0xff, 0x6b, 0xc8, 0x7e, 0x0c, 0xd9, 0x9b, 0x40, 0x34, 0x22, 0x44, 0x00,
0xdf, 0x0e, 0x9e, 0xcd, 0xb9, 0x1d, 0x3d, 0xfe, 0x5a, 0xb9, 0x28, 0xdc,
0x94, 0x43, 0xc4, 0x1c, 0x66, 0xa9, 0x8a, 0xa4, 0x61, 0xdf, 0x8a, 0xf3,
0x7c, 0xf0, 0xbe, 0x66, 0xe9, 0xdf, 0x65, 0x93, 0x6c, 0xc7, 0xb5, 0x1a,
0x76, 0x07, 0x40, 0xde, 0xa1, 0xc5, 0x40, 0xde, 0xac, 0x5b, 0x9f, 0x32,
0xbb, 0xd4, 0xf2, 0x09, 0x13, 0x20, 0xbe, 0xee, 0xf4, 0xb5, 0xb0, 0xec,
0xeb, 0x1e, 0xfa, 0x03, 0x1b, 0x9d, 0x5a, 0xa0, 0x2f, 0x71, 0x1a, 0x76,
0xe7, 0x6f, 0x71, 0x7d, 0x3a, 0x7d, 0x8c, 0x46, 0xaf, 0x93, 0x94, 0x47,
0x27, 0xec, 0x1b, 0x1e, 0xd7, 0x8c, 0x7c, 0xec, 0x42, 0xaf, 0x55, 0x82,
0x3b, 0x6d, 0x07, 0x24, 0xb3, 0xfa, 0x2d, 0x1e, 0x12, 0x02, 0x94, 0x04,
0x23, 0xeb, 0xf3, 0x74, 0x04, 0x7e, 0x2a, 0x7f, 0x00, 0x34, 0x2b, 0x5c,
0x5b, 0x10, 0xe7, 0x36, 0x52, 0xde, 0x9f, 0x56, 0x10, 0xe3, 0x0b, 0xa5,
0x29, 0x85, 0xa5, 0x95, 0xed, 0xf5, 0x39, 0x0a, 0x03, 0x51, 0x29, 0x64,
0xa1, 0x4f, 0x38, 0xde, 0x3b, 0x4d, 0x0a, 0xf3, 0x7e, 0x37, 0x14, 0xce,
0xdf, 0x9d, 0x86, 0x16, 0xad, 0x62, 0xa8, 0xf8, 0xa7, 0xc2, 0xa4, 0xc1,
0xe2, 0xd6, 0x40, 0xa4, 0x7b, 0x20, 0x1b, 0x6d, 0x7c, 0x97, 0x0b, 0x73,
0x85, 0xbf, 0xdb, 0xc3, 0xa1, 0xf5, 0xd4, 0xb7, 0x95, 0xf2, 0xe7, 0x10,
0x77, 0xc6, 0x82, 0xb2, 0x68, 0x24, 0x31, 0xdc, 0x69, 0x43, 0x56, 0xf5,
0x76, 0x20, 0x0a, 0x82, 0x1a, 0x98, 0xb3, 0x02, 0x0f, 0x67, 0xcd, 0x4f,
0xab, 0x43, 0x44, 0xbd, 0xdb, 0x07, 0xd3, 0xff, 0x8b, 0x68, 0x33, 0x24,
0x35, 0xe5, 0xc6, 0x1a, 0x94, 0x14, 0x4f, 0x40, 0xef, 0x92, 0xfb, 0xfd,
0x72, 0x15, 0xd4, 0x10, 0x60, 0x22, 0x3e, 0x60, 0x49, 0x3d, 0x58, 0xc6,
0x3d, 0x28, 0x70, 0x55, 0x32, 0xd5, 0x78, 0x03, 0x51, 0xff, 0xd6, 0x4f,
0x4e, 0x89, 0x0e, 0x50, 0x85, 0x6e, 0x1c, 0x6a, 0x5f, 0x11, 0xd0, 0xf5,
0xee, 0xe5, 0x1c, 0xa8, 0xb2, 0xdb, 0x26, 0x93, 0xb1, 0xe2, 0xc1, 0x05,
0xe0, 0x7f, 0x16, 0xe7, 0x9c, 0xcf, 0xe7, 0xb7, 0x7e, 0xaa, 0x96, 0x21,
0x64, 0x39, 0x6d, 0x7a, 0xdc, 0x70, 0x6e, 0xc8, 0xf5, 0x44, 0x2e, 0x9f,
0xc1, 0xe9, 0x46, 0x8c, 0x1b, 0x58, 0xec, 0x73, 0x1b, 0x9a, 0x04, 0xcb,
0x68, 0x58, 0x21, 0x0e, 0xd6, 0xd7, 0x7a, 0x2b, 0x60, 0x02, 0x20, 0x7b,
0x85, 0xe5, 0x84, 0x2c, 0x5f, 0x24, 0x90, 0x2d, 0xc5, 0x19, 0xea, 0xf3,
0x91, 0x78, 0xc2, 0xa7, 0x36, 0x5a, 0x72, 0x64, 0x45, 0x13, 0x49,
};
const unsigned char kTestIntermediateCertificateWithECKey[] = {
0x0a, 0x9a, 0x01, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18,
0xb2, 0x92, 0x04, 0x22, 0x78, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00,
0x22, 0x03, 0x62, 0x00, 0x04, 0xb0, 0x50, 0x2a, 0x13, 0x20, 0x3e, 0x66,
0x67, 0xdf, 0x11, 0x2a, 0xbc, 0x0f, 0x76, 0x69, 0x4b, 0xa1, 0x88, 0xec,
0xb8, 0x71, 0xcf, 0xc9, 0xbb, 0xd2, 0xbc, 0xf8, 0x53, 0xfd, 0x8b, 0x8d,
0x14, 0x6f, 0xda, 0xea, 0x60, 0x51, 0xc8, 0xd3, 0x3a, 0xd4, 0x75, 0x81,
0x05, 0x16, 0x03, 0x0b, 0xcb, 0x33, 0x2c, 0x8b, 0xe6, 0xd3, 0x57, 0x6c,
0xfb, 0x81, 0x4b, 0xfe, 0x79, 0x56, 0xf7, 0x6a, 0x2b, 0xca, 0xa7, 0x04,
0xe9, 0x37, 0xd6, 0x49, 0xe5, 0x8b, 0x2c, 0xe9, 0x8e, 0xcd, 0xe7, 0xe3,
0xc9, 0xf5, 0x4c, 0x90, 0x82, 0x5f, 0xf0, 0x53, 0xd2, 0xa4, 0x1a, 0xb3,
0x53, 0x3d, 0xa7, 0xa7, 0xfd, 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48,
0x03, 0x12, 0x80, 0x03, 0x42, 0x90, 0xc4, 0x87, 0x0b, 0x55, 0x78, 0xb5,
0x25, 0x64, 0x23, 0xf2, 0x6a, 0x28, 0x7b, 0x1e, 0x12, 0xeb, 0x94, 0x08,
0x4f, 0xce, 0x6b, 0x53, 0x35, 0xda, 0xa6, 0xf3, 0x90, 0x3b, 0x1b, 0xa8,
0x2f, 0x17, 0x8e, 0x09, 0x12, 0x4b, 0xc6, 0x10, 0xfc, 0x8a, 0x63, 0xda,
0xf6, 0x7e, 0x18, 0x3e, 0x49, 0x4c, 0x85, 0x5b, 0x2c, 0xcb, 0x09, 0x67,
0x3b, 0xd3, 0xf3, 0x90, 0xe7, 0x4e, 0x06, 0x2f, 0x25, 0xbe, 0x22, 0x7f,
0xd6, 0x5c, 0xd5, 0xda, 0xac, 0x60, 0x29, 0x83, 0x53, 0x54, 0x73, 0x0d,
0x96, 0xca, 0x50, 0x6e, 0x45, 0xd6, 0x3c, 0xe6, 0xab, 0xf7, 0xe8, 0x69,
0x9e, 0xe2, 0x8e, 0xfd, 0x46, 0x11, 0x40, 0x9d, 0xfc, 0xd8, 0x2d, 0xe0,
0x94, 0xbc, 0x05, 0x74, 0x3c, 0x0a, 0xdd, 0x64, 0x37, 0x93, 0x9d, 0x5a,
0x08, 0xfe, 0x5f, 0xae, 0xa3, 0xc6, 0x48, 0xbd, 0x8a, 0x4e, 0x3c, 0xac,
0x7c, 0x66, 0xad, 0xc4, 0x7b, 0x7b, 0x89, 0xd9, 0xae, 0xf5, 0x8d, 0xf3,
0x0e, 0x3b, 0x1c, 0xb6, 0xf0, 0xff, 0x52, 0x22, 0xbc, 0xdd, 0x1e, 0xe5,
0x90, 0xe1, 0x09, 0xe2, 0x65, 0x42, 0x70, 0x4b, 0xfa, 0xf0, 0x41, 0x41,
0x53, 0xa2, 0x2c, 0x32, 0xc4, 0x1a, 0x42, 0x0d, 0xbe, 0x8d, 0x5b, 0x14,
0xae, 0x8f, 0xca, 0x85, 0xda, 0xfb, 0xe1, 0x25, 0x71, 0xc6, 0x8a, 0x3c,
0xe1, 0x99, 0x09, 0x30, 0x9d, 0xa7, 0xec, 0x10, 0x7b, 0x43, 0xee, 0xf8,
0xa5, 0x58, 0x9d, 0xd7, 0x31, 0x6a, 0x22, 0x45, 0xf5, 0x0c, 0x30, 0xb2,
0x77, 0x05, 0x13, 0x10, 0xfd, 0xc1, 0xf9, 0x13, 0xc2, 0x88, 0xc8, 0x71,
0xd9, 0x14, 0x5f, 0xc9, 0xde, 0x96, 0xe7, 0x55, 0xb9, 0x4a, 0xb0, 0x18,
0x22, 0x17, 0x9f, 0x95, 0xe2, 0xa7, 0x66, 0x9b, 0xfd, 0x38, 0xf9, 0x5c,
0xa0, 0xaa, 0xf4, 0x60, 0xee, 0x00, 0x53, 0x87, 0x29, 0x63, 0x53, 0x55,
0xfb, 0x32, 0x7a, 0x80, 0x56, 0xea, 0xaa, 0x95, 0x22, 0x08, 0x9e, 0x25,
0x53, 0x50, 0xb4, 0xd0, 0x07, 0x3c, 0x29, 0x3f, 0x03, 0xab, 0x68, 0xf5,
0xa5, 0xc6, 0xd2, 0x73, 0xf6, 0xee, 0xa2, 0x6c, 0xec, 0xd4, 0xf3, 0x20,
0xdc, 0x56, 0x00, 0x3d, 0xea, 0x57, 0x14, 0xc7, 0x90, 0x86, 0x82, 0x1b,
0x14, 0x57, 0x68, 0xec, 0x24, 0x0e, 0x8d, 0x6b, 0xcc, 0x5f, 0x7a, 0x53,
0xac, 0x60, 0x20, 0x5f, 0xe7, 0x79, 0xb6, 0x2c, 0xfb, 0x23, 0xa3, 0x43,
0x91, 0x0f, 0x53, 0x38, 0x0e, 0xcc, 0x27, 0xaf, 0x57, 0x01, 0x26, 0xd8,
0x01, 0x41, 0x27, 0x63, 0xca, 0x9f, 0xf5, 0xa7, 0x43, 0x26, 0x74, 0x59,
0xec, 0xce, 0x71, 0x09, 0x0d, 0xda, 0x5d, 0x63, 0xef, 0xfd, 0x6e, 0x92,
0x53, 0x12, 0xbc, 0x6a, 0x5b, 0x4d, 0x4a, 0x43, 0x04, 0x5d, 0x8e, 0x93,
0xd7, 0x89, 0x21, 0xff,
};
const unsigned char kTestUserDrmCertificate[] = {
0x0a, 0xc3, 0x02, 0x08, 0x02, 0x12, 0x10, 0x46, 0x45, 0x44, 0x43, 0x42,
0x41, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x18,
0x91, 0xab, 0x4b, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51,
0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d,
0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c,
0x61, 0x36, 0x44, 0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32,
0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7,
0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3,
0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7,
0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc,
0x95, 0x47, 0x94, 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93,
0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99,
0xee, 0x03, 0x68, 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc,
0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6,
0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a,
0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44,
0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec,
0x24, 0x05, 0x06, 0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea,
0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e,
0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94,
0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8,
0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16,
0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd,
0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01,
0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65,
0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x48, 0x01, 0x12, 0x80, 0x02, 0x23, 0x61, 0xfb, 0xd0, 0xf4, 0xcf, 0xf2,
0x58, 0xd7, 0xb0, 0x79, 0x4e, 0x4e, 0xf3, 0x2c, 0x83, 0x63, 0x34, 0x6c,
0x49, 0x80, 0xdd, 0x85, 0xf4, 0xa5, 0x23, 0x89, 0x95, 0x0c, 0x8f, 0xf6,
0xc6, 0xdc, 0x90, 0x8b, 0x83, 0xd3, 0x0b, 0x1c, 0x34, 0xd2, 0xa0, 0x08,
0xdc, 0x05, 0x76, 0x8f, 0xff, 0xa3, 0x2e, 0xf8, 0x93, 0x9e, 0xe6, 0xf3,
0x62, 0x0f, 0x70, 0x1c, 0x31, 0x15, 0xbb, 0x98, 0xf4, 0xa6, 0x22, 0x2c,
0x90, 0x59, 0xc2, 0x16, 0x48, 0xe0, 0x5a, 0xb8, 0x94, 0x6f, 0xde, 0x80,
0xaf, 0x83, 0x8e, 0x77, 0x6a, 0xa4, 0xf4, 0x9b, 0xf8, 0x76, 0xd1, 0x1b,
0x6d, 0x87, 0x85, 0x35, 0xd9, 0xd0, 0x62, 0x55, 0xfe, 0x11, 0xed, 0x4a,
0x6c, 0xc9, 0x14, 0x67, 0x72, 0xb6, 0x46, 0x56, 0xbc, 0x81, 0xac, 0xe6,
0xf0, 0x7a, 0x0e, 0x57, 0x95, 0x4d, 0x53, 0xf5, 0x33, 0x2e, 0xa5, 0x7e,
0x71, 0x8e, 0x04, 0x64, 0x50, 0x88, 0x6b, 0xb9, 0x6e, 0xbc, 0x6b, 0x74,
0xfc, 0x69, 0xa3, 0x81, 0x30, 0x1f, 0xac, 0x9d, 0x7b, 0xa0, 0xf5, 0x7f,
0x42, 0xfd, 0x14, 0xca, 0x89, 0x5b, 0xb0, 0xcd, 0xa2, 0x4b, 0xef, 0xcf,
0x84, 0x8f, 0xe8, 0xe4, 0xf7, 0xd2, 0x63, 0xe2, 0x95, 0x94, 0x45, 0xd5,
0xc2, 0xe3, 0x99, 0xfc, 0x34, 0xcb, 0x6a, 0x15, 0x74, 0x6e, 0x16, 0xe3,
0x6f, 0x8e, 0xe7, 0x9b, 0x01, 0xed, 0x7f, 0xf8, 0x90, 0xc6, 0x87, 0xf4,
0x9e, 0x45, 0x64, 0x09, 0xf9, 0xaa, 0x46, 0xe4, 0x83, 0x3b, 0x4f, 0x36,
0xdb, 0x32, 0x72, 0x00, 0xcf, 0x3c, 0x4c, 0x41, 0x67, 0x59, 0xf2, 0x93,
0xff, 0x4e, 0x07, 0x22, 0x6e, 0x5a, 0x03, 0xf5, 0xe1, 0x48, 0x72, 0x9d,
0x2f, 0xfc, 0xcd, 0x38, 0x5f, 0x2d, 0x69, 0x47, 0xd3, 0xa8, 0x09, 0x8e,
0xd5, 0x9b, 0x24, 0x45, 0x43, 0x08, 0xca, 0xc6, 0xed, 0x1a, 0xb7, 0x05,
0x0a, 0xb1, 0x02, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18,
0xb2, 0x92, 0x04, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a,
0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd,
0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67,
0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d,
0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f,
0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f,
0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf,
0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73,
0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5,
0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13,
0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad,
0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57,
0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24,
0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06,
0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61,
0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8,
0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb,
0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b,
0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b,
0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d,
0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb,
0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01,
0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, 0x01, 0x12, 0x80, 0x03, 0x06,
0xe2, 0xc2, 0x94, 0x0e, 0x81, 0x87, 0x59, 0xe3, 0xe8, 0x15, 0x7f, 0xc6,
0xff, 0x6b, 0xc8, 0x7e, 0x0c, 0xd9, 0x9b, 0x40, 0x34, 0x22, 0x44, 0x00,
0xdf, 0x0e, 0x9e, 0xcd, 0xb9, 0x1d, 0x3d, 0xfe, 0x5a, 0xb9, 0x28, 0xdc,
0x94, 0x43, 0xc4, 0x1c, 0x66, 0xa9, 0x8a, 0xa4, 0x61, 0xdf, 0x8a, 0xf3,
0x7c, 0xf0, 0xbe, 0x66, 0xe9, 0xdf, 0x65, 0x93, 0x6c, 0xc7, 0xb5, 0x1a,
0x76, 0x07, 0x40, 0xde, 0xa1, 0xc5, 0x40, 0xde, 0xac, 0x5b, 0x9f, 0x32,
0xbb, 0xd4, 0xf2, 0x09, 0x13, 0x20, 0xbe, 0xee, 0xf4, 0xb5, 0xb0, 0xec,
0xeb, 0x1e, 0xfa, 0x03, 0x1b, 0x9d, 0x5a, 0xa0, 0x2f, 0x71, 0x1a, 0x76,
0xe7, 0x6f, 0x71, 0x7d, 0x3a, 0x7d, 0x8c, 0x46, 0xaf, 0x93, 0x94, 0x47,
0x27, 0xec, 0x1b, 0x1e, 0xd7, 0x8c, 0x7c, 0xec, 0x42, 0xaf, 0x55, 0x82,
0x3b, 0x6d, 0x07, 0x24, 0xb3, 0xfa, 0x2d, 0x1e, 0x12, 0x02, 0x94, 0x04,
0x23, 0xeb, 0xf3, 0x74, 0x04, 0x7e, 0x2a, 0x7f, 0x00, 0x34, 0x2b, 0x5c,
0x5b, 0x10, 0xe7, 0x36, 0x52, 0xde, 0x9f, 0x56, 0x10, 0xe3, 0x0b, 0xa5,
0x29, 0x85, 0xa5, 0x95, 0xed, 0xf5, 0x39, 0x0a, 0x03, 0x51, 0x29, 0x64,
0xa1, 0x4f, 0x38, 0xde, 0x3b, 0x4d, 0x0a, 0xf3, 0x7e, 0x37, 0x14, 0xce,
0xdf, 0x9d, 0x86, 0x16, 0xad, 0x62, 0xa8, 0xf8, 0xa7, 0xc2, 0xa4, 0xc1,
0xe2, 0xd6, 0x40, 0xa4, 0x7b, 0x20, 0x1b, 0x6d, 0x7c, 0x97, 0x0b, 0x73,
0x85, 0xbf, 0xdb, 0xc3, 0xa1, 0xf5, 0xd4, 0xb7, 0x95, 0xf2, 0xe7, 0x10,
0x77, 0xc6, 0x82, 0xb2, 0x68, 0x24, 0x31, 0xdc, 0x69, 0x43, 0x56, 0xf5,
0x76, 0x20, 0x0a, 0x82, 0x1a, 0x98, 0xb3, 0x02, 0x0f, 0x67, 0xcd, 0x4f,
0xab, 0x43, 0x44, 0xbd, 0xdb, 0x07, 0xd3, 0xff, 0x8b, 0x68, 0x33, 0x24,
0x35, 0xe5, 0xc6, 0x1a, 0x94, 0x14, 0x4f, 0x40, 0xef, 0x92, 0xfb, 0xfd,
0x72, 0x15, 0xd4, 0x10, 0x60, 0x22, 0x3e, 0x60, 0x49, 0x3d, 0x58, 0xc6,
0x3d, 0x28, 0x70, 0x55, 0x32, 0xd5, 0x78, 0x03, 0x51, 0xff, 0xd6, 0x4f,
0x4e, 0x89, 0x0e, 0x50, 0x85, 0x6e, 0x1c, 0x6a, 0x5f, 0x11, 0xd0, 0xf5,
0xee, 0xe5, 0x1c, 0xa8, 0xb2, 0xdb, 0x26, 0x93, 0xb1, 0xe2, 0xc1, 0x05,
0xe0, 0x7f, 0x16, 0xe7, 0x9c, 0xcf, 0xe7, 0xb7, 0x7e, 0xaa, 0x96, 0x21,
0x64, 0x39, 0x6d, 0x7a, 0xdc, 0x70, 0x6e, 0xc8, 0xf5, 0x44, 0x2e, 0x9f,
0xc1, 0xe9, 0x46, 0x8c, 0x1b, 0x58, 0xec, 0x73, 0x1b, 0x9a, 0x04, 0xcb,
0x68, 0x58, 0x21, 0x0e, 0xd6, 0xd7, 0x7a, 0x2b, 0x60, 0x02, 0x20, 0x7b,
0x85, 0xe5, 0x84, 0x2c, 0x5f, 0x24, 0x90, 0x2d, 0xc5, 0x19, 0xea, 0xf3,
0x91, 0x78, 0xc2, 0xa7, 0x36, 0x5a, 0x72, 0x64, 0x45, 0x13, 0x49,
};
const unsigned char kTestUserDrmCertificateWithECKey[] = {
0x0a, 0x8f, 0x01, 0x08, 0x02, 0x12, 0x10, 0x46, 0x45, 0x44, 0x43, 0x42,
0x41, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x18,
0x91, 0xab, 0x4b, 0x22, 0x5b, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x8a, 0xea, 0x3f, 0x16,
0xff, 0x24, 0xa9, 0xbf, 0x03, 0x28, 0x30, 0x15, 0xee, 0x52, 0x50, 0x9a,
0x55, 0x1c, 0x60, 0xc7, 0xa7, 0xcc, 0x4b, 0x99, 0x5b, 0x40, 0x55, 0xce,
0x46, 0x19, 0xd4, 0xd4, 0x5e, 0xfd, 0xe0, 0x68, 0x27, 0xea, 0x78, 0xf3,
0x07, 0x1f, 0x02, 0x4a, 0x78, 0x52, 0x44, 0xd3, 0xdf, 0xbe, 0xac, 0x5f,
0xa5, 0x1c, 0x8a, 0x49, 0x8d, 0xa6, 0x5a, 0xac, 0xa1, 0x25, 0x2b, 0xd1,
0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65,
0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x48, 0x02, 0x12, 0x66, 0x30, 0x64, 0x02, 0x30, 0x4c, 0x7a, 0x79, 0x4a,
0x18, 0xf2, 0x2f, 0x9f, 0x29, 0x3b, 0x6f, 0x8f, 0x8f, 0xe4, 0xe0, 0xf2,
0xd9, 0x38, 0x18, 0x8a, 0x9a, 0x88, 0x85, 0x95, 0x72, 0xb7, 0x3c, 0xb6,
0x47, 0xa4, 0x6b, 0x0a, 0x56, 0x4a, 0x38, 0x1d, 0x2f, 0x4a, 0xc6, 0x61,
0x97, 0x35, 0x81, 0x87, 0x4b, 0xca, 0xdc, 0x20, 0x02, 0x30, 0x28, 0x4e,
0xf1, 0x23, 0x6d, 0x3f, 0x4f, 0x29, 0x29, 0x86, 0x75, 0x46, 0x83, 0x03,
0xa0, 0xe7, 0x23, 0x07, 0x2b, 0x28, 0x4d, 0xa9, 0x72, 0xb6, 0x5e, 0x3b,
0xd2, 0x90, 0x05, 0xd3, 0x33, 0x35, 0x99, 0xdc, 0xe9, 0x54, 0xa0, 0x6e,
0xca, 0x38, 0x63, 0x4d, 0x95, 0xab, 0x99, 0x77, 0x87, 0x38, 0x1a, 0xa0,
0x04, 0x0a, 0x9a, 0x01, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x18, 0xb2, 0x92, 0x04, 0x22, 0x78, 0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
0x00, 0x22, 0x03, 0x62, 0x00, 0x04, 0xb0, 0x50, 0x2a, 0x13, 0x20, 0x3e,
0x66, 0x67, 0xdf, 0x11, 0x2a, 0xbc, 0x0f, 0x76, 0x69, 0x4b, 0xa1, 0x88,
0xec, 0xb8, 0x71, 0xcf, 0xc9, 0xbb, 0xd2, 0xbc, 0xf8, 0x53, 0xfd, 0x8b,
0x8d, 0x14, 0x6f, 0xda, 0xea, 0x60, 0x51, 0xc8, 0xd3, 0x3a, 0xd4, 0x75,
0x81, 0x05, 0x16, 0x03, 0x0b, 0xcb, 0x33, 0x2c, 0x8b, 0xe6, 0xd3, 0x57,
0x6c, 0xfb, 0x81, 0x4b, 0xfe, 0x79, 0x56, 0xf7, 0x6a, 0x2b, 0xca, 0xa7,
0x04, 0xe9, 0x37, 0xd6, 0x49, 0xe5, 0x8b, 0x2c, 0xe9, 0x8e, 0xcd, 0xe7,
0xe3, 0xc9, 0xf5, 0x4c, 0x90, 0x82, 0x5f, 0xf0, 0x53, 0xd2, 0xa4, 0x1a,
0xb3, 0x53, 0x3d, 0xa7, 0xa7, 0xfd, 0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04,
0x48, 0x03, 0x12, 0x80, 0x03, 0x42, 0x90, 0xc4, 0x87, 0x0b, 0x55, 0x78,
0xb5, 0x25, 0x64, 0x23, 0xf2, 0x6a, 0x28, 0x7b, 0x1e, 0x12, 0xeb, 0x94,
0x08, 0x4f, 0xce, 0x6b, 0x53, 0x35, 0xda, 0xa6, 0xf3, 0x90, 0x3b, 0x1b,
0xa8, 0x2f, 0x17, 0x8e, 0x09, 0x12, 0x4b, 0xc6, 0x10, 0xfc, 0x8a, 0x63,
0xda, 0xf6, 0x7e, 0x18, 0x3e, 0x49, 0x4c, 0x85, 0x5b, 0x2c, 0xcb, 0x09,
0x67, 0x3b, 0xd3, 0xf3, 0x90, 0xe7, 0x4e, 0x06, 0x2f, 0x25, 0xbe, 0x22,
0x7f, 0xd6, 0x5c, 0xd5, 0xda, 0xac, 0x60, 0x29, 0x83, 0x53, 0x54, 0x73,
0x0d, 0x96, 0xca, 0x50, 0x6e, 0x45, 0xd6, 0x3c, 0xe6, 0xab, 0xf7, 0xe8,
0x69, 0x9e, 0xe2, 0x8e, 0xfd, 0x46, 0x11, 0x40, 0x9d, 0xfc, 0xd8, 0x2d,
0xe0, 0x94, 0xbc, 0x05, 0x74, 0x3c, 0x0a, 0xdd, 0x64, 0x37, 0x93, 0x9d,
0x5a, 0x08, 0xfe, 0x5f, 0xae, 0xa3, 0xc6, 0x48, 0xbd, 0x8a, 0x4e, 0x3c,
0xac, 0x7c, 0x66, 0xad, 0xc4, 0x7b, 0x7b, 0x89, 0xd9, 0xae, 0xf5, 0x8d,
0xf3, 0x0e, 0x3b, 0x1c, 0xb6, 0xf0, 0xff, 0x52, 0x22, 0xbc, 0xdd, 0x1e,
0xe5, 0x90, 0xe1, 0x09, 0xe2, 0x65, 0x42, 0x70, 0x4b, 0xfa, 0xf0, 0x41,
0x41, 0x53, 0xa2, 0x2c, 0x32, 0xc4, 0x1a, 0x42, 0x0d, 0xbe, 0x8d, 0x5b,
0x14, 0xae, 0x8f, 0xca, 0x85, 0xda, 0xfb, 0xe1, 0x25, 0x71, 0xc6, 0x8a,
0x3c, 0xe1, 0x99, 0x09, 0x30, 0x9d, 0xa7, 0xec, 0x10, 0x7b, 0x43, 0xee,
0xf8, 0xa5, 0x58, 0x9d, 0xd7, 0x31, 0x6a, 0x22, 0x45, 0xf5, 0x0c, 0x30,
0xb2, 0x77, 0x05, 0x13, 0x10, 0xfd, 0xc1, 0xf9, 0x13, 0xc2, 0x88, 0xc8,
0x71, 0xd9, 0x14, 0x5f, 0xc9, 0xde, 0x96, 0xe7, 0x55, 0xb9, 0x4a, 0xb0,
0x18, 0x22, 0x17, 0x9f, 0x95, 0xe2, 0xa7, 0x66, 0x9b, 0xfd, 0x38, 0xf9,
0x5c, 0xa0, 0xaa, 0xf4, 0x60, 0xee, 0x00, 0x53, 0x87, 0x29, 0x63, 0x53,
0x55, 0xfb, 0x32, 0x7a, 0x80, 0x56, 0xea, 0xaa, 0x95, 0x22, 0x08, 0x9e,
0x25, 0x53, 0x50, 0xb4, 0xd0, 0x07, 0x3c, 0x29, 0x3f, 0x03, 0xab, 0x68,
0xf5, 0xa5, 0xc6, 0xd2, 0x73, 0xf6, 0xee, 0xa2, 0x6c, 0xec, 0xd4, 0xf3,
0x20, 0xdc, 0x56, 0x00, 0x3d, 0xea, 0x57, 0x14, 0xc7, 0x90, 0x86, 0x82,
0x1b, 0x14, 0x57, 0x68, 0xec, 0x24, 0x0e, 0x8d, 0x6b, 0xcc, 0x5f, 0x7a,
0x53, 0xac, 0x60, 0x20, 0x5f, 0xe7, 0x79, 0xb6, 0x2c, 0xfb, 0x23, 0xa3,
0x43, 0x91, 0x0f, 0x53, 0x38, 0x0e, 0xcc, 0x27, 0xaf, 0x57, 0x01, 0x26,
0xd8, 0x01, 0x41, 0x27, 0x63, 0xca, 0x9f, 0xf5, 0xa7, 0x43, 0x26, 0x74,
0x59, 0xec, 0xce, 0x71, 0x09, 0x0d, 0xda, 0x5d, 0x63, 0xef, 0xfd, 0x6e,
0x92, 0x53, 0x12, 0xbc, 0x6a, 0x5b, 0x4d, 0x4a, 0x43, 0x04, 0x5d, 0x8e,
0x93, 0xd7, 0x89, 0x21, 0xff,
};
const unsigned char kTestUserDrmCertificateWithRotId[] = {
0x0a, 0xdf, 0x03, 0x08, 0x02, 0x12, 0x10, 0x46, 0x45, 0x44, 0x43, 0x42,
0x41, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x18,
0x91, 0xab, 0x4b, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xa5, 0xd0, 0xd7, 0x3e, 0x0e, 0x2d, 0xfb, 0x43, 0x51,
0x99, 0xea, 0x40, 0x1e, 0x2d, 0x89, 0xe4, 0xa2, 0x3e, 0xfc, 0x51, 0x3d,
0x0e, 0x83, 0xa7, 0xe0, 0xa5, 0x41, 0x04, 0x1e, 0x14, 0xc5, 0xa7, 0x5c,
0x61, 0x36, 0x44, 0xb3, 0x08, 0x05, 0x5b, 0x14, 0xde, 0x01, 0x0c, 0x32,
0x3c, 0x9a, 0x91, 0x00, 0x50, 0xa8, 0x1d, 0xcc, 0x9f, 0x8f, 0x35, 0xb7,
0xc2, 0x75, 0x08, 0x32, 0x8b, 0x10, 0x3a, 0x86, 0xf9, 0xd7, 0x78, 0xa3,
0x9d, 0x74, 0x10, 0xc6, 0x24, 0xb1, 0x7f, 0xa5, 0xbf, 0x5f, 0xc2, 0xd7,
0x15, 0xa3, 0x1d, 0xe0, 0x15, 0x6b, 0x1b, 0x0e, 0x38, 0xba, 0x34, 0xbc,
0x95, 0x47, 0x94, 0x40, 0x70, 0xac, 0x99, 0x1f, 0x0b, 0x8e, 0x56, 0x93,
0x36, 0x2b, 0x6d, 0x04, 0xe7, 0x95, 0x1a, 0x37, 0xda, 0x16, 0x57, 0x99,
0xee, 0x03, 0x68, 0x16, 0x31, 0xaa, 0xc3, 0xb7, 0x92, 0x75, 0x53, 0xfc,
0xf6, 0x20, 0x55, 0x44, 0xf8, 0xd4, 0x8d, 0x78, 0x15, 0xc7, 0x1a, 0xb6,
0xde, 0x6c, 0xe8, 0x49, 0x5d, 0xaf, 0xa8, 0x4e, 0x6f, 0x7c, 0xe2, 0x6a,
0x4c, 0xd5, 0xe7, 0x8c, 0x8f, 0x0b, 0x5d, 0x3a, 0x09, 0xd6, 0xb3, 0x44,
0xab, 0xe0, 0x35, 0x52, 0x7c, 0x66, 0x85, 0xa4, 0x40, 0xd7, 0x20, 0xec,
0x24, 0x05, 0x06, 0xd9, 0x84, 0x51, 0x5a, 0xd2, 0x38, 0xd5, 0x1d, 0xea,
0x70, 0x2a, 0x21, 0xe6, 0x82, 0xfd, 0xa4, 0x46, 0x1c, 0x4f, 0x59, 0x6e,
0x29, 0x3d, 0xae, 0xb8, 0x8e, 0xee, 0x77, 0x1f, 0x15, 0x33, 0xcf, 0x94,
0x1d, 0x87, 0x3c, 0x37, 0xc5, 0x89, 0xe8, 0x7d, 0x85, 0xb3, 0xbc, 0xe8,
0x62, 0x6a, 0x84, 0x7f, 0xfe, 0x9a, 0x85, 0x3f, 0x39, 0xe8, 0xaa, 0x16,
0xa6, 0x8f, 0x87, 0x7f, 0xcb, 0xc1, 0xd6, 0xf2, 0xec, 0x2b, 0xa7, 0xdd,
0x49, 0x98, 0x7b, 0x6f, 0xdd, 0x69, 0x6d, 0x02, 0x03, 0x01, 0x00, 0x01,
0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65,
0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
0x48, 0x01, 0x52, 0x99, 0x01, 0x08, 0x01, 0x10, 0x00, 0x1a, 0x71, 0x04,
0x8a, 0xea, 0x3f, 0x16, 0xff, 0x24, 0xa9, 0xbf, 0x03, 0x28, 0x30, 0x15,
0xee, 0x52, 0x50, 0x9a, 0x55, 0x1c, 0x60, 0xc7, 0xa7, 0xcc, 0x4b, 0x99,
0x5b, 0x40, 0x55, 0xce, 0x46, 0x19, 0xd4, 0xd4, 0x5e, 0xfd, 0xe0, 0x68,
0x27, 0xea, 0x78, 0xf3, 0x07, 0x1f, 0x02, 0x4a, 0x78, 0x52, 0x44, 0xd3,
0xdf, 0xbe, 0xac, 0x5f, 0xa5, 0x1c, 0x8a, 0x49, 0x8d, 0xa6, 0x5a, 0xac,
0xa1, 0x25, 0x2b, 0xd1, 0xd9, 0xeb, 0xa7, 0x91, 0x26, 0x46, 0x3a, 0xe4,
0x5b, 0x06, 0x6b, 0x77, 0x83, 0xa9, 0x0f, 0xa3, 0xf3, 0x2a, 0x39, 0x36,
0xc1, 0xbd, 0x37, 0xeb, 0xd7, 0x83, 0x3e, 0xbd, 0x17, 0x53, 0x82, 0x69,
0xc3, 0xe4, 0x48, 0xb5, 0x0d, 0x8c, 0xe1, 0x30, 0x17, 0xef, 0x01, 0x88,
0x30, 0x62, 0x5a, 0xb3, 0x22, 0x20, 0x91, 0x69, 0x9e, 0xbc, 0xa2, 0x5c,
0xd4, 0x51, 0x79, 0xfd, 0xbc, 0x2f, 0x92, 0xcd, 0x48, 0x2d, 0xd3, 0x30,
0xe6, 0x1e, 0xbd, 0x4e, 0x23, 0x96, 0x2b, 0xb0, 0x3a, 0xfc, 0xb4, 0x7b,
0x0e, 0x3d, 0x12, 0x80, 0x02, 0xa0, 0xe0, 0x2b, 0x1d, 0xe4, 0x28, 0x7b,
0x57, 0x64, 0x3f, 0xe2, 0xf7, 0x10, 0xda, 0x97, 0x7f, 0x49, 0xf4, 0xd2,
0x57, 0xc5, 0xf5, 0xe1, 0xd9, 0xd9, 0xbb, 0x34, 0xac, 0x90, 0x0c, 0xfa,
0x9f, 0x0d, 0xd7, 0x14, 0xfc, 0xbb, 0xc9, 0xfa, 0xa5, 0x41, 0xd8, 0x87,
0xa5, 0xef, 0x39, 0xf8, 0x70, 0x4f, 0x93, 0xfc, 0xb8, 0x62, 0xb8, 0x7e,
0x6e, 0x9f, 0x25, 0xe9, 0x47, 0x08, 0xe6, 0x89, 0xe9, 0xc2, 0x41, 0x6a,
0xc6, 0x0f, 0x84, 0x71, 0xa7, 0x90, 0xf2, 0x86, 0x7b, 0xbc, 0x99, 0xca,
0xf1, 0xd4, 0xa5, 0xc0, 0x9f, 0x4e, 0x53, 0x27, 0xde, 0x3e, 0x4b, 0x7b,
0x7d, 0x6a, 0xa4, 0xaa, 0x53, 0x9c, 0x4f, 0xff, 0xf6, 0x61, 0xbe, 0x4d,
0xa7, 0x9b, 0xa6, 0xc9, 0xb1, 0x00, 0x57, 0xd6, 0x47, 0xb2, 0x0e, 0xf6,
0x56, 0x1b, 0xc3, 0x7d, 0xe0, 0x97, 0x85, 0x93, 0xe9, 0xa4, 0x43, 0xfa,
0x02, 0xd9, 0x40, 0x97, 0x22, 0x86, 0x15, 0xd8, 0x24, 0x92, 0x35, 0x32,
0x15, 0xc2, 0x19, 0xbc, 0x32, 0x21, 0x3f, 0x8c, 0xdf, 0x9f, 0x5c, 0x3a,
0x57, 0x73, 0x4f, 0x25, 0x3b, 0xa1, 0x88, 0x6f, 0xbb, 0x4a, 0xb7, 0xe5,
0xc6, 0x33, 0x1b, 0x59, 0xa9, 0xe9, 0xc3, 0x0b, 0xdb, 0xe9, 0x41, 0xb0,
0x06, 0x49, 0xdf, 0x0a, 0xa9, 0x85, 0xf5, 0xc7, 0xe6, 0x2c, 0x20, 0x25,
0x50, 0x45, 0xf2, 0x86, 0x57, 0xdb, 0x3f, 0x28, 0x0b, 0xd6, 0xc4, 0xac,
0xb0, 0x1c, 0xc3, 0xed, 0x7a, 0x8d, 0xa9, 0x83, 0x20, 0x43, 0xc7, 0x42,
0x03, 0xca, 0x23, 0xc8, 0xf7, 0xbf, 0x2e, 0x70, 0x9a, 0xff, 0x23, 0xff,
0x17, 0x22, 0xca, 0xe0, 0x58, 0x2f, 0xd3, 0x0d, 0xa4, 0xa2, 0x90, 0x6c,
0xf1, 0x78, 0x7c, 0xee, 0x1a, 0xe7, 0x0c, 0xe2, 0x89, 0xf0, 0x5b, 0x9a,
0x24, 0x4e, 0x10, 0xcf, 0x58, 0xa1, 0xdb, 0x3f, 0x1b, 0x1a, 0xb7, 0x05,
0x0a, 0xb1, 0x02, 0x08, 0x01, 0x12, 0x10, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x18,
0xb2, 0x92, 0x04, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82,
0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a,
0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd,
0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67,
0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d,
0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f,
0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f,
0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf,
0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73,
0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5,
0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13,
0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad,
0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57,
0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24,
0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06,
0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61,
0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8,
0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb,
0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b,
0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b,
0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d,
0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb,
0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01,
0x28, 0xd2, 0x85, 0xd8, 0xcc, 0x04, 0x48, 0x01, 0x12, 0x80, 0x03, 0x06,
0xe2, 0xc2, 0x94, 0x0e, 0x81, 0x87, 0x59, 0xe3, 0xe8, 0x15, 0x7f, 0xc6,
0xff, 0x6b, 0xc8, 0x7e, 0x0c, 0xd9, 0x9b, 0x40, 0x34, 0x22, 0x44, 0x00,
0xdf, 0x0e, 0x9e, 0xcd, 0xb9, 0x1d, 0x3d, 0xfe, 0x5a, 0xb9, 0x28, 0xdc,
0x94, 0x43, 0xc4, 0x1c, 0x66, 0xa9, 0x8a, 0xa4, 0x61, 0xdf, 0x8a, 0xf3,
0x7c, 0xf0, 0xbe, 0x66, 0xe9, 0xdf, 0x65, 0x93, 0x6c, 0xc7, 0xb5, 0x1a,
0x76, 0x07, 0x40, 0xde, 0xa1, 0xc5, 0x40, 0xde, 0xac, 0x5b, 0x9f, 0x32,
0xbb, 0xd4, 0xf2, 0x09, 0x13, 0x20, 0xbe, 0xee, 0xf4, 0xb5, 0xb0, 0xec,
0xeb, 0x1e, 0xfa, 0x03, 0x1b, 0x9d, 0x5a, 0xa0, 0x2f, 0x71, 0x1a, 0x76,
0xe7, 0x6f, 0x71, 0x7d, 0x3a, 0x7d, 0x8c, 0x46, 0xaf, 0x93, 0x94, 0x47,
0x27, 0xec, 0x1b, 0x1e, 0xd7, 0x8c, 0x7c, 0xec, 0x42, 0xaf, 0x55, 0x82,
0x3b, 0x6d, 0x07, 0x24, 0xb3, 0xfa, 0x2d, 0x1e, 0x12, 0x02, 0x94, 0x04,
0x23, 0xeb, 0xf3, 0x74, 0x04, 0x7e, 0x2a, 0x7f, 0x00, 0x34, 0x2b, 0x5c,
0x5b, 0x10, 0xe7, 0x36, 0x52, 0xde, 0x9f, 0x56, 0x10, 0xe3, 0x0b, 0xa5,
0x29, 0x85, 0xa5, 0x95, 0xed, 0xf5, 0x39, 0x0a, 0x03, 0x51, 0x29, 0x64,
0xa1, 0x4f, 0x38, 0xde, 0x3b, 0x4d, 0x0a, 0xf3, 0x7e, 0x37, 0x14, 0xce,
0xdf, 0x9d, 0x86, 0x16, 0xad, 0x62, 0xa8, 0xf8, 0xa7, 0xc2, 0xa4, 0xc1,
0xe2, 0xd6, 0x40, 0xa4, 0x7b, 0x20, 0x1b, 0x6d, 0x7c, 0x97, 0x0b, 0x73,
0x85, 0xbf, 0xdb, 0xc3, 0xa1, 0xf5, 0xd4, 0xb7, 0x95, 0xf2, 0xe7, 0x10,
0x77, 0xc6, 0x82, 0xb2, 0x68, 0x24, 0x31, 0xdc, 0x69, 0x43, 0x56, 0xf5,
0x76, 0x20, 0x0a, 0x82, 0x1a, 0x98, 0xb3, 0x02, 0x0f, 0x67, 0xcd, 0x4f,
0xab, 0x43, 0x44, 0xbd, 0xdb, 0x07, 0xd3, 0xff, 0x8b, 0x68, 0x33, 0x24,
0x35, 0xe5, 0xc6, 0x1a, 0x94, 0x14, 0x4f, 0x40, 0xef, 0x92, 0xfb, 0xfd,
0x72, 0x15, 0xd4, 0x10, 0x60, 0x22, 0x3e, 0x60, 0x49, 0x3d, 0x58, 0xc6,
0x3d, 0x28, 0x70, 0x55, 0x32, 0xd5, 0x78, 0x03, 0x51, 0xff, 0xd6, 0x4f,
0x4e, 0x89, 0x0e, 0x50, 0x85, 0x6e, 0x1c, 0x6a, 0x5f, 0x11, 0xd0, 0xf5,
0xee, 0xe5, 0x1c, 0xa8, 0xb2, 0xdb, 0x26, 0x93, 0xb1, 0xe2, 0xc1, 0x05,
0xe0, 0x7f, 0x16, 0xe7, 0x9c, 0xcf, 0xe7, 0xb7, 0x7e, 0xaa, 0x96, 0x21,
0x64, 0x39, 0x6d, 0x7a, 0xdc, 0x70, 0x6e, 0xc8, 0xf5, 0x44, 0x2e, 0x9f,
0xc1, 0xe9, 0x46, 0x8c, 0x1b, 0x58, 0xec, 0x73, 0x1b, 0x9a, 0x04, 0xcb,
0x68, 0x58, 0x21, 0x0e, 0xd6, 0xd7, 0x7a, 0x2b, 0x60, 0x02, 0x20, 0x7b,
0x85, 0xe5, 0x84, 0x2c, 0x5f, 0x24, 0x90, 0x2d, 0xc5, 0x19, 0xea, 0xf3,
0x91, 0x78, 0xc2, 0xa7, 0x36, 0x5a, 0x72, 0x64, 0x45, 0x13, 0x49};
const unsigned char kTestDrmServiceCertificateLicenseSdk[] = {
0x0a, 0xc0, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32,
0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18,
0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02,
0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54,
0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58,
0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57,
0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa,
0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e,
0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda,
0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9,
0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2,
0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e,
0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a,
0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67,
0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56,
0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b,
0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83,
0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1,
0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f,
0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40,
0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46,
0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86,
0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b,
0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b,
0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00,
0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x40, 0x01, 0x48, 0x01, 0x12,
0x80, 0x03, 0x20, 0x54, 0x65, 0x70, 0x93, 0x53, 0x0a, 0x76, 0x95, 0xe5,
0xaa, 0x48, 0x94, 0xa1, 0xb8, 0x25, 0xa6, 0xa4, 0x5a, 0x56, 0x59, 0x8d,
0x80, 0x64, 0x7c, 0xb2, 0x1e, 0xeb, 0xda, 0xfb, 0x30, 0x26, 0x09, 0xc0,
0x25, 0x65, 0xdb, 0xb8, 0x7d, 0x0e, 0xe0, 0x2b, 0xfb, 0xfe, 0xe6, 0x3a,
0x5b, 0x9b, 0x1f, 0xbb, 0xa4, 0x89, 0xf5, 0x7c, 0x52, 0x6f, 0x52, 0xe3,
0xb3, 0xc7, 0x27, 0x9d, 0xca, 0x01, 0x78, 0x08, 0x9b, 0x59, 0x37, 0x9f,
0x27, 0x52, 0x90, 0x80, 0x22, 0xfb, 0x0d, 0xca, 0x57, 0xc2, 0xd9, 0x89,
0xb6, 0x69, 0x45, 0x1f, 0x15, 0x23, 0xf1, 0xf8, 0x39, 0xbb, 0x45, 0xb9,
0x39, 0xe5, 0x1e, 0x8b, 0x71, 0x82, 0x25, 0x4a, 0x32, 0xc2, 0x44, 0xee,
0x76, 0x91, 0x61, 0xa2, 0xe2, 0x7a, 0xb4, 0x68, 0x56, 0xaf, 0x33, 0xe4,
0x97, 0x44, 0xfe, 0x6d, 0x70, 0x85, 0x4f, 0x16, 0x1a, 0xda, 0xa4, 0x30,
0x66, 0xf7, 0x95, 0xe9, 0x7b, 0x84, 0x42, 0xd6, 0x7c, 0x4b, 0x05, 0xca,
0x67, 0x2f, 0xf4, 0xdc, 0x81, 0x9b, 0x7c, 0x80, 0xc4, 0x9e, 0x25, 0x98,
0x84, 0xc4, 0x43, 0x35, 0x13, 0xf4, 0x9d, 0x57, 0x02, 0x1e, 0x67, 0x86,
0x00, 0x6c, 0x46, 0xde, 0x91, 0x9f, 0x1f, 0x42, 0xbb, 0xa7, 0xd1, 0xb8,
0x80, 0x2c, 0x33, 0x51, 0x87, 0x93, 0x6d, 0x75, 0x03, 0xb0, 0x42, 0xc9,
0xe6, 0xa1, 0xc7, 0xa5, 0xd3, 0x40, 0xe7, 0x99, 0x6d, 0x07, 0x78, 0x13,
0x8a, 0x01, 0x4d, 0x3e, 0xb4, 0x9a, 0x1b, 0x52, 0xb7, 0xac, 0x6d, 0x27,
0xda, 0x5c, 0xa2, 0x78, 0x01, 0xe3, 0x4d, 0x5d, 0x0a, 0xd0, 0xc7, 0xb5,
0x73, 0xcf, 0x6e, 0xdd, 0x89, 0xc6, 0xd4, 0x9c, 0xc7, 0xfa, 0x87, 0xe9,
0x74, 0x01, 0xe9, 0xdd, 0x16, 0x0f, 0x3a, 0x8e, 0x38, 0x8d, 0x0b, 0x5a,
0xc8, 0x01, 0xca, 0xb2, 0x7f, 0xcb, 0xe3, 0x25, 0xaa, 0x10, 0xc9, 0x4f,
0x5a, 0x17, 0xe0, 0x31, 0x30, 0x34, 0xe8, 0xe6, 0x06, 0x27, 0xb3, 0x26,
0xee, 0x44, 0x5d, 0x34, 0x2d, 0xc0, 0xff, 0x98, 0x1d, 0x33, 0x99, 0x96,
0x29, 0xa9, 0xc6, 0x31, 0xc1, 0xe1, 0x2f, 0xb9, 0x3a, 0xd2, 0x80, 0x16,
0xc2, 0x4a, 0x38, 0x58, 0x9f, 0x78, 0x7b, 0x11, 0x6c, 0x4e, 0xb0, 0x6b,
0x3b, 0x8f, 0x77, 0x59, 0xb7, 0xca, 0x08, 0x85, 0xc5, 0xe2, 0x03, 0xa7,
0x33, 0xe7, 0x34, 0xc5, 0x64, 0x37, 0x9b, 0x19, 0x48, 0x54, 0xa7, 0xe5,
0x74, 0xe3, 0xa9, 0xfc, 0xe7, 0x6f, 0x9f, 0x04, 0xd4, 0xbd, 0x4a, 0x70,
0xc9, 0x09, 0x67, 0x1a, 0xc5, 0x7b, 0xe9, 0x88, 0x71, 0xcb, 0x96, 0x46,
0x2f, 0x5e, 0x47, 0x19, 0x48, 0xc0, 0xc6, 0xc1, 0xef, 0xb1, 0x26, 0x95,
0x0c, 0x16, 0xed, 0x88, 0x4d, 0xaf, 0x96, 0x3f, 0xa2, 0xf8, 0xc7, 0x38,
0x95, 0x48,
};
const unsigned char kTestDrmServiceCertificateAllTypes[] = {
0x0a, 0xc4, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32,
0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18,
0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02,
0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54,
0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58,
0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57,
0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa,
0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e,
0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda,
0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9,
0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2,
0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e,
0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a,
0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67,
0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56,
0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b,
0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83,
0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1,
0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f,
0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40,
0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46,
0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86,
0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b,
0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b,
0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00,
0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x40, 0x01, 0x40, 0x02, 0x40,
0x03, 0x48, 0x01, 0x12, 0x80, 0x03, 0x72, 0x7c, 0xb3, 0x19, 0x62, 0x88,
0x4d, 0xc5, 0x46, 0x11, 0xcc, 0x6b, 0x32, 0x47, 0x65, 0x7a, 0x5e, 0xe7,
0xf7, 0x58, 0x7e, 0xbc, 0x76, 0xa6, 0x55, 0x75, 0x32, 0x19, 0xaa, 0xf6,
0xb7, 0x02, 0x16, 0x75, 0xfd, 0x05, 0x0b, 0x1c, 0x2c, 0xc5, 0x44, 0x6c,
0xcf, 0x96, 0x02, 0x93, 0x23, 0x60, 0x4b, 0xd4, 0x97, 0x81, 0xa4, 0xe5,
0x5f, 0x0a, 0xe0, 0x5f, 0x53, 0x23, 0x66, 0x19, 0x70, 0xe0, 0x8c, 0x08,
0x19, 0x88, 0xf2, 0xda, 0xd9, 0x7c, 0x69, 0x52, 0xc0, 0x8a, 0x7a, 0x62,
0x81, 0xaa, 0x2b, 0x0e, 0xe8, 0x28, 0x21, 0xce, 0x4a, 0x63, 0x52, 0x23,
0xab, 0xea, 0x65, 0xf9, 0x0f, 0x8a, 0xd2, 0x77, 0xa5, 0x94, 0x05, 0x77,
0x8b, 0x35, 0x99, 0x8b, 0xa9, 0xdd, 0xe4, 0x69, 0x00, 0xbe, 0x4d, 0xd2,
0xce, 0x6c, 0xe4, 0xf9, 0x34, 0x97, 0xaa, 0x59, 0xd8, 0xc9, 0x58, 0x11,
0xa9, 0xb4, 0x9b, 0x0e, 0xce, 0xb7, 0x15, 0x73, 0x6b, 0xb5, 0x5f, 0x87,
0xea, 0xf1, 0x1c, 0x8d, 0x66, 0x5a, 0x28, 0x7e, 0x9a, 0x01, 0x15, 0xfb,
0xb1, 0x92, 0x28, 0x3b, 0x62, 0x6a, 0xcb, 0xb0, 0xe7, 0x11, 0x76, 0x44,
0x5a, 0x97, 0x4b, 0x1a, 0x26, 0xbe, 0x3c, 0xa6, 0x33, 0xd8, 0x99, 0x7b,
0x97, 0xb2, 0xec, 0xa3, 0x18, 0xdf, 0x6b, 0xeb, 0x9f, 0x43, 0x14, 0x0a,
0x49, 0xdb, 0xb0, 0xe2, 0xc0, 0xe0, 0xe3, 0x73, 0x66, 0x0f, 0x14, 0x1c,
0x48, 0x21, 0x28, 0x3a, 0x90, 0xfd, 0x32, 0x1d, 0x35, 0x9a, 0x11, 0x6c,
0xf8, 0x39, 0xd1, 0xcb, 0x45, 0x76, 0xc0, 0x5e, 0xc5, 0xa8, 0xba, 0xd9,
0x09, 0xfc, 0x44, 0xf2, 0x9e, 0xaf, 0x95, 0xc4, 0xe0, 0x06, 0x0e, 0xbf,
0x99, 0x6e, 0x57, 0xfa, 0xa8, 0xcd, 0x2b, 0x4b, 0x97, 0x62, 0xf7, 0x92,
0x14, 0x8f, 0xf4, 0x8c, 0xba, 0xb1, 0xb4, 0x8e, 0x07, 0xd2, 0x7b, 0x93,
0xd1, 0xbf, 0x90, 0x60, 0xe0, 0xbf, 0x1a, 0x3b, 0xd2, 0xee, 0xad, 0xf8,
0x4f, 0x5b, 0xee, 0xe5, 0xf4, 0x8e, 0x97, 0x5b, 0x24, 0xd2, 0xa6, 0x80,
0x5c, 0x09, 0x27, 0x8e, 0x14, 0xa9, 0xcc, 0xff, 0x5a, 0xc1, 0xb4, 0x5f,
0xb5, 0x07, 0x04, 0xd0, 0x3a, 0xef, 0xa9, 0x45, 0xa1, 0x23, 0x0f, 0xc2,
0x13, 0x4f, 0xc8, 0xd4, 0x7f, 0xef, 0x54, 0x5c, 0xcc, 0xdb, 0xdf, 0x89,
0x4c, 0x31, 0x8f, 0x27, 0x50, 0x2b, 0x99, 0xd8, 0xee, 0xdf, 0x8b, 0x06,
0x93, 0xc0, 0xd0, 0x59, 0xf5, 0x66, 0xaf, 0x4b, 0x98, 0x68, 0xb6, 0x8c,
0xd7, 0x70, 0xad, 0x69, 0x60, 0xca, 0xae, 0x64, 0xc2, 0x53, 0xcb, 0xa1,
0x39, 0xb7, 0x08, 0x50, 0x31, 0x12, 0xc1, 0x02, 0x08, 0x58, 0x59, 0xc8,
0x69, 0x9e, 0x43, 0xac, 0x60, 0x7d, 0x4c, 0x8b, 0x1a, 0xe8, 0xa8, 0x3d,
0x65, 0x29, 0x83, 0x85, 0x9b, 0x8e,
};
const unsigned char kTestDrmServiceCertificateNoType[] = {
0x0a, 0xbe, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32,
0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18,
0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02,
0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54,
0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58,
0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57,
0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa,
0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e,
0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda,
0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9,
0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2,
0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e,
0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a,
0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67,
0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56,
0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b,
0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83,
0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1,
0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f,
0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40,
0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46,
0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86,
0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b,
0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b,
0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00,
0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x48, 0x01, 0x12, 0x80, 0x03,
0x21, 0xa4, 0x86, 0x36, 0x40, 0x9d, 0x0f, 0x7d, 0x31, 0x8a, 0xbe, 0x98,
0x85, 0x0f, 0x4a, 0xe6, 0x5e, 0x2e, 0x94, 0xc3, 0x4a, 0x69, 0x26, 0x55,
0x76, 0xf6, 0x11, 0xfe, 0xd4, 0x1d, 0xfc, 0xb3, 0xbe, 0x94, 0x6a, 0x5c,
0x51, 0x2d, 0xda, 0x95, 0x70, 0x6f, 0x62, 0x23, 0x69, 0xfa, 0x3d, 0xce,
0x09, 0x0c, 0x2f, 0xc7, 0x30, 0xac, 0xf2, 0x46, 0x6a, 0x14, 0x42, 0x24,
0x8f, 0x2a, 0xb4, 0xa7, 0x32, 0xbb, 0x8c, 0x02, 0xe2, 0x1f, 0x63, 0xfd,
0xf4, 0x40, 0x14, 0xd9, 0x12, 0x88, 0xa6, 0x46, 0x15, 0x67, 0x85, 0xa3,
0xe2, 0xe4, 0x88, 0x5f, 0xdd, 0x20, 0xcd, 0xa7, 0xd1, 0x26, 0x71, 0x63,
0x89, 0x2e, 0x1a, 0x8a, 0x52, 0x59, 0xba, 0x3b, 0x09, 0x8a, 0x1c, 0x67,
0x0c, 0xfd, 0xc9, 0xad, 0x7b, 0x4f, 0xd8, 0x0e, 0x47, 0x9e, 0x47, 0x44,
0x20, 0x67, 0x7a, 0xec, 0x3b, 0xfe, 0x58, 0xf2, 0x25, 0xb2, 0x72, 0xe1,
0x05, 0xbd, 0x7c, 0x02, 0xc9, 0xdb, 0x40, 0x3c, 0x90, 0x04, 0xab, 0xa7,
0xb6, 0x06, 0xb2, 0x30, 0x64, 0x42, 0x84, 0x3e, 0x89, 0xd7, 0xd5, 0x90,
0xaa, 0x14, 0x00, 0xa6, 0x45, 0x26, 0xe1, 0x16, 0xa8, 0x24, 0x65, 0x01,
0xe1, 0x0e, 0xd3, 0xff, 0x68, 0x0c, 0x0f, 0x8f, 0xc3, 0x68, 0xed, 0x82,
0x7c, 0xae, 0x21, 0x97, 0x6a, 0x5a, 0x55, 0x76, 0x4b, 0x4e, 0x65, 0x9b,
0xbd, 0x18, 0x8b, 0xf4, 0xc4, 0x28, 0xab, 0x6c, 0x52, 0xc7, 0xfc, 0xb3,
0x12, 0x79, 0x3c, 0x29, 0x82, 0x15, 0xd1, 0x45, 0xae, 0x0b, 0xbc, 0x46,
0x13, 0x24, 0x80, 0xb1, 0x6a, 0x15, 0x7f, 0x68, 0x91, 0xfe, 0xa6, 0x5d,
0x7a, 0xdb, 0x81, 0xc4, 0x14, 0xf0, 0x7d, 0x59, 0x15, 0x7c, 0x11, 0x6d,
0xe5, 0x97, 0xc2, 0x5e, 0x00, 0xfc, 0x36, 0x4f, 0xf7, 0xc1, 0xe6, 0x62,
0x92, 0x03, 0x92, 0x4d, 0x91, 0x61, 0x7e, 0xdc, 0xe9, 0xd3, 0x16, 0x17,
0xa7, 0x21, 0xb8, 0xf7, 0x27, 0xc4, 0x72, 0xe9, 0xff, 0x66, 0x60, 0x65,
0x50, 0x6d, 0x2d, 0xe9, 0x02, 0xf2, 0x48, 0xbc, 0xfa, 0x7b, 0x3e, 0xdc,
0x51, 0x4a, 0xd8, 0x2a, 0xd2, 0x32, 0x95, 0xff, 0x32, 0xf0, 0x68, 0xae,
0x74, 0xb3, 0xaf, 0x93, 0x79, 0x2e, 0x4e, 0xd8, 0x23, 0x61, 0xf4, 0xca,
0x34, 0x3f, 0x2d, 0x12, 0x5d, 0xef, 0x05, 0xd0, 0xdc, 0x72, 0x0b, 0x02,
0xc4, 0x2d, 0x97, 0x65, 0x6d, 0x44, 0x25, 0x50, 0x8e, 0xd1, 0x34, 0x8b,
0xc3, 0xff, 0xca, 0x17, 0xcb, 0x5c, 0x64, 0x8e, 0xd1, 0xe5, 0x81, 0xb2,
0x5c, 0xd6, 0xd3, 0x2a, 0x0c, 0x74, 0x41, 0x14, 0xc5, 0x27, 0x3c, 0x3f,
0x2b, 0xf8, 0xba, 0x33, 0x0b, 0xf4, 0x88, 0x9c, 0x8b, 0x75, 0xf5, 0xf0,
0x29, 0x08, 0x23, 0x91, 0xe1, 0xcc, 0xc3, 0x6e, 0x5e, 0x60, 0x5d, 0x5a,
};
TestDrmCertificates::TestDrmCertificates()
: test_root_certificate_(
kTestRootCertificate,
kTestRootCertificate + sizeof(kTestRootCertificate)),
test_intermediate_certificate_(
kTestIntermediateCertificate,
kTestIntermediateCertificate + sizeof(kTestIntermediateCertificate)),
test_intermediate_certificate_with_ec_key_(
kTestIntermediateCertificateWithECKey,
kTestIntermediateCertificateWithECKey +
sizeof(kTestIntermediateCertificateWithECKey)),
test_user_device_certificate_(
kTestUserDrmCertificate,
kTestUserDrmCertificate + sizeof(kTestUserDrmCertificate)),
test_user_device_certificate_with_ec_key_(
kTestUserDrmCertificateWithECKey,
kTestUserDrmCertificateWithECKey +
sizeof(kTestUserDrmCertificateWithECKey)),
test_user_device_certificate_with_rot_id_(
kTestUserDrmCertificateWithRotId,
kTestUserDrmCertificateWithRotId +
sizeof(kTestUserDrmCertificateWithRotId)),
test_service_certificate_license_sdk_(
kTestDrmServiceCertificateLicenseSdk,
kTestDrmServiceCertificateLicenseSdk +
sizeof(kTestDrmServiceCertificateLicenseSdk)),
test_service_certificate_all_types_(
kTestDrmServiceCertificateAllTypes,
kTestDrmServiceCertificateAllTypes +
sizeof(kTestDrmServiceCertificateAllTypes)),
test_service_certificate_no_type_(
kTestDrmServiceCertificateNoType,
kTestDrmServiceCertificateNoType +
sizeof(kTestDrmServiceCertificateNoType)) {}
} // namespace widevine

View File

@@ -1,91 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 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.
////////////////////////////////////////////////////////////////////////////////
//
// Class contains certificates that can be used for testing. Provides methods
// to retrieve a test root certificate, a test intermediate certificate and a
// test user device certificate.
#ifndef COMMON_TEST_DRM_CERTIFICATES_H_
#define COMMON_TEST_DRM_CERTIFICATES_H_
#include <string>
namespace widevine {
class TestDrmCertificates {
public:
TestDrmCertificates();
TestDrmCertificates(const TestDrmCertificates&) = delete;
TestDrmCertificates& operator=(const TestDrmCertificates&) = delete;
virtual ~TestDrmCertificates() {}
// returns a test root certificate
const std::string& test_root_certificate() const {
return test_root_certificate_;
}
// returns a test intermediate certificate with an RSA key
const std::string& test_intermediate_certificate() const {
return test_intermediate_certificate_;
}
// returns a test intermediate certificate with an EC key
const std::string& test_intermediate_certificate_with_ec_key() const {
return test_intermediate_certificate_with_ec_key_;
}
// returns a user device certificate with an RSA key
const std::string& test_user_device_certificate() const {
return test_user_device_certificate_;
}
// returns a user device certificate with an EC key
const std::string& test_user_device_certificate_with_ec_key() const {
return test_user_device_certificate_with_ec_key_;
}
// returns a user device certificate with a Root of Trust Id.
const std::string& test_user_device_certificate_with_rot_id() const {
return test_user_device_certificate_with_rot_id_;
}
// returns a service certificate with license sdk service type
const std::string& test_service_certificate_license_sdk() const {
return test_service_certificate_license_sdk_;
}
// returns a service certificate with all service types
const std::string& test_service_certificate_all_types() const {
return test_service_certificate_all_types_;
}
// returns a service certificate prior to a change requiring the service
// type to be specified.
const std::string& test_service_certificate_no_type() const {
return test_service_certificate_no_type_;
}
private:
const std::string test_root_certificate_;
const std::string test_intermediate_certificate_;
const std::string test_intermediate_certificate_with_ec_key_;
const std::string test_user_device_certificate_;
const std::string test_user_device_certificate_with_ec_key_;
const std::string test_user_device_certificate_with_rot_id_;
const std::string test_service_certificate_license_sdk_;
const std::string test_service_certificate_all_types_;
const std::string test_service_certificate_no_type_;
};
} // namespace widevine
#endif // COMMON_TEST_DRM_CERTIFICATES_H_

View File

@@ -1,72 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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/test_utils.h"
#include <stddef.h>
#include <memory>
#include "glog/logging.h"
#include "openssl/pem.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"
namespace widevine {
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature) {
CHECK(signature);
if (pem_private_key.empty()) {
return Status(error::INVALID_ARGUMENT, "Empty PEM private key");
}
if (message.empty()) {
return Status(error::INVALID_ARGUMENT, "Empty message");
}
BIO* bio(NULL);
bio = BIO_new_mem_buf(const_cast<char*>(pem_private_key.data()),
pem_private_key.size());
if (bio == NULL) {
return Status(error::INTERNAL, "BIO allocation failed");
}
Status status;
RSA* key(NULL);
std::unique_ptr<char[]> 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 = Status(Status::canonical_space(), error::INVALID_ARGUMENT,
"PEM RSA private key load failed");
goto cleanup;
}
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
digest);
sig_size = RSA_size(key);
sig_buffer.reset(new char[sig_size]);
if (RSA_sign(NID_sha256, digest, sizeof(digest),
reinterpret_cast<unsigned char*>(sig_buffer.get()), &sig_size,
key) != 1) {
status = Status(Status::canonical_space(), error::INTERNAL,
"RSA private encrypt failed");
goto cleanup;
}
signature->assign(sig_buffer.get(), sig_size);
cleanup:
if (key != NULL) {
RSA_free(key);
}
if (bio != NULL) {
BIO_free(bio);
}
return status;
}
} // namespace widevine

View File

@@ -1,32 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Auxiliary functions for license server SDK testing.
#ifndef COMMON_TEST_UTILS_H_
#define COMMON_TEST_UTILS_H_
#include <string>
#include "common/status.h"
namespace widevine {
// Generate RSA signature using the specified RSA private key, SHA256 digest,
// and PKCS#1 1.5 padding. |pem_private_key| is a PEM-encoded private RSA key,
// |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 parameters.
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature);
} // namespace widevine
#endif // COMMON_TEST_UTILS_H_

View File

@@ -1,43 +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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Helper methods for verifying VMP (Verified Media Pipeline) data.
#include "common/verified_media_pipeline.h"
#include "common/vmp_checker.h"
namespace widevine {
Status VerifyVmpData(const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status) {
*platform_verification_status = PLATFORM_UNVERIFIED;
VmpChecker::Result vmp_result;
Status status = VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result);
if (status.ok()) {
switch (vmp_result) {
case VmpChecker::kUnverified:
*platform_verification_status = PLATFORM_UNVERIFIED;
break;
case VmpChecker::kVerified:
*platform_verification_status = PLATFORM_SOFTWARE_VERIFIED;
break;
case VmpChecker::kSecureStorageVerified:
*platform_verification_status =
PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED;
break;
case VmpChecker::kTampered:
*platform_verification_status = PLATFORM_TAMPERED;
break;
}
} else {
*platform_verification_status = PLATFORM_TAMPERED;
}
return status;
}
} // namespace widevine

View File

@@ -1,28 +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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Helper methods for verifying VMP (Verified Media Pipeline) data.
#ifndef COMMON_VERIFIED_MEDIA_PIPELINE_H_
#define COMMON_VERIFIED_MEDIA_PIPELINE_H_
#include <string>
#include "common/status.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
// Retrieve the PlatformVerificationStatus for |vmp_data|. The
// PlatformVerificationStatus is defined at
Status VerifyVmpData(const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status);
} // namespace widevine
#endif // COMMON_VERIFIED_MEDIA_PIPELINE_H_

View File

@@ -1,362 +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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Singleton object which validates VMP (Verified Media Pipeline) data for
// purposes of platform software verification. Thread safe.
#include "common/vmp_checker.h"
#include <stddef.h>
#include <vector>
#include <cstdint>
#include "glog/logging.h"
#include "common/certificate_type.h"
#include "common/error_space.h"
#include "common/hash_algorithm_util.h"
#include "common/rsa_key.h"
#include "common/x509_cert.h"
#include "protos/public/errors.pb.h"
#include "protos/public/verified_media_pipeline.pb.h"
namespace {
const uint32_t kBlessedBinaryFlag = 0x00000001;
const uint8_t kDevVmpCodeSigningDrmRootCertificate[] = {
0x30, 0x82, 0x04, 0xb8, 0x30, 0x82, 0x03, 0x20, 0x02, 0x09, 0x00, 0xc5,
0xf8, 0x2f, 0x03, 0x8f, 0xac, 0xf1, 0x58, 0x30, 0x0d, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81,
0x9c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69,
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x15, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e,
0x65, 0x2d, 0x64, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69,
0x67, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x74, 0x69, 0x6e, 0x73, 0x6b,
0x69, 0x70, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
0x6d, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x36, 0x31, 0x30, 0x32, 0x38, 0x30,
0x31, 0x30, 0x37, 0x34, 0x30, 0x5a, 0x18, 0x0f, 0x32, 0x31, 0x31, 0x36,
0x31, 0x30, 0x30, 0x34, 0x30, 0x31, 0x30, 0x37, 0x34, 0x30, 0x5a, 0x30,
0x81, 0x9c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b,
0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06,
0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57,
0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x1e, 0x30, 0x1c, 0x06,
0x03, 0x55, 0x04, 0x03, 0x0c, 0x15, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69,
0x6e, 0x65, 0x2d, 0x64, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73,
0x69, 0x67, 0x6e, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x74, 0x69, 0x6e, 0x73,
0x6b, 0x69, 0x70, 0x40, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63,
0x6f, 0x6d, 0x30, 0x82, 0x01, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
0x8f, 0x00, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xd2,
0x6f, 0x60, 0x7f, 0xff, 0x7c, 0xbd, 0xa4, 0xe5, 0x8c, 0xa6, 0xcf, 0xde,
0x22, 0x6d, 0x3a, 0x5e, 0x83, 0xa9, 0x0e, 0x9b, 0xd4, 0x93, 0xb8, 0xb0,
0xe0, 0x5d, 0x03, 0x3d, 0xc1, 0x00, 0xb8, 0x1a, 0xcc, 0x84, 0x31, 0xfb,
0x9e, 0x97, 0x79, 0x17, 0x04, 0x48, 0xe7, 0x13, 0x98, 0x0a, 0x47, 0x41,
0xac, 0x6c, 0x52, 0xb0, 0xca, 0x9e, 0xfb, 0xfd, 0x78, 0x65, 0xd0, 0xd6,
0x12, 0x07, 0x7e, 0x24, 0x65, 0x46, 0x6c, 0xb9, 0x23, 0xbb, 0xdc, 0x02,
0x03, 0xc7, 0xb0, 0x02, 0xc1, 0xd3, 0x10, 0x59, 0xe7, 0x0b, 0x45, 0x13,
0x73, 0x5f, 0xae, 0x58, 0xcd, 0xbf, 0x42, 0x8a, 0xac, 0xf5, 0x6a, 0x1e,
0x75, 0x26, 0xb1, 0x69, 0x07, 0xad, 0xf5, 0xfd, 0x4c, 0xaa, 0x66, 0x55,
0x74, 0x56, 0x9a, 0x9e, 0x40, 0x78, 0x77, 0x9a, 0x39, 0x7a, 0x37, 0xe4,
0x25, 0x6b, 0x07, 0x09, 0xbe, 0xe2, 0x0d, 0x23, 0x83, 0xfc, 0x94, 0x9f,
0x26, 0x98, 0x0e, 0x49, 0x81, 0x7b, 0xf4, 0xe6, 0xd4, 0xda, 0x7a, 0xc9,
0xa4, 0x14, 0x5a, 0xa9, 0xaf, 0x0c, 0xd9, 0xf1, 0xbc, 0xd8, 0x6c, 0xd2,
0xd4, 0x1b, 0x82, 0x10, 0x3d, 0x87, 0xf1, 0x81, 0xe6, 0x1a, 0xb7, 0xfa,
0xfa, 0x1f, 0x9c, 0xde, 0xa1, 0x3f, 0x11, 0xb1, 0xd8, 0x26, 0xd1, 0x86,
0x21, 0xdc, 0x03, 0xcb, 0xd6, 0x40, 0xfb, 0x5f, 0xb0, 0x84, 0x7f, 0x69,
0x9e, 0xa3, 0xbc, 0xfb, 0x03, 0xb6, 0xc1, 0xb9, 0x23, 0xb1, 0x20, 0x6f,
0x71, 0xf5, 0x7a, 0x3b, 0x84, 0x30, 0xa8, 0x59, 0xc0, 0x8f, 0x75, 0xfd,
0xcb, 0xe1, 0xc3, 0x5f, 0xe7, 0x8a, 0xb0, 0xe9, 0xf8, 0xef, 0x04, 0x4b,
0x4a, 0xf6, 0xc3, 0x7d, 0x08, 0xfe, 0x08, 0x52, 0x2e, 0xbc, 0x1f, 0x65,
0xf6, 0x51, 0xb7, 0xd8, 0x24, 0x21, 0x49, 0x1d, 0x7f, 0x16, 0x28, 0x14,
0xd9, 0xc2, 0x19, 0xdb, 0xa2, 0xc6, 0xf0, 0x3a, 0x2d, 0x98, 0x70, 0x72,
0x45, 0xf7, 0x80, 0x37, 0x56, 0x0b, 0x0c, 0x6f, 0x80, 0xf1, 0x8c, 0xe2,
0xf3, 0x4d, 0x16, 0xc5, 0x74, 0x90, 0x34, 0x1e, 0x57, 0x3c, 0xde, 0xf1,
0xc4, 0x8c, 0x17, 0x09, 0xd3, 0xc5, 0x92, 0x9d, 0xcf, 0xdc, 0x7b, 0x4f,
0xae, 0x20, 0x10, 0xd7, 0x04, 0x56, 0x9d, 0x9a, 0xa9, 0xd8, 0x06, 0x4a,
0xd6, 0x68, 0xd4, 0x83, 0xcb, 0x7d, 0xe2, 0x62, 0xd1, 0x99, 0xb8, 0x9d,
0x81, 0xc7, 0xfc, 0x94, 0x69, 0x0d, 0x2a, 0x1c, 0x99, 0xcf, 0x40, 0xc3,
0xfd, 0xe9, 0x64, 0x5b, 0xc3, 0x1d, 0xda, 0x1c, 0x89, 0xab, 0x34, 0x1b,
0x53, 0x6e, 0xad, 0xf0, 0x6e, 0x97, 0x87, 0xe8, 0xfb, 0x0c, 0x96, 0x93,
0x1b, 0x52, 0x82, 0x6a, 0xba, 0x0f, 0xe3, 0x5d, 0xc4, 0x17, 0xdc, 0xe4,
0x31, 0x78, 0x12, 0x26, 0x10, 0x74, 0x14, 0x7c, 0x45, 0xb2, 0xb9, 0x02,
0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x81, 0x00,
0x8f, 0x5b, 0x2a, 0x40, 0xce, 0xae, 0xa2, 0x79, 0xfc, 0xc5, 0x5e, 0x94,
0xc8, 0x10, 0x4b, 0xf1, 0x21, 0x7f, 0x4b, 0xeb, 0x81, 0x3d, 0xb8, 0x26,
0x83, 0x84, 0x76, 0x79, 0xda, 0x35, 0xfc, 0xdf, 0xfe, 0x10, 0x7a, 0xd5,
0x17, 0xc0, 0xad, 0x0d, 0xf9, 0x3f, 0xa6, 0xa1, 0xcd, 0x6c, 0x9c, 0x3b,
0x52, 0xbd, 0x04, 0xf9, 0xe2, 0x9e, 0x86, 0x83, 0x98, 0x60, 0x01, 0x99,
0xb7, 0xbd, 0x02, 0x87, 0xd8, 0xea, 0x65, 0xaa, 0x60, 0x6f, 0x33, 0x50,
0x25, 0x84, 0xb7, 0x42, 0x63, 0x39, 0xfd, 0x17, 0x67, 0x74, 0x88, 0x66,
0xe2, 0x38, 0x59, 0xf6, 0x9b, 0x98, 0x95, 0xdd, 0x54, 0x2c, 0x69, 0x6a,
0x0a, 0x51, 0x66, 0x4d, 0x65, 0xc0, 0x58, 0x3e, 0xcf, 0x15, 0x63, 0x7a,
0x32, 0xc8, 0xfb, 0xe7, 0x11, 0x2e, 0x25, 0x17, 0x52, 0x4d, 0x8e, 0x6b,
0x6d, 0x58, 0x4e, 0xf6, 0xd6, 0xb0, 0xfa, 0x0d, 0x7a, 0xb1, 0x44, 0x52,
0x9a, 0x6c, 0x90, 0x38, 0x68, 0xa5, 0xa9, 0x9b, 0xc5, 0x45, 0x09, 0xfa,
0xaa, 0x8c, 0xfe, 0x91, 0x55, 0x93, 0x35, 0x52, 0x45, 0xbb, 0xaa, 0x5b,
0xf0, 0x63, 0x53, 0x13, 0xcf, 0x48, 0x7b, 0xaa, 0x20, 0xa0, 0x07, 0x43,
0x1d, 0xd7, 0xb3, 0x4a, 0x1b, 0x8c, 0x51, 0xb5, 0xf6, 0xb9, 0x5b, 0x13,
0x02, 0x74, 0x3e, 0x48, 0xde, 0xec, 0xeb, 0x65, 0xfe, 0xf2, 0x61, 0xe5,
0x68, 0xd5, 0xea, 0xd9, 0x79, 0xa6, 0x71, 0xb1, 0x57, 0x0f, 0xbc, 0xd0,
0x31, 0x4f, 0xff, 0xc5, 0x95, 0xe8, 0xee, 0x70, 0x18, 0xb9, 0xbc, 0x19,
0xcd, 0x3a, 0x06, 0x75, 0xe4, 0x57, 0xc1, 0x2e, 0x32, 0x19, 0xdd, 0x2e,
0x45, 0xc0, 0x19, 0xe6, 0x72, 0x81, 0x2c, 0xb6, 0xed, 0x1c, 0xd4, 0xef,
0x42, 0x18, 0x44, 0x44, 0x75, 0xd6, 0x29, 0x81, 0xe1, 0xf7, 0x5b, 0x48,
0xa3, 0xf8, 0x92, 0x54, 0xd0, 0x79, 0xa1, 0xe1, 0x8e, 0xa8, 0x98, 0x2d,
0x57, 0x5d, 0xb5, 0x5a, 0x01, 0x1b, 0xb3, 0xcf, 0x5f, 0x64, 0x2e, 0x70,
0xba, 0xa0, 0x41, 0xbb, 0xd4, 0x82, 0x28, 0x3c, 0xb1, 0x81, 0x76, 0xd6,
0x85, 0x2e, 0xc6, 0x01, 0x7f, 0xae, 0xc3, 0x17, 0x2f, 0xed, 0xbe, 0xad,
0xa2, 0x7c, 0x53, 0xc6, 0x77, 0x73, 0x1d, 0x19, 0x90, 0x2a, 0xf8, 0xd5,
0x50, 0x65, 0xc1, 0x22, 0x3c, 0x24, 0x96, 0xeb, 0x7b, 0x53, 0x8f, 0xbf,
0xd9, 0xf7, 0x80, 0xa8, 0x76, 0x72, 0xea, 0xb7, 0x7f, 0xf7, 0xa2, 0x52,
0xc7, 0xa7, 0xd6, 0x88, 0xa1, 0x38, 0x40, 0x5d, 0xcd, 0xdb, 0xe3, 0x8e,
0xc7, 0xf9, 0x39, 0xbe, 0xfa, 0x27, 0x41, 0x73, 0x3a, 0x1c, 0xb3, 0x03,
0xf1, 0x36, 0xea, 0xe8, 0xb3, 0xe1, 0x6e, 0x59, 0xcc, 0xe2, 0x75, 0x2b,
0xf9, 0x55, 0xb9, 0xc2, 0xdf, 0x0a, 0x8d, 0x8d, 0xd1, 0x62, 0x3b, 0x86};
const uint8_t kProdVmpCodeSigningDrmRootCertificate[] = {
0x30, 0x82, 0x04, 0xd7, 0x30, 0x82, 0x03, 0x3f, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x11, 0x00, 0xca, 0xa4, 0xbd, 0x6b, 0x93, 0x56, 0x4a, 0xf1,
0x84, 0xef, 0x5e, 0xed, 0xe8, 0xf7, 0xe2, 0x0b, 0x30, 0x0d, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30,
0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c,
0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69,
0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31,
0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69,
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03,
0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e,
0x65, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, 0x6e, 0x2d, 0x72,
0x6f, 0x6f, 0x74, 0x2d, 0x63, 0x61, 0x30, 0x20, 0x17, 0x0d, 0x31, 0x37,
0x30, 0x31, 0x32, 0x34, 0x32, 0x33, 0x33, 0x38, 0x31, 0x34, 0x5a, 0x18,
0x0f, 0x33, 0x30, 0x31, 0x36, 0x30, 0x35, 0x32, 0x37, 0x32, 0x33, 0x33,
0x38, 0x31, 0x34, 0x5a, 0x30, 0x7d, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x77, 0x69,
0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2d, 0x63, 0x6f, 0x64, 0x65, 0x73,
0x69, 0x67, 0x6e, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x63, 0x61, 0x30,
0x82, 0x01, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30,
0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xe0, 0xb5, 0xc5, 0x6d,
0x04, 0xc1, 0x97, 0xaf, 0xe7, 0x62, 0xfb, 0x84, 0xdc, 0xd1, 0xf4, 0xb1,
0xb5, 0xa2, 0x7c, 0xca, 0x31, 0xf8, 0xce, 0xa7, 0x7a, 0x92, 0xc2, 0xbe,
0x14, 0xdc, 0x85, 0x9f, 0x18, 0x9e, 0x78, 0xba, 0x65, 0x05, 0x56, 0x88,
0x88, 0xdc, 0x1f, 0x4f, 0x24, 0x7f, 0xf5, 0x26, 0x6f, 0x6e, 0xcc, 0x04,
0x2f, 0x38, 0xb8, 0xcd, 0x27, 0xd7, 0x9e, 0x07, 0xd3, 0xa9, 0xd4, 0x6b,
0x84, 0xfe, 0xf8, 0xac, 0x9c, 0x53, 0xdf, 0x7a, 0x45, 0x5e, 0x77, 0xf8,
0x4e, 0x88, 0x00, 0x5c, 0x6f, 0xb6, 0xa7, 0x0b, 0x4b, 0x63, 0x57, 0x92,
0x7a, 0x7b, 0x3d, 0x20, 0x88, 0x3e, 0x7b, 0xb4, 0x28, 0x2b, 0x63, 0x81,
0xd4, 0x0c, 0x4c, 0xb7, 0x54, 0x68, 0x68, 0x2c, 0x0d, 0xf5, 0xa6, 0x9e,
0x16, 0x93, 0x76, 0xdd, 0xc0, 0xd5, 0x93, 0x65, 0x99, 0x90, 0x17, 0x2d,
0x2b, 0xdc, 0x6f, 0xaf, 0x58, 0xfd, 0x78, 0xe9, 0xf5, 0xde, 0x2e, 0x36,
0x95, 0xf0, 0xcf, 0x25, 0x41, 0x3d, 0x4f, 0x37, 0xd1, 0x70, 0x5b, 0xb5,
0xc0, 0xc8, 0xf3, 0x63, 0xa3, 0xda, 0x9f, 0x94, 0xdb, 0xf8, 0x51, 0xf2,
0xa9, 0xe5, 0x67, 0x0e, 0x29, 0xb3, 0x45, 0x12, 0xc5, 0x42, 0xf9, 0x3b,
0x38, 0xf9, 0xa5, 0x7b, 0x41, 0x88, 0x6f, 0x32, 0x62, 0x03, 0x5f, 0xfd,
0x35, 0x97, 0xc2, 0x83, 0x15, 0xb6, 0x56, 0x4f, 0xbb, 0x81, 0x39, 0x37,
0xf2, 0x9c, 0x2a, 0x61, 0xa8, 0x63, 0x5f, 0xa0, 0x27, 0x30, 0x06, 0xd4,
0xcb, 0x9d, 0xb7, 0xe9, 0xf2, 0xae, 0xd6, 0xc9, 0xcd, 0x72, 0xa3, 0xe6,
0xf8, 0x54, 0x03, 0x6e, 0xe1, 0x95, 0x03, 0xdd, 0x7a, 0x85, 0xb3, 0x5c,
0xa7, 0xca, 0x99, 0xec, 0xa6, 0xe8, 0x1a, 0xb2, 0x72, 0xe1, 0x91, 0x2d,
0x97, 0xe3, 0x2a, 0x9c, 0x42, 0xaa, 0x45, 0xf2, 0x8e, 0x51, 0xc0, 0xd8,
0x21, 0x83, 0x66, 0x07, 0xb5, 0x20, 0xb8, 0x28, 0xa5, 0xde, 0xfb, 0x4e,
0x2e, 0xc7, 0x70, 0x9b, 0x3d, 0x52, 0x66, 0x24, 0xc5, 0xa2, 0x2e, 0x49,
0x54, 0x5c, 0xfd, 0xc0, 0xde, 0xf6, 0x9d, 0xb4, 0x70, 0x31, 0x2b, 0xac,
0x14, 0xfb, 0x19, 0x9e, 0x89, 0xd5, 0x07, 0x87, 0xa0, 0xd8, 0x15, 0x96,
0xe9, 0xf7, 0x91, 0x36, 0x52, 0x83, 0x3c, 0x2c, 0xfa, 0xb5, 0xc4, 0xc6,
0x1a, 0x34, 0xf0, 0x53, 0x94, 0x15, 0x82, 0xa2, 0x2f, 0x98, 0xbb, 0x49,
0xca, 0xf7, 0xe0, 0xcb, 0x9e, 0x3c, 0xa6, 0x64, 0x59, 0x77, 0x63, 0xd1,
0x05, 0x03, 0x99, 0x6c, 0x50, 0x08, 0xec, 0x64, 0x86, 0xf7, 0x97, 0xaf,
0xf8, 0xcc, 0xdf, 0x91, 0xc7, 0x2c, 0x15, 0x0f, 0xa7, 0x0e, 0x02, 0x33,
0x63, 0x84, 0xb7, 0x7e, 0xd3, 0x10, 0x89, 0x05, 0x2d, 0xb4, 0x68, 0x38,
0xe0, 0x00, 0x49, 0xda, 0xaa, 0xb9, 0xf9, 0xbf, 0x02, 0x03, 0x01, 0x00,
0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
0x04, 0x16, 0x04, 0x14, 0xca, 0x3d, 0xd8, 0x8e, 0x0f, 0x74, 0x57, 0x7f,
0xd0, 0x9a, 0xd9, 0xe1, 0x21, 0xbf, 0x42, 0xfb, 0x23, 0x55, 0x29, 0x86,
0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
0x14, 0xca, 0x3d, 0xd8, 0x8e, 0x0f, 0x74, 0x57, 0x7f, 0xd0, 0x9a, 0xd9,
0xe1, 0x21, 0xbf, 0x42, 0xfb, 0x23, 0x55, 0x29, 0x86, 0x30, 0x0c, 0x06,
0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x01, 0x81, 0x00, 0xc1, 0x81, 0x17, 0x08, 0x0a,
0xcb, 0xae, 0x54, 0x92, 0xed, 0x0f, 0xc0, 0xf0, 0x83, 0xb8, 0xe9, 0x2a,
0xd5, 0x65, 0x18, 0xb5, 0x92, 0xfc, 0x67, 0x9c, 0x39, 0x9e, 0x3a, 0x93,
0x1f, 0x91, 0x7b, 0x35, 0x6d, 0x09, 0x6c, 0x3c, 0x02, 0x85, 0xe8, 0xc6,
0x0c, 0x6b, 0x35, 0xeb, 0x8c, 0xe4, 0x44, 0x80, 0xc5, 0x4e, 0x65, 0xa6,
0xbc, 0x25, 0x93, 0x5a, 0xed, 0x5a, 0xd1, 0x5a, 0xcf, 0xf1, 0xbe, 0xd5,
0x46, 0x7c, 0x78, 0xfe, 0xb6, 0xa6, 0x9c, 0x85, 0xa9, 0xe2, 0x13, 0x70,
0x99, 0x03, 0x5a, 0x3a, 0xa8, 0x7b, 0xdd, 0x50, 0x76, 0x83, 0xfe, 0x49,
0xc0, 0x5e, 0xc7, 0xf1, 0x18, 0xc0, 0xe6, 0xb7, 0xc7, 0xe4, 0x9d, 0x54,
0xaf, 0x25, 0xdf, 0xe4, 0x81, 0xc1, 0xe9, 0xaa, 0x7c, 0x05, 0x20, 0xfa,
0x91, 0x47, 0xd1, 0x4a, 0xe2, 0x24, 0x6f, 0x72, 0x22, 0x69, 0xd0, 0x89,
0x78, 0x2c, 0x9a, 0x16, 0x7d, 0x92, 0xdd, 0x64, 0x6c, 0xc8, 0xbf, 0x33,
0xe3, 0x91, 0xb9, 0xb5, 0x16, 0xfe, 0xfd, 0xa2, 0xdb, 0x82, 0xf0, 0xec,
0xac, 0xe7, 0xf9, 0x2e, 0xac, 0x50, 0xf0, 0xcf, 0xba, 0xe1, 0x55, 0xa9,
0xb0, 0xd9, 0x66, 0x3f, 0xb6, 0xee, 0x57, 0xff, 0x8d, 0x43, 0xb7, 0xc3,
0xb4, 0x44, 0xa9, 0xcc, 0x99, 0xa2, 0xbf, 0xac, 0x4f, 0xec, 0xed, 0xb5,
0xd0, 0x3f, 0xa9, 0x50, 0x3b, 0xc1, 0x24, 0xf2, 0xd0, 0xef, 0x5c, 0xbf,
0x5c, 0xc2, 0x41, 0x29, 0xbe, 0xb6, 0x76, 0x5a, 0x19, 0xde, 0x67, 0x1c,
0x2a, 0x67, 0xae, 0x07, 0xe8, 0xfa, 0x49, 0xf1, 0x81, 0xbc, 0x22, 0xa1,
0xe6, 0x5d, 0x27, 0x76, 0x0f, 0x4d, 0x41, 0x57, 0xcf, 0x0f, 0x12, 0x2f,
0xdd, 0x20, 0x88, 0xcf, 0xc8, 0xa7, 0xc0, 0xe5, 0xec, 0xcd, 0xb9, 0xa7,
0x1c, 0x29, 0x55, 0xed, 0x67, 0xf9, 0x38, 0x33, 0xea, 0x85, 0xe9, 0x69,
0x5a, 0x7c, 0xfe, 0x37, 0x3b, 0xdd, 0x61, 0x5f, 0xaa, 0xc3, 0x18, 0xbc,
0x58, 0x95, 0x39, 0x61, 0x79, 0xa1, 0x46, 0xcc, 0xc0, 0xe7, 0xd6, 0x52,
0x3c, 0xc7, 0xfa, 0xed, 0x89, 0x06, 0xeb, 0xd4, 0x5e, 0x9c, 0xa5, 0x55,
0x8c, 0xe3, 0x5f, 0xe6, 0xb4, 0x0a, 0xf4, 0xf6, 0x7d, 0xeb, 0x64, 0x74,
0xa9, 0x1a, 0x8d, 0x6e, 0xf1, 0x41, 0xc7, 0x7e, 0xc6, 0x26, 0x3a, 0x47,
0x70, 0x49, 0x07, 0x27, 0xa2, 0xb9, 0xc6, 0x79, 0x9d, 0x94, 0xf5, 0x51,
0x69, 0xdf, 0xbd, 0x84, 0xee, 0xaa, 0x46, 0xea, 0x4b, 0x27, 0xb6, 0x5c,
0xac, 0xcf, 0x4a, 0x48, 0x12, 0x40, 0x86, 0x80, 0xd4, 0xb8, 0x0a, 0xb1,
0x9f, 0xdc, 0x68, 0x60, 0x14, 0x33, 0x1d, 0x88, 0xfb, 0xa2, 0xfc, 0x49,
0x0c, 0xa9, 0x76, 0x2d, 0xd7, 0x32, 0x3f, 0x77, 0xdb, 0x62, 0x8c, 0x35,
0x88, 0x5d, 0x66, 0xc9, 0x8d, 0x07, 0xe5};
const char kCodeSigningDevelopmentFlagOid[] = "1.3.6.1.4.1.11129.4.1.2";
const char kSecureStorageFlagOid[] = "1.3.6.1.4.1.11129.4.1.3";
} // namespace
namespace widevine {
VmpChecker::VmpChecker() : allow_development_vmp_(false) {}
VmpChecker::~VmpChecker() {}
Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
Status status = ca_cert->LoadDer(
cert_type == kCertificateTypeProduction
? std::string(reinterpret_cast<const char*>(
kProdVmpCodeSigningDrmRootCertificate),
sizeof(kProdVmpCodeSigningDrmRootCertificate))
: std::string(reinterpret_cast<const char*>(
kDevVmpCodeSigningDrmRootCertificate),
sizeof(kDevVmpCodeSigningDrmRootCertificate)));
if (!status.ok()) return status;
ca_.reset(new X509CA(ca_cert.release()));
return OkStatus();
}
VmpChecker* VmpChecker::Instance() {
static VmpChecker instance;
return &instance;
}
// Verify VMP data and return appropriate result.
Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
DCHECK(!vmp_data.empty());
DCHECK(result);
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 Status(error_space, INVALID_MESSAGE, "vmp-data-deserialize-failed");
}
std::vector<std::unique_ptr<X509Cert>> code_signing_certs;
const std::string kDevelopmentFlagOid(kCodeSigningDevelopmentFlagOid);
bool secure_storage_verified(true);
for (int cert_idx = 0; cert_idx < vmp_data_obj.certificates_size();
++cert_idx) {
code_signing_certs.emplace_back(new X509Cert);
Status status(code_signing_certs.back()->LoadDer(
vmp_data_obj.certificates(cert_idx)));
if (!status.ok()) return status;
if (!allow_development_vmp_) {
bool dev_flag;
if (code_signing_certs.back()->GetV3BooleanExtension(kDevelopmentFlagOid,
&dev_flag) &&
dev_flag) {
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"development-vmp-certificate-not-allowed");
}
}
status = ca_->VerifyCert(*code_signing_certs.back());
if (!status.ok()) return status;
if (secure_storage_verified) {
bool secure_storage_flag;
if (!code_signing_certs.back()->GetV3BooleanExtension(
kSecureStorageFlagOid, &secure_storage_flag) ||
!secure_storage_flag) {
secure_storage_verified = false;
}
}
}
size_t num_blessed_binaries(0);
for (int binary_idx = 0; binary_idx < vmp_data_obj.signed_binary_info_size();
++binary_idx) {
const vmp::VmpData::SignedBinaryInfo& binary_info(
vmp_data_obj.signed_binary_info(binary_idx));
if (binary_info.signature().empty()) {
LOG(INFO) << "Unsigned binary \"" << binary_info.file_name() << "\".";
*result = kTampered;
return OkStatus();
}
if (binary_info.certificate_index() >= code_signing_certs.size()) {
LOG(INFO) << "Invalid code signing certificate index.";
*result = kTampered;
return OkStatus();
}
X509Cert* cert = code_signing_certs[binary_info.certificate_index()].get();
std::unique_ptr<RsaPublicKey> key(cert->GetRsaPublicKey());
std::string message(binary_info.binary_hash());
message += binary_info.flags() & 0xff;
if (!key->VerifySignature(
message, HashAlgorithmProtoToEnum(binary_info.hash_algorithm()),
binary_info.signature())) {
LOG(INFO) << "Code signature verification failed for file \""
<< binary_info.file_name() << "\".";
*result = kTampered;
return OkStatus();
}
if (binary_info.flags() & kBlessedBinaryFlag) ++num_blessed_binaries;
}
if (num_blessed_binaries != 1) {
LOG(INFO) << "Invalid number of blessed binaries (" << num_blessed_binaries
<< ").";
*result = kTampered;
return OkStatus();
}
VLOG(2) << "VMP verification success. Secure storage: "
<< secure_storage_verified;
*result = secure_storage_verified ? kSecureStorageVerified : kVerified;
return OkStatus();
}
} // namespace widevine

View File

@@ -1,57 +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.
////////////////////////////////////////////////////////////////////////////////
//
// Description:
// Singleton object which validates VMP (Verified Media Pipeline) data for
// purposes of platform software verification.
#ifndef COMMON_VMP_CHECKER_H_
#define COMMON_VMP_CHECKER_H_
#include <memory>
#include <string>
#include "common/certificate_type.h"
#include "common/status.h"
namespace widevine {
class X509CA;
class VmpChecker {
public:
enum Result {
kUnverified = 0,
kVerified = 1,
kSecureStorageVerified = 2,
kTampered = 3
};
// Singleton accessor.
static VmpChecker* Instance();
// Select the type of root to use. Not thread-safe.
virtual Status SelectCertificateType(CertificateType cert_type);
// Verify VMP data and return appropriate 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; }
bool allow_development_vmp() const { return allow_development_vmp_; }
private:
VmpChecker();
~VmpChecker();
std::unique_ptr<X509CA> ca_;
bool allow_development_vmp_ = false;
};
} // namespace widevine
#endif // COMMON_VMP_CHECKER_H_

Some files were not shown because too many files have changed in this diff Show More