Add new ParsedCertificate class, move TrustStore to own file.

This consolidates the certificate parsing from various places in
verify_certificate_chain.cc into a single class that pre-parses all the
important information.
The relevant places are all changed to use the new ParsedCertificate
class, and TrustStore is separated into its own file.

BUG=410574

Review-Url: https://codereview.chromium.org/1976433002
Cr-Commit-Position: refs/heads/master@{#397863}
diff --git a/components/cast_certificate/cast_cert_validator.cc b/components/cast_certificate/cast_cert_validator.cc
index b83ad54..5fb0ea1 100644
--- a/components/cast_certificate/cast_cert_validator.cc
+++ b/components/cast_certificate/cast_cert_validator.cc
@@ -17,8 +17,10 @@
 #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/parsed_certificate.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store.h"
 #include "net/cert/internal/verify_certificate_chain.h"
 #include "net/cert/internal/verify_signed_data.h"
 #include "net/der/input.h"
@@ -55,10 +57,18 @@
 
   CastTrustStore() {
     // Initialize the trust store with two root certificates.
-    CHECK(store_.AddTrustedCertificateWithoutCopying(kCastRootCaDer,
-                                                     sizeof(kCastRootCaDer)));
-    CHECK(store_.AddTrustedCertificateWithoutCopying(kEurekaRootCaDer,
-                                                     sizeof(kEurekaRootCaDer)));
+    scoped_refptr<net::ParsedCertificate> root =
+        net::ParsedCertificate::CreateFromCertificateData(
+            kCastRootCaDer, sizeof(kCastRootCaDer),
+            net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE);
+    CHECK(root);
+    store_.AddTrustedCertificate(std::move(root));
+
+    root = net::ParsedCertificate::CreateFromCertificateData(
+        kEurekaRootCaDer, sizeof(kEurekaRootCaDer),
+        net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE);
+    CHECK(root);
+    store_.AddTrustedCertificate(std::move(root));
   }
 
   net::TrustStore store_;
@@ -167,50 +177,27 @@
 // Checks properties on the target certificate.
 //
 //   * The Key Usage must include Digital Signature
-//   * THe Extended Key Usage must includ TLS Client Auth
+//   * The Extended Key Usage must include 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,
+    const net::ParsedCertificate* cert,
     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::der::Input tbs_certificate_tlv;
-  net::der::Input signature_algorithm_tlv;
-  net::der::BitString signature_value;
-  if (!net::ParseCertificate(cert_der, &tbs_certificate_tlv,
-                             &signature_algorithm_tlv, &signature_value))
-    return false;
-
-  net::ParsedTbsCertificate tbs;
-  if (!net::ParseTbsCertificate(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))
+  if (!cert->has_key_usage())
     return false;
 
   // Ensure Key Usage contains digitalSignature.
-  if (!key_usage.AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE))
+  if (!cert->key_usage().AssertsBit(net::KEY_USAGE_BIT_DIGITAL_SIGNATURE))
     return false;
 
   // Get the Extended Key Usage extension.
-  if (!GetExtensionValue(extensions, net::ExtKeyUsageOid(), &extension_value))
+  net::der::Input extension_value;
+  if (!GetExtensionValue(cert->unparsed_extensions(), net::ExtKeyUsageOid(),
+                         &extension_value)) {
     return false;
+  }
   std::vector<net::der::Input> ekus;
   if (!net::ParseEKUExtension(extension_value, &ekus))
     return false;
@@ -221,8 +208,8 @@
 
   // Check for an optional audio-only policy extension.
   *policy = CastDeviceCertPolicy::NONE;
-  if (GetExtensionValue(extensions, net::CertificatePoliciesOid(),
-                        &extension_value)) {
+  if (GetExtensionValue(cert->unparsed_extensions(),
+                        net::CertificatePoliciesOid(), &extension_value)) {
     std::vector<net::der::Input> policies;
     if (!net::ParseCertificatePoliciesExtension(extension_value, &policies))
       return false;
@@ -236,10 +223,11 @@
 
   // Get the Common Name for the certificate.
   std::string common_name;
-  if (!GetCommonNameFromSubject(tbs.subject_tlv, &common_name))
+  if (!GetCommonNameFromSubject(cert->tbs().subject_tlv, &common_name))
     return false;
 
-  context->reset(new CertVerificationContextImpl(tbs.spki_tlv, common_name));
+  context->reset(
+      new CertVerificationContextImpl(cert->tbs().spki_tlv, common_name));
   return true;
 }
 
@@ -256,6 +244,20 @@
   return result;
 }
 
+class ScopedCheckUnreferencedCerts {
+ public:
+  explicit ScopedCheckUnreferencedCerts(
+      std::vector<scoped_refptr<net::ParsedCertificate>>* certs)
+      : certs_(certs) {}
+  ~ScopedCheckUnreferencedCerts() {
+    for (const auto& cert : *certs_)
+      DCHECK(cert->HasOneRef());
+  }
+
+ private:
+  std::vector<scoped_refptr<net::ParsedCertificate>>* certs_;
+};
+
 }  // namespace
 
 bool VerifyDeviceCert(const std::vector<std::string>& certs,
@@ -263,10 +265,22 @@
                       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));
+  // ParsedCertificate.
+  std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
+  // Verify that nothing saves a reference to the input certs, since the backing
+  // data will go out of scope when the function finishes.
+  ScopedCheckUnreferencedCerts ref_checker(&input_chain);
+
+  for (const auto& cert_der : certs) {
+    // No reference to the ParsedCertificate is kept past the end of this
+    // function, so using EXTERNAL_REFERENCE here is safe.
+    if (!net::ParsedCertificate::CreateAndAddToVector(
+            reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
+            net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
+            &input_chain)) {
+      return false;
+    }
+  }
 
   // Use a signature policy compatible with Cast's PKI.
   auto signature_policy = CreateCastSignaturePolicy();
@@ -281,7 +295,7 @@
 
   // 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);
+  return CheckTargetCertificate(input_chain[0].get(), context, policy);
 }
 
 std::unique_ptr<CertVerificationContext> CertVerificationContextImplForTest(
@@ -293,8 +307,14 @@
 }
 
 bool AddTrustAnchorForTest(const uint8_t* data, size_t length) {
-  return CastTrustStore::Get().AddTrustedCertificateWithoutCopying(data,
-                                                                   length);
+  scoped_refptr<net::ParsedCertificate> anchor(
+      net::ParsedCertificate::CreateFromCertificateData(
+          data, length,
+          net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE));
+  if (!anchor)
+    return false;
+  CastTrustStore::Get().AddTrustedCertificate(std::move(anchor));
+  return true;
 }
 
 }  // namespace cast_certificate
diff --git a/net/cert/internal/parse_certificate.cc b/net/cert/internal/parse_certificate.cc
index 6bf3e3a..2a69926 100644
--- a/net/cert/internal/parse_certificate.cc
+++ b/net/cert/internal/parse_certificate.cc
@@ -508,6 +508,19 @@
   return true;
 }
 
+NET_EXPORT bool ConsumeExtension(
+    const der::Input& oid,
+    std::map<der::Input, ParsedExtension>* unconsumed_extensions,
+    ParsedExtension* extension) {
+  auto it = unconsumed_extensions->find(oid);
+  if (it == unconsumed_extensions->end())
+    return false;
+
+  *extension = it->second;
+  unconsumed_extensions->erase(it);
+  return true;
+}
+
 bool ParseBasicConstraints(const der::Input& basic_constraints_tlv,
                            ParsedBasicConstraints* out) {
   der::Parser parser(basic_constraints_tlv);
diff --git a/net/cert/internal/parse_certificate.h b/net/cert/internal/parse_certificate.h
index d3c4d97..1414d2e0 100644
--- a/net/cert/internal/parse_certificate.h
+++ b/net/cert/internal/parse_certificate.h
@@ -324,6 +324,14 @@
     const der::Input& extensions_tlv,
     std::map<der::Input, ParsedExtension>* extensions) WARN_UNUSED_RESULT;
 
