Export media_cas_packager_sdk

This commit is contained in:
Fang Yu
2018-10-01 14:59:29 -07:00
parent 5bdf48b400
commit ba0d63e2c1
110 changed files with 14079 additions and 0 deletions

564
common/BUILD Normal file
View File

@@ -0,0 +1,564 @@
################################################################################
# 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:
# Build file for code common to multiple Widevine services.
package(default_visibility = ["//visibility:public"])
filegroup(
name = "binary_release_files",
srcs = [
"certificate_type.h",
],
)
cc_library(
name = "certificate_type",
hdrs = ["certificate_type.h"],
)
cc_library(
name = "drm_root_certificate",
srcs = ["drm_root_certificate.cc"],
hdrs = ["drm_root_certificate.h"],
deps = [
":certificate_type",
":error_space",
":rsa_key",
"//base",
"@abseil_repo//absl/strings",
"//external:openssl",
"//util:status",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
"//protos/public:signed_drm_certificate_proto",
],
)
cc_test(
name = "drm_root_certificate_test",
timeout = "short",
srcs = ["drm_root_certificate_test.cc"],
deps = [
":drm_root_certificate",
"//base",
"//testing:gunit_main",
"//common:rsa_key",
"//common:rsa_test_keys",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
"//protos/public:signed_drm_certificate_proto",
],
)
cc_library(
name = "certificate_util",
srcs = ["certificate_util.cc"],
hdrs = ["certificate_util.h"],
deps = [
":certificate_type",
":drm_service_certificate",
":verified_media_pipeline",
":vmp_checker",
"//license_server_sdk/internal:sdk",
],
)
cc_library(
name = "client_id_util",
srcs = ["client_id_util.cc"],
hdrs = ["client_id_util.h"],
deps = [
":aes_cbc_util",
":drm_service_certificate",
":error_space",
"//base",
"@abseil_repo//absl/strings",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:errors_proto",
],
)
cc_library(
name = "rsa_util",
srcs = ["rsa_util.cc"],
hdrs = ["rsa_util.h"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "rsa_util_test",
size = "medium",
timeout = "short",
srcs = ["rsa_util_test.cc"],
deps = [
":rsa_test_keys",
":rsa_util",
"//testing:gunit",
"//testing:gunit_main",
"//external:openssl",
],
)
cc_library(
name = "openssl_util",
hdrs = ["openssl_util.h"],
deps = [
"//external:openssl",
],
)
cc_library(
name = "rsa_key",
srcs = ["rsa_key.cc"],
hdrs = ["rsa_key.h"],
deps = [
":rsa_util",
":sha_util",
"//base",
"//external:openssl",
],
)
cc_test(
name = "rsa_key_test",
size = "medium",
timeout = "short",
srcs = ["rsa_key_test.cc"],
deps = [
":rsa_key",
":rsa_test_keys",
"//testing:gunit",
"//testing:gunit_main",
],
)
cc_library(
name = "rsa_test_keys",
testonly = 1,
srcs = ["rsa_test_keys.cc"],
hdrs = ["rsa_test_keys.h"],
deps = [
"//base",
],
)
cc_library(
name = "mock_rsa_key",
testonly = 1,
hdrs = ["mock_rsa_key.h"],
deps = [
":rsa_key",
"//testing:gunit",
],
)
cc_library(
name = "aes_cbc_util",
srcs = ["aes_cbc_util.cc"],
hdrs = ["aes_cbc_util.h"],
visibility = ["//visibility:public"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "aes_cbc_util_test",
srcs = ["aes_cbc_util_test.cc"],
deps = [
":aes_cbc_util",
"//testing:gunit_main",
],
)
cc_library(
name = "crypto_util",
srcs = ["crypto_util.cc"],
hdrs = ["crypto_util.h"],
visibility = ["//visibility:public"],
deps = [
"//base",
"@abseil_repo//absl/strings",
"//external:openssl",
"//util/endian",
],
)
cc_test(
name = "crypto_util_test",
size = "medium",
srcs = ["crypto_util_test.cc"],
deps = [
":crypto_util",
"//testing:gunit",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "ecb_util",
srcs = ["ecb_util.cc"],
hdrs = ["ecb_util.h"],
visibility = ["//visibility:public"],
deps = [
"//base",
"@abseil_repo//absl/strings",
"//external:openssl",
],
)
cc_test(
name = "ecb_util_test",
size = "small",
srcs = ["ecb_util_test.cc"],
deps = [
":ecb_util",
"//testing:gunit",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "file_util",
srcs = ["file_util.cc"],
hdrs = ["file_util.h"],
deps = [
"//base",
],
)
cc_test(
name = "file_util_test",
srcs = ["file_util_test.cc"],
deps = [
":file_util",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "random_util",
srcs = ["random_util.cc"],
hdrs = ["random_util.h"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "random_util_test",
srcs = ["random_util_test.cc"],
deps = [
":random_util",
"//testing:gunit_main",
],
)
cc_library(
name = "sha_util",
srcs = ["sha_util.cc"],
hdrs = ["sha_util.h"],
deps = [
"//base",
"//external:openssl",
],
)
cc_test(
name = "sha_util_test",
srcs = ["sha_util_test.cc"],
deps = [
":sha_util",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "signature_util",
srcs = ["signature_util.cc"],
hdrs = ["signature_util.h"],
deps = [
":aes_cbc_util",
":rsa_key",
":sha_util",
"//base",
"//util:status",
],
)
cc_library(
name = "signing_key_util",
srcs = ["signing_key_util.cc"],
hdrs = ["signing_key_util.h"],
deps = [
":crypto_util",
"//base",
"//protos/public:license_protocol_proto",
],
)
cc_test(
name = "signing_key_util_test",
size = "small",
srcs = ["signing_key_util_test.cc"],
deps = [
":signing_key_util",
"//testing:gunit",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
"//protos/public:license_protocol_proto",
],
)
cc_library(
name = "test_certificates",
testonly = 1,
srcs = ["test_certificates.cc"],
hdrs = ["test_certificates.h"],
deps = [
"//base",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "wvm_token_handler",
srcs = ["wvm_token_handler.cc"],
hdrs = ["wvm_token_handler.h"],
deps = [
":aes_cbc_util",
":ecb_util",
":sha_util",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util/endian",
"//util/gtl:map_util",
"//util:status",
],
)
cc_test(
name = "wvm_token_handler_test",
size = "small",
srcs = ["wvm_token_handler_test.cc"],
deps = [
":wvm_test_keys",
":wvm_token_handler",
"//testing:gunit",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "wvm_test_keys",
testonly = 1,
srcs = ["wvm_test_keys.cc"],
hdrs = ["wvm_test_keys.h"],
deps = [
":wvm_token_handler",
"//base",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "error_space",
srcs = ["error_space.cc"],
hdrs = ["error_space.h"],
deps = [
"//util:status",
"//util:proto_status",
"//protos/public:errors_proto",
],
)
cc_library(
name = "remote_attestation_verifier",
srcs = ["remote_attestation_verifier.cc"],
hdrs = ["remote_attestation_verifier.h"],
deps = [
":client_id_util",
":drm_service_certificate",
":error_space",
":rsa_key",
":x509_cert",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:errors_proto",
"//protos/public:remote_attestation_proto",
],
)
cc_library(
name = "drm_service_certificate",
srcs = ["drm_service_certificate.cc"],
hdrs = ["drm_service_certificate.h"],
deps = [
":aes_cbc_util",
":certificate_type",
":drm_root_certificate",
":error_space",
":rsa_key",
":rsa_util",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util/gtl:map_util",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
"//protos/public:signed_drm_certificate_proto",
],
)
cc_test(
name = "drm_service_certificate_test",
timeout = "short",
srcs = ["drm_service_certificate_test.cc"],
deps = [
":aes_cbc_util",
":drm_service_certificate",
":rsa_key",
":rsa_test_keys",
":rsa_util",
":test_certificates",
"//base",
"//external:protobuf",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
"//protos/public:client_identification_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
"//protos/public:license_server_sdk_proto",
"//protos/public:signed_drm_certificate_proto",
],
)
cc_library(
name = "verified_media_pipeline",
srcs = ["verified_media_pipeline.cc"],
hdrs = ["verified_media_pipeline.h"],
deps = [
":vmp_checker",
"//base",
"@abseil_repo//absl/strings",
"//util:status",
"//protos/public:license_protocol_proto",
],
)
cc_library(
name = "x509_cert",
srcs = ["x509_cert.cc"],
hdrs = ["x509_cert.h"],
deps = [
":openssl_util",
":rsa_key",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//external:openssl",
"//util:status",
],
)
cc_library(
name = "test_utils",
testonly = 1,
srcs = ["test_utils.cc"],
hdrs = ["test_utils.h"],
deps = [
"//base",
"//external:openssl",
"//util:status",
],
)
cc_test(
name = "x509_cert_test",
timeout = "short",
srcs = ["x509_cert_test.cc"],
deps = [
":rsa_key",
":test_utils",
":x509_cert",
"//base",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
],
)
cc_library(
name = "vmp_checker",
srcs = ["vmp_checker.cc"],
hdrs = ["vmp_checker.h"],
deps = [
":certificate_type",
":error_space",
":x509_cert",
"//base",
"@abseil_repo//absl/strings",
"//protos/public:errors_proto",
"//protos/public:verified_media_pipeline_proto",
],
)
cc_test(
name = "vmp_checker_test",
timeout = "short",
srcs = ["vmp_checker_test.cc"],
deps = [
":rsa_key",
":vmp_checker",
"//base",
"//testing:gunit_main",
"@abseil_repo//absl/strings",
"//protos/public:errors_proto",
"//protos/public:verified_media_pipeline_proto",
],
)
cc_library(
name = "string_util",
srcs = ["string_util.cc"],
hdrs = ["string_util.h"],
deps = [
"//base",
"//util:status",
],
)
cc_test(
name = "string_util_test",
srcs = ["string_util_test.cc"],
deps = [
":string_util",
"//base",
"//testing:gunit_main",
],
)

132
common/aes_cbc_util.cc Normal file
View File

@@ -0,0 +1,132 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <vector>
#include <cstdint>
#include "glog/logging.h"
#include "openssl/aes.h"
namespace widevine {
namespace crypto_util {
// Encrypts the provided plantext std::string using AES-CBC encryption.
std::string EncryptAesCbc(const std::string& key, const std::string& iv,
const std::string& plaintext) {
const size_t num_padding_bytes =
AES_BLOCK_SIZE - (plaintext.size() % AES_BLOCK_SIZE);
std::string padded_text = plaintext;
padded_text.append(num_padding_bytes, static_cast<char>(num_padding_bytes));
return EncryptAesCbcNoPad(key, iv, padded_text);
}
std::string EncryptAesCbcNoPad(const std::string& key, const std::string& iv,
const std::string& plaintext) {
if (iv.size() != AES_BLOCK_SIZE) {
LOG(WARNING) << "Invalid CBC IV size: " << iv.size();
return std::string();
}
if (plaintext.size() % AES_BLOCK_SIZE) {
LOG(WARNING) << "Invalid AEC-CBC plaintext size: " << plaintext.size();
return std::string();
}
AES_KEY aes_key;
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
key.size() * 8, &aes_key) != 0) {
LOG(WARNING) << "Invalid AES key.";
return std::string();
}
std::string encrypted(plaintext.size(), 0);
std::vector<uint8_t> local_iv(iv.begin(), iv.end());
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(plaintext.data()),
reinterpret_cast<uint8_t*>(&encrypted[0]), plaintext.size(),
&aes_key, &local_iv[0], AES_ENCRYPT);
return encrypted;
}
// Decrypts the AES-CBC encrypted text. Returns an empty std::string on error or
// the plaintext on success.
std::string DecryptAesCbc(const std::string& key, const std::string& iv,
const std::string& ciphertext) {
if (ciphertext.empty()) {
LOG(WARNING) << "Empty ciphertext.";
return std::string();
}
if (iv.size() != AES_BLOCK_SIZE) {
LOG(WARNING) << "Invalid CBC IV size: " << iv.size();
return std::string();
}
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
LOG(WARNING) << "Ciphertext not a multiple of AES block size: "
<< ciphertext.size();
return std::string();
}
AES_KEY aes_key;
if (AES_set_decrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
key.size() * 8, &aes_key) != 0) {
LOG(WARNING) << "Invalid AES key.";
return std::string();
}
std::string cleartext(ciphertext.size(), 0);
std::vector<uint8_t> local_iv(iv.begin(), iv.end());
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
reinterpret_cast<uint8_t*>(&cleartext[0]), ciphertext.size(),
&aes_key, &local_iv[0], AES_DECRYPT);
const uint8_t num_padding_bytes = cleartext[cleartext.size() - 1];
if (num_padding_bytes > AES_BLOCK_SIZE) {
LOG(WARNING) << "AES padding too long: " << num_padding_bytes;
return std::string();
}
for (uint8_t i = 0; i < num_padding_bytes; ++i) {
if (cleartext[cleartext.size() - 1 - i] != num_padding_bytes) {
LOG(WARNING) << "Padding verification failure.";
return std::string();
}
}
cleartext.resize(cleartext.size() - num_padding_bytes);
return cleartext;
}
std::string DecryptAesCbcNoPad(const std::string& key, const std::string& iv,
const std::string& ciphertext) {
std::vector<uint8_t> local_iv(iv.begin(), iv.end());
if (local_iv.empty()) {
local_iv.resize(AES_BLOCK_SIZE, '\0');
} else if (local_iv.size() != AES_BLOCK_SIZE) {
LOG(WARNING) << "Invalid CBC IV size: " << iv.size();
return std::string();
}
if ((ciphertext.size() % AES_BLOCK_SIZE) != 0) {
LOG(WARNING) << "Ciphertext not a multiple of AES block size: "
<< ciphertext.size();
return std::string();
}
AES_KEY aes_key;
if (AES_set_decrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
key.size() * 8, &aes_key) != 0) {
LOG(WARNING) << "Invalid AES key.";
return std::string();
}
std::string cleartext(ciphertext.size(), 0);
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(ciphertext.data()),
reinterpret_cast<uint8_t*>(&cleartext[0]), ciphertext.size(),
&aes_key, &local_iv[0], AES_DECRYPT);
return cleartext;
}
} // namespace crypto_util
} // namespace widevine

43
common/aes_cbc_util.h Normal file
View File

@@ -0,0 +1,43 @@
////////////////////////////////////////////////////////////////////////////////
// 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_AES_CBC_UTIL_H_
#define COMMON_AES_CBC_UTIL_H_
#include <string>
namespace widevine {
namespace crypto_util {
// Helper for wrapping AES CBC encryption. Uses PKCS7 padding.
std::string EncryptAesCbc(const std::string& key, const std::string& iv,
const std::string& plaintext);
// Helper for wrapping AES CBC encryption. Adds no padding, so the input
// must be an multiple of the 16-byte AES block size. Returns empty std::string
// on error.
std::string EncryptAesCbcNoPad(const std::string& key, const std::string& iv,
const std::string& plaintext);
// Helper for common Keybox decrypt operations; wraps AES-CBC. Returns an
// empty std::string on error or the plaintext on success. Expects PKCS7 padding.
std::string DecryptAesCbc(const std::string& key, const std::string& iv,
const std::string& ciphertext);
// Helper for common Keybox decrypt operations; wraps AES-CBC. Returns an
// empty std::string on error or the plaintext on success.
// Uses no padding; fails if the ciphertext is not a multiple of 16 bytes.
// This is used to decrypt the encrypted blob in the WVM keyboxes, with
// a zero iv.
std::string DecryptAesCbcNoPad(const std::string& key, const std::string& iv,
const std::string& ciphertext);
} // namespace crypto_util
} // namespace widevine
#endif // COMMON_AES_CBC_UTIL_H_

162
common/aes_cbc_util_test.cc Normal file
View File

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

22
common/certificate_type.h Normal file
View File

@@ -0,0 +1,22 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2017 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CERTIFICATE_TYPE_H_
#define COMMON_CERTIFICATE_TYPE_H_
namespace widevine {
enum CertificateType {
kCertificateTypeTesting,
kCertificateTypeDevelopment,
kCertificateTypeProduction,
};
} // namespace widevine
#endif // COMMON_CERTIFICATE_TYPE_H_

View File

@@ -0,0 +1,54 @@
////////////////////////////////////////////////////////////////////////////////
// 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/certificate_util.h"
#include "common/drm_root_certificate.h"
#include "common/drm_service_certificate.h"
#include "common/verified_media_pipeline.h"
#include "common/vmp_checker.h"
#include "license_server_sdk/internal/client_cert.h"
#include "license_server_sdk/internal/device_status_list.h"
namespace widevine {
util::Status SetCertificateStatusList(
CertificateType cert_type, const std::string& signed_certificate_status_list,
uint32_t expiration_period_seconds, bool allow_unknown_devices) {
util::Status status =
VmpChecker::Instance()->SelectDrmCertificateType(cert_type);
if (!status.ok()) return status;
std::unique_ptr<DrmRootCertificate> root_cert;
status = DrmRootCertificate::CreateByType(cert_type, &root_cert);
if (!status.ok()) {
return status;
}
status = CertificateClientCert::SetDrmRootCertificatePublicKey(
root_cert->public_key());
if (!status.ok()) {
return status;
}
DeviceStatusList::Instance()->set_allow_unknown_devices(
allow_unknown_devices);
return DeviceStatusList::Instance()->UpdateStatusList(
root_cert->public_key(), signed_certificate_status_list,
expiration_period_seconds);
}
util::Status AddDrmServiceCertificate(
CertificateType cert_type, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
util::Status status =
VmpChecker::Instance()->SelectDrmCertificateType(cert_type);
if (!status.ok()) return status;
return DrmServiceCertificate::AddDrmServiceCertificate(
cert_type, service_certificate, service_private_key,
service_private_key_passphrase);
}
} // namespace widevine

42
common/certificate_util.h Normal file
View File

@@ -0,0 +1,42 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_CERTIFICATE_UTIL_H_
#define COMMON_CERTIFICATE_UTIL_H_
#include <string>
#include "util/status.h"
#include "common/certificate_type.h"
namespace widevine {
// Set the certificate status list system-wide. |cert_type| specifies
// whether to use development or production root certificates.
// |expiration_period| is the number of seconds until the
// certificate_status_list expires after its creation time
// (creation_time_seconds). If |allow_unknown_devices| is false, an error is
// returned if the device does not appear in the certificate_status_list.
util::Status SetCertificateStatusList(CertificateType cert_type,
const std::string& certificate_status_list,
uint32_t expiration_period_seconds,
bool allow_unknown_devices);
// Add a service certificate system-wide. |cert_type| indicates the type of
// root certificate used to sign the service certificate;
// |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; and |service_private_key_passphrase| is the
// password required to decrypt |service_private_key|.
util::Status AddDrmServiceCertificate(
CertificateType cert_type, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase);
} // namespace widevine
#endif // COMMON_CERTIFICATE_UTIL_H_

89
common/client_id_util.cc Normal file
View File

@@ -0,0 +1,89 @@
////////////////////////////////////////////////////////////////////////////////
// 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/drm_service_certificate.h"
#include "common/error_space.h"
#include "protos/public/errors.pb.h"
namespace widevine {
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;
}
util::Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id,
client_id);
}
util::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 util::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 util::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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return util::OkStatus();
}
} // namespace widevine

61
common/client_id_util.h Normal file
View File

@@ -0,0 +1,61 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "util/status.h"
#include "protos/public/client_identification.pb.h"
namespace widevine {
// 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 util::Status::OK, if successful, else an error.
util::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 util::Status::OK, if successful, else an error.
util::Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
const std::string& privacy_key, ClientIdentification* client_id);
} // namespace widevine
#endif // COMMON_CLIENT_ID_UTIL_H_

174
common/crypto_util.cc Normal file
View File

@@ -0,0 +1,174 @@
////////////////////////////////////////////////////////////////////////////////
// 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 Common crypto utilities used by Widevine services.
#include "common/crypto_util.h"
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include "glog/logging.h"
#include "absl/strings/string_view.h"
#include "openssl/aes.h"
#include "openssl/cmac.h"
#include "openssl/evp.h"
#include "util/endian/endian.h"
namespace widevine {
namespace crypto_util {
const char kEncryptionKeyLabel[] = "ENCRYPTION";
const int kEncryptionKeySizeBits = 128;
const char kSigningKeyLabel[] = "AUTHENTICATION";
const int kSigningKeySizeBits = 256;
const size_t kSigningKeySizeBytes = 32;
const char kIvMasterKey[] = "1234567890123456";
const char kIvLabel[] = "IV_ENCRYPTION";
const int kIvSizeBits = 128;
const char kGroupKeyLabel[] = "GROUP_ENCRYPTION";
// TODO(user): This is a temporary key for development. Replace this with
// a real group master key in keystore.
// TODO(user): figure out why VerifySignatureHmacSha256 can not crypto_mcmcpy
// like VerifySignatureHmacSha1.
const char kPhonyGroupMasterKey[] = "fedcba9876543210";
const int kAes128KeySizeBits = 128;
const int kAes128KeySizeBytes = 16;
const uint32_t kCENCSchemeID = 0x63656E63; // 'cenc' (AES-CTR): 0x63656E63
const uint32_t kCBC1SchemeID = 0x63626331; // 'cbc1' (AES-CBC): 0x63626331
const uint32_t kCENSSchemeID =
0x63656E73; // 'cens' (AES-CTR subsample): 0x63656E73
const uint32_t kCBCSSchemeID =
0x63626373; // 'cbcs' (AES-CBC subsample): 0x63626373
// Creates a SHA-256 HMAC signature for the given message.
std::string CreateSignatureHmacSha256(absl::string_view key,
absl::string_view message) {
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init(&ctx, key.data(), key.size(), EVP_sha256());
HMAC_Update(&ctx, reinterpret_cast<const unsigned char*>(message.data()),
message.size());
unsigned char digest[SHA256_DIGEST_LENGTH];
unsigned int digest_len;
HMAC_Final(&ctx, digest, &digest_len);
HMAC_CTX_cleanup(&ctx);
std::string s(reinterpret_cast<char*>(digest), digest_len);
return s;
}
// Compares the SHA-256 HMAC against the provided signature.
bool VerifySignatureHmacSha256(absl::string_view key,
absl::string_view signature,
absl::string_view message) {
return CreateSignatureHmacSha256(key, message) == signature;
}
// Creates a SHA-1 HMAC signature for the given message.
std::string CreateSignatureHmacSha1(absl::string_view key,
absl::string_view message) {
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init(&ctx, key.data(), key.size(), EVP_sha1());
HMAC_Update(&ctx, reinterpret_cast<const unsigned char*>(message.data()),
message.size());
unsigned char digest[SHA_DIGEST_LENGTH];
unsigned int digest_len;
HMAC_Final(&ctx, digest, &digest_len);
HMAC_CTX_cleanup(&ctx);
std::string s(reinterpret_cast<char*>(digest), digest_len);
return s;
}
// Compares the SHA-1 HMAC against the provided signature.
bool VerifySignatureHmacSha1(absl::string_view key, absl::string_view signature,
absl::string_view message) {
return CreateSignatureHmacSha1(key, message) == signature;
}
// Derives an AES 128 key from the provided key and additional info.
std::string DeriveKey(absl::string_view key, absl::string_view label,
absl::string_view context, const uint32_t size_bits) {
if (key.size() != kAes128KeySizeBytes) return "";
// We only handle even multiples of 16 bytes (128 bits) right now.
if ((size_bits % 128) || (size_bits > (128 * 255))) {
return "";
}
std::string result;
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
for (unsigned char counter = 1; counter <= (size_bits / 128); counter++) {
if (CMAC_Init(cmac_ctx, key.data(), key.size(), cipher, 0)) {
std::string message;
message.append(1, counter);
message.append(label.data(), label.size());
message.append(1, '\0');
message.append(context.data(), context.size());
char size_string[4];
BigEndian::Store32(&size_string, size_bits);
message.append(&size_string[0], &size_string[0] + 4);
if (CMAC_Update(cmac_ctx, reinterpret_cast<const uint8_t*>(message.data()),
message.size())) {
size_t reslen;
unsigned char res[AES_BLOCK_SIZE];
if (CMAC_Final(cmac_ctx, res, &reslen)) {
result.append(reinterpret_cast<const char*>(res), reslen);
}
DCHECK(reslen == AES_BLOCK_SIZE);
}
}
}
CMAC_CTX_free(cmac_ctx);
return result;
}
// Derives an IV from the provided info.
std::string DeriveIv(absl::string_view context) {
return DeriveKey(kIvMasterKey, kIvLabel, context, kIvSizeBits);
}
std::string DeriveGroupSessionKey(absl::string_view context,
const uint32_t size_bits) {
return DeriveKey(kPhonyGroupMasterKey, kGroupKeyLabel, context, size_bits);
}
std::string DeriveSigningKey(absl::string_view key, absl::string_view context,
const uint32_t size_bits) {
return DeriveKey(key, kSigningKeyLabel, context, size_bits);
}
bool FourCCEncryptionSchemeIDFromString(const std::string& requested,
uint32_t* four_cc_code) {
if (requested.size() != 4 || four_cc_code == nullptr) return false;
uint32_t result = 0;
for (auto i = 0; i < 4; ++i) {
result <<= 8;
result |= requested[i];
}
switch (result) {
case kCENCSchemeID:
case kCBC1SchemeID:
case kCENSSchemeID:
case kCBCSSchemeID:
*four_cc_code = result;
return true;
default:
return false;
}
}
} // namespace crypto_util
} // namespace widevine

