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

Unified Diff: net/cert/internal/verify_certificate_chain.cc

Issue 1410713005: NOT FOR REVIEW.... (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@extension_parsing
Patch Set: Created 5 years, 2 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: net/cert/internal/verify_certificate_chain.cc
diff --git a/net/cert/internal/verify_certificate_chain.cc b/net/cert/internal/verify_certificate_chain.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6a7f9701415b88e6950f148c3af4353f02fd8c47
--- /dev/null
+++ b/net/cert/internal/verify_certificate_chain.cc
@@ -0,0 +1,205 @@
+// Copyright 2015 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/verify_certificate_chain.h"
+
+#include <utility>
+
+#include "net/cert/internal/parse_certificate.h"
+#include "net/cert/internal/signature_algorithm.h"
+#include "net/cert/internal/signature_policy.h"
+#include "net/cert/internal/verify_signed_data.h"
+#include "net/der/input.h"
+
+namespace net {
+
+TrustedRoot::~TrustedRoot() {}
+
+TrustStore::TrustStore() {}
+TrustStore::~TrustStore() {}
+
+// TODO(eroman): Move into net/der (duplicated this from test_helpers.cc).
+der::Input InputFromString(const std::string* s) {
+ return der::Input(reinterpret_cast<const uint8_t*>(s->data()), s->size());
+}
+
+struct FullyParsedCert {
+ CertificateVersion version;
+ scoped_ptr<SignatureAlgorithm> signature_algorithm;
+ scoped_ptr<SignatureAlgorithm> tbs_signature_algorithm;
+ der::BitString signature_value;
+ der::Input tbs_tlv;
+
+ // TODO(eroman): Everywhere this is consumed should also consider
+ // issuerAltName.
+ der::Input issuer_tlv;
+ der::GeneralizedTime validity_not_before;
+ der::GeneralizedTime validity_not_after;
+
+ // TODO(eroman): Everywhere this is consumed should also consider
+ // subjectAltName.
+ der::Input subject_tlv;
+ der::Input spki_tlv;
+
+ // Extensions
+};
+
+WARN_UNUSED_RESULT bool FullyParseCertificate(const der::Input& cert_tlv,
+ FullyParsedCert* out) {
+ ParsedCertificate cert;
+ if (!ParseCertificate(cert_tlv, &cert))
+ return false;
+
+ out->tbs_tlv = cert.tbs_certificate_tlv;
+ out->signature_value = cert.signature_value;
+ out->signature_algorithm =
+ SignatureAlgorithm::CreateFromDer(cert.signature_algorithm_tlv);
+
+ if (!out->signature_algorithm)
+ return false;
+
+ ParsedTbsCertificate tbs;
+ if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs))
+ return false;
+
+ out->tbs_signature_algorithm =
+ SignatureAlgorithm::CreateFromDer(tbs.signature_algorithm_tlv);
+ if (!out->tbs_signature_algorithm)
+ return false;
+
+ out->issuer_tlv = tbs.issuer_tlv;
+ out->version = tbs.version;
+ out->spki_tlv = tbs.spki_tlv;
+ out->subject_tlv = tbs.subject_tlv;
+ out->validity_not_after = tbs.validity_not_after;
+ out->validity_not_before = tbs.validity_not_before;
+
+ // Note that the serial_number, issuer_unique_id and subject_unique_id are
+ // unused by verification at this time. Invalid encodings will be rejected
+ // while parsing, but other then that are unused.
+
+ return true;
+}
+
+WARN_UNUSED_RESULT bool IsValidAtTime(const der::GeneralizedTime& time,
+ const der::GeneralizedTime& not_before,
+ const der::GeneralizedTime& not_after) {
+ // TODO(eroman): IMPORTANT: Return true if time >= not_before && time <=
+ // not_after
+ return true;
+}
+
+WARN_UNUSED_RESULT bool NameMatches(const der::Input& name1,
+ const der::Input& name2) {
+ // TODO(eroman): Should account for normalization.
+ return name1.Equals(name2);
+}
+
+WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) {
+ return NameMatches(cert.subject_tlv, cert.issuer_tlv);
+}
+
+// Finds a mapping in the trust for matching |name|, or returns nullptr.
+//
+// TODO(eroman): This implementation is linear in the size of the trust store,
+// and also presumes that all names are unique (in practice could have multiple
+// SPKIs with the same name).
+WARN_UNUSED_RESULT const TrustedRoot* FindTrustedRootByName(
+ const TrustStore& trust_store,
+ const der::Input& name) {
+ for (const auto& root : trust_store.roots) {
+ if (NameMatches(name, InputFromString(&root.name)))
+ return &root;
+ }
+
+ return nullptr;
+}
+
+bool VerifyCertificateChain(const std::vector<der::Input>& certs_der,
+ const TrustStore& trust_store,
+ const SignaturePolicy* signature_policy,
+ const der::GeneralizedTime time) {
+ // An empty chain is invalid input. Fail early since the rest of the code
+ // assumes a non-empty chain.
+ if (certs_der.empty())
+ return false;
+
+ // Fully parse all of the certificates.
+ std::vector<FullyParsedCert> certs(certs_der.size());
+ for (size_t i = 0; i < certs_der.size(); ++i) {
+ if (!FullyParseCertificate(certs_der[i], &certs[i]))
+ return false;
+ }
+
+ // Walk the chain in the forward direction (from end entity towards trust
+ // anchor) and check all properties of the certificate except for name
+ // constraints.
+ size_t num_prev_self_issued_certs = 0;
+ for (size_t i = 0; i < certs_der.size(); ++i) {
+ const auto& cert = certs[i];
+
+ // Check for expiration.
+ if (!IsValidAtTime(time, cert.validity_not_before, cert.validity_not_after))
+ return false;
+
+ // Verify that the signature algorithm provided in tbsCertificate
+ // matches that provided in the certificate. This requirement comes from
+ // RFC 5280 section 4.1.1.2.
+ if (!cert.signature_algorithm->Equals(*cert.tbs_signature_algorithm))
+ return false;
+
+ // TODO: use is_self_issued
+
+ // TODO(eroman): the usage must allow signing if i > 0. Otherwise ....
+
+ // Verify that the previous certificate (i-1) was signed by the current one
+ // (i).
+ // Note that the signature for the final certificate in the chain is checked
+ // separately outside this loop.
+ if (i > 0) {
+ const auto& subordinate_cert = certs[i - 1];
+
+ // The issuer and subject must match.
+ if (!NameMatches(cert.subject_tlv, subordinate_cert.issuer_tlv))
+ return false;
+
+ // The digital signature must be correct.
+ if (!VerifySignedData(*subordinate_cert.signature_algorithm,
+ subordinate_cert.tbs_tlv,
+ subordinate_cert.signature_value, cert.spki_tlv,
+ signature_policy)) {
+ return false;
+ }
+
+ // The last certificate must chain up to a trust anchor.
+ if (i + 1 == certs.size()) {
+ const TrustedRoot* trusted_root =
+ FindTrustedRootByName(trust_store, cert.issuer_tlv);
+
+ if (!trusted_root)
+ return false;
+
+ if (!VerifySignedData(
+ *cert.signature_algorithm, cert.tbs_tlv, cert.signature_value,
+ InputFromString(&trusted_root->spki), signature_policy)) {
+ return false;
+ }
+ }
+ }
+
+ // Keep track of how many certificates were self-issued, since some of the
+ // rules are different for self-issued certificates.
+ bool is_self_issued = IsSelfIssued(cert);
+ if (is_self_issued)
+ num_prev_self_issued_certs++;
+ }
+
+ // TODO(eroman): Verify that no certificate in the chain violates the name
+ // constraints extension. This can be done by walking the chain in the
+ // reverse direction.
+
+ return true;
+}
+
+} // namespace net
« no previous file with comments | « net/cert/internal/verify_certificate_chain.h ('k') | net/cert/internal/verify_certificate_chain_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698