+// Removes the extension with OID |oid| from |unconsumed_extensions| and fills
+// |extension| with the matching extension value. If there was no extension
+// matching |oid| then returns |false|.
+NET_EXPORT bool ConsumeExtension(
+    const der::Input& oid,
+    std::map<der::Input, ParsedExtension>* unconsumed_extensions,
+    ParsedExtension* extension) WARN_UNUSED_RESULT;
+
 struct ParsedBasicConstraints {
   bool is_ca = false;
   bool has_path_len = false;
diff --git a/net/cert/internal/parsed_certificate.cc b/net/cert/internal/parsed_certificate.cc
new file mode 100644
index 0000000..0f836b20
--- /dev/null
+++ b/net/cert/internal/parsed_certificate.cc
@@ -0,0 +1,158 @@
+// Copyright 2016 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 "net/cert/internal/parsed_certificate.h"
+
+#include "net/cert/internal/name_constraints.h"
+#include "net/cert/internal/signature_algorithm.h"
+#include "net/cert/internal/verify_name_match.h"
+#include "net/der/parser.h"
+
+namespace net {
+
+namespace {
+
+WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv,
+                                         der::Input* value) {
+  der::Parser parser(tlv);
+  return parser.ReadTag(der::kSequence, value) && !parser.HasMore();
+}
+
+}  // namespace
+
+ParsedCertificate::ParsedCertificate() {}
+ParsedCertificate::~ParsedCertificate() {}
+
+scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateData(
+    const uint8_t* data,
+    size_t length,
+    DataSource source) {
+  scoped_refptr<ParsedCertificate> result(new ParsedCertificate);
+
+  switch (source) {
+    case DataSource::INTERNAL_COPY:
+      result->cert_data_.assign(data, data + length);
+      result->cert_ =
+          der::Input(result->cert_data_.data(), result->cert_data_.size());
+      break;
+    case DataSource::EXTERNAL_REFERENCE:
+      result->cert_ = der::Input(data, length);
+      break;
+  }
+
+  if (!ParseCertificate(result->cert_, &result->tbs_certificate_tlv_,
+                        &result->signature_algorithm_tlv_,
+                        &result->signature_value_)) {
+    return nullptr;
+  }
+
+  if (!ParseTbsCertificate(result->tbs_certificate_tlv_, &result->tbs_))
+    return nullptr;
+
+  // Attempt to parse the signature algorithm contained in the Certificate.
+  // Do not give up on failure here, since SignatureAlgorithm::CreateFromDer
+  // will fail on valid but unsupported signature algorithms.
+  // TODO(mattm): should distinguish between unsupported algorithms and parsing
+  // errors.
+  result->signature_algorithm_ =
+      SignatureAlgorithm::CreateFromDer(result->signature_algorithm_tlv_);
+
+  der::Input subject_value;
+  if (!GetSequenceValue(result->tbs_.subject_tlv, &subject_value) ||
+      !NormalizeName(subject_value, &result->normalized_subject_)) {
+    return nullptr;
+  }
+  der::Input issuer_value;
+  if (!GetSequenceValue(result->tbs_.issuer_tlv, &issuer_value) ||
+      !NormalizeName(issuer_value, &result->normalized_issuer_)) {
+    return nullptr;
+  }
+
+  // Parse the standard X.509 extensions and remove them from
+  // |unparsed_extensions|.
+  if (result->tbs_.has_extensions) {
+    // ParseExtensions() ensures there are no duplicates, and maps the (unique)
+    // OID to the extension value.
+    if (!ParseExtensions(result->tbs_.extensions_tlv,
+                         &result->unparsed_extensions_)) {
+      return nullptr;
+    }
+
+    ParsedExtension extension;
+
+    // Basic constraints.
+    if (ConsumeExtension(BasicConstraintsOid(), &result->unparsed_extensions_,
+                         &extension)) {
+      result->has_basic_constraints_ = true;
+      if (!ParseBasicConstraints(extension.value, &result->basic_constraints_))
+        return nullptr;
+    }
+
+    // KeyUsage.
+    if (ConsumeExtension(KeyUsageOid(), &result->unparsed_extensions_,
+                         &extension)) {
+      result->has_key_usage_ = true;
+      if (!ParseKeyUsage(extension.value, &result->key_usage_))
+        return nullptr;
+    }
+
+    // Subject alternative name.
+    if (ConsumeExtension(SubjectAltNameOid(), &result->unparsed_extensions_,
+                         &result->subject_alt_names_extension_)) {
+      // RFC 5280 section 4.2.1.6:
+      // SubjectAltName ::= GeneralNames
+      result->subject_alt_names_ = GeneralNames::CreateFromDer(
+          result->subject_alt_names_extension_.value);
+      if (!result->subject_alt_names_)
+        return nullptr;
+      // RFC 5280 section 4.1.2.6:
+      // If subject naming information is present only in the subjectAltName
+      // extension (e.g., a key bound only to an email address or URI), then the
+      // subject name MUST be an empty sequence and the subjectAltName extension
+      // MUST be critical.
+      if (subject_value.Length() == 0 &&
+          !result->subject_alt_names_extension_.critical) {
+        return nullptr;
+      }
+    }
+
+    // Name constraints.
+    if (ConsumeExtension(NameConstraintsOid(), &result->unparsed_extensions_,
+                         &extension)) {
+      result->name_constraints_ =
+          NameConstraints::CreateFromDer(extension.value, extension.critical);
+      if (!result->name_constraints_)
+        return nullptr;
+    }
+
+    // NOTE: if additional extensions are consumed here, the verification code
+    // must be updated to process those extensions, since the
+    // VerifyNoUnconsumedCriticalExtensions uses the unparsed_extensions_
+    // variable to tell which extensions were processed.
+  }
+
+  return result;
+}
+
+scoped_refptr<ParsedCertificate> ParsedCertificate::CreateFromCertificateCopy(
+    const base::StringPiece& data) {
+  return ParsedCertificate::CreateFromCertificateData(
+      reinterpret_cast<const uint8_t*>(data.data()), data.size(),
+      DataSource::INTERNAL_COPY);
+}
+
+bool ParsedCertificate::CreateAndAddToVector(
+    const uint8_t* data,
+    size_t length,
+    DataSource source,
+    std::vector<scoped_refptr<ParsedCertificate>>* chain) {
+  scoped_refptr<ParsedCertificate> cert(
+      CreateFromCertificateData(data, length, source));
+  if (!cert)
+    return false;
+  chain->push_back(std::move(cert));
+  return true;
+}
+
+}  // namespace net
diff --git a/net/cert/internal/parsed_certificate.h b/net/cert/internal/parsed_certificate.h
new file mode 100644
index 0000000..7c9ae3c
--- /dev/null
+++ b/net/cert/internal/parsed_certificate.h
@@ -0,0 +1,213 @@
+// Copyright 2016 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.
+
+#ifndef NET_CERT_INTERNAL_PARSED_CERTIFICATE_H_
+#define NET_CERT_INTERNAL_PARSED_CERTIFICATE_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "net/base/net_export.h"
+#include "net/cert/internal/parse_certificate.h"
+#include "net/der/input.h"
+
+namespace net {
+
+struct GeneralNames;
+class NameConstraints;
+class SignatureAlgorithm;
+
+// Represents an X.509 certificate, including Certificate, TBSCertificate, and
+// standard extensions.
+// Creating a ParsedCertificate does not completely parse and validate the
+// certificate data. Presence of a member in this class implies the DER was
+// parsed successfully to that level, but does not imply the contents of that
+// member are valid, unless otherwise specified. See the documentation for each
+// member or the documentation of the type it returns.
+class NET_EXPORT ParsedCertificate
+    : public base::RefCountedThreadSafe<ParsedCertificate> {
+ public:
+  // Map from OID to ParsedExtension.
+  using ExtensionsMap = std::map<der::Input, ParsedExtension>;
+
+  // The certificate data for may either be owned internally (INTERNAL_COPY) or
+  // owned externally (EXTERNAL_REFERENCE). When it is owned internally the data
+  // is held by |cert_data_|
+  enum class DataSource {
+    INTERNAL_COPY,
+    EXTERNAL_REFERENCE,
+  };
+
+  // Creates a ParsedCertificate given a DER-encoded Certificate. Returns
+  // nullptr on failure. Failure will occur if the standard certificate fields
+  // and supported extensions cannot be parsed.
+  //
+  // The provided certificate data is either copied, or aliased, depending on
+  // the value of |source|. See the comments for DataSource for details.
+  static scoped_refptr<ParsedCertificate> CreateFromCertificateData(
+      const uint8_t* data,
+      size_t length,
+      DataSource source);
+
+  // Creates a ParsedCertificate and appends it to |chain|. Returns true if the
+  // certificate was successfully parsed and added. If false is return, |chain|
+  // is unmodified.
+  static bool CreateAndAddToVector(
+      const uint8_t* data,
+      size_t length,
+      DataSource source,
+      std::vector<scoped_refptr<net::ParsedCertificate>>* chain);
+
+  // Creates a ParsedCertificate, copying the data from |data|.
+  static scoped_refptr<ParsedCertificate> CreateFromCertificateCopy(
+      const base::StringPiece& data);
+
+  // Returns the DER-encoded certificate data for this cert.
+  const der::Input& der_cert() const { return cert_; }
+
+  // Accessors for raw fields of the Certificate.
+  const der::Input& tbs_certificate_tlv() const { return tbs_certificate_tlv_; }
+
+  const der::Input& signature_algorithm_tlv() const {
+    return signature_algorithm_tlv_;
+  }
+
+  const der::BitString& signature_value() const { return signature_value_; }
+
+  // Accessor for struct containing raw fields of the TbsCertificate.
+  const ParsedTbsCertificate& tbs() const { return tbs_; }
+
+  // Returns true if the signatureAlgorithm of the Certificate is supported and
+  // valid.
+  bool has_valid_supported_signature_algorithm() const {
+    return signature_algorithm_ != nullptr;
+  }
+
+  // Returns the signatureAlgorithm of the Certificate (not the tbsCertificate).
+  // Must not be called if has_valid_supported_signature_algorithm() is false.
+  const SignatureAlgorithm& signature_algorithm() const {
+    DCHECK(signature_algorithm_);
+    return *signature_algorithm_;
+  }
+
+  // Returns the DER-encoded normalized subject value (not including outer
+  // Sequence tag). This is gauranteed to be valid DER, though the contents of
+  // unhandled string types are treated as raw bytes.
+  der::Input normalized_subject() const {
+    return der::Input(&normalized_subject_);
+  }
+  // Returns the DER-encoded normalized issuer value (not including outer
+  // Sequence tag). This is gauranteed to be valid DER, though the contents of
+  // unhandled string types are treated as raw bytes.
+  der::Input normalized_issuer() const {
+    return der::Input(&normalized_issuer_);
+  }
+
+  // Returns true if the certificate has a BasicConstraints extension.
+  bool has_basic_constraints() const { return has_basic_constraints_; }
+
+  // Returns the ParsedBasicConstraints struct. Caller must check
+  // has_basic_constraints() before accessing this.
+  const ParsedBasicConstraints& basic_constraints() const {
+    DCHECK(has_basic_constraints_);
+    return basic_constraints_;
+  }
+
+  // Returns true if the certificate has a KeyUsage extension.
+  bool has_key_usage() const { return has_key_usage_; }
+
+  // Returns the KeyUsage BitString. Caller must check
+  // has_key_usage() before accessing this.
+  const der::BitString& key_usage() const {
+    DCHECK(has_key_usage_);
+    return key_usage_;
+  }
+
+  // Returns true if the certificate has a SubjectAltName extension.
+  bool has_subject_alt_names() const { return subject_alt_names_ != nullptr; }
+
+  // Returns the ParsedExtension struct for the SubjectAltName extension.
+  // If the cert did not have a SubjectAltName extension, this will be a
+  // default-initialized ParsedExtension struct.
+  const ParsedExtension& subject_alt_names_extension() const {
+    return subject_alt_names_extension_;
+  }
+
+  // Returns the GeneralNames class parsed from SubjectAltName extension, or
+  // nullptr if no SubjectAltName extension was present.
+  const GeneralNames* subject_alt_names() const {
+    return subject_alt_names_.get();
+  }
+
+  // Returns true if the certificate has a NameConstraints extension.
+  bool has_name_constraints() const { return name_constraints_ != nullptr; }
+
+  // Returns the parsed NameConstraints extension. Must not be called if
+  // has_name_constraints() is false.
+  const NameConstraints& name_constraints() const {
+    DCHECK(name_constraints_);
+    return *name_constraints_;
+  }
+
+  // Returns a map of unhandled extensions (excludes the ones above).
+  const ExtensionsMap& unparsed_extensions() const {
+    return unparsed_extensions_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<ParsedCertificate>;
+  ParsedCertificate();
+  ~ParsedCertificate();
+
+  // The backing store for the certificate data. This is only applicable when
+  // the ParsedCertificate was initialized using DataSource::INTERNAL_COPY.
+  std::vector<uint8_t> cert_data_;
+
+  // Note that the backing data for |cert_| (and its  may come either from
+  // |cert_data_| or some external buffer (depending on how the
+  // ParsedCertificate was created).
+
+  // Points to the raw certificate DER.
+  der::Input cert_;
+
+  der::Input tbs_certificate_tlv_;
+  der::Input signature_algorithm_tlv_;
+  der::BitString signature_value_;
+  ParsedTbsCertificate tbs_;
+
+  // The signatureAlgorithm from the Certificate.
+  std::unique_ptr<SignatureAlgorithm> signature_algorithm_;
+
+  // Normalized DER-encoded Subject (not including outer Sequence tag).
+  std::string normalized_subject_;
+  // Normalized DER-encoded Issuer (not including outer Sequence tag).
+  std::string normalized_issuer_;
+
+  // BasicConstraints extension.
+  bool has_basic_constraints_ = false;
+  ParsedBasicConstraints basic_constraints_;
+
+  // KeyUsage extension.
+  bool has_key_usage_ = false;
+  der::BitString key_usage_;
+
+  // Raw SubjectAltName extension.
+  ParsedExtension subject_alt_names_extension_;
+  // Parsed SubjectAltName extension.
+  std::unique_ptr<GeneralNames> subject_alt_names_;
+
+  // NameConstraints extension.
+  std::unique_ptr<NameConstraints> name_constraints_;
+
+  // The remaining extensions (excludes the standard ones above).
+  ExtensionsMap unparsed_extensions_;
+
+  DISALLOW_COPY_AND_ASSIGN(ParsedCertificate);
+};
+
+}  // namespace net
+
+#endif  // NET_CERT_INTERNAL_PARSED_CERTIFICATE_H_
diff --git a/net/cert/internal/trust_store.cc b/net/cert/internal/trust_store.cc
new file mode 100644
index 0000000..892698ba5
--- /dev/null
+++ b/net/cert/internal/trust_store.cc
@@ -0,0 +1,44 @@
+// Copyright 2016 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 "net/cert/internal/trust_store.h"
+
+#include "net/cert/internal/parsed_certificate.h"
+
+namespace net {
+
+TrustStore::TrustStore() {}
+TrustStore::~TrustStore() {}
+
+void TrustStore::Clear() {
+  anchors_.clear();
+}
+
+void TrustStore::AddTrustedCertificate(
+    scoped_refptr<ParsedCertificate> anchor) {
+  // TODO(mattm): should this check for duplicate certs?
+  anchors_.insert(std::make_pair(anchor->normalized_subject().AsStringPiece(),
+                                 std::move(anchor)));
+}
+
+void TrustStore::FindTrustAnchorsByNormalizedName(
+    const der::Input& normalized_name,
+    std::vector<scoped_refptr<ParsedCertificate>>* matches) const {
+  auto range = anchors_.equal_range(normalized_name.AsStringPiece());
+  for (auto it = range.first; it != range.second; ++it)
+    matches->push_back(it->second);
+}
+
+bool TrustStore::IsTrustedCertificate(const ParsedCertificate* cert) const {
+  auto range = anchors_.equal_range(cert->normalized_subject().AsStringPiece());
+  for (auto it = range.first; it != range.second; ++it) {
+    // First compare the ParsedCertificate pointers as an optimization, fall
+    // back to comparing full DER encoding.
+    if (it->second == cert || it->second->der_cert() == cert->der_cert())
+      return true;
+  }
+  return false;
+}
+
+}  // namespace net
diff --git a/net/cert/internal/trust_store.h b/net/cert/internal/trust_store.h
new file mode 100644
index 0000000..611af1c
--- /dev/null
+++ b/net/cert/internal/trust_store.h
@@ -0,0 +1,59 @@
+// Copyright 2016 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.
+
+#ifndef NET_CERT_INTERNAL_TRUST_STORE_H_
+#define NET_CERT_INTERNAL_TRUST_STORE_H_
+
+#include <unordered_map>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace der {
+class Input;
+}
+
+class ParsedCertificate;
+
+// A very simple implementation of a TrustStore, which contains a set of
+// trusted certificates.
+// TODO(mattm): convert this into an interface, provide implementations that
+// interface with OS trust store.
+class NET_EXPORT TrustStore {
+ public:
+  TrustStore();
+  ~TrustStore();
+
+  // Empties the trust store, resetting it to original state.
+  void Clear();
+
+  // Adds a trusted certificate to the store.
+  void AddTrustedCertificate(scoped_refptr<ParsedCertificate> anchor);
+
+  // Returns the trust anchors that match |name| in |*matches|, if any.
+  void FindTrustAnchorsByNormalizedName(
+      const der::Input& normalized_name,
+      std::vector<scoped_refptr<ParsedCertificate>>* matches) const;
+
+  // Returns true if |cert| matches a certificate in the TrustStore.
+  bool IsTrustedCertificate(const ParsedCertificate* cert) const
+      WARN_UNUSED_RESULT;
+
+ private:
+  // Multimap from normalized subject -> ParsedCertificate.
+  std::unordered_multimap<base::StringPiece,
+                          scoped_refptr<ParsedCertificate>,
+                          base::StringPieceHash>
+      anchors_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrustStore);
+};
+
+}  // namespace net
+
+#endif  // NET_CERT_INTERNAL_TRUST_STORE_H_
diff --git a/net/cert/internal/verify_certificate_chain.cc b/net/cert/internal/verify_certificate_chain.cc
index edfbfcb5..f6a45b24 100644
--- a/net/cert/internal/verify_certificate_chain.cc
+++ b/net/cert/internal/verify_certificate_chain.cc
@@ -9,9 +9,10 @@
 #include "base/logging.h"
 #include "net/cert/internal/name_constraints.h"
 #include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/internal/signature_policy.h"