86
common/crypto_util.h Normal file
View File

@@ -0,0 +1,86 @@
////////////////////////////////////////////////////////////////////////////////
// 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 common crypto routines for widevine protocols. These routines are
// used as part of licensing and provisioning request handling.
#ifndef COMMON_CRYPTO_UTIL_H_
#define COMMON_CRYPTO_UTIL_H_
#include <string>
#include "base/macros.h"
#include "absl/strings/string_view.h"
namespace widevine {
namespace crypto_util {
// Default constants used for key derivation for encryption and signing.
// TODO(user): These are duplicated in session.cc in the sdk. de-dup.
extern const char kEncryptionKeyLabel[];
extern const int kEncryptionKeySizeBits;
extern const char kSigningKeyLabel[];
extern const int kSigningKeySizeBits;
extern const size_t kSigningKeySizeBytes;
extern const char kIvMasterKey[];
extern const char kIvLabel[];
extern const int kIvSizeBits;
extern const int kAes128KeySizeBits;
extern const int kAes128KeySizeBytes;
extern const uint32_t kCENCSchemeID; // 'cenc' (AES-CTR): 0x63656E63
extern const uint32_t kCBC1SchemeID; // 'cbc1' (AES-CBC): 0x63626331
extern const uint32_t kCENSSchemeID; // 'cens' (AES-CTR subsample): 0x63656E73
extern const uint32_t kCBCSSchemeID; // 'cbcs' (AES-CBC subsample): 0x63626373
// DeriveKey uses 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
std::string DeriveKey(absl::string_view key, absl::string_view label,
absl::string_view context, const uint32_t size_bits);
// Derives an IV from the provided |context|.
std::string DeriveIv(absl::string_view context);
// Helper function to derive a key using the group master key and context.
std::string DeriveGroupSessionKey(absl::string_view context, const uint32_t size_bits);
// Helper function to derive a signing key for from the signing context.
std::string DeriveSigningKey(absl::string_view key, absl::string_view context,
const uint32_t size_bits);
// Helper function to create a SHA-256 HMAC signature for the given message.
std::string CreateSignatureHmacSha256(absl::string_view key,
absl::string_view message);
// Helper function which compares the SHA-256 HMAC against the provided
// signature.
bool VerifySignatureHmacSha256(absl::string_view key,
absl::string_view signature,
absl::string_view message);
// Helper function to create a SHA-1 HMAC signature for the given message.
std::string CreateSignatureHmacSha1(absl::string_view key,
absl::string_view message);
// Helper function which compares the SHA-1 HMAC against the provided
// signature.
bool VerifySignatureHmacSha1(absl::string_view key, absl::string_view signature,
absl::string_view message);
// Converts a requested 4CC encryption scheme ID from a std::string to a uint32_t and
// verifies it is a correct value.
bool FourCCEncryptionSchemeIDFromString(const std::string& requested,
uint32_t* four_cc_code);
} // namespace crypto_util
} // namespace widevine
#endif // COMMON_CRYPTO_UTIL_H_

222
common/crypto_util_test.cc Normal file
View File

@@ -0,0 +1,222 @@
////////////////////////////////////////////////////////////////////////////////
// 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"
namespace widevine {
namespace crypto_util {
const char kCENCStr[] = "cenc";
const char kCBC1Str[] = "cbc1";
const char kCENSStr[] = "cens";
const char kCBCSStr[] = "cbcs";
static unsigned char key_data[] =
{ 0x87, 0x27, 0xa4, 0x0e, 0xbd, 0x82, 0x32, 0x9e,
0x6b, 0x3b, 0x4e, 0x29, 0xfa, 0x3b, 0x00, 0x4b };
static std::string key_str(key_data, key_data + sizeof(key_data));
static unsigned char iv_data[] =
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
static std::string iv_str(iv_data, iv_data + sizeof(iv_data));
TEST(CryptoUtilTest, DeriveAes128KeyTest) {
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 key_str(key_data, key_data + sizeof(key_data));
std::string context_str(context, context + sizeof(context));
std::string result = DeriveKey(key_str, label_str, context_str, 128);
std::string output_128(output0, output0 + sizeof(output0));
ASSERT_EQ(result, output_128);
result = DeriveKey(key_str, label_str, context_str, 384);
std::string output_384(output1, output1 + sizeof(output1));
ASSERT_EQ(result, output_384);
}
TEST(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(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(key_str, message));
ASSERT_EQ(signature.size(), 32);
ASSERT_TRUE(VerifySignatureHmacSha256(key_str, signature, message));
}
TEST(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(key_str, message);
// Test with bogus key.
ASSERT_FALSE(VerifySignatureHmacSha256(bogus_key, signature, message));
// Test with munged signature.
signature[0] = 0xFF;
ASSERT_FALSE(VerifySignatureHmacSha256(key_str, signature, message));
// Test with bogus signature.
ASSERT_FALSE(VerifySignatureHmacSha256(key_str, "bogus", message));
}
TEST(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(key_str, message));
ASSERT_EQ(20, signature.size());
ASSERT_TRUE(VerifySignatureHmacSha1(key_str, signature, message));
}
TEST(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(key_str, message);
// Test with bogus key.
ASSERT_FALSE(VerifySignatureHmacSha1(bogus_key, signature, message));
// Test with munged signature.
signature[0] = 0xFF;
ASSERT_FALSE(VerifySignatureHmacSha1(key_str, signature, message));
// Test with bogus signature.
ASSERT_FALSE(VerifySignatureHmacSha1(key_str, "bogus", message));
}
TEST(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(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(CryptoUtilTest, Verify4CCEncryptionIDFromString) {
uint32_t cc_code = 0;
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENCStr, &cc_code));
ASSERT_EQ(kCENCSchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBC1Str, &cc_code));
ASSERT_EQ(kCBC1SchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCENSStr, &cc_code));
ASSERT_EQ(kCENSSchemeID, cc_code);
ASSERT_TRUE(FourCCEncryptionSchemeIDFromString(kCBCSStr, &cc_code));
ASSERT_EQ(kCBCSSchemeID, cc_code);
}
} // namespace crypto_util
} // namespace widevine

View File

@@ -0,0 +1,319 @@
////////////////////////////////////////////////////////////////////////////////
// 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_root_certificate.h"
#include <memory>
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "openssl/sha.h"
#include "common/error_space.h"
#include "common/rsa_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 {
// From common::TestCertificates.
// 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};
util::Status DrmRootCertificate::Create(
const std::string& signed_drm_certificate,
std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
SignedDrmCertificate signed_root_cert;
if (!signed_root_cert.ParseFromString(signed_drm_certificate)) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"signed-root-cert-deserialize-fail");
}
DrmCertificate root_cert;
if (!signed_root_cert.has_drm_certificate()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-device-certificate");
}
if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"root-cert-deserialize-fail");
}
if (!root_cert.has_public_key()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-cert-public-key");
}
if (!signed_root_cert.has_signature()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-certificate-signature");
}
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(root_cert.public_key()));
if (!public_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
}
if (!public_key->VerifySignature(signed_root_cert.drm_certificate(),
signed_root_cert.signature())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-certificate-signature");
}
cert->reset(new DrmRootCertificate(root_cert.public_key()));
return util::OkStatus();
}
util::Status DrmRootCertificate::CreateByType(
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
return Create(GetDrmRootCertificate(cert_type), cert);
}
std::string DrmRootCertificate::GetDrmRootCertificate(CertificateType cert_type) {
std::string root_cert;
switch (cert_type) {
case kCertificateTypeProduction: {
root_cert.assign(kProdRootCertificate,
kProdRootCertificate + sizeof(kProdRootCertificate));
break;
}
case kCertificateTypeDevelopment: {
root_cert.assign(kDevRootCertificate,
kDevRootCertificate + sizeof(kDevRootCertificate));
break;
}
case kCertificateTypeTesting: {
root_cert.assign(kTestRootCertificate,
kTestRootCertificate + sizeof(kTestRootCertificate));
break;
}
default:
// TODO(user): Consider returning util::Status indicating unsupported
// cert type.
break;
}
return root_cert;
}
std::string DrmRootCertificate::GetDigest(CertificateType cert_type) {
std::string cert(GetDrmRootCertificate(cert_type));
if (cert.empty()) {
return std::string();
}
std::string hash(SHA256_DIGEST_LENGTH, 0);
SHA256(reinterpret_cast<const unsigned char*>(cert.data()), cert.size(),
reinterpret_cast<unsigned char*>(&hash[0]));
return absl::BytesToHexString(hash);
}
} // namespace widevine

View File

@@ -0,0 +1,66 @@
////////////////////////////////////////////////////////////////////////////////
// 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__
#include <memory>
#include <string>
#include "base/macros.h"
#include "util/status.h"
#include "common/certificate_type.h"
namespace widevine {
class DrmRootCertificate {
public:
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 DrmRootCertificate* if successful. The caller assumes ownership of
// the new DrmRootCertificate. This method returns util::Status::OK on
// success, or appropriate error status otherwise.
static util::Status CreateByType(CertificateType cert_type,
std::unique_ptr<DrmRootCertificate>* cert);
// Returns the hex-encoded SHA-256 digest for the specified root certificate.
static std::string GetDigest(CertificateType cert_type);
// Given |cert_type|, the appropiate root certificate is returned as
// a serialized SignedDrmCertificates.
static std::string GetDrmRootCertificate(CertificateType cert_type);
const std::string& public_key() const { return public_key_; }
// Verifies a DRM certificate.
private:
friend class DrmRootCertificateTest;
// Creates a DrmRootCertificate object given a serialized
// SignedDrmCertificate. |cert| may not be nullptr, and it points to a
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
// created DrmRootCertificate* if successful. The caller assumes ownership of
// the new DrmRootCertificate. This method returns util::Status::OK on
// success, or appropriate error status otherwise.
// TODO(user): Consider moving to private.
static util::Status Create(const std::string& signed_drm_certificate,
std::unique_ptr<DrmRootCertificate>* cert);
explicit DrmRootCertificate(const std::string& public_key)
: public_key_(public_key) {}
std::string public_key_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DrmRootCertificate);
};
} // namespace widevine
#endif // COMMON_DRM_ROOT_CERTIFICATE_H__

View File

@@ -0,0 +1,101 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "testing/gunit.h"
#include "common/rsa_key.h"
#include "common/rsa_test_keys.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
namespace widevine {
class DrmRootCertificateTest : public testing::Test {
protected:
DrmRootCertificateTest() {}
util::Status DrmRootCertificateCreate(
const std::string& signed_drm_certificate,
std::unique_ptr<DrmRootCertificate>* cert) {
return DrmRootCertificate::Create(signed_drm_certificate, cert);
}
};
TEST_F(DrmRootCertificateTest, DrmRootCertificateCreation) {
RsaTestKeys test_keys;
std::unique_ptr<DrmRootCertificate> root_cert;
// First, invalid serialized cert. Should fail.
EXPECT_EQ(INVALID_DRM_CERTIFICATE,
DrmRootCertificateCreate("bad_cert", &root_cert).error_code());
SignedDrmCertificate signed_cert;
std::string serialized;
// Serialized empty cert. Should fail.
ASSERT_TRUE(signed_cert.SerializeToString(&serialized));
EXPECT_NE(util::OkStatus(),
DrmRootCertificateCreate(serialized, &root_cert));
// Add public key. Should still fail.
DrmCertificate drm_cert;
drm_cert.set_public_key(test_keys.public_test_key_1_3072_bits());
ASSERT_TRUE(
drm_cert.SerializeToString(signed_cert.mutable_drm_certificate()));
ASSERT_TRUE(signed_cert.SerializeToString(&serialized));
EXPECT_EQ(INVALID_DRM_CERTIFICATE,
DrmRootCertificateCreate(serialized, &root_cert).error_code());
// Now self-sign the cert. Should succeed.
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_keys.private_test_key_1_3072_bits()));
ASSERT_TRUE(private_key.get());
ASSERT_TRUE(private_key->GenerateSignature(signed_cert.drm_certificate(),
signed_cert.mutable_signature()));
ASSERT_TRUE(signed_cert.SerializeToString(&serialized));
EXPECT_EQ(util::OkStatus(),
DrmRootCertificateCreate(serialized, &root_cert));
ASSERT_TRUE(root_cert);
// Verify the public key.
EXPECT_EQ(test_keys.public_test_key_1_3072_bits(), root_cert->public_key());
}
TEST_F(DrmRootCertificateTest, DrmRootCertificateCreationByType) {
std::unique_ptr<DrmRootCertificate> root_cert;
EXPECT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeDevelopment, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeProduction, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
}
TEST_F(DrmRootCertificateTest, DrmRootCertificateDigest) {
const std::string test_cert_hash(
"49f917b1bdfed78002a58e799a58e940"
"1fffaaed9d8d80752782b066757e2c8c");
const std::string dev_cert_hash(
"0e25ee95476a770f30b98ac5ef778b3f"
"137b66c29385b84f547a361b4724b17d");
const std::string prod_cert_hash(
"d62fdabc9286648a81f7d3bedaf2f5a5"
"27bbad39bc38da034ba98a21569adb9b");
EXPECT_EQ(test_cert_hash,
DrmRootCertificate::GetDigest(kCertificateTypeTesting));
EXPECT_EQ(dev_cert_hash,
DrmRootCertificate::GetDigest(kCertificateTypeDevelopment));
EXPECT_EQ(prod_cert_hash,
DrmRootCertificate::GetDigest(kCertificateTypeProduction));
}
} // namespace widevine

View File

@@ -0,0 +1,314 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "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/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* GetCert(const std::string& serial_number);
static DrmServiceCertificateMap* GetInstance();
private:
absl::Mutex mutex_;
// Certificate serial number to certificate map.
std::map<std::string, std::unique_ptr<DrmServiceCertificate>> map_
GUARDED_BY(mutex_);
DrmServiceCertificate* default_cert_ 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::GetCert(
const std::string& serial_number) {
absl::ReaderMutexLock lock(&mutex_);
return map_[serial_number].get();
}
DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
static auto* const kInstance = new DrmServiceCertificateMap();
return kInstance;
}
} // namespace
util::Status DrmServiceCertificate::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) {
std::unique_ptr<RsaPublicKey> root_key(RsaPublicKey::Create(root_public_key));
if (root_key == nullptr) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"root-certificate-rsa-public-key-failed");
}
SignedDrmCertificate signed_cert;
if (!signed_cert.ParseFromString(service_certificate)) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"signed-certificate-parse-failed");
}
if (!root_key->VerifySignature(signed_cert.drm_certificate(),
signed_cert.signature())) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"certificate-signature-verification-failed");
}
DrmCertificate drm_cert;
if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"certificate-parse-failed");
}
if (drm_cert.type() != DrmCertificate::SERVICE) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"not-service-certificate");
}
if (drm_cert.serial_number().empty()) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-serial-number");
}
if (drm_cert.provider_id().empty()) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-service-id");
}
if (!drm_cert.has_creation_time_seconds()) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-creation-time");
}
if (drm_cert.public_key().empty()) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-public-key");
}
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(drm_cert.public_key()));
if (!public_key) {
return util::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 util::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 util::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 util::OkStatus();
}
util::Status DrmServiceCertificate::AddDrmServiceCertificate(
CertificateType root_cert_type, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
std::unique_ptr<DrmRootCertificate> root_cert;
util::Status status =
DrmRootCertificate::CreateByType(root_cert_type, &root_cert);
if (!status.ok()) {
return status;
}
return AddDrmServiceCertificate(root_cert->public_key(), service_certificate,
service_private_key,
service_private_key_passphrase);
}
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::GetDrmServiceCertificate(
const std::string& serial_number) {
return DrmServiceCertificateMap::GetInstance()->GetCert(serial_number);
}
util::Status DrmServiceCertificate::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) {
DrmServiceCertificateMap::GetInstance()->ClearDefaultDrmServiceCertificate();
return AddDrmServiceCertificate(root_public_key, service_certificate,
service_private_key,
service_private_key_passphrase);
}
util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
CertificateType root_cert_type, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
std::unique_ptr<DrmRootCertificate> root_cert;
util::Status status =
DrmRootCertificate::CreateByType(root_cert_type, &root_cert);
if (!status.ok()) {
return status;
}
return SetDefaultDrmServiceCertificate(
root_cert->public_key(), service_certificate, service_private_key,
service_private_key_passphrase);
}
util::Status DrmServiceCertificate::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
DCHECK(client_id);
if (encrypted_client_id.service_certificate_serial_number().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-certificate-serial-number");
}
if (encrypted_client_id.provider_id().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-id");
}
if (encrypted_client_id.encrypted_client_id().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-privacy-key");
}
std::string privacy_key;
std::string provider_id;
const DrmServiceCertificate* cert = GetDrmServiceCertificate(
encrypted_client_id.service_certificate_serial_number());
if (!cert) {
return util::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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"privacy-key-decryption-failed");
}
if (cert->provider_id() != encrypted_client_id.provider_id()) {
return util::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 util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return util::OkStatus();
}
void DrmServiceCertificate::ResetServiceCertificates() {
DrmServiceCertificateMap::GetInstance()->Reset();
}
DrmServiceCertificate::DrmServiceCertificate(
const std::string& service_certificate, const std::string& provider_id,
const std::string& serial_number, const uint32_t creation_time_seconds,
std::unique_ptr<RsaPublicKey> public_key,
std::unique_ptr<RsaPrivateKey> private_key)
: certificate_(service_certificate),
provider_id_(provider_id),
serial_number_(serial_number),
creation_time_seconds_(creation_time_seconds),
public_key_(std::move(public_key)),
private_key_(std::move(private_key)) {}
} // namespace widevine

View File

