Add EMMG to carry fingerprinting and service blocking info
This commit is contained in:
17
common/BUILD
17
common/BUILD
@@ -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"],
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user