-#include "net/cert/internal/verify_name_match.h"
+#include "net/cert/internal/trust_store.h"
 #include "net/cert/internal/verify_signed_data.h"
 #include "net/der/input.h"
 #include "net/der/parser.h"
@@ -20,172 +21,17 @@
 
 namespace {
 
-// Map from OID to ParsedExtension.
-using ExtensionsMap = std::map<der::Input, ParsedExtension>;
-
-// Describes all parsed properties of a certificate that are relevant for
-// certificate verification.
-struct FullyParsedCert {
-  der::Input tbs_certificate_tlv;
-  der::Input signature_algorithm_tlv;
-  der::BitString signature_value;
-  ParsedTbsCertificate tbs;
-
-  std::unique_ptr<SignatureAlgorithm> signature_algorithm;
-
-  // Standard extensions that were parsed.
-  bool has_basic_constraints = false;
-  ParsedBasicConstraints basic_constraints;
-
-  bool has_key_usage = false;
-  der::BitString key_usage;
-
-  std::unique_ptr<GeneralNames> subject_alt_names;
-
-  bool has_name_constraints = false;
-  ParsedExtension name_constraints_extension;
-
-  // The remaining extensions (excludes the standard ones above).
-  ExtensionsMap unconsumed_extensions;
-};
-
-// Removes the extension with OID |oid| from |unconsumed_extensions| and fills
-// |extension| with the matching extension value. If there was no extension
-// matching |oid| then returns |false|.
-WARN_UNUSED_RESULT bool ConsumeExtension(const der::Input& oid,
-                                         ExtensionsMap* unconsumed_extensions,
-                                         ParsedExtension* extension) {
-  auto it = unconsumed_extensions->find(oid);
-  if (it == unconsumed_extensions->end())
-    return false;
-
-  *extension = it->second;
-  unconsumed_extensions->erase(it);
-  return true;
-}
-
 // Returns true if the certificate does not contain any unconsumed _critical_
 // extensions.
 WARN_UNUSED_RESULT bool VerifyNoUnconsumedCriticalExtensions(
-    const FullyParsedCert& cert) {
-  for (const auto& entry : cert.unconsumed_extensions) {
+    const ParsedCertificate& cert) {
+  for (const auto& entry : cert.unparsed_extensions()) {
     if (entry.second.critical)
       return false;
   }
   return true;
 }
 
-WARN_UNUSED_RESULT bool GetSequenceValue(const der::Input& tlv,
-                                         der::Input* value) {
-  der::Parser parser(tlv);
-  return parser.ReadTag(der::kSequence, value) && !parser.HasMore();
-}
-
-// Parses an X.509 Certificate fully (including the TBSCertificate and
-// standard extensions), saving all the properties to |out_|.
-WARN_UNUSED_RESULT bool FullyParseCertificate(const der::Input& cert_tlv,
-                                              FullyParsedCert* out) {
-  // Parse the outer Certificate.
-  if (!ParseCertificate(cert_tlv, &out->tbs_certificate_tlv,
-                        &out->signature_algorithm_tlv, &out->signature_value))
-    return false;
-
-  // Parse the signature algorithm contained in the Certificate (there is
-  // another one in the TBSCertificate, which is checked later by
-  // VerifySignatureAlgorithmsMatch)
-  out->signature_algorithm =
-      SignatureAlgorithm::CreateFromDer(out->signature_algorithm_tlv);
-  if (!out->signature_algorithm)
-    return false;
-
-  // Parse the TBSCertificate.
-  if (!ParseTbsCertificate(out->tbs_certificate_tlv, &out->tbs))
-    return false;
-
-  // Reset state relating to extensions (which may not get overwritten). This is
-  // just a precaution, since in practice |out| will already be default
-  // initialize.
-  out->has_basic_constraints = false;
-  out->has_key_usage = false;
-  out->unconsumed_extensions.clear();
-  out->subject_alt_names.reset();
-  out->has_name_constraints = false;
-
-  // Parse the standard X.509 extensions and remove them from
-  // |unconsumed_extensions|.
-  if (out->tbs.has_extensions) {
-    // ParseExtensions() ensures there are no duplicates, and maps the (unique)
-    // OID to the extension value.
-    if (!ParseExtensions(out->tbs.extensions_tlv, &out->unconsumed_extensions))
-      return false;
-
-    ParsedExtension extension;
-
-    // Basic constraints.
-    if (ConsumeExtension(BasicConstraintsOid(), &out->unconsumed_extensions,
-                         &extension)) {
-      out->has_basic_constraints = true;
-      if (!ParseBasicConstraints(extension.value, &out->basic_constraints))
-        return false;
-    }
-
-    // KeyUsage.
-    if (ConsumeExtension(KeyUsageOid(), &out->unconsumed_extensions,
-                         &extension)) {
-      out->has_key_usage = true;
-      if (!ParseKeyUsage(extension.value, &out->key_usage))
-        return false;
-    }
-
-    // Subject alternative name.
-    if (ConsumeExtension(SubjectAltNameOid(), &out->unconsumed_extensions,
-                         &extension)) {
-      // RFC 5280 section 4.2.1.6:
-      // SubjectAltName ::= GeneralNames
-      out->subject_alt_names = GeneralNames::CreateFromDer(extension.value);
-      if (!out->subject_alt_names)
-        return false;
-      // RFC 5280 section 4.1.2.6:
-      // If subject naming information is present only in the subjectAltName
-      // extension (e.g., a key bound only to an email address or URI), then the
-      // subject name MUST be an empty sequence and the subjectAltName extension
-      // MUST be critical.
-      if (!extension.critical) {
-        der::Input subject_value;
-        if (!GetSequenceValue(out->tbs.subject_tlv, &subject_value))
-          return false;
-        if (subject_value.Length() == 0)
-          return false;
-      }
-    }
-
-    // Name constraints.
-    if (ConsumeExtension(NameConstraintsOid(), &out->unconsumed_extensions,
-                         &out->name_constraints_extension)) {
-      out->has_name_constraints = true;
-    }
-  }
-
-  return true;
-}
-
-// Returns true if |name1_tlv| matches |name2_tlv|. The two inputs must be
-// tag-length-value for RFC 5280's Name.
-WARN_UNUSED_RESULT bool NameMatches(const der::Input& name1_tlv,
-                                    const der::Input& name2_tlv) {
-  der::Input name1_value;
-  der::Input name2_value;
-
-  // Assume that the Name is an RDNSequence. VerifyNameMatch() expects the
-  // value from a SEQUENCE, so strip off the tag.
-  if (!GetSequenceValue(name1_tlv, &name1_value) ||
-      !GetSequenceValue(name2_tlv, &name2_value)) {
-    return false;
-  }
-
-  return VerifyNameMatch(name1_value, name2_value);
-}
-
 // Returns true if |cert| was self-issued. The definition of self-issuance
 // comes from RFC 5280 section 6.1:
 //
@@ -197,8 +43,8 @@
 //    support key rollover or changes in certificate policies.  These
 //    self-issued certificates are not counted when evaluating path length
 //    or name constraints.
-WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) {
-  return NameMatches(cert.tbs.subject_tlv, cert.tbs.issuer_tlv);
+WARN_UNUSED_RESULT bool IsSelfIssued(const ParsedCertificate& cert) {
+  return cert.normalized_subject() == cert.normalized_issuer();
 }
 
 // Returns true if |cert| is valid at time |time|.
@@ -208,10 +54,10 @@
 //
 //    The validity period for a certificate is the period of time from
 //    notBefore through notAfter, inclusive.
-WARN_UNUSED_RESULT bool VerifyTimeValidity(const FullyParsedCert& cert,
+WARN_UNUSED_RESULT bool VerifyTimeValidity(const ParsedCertificate& cert,
                                            const der::GeneralizedTime time) {
-  return !(time < cert.tbs.validity_not_before) &&
-         !(cert.tbs.validity_not_after < time);
+  return !(time < cert.tbs().validity_not_before) &&
+         !(cert.tbs().validity_not_after < time);
 }
 
 // Returns true if |signature_algorithm_tlv| is a valid algorithm encoding for
@@ -246,9 +92,9 @@
 // specifying RSA with SHA1 (different OIDs). This is special-cased for
 // compatibility sake.
 WARN_UNUSED_RESULT bool VerifySignatureAlgorithmsMatch(
-    const FullyParsedCert& cert) {
-  const der::Input& alg1_tlv = cert.signature_algorithm_tlv;
-  const der::Input& alg2_tlv = cert.tbs.signature_algorithm_tlv;
+    const ParsedCertificate& cert) {
+  const der::Input& alg1_tlv = cert.signature_algorithm_tlv();
+  const der::Input& alg2_tlv = cert.tbs().signature_algorithm_tlv;
 
   // Ensure that the two DER-encoded signature algorithms are byte-for-byte
   // equal, but make a compatibility concession for RSA with SHA1.
@@ -261,18 +107,17 @@
 //
 // |skip_issuer_checks| controls whether the function will skip:
 //   - Checking that |cert|'s signature using |working_spki|
-//   - Checkinging that |cert|'s issuer matches |working_issuer_name|
+//   - Checkinging that |cert|'s issuer matches |working_normalized_issuer_name|
 // This should be set to true only when verifying a trusted root certificate.
 WARN_UNUSED_RESULT bool BasicCertificateProcessing(
-    const FullyParsedCert& cert,
+    const ParsedCertificate& cert,
     bool is_target_cert,
     bool skip_issuer_checks,
     const SignaturePolicy* signature_policy,
     const der::GeneralizedTime& time,
     const der::Input& working_spki,
-    const der::Input& working_issuer_name,
-    const std::vector<std::unique_ptr<NameConstraints>>&
-        name_constraints_list) {
+    const der::Input& working_normalized_issuer_name,
+    const std::vector<const NameConstraints*>& name_constraints_list) {
   // Check that the signature algorithms in Certificate vs TBSCertificate
   // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by
   // sections 4.1.1.2 and 4.1.2.3.
@@ -282,9 +127,10 @@
   // Verify the digital signature using the previous certificate's key (RFC
   // 5280 section 6.1.3 step a.1).
   if (!skip_issuer_checks) {
-    if (!VerifySignedData(*cert.signature_algorithm, cert.tbs_certificate_tlv,
-                          cert.signature_value, working_spki,
-                          signature_policy)) {
+    if (!cert.has_valid_supported_signature_algorithm() ||
+        !VerifySignedData(cert.signature_algorithm(),
+                          cert.tbs_certificate_tlv(), cert.signature_value(),
+                          working_spki, signature_policy)) {
       return false;
     }
   }
@@ -300,7 +146,7 @@
   // Verify the certificate's issuer name matches the issuing certificate's
   // subject name. (RFC 5280 section 6.1.3 step a.4)
   if (!skip_issuer_checks) {
-    if (!NameMatches(cert.tbs.issuer_tlv, working_issuer_name))
+    if (cert.normalized_issuer() != working_normalized_issuer_name)
       return false;
   }
 
@@ -309,12 +155,11 @@
   // path, skip this step for certificate i.
   if (!name_constraints_list.empty() &&
       (!IsSelfIssued(cert) || is_target_cert)) {
-    der::Input subject_value;
-    if (!GetSequenceValue(cert.tbs.subject_tlv, &subject_value))
-      return false;
-    for (const auto& nc : name_constraints_list) {
-      if (!nc->IsPermittedCert(subject_value, cert.subject_alt_names.get()))
+    for (const NameConstraints* nc : name_constraints_list) {
+      if (!nc->IsPermittedCert(cert.normalized_subject(),
+                               cert.subject_alt_names())) {
         return false;
+      }
     }
   }
 
@@ -327,38 +172,31 @@
 // This function corresponds to RFC 5280 section 6.1.4's "Preparation for
 // Certificate i+1" procedure. |cert| is expected to be an intermediary.
 WARN_UNUSED_RESULT bool PrepareForNextCertificate(
-    const FullyParsedCert& cert,
+    const ParsedCertificate& cert,
     size_t* max_path_length_ptr,
     der::Input* working_spki,
-    der::Input* working_issuer_name,
-    std::vector<std::unique_ptr<NameConstraints>>* name_constraints_list) {
+    der::Input* working_normalized_issuer_name,
+    std::vector<const NameConstraints*>* name_constraints_list) {
   // TODO(eroman): Steps a-b are omitted, as policy constraints are not yet
   // implemented.
 
   // From RFC 5280 section 6.1.4 step c:
   //
-  //    Assign the certificate subject name to working_issuer_name.
-  *working_issuer_name = cert.tbs.subject_tlv;
+  //    Assign the certificate subject name to working_normalized_issuer_name.
+  *working_normalized_issuer_name = cert.normalized_subject();
 
   // From RFC 5280 section 6.1.4 step d:
   //
   //    Assign the certificate subjectPublicKey to working_public_key.
-  *working_spki = cert.tbs.spki_tlv;
+  *working_spki = cert.tbs().spki_tlv;
 
   // Note that steps e and f are omitted as they are handled by
   // the assignment to |working_spki| above. See the definition
   // of |working_spki|.
 
   // From RFC 5280 section 6.1.4 step g:
-  if (cert.has_name_constraints) {
-    std::unique_ptr<NameConstraints> name_constraints(
-        NameConstraints::CreateFromDer(
-            cert.name_constraints_extension.value,
-            cert.name_constraints_extension.critical));
-    if (!name_constraints)
-      return false;
-    name_constraints_list->push_back(std::move(name_constraints));
-  }
+  if (cert.has_name_constraints())
+    name_constraints_list->push_back(&cert.name_constraints());
 
   // TODO(eroman): Steps h-j are omitted as policy constraints are not yet
   // implemented.
@@ -376,7 +214,7 @@
   //
   // This code implicitly rejects non version 3 intermediaries, since they
   // can't contain a BasicConstraints extension.
-  if (!cert.has_basic_constraints || !cert.basic_constraints.is_ca)
+  if (!cert.has_basic_constraints() || !cert.basic_constraints().is_ca)
     return false;
 
   // From RFC 5280 section 6.1.4 step l:
@@ -395,17 +233,17 @@
   //    If pathLenConstraint is present in the certificate and is
   //    less than max_path_length, set max_path_length to the value
   //    of pathLenConstraint.
-  if (cert.basic_constraints.has_path_len &&
-      cert.basic_constraints.path_len < *max_path_length_ptr) {
-    *max_path_length_ptr = cert.basic_constraints.path_len;
+  if (cert.basic_constraints().has_path_len &&
+      cert.basic_constraints().path_len < *max_path_length_ptr) {
+    *max_path_length_ptr = cert.basic_constraints().path_len;
   }
 
   // From RFC 5280 section 6.1.4 step n:
   //
   //    If a key usage extension is present, verify that the
   //    keyCertSign bit is set.
-  if (cert.has_key_usage &&
-      !cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) {
+  if (cert.has_key_usage() &&
+      !cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN)) {
     return false;
   }
 
@@ -444,20 +282,21 @@
 // for compatibility reasons. Investigate if we need to similarly relax this
 // constraint.
 WARN_UNUSED_RESULT bool VerifyTargetCertHasConsistentCaBits(
-    const FullyParsedCert& cert) {
+    const ParsedCertificate& cert) {
   // Check if the certificate contains any property specific to CAs.
   bool has_ca_property =
-      (cert.has_basic_constraints &&
-       (cert.basic_constraints.is_ca || cert.basic_constraints.has_path_len)) ||
-      (cert.has_key_usage &&
-       cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+      (cert.has_basic_constraints() &&
+       (cert.basic_constraints().is_ca ||
+        cert.basic_constraints().has_path_len)) ||
+      (cert.has_key_usage() &&
+       cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
 
   // If it "looks" like a CA because it has a CA-only property, then check that
   // it sets ALL the properties expected of a CA.
   if (has_ca_property) {
-    return cert.has_basic_constraints && cert.basic_constraints.is_ca &&
-           (!cert.has_key_usage ||
-            cert.key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+    return cert.has_basic_constraints() && cert.basic_constraints().is_ca &&
+           (!cert.has_key_usage() ||
+            cert.key_usage().AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
   }
 
   return true;
@@ -465,7 +304,7 @@
 
 // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure".
 // It does processing for the final certificate (the target cert).
-WARN_UNUSED_RESULT bool WrapUp(const FullyParsedCert& cert) {
+WARN_UNUSED_RESULT bool WrapUp(const ParsedCertificate& cert) {
   // TODO(eroman): Steps a-b are omitted as policy constraints are not yet
   // implemented.
 
@@ -497,102 +336,6 @@
 
 }  // namespace
 
-TrustAnchor::TrustAnchor() {}
-TrustAnchor::~TrustAnchor() {}
-
-std::unique_ptr<TrustAnchor> TrustAnchor::CreateFromCertificateData(
-    const uint8_t* data,
-    size_t length,
-    DataSource source) {
-  std::unique_ptr<TrustAnchor> result(new TrustAnchor);
-
-  switch (source) {
-    case DataSource::INTERNAL_COPY:
-      result->cert_data_.assign(data, data + length);
-      result->cert_ =
-          der::Input(result->cert_data_.data(), result->cert_data_.size());
-      break;
-    case DataSource::EXTERNAL_REFERENCE:
-      result->cert_ = der::Input(data, length);
-      break;
-  }
-
-  // Parse the certificate to get its name.
-  der::Input tbs_certificate_tlv;
-  der::Input signature_algorithm_tlv;
-  der::BitString signature_value;
-  if (!ParseCertificate(result->cert(), &tbs_certificate_tlv,
-                        &signature_algorithm_tlv, &signature_value))
-    return nullptr;
-
-  ParsedTbsCertificate tbs;
-  if (!ParseTbsCertificate(tbs_certificate_tlv, &tbs))
-    return nullptr;
-
-  result->name_ = tbs.subject_tlv;
-
-  // TODO(eroman): If adding a self-signed certificate, check that its
-  // signature is correct? This check will not otherwise be done during
-  // verification.
-
-  return result;
-}
-
-bool TrustAnchor::MatchesName(const der::Input& name) const {
-  return NameMatches(name, name_);
-}
-
-TrustStore::TrustStore() {}
-TrustStore::~TrustStore() {}
-
-void TrustStore::Clear() {
-  anchors_.clear();
-}
-
-bool TrustStore::AddTrustedCertificate(const uint8_t* data, size_t length) {
-  return AddTrustedCertificate(data, length,
-                               TrustAnchor::DataSource::INTERNAL_COPY);
-}
-
-bool TrustStore::AddTrustedCertificate(const base::StringPiece& data) {
-  return AddTrustedCertificate(reinterpret_cast<const uint8_t*>(data.data()),
-                               data.size());
-}
-
-bool TrustStore::AddTrustedCertificateWithoutCopying(const uint8_t* data,
-                                                     size_t length) {
-  return AddTrustedCertificate(data, length,
-                               TrustAnchor::DataSource::EXTERNAL_REFERENCE);
-}
-
-const TrustAnchor* TrustStore::FindTrustAnchorByName(
-    const der::Input& name) const {
-  for (const auto& anchor : anchors_) {
-    if (anchor->MatchesName(name)) {
-      return anchor.get();
-    }
-  }
-  return nullptr;
-}
-
-bool TrustStore::IsTrustedCertificate(const der::Input& cert_der) const {
-  for (const auto& anchor : anchors_) {
-    if (anchor->cert() == cert_der)
-      return true;
-  }
-  return false;
-}
-
-bool TrustStore::AddTrustedCertificate(const uint8_t* data,
-                                       size_t length,
-                                       TrustAnchor::DataSource source) {
-  auto anchor = TrustAnchor::CreateFromCertificateData(data, length, source);
-  if (!anchor)
-    return false;
-  anchors_.push_back(std::move(anchor));
-  return true;
-}
-
 // TODO(eroman): Move this into existing anonymous namespace.
 namespace {
 
@@ -603,24 +346,24 @@
 // the chain. This root certificate is assumed to be trusted, and neither its
 // signature nor issuer name are verified. (It needn't be self-signed).
 bool VerifyCertificateChainAssumingTrustedRoot(
-    const std::vector<der::Input>& certs_der,
+    const std::vector<scoped_refptr<ParsedCertificate>>& certs,
     // The trust store is only used for assertions.
     const TrustStore& trust_store,
     const SignaturePolicy* signature_policy,
     const der::GeneralizedTime& time) {
   // An empty chain is necessarily invalid.
-  if (certs_der.empty())
+  if (certs.empty())
     return false;
 
   // IMPORTANT: the assumption being made is that the root certificate in
   // the given path is the trust anchor (and has already been verified as
   // such).
-  DCHECK(trust_store.IsTrustedCertificate(certs_der.back()));
+  DCHECK(trust_store.IsTrustedCertificate(certs.back().get()));
 
   // Will contain a NameConstraints for each previous cert in the chain which
   // had nameConstraints. This corresponds to the permitted_subtrees and
   // excluded_subtrees state variables from RFC 5280.
-  std::vector<std::unique_ptr<NameConstraints>> name_constraints_list;
+  std::vector<const NameConstraints*> name_constraints_list;
 
   // |working_spki| is an amalgamation of 3 separate variables from RFC 5280:
   //    * working_public_key
@@ -638,12 +381,12 @@
   //    signature of a certificate.
   der::Input working_spki;
 
-  // |working_issuer_name| corresponds with the same named variable in RFC 5280
-  // section 6.1.2:
+  // |working_normalized_issuer_name| is the normalized value of the
+  // working_issuer_name variable in RFC 5280 section 6.1.2:
   //
   //    working_issuer_name:  the issuer distinguished name expected
   //    in the next certificate in the chain.
-  der::Input working_issuer_name;
+  der::Input working_normalized_issuer_name;
 
   // |max_path_length| corresponds with the same named variable in RFC 5280
   // section 6.1.2:
@@ -653,7 +396,7 @@
   //    and may be reduced to the value in the path length constraint
   //    field within the basic constraints extension of a CA
   //    certificate.
-  size_t max_path_length = certs_der.size();
+  size_t max_path_length = certs.size();
 
   // Iterate over all the certificates in the reverse direction: starting from
   // the trust anchor and progressing towards the target certificate.
@@ -662,37 +405,34 @@
   //
   //   * i=0    :  Trust anchor.
   //   * i=N-1  :  Target certificate.
-  for (size_t i = 0; i < certs_der.size(); ++i) {
-    const size_t index_into_certs_der = certs_der.size() - i - 1;
+  for (size_t i = 0; i < certs.size(); ++i) {
+    const size_t index_into_certs = certs.size() - i - 1;
 
     // |is_target_cert| is true if the current certificate is the target
     // certificate being verified. The target certificate isn't necessarily an
     // end-entity certificate.
-    const bool is_target_cert = index_into_certs_der == 0;
+    const bool is_target_cert = index_into_certs == 0;
 
     // |is_trust_anchor| is true if the current certificate is the trust
     // anchor. This certificate is implicitly trusted.
     const bool is_trust_anchor = i == 0;
 
-    // Parse the current certificate into |cert|.
-    FullyParsedCert cert;
-    const der::Input& cert_der = certs_der[index_into_certs_der];
-    if (!FullyParseCertificate(cert_der, &cert))
-      return false;
+    const ParsedCertificate& cert = *certs[index_into_certs];
 
     // Per RFC 5280 section 6.1:
     //  * Do basic processing for each certificate
     //  * If it is the last certificate in the path (target certificate)
     //     - Then run "Wrap up"
     //     - Otherwise run "Prepare for Next cert"
-    if (!BasicCertificateProcessing(
-            cert, is_target_cert, is_trust_anchor, signature_policy, time,
-            working_spki, working_issuer_name, name_constraints_list)) {
+    if (!BasicCertificateProcessing(cert, is_target_cert, is_trust_anchor,
+                                    signature_policy, time, working_spki,
+                                    working_normalized_issuer_name,
+                                    name_constraints_list)) {
       return false;
     }
     if (!is_target_cert) {
       if (!PrepareForNextCertificate(cert, &max_path_length, &working_spki,
-                                     &working_issuer_name,
+                                     &working_normalized_issuer_name,
                                      &name_constraints_list)) {
         return false;
       }
@@ -717,56 +457,45 @@
 // Beyond this no other verification is done on the chain. The caller is
 // responsible for verifying the subsequent chain's correctness.
 WARN_UNUSED_RESULT bool BuildSimplePathToTrustAnchor(
-    const std::vector<der::Input>& certs_der,
     const TrustStore& trust_store,
-    std::vector<der::Input>* certs_der_trusted_root) {
-  // Copy the input chain.
-  *certs_der_trusted_root = certs_der;
-
-  if (certs_der.empty())
+    std::vector<scoped_refptr<ParsedCertificate>>* certs) {
+  if (certs->empty())
     return false;
 
   // Check if the current root certificate is trusted. If it is then no
   // extra work is needed.
-  if (trust_store.IsTrustedCertificate(certs_der_trusted_root->back()))
+  if (trust_store.IsTrustedCertificate(certs->back().get()))
     return true;
 
-  // Otherwise if it is not trusted, check whether its issuer is trusted. If
-  // so, make *that* trusted certificate the root. If the issuer is not in
-  // the trust store then give up and fail (this is not full path building).
-  der::Input tbs_certificate_tlv;
-  der::Input signature_algorithm_tlv;
-  der::BitString signature_value;
-  ParsedTbsCertificate tbs;
-  if (!ParseCertificate(certs_der.back(), &tbs_certificate_tlv,
-                        &signature_algorithm_tlv, &signature_value) ||
-      !ParseTbsCertificate(tbs_certificate_tlv, &tbs)) {
+  std::vector<scoped_refptr<ParsedCertificate>> trust_anchors;
+  trust_store.FindTrustAnchorsByNormalizedName(
+      certs->back()->normalized_issuer(), &trust_anchors);
+  if (trust_anchors.empty())
     return false;
-  }
-
-  auto trust_anchor = trust_store.FindTrustAnchorByName(tbs.issuer_tlv);
-  if (!trust_anchor)
-    return false;
-  certs_der_trusted_root->push_back(trust_anchor->cert());
+  // TODO(mattm): this only tries the first match, even if there are multiple.
+  certs->push_back(std::move(trust_anchors[0]));
   return true;
 }
 
 }  // namespace
 
-bool VerifyCertificateChain(const std::vector<der::Input>& certs_der,
-                            const TrustStore& trust_store,
-                            const SignaturePolicy* signature_policy,
-                            const der::GeneralizedTime& time) {
-  // Modify the certificate chain so that its root is a trusted certificate.
-  std::vector<der::Input> certs_der_trusted_root;
-  if (!BuildSimplePathToTrustAnchor(certs_der, trust_store,
-                                    &certs_der_trusted_root)) {
+bool VerifyCertificateChain(
+    const std::vector<scoped_refptr<ParsedCertificate>>& cert_chain,
+    const TrustStore& trust_store,
+    const SignaturePolicy* signature_policy,
+    const der::GeneralizedTime& time) {
+  if (cert_chain.empty())
     return false;
-  }
+
+  std::vector<scoped_refptr<ParsedCertificate>> full_chain = cert_chain;
+
+  // Modify the certificate chain so that its root is a trusted certificate.
+  if (!BuildSimplePathToTrustAnchor(trust_store, &full_chain))
+    return false;
 
   // Verify the chain.
-  return VerifyCertificateChainAssumingTrustedRoot(
-      certs_der_trusted_root, trust_store, signature_policy, time);
+  return VerifyCertificateChainAssumingTrustedRoot(full_chain, trust_store,
+                                                   signature_policy, time);
 }
 
 }  // namespace net
diff --git a/net/cert/internal/verify_certificate_chain.h b/net/cert/internal/verify_certificate_chain.h
index c2f83ebe..4d85eb6 100644
--- a/net/cert/internal/verify_certificate_chain.h
+++ b/net/cert/internal/verify_certificate_chain.h
@@ -5,15 +5,11 @@
 #ifndef NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_
 #define NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_
 
-#include <stdint.h>
-
-#include <memory>
-#include <string>
 #include <vector>
 
 #include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
 #include "net/base/net_export.h"
-#include "net/cert/internal/parse_certificate.h"
 #include "net/der/input.h"
 
 namespace net {
@@ -22,99 +18,9 @@
 struct GeneralizedTime;
 }
 
+class ParsedCertificate;
 class SignaturePolicy;
-
-// Represents a trust anchor (i.e. a trusted root certificate).
-class NET_EXPORT TrustAnchor {
- public:
-  // The certificate data for this trust anchor may either be owned internally
-  // (INTERNAL_COPY) or owned externally (EXTERNAL_REFERENCE). When it is
-  // owned internally the data is held by |cert_data_|
-  enum class DataSource {
-    INTERNAL_COPY,
-    EXTERNAL_REFERENCE,
-  };
-
-  TrustAnchor();
-  ~TrustAnchor();
-
-  // Creates a TrustAnchor given a DER-encoded certificate. Returns nullptr on
-  // failure. Failure will occur if the certificate data cannot be parsed to
-  // find a subject.
-  //
-  // The provided certificate data is either copied, or aliased, depending on
-  // the value of |source|. See the comments for DataSource for details.
-  static std::unique_ptr<TrustAnchor> CreateFromCertificateData(
-      const uint8_t* data,
-      size_t length,
-      DataSource source);
-
-  // Returns true if the trust anchor matches |name|. In other words, returns
-  // true if the certificate's subject matches |name|.
-  bool MatchesName(const der::Input& name) const;
-
-  // Returns the DER-encoded certificate data for this trust anchor.
-  const der::Input& cert() const { return cert_; }
-
- private:
-  // The backing store for the certificate data. This is only applicable when
-  // the trust anchor was initialized using DataSource::INTERNAL_COPY.
-  std::vector<uint8_t> cert_data_;
-
-  // Note that the backing data for |cert_| and |name_| may come either form
-  // |cert_data_| or some external buffer (depending on how the anchor was
-  // created).
-
-  // Points to the raw certificate DER.
-  der::Input cert_;
-
-  // Points to the subject TLV for the certificate.
-  der::Input name_;
-
-  DISALLOW_COPY_AND_ASSIGN(TrustAnchor);
-};
-
-// A very simple implementation of a TrustStore, which contains a set of
-// trusted certificates.
-class NET_EXPORT TrustStore {
- public:
-  TrustStore();
-  ~TrustStore();
-
-  // Empties the trust store, resetting it to original state.
-  void Clear();
-
-  // Adds a trusted certificate to the store. The trust store makes a copy of
-  // the provided certificate data.
-  bool AddTrustedCertificate(const uint8_t* data,
-                             size_t length) WARN_UNUSED_RESULT;
-  bool AddTrustedCertificate(const base::StringPiece& data) WARN_UNUSED_RESULT;
-
-  // This function is the same as AddTrustedCertificate() except the underlying
-  // data is not copied. The caller is responsible for ensuring that the data
-  // pointer remains alive and is not mutated for the lifetime of the
-  // TrustStore.
-  bool AddTrustedCertificateWithoutCopying(const uint8_t* data,
-                                           size_t length) WARN_UNUSED_RESULT;
-
-  // Returns the trust anchor that matches |name|, or nullptr if there is none.
-  // TODO(eroman): There may be multiple matches.
-  const TrustAnchor* FindTrustAnchorByName(const der::Input& name) const
-      WARN_UNUSED_RESULT;
-
-  // Returns true if |cert_der| matches a certificate in the TrustStore.
-  bool IsTrustedCertificate(const der::Input& cert_der) const
-      WARN_UNUSED_RESULT;
-
- private:
-  bool AddTrustedCertificate(const uint8_t* data,
-                             size_t length,
-                             TrustAnchor::DataSource source) WARN_UNUSED_RESULT;
-
-  std::vector<std::unique_ptr<TrustAnchor>> anchors_;
-
-  DISALLOW_COPY_AND_ASSIGN(TrustStore);
-};
+class TrustStore;
 
 // VerifyCertificateChain() verifies a certificate path (chain) based on the
 // rules in RFC 5280.
@@ -150,11 +56,11 @@
 // ---------
 //
 //   Returns true if the target certificate can be verified.
-NET_EXPORT bool VerifyCertificateChain(const std::vector<der::Input>& certs_der,
-                                       const TrustStore& trust_store,
-                                       const SignaturePolicy* signature_policy,
-                                       const der::GeneralizedTime& time)
-    WARN_UNUSED_RESULT;
+NET_EXPORT bool VerifyCertificateChain(
+    const std::vector<scoped_refptr<ParsedCertificate>>& cert_chain,
+    const TrustStore& trust_store,
+    const SignaturePolicy* signature_policy,
+    const der::GeneralizedTime& time) WARN_UNUSED_RESULT;
 
 }  // namespace net
 
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
index 60656370..1a2fc78 100644
--- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -4,8 +4,9 @@
 
 #include "net/cert/internal/verify_certificate_chain.h"
 
-#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/trust_store.h"
 #include "net/der/input.h"
 
 // Disable tests that require DSA signatures (DSA signatures are intentionally
@@ -53,13 +54,25 @@
     }
     // First entry in the PKITS chain is the trust anchor.
     TrustStore trust_store;
-    EXPECT_TRUE(trust_store.AddTrustedCertificate(cert_ders[0]));
+    scoped_refptr<ParsedCertificate> anchor(
+        ParsedCertificate::CreateFromCertificateCopy(cert_ders[0]));
+    EXPECT_TRUE(anchor);
+    if (anchor)
+      trust_store.AddTrustedCertificate(std::move(anchor));
 
     // PKITS lists chains from trust anchor to target, VerifyCertificateChain
     // takes them starting with the target and not including the trust anchor.
-    std::vector<der::Input> input_chain;
-    for (size_t i = cert_ders.size() - 1; i > 0; --i)
-      input_chain.push_back(der::Input(&cert_ders[i]));
+    std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
+    for (size_t i = cert_ders.size() - 1; i > 0; --i) {
+      if (!net::ParsedCertificate::CreateAndAddToVector(
+              reinterpret_cast<const uint8_t*>(cert_ders[i].data()),
+              cert_ders[i].size(),
+              net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE,
+              &input_chain)) {
+        ADD_FAILURE() << "cert " << i << " failed to parse";
+        return false;
+      }
+    }
 
     SimpleSignaturePolicy signature_policy(1024);
 
diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc
index a4443ca..11323f8 100644
--- a/net/cert/internal/verify_certificate_chain_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -10,9 +10,10 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/internal/signature_policy.h"
 #include "net/cert/internal/test_helpers.h"
+#include "net/cert/internal/trust_store.h"
 #include "net/cert/pem_tokenizer.h"
 #include "net/der/input.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -75,7 +76,10 @@
     if (block_type == kCertificateHeader) {
       chain->push_back(block_data);
     } else if (block_type == kTrustedCertificateHeader) {
-      ASSERT_TRUE(trust_store->AddTrustedCertificate(block_data));
+      scoped_refptr<ParsedCertificate> cert(
+          ParsedCertificate::CreateFromCertificateCopy(block_data));
+      ASSERT_TRUE(cert);
+      trust_store->AddTrustedCertificate(std::move(cert));
     } else if (block_type == kTimeHeader) {
       ASSERT_FALSE(has_time) << "Duplicate " << kTimeHeader;
       has_time = true;
@@ -101,9 +105,12 @@
 
   ReadTestFromFile(file_name, &chain, &trust_store, &time, &expected_result);
 
-  std::vector<der::Input> input_chain;
-  for (const auto& cert_str : chain)
-    input_chain.push_back(der::Input(&cert_str));
+  std::vector<scoped_refptr<net::ParsedCertificate>> input_chain;
+  for (const auto& cert_der : chain) {
+    ASSERT_TRUE(net::ParsedCertificate::CreateAndAddToVector(
+        reinterpret_cast<const uint8_t*>(cert_der.data()), cert_der.size(),
+        net::ParsedCertificate::DataSource::EXTERNAL_REFERENCE, &input_chain));
+  }
 
   SimpleSignaturePolicy signature_policy(1024);
 
@@ -225,7 +232,7 @@
 TEST(VerifyCertificateChainTest, EmptyChainIsInvalid) {
   TrustStore trust_store;
   der::GeneralizedTime time;
-  std::vector<der::Input> chain;
+  std::vector<scoped_refptr<ParsedCertificate>> chain;
   SimpleSignaturePolicy signature_policy(2048);
 
   ASSERT_FALSE(
diff --git a/net/net.gypi b/net/net.gypi
index 868c64c3..ea7bc65 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -98,10 +98,14 @@
       'cert/internal/parse_name.h',
       'cert/internal/parse_ocsp.cc',
       'cert/internal/parse_ocsp.h',
+      'cert/internal/parsed_certificate.cc',
+      'cert/internal/parsed_certificate.h',
       'cert/internal/signature_algorithm.cc',
       'cert/internal/signature_algorithm.h',
       'cert/internal/signature_policy.cc',
       'cert/internal/signature_policy.h',
+      'cert/internal/trust_store.cc',
+      'cert/internal/trust_store.h',
       'cert/internal/verify_certificate_chain.cc',
       'cert/internal/verify_certificate_chain.h',
       'cert/internal/verify_name_match.cc',