@@ -0,0 +1,123 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "base/macros.h"
#include "util/status.h"
#include "common/certificate_type.h"
#include "common/rsa_key.h"
namespace widevine {
class RequestInspectorTest;
} // namespace widevine
namespace widevine {
class ClientIdentification;
class EncryptedClientIdentification;
class DrmServiceCertificate {
public:
// Create a new DrmServiceCertificate object and add it to the list of valid
// service certificates. |root_cert_type| indicates which root public key to
// use to verify |service_certificate|, |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 util::Status AddDrmServiceCertificate(
CertificateType root_cert_type, 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 util::Status SetDefaultDrmServiceCertificate(
CertificateType root_cert_type, 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 serial number if found, or
// null otherwise.
static const DrmServiceCertificate* GetDrmServiceCertificate(
const std::string& cert_serial_number);
// 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 util::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_; }
const RsaPrivateKey* const private_key() const { return private_key_.get(); }
const RsaPublicKey* const public_key() const { return public_key_.get(); }
private:
friend class DrmServiceCertificateTest;
friend class widevine::RequestInspectorTest;
static util::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 util::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_;
DISALLOW_IMPLICIT_CONSTRUCTORS(DrmServiceCertificate);
};
} // namespace widevine
#endif // COMMON_DRM_SERVICE_CERTIFICATE_H__

View File

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

113
common/ecb_util.cc Normal file
View File

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

59
common/ecb_util.h Normal file
View File

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

90
common/ecb_util_test.cc Normal file
View File

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

19
common/error_space.cc Normal file
View File

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

20
common/error_space.h Normal file
View File

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

63
common/file_util.cc Normal file
View File

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

27
common/file_util.h Normal file
View File

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

30
common/file_util_test.cc Normal file
View File

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

73
common/mock_rsa_key.h Normal file
View File

@@ -0,0 +1,73 @@
////////////////////////////////////////////////////////////////////////////////
// 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/rsa_key.h"
namespace widevine {
class MockRsaPrivateKey : public RsaPrivateKey {
public:
MockRsaPrivateKey() : RsaPrivateKey(RSA_new()) {}
~MockRsaPrivateKey() override {}
MOCK_CONST_METHOD2(Decrypt, bool(const std::string& encrypted_message,
std::string* decrypted_message));
MOCK_CONST_METHOD2(GenerateSignature,
bool(const std::string& message, std::string* signature));
MOCK_CONST_METHOD1(MatchesPrivateKey, bool(const RsaPrivateKey& private_key));
MOCK_CONST_METHOD1(MatchesPublicKey, bool(const RsaPublicKey& public_key));
private:
MockRsaPrivateKey(const MockRsaPrivateKey&) = delete;
MockRsaPrivateKey& operator=(const MockRsaPrivateKey&) = delete;
};
class MockRsaPublicKey : public RsaPublicKey {
public:
MockRsaPublicKey() : RsaPublicKey(RSA_new()) {}
~MockRsaPublicKey() override {}
MOCK_CONST_METHOD2(Encrypt, bool(const std::string& clear_message,
std::string* encrypted_message));
MOCK_CONST_METHOD2(VerifySignature, bool(const std::string& message,
const std::string& signature));
MOCK_CONST_METHOD1(MatchesPrivateKey, bool(const RsaPrivateKey& private_key));
MOCK_CONST_METHOD1(MatchesPublicKey, bool(const RsaPublicKey& public_key));
private:
MockRsaPublicKey(const MockRsaPublicKey&) = delete;
MockRsaPublicKey& operator=(const MockRsaPublicKey&) = delete;
};
class MockRsaKeyFactory : public RsaKeyFactory{
public:
MockRsaKeyFactory() {}
~MockRsaKeyFactory() override {}
MOCK_METHOD1(CreateFromPkcs1PrivateKey,
std::unique_ptr<RsaPrivateKey>(const std::string& private_key));
MOCK_METHOD2(
CreateFromPkcs8PrivateKey,
std::unique_ptr<RsaPrivateKey>(const std::string& private_key,
const std::string& private_key_passphrase));
MOCK_METHOD1(CreateFromPkcs1PublicKey,
std::unique_ptr<RsaPublicKey>(const std::string& public_key));
private:
MockRsaKeyFactory(const MockRsaKeyFactory&) = delete;
MockRsaKeyFactory& operator=(const MockRsaKeyFactory&) = delete;
};
} // namespace widevine
#endif // COMMON_MOCK_RSA_KEY_H_

77
common/openssl_util.h Normal file
View File

@@ -0,0 +1,77 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
//
// RAII wrapper classes for cleaning up various OpenSSL dynamically allocated
// structures.
#ifndef COMMON_OPENSSL_UTIL_H__
#define COMMON_OPENSSL_UTIL_H__
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/rsa.h"
#include "openssl/x509v3.h"
template <typename T, void (*func)(T *)>
struct OpenSSLDeleter {
void operator()(T *obj) { func(obj); }
};
template <typename StackType, typename T, void (*func)(T *)>
struct OpenSSLStackDeleter {
void operator()(StackType *obj) {
sk_pop_free(reinterpret_cast<_STACK *>(obj),
reinterpret_cast<void (*)(void *)>(func));
}
};
template <typename StackType>
struct OpenSSLStackOnlyDeleter {
void operator()(StackType *obj) { sk_free(reinterpret_cast<_STACK *>(obj)); }
};
template <typename T, void (*func)(T *)>
using ScopedOpenSSLType = std::unique_ptr<T, OpenSSLDeleter<T, func>>;
template <typename StackType, typename T, void (*func)(T *)>
using ScopedOpenSSLStack =
std::unique_ptr<StackType, OpenSSLStackDeleter<StackType, T, func>>;
template <typename StackType>
using ScopedOpenSSLStackOnly =
std::unique_ptr<StackType, OpenSSLStackOnlyDeleter<StackType>>;
using ScopedBIGNUM = ScopedOpenSSLType<BIGNUM, BN_free>;
using ScopedBIO = ScopedOpenSSLType<BIO, BIO_vfree>;
using ScopedPKEY = ScopedOpenSSLType<EVP_PKEY, EVP_PKEY_free>;
using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>;
using ScopedX509 = ScopedOpenSSLType<X509, X509_free>;
using ScopedX509Extension =
ScopedOpenSSLType<X509_EXTENSION, X509_EXTENSION_free>;
using ScopedX509Name = ScopedOpenSSLType<X509_NAME, X509_NAME_free>;
using ScopedX509NameEntry =
ScopedOpenSSLType<X509_NAME_ENTRY, X509_NAME_ENTRY_free>;
using ScopedX509Store = ScopedOpenSSLType<X509_STORE, X509_STORE_free>;
using ScopedX509StoreCtx =
ScopedOpenSSLType<X509_STORE_CTX, X509_STORE_CTX_free>;
using ScopedX509Req = ScopedOpenSSLType<X509_REQ, X509_REQ_free>;
using ScopedAsn1UtcTime = ScopedOpenSSLType<ASN1_UTCTIME, ASN1_UTCTIME_free>;
using ScopedAsn1Utc8String =
ScopedOpenSSLType<ASN1_UTF8STRING, ASN1_UTF8STRING_free>;
using ScopedAsn1Integer = ScopedOpenSSLType<ASN1_INTEGER, ASN1_INTEGER_free>;
using ScopedAsn1Object = ScopedOpenSSLType<ASN1_OBJECT, ASN1_OBJECT_free>;
using ScopedAsn1OctetString =
ScopedOpenSSLType<ASN1_OCTET_STRING, ASN1_OCTET_STRING_free>;
// XxxStack deallocates the stack and its members while XxxStackOnly deallocates
// the stack only.
using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
using ScopedX509StackOnly = ScopedOpenSSLStackOnly<STACK_OF(X509)>;
using ScopedX509InfoStack =
ScopedOpenSSLStack<STACK_OF(X509_INFO), X509_INFO, X509_INFO_free>;
using ScopedX509InfoStackOnly = ScopedOpenSSLStackOnly<STACK_OF(X509_INFO)>;
#endif // COMMON_OPENSSL_UTIL_H__

27
common/random_util.cc Normal file
View File

@@ -0,0 +1,27 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "glog/logging.h"
#include "openssl/rand.h"
namespace widevine {
bool RandomBytes(size_t num_bytes, std::string* output) {
DCHECK(output);
output->resize(num_bytes);
return RAND_bytes(reinterpret_cast<uint8_t*>(&(*output)[0]), num_bytes);
}
std::string Random16Bytes() {
std::string output;
CHECK(RandomBytes(16u, &output));
return output;
}
} // namespace widevine

25
common/random_util.h Normal file
View File

@@ -0,0 +1,25 @@
////////////////////////////////////////////////////////////////////////////////
// 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_RANDOM_UTIL_H_
#define COMMON_RANDOM_UTIL_H_
#include <string>
namespace widevine {
// Generates a random string.
// Returns true on success, false otherwise.
bool RandomBytes(size_t num_bytes, std::string* output);
// Returns a 16-byte std::string suitable for use as an AES key
std::string Random16Bytes();
} // namespace widevine
#endif // COMMON_RANDOM_UTIL_H_

View File

@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2016 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/random_util.h"
#include "testing/gunit.h"
namespace widevine {
TEST(RandomUtilTest, Test) {
std::string output;
ASSERT_TRUE(RandomBytes(16u, &output));
EXPECT_EQ(16u, output.size());
std::string output2;
ASSERT_TRUE(RandomBytes(16u, &output2));
EXPECT_EQ(16u, output2.size());
EXPECT_NE(output, output2);
ASSERT_TRUE(RandomBytes(10u, &output2));
EXPECT_EQ(10u, output2.size());
}
} // namespace widevine

View File

@@ -0,0 +1,261 @@
////////////////////////////////////////////////////////////////////////////////
// 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::EnableTestCertificates(bool enable) {
absl::WriterMutexLock lock(&ca_mutex_);
enable_test_certificates_ = enable;
ca_.reset();
}
util::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 (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
}
if (!remote_attestation.has_salt()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
}
if (!remote_attestation.has_signature()) {
return (util::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;
util::Status status = DrmServiceCertificate::DecryptClientIdentification(
remote_attestation.certificate(), &client_id);
if (!status.ok()) return status;
if (client_id.type() !=
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
return (util::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);
}
util::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 (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
}
if (!remote_attestation.has_salt()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
}
if (!remote_attestation.has_signature()) {
return (util::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;
util::Status status = DecryptEncryptedClientIdentification(
remote_attestation.certificate(), privacy_key, &client_id);
if (!status.ok()) return status;
if (client_id.type() !=
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
return (util::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);
}
util::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 (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-token-missing"));
}
// Load and verify the certificate chain.
std::unique_ptr<X509CertChain> cert_chain(new X509CertChain);
util::Status status = cert_chain->LoadPem(client_id.token());
if (!status.ok()) return status;
if (cert_chain->GetNumCerts() < 1) {
return (util::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 (util::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 (util::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 util::Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-cert-chain-no-leaf");
}
if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt,
remote_attestation.signature())) {
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-signature-verification-failed: "));
}
*remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber();
return util::OkStatus();
}
util::Status RemoteAttestationVerifier::LoadCa() {
absl::WriterMutexLock lock(&ca_mutex_);
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
util::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 util::OkStatus();
}
} // namespace widevine

View File

@@ -0,0 +1,92 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "base/macros.h"
#include "base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "util/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) {}
virtual ~RemoteAttestationVerifier() {}
// Singleton accessor.
static RemoteAttestationVerifier& get();
// Call to use the test (non-production) remote attestation root certificate.
// This method is thread-safe.
void EnableTestCertificates(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.
util::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.
util::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.
util::Status VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
const ClientIdentification& client_id,
std::string* remote_attestation_cert_sn);
util::Status LoadCa();
bool enable_test_certificates_;
absl::Mutex ca_mutex_;
std::unique_ptr<X509CA> ca_ GUARDED_BY(ca_mutex_);
DISALLOW_COPY_AND_ASSIGN(RemoteAttestationVerifier);
};
} // namespace widevine
#endif // COMMON_REMOTE_ATTESTATION_VERIFIER_H__

313
common/rsa_key.cc Normal file
View File

@@ -0,0 +1,313 @@
////////////////////////////////////////////////////////////////////////////////
// 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:
// Definition of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
//
// RSA signature details:
// Algorithm: RSASSA-PSS
// Hash algorithm: SHA1
// Mask generation function: mgf1SHA1
// Salt length: 20 bytes
// Trailer field: 0xbc
//
// RSA encryption details:
// Algorithm: RSA-OAEP
// Mask generation function: mgf1SHA1
// Label (encoding paramter): empty std::string
#include "common/rsa_key.h"
#include "glog/logging.h"
#include "openssl/bn.h"
#include "openssl/err.h"
#include "openssl/evp.h"
#include "openssl/rsa.h"
#include "openssl/sha.h"
#include "common/rsa_util.h"
#include "common/sha_util.h"
static const int kPssSaltLength = 20;
namespace {
// Check if two RSA keys match. If matches, they are either a public-private key
// pair or the same public key or the same private key.
bool RsaKeyMatch(const RSA* key1, const RSA* key2) {
if (!key1 || !key2) return false;
return BN_cmp(key1->n, key2->n) == 0;
}
std::string OpenSSLErrorString(uint32_t error) {
char buf[ERR_ERROR_STRING_BUF_LEN];
ERR_error_string_n(error, buf, sizeof(buf));
return buf;
}
} // namespace
namespace widevine {
RsaPrivateKey::RsaPrivateKey(RSA* key) : key_(key) { CHECK(key_ != nullptr); }
RsaPrivateKey::RsaPrivateKey(const RsaPrivateKey& rsa_key)
: key_(RSAPrivateKey_dup(rsa_key.key_)) {
CHECK(key_ != nullptr);
}
RsaPrivateKey::~RsaPrivateKey() { RSA_free(key_); }
RsaPrivateKey* RsaPrivateKey::Create(const std::string& serialized_key) {
RSA* key;
if (!rsa_util::DeserializeRsaPrivateKey(serialized_key, &key)) return nullptr;
if (RSA_check_key(key) != 1) {
LOG(ERROR) << "Invalid private RSA key: "
<< OpenSSLErrorString(ERR_get_error());
RSA_free(key);
}
return new RsaPrivateKey(key);
}
bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
std::string* decrypted_message) const {
DCHECK(decrypted_message);
size_t rsa_size = RSA_size(key_);
if (encrypted_message.size() != rsa_size) {
LOG(ERROR) << "Encrypted RSA message has the wrong size (expected "
<< rsa_size << ", actual " << encrypted_message.size() << ")";
return false;
}
decrypted_message->assign(rsa_size, 0);
int decrypted_size = RSA_private_decrypt(
rsa_size,
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(encrypted_message.data())),
reinterpret_cast<unsigned char*>(&(*decrypted_message)[0]), key_,
RSA_PKCS1_OAEP_PADDING);
if (decrypted_size == -1) {
LOG(ERROR) << "RSA private decrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
decrypted_message->resize(decrypted_size);
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::GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const {
DCHECK(signature);
if (message.empty()) {
LOG(ERROR) << "Empty signature verification message";
return false;
}
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
digest);
unsigned int sig_len = RSA_size(key_);
signature->resize(sig_len);
return RSA_sign(NID_sha256, digest, sizeof(digest),
reinterpret_cast<unsigned char*>(&(*signature)[0]), &sig_len,
key_) == 1;
}
bool RsaPrivateKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
return RsaKeyMatch(key(), private_key.key());
}
bool RsaPrivateKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
return RsaKeyMatch(key(), public_key.key());
}
uint32_t RsaPrivateKey::KeySize() const { return RSA_size(key_); }
RsaPublicKey::RsaPublicKey(RSA* key) : key_(key) { CHECK(key_ != nullptr); }
RsaPublicKey::RsaPublicKey(const RsaPublicKey& rsa_key)
: key_(RSAPublicKey_dup(rsa_key.key_)) {
CHECK(key_ != nullptr);
}
RsaPublicKey::~RsaPublicKey() { RSA_free(key_); }
RsaPublicKey* RsaPublicKey::Create(const std::string& serialized_key) {
RSA* key;
if (!rsa_util::DeserializeRsaPublicKey(serialized_key, &key)) return nullptr;
if (RSA_size(key) == 0) {
LOG(ERROR) << "Invalid public RSA key: "
<< OpenSSLErrorString(ERR_get_error());
RSA_free(key);
}
return new RsaPublicKey(key);
}
bool RsaPublicKey::Encrypt(const std::string& clear_message,
std::string* encrypted_message) const {
DCHECK(encrypted_message);
if (clear_message.empty()) {
LOG(ERROR) << "Message to be encrypted is empty";
return false;
}
size_t rsa_size = RSA_size(key_);
encrypted_message->assign(rsa_size, 0);
if (RSA_public_encrypt(
clear_message.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(clear_message.data())),
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key_,
RSA_PKCS1_OAEP_PADDING) != static_cast<int>(rsa_size)) {
LOG(ERROR) << "RSA public encrypt failure: "
<< OpenSSLErrorString(ERR_get_error());
return false;
}
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::VerifySignatureSha256Pkcs7(const std::string& message,
const std::string& signature) const {
if (message.empty()) {
LOG(ERROR) << "Empty signature verification message";
return false;
}
if (signature.empty()) {
LOG(ERROR) << "Empty signature";
return false;
}
if (signature.size() != RSA_size(key_)) {
LOG(ERROR) << "RSA signature has the wrong size";
return false;
}
unsigned char digest[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
digest);
return RSA_verify(NID_sha256, digest, sizeof(digest),
reinterpret_cast<const unsigned char*>(signature.data()),
signature.size(), key_) == 1;
}
bool RsaPublicKey::MatchesPrivateKey(const RsaPrivateKey& private_key) const {
return RsaKeyMatch(key(), private_key.key());
}
bool RsaPublicKey::MatchesPublicKey(const RsaPublicKey& public_key) const {
return RsaKeyMatch(key(), public_key.key());
}
uint32_t RsaPublicKey::KeySize() const { return RSA_size(key_); }
RsaKeyFactory::RsaKeyFactory() {}
RsaKeyFactory::~RsaKeyFactory() {}
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs1PrivateKey(
const std::string& private_key) {
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(private_key));
}
std::unique_ptr<RsaPrivateKey> RsaKeyFactory::CreateFromPkcs8PrivateKey(
const std::string& private_key, const std::string& private_key_passphrase) {
std::string pkcs1_key;
const bool result =
private_key_passphrase.empty()
? rsa_util::PrivateKeyInfoToRsaPrivateKey(private_key, &pkcs1_key)
: rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
private_key, private_key_passphrase, &pkcs1_key);
if (!result) {
LOG(WARNING) << "Failed to get pkcs1_key.";
return std::unique_ptr<RsaPrivateKey>();
}
return std::unique_ptr<RsaPrivateKey>(RsaPrivateKey::Create(pkcs1_key));
}
std::unique_ptr<RsaPublicKey> RsaKeyFactory::CreateFromPkcs1PublicKey(
const std::string& public_key) {
return std::unique_ptr<RsaPublicKey>(RsaPublicKey::Create(public_key));
}
} // namespace widevine

151
common/rsa_key.h Normal file
View File

@@ -0,0 +1,151 @@
////////////////////////////////////////////////////////////////////////////////
// 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:
// Declaration of classes representing RSA private and public keys used
// for message signing, signature verification, encryption and decryption.
#ifndef COMMON_RSA_KEY_H_
#define COMMON_RSA_KEY_H_
#include <memory>
#include <string>
#include <cstdint>
#include "base/macros.h"
#include "openssl/rsa.h"
namespace widevine {
class RsaPublicKey;
class RsaPrivateKey {
public:
explicit RsaPrivateKey(RSA* key);
RsaPrivateKey(const RsaPrivateKey&);
virtual ~RsaPrivateKey();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
// Returns NULL on failure.
static RsaPrivateKey* Create(const std::string& serialized_key);
// Decrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Returns true if successful, false otherwise.
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.
virtual bool GenerateSignature(const std::string& message,
std::string* signature) const;
// Generate SHA256 digest, PKCS#7 padded signature. Caller retains ownership
// of all parameters. Returns true if successful, false otherwise.
virtual bool GenerateSignatureSha256Pkcs7(const std::string& message,
std::string* signature) const;
// Return true if the underlying key matches with |private_key|.
virtual bool MatchesPrivateKey(const RsaPrivateKey& private_key) const;
// Return true if the underlying key is a public-private key pair with
// |public_key|.
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
// Returns the RSA key size (modulus) in bytes.
virtual uint32_t KeySize() const;
const RSA* key() const { return key_; }
private:
RSA* key_;
// SWIG appears to think this declaration is a syntax error. Excluding it for
// python SWIG wrapping.
#ifndef SWIG
// Disallow assignment operator.
RsaPrivateKey& operator=(const RsaPrivateKey&) = delete;
#endif // SWIG
};
class RsaPublicKey {
public:
explicit RsaPublicKey(RSA* key);
RsaPublicKey(const RsaPublicKey&);
virtual ~RsaPublicKey();
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
// Returns NULL on failure.
static RsaPublicKey* Create(const std::string& serialized_key);
// Encrypt a message using RSA-OAEP. Caller retains ownership of all
// parameters. Returns true if successful, false otherwise.
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.
virtual bool VerifySignature(const std::string& message,
const std::string& signature) const;
// Verify a signature. This method takes two parameters: |message| which is a
// std::string containing the data which was signed, and |signature| which is a
// std::string containing the message SHA256 digest signature with PKCS#7
// padding. Returns true if verification succeeds, false otherwise.
virtual bool VerifySignatureSha256Pkcs7(const std::string& message,
const std::string& signature) const;
// Return true if the underlying key is a public-private key pair with
// |private_key|.
virtual bool MatchesPrivateKey(const RsaPrivateKey& private_key) const;
// Return true if the underlying key matches with |public_key|.
virtual bool MatchesPublicKey(const RsaPublicKey& public_key) const;
// Returns the RSA key size (modulus) in bytes.
virtual uint32_t KeySize() const;
const RSA* key() const { return key_; }
private:
RSA* key_;
// SWIG appears to think this declaration is a syntax error. Excluding it for
// python SWIG wrapping.
#ifndef SWIG
// Disallow assignment operator.
RsaPublicKey& operator=(const RsaPublicKey&) = delete;
#endif // SWIG
};
class RsaKeyFactory {
public:
RsaKeyFactory();
virtual ~RsaKeyFactory();
// Create an RsaPrivateKey object using a DER encoded PKCS#1 RSAPrivateKey.
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs1PrivateKey(
const std::string& private_key);
// Create a PKCS#1 RsaPrivateKey object using an PKCS#8 PrivateKeyInfo or
// EncryptedPrivateKeyInfo (if |private_key_passprhase| is not empty).
virtual std::unique_ptr<RsaPrivateKey> CreateFromPkcs8PrivateKey(
const std::string& private_key, const std::string& private_key_passphrase);
// Create an RsaPublicKey object using a DER encoded PKCS#1 RSAPublicKey.
virtual std::unique_ptr<RsaPublicKey> CreateFromPkcs1PublicKey(
const std::string& public_key);
private:
DISALLOW_COPY_AND_ASSIGN(RsaKeyFactory);
};
} // namespace widevine
#endif // COMMON_RSA_KEY_H_

255
common/rsa_key_test.cc Normal file
View File

@@ -0,0 +1,255 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <memory>
#include "testing/gunit.h"
#include "common/rsa_key.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, 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

1147
common/rsa_test_keys.cc Normal file

File diff suppressed because it is too large Load Diff

92
common/rsa_test_keys.h Normal file
View File

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

514
common/rsa_util.cc Normal file
View File

