Index: extensions/common/cast/cast_cert_validator.cc |
diff --git a/extensions/common/cast/cast_cert_validator.cc b/extensions/common/cast/cast_cert_validator.cc |
deleted file mode 100644 |
index b01a30054dc6ca5091f5c58f591565fd6339e694..0000000000000000000000000000000000000000 |
--- a/extensions/common/cast/cast_cert_validator.cc |
+++ /dev/null |
@@ -1,302 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "extensions/common/cast/cast_cert_validator.h" |
- |
-#include <stddef.h> |
-#include <stdint.h> |
- |
-#include <algorithm> |
-#include <memory> |
-#include <utility> |
- |
-#include "base/memory/ptr_util.h" |
-#include "base/memory/singleton.h" |
-#include "net/cert/internal/certificate_policies.h" |
-#include "net/cert/internal/extended_key_usage.h" |
-#include "net/cert/internal/parse_certificate.h" |
-#include "net/cert/internal/parse_name.h" |
-#include "net/cert/internal/signature_algorithm.h" |
-#include "net/cert/internal/signature_policy.h" |
-#include "net/cert/internal/verify_certificate_chain.h" |
-#include "net/cert/internal/verify_signed_data.h" |
-#include "net/der/input.h" |
- |
-namespace extensions { |
-namespace api { |
-namespace cast_crypto { |
-namespace { |
- |
-// ------------------------------------------------------------------------- |
-// Cast trust anchors. |
-// ------------------------------------------------------------------------- |
- |
-// There are two trusted roots for Cast certificate chains: |
-// |
-// (1) CN=Cast Root CA (kCastRootCaDer) |
-// (2) CN=Eureka Root CA (kEurekaRootCaDer) |
-// |
-// These constants are defined by the files included next: |
- |
-#include "extensions/common/cast/cast_root_ca_cert_der-inc.h" |
-#include "extensions/common/cast/eureka_root_ca_der-inc.h" |
- |
-// Singleton for the Cast trust store. |
-class CastTrustStore { |
- public: |
- static CastTrustStore* GetInstance() { |
- return base::Singleton<CastTrustStore, |
- base::LeakySingletonTraits<CastTrustStore>>::get(); |
- } |
- |
- static net::TrustStore& Get() { return GetInstance()->store_; } |
- |
- private: |
- friend struct base::DefaultSingletonTraits<CastTrustStore>; |
- |
- CastTrustStore() { |
- // Initialize the trust store with two root certificates. |
- CHECK(store_.AddTrustedCertificateWithoutCopying(kCastRootCaDer, |
- sizeof(kCastRootCaDer))); |
- CHECK(store_.AddTrustedCertificateWithoutCopying(kEurekaRootCaDer, |
- sizeof(kEurekaRootCaDer))); |
- } |
- |
- net::TrustStore store_; |
- DISALLOW_COPY_AND_ASSIGN(CastTrustStore); |
-}; |
- |
-using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; |
- |
-// Helper that looks up an extension by OID given a map of extensions. |
-bool GetExtensionValue(const ExtensionsMap& extensions, |
- const net::der::Input& oid, |
- net::der::Input* value) { |
- auto it = extensions.find(oid); |
- if (it == extensions.end()) |
- return false; |
- *value = it->second.value; |
- return true; |
-} |
- |
-// Returns the OID for the Audio-Only Cast policy |
-// (1.3.6.1.4.1.11129.2.5.2) in DER form. |
-net::der::Input AudioOnlyPolicyOid() { |
- static const uint8_t kAudioOnlyPolicy[] = {0x2B, 0x06, 0x01, 0x04, 0x01, |
- 0xD6, 0x79, 0x02, 0x05, 0x02}; |
- return net::der::Input(kAudioOnlyPolicy); |
-} |
- |
-// Cast certificates rely on RSASSA-PKCS#1 v1.5 with SHA-1 for signatures. |
-// |
-// The following signature policy specifies which signature algorithms (and key |
-// sizes) are acceptable. It is used when verifying a chain of certificates, as |
-// well as when verifying digital signature using the target certificate's |
-// SPKI. |
-// |
-// This particular policy allows for: |
-// * ECDSA, RSA-SSA, and RSA-PSS |
-// * Supported EC curves: P-256, P-384, P-521. |
-// * Hashes: All SHA hashes including SHA-1 (despite being known weak). |
-// * RSA keys must have a modulus at least 2048-bits long. |
-std::unique_ptr<net::SignaturePolicy> CreateCastSignaturePolicy() { |
- return base::WrapUnique(new net::SimpleSignaturePolicy(2048)); |
-} |
- |
-class CertVerificationContextImpl : public CertVerificationContext { |
- public: |
- // Save a copy of the passed in public key (DER) and common name (text). |
- CertVerificationContextImpl(const net::der::Input& spki, |
- const base::StringPiece& common_name) |
- : spki_(spki.AsString()), common_name_(common_name.as_string()) {} |
- |
- bool VerifySignatureOverData(const base::StringPiece& signature, |
- const base::StringPiece& data) const override { |
- // This code assumes the signature algorithm was RSASSA PKCS#1 v1.5 with |
- // SHA-1. |
- // TODO(eroman): Is it possible to use other hash algorithms? |
- auto signature_algorithm = |
- net::SignatureAlgorithm::CreateRsaPkcs1(net::DigestAlgorithm::Sha1); |
- |
- // Use the same policy as was used for verifying signatures in |
- // certificates. This will ensure for instance that the key used is at |
- // least 2048-bits long. |
- auto signature_policy = CreateCastSignaturePolicy(); |
- |
- return net::VerifySignedData( |
- *signature_algorithm, net::der::Input(data), |
- net::der::BitString(net::der::Input(signature), 0), |
- net::der::Input(&spki_), signature_policy.get()); |
- } |
- |
- std::string GetCommonName() const override { return common_name_; } |
- |
- private: |
- std::string spki_; |
- std::string common_name_; |
-}; |
- |
-// Helper that extracts the Common Name from a certificate's subject field. On |
-// success |common_name| contains the text for the attribute (unescaped, so |
-// will depend on the encoding used, but for Cast device certs it should |
-// be ASCII). |
-bool GetCommonNameFromSubject(const net::der::Input& subject_tlv, |
- std::string* common_name) { |
- net::RDNSequence rdn_sequence; |
- if (!net::ParseName(subject_tlv, &rdn_sequence)) |
- return false; |
- |
- for (const net::RelativeDistinguishedName& rdn : rdn_sequence) { |
- for (const auto& atv : rdn) { |
- if (atv.type == net::TypeCommonNameOid()) { |
- return atv.ValueAsStringUnsafe(common_name); |
- } |
- } |
- } |
- return false; |
-} |
- |
-// Returns true if the extended key usage list |ekus| contains client auth. |
-bool HasClientAuth(const std::vector<net::der::Input>& ekus) { |
- for (const auto& oid : ekus) { |
- if (oid == net::ClientAuth()) |
- return true; |
- } |
- return false; |
-} |
- |
-// Checks properties on the target certificate. |
-// |
-// * The Key Usage must include Digital Signature |
-// * THe Extended Key Usage must includ TLS Client Auth |
-// * May have the policy 1.3.6.1.4.1.11129.2.5.2 to indicate it |
-// is an audio-only device. |
-WARN_UNUSED_RESULT bool CheckTargetCertificate( |
- const net::der::Input& cert_der, |
- std::unique_ptr<CertVerificationContext>* context, |
- CastDeviceCertPolicy* policy) { |
- // TODO(eroman): Simplify this. The certificate chain verification |
- // function already parses this stuff, awkward to re-do it here. |
- |
- net::ParsedCertificate cert; |
- if (!net::ParseCertificate(cert_der, &cert)) |
- return false; |
- |
- net::ParsedTbsCertificate tbs; |
- if (!net::ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs)) |
- return false; |
- |
- // Get the extensions. |
- if (!tbs.has_extensions) |
- return false; |
- ExtensionsMap extensions; |
- if (!net::ParseExtensions(tbs.extensions_tlv, &extensions)) |
- return false; |
- |
- net::der::Input extension_value; |
- |
- // Get the Key Usage extension. |
- if (!GetExtensionValue(extensions, net::KeyUsageOid(), &extension_value)) |
- return false; |
- net::der::BitString key_usage; |
- if (!net::ParseKeyUsage(extension_value, &key_usage)) |
- return false; |
- |
- // Ensure Key Usage contains digitalSignature. |
- if (!key_usage.AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE)) |
- return false; |
- |
- // Get the Extended Key Usage extension. |
- if (!GetExtensionValue(extensions, net::ExtKeyUsageOid(), &extension_value)) |
- return false; |
- std::vector<net::der::Input> ekus; |
- if (!net::ParseEKUExtension(extension_value, &ekus)) |
- return false; |
- |
- // Ensure Extended Key Usage contains client auth. |
- if (!HasClientAuth(ekus)) |
- return false; |
- |
- // Check for an optional audio-only policy extension. |
- *policy = CastDeviceCertPolicy::NONE; |
- if (GetExtensionValue(extensions, net::CertificatePoliciesOid(), |
- &extension_value)) { |
- std::vector<net::der::Input> policies; |
- if (!net::ParseCertificatePoliciesExtension(extension_value, &policies)) |
- return false; |
- |
- // Look for an audio-only policy. Disregard any other policy found. |
- if (std::find(policies.begin(), policies.end(), AudioOnlyPolicyOid()) != |
- policies.end()) { |
- *policy = CastDeviceCertPolicy::AUDIO_ONLY; |
- } |
- } |
- |
- // Get the Common Name for the certificate. |
- std::string common_name; |
- if (!GetCommonNameFromSubject(tbs.subject_tlv, &common_name)) |
- return false; |
- |
- context->reset(new CertVerificationContextImpl(tbs.spki_tlv, common_name)); |
- return true; |
-} |
- |
- |
-// Converts a base::Time::Exploded to a net::der::GeneralizedTime. |
-net::der::GeneralizedTime ConvertExplodedTime( |
- const base::Time::Exploded& exploded) { |
- net::der::GeneralizedTime result; |
- result.year = exploded.year; |
- result.month = exploded.month; |
- result.day = exploded.day_of_month; |
- result.hours = exploded.hour; |
- result.minutes = exploded.minute; |
- result.seconds = exploded.second; |
- return result; |
-} |
- |
-} // namespace |
- |
-bool VerifyDeviceCert(const std::vector<std::string>& certs, |
- const base::Time::Exploded& time, |
- std::unique_ptr<CertVerificationContext>* context, |
- CastDeviceCertPolicy* policy) { |
- // The underlying verification function expects a sequence of |
- // der::Input, so wrap the data in it (cheap). |
- std::vector<net::der::Input> input_chain; |
- for (const auto& cert : certs) |
- input_chain.push_back(net::der::Input(&cert)); |
- |
- // Use a signature policy compatible with Cast's PKI. |
- auto signature_policy = CreateCastSignaturePolicy(); |
- |
- // Do RFC 5280 compatible certificate verification using the two Cast |
- // trust anchors and Cast signature policy. |
- if (!net::VerifyCertificateChain(input_chain, CastTrustStore::Get(), |
- signature_policy.get(), |
- ConvertExplodedTime(time))) { |
- return false; |
- } |
- |
- // Check properties of the leaf certificate (key usage, policy), and construct |
- // a CertVerificationContext that uses its public key. |
- return CheckTargetCertificate(input_chain[0], context, policy); |
-} |
- |
-std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest( |
- const base::StringPiece& spki) { |
- // Use a bogus CommonName, since this is just exposed for testing signature |
- // verification by unittests. |
- return base::WrapUnique( |
- new CertVerificationContextImpl(net::der::Input(spki), "CommonName")); |
-} |
- |
-bool AddTrustAnchorForTest(const uint8_t* data, size_t length) { |
- return CastTrustStore::Get().AddTrustedCertificateWithoutCopying(data, |
- length); |
-} |
- |
-} // namespace cast_crypto |
-} // namespace api |
-} // namespace extensions |