Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1041)

Unified Diff: extensions/common/cast/cast_cert_validator.cc

Issue 1924323002: Move Cast certificate verification code from extensions to components. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Simplified OWNERS files Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
« no previous file with comments | « extensions/common/cast/cast_cert_validator.h ('k') | extensions/common/cast/cast_cert_validator_test_helpers.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698