@@ -0,0 +1,514 @@
////////////////////////////////////////////////////////////////////////////////
// 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 utility functions for serializing and deserializing RSA keys,
// encryption, and signing.
#include "common/rsa_util.h"
#include <limits.h>
#include <cstring>
#include <memory>
#include "glog/logging.h"
#include "openssl/pem.h"
#include "openssl/x509.h"
namespace {
int BigNumGreaterThanPow2(const BIGNUM* b, int n) {
if (BN_is_negative(b) || n == INT_MAX) {
return 0;
}
int b_bits = BN_num_bits(b);
return b_bits > n + 1 || (b_bits == n + 1 && !BN_is_pow2(b));
}
} // anonymous namespace
namespace widevine {
namespace rsa_util {
static bool SerializeRsaKey(const RSA* key, std::string* serialized_key,
bool serialize_private_key) {
if (key == nullptr) {
LOG(ERROR) << (serialize_private_key ? "Private" : "Public")
<< " RSA key is nullptr.";
return false;
}
if (serialized_key == nullptr) {
LOG(ERROR) << "Pointer to hold serialized RSA" << (serialize_private_key ?
"Private" : "Public") << "Key is nullptr.";
return false;
}
BIO* bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new returned nullptr";
return false;
}
bool success = false;
if ((serialize_private_key ?
i2d_RSAPrivateKey_bio(bio, const_cast<RSA*>(key)) :
i2d_RSAPublicKey_bio(bio, const_cast<RSA*>(key))) != 0) {
int serialized_size = BIO_pending(bio);
serialized_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_key)[0], serialized_size) ==
serialized_size) {
success = true;
} else {
LOG(ERROR) << "BIO_read failure";
}
} else {
LOG(ERROR) << (serialize_private_key ? "Private" : "Public") <<
" key serialization failure";
}
BIO_free(bio);
return success;
}
static bool DeserializeRsaKey(const std::string& serialized_key, RSA** key,
bool deserialize_private_key) {
if (serialized_key.empty()) {
LOG(ERROR) << "Serialized RSA" << (deserialize_private_key ?
"Private" : "Public") << "Key is empty.";
return false;
}
if (key == nullptr) {
LOG(ERROR) << "Pointer to hold new RSA " << (deserialize_private_key ?
"private" : "public") << " key is nullptr.";
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_key.data()),
serialized_key.size());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new_mem_buf returned nullptr";
return false;
}
*key = deserialize_private_key ? d2i_RSAPrivateKey_bio(bio, nullptr) :
d2i_RSAPublicKey_bio(bio, nullptr);
BIO_free(bio);
if (*key == nullptr) {
LOG(ERROR) << (deserialize_private_key ? "Private" : "Public") <<
" RSA key deserialization failure";
}
return *key != nullptr;
}
bool SerializeRsaPrivateKey(const RSA* private_key,
std::string* serialized_private_key) {
return SerializeRsaKey(private_key, serialized_private_key, true);
}
bool DeserializeRsaPrivateKey(const std::string& serialized_private_key,
RSA** private_key) {
return DeserializeRsaKey(serialized_private_key, private_key, true);
}
bool SerializeRsaPublicKey(const RSA* public_key,
std::string* serialized_public_key) {
return SerializeRsaKey(public_key, serialized_public_key, false);
}
bool DeserializeRsaPublicKey(const std::string& serialized_public_key,
RSA** public_key) {
return DeserializeRsaKey(serialized_public_key, public_key, false);
}
bool SerializePrivateKeyInfo(const RSA* private_key,
std::string* serialized_private_key) {
if (private_key == nullptr) {
LOG(ERROR) << "Private RSA key is nullptr.";
return false;
}
if (serialized_private_key == nullptr) {
LOG(ERROR) << "Pointer to hold serialized PrivateKeyInfo is nullptr.";
return false;
}
// The following method of serializing a PKCS#8 PrivateKeyInfo object
// was obtained from analyzing the openssl utility code, as the official
// mechanism via i2d_PKCS8PrivateKey_bio is broken in the current openssl
// version (1.0.0c). Please refer to b/8560683.
EVP_PKEY* evp = EVP_PKEY_new();
if (evp == nullptr) {
LOG(ERROR) << "EVP_PKEY_new returned nullptr.";
return false;
}
bool success = false;
PKCS8_PRIV_KEY_INFO *pkcs8_pki = nullptr;
BIO* bio = nullptr;
if (EVP_PKEY_set1_RSA(evp, const_cast<RSA*>(private_key)) == 0) {
LOG(ERROR) << "EVP_PKEY_set1_RSA failed.";
goto cleanup;
}
pkcs8_pki = EVP_PKEY2PKCS8(evp);
if (pkcs8_pki == nullptr) {
LOG(ERROR) << "EVP_PKEY2PKCS8 returned nullptr.";
goto cleanup;
}
bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new returned nullptr.";
goto cleanup;
}
if (i2d_PKCS8_PRIV_KEY_INFO_bio(bio, pkcs8_pki) == 0) {
LOG(ERROR) << "i2d_PKCS8_PRIV_KEY_INFO_bio failed.";
goto cleanup;
}
{
int serialized_size = BIO_pending(bio);
serialized_private_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_private_key)[0], serialized_size) !=
serialized_size) {
LOG(ERROR) << "BIO_read failed.";
goto cleanup;
}
}
success = true;
cleanup:
if (bio != nullptr) {
BIO_free(bio);
}
if (pkcs8_pki != nullptr) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
EVP_PKEY_free(evp);
return success;
}
bool DeserializePrivateKeyInfo(const std::string& serialized_private_key,
RSA** private_key) {
if (serialized_private_key.empty()) {
LOG(ERROR) << "Serialized PrivateKeyInfo is empty.";
return false;
}
if (private_key == nullptr) {
LOG(ERROR) << "Pointer to hold new RSA private key is nullptr.";
return false;
}
// The following method of deserializing a PKCS#8 PrivateKeyInfo object
// was obtained from analyzing the openssl utility code, as the official
// mechanism via d2i_PKCS8PrivateKey_bio is broken in the current openssl
// version (1.0.0c). Please refer to b/8560683.
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_private_key.data()),
serialized_private_key.size());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new_mem_buf returned nullptr";
return false;
}
bool success = false;
EVP_PKEY* evp = nullptr;
PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
if (pkcs8_pki == nullptr) {
LOG(ERROR) << "d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr.";
goto cleanup;
}
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == nullptr) {
LOG(ERROR) << "EVP_PKCS82PKEY returned nullptr.";
goto cleanup;
}
*private_key = EVP_PKEY_get1_RSA(evp);
if (*private_key == nullptr) {
LOG(ERROR) << "PrivateKeyInfo did not contain an RSA key.";
goto cleanup;
}
success = true;
cleanup:
if (evp != nullptr) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != nullptr) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
return success;
}
bool RsaPrivateKeyToPrivateKeyInfo(const std::string& rsa_private_key,
std::string* private_key_info) {
RSA* key = nullptr;
if (DeserializeRsaPrivateKey(rsa_private_key, &key)) {
bool success = SerializePrivateKeyInfo(key, private_key_info);
RSA_free(key);
return success;
}
return false;
}
bool PrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
std::string* rsa_private_key) {
RSA* key = nullptr;
if (DeserializePrivateKeyInfo(private_key_info, &key)) {
bool success = SerializeRsaPrivateKey(key, rsa_private_key);
RSA_free(key);
return success;
}
return false;
}
bool SerializeEncryptedPrivateKeyInfo(const RSA* private_key,
const std::string& passphrase,
std::string* serialized_private_key) {
if (private_key == nullptr) {
LOG(ERROR) << "Private RSA key is nullptr.";
return false;
}
if (passphrase.empty()) {
LOG(ERROR) << "Passphrase for RSA key encryption is empty.";
return false;
}
if (serialized_private_key == nullptr) {
LOG(ERROR)
<< "Pointer to hold serialized EncryptedPrivateKeyInfo is nullptr.";
return false;
}
EVP_PKEY* evp = EVP_PKEY_new();
if (evp == nullptr) {
LOG(ERROR) << "EVP_PKEY_new returned nullptr.";
return false;
}
bool success = false;
BIO* bio = nullptr;
if (EVP_PKEY_set1_RSA(evp, const_cast<RSA*>(private_key)) == 0) {
LOG(ERROR) << "EVP_PKEY_set1_RSA failed.";
goto cleanup;
}
bio = BIO_new(BIO_s_mem());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new returned nullptr.";
goto cleanup;
}
if (i2d_PKCS8PrivateKey_bio(bio, evp, EVP_aes_256_cbc(),
const_cast<char*>(passphrase.data()),
passphrase.size(), nullptr, nullptr) == 0) {
LOG(ERROR) << "i2d_PKCS8PrivateKey_bio failed.";
goto cleanup;
}
{
int serialized_size = BIO_pending(bio);
serialized_private_key->assign(serialized_size, 0);
if (BIO_read(bio, &(*serialized_private_key)[0], serialized_size) !=
serialized_size) {
LOG(ERROR) << "BIO_read failed.";
goto cleanup;
}
}
success = true;
cleanup:
if (bio != nullptr) {
BIO_free(bio);
}
EVP_PKEY_free(evp);
return success;
}
namespace {
// Password retrieval function used by DeserializeEncryptedPrivateKeyInfo below.
int get_password(char *buf, int size, int rwflag, void *u) {
CHECK(buf);
CHECK(u);
const std::string* pass(static_cast<const std::string*>(u));
if (!pass->empty() && size >= static_cast<int>(pass->size())) {
memcpy(buf, pass->data(), pass->size());
return pass->size();
}
return 0;
}
} // namespace
bool DeserializeEncryptedPrivateKeyInfo(const std::string& serialized_private_key,
const std::string& passphrase,
RSA** private_key) {
if (serialized_private_key.empty()) {
LOG(ERROR) << "Serialized RSAEncryptedPrivateKeyInfo is empty.";
return false;
}
if (passphrase.empty()) {
LOG(ERROR) << "Passphrase for RSA key decryption is empty.";
return false;
}
if (private_key == nullptr) {
LOG(ERROR) << "Pointer to hold new RSA private key is nullptr.";
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_private_key.data()),
serialized_private_key.size());
if (bio == nullptr) {
LOG(ERROR) << "BIO_new_mem_buf returned nullptr";
return false;
}
bool success = false;
EVP_PKEY* evp = d2i_PKCS8PrivateKey_bio(bio, nullptr, get_password,
const_cast<std::string*>(&passphrase));
if (evp == nullptr) {
LOG(ERROR) << "d2i_PKCS8PrivateKey_bio returned nullptr.";
goto cleanup;
}
*private_key = EVP_PKEY_get1_RSA(evp);
if (*private_key == nullptr) {
LOG(ERROR) << "EncryptedPrivateKeyInfo did not contain an RSA key.";
goto cleanup;
}
success = true;
cleanup:
if (evp != nullptr) {
EVP_PKEY_free(evp);
}
BIO_free(bio);
return success;
}
bool RsaPrivateKeyToEncryptedPrivateKeyInfo(const std::string& rsa_private_key,
const std::string& passphrase,
std::string* private_key_info) {
RSA* key = nullptr;
if (DeserializeRsaPrivateKey(rsa_private_key, &key)) {
bool success = SerializeEncryptedPrivateKeyInfo(key,
passphrase,
private_key_info);
RSA_free(key);
return success;
}
return false;
}
bool EncryptedPrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
const std::string& passphrase,
std::string* rsa_private_key) {
RSA* key = nullptr;
if (DeserializeEncryptedPrivateKeyInfo(private_key_info, passphrase, &key)) {
bool success = SerializeRsaPrivateKey(key, rsa_private_key);
RSA_free(key);
return success;
}
return false;
}
bool ConvertToEulerTotient(RSA* rsa) {
// RSA key generation requires computing e (public exponent) and d (private
// exponent), such that m^(e * d) = 1 (mod n) for all m coprime to n.
// BoringSSL previously computed this by taking the inverse of e modulo the
// Euler totient, (p - 1) * (q - 1). However, it now uses the Carmichael
// totient, lcm(p - 1, q - 1). These two methods produce equivalent RSA keys.
//
// This breaks some vendors' RSA code which use a custom RSA format (rather
// than the standard one in RFC 8017) which omits most of the required
// parameters. They then attempt to recover those parameters, but their
// recovery algorithm breaks when using the Carmichael totient. To work around
// this bug, re-compute the private exponent against the Euler totient.
const BIGNUM *e, *p, *q;
RSA_get0_key(rsa, nullptr /* n */, &e, nullptr /* d */);
RSA_get0_factors(rsa, &p, &q);
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> pm1(BN_new());
bssl::UniquePtr<BIGNUM> qm1(BN_new());
bssl::UniquePtr<BIGNUM> totient(BN_new());
bssl::UniquePtr<BIGNUM> d(BN_new());
if (!ctx || !pm1 || !qm1 || !totient || !d ||
!BN_sub(pm1.get(), p, BN_value_one()) ||
!BN_sub(qm1.get(), q, BN_value_one()) ||
!BN_mul(totient.get(), pm1.get(), qm1.get(), ctx.get()) ||
!BN_mod_inverse(d.get(), e, totient.get(), ctx.get())) {
return false;
}
// Perform a sanity check that d is still valid after conversion.
// d > 2 ^ (nlen / 2) per Appendix B 3.1 in FIPS 186/4.
int prime_bits = (8 * RSA_size(rsa)) / 2;
if (!BigNumGreaterThanPow2(d.get(), prime_bits)) {
return false;
}
if (!RSA_set0_key(rsa, nullptr /* n */, nullptr /* e */, d.get())) {
return false;
}
d.release(); // RSA_set0_key takes ownership on success.
if (!RSA_check_key(rsa)) {
return false;
}
return true;
}
bool ConvertToEulerTotient(const std::string& private_key,
std::string* euler_private_key) {
CHECK(euler_private_key);
RSA* rsa_ptr;
if (!rsa_util::DeserializeRsaPrivateKey(private_key, &rsa_ptr)) {
return false;
}
bssl::UniquePtr<RSA> rsa(rsa_ptr);
if (!rsa_util::ConvertToEulerTotient(rsa.get())
|| !rsa_util::SerializeRsaPrivateKey(rsa.get(), euler_private_key)) {
return false;
}
return true;
}
bool ConvertToCarmichaelTotient(RSA* rsa) {
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
bssl::UniquePtr<BIGNUM> pm1(BN_new());
bssl::UniquePtr<BIGNUM> qm1(BN_new());
bssl::UniquePtr<BIGNUM> gcd(BN_new());
bssl::UniquePtr<BIGNUM> totient(BN_new());
bssl::UniquePtr<BIGNUM> d(BN_new());
// This calculates d = e^-1 (mod lcm(p-1, q-1)).
// This is equivalent to what is used in RSA_generate_key in BoringSSL.
if (!BN_sub(pm1.get(), rsa->p, BN_value_one()) ||
!BN_sub(qm1.get(), rsa->q, BN_value_one()) ||
!BN_mul(totient.get(), pm1.get(), qm1.get(), ctx.get()) ||
!BN_gcd(gcd.get(), pm1.get(), qm1.get(), ctx.get()) ||
!BN_div(totient.get(), nullptr, totient.get(), gcd.get(), ctx.get()) ||
!BN_mod_inverse(d.get(), rsa->e, totient.get(), ctx.get())) {
return false;
}
// Perform a sanity check that d is still valid after conversion.
// d > 2 ^ (nlen / 2) per Appendix B 3.1 in FIPS 186/4.
int prime_bits = (8 * RSA_size(rsa)) / 2;
if (!BigNumGreaterThanPow2(d.get(), prime_bits)) {
return false;
}
// TODO(user): Replace this with |RSA_set0_key| once BoringSSL has
// finished transitioning to the OpenSSL 1.1.0 API.
BN_free(rsa->d);
rsa->d = d.release();
if (!RSA_check_key(rsa)) {
return false;
}
return true;
}
bool ConvertToCarmichaelTotient(const std::string& private_key,
std::string* carmichael_private_key) {
CHECK(carmichael_private_key);
RSA* rsa_ptr;
if (!rsa_util::DeserializeRsaPrivateKey(private_key, &rsa_ptr)) {
return false;
}
bssl::UniquePtr<RSA> rsa(rsa_ptr);
if (!rsa_util::ConvertToCarmichaelTotient(rsa.get())
|| !rsa_util::SerializeRsaPrivateKey(rsa.get(), carmichael_private_key)) {
return false;
}
return true;
}
} // namespace rsa_util
} // namespace widevine

202
common/rsa_util.h Normal file
View File

@@ -0,0 +1,202 @@
////////////////////////////////////////////////////////////////////////////////
// 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 utility functions for serializing and deserializing RSA keys,
// encryption, and signing.
#ifndef COMMON_RSA_UTIL_H_
#define COMMON_RSA_UTIL_H_
#include <string>
#include "openssl/rsa.h"
namespace widevine {
namespace rsa_util {
// Serialize RSA private key into DER encoded PKCS#1 RSAPrivateKey.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - serialized_private_key is a pointer to the std::string to hold the serialized
// PKCS#1 RSAPrivateKey object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeRsaPrivateKey(const RSA* private_key,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#1 RSAPrivateKey.
// - serialized_private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeRsaPrivateKey(const std::string& serialized_private_key,
RSA** private_key);
// Serialize RSA key into DER encoded PKCS#1 RSAPublicKey.
// - public_key is the RSA key to be serialized, which must not be NULL.
// - serialized_public_key is a pointer to the std::string to hold the serialized
// PKCS#1 RSAPublicKey object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeRsaPublicKey(const RSA* public_key,
std::string* serialized_public_key);
// Deserialize RSA public key from DER encoded PKCS#1 RSAPublicKey.
// - serialized_public_key is the DER-encoded PKCS#1 RSAPublicKey to be
// deserialized.
// - public_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeRsaPublicKey(const std::string& serialized_public_key,
RSA** public_key);
// Serialize RSA private key into DER encoded PKCS#8 PrivateKeyInfo.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - serialized_private_key is a pointer to the std::string to hold the serialized
// PKCS#8 PrivateKeyInfo object. Caller retains ownership of the string. This
// parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializePrivateKeyInfo(const RSA* private_key,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#8 PrivateKeyInfo.
// - serialized_private_key is the DER-encoded PKCS#8 PrivateKeyInfo to be
// deserialized.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializePrivateKeyInfo(const std::string& serialized_private_key,
RSA** private_key);
// Convert DER-encoded PKCS#1 RSAPrivateKey to DER-encoded PKCS#8
// PrivateKeyInfo.
// - rsa_private_key is the PKCS#1 RSAPrivateKey to be converted.
// - private_key_info is a pointer to std::string to hold the PKCS#8 PrivateKeyInfo.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool RsaPrivateKeyToPrivateKeyInfo(const std::string& rsa_private_key,
std::string* private_key_info);
// Convert DER-encoded PKCS#8 PrivateKeyInfo to DER-encoded PKCS#1
// RSAPrivateKey.
// - private_key_info is the PKCS#8 PrivateKeyInfo to be converted.
// - rsa_private_key is a pointer to std::string to hold the PKCS#1 RSAPrivateKey.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool PrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
std::string* rsa_private_key);
// Serialize RSA private key into DER encoded PKCS#8 EncryptedPrivateKeyInfo.
// - private_key is the RSA key to be serialized, which must not be NULL.
// - passphrase is the password to use for PKCS#5 v2.0 3DES encryption.
// - serialized_private_key is a pointer to the std::string to hold the serialized
// PKCS#8 EncryptedPrivateKeyInfo object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if successful, false otherwise.
bool SerializeEncryptedPrivateKeyInfo(const RSA* private_key,
const std::string& passphrase,
std::string* serialized_private_key);
// Deserialize RSA private key from DER encoded PKCS#8 EncryptedPrivateKeyInfo.
// - serialized_private_key is the DER-encoded PKCS#8 EncryptedPrivateKeyInfo to
// be deserialized.
// - passphrase is the password to use for key decryption.
// - private_key is a pointer to an RSA structure pointer to point to a newly
// allocated RSA structure. Caller assumes ownership of the new RSA pointer,
// which is not allocated if the method fails. This parameter must not be
// NULL.
// Returns true if successful, false otherwise.
bool DeserializeEncryptedPrivateKeyInfo(const std::string& serialized_private_key,
const std::string& passphrase,
RSA** private_key);
// Convert DER-encoded PKCS#1 RSAPrivateKey to DER-encoded PKCS#8
// EncryptedPrivateKeyInfo.
// - rsa_private_key is the PKCS#1 RSAPrivateKey to be converted.
// - passphrase is the password to use for PKCS#5 v2.1 AES-256-CBC encryption.
// - private_key_info is a pointer to std::string to hold the PKCS#8
// EncryptedPrivateKeyInfo.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool RsaPrivateKeyToEncryptedPrivateKeyInfo(const std::string& rsa_private_key,
const std::string& passphrase,
std::string* private_key_info);
// Convert DER-encoded PKCS#8 EncryptedPrivateKeyInfo to DER-encoded PKCS#1
// RSAPrivateKey.
// - private_key_info is the PKCS#8 EncryptedPrivateKeyInfo to be converted.
// - passphrase is the password to use for key decryption.
// - rsa_private_key is a pointer to std::string to hold the PKCS#1 RSAPrivateKey.
// The caller retains ownership of this parameter, which must not be NULL.
// Returns true if successful, false otherwise.
bool EncryptedPrivateKeyInfoToRsaPrivateKey(const std::string& private_key_info,
const std::string& passphrase,
std::string* rsa_private_key);
// This method changes |rsa| to use the more common, but not FIPS 186-4
// compliant, computation for the RSA private exponent (d). This used to be the
// form produced by the BoringSSL method RSA_generate_key. This changed in this
// CL: https://boringssl-review.googlesource.com/c/boringssl/+/15944
//
// This method is used to produce a "backward-compatible" version. Some vendor
// RSA implementations do not handle the new computation properly.
//
// - rsa is the openssl RSA structure. Must not be null. Caller retains
// ownership.
//
// Returns true if the key was successfully updated, false otherwise.
bool ConvertToEulerTotient(RSA* rsa);
// This is wrapper to the other SwitchToEulerTotient that supports deserializing
// and serializing from and to a DER encoded PKCS#1 RSAPrivateKey.
//
// - private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized and converted.
// - euler_private_key is a pointer to the std::string to hold the converted and
// serialized PKCS#1 RSAPrivateKey object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if the key was successfully updated, false otherwise.
bool ConvertToEulerTotient(const std::string& private_key,
std::string* euler_private_key);
// This method changes |rsa| to use the FIPS 186-4 compliant computation for d.
// This uses the Carmichael totient. This is equivalent to the way the key
// is generated in BoringSSL as of this change:
// https://boringssl-review.googlesource.com/c/boringssl/+/15944
//
// This method is mostly used for testing. It allows tests to convert back and
// forth between forms and verify the output.
//
// Returns true if the key can be successfully updated, false otherwise.
bool ConvertToCarmichaelTotient(RSA* rsa);
// This is wrapper to the other SwitchToCarmichaelTotient that supports
// deserializing and serializing from and to a DER encoded PKCS#1 RSAPrivateKey.
//
// - private_key is the DER-encoded PKCS#1 RSAPrivateKey to be
// deserialized and converted.
// - carmichael_private_key is a pointer to the std::string to hold the converted and
// serialized PKCS#1 RSAPrivateKey object. Caller retains ownership of the
// string. This parameter must not be NULL.
// Returns true if the key was successfully updated, false otherwise.
bool ConvertToCarmichaelTotient(const std::string& private_key,
std::string* carmichael_private_key);
} // namespace rsa_util
} // namespace widevine
#endif // COMMON_RSA_UTIL_H_

354
common/rsa_util_test.cc Normal file
View File

@@ -0,0 +1,354 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "common/rsa_util.h"
#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"
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

63
common/sha_util.cc Normal file
View File

@@ -0,0 +1,63 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <cstdint>
#include "openssl/sha.h"
namespace widevine {
std::string Sha1_Hash(const std::string& message) {
std::string digest;
digest.resize(SHA_DIGEST_LENGTH);
SHA1(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<uint8_t*>(&digest[0]));
return digest;
}
std::string Sha256_Hash(const std::string& message) {
std::string digest;
digest.resize(SHA256_DIGEST_LENGTH);
SHA256(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<uint8_t*>(&digest[0]));
return digest;
}
std::string GenerateSha1Uuid(const std::string& name_space, const std::string& name) {
// X.667 14 Setting the fields of a name-based UUID.
// - Allocate a UUID to use as a "name space identifier" for all UUIDs
// generated from names in that name space.
// - Compute the 16-octet hash value of the name space identifier concatenated
// with the name.
SHA_CTX ctx;
SHA1_Init(&ctx);
SHA1_Update(&ctx, name_space.data(), name_space.length());
SHA1_Update(&ctx, name.data(), name.length());
unsigned char hash[SHA_DIGEST_LENGTH];
SHA1_Final(hash, &ctx);
std::string hash_str =
std::string(reinterpret_cast<const char*>(hash), SHA_DIGEST_LENGTH);
// - For a SHA-1 hash function, the "hash value" referenced in 14.1 shall be
// octets zero to 15.
std::string uuid = hash_str.substr(0, 16);
// - Overwrite the four most significant bits (bits 15 through 12) of the
// "VersionAndTimeHigh" field with the four-bit version number from Table 3
// of 12.2 for the hash function that was used. [Name-based SHA-1 is 5]
(uuid[6] &= 0xF) |= 0x50;
// - Overwrite the two most significant bits (bits 7 and 6) of the
// "VariantAndClockSeqHigh" field with 1 and 0, respectively.
(uuid[8] &= 0x3F) |= 0x80;
return uuid;
}
} // namespace widevine

31
common/sha_util.h Normal file
View File

@@ -0,0 +1,31 @@
////////////////////////////////////////////////////////////////////////////////
// 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_SHA_UTIL_H_
#define COMMON_SHA_UTIL_H_
#include <string>
#include <cstdint>
namespace widevine {
// Calculates SHA1 hash.
std::string Sha1_Hash(const std::string& message);
// Calculates SHA256 hash.
std::string Sha256_Hash(const std::string& message);
// Generates a UUID as specified in ITU-T X.667 ch. 14, SHA-1 name-based,
// 16-byte binary representation. Name_space is a GUID prefix; name is a unique
// name in the namespace.
std::string GenerateSha1Uuid(const std::string& name_space, const std::string& name);
} // namespace widevine
#endif // COMMON_SHA_UTIL_H_

60
common/sha_util_test.cc Normal file
View File

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

66
common/signature_util.cc Normal file
View File

@@ -0,0 +1,66 @@
////////////////////////////////////////////////////////////////////////////////
// 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/signature_util.h"
#include <memory>
#include <string>
#include "util/status.h"
#include "common/aes_cbc_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
namespace widevine {
namespace signature_util {
util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
const std::string& aes_iv, std::string* signature) {
if (signature == nullptr) {
return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr");
}
std::string hash = Sha1_Hash(message);
if (hash.empty()) {
return util::Status(util::error::INTERNAL, "Computed hash is empty");
}
std::string sig = crypto_util::EncryptAesCbc(aes_key, aes_iv, hash);
if (sig.empty()) {
return util::Status(util::error::INTERNAL,
"Computed AES signature is empty");
}
*signature = sig;
return util::OkStatus();
}
util::Status GenerateRsaSignature(const std::string& message,
const std::string& private_key,
std::string* signature) {
if (signature == nullptr) {
return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr");
}
std::unique_ptr<RsaPrivateKey> rsa_private_key(
RsaPrivateKey::Create(private_key));
if (rsa_private_key == nullptr) {
return util::Status(util::error::INTERNAL,
"Failed to construct a RsaPrivateKey");
}
std::string sig;
if (!rsa_private_key->GenerateSignature(message, &sig)) {
return util::Status(util::error::INTERNAL,
"Failed to generate a RSA signature");
}
if (sig.empty()) {
return util::Status(util::error::INTERNAL,
"Computed RSA signature is empty");
}
*signature = sig;
return util::OkStatus();
}
} // namespace signature_util
} // namespace widevine

34
common/signature_util.h Normal file
View File

@@ -0,0 +1,34 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_SIGNATURE_UTIL_H_
#define COMMON_SIGNATURE_UTIL_H_
#include <string>
#include "util/status.h"
namespace widevine {
namespace signature_util {
// Generates an AES signature of |message| using |aes_key| and |aes_iv|.
// Signature is returned via |signature| if generation was successful.
// Returns a Status that carries the details of error if generation failed.
util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
const std::string& aes_iv, std::string* signature);
// Generates a RSA signature of |message| using |private_key|.
// Signature is returned via |sigature| if generation was successful.
// Returns a Status that carries the details of error if generation failed.
util::Status GenerateRsaSignature(const std::string& message,
const std::string& private_key, std::string* signature);
} // namespace signature_util
} // namespace widevine
#endif // COMMON_SIGNATURE_UTIL_H_

View File

@@ -0,0 +1,44 @@
////////////////////////////////////////////////////////////////////////////////
// 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 SigningKeyMaterialSize(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

55
common/signing_key_util.h Normal file
View File

@@ -0,0 +1,55 @@
////////////////////////////////////////////////////////////////////////////////
// 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,
// SigningKeyMaterialSize(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 "base/macros.h"
#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 SigningKeyMaterialSize(ProtocolVersion protocol_version);
// Returns the client portion of the derived_key. The client portion
// depend on the size of the key. Keys that are 512 bits in length
// are assumed to be version 2.1 keys. The last 256 bits of those
// keys are returned. Keys that are 256 bits in length are returned
// in there entirety, version 2.0 keys.
std::string GetClientSigningKey(const std::string& derived_key,
ProtocolVersion protocol_version);
// Returns the server portion of the derived_key. The server portion
// is the first 256 bits of the key.
std::string GetServerSigningKey(const std::string& derived_key);
} // namespace widevine
#endif // COMMON_SIGNING_KEY_UTIL_H_

