Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=224206719
This commit is contained in:
Ramji Chandramouli
2018-12-05 13:02:27 -08:00
committed by Fang Yu
parent df7566c0c1
commit 7f649cf826
49 changed files with 2697 additions and 2130 deletions

View File

@@ -6,23 +6,34 @@
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
// common_typos_disable. Successful / successfull.
#include "common/drm_root_certificate.h"
#include <memory>
#include "glog/logging.h"
#include "absl/memory/memory.h"
#include "absl/strings/escaping.h"
#include "openssl/sha.h"
#include "common/certificate_type.h"
#include "absl/synchronization/mutex.h"
#include "common/error_space.h"
#include "common/rsa_key.h"
#include "common/sha_util.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.
namespace {
const char kDevelopmentString[] = "dev"; // QA systems.
const char kProductionString[] = "prod"; // Production.
const char kTestingString[] = "test"; // Code development / unit tests.
const bool kUseCache = true;
// From common::TestDrmCertificates.
// TODO(user): common::test_certificates is a testonly target, consider
// how to use instead of dupliciating the test cert here.
static const unsigned char kTestRootCertificate[] = {
@@ -231,14 +242,145 @@ static const unsigned char kProdRootCertificate[] = {
0x1f, 0x17, 0x25, 0xce, 0x90, 0xb9, 0x6d, 0xcd, 0xc4, 0x46, 0xf5, 0xa3,
0x62, 0x13, 0x74, 0x02, 0xa7, 0x62, 0xa4, 0xfa, 0x55, 0xd9, 0xde, 0xcf,
0xa2, 0xe6, 0x80, 0x74, 0x55, 0x06, 0x49, 0xd5, 0x02, 0x0c};
} // namespace
util::Status DrmRootCertificate::Create(
const std::string& signed_drm_certificate,
std::unique_ptr<DrmRootCertificate>* cert) {
// Caches an individual signature for a certificate with a specific serial
// number (signer).
struct VerifiedCertSignature {
VerifiedCertSignature(const std::string& cert, const std::string& sig,
const std::string& signer_sn)
: signed_cert(cert), signature(sig), signer_serial(signer_sn) {}
std::string signed_cert;
std::string signature;
std::string signer_serial;
};
// Map of certificate serial number to its signature.
typedef std::map<std::string, VerifiedCertSignature> VerifiedCertSignatures;
class VerifiedCertSignatureCache {
public:
explicit VerifiedCertSignatureCache(const RsaKeyFactory* key_factory)
: key_factory_(key_factory) {}
// Checks cache, on miss, uses public key. If successful, adds to
// cache.
util::Status VerifySignature(const std::string& cert, const std::string& serial_number,
const std::string& signature,
const std::string& signer_public_key,
const std::string& signer_serial_number) {
{
VerifiedCertSignatures::iterator cached_signature;
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
cached_signature = signature_cache_.find(serial_number);
if (cached_signature != signature_cache_.end()) {
// TODO(user): Log which of the following three conditions occurs.
if ((cert != cached_signature->second.signed_cert) ||
(signature != cached_signature->second.signature) ||
(signer_serial_number != cached_signature->second.signer_serial)) {
// Cached signature mismatch.
return util::Status(error_space, INVALID_SIGNATURE,
"cached-signature-mismatch");
}
// Cached signature match.
return util::OkStatus();
}
}
// Cache miss. Verify signature.
std::unique_ptr<RsaPublicKey> signer_key(
key_factory_->CreateFromPkcs1PublicKey(signer_public_key));
if (!signer_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-public-key");
}
if (!signer_key->VerifySignature(cert, signature)) {
return util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
// Add signature to cache.
absl::WriterMutexLock write_lock(&signature_cache_mutex_);
signature_cache_.emplace(
serial_number,
VerifiedCertSignature(cert, signature, signer_serial_number));
return util::OkStatus();
}
private:
VerifiedCertSignatures signature_cache_ GUARDED_BY(&signature_cache_mutex_);
absl::Mutex signature_cache_mutex_;
const RsaKeyFactory* key_factory_;
};
util::Status DrmRootCertificate::CreateByType(
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
return Create(cert_type, absl::make_unique<RsaKeyFactory>(), cert);
}
std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
CertificateType cert_type, util::Status* status) {
CHECK(status);
std::unique_ptr<DrmRootCertificate> new_root_cert;
*status = CreateByType(cert_type, &new_root_cert);
return new_root_cert;
}
util::Status DrmRootCertificate::CreateByTypeString(
const std::string& cert_type_string, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
CertificateType cert_type;
if (cert_type_string == kDevelopmentString) {
cert_type = kCertificateTypeDevelopment;
} else if (cert_type_string == kProductionString) {
cert_type = kCertificateTypeProduction;
} else if (cert_type_string == kTestingString) {
cert_type = kCertificateTypeTesting;
} else {
return util::Status(
error_space, INVALID_PARAMETER,
absl::StrCat("invalid-certificate-type ", cert_type_string));
}
return CreateByType(cert_type, cert);
}
util::Status DrmRootCertificate::Create(
CertificateType cert_type, std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert) {
DCHECK(cert);
std::string serialized_certificate;
switch (cert_type) {
case kCertificateTypeProduction: {
serialized_certificate.assign(
kProdRootCertificate,
kProdRootCertificate + sizeof(kProdRootCertificate));
break;
}
case kCertificateTypeDevelopment: {
serialized_certificate.assign(
kDevRootCertificate,
kDevRootCertificate + sizeof(kDevRootCertificate));
break;
}
case kCertificateTypeTesting: {
serialized_certificate.assign(
kTestRootCertificate,
kTestRootCertificate + sizeof(kTestRootCertificate));
break;
}
default:
return util::Status(error_space, INVALID_PARAMETER,
"invalid-certificate-type");
}
SignedDrmCertificate signed_root_cert;
if (!signed_root_cert.ParseFromString(signed_drm_certificate)) {
if (!signed_root_cert.ParseFromString(serialized_certificate)) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"signed-root-cert-deserialize-fail");
}
@@ -259,8 +401,9 @@ util::Status DrmRootCertificate::Create(
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-certificate-signature");
}
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(root_cert.public_key()));
key_factory->CreateFromPkcs1PublicKey(root_cert.public_key()));
if (!public_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
@@ -270,51 +413,123 @@ util::Status DrmRootCertificate::Create(
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-certificate-signature");
}
cert->reset(new DrmRootCertificate(root_cert.public_key()));
cert->reset(new DrmRootCertificate(
cert_type, serialized_certificate, root_cert.serial_number(),
root_cert.public_key(), std::move(key_factory)));
return util::OkStatus();
}
util::Status DrmRootCertificate::CreateByType(
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
return Create(GetDrmRootCertificate(cert_type), cert);
DrmRootCertificate::DrmRootCertificate(
CertificateType type, const std::string& serialized_certificate,
const std::string& serial_number, const std::string& public_key,
std::unique_ptr<RsaKeyFactory> key_factory)
: type_(type),
serialized_certificate_(serialized_certificate),
serial_number_(serial_number),
public_key_(public_key),
key_factory_(std::move(key_factory)),
signature_cache_(new VerifiedCertSignatureCache(key_factory_.get())) {}
DrmRootCertificate::~DrmRootCertificate() {}
std::string DrmRootCertificate::GetDigest() const {
return absl::BytesToHexString(Sha256_Hash(serialized_certificate_));
}
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;
util::Status DrmRootCertificate::VerifyCertificate(
const std::string& serialized_certificate,
SignedDrmCertificate* signed_certificate,
DrmCertificate* certificate) const {
std::unique_ptr<SignedDrmCertificate> local_signed_certificate;
if (!signed_certificate) {
local_signed_certificate = absl::make_unique<SignedDrmCertificate>();
signed_certificate = local_signed_certificate.get();
}
return root_cert;
if (!signed_certificate->ParseFromString(serialized_certificate)) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate");
}
std::unique_ptr<DrmCertificate> local_certificate;
if (!certificate) {
local_certificate = absl::make_unique<DrmCertificate>();
certificate = local_certificate.get();
}
if (signed_certificate->drm_certificate().empty() ||
!certificate->ParseFromString(signed_certificate->drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate");
}
if (certificate->serial_number().empty()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-serial-number");
}
if (!certificate->has_creation_time_seconds()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-creation-time");
}
if (certificate->public_key().empty()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-public-key");
}
// Verify signature chain, but do not use cache for leaf certificates.
return VerifySignatures(*signed_certificate, certificate->serial_number(),
!kUseCache);
}
std::string DrmRootCertificate::GetDigest(CertificateType cert_type) {
std::string cert(GetDrmRootCertificate(cert_type));
if (cert.empty()) {
return std::string();
// Recursively verifies certificates with their signing certs or the root.
// use_cache should be false when initially called so that signatures do not
// cached leaf certificates not signed with the root certificate, such as for
// the case of device-unique device certificates.
// Signatures for root-signed certificates are always cached, even if they are
// leaf certificates. For example service, and provisioner certificates.
util::Status DrmRootCertificate::VerifySignatures(
const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number,
bool use_cache) const {
if (!signed_cert.has_signer()) {
// Always use cache for root-signed certificates.
return signature_cache_->VerifySignature(
signed_cert.drm_certificate(), cert_serial_number,
signed_cert.signature(), public_key(), serial_number_);
}
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);
DrmCertificate signer;
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate");
}
// Verify the signer before verifying signed_cert.
util::Status status =
VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache);
if (!status.ok()) {
return status;
}
if (use_cache) {
status = signature_cache_->VerifySignature(
signed_cert.drm_certificate(), cert_serial_number,
signed_cert.signature(), signer.public_key(), signer.serial_number());
if (!status.ok()) {
return status;
}
} else {
std::unique_ptr<RsaPublicKey> signer_public_key(
key_factory_->CreateFromPkcs1PublicKey(signer.public_key()));
if (!signer_public_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key");
}
if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(),
signed_cert.signature())) {
return util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
}
return util::OkStatus();
}
} // namespace widevine