Replace hardcoded parameters
This commit is contained in:
@@ -16,9 +16,11 @@
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "common/ec_key.h"
|
||||
#include "common/error_space.h"
|
||||
#include "common/rsa_key.h"
|
||||
#include "common/sha_util.h"
|
||||
#include "common/signer_public_key.h"
|
||||
#include "protos/public/drm_certificate.pb.h"
|
||||
#include "protos/public/errors.pb.h"
|
||||
#include "protos/public/signed_drm_certificate.pb.h"
|
||||
@@ -33,6 +35,13 @@ const char kTestingString[] = "test"; // Code development / unit tests.
|
||||
|
||||
const bool kUseCache = true;
|
||||
|
||||
// Restrict the certificate chain size. All leaf DRM certificates must be a
|
||||
// DEVICE certificate. The DEVICE certificate must be signed by a MODEL
|
||||
// certificate. The MODEL certificate can be signed by Widevine or by a
|
||||
// PROVISIONER certificate which is signed by Widevine. Do not allow any
|
||||
// additional links.
|
||||
const uint32_t kMaxCertificateChainSize = 3;
|
||||
|
||||
// From common::TestDrmCertificates.
|
||||
// TODO(user): common::test_certificates is a testonly target, consider
|
||||
// how to use instead of dupliciating the test cert here.
|
||||
@@ -248,12 +257,17 @@ static const unsigned char kProdRootCertificate[] = {
|
||||
// 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) {}
|
||||
const std::string& signer_sn,
|
||||
const std::string& signer_pub_key)
|
||||
: signed_cert(cert),
|
||||
signature(sig),
|
||||
signer_serial(signer_sn),
|
||||
signer_public_key(signer_pub_key) {}
|
||||
|
||||
std::string signed_cert;
|
||||
std::string signature;
|
||||
std::string signer_serial;
|
||||
std::string signer_public_key;
|
||||
};
|
||||
|
||||
// Map of certificate serial number to its signature.
|
||||
@@ -265,50 +279,57 @@ class VerifiedCertSignatureCache {
|
||||
|
||||
// Checks cache, on miss, uses public key. If successful, adds to
|
||||
// cache.
|
||||
Status VerifySignature(const std::string& cert, const std::string& serial_number,
|
||||
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) {
|
||||
const DrmCertificate& signer) {
|
||||
{
|
||||
VerifiedCertSignatures::iterator cached_signature;
|
||||
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
|
||||
cached_signature = signature_cache_.find(serial_number);
|
||||
if (cached_signature != signature_cache_.end()) {
|
||||
// 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.
|
||||
if (cert != cached_signature->second.signed_cert) {
|
||||
return Status(error_space, INVALID_SIGNATURE, "cached-cert-mismatch");
|
||||
}
|
||||
if (signature != cached_signature->second.signature) {
|
||||
return Status(error_space, INVALID_SIGNATURE,
|
||||
"cached-signature-mismatch");
|
||||
}
|
||||
// Cached signature match.
|
||||
if (signer.serial_number() != cached_signature->second.signer_serial) {
|
||||
return Status(error_space, INVALID_SIGNATURE,
|
||||
"cached-serial-number-mismatch");
|
||||
}
|
||||
if (signer.public_key() != cached_signature->second.signer_public_key) {
|
||||
return Status(error_space, INVALID_SIGNATURE,
|
||||
"cached-signer-public-key-mismatch");
|
||||
}
|
||||
return OkStatus();
|
||||
}
|
||||
}
|
||||
|
||||
// Cache miss. Verify signature.
|
||||
std::unique_ptr<RsaPublicKey> signer_key(
|
||||
key_factory_->CreateFromPkcs1PublicKey(signer_public_key));
|
||||
if (!signer_key) {
|
||||
std::unique_ptr<SignerPublicKey> signer_public_key =
|
||||
SignerPublicKey::Create(signer.public_key(), signer.algorithm());
|
||||
if (signer_public_key == nullptr) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"invalid-signer-public-key");
|
||||
}
|
||||
if (!signer_key->VerifySignature(cert, signature)) {
|
||||
if (!signer_public_key->VerifySignature(cert, signature)) {
|
||||
return Status(error_space, INVALID_SIGNATURE,
|
||||
"cache-miss-invalid-signature");
|
||||
}
|
||||
|
||||
// Add signature to cache.
|
||||
absl::WriterMutexLock write_lock(&signature_cache_mutex_);
|
||||
signature_cache_.emplace(
|
||||
serial_number,
|
||||
VerifiedCertSignature(cert, signature, signer_serial_number));
|
||||
VerifiedCertSignature(cert, signature, signer.serial_number(),
|
||||
signer.public_key()));
|
||||
return OkStatus();
|
||||
}
|
||||
|
||||
private:
|
||||
VerifiedCertSignatures signature_cache_ GUARDED_BY(&signature_cache_mutex_);
|
||||
VerifiedCertSignatures signature_cache_
|
||||
ABSL_GUARDED_BY(&signature_cache_mutex_);
|
||||
absl::Mutex signature_cache_mutex_;
|
||||
const RsaKeyFactory* key_factory_;
|
||||
};
|
||||
@@ -330,7 +351,8 @@ std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
|
||||
}
|
||||
|
||||
Status DrmRootCertificate::CreateByTypeString(
|
||||
const std::string& cert_type_string, std::unique_ptr<DrmRootCertificate>* cert) {
|
||||
const std::string& cert_type_string,
|
||||
std::unique_ptr<DrmRootCertificate>* cert) {
|
||||
CHECK(cert);
|
||||
|
||||
CertificateType cert_type;
|
||||
@@ -400,9 +422,9 @@ Status DrmRootCertificate::Create(CertificateType cert_type,
|
||||
"missing-root-certificate-signature");
|
||||
}
|
||||
|
||||
std::unique_ptr<RsaPublicKey> public_key(
|
||||
key_factory->CreateFromPkcs1PublicKey(root_cert.public_key()));
|
||||
if (!public_key) {
|
||||
std::unique_ptr<SignerPublicKey> public_key =
|
||||
SignerPublicKey::Create(root_cert.public_key(), root_cert.algorithm());
|
||||
if (public_key == nullptr) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"invalid-root-public-key");
|
||||
}
|
||||
@@ -424,10 +446,11 @@ DrmRootCertificate::DrmRootCertificate(
|
||||
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())) {}
|
||||
signature_cache_(new VerifiedCertSignatureCache(key_factory_.get())) {
|
||||
root_cert_.set_public_key(public_key);
|
||||
root_cert_.set_serial_number(serial_number);
|
||||
}
|
||||
|
||||
DrmRootCertificate::~DrmRootCertificate() {}
|
||||
|
||||
@@ -472,8 +495,9 @@ Status DrmRootCertificate::VerifyCertificate(
|
||||
}
|
||||
|
||||
// Verify signature chain, but do not use cache for leaf certificates.
|
||||
uint32_t certs_in_chain = 0;
|
||||
return VerifySignatures(*signed_certificate, certificate->serial_number(),
|
||||
!kUseCache);
|
||||
!kUseCache, &certs_in_chain);
|
||||
}
|
||||
|
||||
// Recursively verifies certificates with their signing certs or the root.
|
||||
@@ -483,39 +507,48 @@ Status DrmRootCertificate::VerifyCertificate(
|
||||
// Signatures for root-signed certificates are always cached, even if they are
|
||||
// leaf certificates. For example service, and provisioner certificates.
|
||||
Status DrmRootCertificate::VerifySignatures(
|
||||
const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number,
|
||||
bool use_cache) const {
|
||||
const SignedDrmCertificate& signed_cert,
|
||||
const std::string& cert_serial_number, bool use_cache,
|
||||
uint32_t* certs_in_chain) const {
|
||||
CHECK(certs_in_chain);
|
||||
if (++(*certs_in_chain) > kMaxCertificateChainSize) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"certificate-chain-size-exceeded");
|
||||
}
|
||||
if (!signed_cert.has_signer()) {
|
||||
// Always use cache for root-signed certificates.
|
||||
return signature_cache_->VerifySignature(
|
||||
signed_cert.drm_certificate(), cert_serial_number,
|
||||
signed_cert.signature(), public_key(), serial_number_);
|
||||
signed_cert.signature(), root_cert_);
|
||||
}
|
||||
|
||||
DrmCertificate signer;
|
||||
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"invalid-signer-certificate");
|
||||
}
|
||||
|
||||
// Signer cannot be a device certificate.
|
||||
if (signer.type() == DrmCertificate::DEVICE) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"device-cert-must-be-leaf");
|
||||
}
|
||||
// Verify the signer before verifying signed_cert.
|
||||
Status status =
|
||||
VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache);
|
||||
Status status = VerifySignatures(signed_cert.signer(), signer.serial_number(),
|
||||
kUseCache, certs_in_chain);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (use_cache) {
|
||||
status = signature_cache_->VerifySignature(
|
||||
signed_cert.drm_certificate(), cert_serial_number,
|
||||
signed_cert.signature(), signer.public_key(), signer.serial_number());
|
||||
status = signature_cache_->VerifySignature(signed_cert.drm_certificate(),
|
||||
cert_serial_number,
|
||||
signed_cert.signature(), signer);
|
||||
if (!status.ok()) {
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
std::unique_ptr<RsaPublicKey> signer_public_key(
|
||||
key_factory_->CreateFromPkcs1PublicKey(signer.public_key()));
|
||||
if (!signer_public_key) {
|
||||
std::unique_ptr<SignerPublicKey> signer_public_key =
|
||||
SignerPublicKey::Create(signer.public_key(), signer.algorithm());
|
||||
if (signer_public_key == nullptr) {
|
||||
return Status(error_space, INVALID_DRM_CERTIFICATE,
|
||||
"invalid-leaf-signer-public-key");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user