View File

@@ -0,0 +1,65 @@
////////////////////////////////////////////////////////////////////////////////
// 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, SigningKeyMaterialSizeProtocolVersion_2_0) {
ASSERT_EQ(crypto_util::kSigningKeySizeBits,
SigningKeyMaterialSize(VERSION_2_0));
}
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_1) {
ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2,
SigningKeyMaterialSize(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

36
common/string_util.cc Normal file
View File

@@ -0,0 +1,36 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <bitset>
#include <sstream>
#include <string>
#include "util/status.h"
namespace widevine {
namespace string_util {
util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) {
if (output == nullptr) {
return util::Status(util::error::INTERNAL, "output is nullptr.");
}
std::stringstream sstream(bitset);
for (size_t i = 0; i < bitset.size(); i += 8) {
std::bitset<8> bits;
sstream >> bits;
char c = static_cast<char>(bits.to_ulong());
*output += c;
}
return util::OkStatus();
}
} // namespace string_util
} // namespace widevine

25
common/string_util.h Normal file
View File

@@ -0,0 +1,25 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_STRING_UTIL_H_
#define COMMON_STRING_UTIL_H_
#include <string>
#include "util/status.h"
namespace widevine {
namespace string_util {
// Converts std::string representation of a bitset to its binary equivalent string.
// For example, converts "01110100011001010111001101110100" to "test".
util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output);
} // namespace string_util
} // namespace widevine
#endif // COMMON_STRING_UTIL_H_

View File

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

328
common/test_certificates.cc Normal file
View File

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

View File

@@ -0,0 +1,56 @@
////////////////////////////////////////////////////////////////////////////////
// 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_CERTIFICATES_H_
#define COMMON_TEST_CERTIFICATES_H_
#include <string>
#include "base/macros.h"
namespace widevine {
class TestCertificates {
public:
TestCertificates();
virtual ~TestCertificates() {}
// returns a test root certificate
const std::string& test_root_certificate() const {
return test_root_certificate_;
}
// returns a test intermediate certificate
const std::string& test_intermediate_certificate() const {
return test_intermediate_certificate_;
}
// returns an user device certificate
const std::string& test_user_device_certificate() const {
return test_user_device_certificate_;
}
// returns a service certificate
const std::string& test_service_certificate() const {
return test_service_certificate_;
}
private:
const std::string test_root_certificate_;
const std::string test_intermediate_certificate_;
const std::string test_user_device_certificate_;
const std::string test_service_certificate_;
DISALLOW_COPY_AND_ASSIGN(TestCertificates);
};
} // namespace widevine
#endif // COMMON_TEST_CERTIFICATES_H_

73
common/test_utils.cc Normal file
View File

@@ -0,0 +1,73 @@
////////////////////////////////////////////////////////////////////////////////
// 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 {
util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature) {
CHECK(signature);
if (pem_private_key.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM private key");
}
if (message.empty()) {
return util::Status(util::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 util::Status(util::error::INTERNAL, "BIO allocation failed");
}
util::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 = util::Status(util::Status::canonical_space(),
util::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 =
util::Status(util::Status::canonical_space(), util::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

32
common/test_utils.h Normal file
View File

@@ -0,0 +1,32 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "util/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 paramters.
util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature);
} // namespace widevine
#endif // COMMON_TEST_UTILS_H__

View File

@@ -0,0 +1,45 @@
////////////////////////////////////////////////////////////////////////////////
// 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 {
util::Status VerifyVmpData(
const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status) {
*platform_verification_status = PLATFORM_UNVERIFIED;
VmpChecker::Result vmp_result;
util::Status status =
VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result);
if (status.ok()) {
switch (vmp_result) {
case VmpChecker::kUnverified:
*platform_verification_status = PLATFORM_UNVERIFIED;
break;
case VmpChecker::kVerified:
*platform_verification_status = PLATFORM_SOFTWARE_VERIFIED;
break;
case VmpChecker::kSecureStorageVerified:
*platform_verification_status =
PLATFORM_SECURE_STORAGE_SOFTWARE_VERIFIED;
break;
case VmpChecker::kTampered:
*platform_verification_status = PLATFORM_TAMPERED;
break;
}
} else {
*platform_verification_status = PLATFORM_TAMPERED;
}
return status;
}
} // namespace widevine

View File

@@ -0,0 +1,28 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "util/status.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
// Retrieve the PlatformVerificationStatus for |vmp_data|. The
// PlatformVerificationStatus is defined at
util::Status VerifyVmpData(
const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status);
} // namespace widevine
#endif // COMMON_VERIFIED_MEDIA_PIPELINE_H_

358
common/vmp_checker.cc Normal file
View File

@@ -0,0 +1,358 @@
////////////////////////////////////////////////////////////////////////////////
// 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/error_space.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() {}
util::Status VmpChecker::SelectDrmCertificateType(CertificateType cert_type) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
util::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 util::OkStatus();
}
VmpChecker* VmpChecker::Instance() {
static VmpChecker instance;
return &instance;
}
// Verify VMP data and return appropriate result.
util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
DCHECK(!vmp_data.empty());
DCHECK(result);
if (!ca_) return util::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 util::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);
util::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 util::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 util::OkStatus();
}
if (binary_info.certificate_index() >= code_signing_certs.size()) {
LOG(INFO) << "Invalid code signing certificate index.";
*result = kTampered;
return util::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, binary_info.signature())) {
LOG(INFO) << "Code signature verification failed for file \""
<< binary_info.file_name() << "\".";
*result = kTampered;
return util::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 util::OkStatus();
}
VLOG(2) << "VMP verification success. Secure storage: "
<< secure_storage_verified;
*result = secure_storage_verified ? kSecureStorageVerified : kVerified;
return util::OkStatus();
}
} // namespace widevine

59
common/vmp_checker.h Normal file
View File

@@ -0,0 +1,59 @@
////////////////////////////////////////////////////////////////////////////////
// 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 "util/status.h"
#include "common/certificate_type.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 util::Status SelectDrmCertificateType(CertificateType root_type);
// Verify VMP data and return appropriate result.
virtual util::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_

321
common/vmp_checker_test.cc Normal file
View File

@@ -0,0 +1,321 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <memory>
#include "glog/logging.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/rsa_key.h"
#include "common/vmp_checker.h"
#include "protos/public/errors.pb.h"
#include "protos/public/verified_media_pipeline.pb.h"
namespace widevine {
namespace {
const uint32_t kBlessedBinaryFlag = 0x00000001;
const char kDevVmpCodeSigningKey[] =
"308204a50201000282010100b3a7da87309390688388d614a5a37e7ee73a"
"c3b296caf4464bfeccbeedf2e3d802d62d5de2f7b409b1eac2dc578b2bfd"
"8b5f20acef13d8ba6a4ccfd406f29a60e1af4151212a062c62c71d894fe6"
"d5524e1b28af1d51d2b806aca778f77fd0e4ef278c4fbd5eb756398d646b"
"b50d3a13d8687ad304005b0b0a054e5109d70dec9953b2f99768fca8fe51"
"957dc4608fd34c999a7b35245bce2795715d8a5957a0872398473eed4860"
"29286f51d4118927e88634ad040034e061fd3f58632961761b1fbb8faf45"
"391d84f7ffe2bf5e27bd499eee14a17bc8be2fd258331e7a86baa7394706"
"424420f6eaba0001bffe74976a5b4cc46380ceef9ce93b3bb73008150203"
"01000102820101008befeb1ff28e7ea56a0f63f1a133c08c48c0553efe86"
"07cfd9d216d981aef81a81db226b47277a6d32d09207df88e03316247ae7"
"39325456a00644bbfacd6dc2990851f047ccdc1226bec21afac9eacfb957"
"1e51889cfb6dac853fcdd1bb1593bd5528cdd3cbbb32c69183ef018fd3f5"
"3153f097fd3de9aca7998a6f4522e60c5e76ecc717033a2be16c233fe3e2"
"94c0ae68179a1ae5d33d51f2c0bcda35cffa21e1814374af1c014c280cfb"
"09e294a099f9a6f003d3da026af0f53029cad3d401178b0db53ca97fd166"
"a5eddf1384ddd92c55ab31758e0651e41dd7b24f2c438d58de00f55343cc"
"a461b94ff6358fc37f404ecbda2365d3e75391566248d3e102818100e4c8"
"783343b43fc127f5077fb35b37145ab6ee5f9a802e8100161ce441cbdbdc"
"1eb15f50bbef1f5088ba83ff914977862dffc63bd364172c9044e1131dbb"
"ff98755daa49670a014163b3c121395d880ad874b9ebdf66ff72a245c2b5"
"4f8fe1e233e72fd9cc253cbcd144f52537e9b7ed16b8a6d328de61c41f86"
"ea1d9ef326fb02818100c90738b2cf61af785e53393d9e96bc2f4d79358b"
"7bd487a242d170b8372af0a26af4980534a099647a4f38efb1a47d9dcdcf"
"a4ea6036396ef333e4f1de62ec529c3122f0d3b6abc818918494a52b028b"
"2cdf06bf2b450d5b99da7f203ff011318c030a01659c4c56244c2c312528"
"e30dd3b7709022d8fd14a2dba23a855da02f0281804f8ebeede4cf5b9449"
"d6d582bcd62d73309088984a5be4d00b3da55262e7074fa684bbc69173f8"
"09c36248e0a89f49a7297bd66d9b7724efe4436f997c2f92146c4be4199e"
"71463a7cf75763bc552027d559d2058a2c810c560db845e0a30243ed14a9"
"f92d1a8de2834b5d8c51c33ea87dcc3c8715a12f9249fc5a916e62d3dd02"
"8181008f74c7d1528cb35b82748174a7a789c377d5f790025e382c62e273"
"3e02a071f875baf681407d1af9c90e9fe2ed322532679cb6634b2566f6f6"
"37223a3828ffdc33fa1ca51f704c460ec2498a8a13974d1a484dd83e5898"
"9fb5bb66dcecc3b4815719141acb182ea18a659163c0d0dcb7114ee6d4f5"
"09441165e6b66e6c9dd3a102818100c449003eee6d9a0b724b66027a791e"
"3b86a72b2098ab085c2e69c276627fd6beeee98918de14ce15d17e059906"
"a178015d04e205918203ffa6c1324868d5c0a019f6fe82335403743322ee"
"14b1159692194ac22d9056c0c39309d249b33abaddb0d08ee87cc053a12a"
"83f12d261525e1b37df643c3e55770ef247d5d094816a0";
const char kDevVmpCodeSigningCert[] =
"3082056a308203d2a003020102020f112233445566778899aabbccddeeff300d06092a86"
"4886f70d01010b050030819c310b30090603550406130255533113301106035504080c0a"
"57617368696e67746f6e3111300f06035504070c084b69726b6c616e64310f300d060355"
"040a0c06476f6f676c653111300f060355040b0c085769646576696e65311e301c060355"
"04030c157769646576696e652d6465762d636f64657369676e3121301f06092a864886f7"
"0d010901161274696e736b697040676f6f676c652e636f6d301e170d3137313030393231"
"323835385a170d3237313030373231323835385a3081a0310b3009060355040613025553"
"3113301106035504080c0a57617368696e67746f6e3111300f06035504070c084b69726b"
"6c616e64310f300d060355040a0c06476f6f676c653111300f060355040b0c0857696465"
"76696e653122302006035504030c197769646576696e652d6465762d766d702d636f6465"
"7369676e3121301f06092a864886f70d010901161274696e736b697040676f6f676c652e"
"636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100"
"b3a7da87309390688388d614a5a37e7ee73ac3b296caf4464bfeccbeedf2e3d802d62d5d"
"e2f7b409b1eac2dc578b2bfd8b5f20acef13d8ba6a4ccfd406f29a60e1af4151212a062c"
"62c71d894fe6d5524e1b28af1d51d2b806aca778f77fd0e4ef278c4fbd5eb756398d646b"
"b50d3a13d8687ad304005b0b0a054e5109d70dec9953b2f99768fca8fe51957dc4608fd3"
"4c999a7b35245bce2795715d8a5957a0872398473eed486029286f51d4118927e88634ad"
"040034e061fd3f58632961761b1fbb8faf45391d84f7ffe2bf5e27bd499eee14a17bc8be"
"2fd258331e7a86baa7394706424420f6eaba0001bffe74976a5b4cc46380ceef9ce93b3b"
"b73008150203010001a38201213082011d301d0603551d0e041604147266b4ce84aafd02"
"b1159cd2fa04c2553c6c02463081bb0603551d230481b33081b0a181a2a4819f30819c31"
"0b30090603550406130255533113301106035504080c0a57617368696e67746f6e311130"
"0f06035504070c084b69726b6c616e64310f300d060355040a0c06476f6f676c65311130"
"0f060355040b0c085769646576696e65311e301c06035504030c157769646576696e652d"
"6465762d636f64657369676e3121301f06092a864886f70d010901161274696e736b6970"
"40676f6f676c652e636f6d820900c5f82f038facf15830090603551d1304023000300b06"
"03551d0f04040302078030130603551d25040c300a06082b060105050703033011060a2b"
"06010401d67904010204030101ff300d06092a864886f70d01010b05000382018100aa23"
"6a5c0e23d5bf67c9f80f893d8347ba489541cf7f4ab7dfffda0ca21a3372e8ee8cfea863"
"628b9e0795904bc0e7495517246143c7b8555884e82fe1c305f0f4c3575447d4e7ce3243"
"4e1e0cf11712d537cd434c11d1328b814c94dbd0bab802e8fed5390da5f0cd719ce0e366"
"47620bcf40ed3945c80ab19beb7728080a74d4ff5d62564f47b32c4915c1f14890d379c8"
"8060f0bac73301defda06275a2e1a2024f92f0b4700d4e50d2d6f8d033715a362d7ca5ab"
"6d2dae20d8cefa2d3fc4f61e1734802984e5078dd6d957719fa75ea10dd02d983f7e383b"
"10fa92be7add70238388e63ec2c7ec49a37aa0c8a2566c46e9755cd9ce654c6d42053d1e"
"1cd9555f8a3bc5e426857072a8e8b44a756543893b1d29dabf31a2301597df2666612f23"
"a442613526e19f2aa9b2ea49f16f14b16794e053967a21b821c7b2495b2e02b01344a339"
"9d7e31dd71982cf21a546b1947bbce236381d717070c27096b6a91413abc69c3c0759574"
"4b7e91daf24b2a0acfd85924669f00292a4bd0c57b4c";
const char kDevSecureStorageVmpCodeSigningCert[] =
"30820571308203d9a0030201020203112233300d06092a864886f70d01010b050030819c"
"310b30090603550406130255533113301106035504080c0a57617368696e67746f6e3111"
"300f06035504070c084b69726b6c616e64310f300d060355040a0c06476f6f676c653111"
"300f060355040b0c085769646576696e65311e301c06035504030c157769646576696e65"
"2d6465762d636f64657369676e3121301f06092a864886f70d010901161274696e736b69"
"7040676f6f676c652e636f6d301e170d3138303232323231323834395a170d3238303232"
"303231323834395a3081a0310b30090603550406130255533113301106035504080c0a57"
"617368696e67746f6e3111300f06035504070c084b69726b6c616e64310f300d06035504"
"0a0c06476f6f676c653111300f060355040b0c085769646576696e653122302006035504"
"030c197769646576696e652d6465762d766d702d636f64657369676e3121301f06092a86"
"4886f70d010901161274696e736b697040676f6f676c652e636f6d30820122300d06092a"
"864886f70d01010105000382010f003082010a0282010100b3a7da87309390688388d614"
"a5a37e7ee73ac3b296caf4464bfeccbeedf2e3d802d62d5de2f7b409b1eac2dc578b2bfd"
"8b5f20acef13d8ba6a4ccfd406f29a60e1af4151212a062c62c71d894fe6d5524e1b28af"
"1d51d2b806aca778f77fd0e4ef278c4fbd5eb756398d646bb50d3a13d8687ad304005b0b"
"0a054e5109d70dec9953b2f99768fca8fe51957dc4608fd34c999a7b35245bce2795715d"
"8a5957a0872398473eed486029286f51d4118927e88634ad040034e061fd3f5863296176"
"1b1fbb8faf45391d84f7ffe2bf5e27bd499eee14a17bc8be2fd258331e7a86baa7394706"
"424420f6eaba0001bffe74976a5b4cc46380ceef9ce93b3bb73008150203010001a38201"
"3430820130301d0603551d0e041604147266b4ce84aafd02b1159cd2fa04c2553c6c0246"
"3081bb0603551d230481b33081b0a181a2a4819f30819c310b3009060355040613025553"
"3113301106035504080c0a57617368696e67746f6e3111300f06035504070c084b69726b"
"6c616e64310f300d060355040a0c06476f6f676c653111300f060355040b0c0857696465"
"76696e65311e301c06035504030c157769646576696e652d6465762d636f64657369676e"
"3121301f06092a864886f70d010901161274696e736b697040676f6f676c652e636f6d82"
"0900c5f82f038facf15830090603551d1304023000300b0603551d0f0404030207803013"
"0603551d25040c300a06082b060105050703033011060a2b06010401d679040102040301"
"01ff3011060a2b06010401d67904010304030101ff300d06092a864886f70d01010b0500"
"038201810069482a9bb125b17c76c77f86004e36ca4fc36bbde9c86901481c70d165e3cf"
"1c8541264190b3e7106c33ff4920a99bc9f939298091dc72ff898d22f5017b04d213eb60"
"626382656fdd66b9cd1830d98ef89d8e405b2d7ce9445db8de2ca365438b848f85d5266b"
"c211c8934154bb88ddb9e6f9aaff761814c1c0da90dd499f174507b5f4e89339e8abd157"
"8b3238d8f5c9dcb1f76e4d810679c2eca3583144f1ac0ce955b7c6a2cc9fc9f3d6c87069"
"28e301ebc3844e53f4905ff60803110dfc3b4f74b50ae1baffd091daad3ea29925f8009e"
"adc471a9ae673d9a9a003901d962f58fede85b2f65d9a470725459b19a69b06ae49179a3"
"395286b7d7039b32985a6db5b30bcd5cbed975d9a68de44fbcd1dbc8b6fbf67746b87d30"
"122c1cd8ed303a8bec7e23d284c0de35cfdccf261c317efe192efa84d2600bba3f9af846"
"8f89953a98f92c97b13d320f484627790d5b7b407f29f343c41154efbcf06e98632a3f3d"
"7138184a6f40af2435b3d98054ed9f4c3aa9ecf95c5c3014d3aa4d12f2";
const char kSameAsPrevious[] = "";
} // namespace
class VmpCheckerTest : public ::testing::Test {
public:
void SetUp() override {
ASSERT_OK(VmpChecker::Instance()->SelectDrmCertificateType(
kCertificateTypeTesting));
vmp_data_.Clear();
VmpChecker::Instance()->set_allow_development_vmp(true);
signing_key_.reset(
RsaPrivateKey::Create(absl::HexStringToBytes(kDevVmpCodeSigningKey)));
ASSERT_TRUE(signing_key_);
}
// Adds a binary to the VMP data to be verified. If |signing_cert| is
// |kSameAsPrevious| (empty), then the binary is signed using the same
// certificate as the previously added binary. This means that the first
// call to this function should not use |kSameAsPrevious|.
void AddVmpBinary(const std::string& signing_cert, const std::string& file_name,
const std::string& binary_hash, uint32_t flags) {
DCHECK(!signing_cert.empty() || !vmp_data_.certificates().empty());
if (!signing_cert.empty()) {
*vmp_data_.add_certificates() = absl::HexStringToBytes(signing_cert);
}
vmp::VmpData::SignedBinaryInfo* new_binary =
vmp_data_.add_signed_binary_info();
new_binary->set_file_name(file_name);
new_binary->set_certificate_index(vmp_data_.certificates_size() - 1);
new_binary->set_binary_hash(binary_hash);
new_binary->set_flags(flags);
std::string message(binary_hash);
message += flags & 0xff;
std::string signature;
ASSERT_TRUE(signing_key_->GenerateSignature(message, &signature));
new_binary->set_signature(signature);
}
const std::string GetVmpData() {
std::string result;
vmp_data_.SerializeToString(&result);
return result;
}
protected:
vmp::VmpData vmp_data_;
std::unique_ptr<RsaPrivateKey> signing_key_;
};
TEST_F(VmpCheckerTest, Success) {
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevSecureStorageVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kVerified, result);
}
TEST_F(VmpCheckerTest, SecureStorageSuccess) {
AddVmpBinary(kDevSecureStorageVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevSecureStorageVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kSecureStorageVerified, result);
}
TEST_F(VmpCheckerTest, FailDevelopmentCert) {
VmpChecker::Instance()->set_allow_development_vmp(false);
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
VmpChecker::Result result;
EXPECT_EQ(DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
VmpChecker::Instance()
->VerifyVmpData(GetVmpData(), &result)
.error_code());
}
TEST_F(VmpCheckerTest, FailTwoBlessedBinaries) {
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
vmp_data_.mutable_signed_binary_info(0)->set_flags(kBlessedBinaryFlag);
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kTampered, result);
}
TEST_F(VmpCheckerTest, FailNoBlessedBinaries) {
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
vmp_data_.mutable_signed_binary_info(3)->set_flags(0);
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kTampered, result);
}
TEST_F(VmpCheckerTest, FailBadSignature) {
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
++((*vmp_data_.mutable_signed_binary_info(2)->mutable_signature())[10]);
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kTampered, result);
}
TEST_F(VmpCheckerTest, FailSignatureVerification) {
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
++((*vmp_data_.mutable_signed_binary_info(3)->mutable_binary_hash())[16]);
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kTampered, result);
}
TEST_F(VmpCheckerTest, FailUnsignedBinary) {
AddVmpBinary(kDevVmpCodeSigningCert, "binary1.exe",
"0123456789abdef0123456789abdef", 0);
AddVmpBinary(kSameAsPrevious, "binary2.dll", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
0);
AddVmpBinary(kDevVmpCodeSigningCert, "binary3.dll",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 0);
AddVmpBinary(kSameAsPrevious, "binary4.dll", "cccccccccccccccccccccccccccccc",
kBlessedBinaryFlag);
vmp_data_.mutable_signed_binary_info(2)->clear_binary_hash();
VmpChecker::Result result;
ASSERT_OK(VmpChecker::Instance()->VerifyVmpData(GetVmpData(), &result));
EXPECT_EQ(VmpChecker::kTampered, result);
}
} // namespace widevine

86
common/wvm_test_keys.cc Normal file
View File

