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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/internal/verify_certificate_chain.h"
6
7 #include <utility>
8
9 #include "net/cert/internal/parse_certificate.h"
10 #include "net/cert/internal/signature_algorithm.h"
11 #include "net/cert/internal/signature_policy.h"
12 #include "net/cert/internal/verify_signed_data.h"
13 #include "net/der/input.h"
14
15 namespace net {
16
17 TrustedRoot::~TrustedRoot() {}
18
19 TrustStore::TrustStore() {}
20 TrustStore::~TrustStore() {}
21
22 // TODO(eroman): Move into net/der (duplicated this from test_helpers.cc).
23 der::Input InputFromString(const std::string* s) {
24 return der::Input(reinterpret_cast<const uint8_t*>(s->data()), s->size());
25 }
26
27 struct FullyParsedCert {
28 CertificateVersion version;
29 scoped_ptr<SignatureAlgorithm> signature_algorithm;
30 scoped_ptr<SignatureAlgorithm> tbs_signature_algorithm;
31 der::BitString signature_value;
32 der::Input tbs_tlv;
33
34 // TODO(eroman): Everywhere this is consumed should also consider
35 // issuerAltName.
36 der::Input issuer_tlv;
37 der::GeneralizedTime validity_not_before;
38 der::GeneralizedTime validity_not_after;
39
40 // TODO(eroman): Everywhere this is consumed should also consider
41 // subjectAltName.
42 der::Input subject_tlv;
43 der::Input spki_tlv;
44
45 // Extensions
46 };
47
48 WARN_UNUSED_RESULT bool FullyParseCertificate(const der::Input& cert_tlv,
49 FullyParsedCert* out) {
50 ParsedCertificate cert;
51 if (!ParseCertificate(cert_tlv, &cert))
52 return false;
53
54 out->tbs_tlv = cert.tbs_certificate_tlv;
55 out->signature_value = cert.signature_value;
56 out->signature_algorithm =
57 SignatureAlgorithm::CreateFromDer(cert.signature_algorithm_tlv);
58
59 if (!out->signature_algorithm)
60 return false;
61
62 ParsedTbsCertificate tbs;
63 if (!ParseTbsCertificate(cert.tbs_certificate_tlv, &tbs))
64 return false;
65
66 out->tbs_signature_algorithm =
67 SignatureAlgorithm::CreateFromDer(tbs.signature_algorithm_tlv);
68 if (!out->tbs_signature_algorithm)
69 return false;
70
71 out->issuer_tlv = tbs.issuer_tlv;
72 out->version = tbs.version;
73 out->spki_tlv = tbs.spki_tlv;
74 out->subject_tlv = tbs.subject_tlv;
75 out->validity_not_after = tbs.validity_not_after;
76 out->validity_not_before = tbs.validity_not_before;
77
78 // Note that the serial_number, issuer_unique_id and subject_unique_id are
79 // unused by verification at this time. Invalid encodings will be rejected
80 // while parsing, but other then that are unused.
81
82 return true;
83 }
84
85 WARN_UNUSED_RESULT bool IsValidAtTime(const der::GeneralizedTime& time,
86 const der::GeneralizedTime& not_before,
87 const der::GeneralizedTime& not_after) {
88 // TODO(eroman): IMPORTANT: Return true if time >= not_before && time <=
89 // not_after
90 return true;
91 }
92
93 WARN_UNUSED_RESULT bool NameMatches(const der::Input& name1,
94 const der::Input& name2) {
95 // TODO(eroman): Should account for normalization.
96 return name1.Equals(name2);
97 }
98
99 WARN_UNUSED_RESULT bool IsSelfIssued(const FullyParsedCert& cert) {
100 return NameMatches(cert.subject_tlv, cert.issuer_tlv);
101 }
102
103 // Finds a mapping in the trust for matching |name|, or returns nullptr.
104 //
105 // TODO(eroman): This implementation is linear in the size of the trust store,
106 // and also presumes that all names are unique (in practice could have multiple
107 // SPKIs with the same name).
108 WARN_UNUSED_RESULT const TrustedRoot* FindTrustedRootByName(
109 const TrustStore& trust_store,
110 const der::Input& name) {
111 for (const auto& root : trust_store.roots) {
112 if (NameMatches(name, InputFromString(&root.name)))
113 return &root;
114 }
115
116 return nullptr;
117 }
118
119 bool VerifyCertificateChain(const std::vector<der::Input>& certs_der,
120 const TrustStore& trust_store,
121 const SignaturePolicy* signature_policy,
122 const der::GeneralizedTime time) {
123 // An empty chain is invalid input. Fail early since the rest of the code
124 // assumes a non-empty chain.
125 if (certs_der.empty())
126 return false;
127
128 // Fully parse all of the certificates.
129 std::vector<FullyParsedCert> certs(certs_der.size());
130 for (size_t i = 0; i < certs_der.size(); ++i) {
131 if (!FullyParseCertificate(certs_der[i], &certs[i]))
132 return false;
133 }
134
135 // Walk the chain in the forward direction (from end entity towards trust
136 // anchor) and check all properties of the certificate except for name
137 // constraints.
138 size_t num_prev_self_issued_certs = 0;
139 for (size_t i = 0; i < certs_der.size(); ++i) {
140 const auto& cert = certs[i];
141
142 // Check for expiration.
143 if (!IsValidAtTime(time, cert.validity_not_before, cert.validity_not_after))
144 return false;
145
146 // Verify that the signature algorithm provided in tbsCertificate
147 // matches that provided in the certificate. This requirement comes from
148 // RFC 5280 section 4.1.1.2.
149 if (!cert.signature_algorithm->Equals(*cert.tbs_signature_algorithm))
150 return false;
151
152 // TODO: use is_self_issued
153
154 // TODO(eroman): the usage must allow signing if i > 0. Otherwise ....
155
156 // Verify that the previous certificate (i-1) was signed by the current one
157 // (i).
158 // Note that the signature for the final certificate in the chain is checked
159 // separately outside this loop.
160 if (i > 0) {
161 const auto& subordinate_cert = certs[i - 1];
162
163 // The issuer and subject must match.
164 if (!NameMatches(cert.subject_tlv, subordinate_cert.issuer_tlv))
165 return false;
166
167 // The digital signature must be correct.
168 if (!VerifySignedData(*subordinate_cert.signature_algorithm,
169 subordinate_cert.tbs_tlv,
170 subordinate_cert.signature_value, cert.spki_tlv,
171 signature_policy)) {
172 return false;
173 }
174
175 // The last certificate must chain up to a trust anchor.
176 if (i + 1 == certs.size()) {
177 const TrustedRoot* trusted_root =
178 FindTrustedRootByName(trust_store, cert.issuer_tlv);
179
180 if (!trusted_root)
181 return false;
182
183 if (!VerifySignedData(
184 *cert.signature_algorithm, cert.tbs_tlv, cert.signature_value,
185 InputFromString(&trusted_root->spki), signature_policy)) {
186 return false;
187 }
188 }
189 }
190
191 // Keep track of how many certificates were self-issued, since some of the
192 // rules are different for self-issued certificates.
193 bool is_self_issued = IsSelfIssued(cert);
194 if (is_self_issued)
195 num_prev_self_issued_certs++;
196 }
197
198 // TODO(eroman): Verify that no certificate in the chain violates the name
199 // constraints extension. This can be done by walking the chain in the
200 // reverse direction.
201
202 return true;
203 }
204
205 } // namespace net
OLDNEW
« 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