@@ -0,0 +1,86 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <vector>
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "common/wvm_test_keys.h"
#include "common/wvm_token_handler.h"
namespace widevine {
namespace wvm_test_keys {
// Preprov key and keyboxes in this header use system ID 0x112.
const char kTestPreprovKeyHex[] = "f7538b38acc78ec68c732ac665c55c65";
const char kBadPreprovKey1Hex[] = "1badbadbadbadbadbadbadbadbadbad1";
const char kBadPreprovKey2Hex[] = "2badbadbadbadbadbadbadbadbadbad2";
const char kTestToken1Hex[] =
"00000002000001128e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98"
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e";
// The device key corresponding to kTestToken1.
const char kTestDeviceKey1Hex[] = "4071197f1f8910d9bf10c6bc4c987638";
// Base64Encode(kTestToken1)
const char kTestToken1Base64[] =
"AAAAAgAAARKOHr/gN4KAlsplOLT29Ly1HCtxkc8Dfpi+qiSSSQfhKPn/SbVKFlzZ"
"wz5lR1N+tNKft+jfPCwc2SUXoS9JIpU+";
const char kTestToken2Hex[] =
"0000000200000112d906feebe1750c5886ff77c2dfa31bb40e002f3adbc0fa5b"
"eb2486cf5f419549cdaa23230e5165ac2ffab56d53b692b7ba0c1857400c6add"
"3af3ff3d5cb24985";
// The device key corresponding to kTestToken2.
const char kTestDeviceKey2Hex[] = "42cfb1765201042302a404d1e0fac8ed";
// Base64Encode(kTestToken2)
const char kTestToken2Base64[] =
"AAAAAgAAARLZBv7r4XUMWIb/d8Lfoxu0DgAvOtvA+lvrJIbPX0GVSc2qIyMOUWWs"
"L/q1bVO2kre6DBhXQAxq3Trz/z1cskmF";
const char kTestToken3DesHex[] =
"00000002100000138e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98"
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e";
const char kTestDeviceKey3DesHex[] = "4071197f1f8910d9bf10c6bc4c987638";
std::vector<WvmTokenHandler::PreprovKey> GetPreprovKeyVector() {
return {
// Return multiple preprov keys for the same device.
WvmTokenHandler::PreprovKey(kTestSystemId,
absl::HexStringToBytes(kBadPreprovKey1Hex)),
WvmTokenHandler::PreprovKey(kTestSystemId,
absl::HexStringToBytes(kTestPreprovKeyHex)),
WvmTokenHandler::PreprovKey(kTestSystemId,
absl::HexStringToBytes(kBadPreprovKey2Hex)),
// Add another device that uses 3DES encryption for asset keys. Tokens
// the same except for the system ID portion.
WvmTokenHandler::PreprovKey(kTestSystemId3Des,
absl::HexStringToBytes(kTestPreprovKeyHex),
WvmTokenHandler::DES3),
};
}
std::map<uint32_t, std::string> GetPreprovKeyTable() {
return {{kTestSystemId, std::string(kTestPreprovKeyHex)}};
}
std::multimap<uint32_t, std::string> GetPreprovKeyMultimap() {
return {{kTestSystemId, kBadPreprovKey1Hex},
{kTestSystemId, kTestPreprovKeyHex},
{kTestSystemId, kBadPreprovKey2Hex}};
}
} // namespace wvm_test_keys
} // namespace widevine

58
common/wvm_test_keys.h Normal file
View File

@@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////
// 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.
////////////////////////////////////////////////////////////////////////////////
// Sample keys for use in tests of Widevine WVM crypto code.
#ifndef COMMON_WVM_TEST_KEYS_H_
#define COMMON_WVM_TEST_KEYS_H_
#include <map>
#include <string>
#include <vector>
#include <cstdint>
#include "common/wvm_token_handler.h"
namespace widevine {
namespace wvm_test_keys {
// Most preprov key and keyboxes in this header use system ID 0x112.
const uint32_t kTestSystemId = 0x112;
// One oddball system that uses 3DES. (We'll re-use the system and device keys).
const uint32_t kTestSystemId3Des = 0x10000013;
extern const char kTestPreprovKeyHex[];
extern const char kTestToken1Hex[];
extern const char kTestDeviceKey1Hex[];
extern const char kTestToken2Hex[];
extern const char kTestDeviceKey2Hex[];
extern const char kTestToken3DesHex[];
extern const char kTestDeviceKey3DesHex[];
// Return a list of preprovisioning keys, suitable for initializing
// the preprov key table for tests.
std::vector<WvmTokenHandler::PreprovKey> GetPreprovKeyVector();
// Old version of GetPreprovKeyTable() which uses a simple int->std::string
// map. Doesn't support multiple devices per system ID.
// TODO(user): get rid of this once other code as been migrated off of it.
std::map<uint32_t, std::string> GetPreprovKeyTable();
// Version of GetPreprovKeyTable() which uses a simple int->hex_string
// multimap, useful for modular DRM code which doesn't care about the asset
// key cipher.
std::multimap<uint32_t, std::string> GetPreprovKeyMultimap();
} // namespace wvm_test_keys
} // namespace widevine
#endif // COMMON_WVM_TEST_KEYS_H_

317
common/wvm_token_handler.cc Normal file
View File

@@ -0,0 +1,317 @@
////////////////////////////////////////////////////////////////////////////////
// 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/wvm_token_handler.h"
#include <vector>
#include "glog/logging.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "util/endian/endian.h"
#include "util/gtl/map_util.h"
#include "util/status.h"
#include "common/aes_cbc_util.h"
#include "common/ecb_util.h"
#include "common/sha_util.h"
namespace widevine {
namespace {
const int kKeyboxFlagInsecure = 1;
const int kSystemIdSamsungTVFactory = 8;
const int kPreProvisioningKeySizeBytes = 16;
const int kKeyboxSizeBytes = 72;
const std::string kZeroIV(16, '\0');
class PreprovKeysMap {
public:
void Update(const std::vector<WvmTokenHandler::PreprovKey>& key_vector);
std::vector<WvmTokenHandler::PreprovKey> GetPreprovKeys(uint32_t system_id);
bool IsSystemIdKnown(uint32_t system_id);
bool IsEmpty();
static PreprovKeysMap* GetSingleton();
private:
absl::Mutex mutex_;
std::multimap<uint32_t, WvmTokenHandler::PreprovKey> preprov_keys_;
};
void PreprovKeysMap::Update(
const std::vector<WvmTokenHandler::PreprovKey>& key_vector) {
absl::WriterMutexLock lock(&mutex_);
preprov_keys_.clear();
for (const WvmTokenHandler::PreprovKey& ppk : key_vector) {
if (ppk.key_bytes.size() != kPreProvisioningKeySizeBytes) {
LOG(WARNING) << "Invalid preprov key for system id: " << ppk.system_id;
continue;
}
preprov_keys_.insert(std::make_pair(ppk.system_id, ppk));
}
}
std::vector<WvmTokenHandler::PreprovKey> PreprovKeysMap::GetPreprovKeys(
uint32_t system_id) {
absl::ReaderMutexLock lock(&mutex_);
std::vector<WvmTokenHandler::PreprovKey> key_vector;
auto range = preprov_keys_.equal_range(system_id);
for (auto it = range.first; it != range.second; ++it)
key_vector.push_back(it->second);
return key_vector;
}
bool PreprovKeysMap::IsSystemIdKnown(uint32_t system_id) {
absl::ReaderMutexLock lock(&mutex_);
return gtl::ContainsKey(preprov_keys_, system_id);
}
bool PreprovKeysMap::IsEmpty() {
absl::ReaderMutexLock lock(&mutex_);
return preprov_keys_.empty();
}
PreprovKeysMap* PreprovKeysMap::GetSingleton() {
static auto* const kInstance = new PreprovKeysMap();
return kInstance;
}
} // namespace
WvmTokenHandler::PreprovKey::PreprovKey(uint32_t system_id,
const std::string& key_bytes, Cipher cipher,
const std::string& model_filter)
: system_id(system_id),
key_bytes(key_bytes),
cipher(cipher),
model_filter(model_filter) {}
WvmTokenHandler::PreprovKey::PreprovKey(uint32_t system_id,
const std::string& key_bytes, Cipher cipher)
: system_id(system_id), key_bytes(key_bytes), cipher(cipher) {}
WvmTokenHandler::PreprovKey::PreprovKey(uint32_t system_id,
const std::string& key_bytes)
: system_id(system_id), key_bytes(key_bytes), cipher(AES) {}
void WvmTokenHandler::SetPreprovKeys(const std::vector<PreprovKey>& keyvec) {
PreprovKeysMap::GetSingleton()->Update(keyvec);
}
bool WvmTokenHandler::IsSystemIdKnown(uint32_t system_id) {
return PreprovKeysMap::GetSingleton()->IsSystemIdKnown(system_id);
}
util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
std::string* device_key_out,
Cipher* cipher_out,
bool* insecure_out) {
const std::string default_make_model;
return DecryptDeviceKey(token, default_make_model, device_key_out, cipher_out,
insecure_out);
}
util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
const std::string& make_model,
std::string* device_key_out,
Cipher* cipher_out,
bool* insecure_out) {
DCHECK(device_key_out);
// DCHECK below is commented out because preprov_keys_ being nullptr
// is a valid test in wvm_token_handler_test.cc. If we have
// DCHECK(preprov_keys_) here it would thrown an failure in Kokoro
// presubmit because evidently Kokoro does debug build.
// DCHECK(preprov_keys_);
if (token.size() < kKeyboxSizeBytes) {
return util::Status(util::error::INVALID_ARGUMENT,
"Keybox token is too short.");
}
if (PreprovKeysMap::GetSingleton()->IsEmpty()) {
return util::Status(util::error::INVALID_ARGUMENT,
"Pre-provisioning key map is nullptr.");
}
uint32_t system_id = GetSystemId(token);
// There may be multiple preprov keys for a system ID; try them all.
std::vector<PreprovKey> key_vector =
PreprovKeysMap::GetSingleton()->GetPreprovKeys(system_id);
util::Status status;
// First pass through the matching system Ids is an attempt to find an
// alternate preprov key specific to this make/model.
const PreprovKey* preferred_ppk = NULL;
for (const PreprovKey& ppk : key_vector) {
if (!ppk.model_filter.empty() && ppk.model_filter == make_model) {
preferred_ppk = &ppk;
break;
}
}
for (const PreprovKey& ppk : key_vector) {
if (preferred_ppk && preferred_ppk != &ppk) {
continue;
}
uint32_t version;
status = DecryptDeviceKeyWithPreprovKey(
ppk.key_bytes, token, device_key_out, insecure_out, &version);
if (version != 2) {
// Only version 2 keyboxes supported.
return util::Status(util::error::PERMISSION_DENIED,
absl::StrCat("invalid-keybox-version ", version));
}
if (status.ok()) {
if (cipher_out) {
*cipher_out = ppk.cipher;
}
return status;
}
}
if (!status.ok()) {
// Return error from last attempt.
return status;
}
return util::Status(
util::error::NOT_FOUND,
absl::StrCat("Unknown system id: ", system_id).c_str()); // NOLINT
}
// Decrypt a token using the preprov key for its system ID, and use the
// decrypted device key to encrypt the given asset key. Returns the encrypted
// asset key in |result|.
// On failure, returns an error from the Widevine Server SDK error space.
util::Status WvmTokenHandler::GetEncryptedAssetKey(
absl::string_view token, absl::string_view raw_asset_key,
const std::string& make_model, std::string* result) {
std::string device_key;
Cipher cipher = AES;
util::Status status =
DecryptDeviceKey(token, make_model, &device_key, &cipher, nullptr);
if (!status.ok()) {
return status;
}
return EncryptAssetKey(device_key, raw_asset_key, cipher, result);
}
uint32_t WvmTokenHandler::GetSystemId(absl::string_view token) {
uint32_t system_id = 0;
if (token.size() >= 8) {
// Bytes 4-8 contain the little-endian system ID.
system_id = BigEndian::Load32(token.data() + 4);
}
return system_id;
}
std::string WvmTokenHandler::GetEncryptedUniqueId(absl::string_view token) {
std::string encrypted_unique_id("");
if (token.size() >= 24) {
encrypted_unique_id = std::string(token.substr(8, 16));
}
return encrypted_unique_id;
}
util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key, absl::string_view token,
std::string* device_key_out) {
return DecryptDeviceKeyWithPreprovKey(preprov_key, token, device_key_out,
nullptr, nullptr);
}
util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key, absl::string_view token,
std::string* device_key_out, bool* insecure_out, uint32_t* version) {
CHECK(device_key_out);
if (token.size() < kKeyboxSizeBytes) {
return util::Status(util::error::INVALID_ARGUMENT,
"Keybox token is too short.");
}
if (version) {
*version = BigEndian::Load32(token.data());
}
// This was checked at initialization, so if it fails now something is wrong.
CHECK_EQ(preprov_key.size(), kPreProvisioningKeySizeBytes);
absl::string_view encrypted_unique_id = token.substr(8, 16);
std::string unique_id = crypto_util::DecryptAesCbcNoPad(
std::string(preprov_key), kZeroIV, std::string(encrypted_unique_id));
if (unique_id.size() != 16) {
// Decrypting 16 bytes should result in 16 bytes.
LOG(WARNING) << "Internal error decrypting unique id from token.";
return util::Status(util::error::INTERNAL, "Wrong size after decrypt/16.");
}
absl::string_view encrypted_bits = token.substr(24, 48);
std::string decrypted_bits = crypto_util::DecryptAesCbcNoPad(
unique_id, kZeroIV, std::string(encrypted_bits));
if (decrypted_bits.size() != 48) {
// Decrypting 48 bytes should result in 48 bytes.
LOG(WARNING) << "Internal error decrypting device key from token.";
return util::Status(util::error::INTERNAL, "Wrong size after decrypt/48.");
}
uint8_t keybox_flags = decrypted_bits[36];
absl::string_view device_key =
absl::string_view(decrypted_bits).substr(0, 16);
absl::string_view expected_hash =
absl::string_view(decrypted_bits).substr(16, 20);
std::string actual_hash = Sha1_Hash(std::string(device_key));
if (GetSystemId(token) == kSystemIdSamsungTVFactory) {
// Keyboxes with this system ID have corrupted bytes starting after the
// first 16 bytes of the hash, so we use only the uncorrupted part.
expected_hash = expected_hash.substr(0, 16);
actual_hash.resize(16);
keybox_flags = 0;
}
if (expected_hash != actual_hash) {
return util::Status(util::error::PERMISSION_DENIED,
"Keybox validation failed.");
}
*device_key_out = std::string(device_key);
if (insecure_out) {
*insecure_out = (keybox_flags & kKeyboxFlagInsecure) != 0;
}
return util::OkStatus();
}
util::Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key,
absl::string_view raw_asset_key,
Cipher cipher, std::string* result) {
CHECK(result);
if (device_key.size() != 16) {
return util::Status(util::error::INVALID_ARGUMENT,
"Invalid device key: size != 16");
}
if (raw_asset_key.size() < 16) {
return util::Status(util::error::INVALID_ARGUMENT,
"Invalid asset key: size < 16");
}
// Truncate extra characters in the key; wvm always uses 16.
absl::string_view asset_key = raw_asset_key.substr(0, 16);
switch (cipher) {
case DES3:
if (!crypto_util::Encrypt3DesEcb(device_key, asset_key, result)) {
return util::Status(util::error::INTERNAL,
"Error encrypting asset key with 3DES.");
}
return util::OkStatus();
case AES:
if (!crypto_util::EncryptAesEcb(device_key, asset_key, result)) {
return util::Status(util::error::INTERNAL,
"Error encrypting asset key with AES.");
}
return util::OkStatus();
case PASS_THRU:
result->assign(raw_asset_key.data(), raw_asset_key.size());
return util::OkStatus();
default:
return util::Status(util::error::INVALID_ARGUMENT, "Unknown cipher type");
}
}
} // namespace widevine

126
common/wvm_token_handler.h Normal file
View File

@@ -0,0 +1,126 @@
////////////////////////////////////////////////////////////////////////////////
// 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_WVM_TOKEN_HANDLER_H_
#define COMMON_WVM_TOKEN_HANDLER_H_
#include <map>
#include <vector>
#include "base/macros.h"
#include "absl/strings/string_view.h"
#include "util/status.h"
namespace widevine {
// Class for decoding the encrypted token that comes from a WVM classic keybox.
//
// Internally, this class keeps a multimap from system ID to the preprov key(s)
// for that system, so construction is relatively expensive; don't create an
// instance of this class per-request.
//
// Errors in this file are returned in the canonical space, but are chosen so
// that it's possible to map different failure modes to the appropriate codes
// in the WVM or server SDK error spaces:
// OK - success.
// NOT_FOUND - system id from token wasn't in the preprov key table.
// PERMISSION_DENIED - hash of device key didn't match.
// INVALID_ARGUMENT - token or a key is wrong size or otherwise invalid.
// INTERNAL_ERROR - something went wrong that shouldn't have been able to.
class WvmTokenHandler {
public:
// Cipher type to use for encrypting asset keys. This matches the enum in
// video/widevine/lockbox/public/key.proto.
enum Cipher {
DES3 = 0,
AES = 1,
PASS_THRU = 2,
};
struct PreprovKey {
// Utility constructor.
PreprovKey(uint32_t system_id, const std::string& key_bytes, Cipher cipher,
const std::string& model_filter);
PreprovKey(uint32_t system_id, const std::string& key_bytes, Cipher cipher);
// Constructor if the cipher isn't needed (i.e. modular DRM).
PreprovKey(uint32_t system_id, const std::string& key_bytes);
uint32_t system_id;
std::string key_bytes;
Cipher cipher;
// If set, the make/model in the license request must match this value.
std::string model_filter;
};
// Set pre-provisioning keys from the given vector. This may be called
// concurrently with other methods.
static void SetPreprovKeys(const std::vector<PreprovKey>& preprov_keys);
// Returns true if system_id is in the preprov key table.
static bool IsSystemIdKnown(uint32_t system_id);
// Decrypt a token using the preprov key for its system ID, and
// return the decrypted device key in result.
// On failure, returns one of the errors listed above.
// cipher_out may be null; if not, *cipher_out will be set to the cipher type
// to use with the device key.
// insecure_out may be null; if not, *insecure_out will be set to the
// decrypted value of the 'insecure keybox' flag.
static util::Status DecryptDeviceKey(absl::string_view token,
std::string* device_key_out,
Cipher* cipher_out, bool* insecure_out);
// Same as above, except takes in the make/model from the license request.
// For legacy WVM license, we have some special cases where we need to inspect
// the make/model as we apply alternate keys.
static util::Status DecryptDeviceKey(absl::string_view token,
const std::string& make_model,
std::string* device_key_out,
Cipher* cipher_out, bool* insecure_out);
// Decrypt a token using the preprov key for its system ID, and use the
// decrypted device key to encrypt the given asset key. Returns the encrypted
// asset key in result.
static util::Status GetEncryptedAssetKey(absl::string_view token,
absl::string_view raw_asset_key,
const std::string& make_model,
std::string* result);
// Extract the system ID component of a token (bytes 4-8).
static uint32_t GetSystemId(absl::string_view token);
// Extract the encrypted unique ID component of a token (bytes 8-24).
static std::string GetEncryptedUniqueId(absl::string_view token);
// Try to decrypt a token using the provided preprov key, and return the
// decrypted device key in result.
//
// Note that the if the input std::string lengths are correct (16 and 72 bytes),
// the only possible cause of failure is the decrypted device key hash
// being incorrect.
static util::Status DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key_bytes, absl::string_view token,
std::string* device_key_out);
// Same as above, but allows extracting the 'insecure keybox' flag and keybox
// version.
static util::Status DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key_bytes, absl::string_view token,
std::string* device_key_out, bool* insecure_out, uint32_t* version);
// Given a decrypted device key as returned by DecryptToken(), use it to
// encrypt an asset key with the given cipher.
static util::Status EncryptAssetKey(absl::string_view device_key,
absl::string_view raw_asset_key,
Cipher cipher, std::string* result);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(WvmTokenHandler);
};
} // namespace widevine
#endif // COMMON_WVM_TOKEN_HANDLER_H_

View File

@@ -0,0 +1,236 @@
////////////////////////////////////////////////////////////////////////////////
// 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/wvm_token_handler.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "common/wvm_test_keys.h"
using widevine::wvm_test_keys::kTestSystemId;
using widevine::wvm_test_keys::kTestSystemId3Des;
using widevine::wvm_test_keys::kTestPreprovKeyHex;
using widevine::wvm_test_keys::kTestDeviceKey1Hex;
using widevine::wvm_test_keys::kTestDeviceKey2Hex;
using widevine::wvm_test_keys::kTestDeviceKey3DesHex;
using widevine::wvm_test_keys::kTestToken1Hex;
using widevine::wvm_test_keys::kTestToken2Hex;
using widevine::wvm_test_keys::kTestToken3DesHex;
using widevine::wvm_test_keys::GetPreprovKeyVector;
namespace widevine {
using absl::BytesToHexString;
using absl::HexStringToBytes;
// TODO(user): Add EXPECT_OK macro to testing/gmock.h.
// (b/37545268).
#define EXPECT_OK(expression) \
EXPECT_EQ(util::error::OK, expression.error_code())
TEST(WvmTokenHandlerTest, GetSystemId) {
EXPECT_EQ(kTestSystemId,
WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken1Hex)));
EXPECT_EQ(kTestSystemId,
WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken2Hex)));
}
TEST(WvmTokenHandlerTest, GetEncryptedUniqueId) {
EXPECT_EQ(
HexStringToBytes("8e1ebfe037828096ca6538b4f6f4bcb5"),
WvmTokenHandler::GetEncryptedUniqueId(HexStringToBytes(kTestToken1Hex)));
EXPECT_EQ(
HexStringToBytes("d906feebe1750c5886ff77c2dfa31bb4"),
WvmTokenHandler::GetEncryptedUniqueId(HexStringToBytes(kTestToken2Hex)));
}
TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
util::Status status;
std::string device_key;
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
HexStringToBytes(kTestPreprovKeyHex), HexStringToBytes(kTestToken1Hex),
&device_key);
EXPECT_OK(status) << status;
EXPECT_EQ(kTestDeviceKey1Hex, BytesToHexString(device_key));
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
HexStringToBytes(kTestPreprovKeyHex), HexStringToBytes(kTestToken2Hex),
&device_key);
EXPECT_OK(status);
EXPECT_EQ(kTestDeviceKey2Hex, BytesToHexString(device_key));
// Test with invalid token. Hash failure should produce PERMISSION_DENIED.
device_key.clear();
std::string token = HexStringToBytes(
"00000002000001129e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98"
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e");
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
HexStringToBytes(kTestPreprovKeyHex), token, &device_key);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
EXPECT_TRUE(device_key.empty());
}
// See b/68798704 for background of this test.
// It is important to keep this test *before* all the DecryptDeviceKey* tests
// below, in which WvmTokenHandler::SetPreprovKeys() would be called.
TEST(WvmTokenHandlerTest, DecryptDeviceKey_PreprovKeysNullPtr) {
// Not calling WvmTokenHandler::SetPreprovKeys()
// So preprov_keys_ would be nullptr.
util::Status status;
std::string device_key;
status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex),
&device_key, nullptr, nullptr);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
}
// Same tests as DecryptDeviceKeyWithPreprovKey(), but we use the handler's
// table of preprov keys instead of providing our own.
TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
util::Status status;
std::string device_key;
WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector());
status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex),
&device_key, nullptr, nullptr);
EXPECT_OK(status);
EXPECT_EQ(HexStringToBytes(kTestDeviceKey1Hex), device_key);
status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken2Hex),
&device_key, nullptr, nullptr);
EXPECT_OK(status);
EXPECT_EQ(HexStringToBytes(kTestDeviceKey2Hex), device_key);
// Test with invalid token. Hash failure should produce PERMISSION_DENIED.
device_key.clear();
std::string token = HexStringToBytes(
"00000002000001129e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98"
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e");
status =
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
EXPECT_TRUE(device_key.empty());
// Test with nonexistent system id. Should produce NOT_FOUND.
device_key.clear();
token = HexStringToBytes(
"00000002555555559e1ebfe037828096ca6538b4f6f4bcb51c2b7191cf037e98"
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e");
status =
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::NOT_FOUND, status.error_code());
EXPECT_TRUE(device_key.empty());
}
TEST(WvmTokenHandlerTest, GetEncryptedAssetKey) {
WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector());
std::string raw_asset_key = "asset-key-000000";
std::string asset_key;
std::string make_model;
util::Status status = WvmTokenHandler::GetEncryptedAssetKey(
HexStringToBytes(kTestToken1Hex), raw_asset_key, make_model, &asset_key);
EXPECT_OK(status);
EXPECT_EQ("305d5f979074b1c4f932be70d3cc850c", BytesToHexString(asset_key));
status = WvmTokenHandler::GetEncryptedAssetKey(
HexStringToBytes(kTestToken2Hex), raw_asset_key, make_model, &asset_key);
EXPECT_OK(status);
EXPECT_EQ("091802159bf8da12aecfcdfb092075c8", BytesToHexString(asset_key));
// Check 3DES encryption of asset keys
status = WvmTokenHandler::EncryptAssetKey(
HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key,
WvmTokenHandler::DES3, &asset_key);
EXPECT_OK(status);
EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key));
asset_key.clear();
status = WvmTokenHandler::GetEncryptedAssetKey(
HexStringToBytes(kTestToken3DesHex), raw_asset_key, make_model,
&asset_key);
EXPECT_OK(status);
EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key));
// Test with pass-thru (Cipher=PASS_THRU).
asset_key.clear();
status = WvmTokenHandler::EncryptAssetKey(
HexStringToBytes(kTestDeviceKey1Hex), raw_asset_key,
WvmTokenHandler::PASS_THRU, &asset_key);
EXPECT_OK(status);
EXPECT_EQ(BytesToHexString(raw_asset_key), BytesToHexString(asset_key));
}
TEST(WvmTokenHandlerTest, FilterOnMakeModel) {
// Use all good keys, but only the key for LG:BD572 should work. It works
// by setting only that one to DES3. All other AES ppks will encrypt the
// asset key incorrectly.
std::vector<WvmTokenHandler::PreprovKey> ppks;
ppks.push_back(WvmTokenHandler::PreprovKey(
kTestSystemId3Des, HexStringToBytes(kTestPreprovKeyHex),
WvmTokenHandler::AES, ""));
ppks.push_back(WvmTokenHandler::PreprovKey(
kTestSystemId3Des, HexStringToBytes(kTestPreprovKeyHex),
WvmTokenHandler::DES3, "LG:BD572"));
ppks.push_back(WvmTokenHandler::PreprovKey(
kTestSystemId3Des, HexStringToBytes(kTestPreprovKeyHex),
WvmTokenHandler::AES, ""));
WvmTokenHandler::SetPreprovKeys(ppks);
std::string raw_asset_key = "asset-key-000000";
std::string asset_key;
// Check 3DES encryption of asset keys
util::Status status = WvmTokenHandler::EncryptAssetKey(
HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key,
WvmTokenHandler::DES3, &asset_key);
EXPECT_OK(status);
EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key));
asset_key.clear();
std::string make_model;
status = WvmTokenHandler::GetEncryptedAssetKey(
HexStringToBytes(kTestToken3DesHex), raw_asset_key, make_model,
&asset_key);
EXPECT_OK(status);
// Should fail because the asset key was encrypted with AES instead of DES3.
EXPECT_NE("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key));
// Set the make/model so we find and use the correct ppk.
make_model = "LG:BD572";
status = WvmTokenHandler::GetEncryptedAssetKey(
HexStringToBytes(kTestToken3DesHex), raw_asset_key, make_model,
&asset_key);
EXPECT_OK(status);
// Should work because the asset key was encrypted with DES3.
EXPECT_EQ("3693a68bdeba192be0ea279e6c165197", BytesToHexString(asset_key));
}
TEST(WvmTokenHandlerTest, AncientKeybox) {
util::Status status;
std::string device_key;
std::string v1_token(
std::string(kTestPreprovKeyHex).replace(0, 16, "0000000100000001"));
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
HexStringToBytes(v1_token), HexStringToBytes(kTestToken1Hex),
&device_key);
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
EXPECT_TRUE(device_key.empty());
}
} // namespace widevine

361
common/x509_cert.cc Normal file
View File

@@ -0,0 +1,361 @@
////////////////////////////////////////////////////////////////////////////////
// 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/x509_cert.h"
#include <memory>
#include <cstdint>
#include "glog/logging.h"
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/pem.h"
#include "openssl/x509.h"
#include "openssl/x509v3.h"
#include "common/openssl_util.h"
#include "common/rsa_key.h"
namespace {
// Serializes the X509 |certificate| into a PEM-encoded string. Returns true
// on success, false otherwise. The caller retains ownership of
// |certificate| and |serialized_certificate|. |serialized_certificate| must
// not be NULL.
bool PemEncodeX509Certificate(const X509& certificate,
std::string* serialized_certificate) {
CHECK(serialized_certificate) << "serialized_certificate can not be null.";
ScopedBIO bio(BIO_new(BIO_s_mem()));
if (bio == nullptr) {
return false;
}
// The const_cast is necessary for the openssl call.
PEM_write_bio_X509(bio.get(), const_cast<X509*>(&certificate));
int serialized_size = BIO_pending(bio.get());
serialized_certificate->resize(serialized_size);
if (BIO_read(bio.get(), &(*serialized_certificate)[0], serialized_size) !=
serialized_size) {
return false;
}
return true;
}
} // anonymous namespace.
namespace widevine {
std::unique_ptr<X509Cert> X509Cert::FromOpenSslCert(
ScopedX509 certificate) {
return std::unique_ptr<X509Cert>(new X509Cert(certificate.release()));
}
X509Cert::X509Cert() : openssl_cert_(NULL) {}
X509Cert::~X509Cert() {
if (openssl_cert_ != NULL) {
X509_free(openssl_cert_);
}
}
X509Cert::X509Cert(X509* openssl_cert) : openssl_cert_(openssl_cert) {}
util::Status X509Cert::LoadPem(const std::string& pem_cert) {
if (pem_cert.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM certificate");
}
BIO* bio(NULL);
X509* new_cert(NULL);
bio = BIO_new_mem_buf(const_cast<char*>(pem_cert.data()), pem_cert.size());
if (bio == NULL) {
return util::Status(util::error::INTERNAL, "BIO allocation failed");
}
util::Status status;
new_cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (new_cert == NULL) {
status = util::Status(util::Status::canonical_space(),
util::error::INVALID_ARGUMENT,
"PEM certificate load failed");
goto cleanup;
}
if (openssl_cert_ != NULL) {
X509_free(openssl_cert_);
}
openssl_cert_ = new_cert;
cleanup:
if (bio != NULL) {
BIO_free(bio);
}
return status;
}
util::Status X509Cert::LoadDer(const std::string& der_cert) {
if (der_cert.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty DER certificate");
}
const unsigned char* cert_data =
reinterpret_cast<const unsigned char*>(der_cert.data());
X509* new_cert = d2i_X509(NULL, &cert_data, der_cert.size());
if (new_cert == NULL) {
return util::Status(util::error::INVALID_ARGUMENT,
"DER certificate load failed");
}
if (openssl_cert_ != NULL) {
X509_free(openssl_cert_);
}
openssl_cert_ = new_cert;
return util::OkStatus();
}
std::string X509Cert::GetPem() const {
std::string serialized_certificate;
if (!PemEncodeX509Certificate(*openssl_cert_, &serialized_certificate)) {
return "";
}
return serialized_certificate;
}
std::unique_ptr<RsaPublicKey> X509Cert::GetRsaPublicKey() const {
ScopedPKEY pkey(X509_get_pubkey(openssl_cert_));
return std::unique_ptr<RsaPublicKey>(
new RsaPublicKey(EVP_PKEY_get1_RSA(pkey.get())));
}
const std::string& X509Cert::GetSubjectName() {
if (subject_name_.empty() && (openssl_cert_ != NULL)) {
X509_NAME* subject = X509_get_subject_name(openssl_cert_);
if (subject != NULL) {
BIO* bio = BIO_new(BIO_s_mem());
if (bio != NULL) {
X509_NAME_print_ex(bio, subject, 0, 0);
int size = BIO_pending(bio);
std::unique_ptr<char[]> buffer(new char[size]);
int bytes_read = BIO_read(bio, buffer.get(), size);
if (bytes_read == size) {
subject_name_.assign(buffer.get(), bytes_read);
}
BIO_free(bio);
}
}
}
return subject_name_;
}
std::string X509Cert::GetSubjectNameField(const std::string& field) {
if (field.empty()) {
return std::string();
}
const std::string& subject = GetSubjectName();
size_t start_pos = subject.find(field + "=");
if (start_pos == std::string::npos) {
return std::string();
}
start_pos += field.size() + 1;
size_t end_pos = subject.find(",", start_pos);
if (end_pos == std::string::npos) {
end_pos = subject.size();
}
return subject.substr(start_pos, end_pos - start_pos);
}
std::string X509Cert::GetSerialNumber() const {
if (openssl_cert_ == NULL) {
return std::string();
}
BIGNUM* bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(openssl_cert_), NULL);
if (bn == NULL) {
return std::string();
}
std::string result;
char* openssl_sn = BN_bn2hex(bn);
if (openssl_sn != NULL) {
result = absl::HexStringToBytes(openssl_sn);
OPENSSL_free(openssl_sn);
}
BN_free(bn);
return result;
}
bool X509Cert::IsCaCertificate() const {
return X509_check_ca(openssl_cert_) != 0;
}
bool X509Cert::GetV3BooleanExtension(const std::string& oid, bool* value) const {
ScopedAsn1Object extension_name(OBJ_txt2obj(oid.c_str(), 1));
int ext_pos = X509_get_ext_by_OBJ(openssl_cert_, extension_name.get(), -1);
if (ext_pos < 0) return false;
X509_EXTENSION* extension(X509_get_ext(openssl_cert_, ext_pos));
if (!extension) return false;
ASN1_OCTET_STRING *extension_data(X509_EXTENSION_get_data(extension));
if (!extension_data) return false;
if ((extension_data->length != 3) || (extension_data->data[0] != 1) ||
(extension_data->data[1] != 1)) return false;
*value = extension_data->data[2] != 0;
return true;
}
X509CertChain::~X509CertChain() { Reset(); }
void X509CertChain::Reset() {
for (auto certp : cert_chain_) {
delete certp;
}
cert_chain_.clear();
}
util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
static const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----";
static const char kEndCertificate[] = "-----END CERTIFICATE-----";
Reset();
size_t begin_pos = pem_cert_chain.find(kBeginCertificate);
while (begin_pos != std::string::npos) {
size_t end_pos = pem_cert_chain.find(
kEndCertificate, begin_pos + sizeof(kBeginCertificate) - 1);
if (end_pos != std::string::npos) {
end_pos += sizeof(kEndCertificate) - 1;
std::unique_ptr<X509Cert> new_cert(new X509Cert);
util::Status status = new_cert->LoadPem(
pem_cert_chain.substr(begin_pos, end_pos - begin_pos));
if (!status.ok()) {
return status;
}
cert_chain_.push_back(new_cert.release());
begin_pos = pem_cert_chain.find(kBeginCertificate, end_pos);
}
}
return util::OkStatus();
}
util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
ScopedX509Stack cert_stack(sk_X509_new_null());
CBS cbs;
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pk7_cert_chain.data()),
pk7_cert_chain.size());
if (!PKCS7_get_certificates(cert_stack.get(), &cbs)) {
return util::Status(util::error::INVALID_ARGUMENT,
"Unable to load PKCS#7 certificate chain");
}
while (sk_X509_num(cert_stack.get()) > 0) {
cert_chain_.push_back(new X509Cert(sk_X509_pop(cert_stack.get())));
}
return util::OkStatus();
}
X509Cert* X509CertChain::GetCert(size_t cert_index) const {
if (cert_index >= cert_chain_.size()) {
return NULL;
}
return cert_chain_[cert_index];
}
X509CA::X509CA(X509Cert* ca_cert) : ca_cert_(ca_cert), openssl_store_(NULL) {}
X509CA::~X509CA() {
if (openssl_store_ != NULL) {
X509_STORE_free(openssl_store_);
}
}
util::Status X509CA::InitializeStore() {
absl::WriterMutexLock lock(&openssl_store_mutex_);
if (openssl_store_ == NULL) {
if (ca_cert_ == NULL) {
return util::Status(util::error::INTERNAL, "CA X.509Cert is NULL");
}
openssl_store_ = X509_STORE_new();
if (openssl_store_ == NULL) {
return util::Status(util::error::INTERNAL,
"Failed to allocate X.509 store");
}
if (X509_STORE_add_cert(openssl_store_,
const_cast<X509*>(ca_cert_->openssl_cert())) == 0) {
X509_STORE_free(openssl_store_);
openssl_store_ = NULL;
return util::Status(util::error::INTERNAL,
"Failed to add X.509 CA certificate to store");
}
}
return util::OkStatus();
}
util::Status X509CA::VerifyCert(const X509Cert& cert) {
return OpenSslX509Verify(cert.openssl_cert(), nullptr);
}
util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
if (cert_chain.GetNumCerts() < 1) {
return util::Status(util::error::INVALID_ARGUMENT,
"Cannot verify empty certificate chain");
}
ScopedX509StackOnly intermediates(sk_X509_new_null());
if (!intermediates) {
return util::Status(
util::Status::canonical_space(), util::error::INTERNAL,
"Failed to allocate X.509 intermediate certificate stack");
}
const X509Cert* leaf_cert(nullptr);
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
if (cert_chain.GetCert(idx)->IsCaCertificate()) {
sk_X509_push(intermediates.get(),
const_cast<X509*>(cert_chain.GetCert(idx)->openssl_cert()));
} else {
leaf_cert = cert_chain.GetCert(idx);
}
}
if (!leaf_cert) {
return util::Status(util::Status::canonical_space(),
util::error::INVALID_ARGUMENT,
"X.509 certificate chain without leaf certificate.");
}
return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get());
}
util::Status X509CA::OpenSslX509Verify(const X509* cert,
STACK_OF(X509) * intermediates) {
DCHECK(cert);
absl::ReaderMutexLock lock(&openssl_store_mutex_);
if (openssl_store_ == NULL) {
openssl_store_mutex_.ReaderUnlock();
util::Status status = InitializeStore();
if (!status.ok()) {
return status;
}
openssl_store_mutex_.ReaderLock();
}
ScopedX509StoreCtx store_ctx(X509_STORE_CTX_new());
if (!store_ctx) {
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
"Failed to allocate X.509 store context");
}
if (X509_STORE_CTX_init(store_ctx.get(), openssl_store_,
const_cast<X509*>(cert), intermediates) == 0) {
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
"Failed to initialize X.509 store context");
}
int x509_status = X509_verify_cert(store_ctx.get());
if (x509_status != 1) {
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
std::string("X.509 certificate chain validation failed: ") +
X509_verify_cert_error_string(
X509_STORE_CTX_get_error(store_ctx.get())));
}
return util::OkStatus();
}
} // namespace widevine

155
common/x509_cert.h Normal file
View File

@@ -0,0 +1,155 @@
////////////////////////////////////////////////////////////////////////////////
// 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:
// X.509 certificate classes used by the license server SDK.
#ifndef COMMON_X509_CERT_H__
#define COMMON_X509_CERT_H__
#include <stddef.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "openssl/pem.h"
#include "openssl/x509.h"
#include "openssl/x509v3.h"
#include "util/status.h"
#include "common/openssl_util.h"
namespace widevine {
class RsaPublicKey;
// NOTE: All util::Status codes are in the canonical error space.
// Class which holds a single X.509 certificates.
class X509Cert {
public:
// Load the certificate from an openssl X509 certificate instance.
static std::unique_ptr<X509Cert> FromOpenSslCert(ScopedX509 openssl_cert_);
X509Cert();
virtual ~X509Cert();
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
// a PEM-encoded certificate.
util::Status LoadPem(const std::string& pem_cert);
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
// a DER-encoded certificate.
util::Status LoadDer(const std::string& der_cert);
// Return a std::string containing the PEM-encoded certificate.
std::string GetPem() const;
// Returns certificate RSA public key. nullptr if not found, or if key type
// is not RSA.
std::unique_ptr<RsaPublicKey> GetRsaPublicKey() const;
// Returns the internal OpenSSL X509 certificate.
const X509* openssl_cert() const { return openssl_cert_; }
// Returns the certificate subject name.
const std::string& GetSubjectName();
// Returns a field within the certificate subject name, or an empty std::string
// if the field is not found.
std::string GetSubjectNameField(const std::string& field);
// Returns the certificate serial number, binary encoded, or an empty std::string
// if an error occurs.
std::string GetSerialNumber() const;
// Returns true if the certificate is a CA (root or intermediate) certificate.
bool IsCaCertificate() const;
// Gets the value of an X.509 V3 extension encoded as a boolean. |oid| is the
// object identifier sequence for the extension, and |value| is a pointer to
// an integer which will contain the extension value upon successful return.
// Returns true if successful, or false otherwise.
bool GetV3BooleanExtension(const std::string& oid, bool* value) const;
private:
explicit X509Cert(X509* openssl_cert);
X509* openssl_cert_;
std::string subject_name_;
friend class X509CertChain;
DISALLOW_COPY_AND_ASSIGN(X509Cert);
};
// Class which holds a chain of X.509 certificates.
class X509CertChain {
public:
X509CertChain() {}
virtual ~X509CertChain();
// Loads a chain of PEM-encoded X.509 certificates. Takes a single parameter,
// |pem_cert_chain|, which is the concatenation of a number of PEM X.509
// certificates, beginning with the leaf certificate, and ending with the
// certificate signed by the root CA.
util::Status LoadPem(const std::string& pem_cert_chain);
// Loads a chain of DER-encoded PKCS#7 certificates. Takes a single parameter,
// |pk7_cert_chain|, which is a DER-encoded PKCS#7 X.509 certificate
// container.
util::Status LoadPkcs7(const std::string& pk7_cert_chain);
// Returns the number of certificates in the chain.
size_t GetNumCerts() const { return cert_chain_.size(); }
// Returns the X509Cert at the specified chain index (0 start). Returns
// NULL if cert_index is out of range. The X509CertChain retains ownwership
// of the object returned.
X509Cert* GetCert(size_t cert_index) const;
private:
void Reset();
std::vector<X509Cert*> cert_chain_;
DISALLOW_COPY_AND_ASSIGN(X509CertChain);
};
// CA class which holds the root CA cert, and verifies certificate chains.
class X509CA {
public:
// New object assumes ownership of |ca_cert|.
explicit X509CA(X509Cert* ca_cert);
virtual ~X509CA();
// Does X.509 PKI validation of |cert| against the root CA certificate
// used when constructing X509CA. This method is thread-safe.
util::Status VerifyCert(const X509Cert& cert);
// Does X.509 PKI validation of |cert_chain| against the root CA certificate
// used when constructing X509CA. This method is thread-safe.
util::Status VerifyCertChain(const X509CertChain& cert_chain);
private:
util::Status InitializeStore();
util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509)* stack);
std::unique_ptr<X509Cert> ca_cert_;
absl::Mutex openssl_store_mutex_;
X509_STORE* openssl_store_ GUARDED_BY(openssl_store_mutex_);
DISALLOW_IMPLICIT_CONSTRUCTORS(X509CA);
};
} // namespace widevine
#endif // COMMON_X509_CERT_H__

404
common/x509_cert_test.cc Normal file
View File

@@ -0,0 +1,404 @@
////////////////////////////////////////////////////////////////////////////////
// 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/x509_cert.h"
#include <memory>
#include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "common/rsa_key.h"
#include "common/test_utils.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 kTestPemCert[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
"VQQIDApXYXNoaW5ndG9uMREwDwYDVQQHDAhLaXJrbGFuZDETMBEGA1UECgwKR29v\n"
"Z2xlIEluYzERMA8GA1UECwwIV2lkZXZpbmUxHTAbBgNVBAMMFFRlc3QgSW50ZXJt\n"
"ZWRpYXRlIENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcN\n"
"MTMwODE2MjE0NDAwWhcNMzMwODE1MjE0NDAwWjCBrjELMAkGA1UEBhMCVVMxEzAR\n"
"BgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMSkwJwYDVQQKDCBD\n"
"aHJvbWUgRGV2aWNlIENvbnRlbnQgUHJvdGVjdGlvbjEVMBMGA1UECwwMdGVzdGlu\n"
"Zy50ZXN0MRIwEAYDVQQDDAlzdGFibGUgaWQxITAfBgkqhkiG9w0BCQEWEnRpbnNr\n"
"aXBAZ29vZ2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKlb\n"
"DqstOK0TlLtJZOGzysjD48ZXEnpwti0cQAK6JcN9htwpHemBlzAbIuOIjeY2tfvk\n"
"l2uIOOnNMgAiKs/Dpu9VbedXAVCnuxE7/yrWIw/rg1ZmqdxQXFqTo+52ErteMru4\n"
"krOaNgQ63SE934yR0MSFzuSbvTgTFLP7hHueaeg8+CUvQRU0WoC2akMXzY1G6AkV\n"
"wyY/lufA/XEQXgPbhvP67YxR+exwCfzQGolB5hkliKux0rmzDfcIiHMM0IDaE6nu\n"
"fbm8BKPxlZS/QrzTZAr9Q5GMyjcu0XTI1fknGVrE4pZMh8ge+ondcgIQxXBOhfJK\n"
"FCofYSP7rBxtasK+4ncCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEATcNfaLpfLbX6\n"
"qz1qKMLYaNe4OI0X8t8ZNXqEdqyNd4C7kSdaQkwNunVAqw1CadUzLRi8Of18cwlQ\n"
"EXBN4bPTeODCobPjS71YcYPhDsvGQcQ3GQC6BOyHKCTYpqgcIIPEGFzI+FrACede\n"
"f4tyIexq63iIx1IpmTBnpYnnfgc8v4anphNODHKMRBHy8BJRcKpTFFFo571c5OjE\n"
"QjhKEOp9eD72GuEgtK0f7jXYH2bRT4lmSLxg2L1jbwg3qIjoX2gjeILyzUF+FTzO\n"
"7G5JWQnyDjd/ZJuld7FRsJmuzAgISeqVeraYXU1p4utbqutATmmHBcYhkXJKBKkf\n"
"3rDeUI+Odg==\n"
"-----END CERTIFICATE-----\n";
const char kTestPemCertSubjectField_C[] = "US";
const char kTestPemCertSubjectField_CN[] =
"stable id/emailAddress=tinskip@google.com";
const char kTestPemCertSerialNumber[] = "\002";
const char kTestPemCertChain[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
"VQQIDApXYXNoaW5ndG9uMREwDwYDVQQHDAhLaXJrbGFuZDETMBEGA1UECgwKR29v\n"
"Z2xlIEluYzERMA8GA1UECwwIV2lkZXZpbmUxHTAbBgNVBAMMFFRlc3QgSW50ZXJt\n"
"ZWRpYXRlIENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcN\n"
"MTMwODE2MjE0NDAwWhcNMzMwODE1MjE0NDAwWjCBrjELMAkGA1UEBhMCVVMxEzAR\n"
"BgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMSkwJwYDVQQKDCBD\n"
"aHJvbWUgRGV2aWNlIENvbnRlbnQgUHJvdGVjdGlvbjEVMBMGA1UECwwMdGVzdGlu\n"
"Zy50ZXN0MRIwEAYDVQQDDAlzdGFibGUgaWQxITAfBgkqhkiG9w0BCQEWEnRpbnNr\n"
"aXBAZ29vZ2xlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKlb\n"
"DqstOK0TlLtJZOGzysjD48ZXEnpwti0cQAK6JcN9htwpHemBlzAbIuOIjeY2tfvk\n"
"l2uIOOnNMgAiKs/Dpu9VbedXAVCnuxE7/yrWIw/rg1ZmqdxQXFqTo+52ErteMru4\n"
"krOaNgQ63SE934yR0MSFzuSbvTgTFLP7hHueaeg8+CUvQRU0WoC2akMXzY1G6AkV\n"
"wyY/lufA/XEQXgPbhvP67YxR+exwCfzQGolB5hkliKux0rmzDfcIiHMM0IDaE6nu\n"
"fbm8BKPxlZS/QrzTZAr9Q5GMyjcu0XTI1fknGVrE4pZMh8ge+ondcgIQxXBOhfJK\n"
"FCofYSP7rBxtasK+4ncCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEATcNfaLpfLbX6\n"
"qz1qKMLYaNe4OI0X8t8ZNXqEdqyNd4C7kSdaQkwNunVAqw1CadUzLRi8Of18cwlQ\n"
"EXBN4bPTeODCobPjS71YcYPhDsvGQcQ3GQC6BOyHKCTYpqgcIIPEGFzI+FrACede\n"
"f4tyIexq63iIx1IpmTBnpYnnfgc8v4anphNODHKMRBHy8BJRcKpTFFFo571c5OjE\n"
"QjhKEOp9eD72GuEgtK0f7jXYH2bRT4lmSLxg2L1jbwg3qIjoX2gjeILyzUF+FTzO\n"
"7G5JWQnyDjd/ZJuld7FRsJmuzAgISeqVeraYXU1p4utbqutATmmHBcYhkXJKBKkf\n"
"3rDeUI+Odg==\n"
"-----END CERTIFICATE-----\n"
"-----BEGIN CERTIFICATE-----\n"
"MIIEAzCCAuugAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMx\n"
"EzARBgNVBAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQK\n"
"DApHb29nbGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEVMBMGA1UEAwwMVGVzdCBS\n"
"b290IENBMSEwHwYJKoZIhvcNAQkBFhJ0aW5za2lwQGdvb2dsZS5jb20wHhcNMTMw\n"
"ODE2MjE0MTQ2WhcNMzMwODE1MjE0MTQ2WjCBnzELMAkGA1UEBhMCVVMxEzARBgNV\n"
"BAgMCldhc2hpbmd0b24xETAPBgNVBAcMCEtpcmtsYW5kMRMwEQYDVQQKDApHb29n\n"
"bGUgSW5jMREwDwYDVQQLDAhXaWRldmluZTEdMBsGA1UEAwwUVGVzdCBJbnRlcm1l\n"
"ZGlhdGUgQ0ExITAfBgkqhkiG9w0BCQEWEnRpbnNraXBAZ29vZ2xlLmNvbTCCASIw\n"
"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANooBi6x3I9Incs6ytlPjBu7yEy5\n"
"f6BLf5NREE5nQm74Rt7PAA7YVDtxHP+pi1uyxsL3fUrx904s4tdXNRK85/2zn7+o\n"
"oZPYb8fH6dgl7ocmYeyC0jSmg7++ZiaS6OsjPSUTE2aEbAe6Q+ZhYsAbdkL7Z2dN\n"
"UJR9akhLEqlqfX4q5bWA0M3P/2/fqNYMS0w010Nwpd+KydbceT0rHQTmTGVsqCCL\n"
"gmaP9a8aQRMSP0dn5IOcc/K1Qnnfw1gxnjGF4aBP7KbCMxNBrbgBOwiTxgEMIcKZ\n"
"9IGszAcpftKX5ra3XePzFWCcnwilppaaE/2XWXkcAehc8d3xtkdAYZyVIBUCAwEA\n"
"AaNQME4wHQYDVR0OBBYEFDm35gzM6ll13HhZUbW5uDw7BieTMB8GA1UdIwQYMBaA\n"
"FE0w/xgaxPENqZ5qEsAeAqzK34QKMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n"
"BQADggEBALj+/Z8ygfWVNncV0N9UsAcwlGUe5ME+VoXUF/0SOmdrc8LtPc2Dkc8b\n"
"xiQN1wHxE/OFsbsOdobPzwOBh67KyYyVWtxzzsLO0MHGxsbOmwa1AersoP4x8xoC\n"
"HaBU90cviYqz5k6rZyBIlFIrM5lqG1JB3U0kTceG/1sqwRAAu94BYqMW1iWyr9Mq\n"
"ASRCVBOrksWda4pZkCLp62vk7ItOcs2PrHf6UWbANTDH+8Q+pIw2wuJ5lf/imqKO\n"
"qrYCJmAi6VBa2jyHqXVPMk6lL1Rmdk4UgOsRvsbmKzb2vYeWIwhsXY5Spo3WVTLv\n"
"6kIkGZCFP/ws7ctk+fQyjjttncIdL2k=\n"
"-----END CERTIFICATE-----\n";
const char kTestPk7CertChain[] =
"308207fb06092a864886f70d010702a08207ec308207e80201013100300b"
"06092a864886f70d010701a08207ce308203c3308202ab020102300d0609"
"2a864886f70d010105050030819f310b3009060355040613025553311330"
"1106035504080c0a57617368696e67746f6e3111300f06035504070c084b"
"69726b6c616e6431133011060355040a0c0a476f6f676c6520496e633111"
"300f060355040b0c085769646576696e65311d301b06035504030c145465"
"737420496e7465726d6564696174652043413121301f06092a864886f70d"
"010901161274696e736b697040676f6f676c652e636f6d301e170d313330"
"3831363231343430305a170d3333303831353231343430305a3081ae310b"
"30090603550406130255533113301106035504080c0a57617368696e6774"
"6f6e3111300f06035504070c084b69726b6c616e6431293027060355040a"
"0c204368726f6d652044657669636520436f6e74656e742050726f746563"
"74696f6e31153013060355040b0c0c74657374696e672e74657374311230"
"1006035504030c09737461626c652069643121301f06092a864886f70d01"
"0901161274696e736b697040676f6f676c652e636f6d30820122300d0609"
"2a864886f70d01010105000382010f003082010a0282010100a95b0eab2d"
"38ad1394bb4964e1b3cac8c3e3c657127a70b62d1c4002ba25c37d86dc29"
"1de98197301b22e3888de636b5fbe4976b8838e9cd3200222acfc3a6ef55"
"6de7570150a7bb113bff2ad6230feb835666a9dc505c5a93a3ee7612bb5e"
"32bbb892b39a36043add213ddf8c91d0c485cee49bbd381314b3fb847b9e"
"69e83cf8252f4115345a80b66a4317cd8d46e80915c3263f96e7c0fd7110"
"5e03db86f3faed8c51f9ec7009fcd01a8941e6192588abb1d2b9b30df708"
"88730cd080da13a9ee7db9bc04a3f19594bf42bcd3640afd43918cca372e"
"d174c8d5f927195ac4e2964c87c81efa89dd720210c5704e85f24a142a1f"
"6123fbac1c6d6ac2bee2770203010001300d06092a864886f70d01010505"
"0003820101004dc35f68ba5f2db5faab3d6a28c2d868d7b8388d17f2df19"
"357a8476ac8d7780bb91275a424c0dba7540ab0d4269d5332d18bc39fd7c"
"73095011704de1b3d378e0c2a1b3e34bbd587183e10ecbc641c4371900ba"
"04ec872824d8a6a81c2083c4185cc8f85ac009e75e7f8b7221ec6aeb7888"
"c75229993067a589e77e073cbf86a7a6134e0c728c4411f2f0125170aa53"
"145168e7bd5ce4e8c442384a10ea7d783ef61ae120b4ad1fee35d81f66d1"
"4f896648bc60d8bd636f0837a888e85f68237882f2cd417e153cceec6e49"
"5909f20e377f649ba577b151b099aecc080849ea957ab6985d4d69e2eb5b"
"aaeb404e698705c62191724a04a91fdeb0de508f8e7630820403308202eb"
"a003020102020101300d06092a864886f70d0101050500308197310b3009"
"0603550406130255533113301106035504080c0a57617368696e67746f6e"
"3111300f06035504070c084b69726b6c616e6431133011060355040a0c0a"
"476f6f676c6520496e633111300f060355040b0c085769646576696e6531"
"15301306035504030c0c5465737420526f6f742043413121301f06092a86"
"4886f70d010901161274696e736b697040676f6f676c652e636f6d301e17"
"0d3133303831363231343134365a170d3333303831353231343134365a30"
"819f310b30090603550406130255533113301106035504080c0a57617368"
"696e67746f6e3111300f06035504070c084b69726b6c616e643113301106"
"0355040a0c0a476f6f676c6520496e633111300f060355040b0c08576964"
"6576696e65311d301b06035504030c145465737420496e7465726d656469"
"6174652043413121301f06092a864886f70d010901161274696e736b6970"
"40676f6f676c652e636f6d30820122300d06092a864886f70d0101010500"
"0382010f003082010a0282010100da28062eb1dc8f489dcb3acad94f8c1b"
"bbc84cb97fa04b7f9351104e67426ef846decf000ed8543b711cffa98b5b"
"b2c6c2f77d4af1f74e2ce2d7573512bce7fdb39fbfa8a193d86fc7c7e9d8"
"25ee872661ec82d234a683bfbe662692e8eb233d25131366846c07ba43e6"
"6162c01b7642fb67674d50947d6a484b12a96a7d7e2ae5b580d0cdcfff6f"
"dfa8d60c4b4c34d74370a5df8ac9d6dc793d2b1d04e64c656ca8208b8266"
"8ff5af1a4113123f4767e4839c73f2b54279dfc358319e3185e1a04feca6"
"c2331341adb8013b0893c6010c21c299f481accc07297ed297e6b6b75de3"
"f315609c9f08a5a6969a13fd9759791c01e85cf1ddf1b64740619c952015"
"0203010001a350304e301d0603551d0e0416041439b7e60cccea5975dc78"
"5951b5b9b83c3b062793301f0603551d230418301680144d30ff181ac4f1"
"0da99e6a12c01e02accadf840a300c0603551d13040530030101ff300d06"
"092a864886f70d01010505000382010100b8fefd9f3281f595367715d0df"
"54b0073094651ee4c13e5685d417fd123a676b73c2ed3dcd8391cf1bc624"
"0dd701f113f385b1bb0e7686cfcf038187aecac98c955adc73cec2ced0c1"
"c6c6c6ce9b06b501eaeca0fe31f31a021da054f7472f898ab3e64eab6720"
"4894522b33996a1b5241dd4d244dc786ff5b2ac11000bbde0162a316d625"
"b2afd32a0124425413ab92c59d6b8a599022e9eb6be4ec8b4e72cd8fac77"
"fa5166c03530c7fbc43ea48c36c2e27995ffe29aa28eaab602266022e950"
"5ada3c87a9754f324ea52f5466764e1480eb11bec6e62b36f6bd87962308"
"6c5d8e52a68dd65532efea42241990853ffc2cedcb64f9f4328e3b6d9dc2"
"1d2f69a1003100";
const char kTestCertPrivateKey[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIIEowIBAAKCAQEAqVsOqy04rROUu0lk4bPKyMPjxlcSenC2LRxAArolw32G3Ckd\n"
"6YGXMBsi44iN5ja1++SXa4g46c0yACIqz8Om71Vt51cBUKe7ETv/KtYjD+uDVmap\n"
"3FBcWpOj7nYSu14yu7iSs5o2BDrdIT3fjJHQxIXO5Ju9OBMUs/uEe55p6Dz4JS9B\n"
"FTRagLZqQxfNjUboCRXDJj+W58D9cRBeA9uG8/rtjFH57HAJ/NAaiUHmGSWIq7HS\n"
"ubMN9wiIcwzQgNoTqe59ubwEo/GVlL9CvNNkCv1DkYzKNy7RdMjV+ScZWsTilkyH\n"
"yB76id1yAhDFcE6F8koUKh9hI/usHG1qwr7idwIDAQABAoIBADdwlZa30QvnkxLU\n"
"be/s+X9LkS8GpgfrCdgunU3HPkGGwDUmSKJ+R835tCwkMb+hPWXeaStMhsUS5UFh\n"
"7f3hoK5MmxPWSZnrrrNvnpKZUxUNFgucxBJZREJqfom7oVow9g6511xwKSqtUmJl\n"
"bN8JhPwwiZAQ45qNtINO3QnSy/y4IGrUPgjMpmJa26a+JhduTRq+LMPu2wz+HxS1\n"
"Vf2q0H1IOJr/kimMFMaBRYErNclFa8VIFjwjz5reH5lJyptajGhruor6EK1qqhNc\n"
"zPSRY4TZH5QcjM46zui6l3tL9e32j6oUd4mAp4HhH0fws/pwawFYECI+M+7OCjgK\n"
"y+qSJ1ECgYEA1g+L0yN4i+uScs7EpsYJfaRP1PMtGnUsof64Pg6i9IKcuf5mi5Kp\n"
"aIgZdXAZIzsACH5XbfuC5Srs4565k/9XrHehLcuBzodulrzwmOUDbJAxIDw4uTUX\n"
"95W0uK9UqyGLyM8wNYs/EzhveSFL8fnFWzOAL/+HshQpKCBzedSU+G0CgYEAyolH\n"
"xws2mim7rSrYyRz1Vj02rLZuBUR7cPaHDxjjuuSUbI2nsDRsm6ZUCNlJtReHBkpH\n"
"eW5iClBGkksVsJJYJBmyDw6a3mnj0mfxBnh9zGaHQi0RCuOwmYlu2L/XVQXiMFKT\n"
"gffazuvysg7N/bz7CJjm8PRRx/cAxxFfAozdf/MCgYEAtBagLCHLaOvnaW9LQoOZ\n"
"uHpkL2PmrjumMSN7HbpyngLEmDXPT90zaR4XTRXiECGzBXJFW+IdXW+fnGANANXx\n"
"jMeYck6kBn0qLOcIA5moJ82nhtcjYa2pXEI2qKnZMaAnWen1RRbBGgqAvgelPQ5F\n"
"W1UYo0j3gHo1peynOff+3IECgYAsP53M4KhHOgLkrE28cnUvKCR/y0NyJyoI3fNX\n"
"2wo11KaQqMoP9wQbZVVKsZ4m0EMRnrzKzNDii/M/FuRgNTjIekyqeXhgSyYY29iO\n"
"n1hshaHbVVk51dDJWns7I3559tUZ1ZCgfnPxbR8Sw6VBYD4//JfH4LjVRSOIWkU1\n"
"m2zw/QKBgGE55o0xrCywF3wDUtFa6vgpsOfZu9IblsWktSbD/lk1YOqGpU//B0O4\n"
"GqihOQT7E9kDNusspFUGpZrE0T0B+GW1T9iTR0zd+lC+qExv2ggDJoH063DnH5OU\n"
"Qz2M8LESeFxf6ZlBxkcyrk6G1RAy7lUs9fHhfmpEJLVv4DTCuWDl\n"
"-----END RSA PRIVATE KEY-----\n";
const char kTestMessage[] =
"c8635a17ccc672c941d0cc287715411a0a0222613a04d47693a53eb7f32c"
"1ebae1f5d916a815b880426362c42f5f18f694a380756e0452018c70b3e4"
"f72ebb5269cb7233a3b8a2a1840e33ca9d473224d17ff91bae6b8d4ff2d1"
"8e5c89b5fc8a52c4f791c2063ab1a29ffd3372db483e4975c1c9c7408bf6"
"dfe5696e256e86b75313c501ab781175971b9411a73c444592afb1ec1667"
"2bfb935715ef5302f3bef712d2296be4f64ef2dc861f0611b06c35d0a5c2"
"5ff9f4a2563f265f109d2fa8f8165d7891b8a83c84520eaa284d49a4f76e"
"ac158204a5bdf018edd9401ae6593092ba97970be9a58b10720a235c9158"
"b9f235f9dda3de05990cef8c2fd04920a2a434bd5b6aa75767762d89b964"
"90e42524855a7eab49a8f82ac593e4df01990206d3fa98329aa50e31db89"
"b46b82ee0073851826f77aabb3779738a6f311b79f54d036a98dca4881ef"
"88c3cbfc86ac358c7bd107dc234d3772fc707df01637354dcb9270c7aefa"
"852dd21818ede33ab7154c32f25268b82f89b344e6469b81b6699df68c56"
"a6e61f1dd8f140f3be4edce755ceee8ee7868f45a17f8b4b4b0988f45815"
"1b43d07dcb0cd80b1ffa37b824e0abc25897cb41c242a3db845bedd37adf"
"88a13c0b2f0b158464b02f9fd97ad6e87b92c13cbeee5e69d183cc898c4e"
"0cfa9c59abde74a437d030cb966137ffe9abe6be71ed21ef751cdea73625"
"7cff9e378718f7d7e9c4d567cbec8e0afdfab0585b8ed0d5f8de159b6524"
"22c90737b44c84603ba1131f557604fe4e6b4d91e45363903b8db179cee0"
"a50f2ae73394973c8671df7a7b2eeb8341a3417727cfe43290a67ac3ad02"
"a52c3d1698c2c28a46268518aea66cecb40f43f50bb9cea4ed1d49ceb51d"
"9967fabccccc7237a36b6cecda5916234730d7b3ca3295519d77b7516824"
"10e8a238b6345e8d28132f60423a13fdf4b6a6cf272cef9a0833abb4b86d"
"9828af45442a390e241b2b8c3290671da4a163d7e55fea7828098c0749ca"
"ff65145dd6b4a6e4c65d214801bb8302d8914864e99c4d0b390b8126d4bc"
"0353e376e69aba56cf71b9943a47dcffa07c6a24986a077f69b7bec6bd9c"
"357e211875453bdadd9bfc4526f96c458e0052d27a903611c09a9c7b5f51"
"83daad078aec0e79ef991d102d4af492773f1509a265c5644cbab3253e34"
"3015e4305fffd17ce0261bcb232cfa0e1dcc71f83dc1aac490e526f6269f"
"606d0e0e556bb30b774c2208ed3771474be23f39b7fc21dcbf304a923d9c";
const char kTestDevCodeSigningCert[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIFDjCCA3agAwIBAgIPESIzRFVmd4iZqrvM3e7/MA0GCSqGSIb3DQEBCwUAMIGc\n"
"MQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2ly\n"
"a2xhbmQxDzANBgNVBAoMBkdvb2dsZTERMA8GA1UECwwIV2lkZXZpbmUxHjAcBgNV\n"
"BAMMFXdpZGV2aW5lLWRldi1jb2Rlc2lnbjEhMB8GCSqGSIb3DQEJARYSdGluc2tp\n"
"cEBnb29nbGUuY29tMB4XDTE3MTAwOTIwMjUwNloXDTI3MTAwNzIwMjUwNlowRTEL\n"
"MAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n"
"bmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n"
"ggEBAObsg/w+dJedH3x5KEsXdA/5sunWc8G+iZl0wMcngh2DiwmOSkKf68uCK/iW\n"
"T0a2XGgk13zl1HuKrjatgc7n6E1j/sqDZBGkr0q1wQgsdzm3qvGZoDG/+Z2U23WU\n"
"kX6ZcyIYUbpO2VtQELEl6DgNwoUi/9Yp+vCb6lsItpSZ1WRD9NhbWh1MxZxj1s18\n"
"OYcEzpEYg4/vHTVhocUR/1Rp9M9yn0nH1MUdtjhgBM3BmlRH7TA/nF111A4+GzMN\n"
"qyqfb0/6yXE64Ca3+fGg1hstfUUXkpmjjNPhYJ6QTgA3Xfrz04a4uwB+pSliF3SD\n"
"gip7O3rDyK0ES55lGpZ7B3s3TakCAwEAAaOCASEwggEdMB0GA1UdDgQWBBQ2jJme\n"
"0BuaGrhgFGJR2i59HR+DizCBuwYDVR0jBIGzMIGwoYGipIGfMIGcMQswCQYDVQQG\n"
"EwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQxDzAN\n"
"BgNVBAoMBkdvb2dsZTERMA8GA1UECwwIV2lkZXZpbmUxHjAcBgNVBAMMFXdpZGV2\n"
"aW5lLWRldi1jb2Rlc2lnbjEhMB8GCSqGSIb3DQEJARYSdGluc2tpcEBnb29nbGUu\n"
"Y29tggkAxfgvA4+s8VgwCQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwEwYDVR0lBAww\n"
"CgYIKwYBBQUHAwMwEQYKKwYBBAHWeQQBAgQDAQH/MA0GCSqGSIb3DQEBCwUAA4IB\n"
"gQAtan04ZGie7rRsKpb1F6t7xs48KE6cj6L99B5dgl37fZaZIQ3XE2vbmmmY5YTx\n"
"wofCkvOZMXHeQfJEK5GIK49TW/lAR+3kJUJzSh+N67f0X8O1pUl97IUFsbi6PTw/\n"
"mjhu197Kdy/OxPu/csOkEChuOfJLagRxXtIXeIyaeVOmn6fkFTOMOL2BusWOPuIs\n"
"9OmOQ+UHXpMuX4c2x9iO4NzZwwI/MgULLCrd/c73q199H+ttdPFoNs8+xGdodqA/\n"
"NFlHtMHMLMKVGpazAf+JW1/c3nb8L3S0nw4q7vPWi216RdZTfKfSIs/f/IW3CYJh\n"
"/IAuHOYvlD0GdSOFZHfhrnAvKhJ2iRu32psN87L9rL5EL22LT8csV/gLMc3SZ35n\n"
"/viuYcTDnMbe9S/Mge3mMJ9XHD5XBhN3hzmGDQEUdRS5MXrYdY32viPE7f+GAO9s\n"
"5MXS+h+FxQ6QUar2q1zHc/0Gr1hLzA6HYBmI0/AF8LsHs799XjrMKHkSBN6UQkC1\n"
"hRk=\n"
"-----END CERTIFICATE-----\n";
const char kDevCertFlagOid[] = "1.3.6.1.4.1.11129.4.1.2";
const bool kTestDevCodeSigningCertFlagValue = true;
TEST(X509CertTest, LoadCert) {
X509Cert test_cert;
EXPECT_EQ(util::OkStatus(),
test_cert.LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
EXPECT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
// TODO(user): Add more specific status checks to failure tests.
EXPECT_NE(util::OkStatus(), test_cert.LoadDer("bad cert"));
EXPECT_NE(util::OkStatus(), test_cert.LoadPem("bad cert"));
EXPECT_NE(util::OkStatus(), test_cert.LoadDer(""));
EXPECT_NE(util::OkStatus(), test_cert.LoadPem(""));
}
TEST(X509CertTest, VerifySignature) {
X509Cert test_cert;
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
std::string message(absl::HexStringToBytes(kTestMessage));
std::string signature;
ASSERT_EQ(util::OkStatus(), GenerateRsaSignatureSha256Pkcs1(
kTestCertPrivateKey, message, &signature));
std::unique_ptr<RsaPublicKey> pub_key(test_cert.GetRsaPublicKey());
ASSERT_TRUE(pub_key);
EXPECT_TRUE(pub_key->VerifySignatureSha256Pkcs7(message, signature));
EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7(message, "bad signature"));
EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7("bad digest", signature));
EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7(message, ""));
EXPECT_FALSE(pub_key->VerifySignatureSha256Pkcs7("", signature));
}
TEST(X509CertTest, GetSubjectNameField) {
X509Cert test_cert;
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
EXPECT_EQ(kTestPemCertSubjectField_C, test_cert.GetSubjectNameField("C"));
EXPECT_EQ(kTestPemCertSubjectField_CN, test_cert.GetSubjectNameField("CN"));
EXPECT_EQ("", test_cert.GetSubjectNameField("invalid_field"));
}
TEST(X509CertTest, GetSerialNumber) {
X509Cert test_cert;
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
EXPECT_EQ(kTestPemCertSerialNumber, test_cert.GetSerialNumber());
}
TEST(X509CertTest, CertChain) {
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(2, test_chain.GetNumCerts());
EXPECT_FALSE(test_chain.GetCert(0) == NULL);
EXPECT_FALSE(test_chain.GetCert(1) == NULL);
EXPECT_TRUE(test_chain.GetCert(2) == NULL);
}
TEST(X509CertTest, IsCaCertificate) {
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(2, test_chain.GetNumCerts());
EXPECT_FALSE(test_chain.GetCert(0)->IsCaCertificate());
EXPECT_TRUE(test_chain.GetCert(1)->IsCaCertificate());
}
TEST(X509CertTest, ChainVerificationPem) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(),
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
X509CA ca(ca_cert.release());
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert));
ASSERT_EQ(1, test_chain.GetNumCerts());
EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
}
TEST(X509CertTest, ChainVerificationPkcs7) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(),
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
X509CA ca(ca_cert.release());
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(),
test_chain.LoadPkcs7(absl::HexStringToBytes(kTestPk7CertChain)));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert));
ASSERT_EQ(1, test_chain.GetNumCerts());
EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
}
TEST(X509CertTest, BooleanExtension) {
std::unique_ptr<X509Cert> cert1(new X509Cert);
ASSERT_EQ(util::OkStatus(), cert1->LoadPem(kTestPemCert));
bool extension_value;
EXPECT_FALSE(cert1->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
std::unique_ptr<X509Cert> cert2(new X509Cert);
ASSERT_EQ(util::OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert));
ASSERT_TRUE(cert2->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
EXPECT_EQ(kTestDevCodeSigningCertFlagValue, extension_value);
}
} // namespace widevine