OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert/internal/path_builder.h" | 5 #include "net/cert/internal/path_builder.h" |
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <unordered_set> | 8 #include <unordered_set> |
9 | 9 |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 if (!ParseName(cert->tbs().subject_tlv, &subject) || | 33 if (!ParseName(cert->tbs().subject_tlv, &subject) || |
34 !ConvertToRFC2253(subject, &subject_str)) | 34 !ConvertToRFC2253(subject, &subject_str)) |
35 subject_str = "???"; | 35 subject_str = "???"; |
36 if (!ParseName(cert->tbs().issuer_tlv, &issuer) || | 36 if (!ParseName(cert->tbs().issuer_tlv, &issuer) || |
37 !ConvertToRFC2253(issuer, &issuer_str)) | 37 !ConvertToRFC2253(issuer, &issuer_str)) |
38 issuer_str = "???"; | 38 issuer_str = "???"; |
39 | 39 |
40 return subject_str + "(" + issuer_str + ")"; | 40 return subject_str + "(" + issuer_str + ")"; |
41 } | 41 } |
42 | 42 |
43 // This structure contains either a ParsedCertificate or a TrustAnchor. It is | 43 // This structure describes a certificate and its trust level. Note that |cert| |
44 // used to describe the result of getting a certificate's issuer, which may | 44 // may be null to indicate an "empty" entry. |
45 // either be another certificate, or a trust anchor. | 45 struct IssuerEntry { |
46 struct CertificateOrTrustAnchor { | 46 scoped_refptr<ParsedCertificate> cert; |
47 CertificateOrTrustAnchor() {} | 47 CertificateTrust trust; |
| 48 }; |
48 | 49 |
49 explicit CertificateOrTrustAnchor(scoped_refptr<ParsedCertificate> cert) | 50 // Simple comparator of IssuerEntry that defines the order in which issuers |
50 : cert(std::move(cert)) {} | 51 // should be explored. It puts trust anchors ahead of unknown or distrusted |
| 52 // ones. |
| 53 struct IssuerEntryComparator { |
| 54 bool operator()(const IssuerEntry& issuer1, const IssuerEntry& issuer2) { |
| 55 return CertificateTrustToOrder(issuer1.trust) < |
| 56 CertificateTrustToOrder(issuer2.trust); |
| 57 } |
51 | 58 |
52 explicit CertificateOrTrustAnchor(scoped_refptr<TrustAnchor> anchor) | 59 static int CertificateTrustToOrder(const CertificateTrust& trust) { |
53 : anchor(std::move(anchor)) {} | 60 switch (trust.type) { |
| 61 case CertificateTrustType::TRUSTED_ANCHOR: |
| 62 case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS: |
| 63 return 1; |
| 64 case CertificateTrustType::UNSPECIFIED: |
| 65 return 2; |
| 66 case CertificateTrustType::DISTRUSTED: |
| 67 return 4; |
| 68 } |
54 | 69 |
55 bool IsTrustAnchor() const { return anchor.get() != nullptr; } | 70 NOTREACHED(); |
56 bool IsCertificate() const { return cert.get() != nullptr; } | 71 return 5; |
57 bool IsEmpty() const { return !IsTrustAnchor() && !IsCertificate(); } | 72 } |
58 | |
59 scoped_refptr<ParsedCertificate> cert; | |
60 scoped_refptr<TrustAnchor> anchor; | |
61 }; | 73 }; |
62 | 74 |
63 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| | 75 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| |
64 // which may be issuers of |cert|. | 76 // which may be issuers of |cert|. |
65 class CertIssuersIter { | 77 class CertIssuersIter { |
66 public: | 78 public: |
67 // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| | 79 // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| |
68 // must be valid for the lifetime of the CertIssuersIter. | 80 // must be valid for the lifetime of the CertIssuersIter. |
69 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, | 81 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, |
70 CertIssuerSources* cert_issuer_sources, | 82 CertIssuerSources* cert_issuer_sources, |
71 const TrustStore* trust_store); | 83 const TrustStore* trust_store); |
72 | 84 |
73 // Gets the next candidate issuer, or clears |*out| when all issuers have been | 85 // Gets the next candidate issuer, or clears |*out| when all issuers have been |
74 // exhausted. | 86 // exhausted. |
75 void GetNextIssuer(CertificateOrTrustAnchor* out); | 87 void GetNextIssuer(IssuerEntry* out); |
76 | 88 |
77 // Returns the |cert| for which issuers are being retrieved. | 89 // Returns the |cert| for which issuers are being retrieved. |
78 const ParsedCertificate* cert() const { return cert_.get(); } | 90 const ParsedCertificate* cert() const { return cert_.get(); } |
79 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } | 91 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
80 | 92 |
81 private: | 93 private: |
82 void AddIssuers(ParsedCertificateList issuers); | 94 void AddIssuers(ParsedCertificateList issuers); |
83 void DoAsyncIssuerQuery(); | 95 void DoAsyncIssuerQuery(); |
84 | 96 |
85 // Returns true if |issuers_| contains unconsumed certificates. | 97 // Returns true if |issuers_| contains unconsumed certificates. |
86 bool HasCurrentIssuer() const { return cur_issuer_ < issuers_.size(); } | 98 bool HasCurrentIssuer() const { return cur_issuer_ < issuers_.size(); } |
87 | 99 |
| 100 // Sorts the remaining entries in |issuers_| in the preferred order to |
| 101 // explore. Does not change the ordering for indices before cur_issuer_. |
| 102 void SortRemainingIssuers(); |
| 103 |
88 scoped_refptr<ParsedCertificate> cert_; | 104 scoped_refptr<ParsedCertificate> cert_; |
89 CertIssuerSources* cert_issuer_sources_; | 105 CertIssuerSources* cert_issuer_sources_; |
90 const TrustStore* trust_store_; | 106 const TrustStore* trust_store_; |
91 | 107 |
92 // The list of trust anchors that match the issuer name for |cert_|. | |
93 TrustAnchors anchors_; | |
94 // The index of the next trust anchor in |anchors_| to return. | |
95 size_t cur_anchor_ = 0; | |
96 | |
97 // The list of issuers for |cert_|. This is added to incrementally (first | 108 // The list of issuers for |cert_|. This is added to incrementally (first |
98 // synchronous results, then possibly multiple times as asynchronous results | 109 // synchronous results, then possibly multiple times as asynchronous results |
99 // arrive.) The issuers may be re-sorted each time new issuers are added, but | 110 // arrive.) The issuers may be re-sorted each time new issuers are added, but |
100 // only the results from |cur_| onwards should be sorted, since the earlier | 111 // only the results from |cur_| onwards should be sorted, since the earlier |
101 // results were already returned. | 112 // results were already returned. |
102 // Elements should not be removed from |issuers_| once added, since | 113 // Elements should not be removed from |issuers_| once added, since |
103 // |present_issuers_| will point to data owned by the certs. | 114 // |present_issuers_| will point to data owned by the certs. |
104 ParsedCertificateList issuers_; | 115 std::vector<IssuerEntry> issuers_; |
105 // The index of the next cert in |issuers_| to return. | 116 // The index of the next cert in |issuers_| to return. |
106 size_t cur_issuer_ = 0; | 117 size_t cur_issuer_ = 0; |
| 118 // Set to true whenever new issuers are appended at the end, to indicate the |
| 119 // ordering needs to be checked. |
| 120 bool issuers_needs_sort_ = false; |
107 | 121 |
108 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent | 122 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent |
109 // duplicates. This is based on the full DER of the cert to allow different | 123 // duplicates. This is based on the full DER of the cert to allow different |
110 // versions of the same certificate to be tried in different candidate paths. | 124 // versions of the same certificate to be tried in different candidate paths. |
111 // This points to data owned by |issuers_|. | 125 // This points to data owned by |issuers_|. |
112 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; | 126 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; |
113 | 127 |
114 // Tracks which requests have been made yet. | 128 // Tracks which requests have been made yet. |
115 bool did_initial_query_ = false; | 129 bool did_initial_query_ = false; |
116 bool did_async_issuer_query_ = false; | 130 bool did_async_issuer_query_ = false; |
117 // Index into pending_async_requests_ that is the next one to process. | 131 // Index into pending_async_requests_ that is the next one to process. |
118 size_t cur_async_request_ = 0; | 132 size_t cur_async_request_ = 0; |
119 // Owns the Request objects for any asynchronous requests so that they will be | 133 // Owns the Request objects for any asynchronous requests so that they will be |
120 // cancelled if CertIssuersIter is destroyed. | 134 // cancelled if CertIssuersIter is destroyed. |
121 std::vector<std::unique_ptr<CertIssuerSource::Request>> | 135 std::vector<std::unique_ptr<CertIssuerSource::Request>> |
122 pending_async_requests_; | 136 pending_async_requests_; |
123 | 137 |
124 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); | 138 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
125 }; | 139 }; |
126 | 140 |
127 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, | 141 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, |
128 CertIssuerSources* cert_issuer_sources, | 142 CertIssuerSources* cert_issuer_sources, |
129 const TrustStore* trust_store) | 143 const TrustStore* trust_store) |
130 : cert_(in_cert), | 144 : cert_(in_cert), |
131 cert_issuer_sources_(cert_issuer_sources), | 145 cert_issuer_sources_(cert_issuer_sources), |
132 trust_store_(trust_store) { | 146 trust_store_(trust_store) { |
133 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; | 147 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
134 } | 148 } |
135 | 149 |
136 void CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out) { | 150 void CertIssuersIter::GetNextIssuer(IssuerEntry* out) { |
137 if (!did_initial_query_) { | 151 if (!did_initial_query_) { |
138 did_initial_query_ = true; | 152 did_initial_query_ = true; |
139 trust_store_->FindTrustAnchorsForCert(cert_, &anchors_); | |
140 | |
141 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 153 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
142 ParsedCertificateList new_issuers; | 154 ParsedCertificateList new_issuers; |
143 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); | 155 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); |
144 AddIssuers(std::move(new_issuers)); | 156 AddIssuers(std::move(new_issuers)); |
145 } | 157 } |
146 DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() | |
147 << " sync issuers"; | |
148 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust | |
149 // anchor subject (or is a trust anchor), that should be sorted higher too. | |
150 // See big list of possible sorting hints in RFC 4158.) | |
151 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that | |
152 // is done) | |
153 } | 158 } |
154 | 159 |
155 // Return possible trust anchors first. | 160 // If there aren't any issuers, block until async results are ready. |
156 if (cur_anchor_ < anchors_.size()) { | |
157 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
158 << "): returning anchor " << cur_anchor_ << " of " | |
159 << anchors_.size(); | |
160 // Still have anchors that haven't been returned yet, return one of them. | |
161 *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); | |
162 return; | |
163 } | |
164 | |
165 // If there aren't any issuers left, block until async results are ready. | |
166 if (!HasCurrentIssuer()) { | 161 if (!HasCurrentIssuer()) { |
167 if (!did_async_issuer_query_) { | 162 if (!did_async_issuer_query_) { |
168 // Now issue request(s) for async ones (AIA, etc). | 163 // Now issue request(s) for async ones (AIA, etc). |
169 DoAsyncIssuerQuery(); | 164 DoAsyncIssuerQuery(); |
170 } | 165 } |
171 | 166 |
172 // TODO(eroman): Rather than blocking on the async requests in FIFO order, | 167 // TODO(eroman): Rather than blocking on the async requests in FIFO order, |
173 // consume in the order they become ready. | 168 // consume in the order they become ready. |
174 while (!HasCurrentIssuer() && | 169 while (!HasCurrentIssuer() && |
175 cur_async_request_ < pending_async_requests_.size()) { | 170 cur_async_request_ < pending_async_requests_.size()) { |
176 ParsedCertificateList new_issuers; | 171 ParsedCertificateList new_issuers; |
177 pending_async_requests_[cur_async_request_]->GetNext(&new_issuers); | 172 pending_async_requests_[cur_async_request_]->GetNext(&new_issuers); |
178 if (new_issuers.empty()) { | 173 if (new_issuers.empty()) { |
179 // Request is exhausted, no more results pending from that | 174 // Request is exhausted, no more results pending from that |
180 // CertIssuerSource. | 175 // CertIssuerSource. |
181 pending_async_requests_[cur_async_request_++].reset(); | 176 pending_async_requests_[cur_async_request_++].reset(); |
182 } else { | 177 } else { |
183 AddIssuers(std::move(new_issuers)); | 178 AddIssuers(std::move(new_issuers)); |
184 } | 179 } |
185 } | 180 } |
186 } | 181 } |
187 | 182 |
188 if (HasCurrentIssuer()) { | 183 if (HasCurrentIssuer()) { |
| 184 SortRemainingIssuers(); |
| 185 |
189 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 186 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
190 << "): returning issuer " << cur_issuer_ << " of " | 187 << "): returning issuer " << cur_issuer_ << " of " |
191 << issuers_.size(); | 188 << issuers_.size(); |
192 // Still have issuers that haven't been returned yet, return one of them. | 189 // Still have issuers that haven't been returned yet, return the highest |
193 // A reference to the returned issuer is retained, since |present_issuers_| | 190 // priority one (head of remaining list). A reference to the returned issuer |
194 // points to data owned by it. | 191 // is retained, since |present_issuers_| points to data owned by it. |
195 *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); | 192 *out = issuers_[cur_issuer_++]; |
196 return; | 193 return; |
197 } | 194 } |
198 | 195 |
199 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 196 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
200 << ") Reached the end of all available issuers."; | 197 << ") Reached the end of all available issuers."; |
201 // Reached the end of all available issuers. | 198 // Reached the end of all available issuers. |
202 *out = CertificateOrTrustAnchor(); | 199 *out = IssuerEntry(); |
203 } | 200 } |
204 | 201 |
205 void CertIssuersIter::AddIssuers(ParsedCertificateList new_issuers) { | 202 void CertIssuersIter::AddIssuers(ParsedCertificateList new_issuers) { |
206 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { | 203 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { |
207 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != | 204 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != |
208 present_issuers_.end()) | 205 present_issuers_.end()) |
209 continue; | 206 continue; |
210 present_issuers_.insert(issuer->der_cert().AsStringPiece()); | 207 present_issuers_.insert(issuer->der_cert().AsStringPiece()); |
211 issuers_.push_back(std::move(issuer)); | 208 |
| 209 // Look up the trust for this issuer. |
| 210 IssuerEntry entry; |
| 211 entry.cert = std::move(issuer); |
| 212 trust_store_->GetTrust(entry.cert, &entry.trust); |
| 213 |
| 214 issuers_.push_back(std::move(entry)); |
| 215 issuers_needs_sort_ = true; |
212 } | 216 } |
213 } | 217 } |
214 | 218 |
215 void CertIssuersIter::DoAsyncIssuerQuery() { | 219 void CertIssuersIter::DoAsyncIssuerQuery() { |
216 DCHECK(!did_async_issuer_query_); | 220 DCHECK(!did_async_issuer_query_); |
217 did_async_issuer_query_ = true; | 221 did_async_issuer_query_ = true; |
218 cur_async_request_ = 0; | 222 cur_async_request_ = 0; |
219 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 223 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
220 std::unique_ptr<CertIssuerSource::Request> request; | 224 std::unique_ptr<CertIssuerSource::Request> request; |
221 cert_issuer_source->AsyncGetIssuersOf(cert(), &request); | 225 cert_issuer_source->AsyncGetIssuersOf(cert(), &request); |
222 if (request) { | 226 if (request) { |
223 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) | 227 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) |
224 << ") pending..."; | 228 << ") pending..."; |
225 pending_async_requests_.push_back(std::move(request)); | 229 pending_async_requests_.push_back(std::move(request)); |
226 } | 230 } |
227 } | 231 } |
228 } | 232 } |
229 | 233 |
| 234 void CertIssuersIter::SortRemainingIssuers() { |
| 235 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust |
| 236 // anchor subject (or is a trust anchor), that should be sorted higher too. |
| 237 // See big list of possible sorting hints in RFC 4158.) |
| 238 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
| 239 // is done) |
| 240 if (!issuers_needs_sort_) |
| 241 return; |
| 242 |
| 243 std::stable_sort(issuers_.begin() + cur_issuer_, issuers_.end(), |
| 244 IssuerEntryComparator()); |
| 245 |
| 246 issuers_needs_sort_ = false; |
| 247 } |
| 248 |
230 // CertIssuerIterPath tracks which certs are present in the path and prevents | 249 // CertIssuerIterPath tracks which certs are present in the path and prevents |
231 // paths from being built which repeat any certs (including different versions | 250 // paths from being built which repeat any certs (including different versions |
232 // of the same cert, based on Subject+SubjectAltName+SPKI). | 251 // of the same cert, based on Subject+SubjectAltName+SPKI). |
233 class CertIssuerIterPath { | 252 class CertIssuerIterPath { |
234 public: | 253 public: |
235 // Returns true if |cert| is already present in the path. | 254 // Returns true if |cert| is already present in the path. |
236 bool IsPresent(const ParsedCertificate* cert) const { | 255 bool IsPresent(const ParsedCertificate* cert) const { |
237 return present_certs_.find(GetKey(cert)) != present_certs_.end(); | 256 return present_certs_.find(GetKey(cert)) != present_certs_.end(); |
238 } | 257 } |
239 | 258 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 // TODO(mattm): use unordered_set. Requires making a hash function for Key. | 317 // TODO(mattm): use unordered_set. Requires making a hash function for Key. |
299 std::set<Key> present_certs_; | 318 std::set<Key> present_certs_; |
300 }; | 319 }; |
301 | 320 |
302 } // namespace | 321 } // namespace |
303 | 322 |
304 CertPath::CertPath() = default; | 323 CertPath::CertPath() = default; |
305 CertPath::~CertPath() = default; | 324 CertPath::~CertPath() = default; |
306 | 325 |
307 void CertPath::Clear() { | 326 void CertPath::Clear() { |
308 trust_anchor = nullptr; | 327 last_cert_trust = CertificateTrust::ForUnspecified(); |
309 certs.clear(); | 328 certs.clear(); |
310 } | 329 } |
311 | 330 |
312 bool CertPath::IsEmpty() const { | 331 bool CertPath::IsEmpty() const { |
313 return certs.empty(); | 332 return certs.empty(); |
314 } | 333 } |
315 | 334 |
| 335 const ParsedCertificate* CertPath::GetTrustedCert() const { |
| 336 if (certs.empty()) |
| 337 return nullptr; |
| 338 |
| 339 switch (last_cert_trust.type) { |
| 340 case CertificateTrustType::TRUSTED_ANCHOR: |
| 341 case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS: |
| 342 return certs.back().get(); |
| 343 case CertificateTrustType::UNSPECIFIED: |
| 344 case CertificateTrustType::DISTRUSTED: |
| 345 return nullptr; |
| 346 } |
| 347 |
| 348 NOTREACHED(); |
| 349 return nullptr; |
| 350 } |
| 351 |
316 // CertPathIter generates possible paths from |cert| to a trust anchor in | 352 // CertPathIter generates possible paths from |cert| to a trust anchor in |
317 // |trust_store|, using intermediates from the |cert_issuer_source| objects if | 353 // |trust_store|, using intermediates from the |cert_issuer_source| objects if |
318 // necessary. | 354 // necessary. |
319 class CertPathIter { | 355 class CertPathIter { |
320 public: | 356 public: |
321 CertPathIter(scoped_refptr<ParsedCertificate> cert, | 357 CertPathIter(scoped_refptr<ParsedCertificate> cert, |
322 const TrustStore* trust_store); | 358 const TrustStore* trust_store); |
323 | 359 |
324 // Adds a CertIssuerSource to provide intermediates for use in path building. | 360 // Adds a CertIssuerSource to provide intermediates for use in path building. |
325 // The |*cert_issuer_source| must remain valid for the lifetime of the | 361 // The |*cert_issuer_source| must remain valid for the lifetime of the |
(...skipping 12 matching lines...) Expand all Loading... |
338 STATE_RETURN_A_PATH, | 374 STATE_RETURN_A_PATH, |
339 STATE_BACKTRACK, | 375 STATE_BACKTRACK, |
340 }; | 376 }; |
341 | 377 |
342 void DoGetNextIssuer(); | 378 void DoGetNextIssuer(); |
343 void DoGetNextIssuerComplete(); | 379 void DoGetNextIssuerComplete(); |
344 void DoBackTrack(); | 380 void DoBackTrack(); |
345 | 381 |
346 // Stores the next candidate issuer, until it is used during the | 382 // Stores the next candidate issuer, until it is used during the |
347 // STATE_GET_NEXT_ISSUER_COMPLETE step. | 383 // STATE_GET_NEXT_ISSUER_COMPLETE step. |
348 CertificateOrTrustAnchor next_issuer_; | 384 IssuerEntry next_issuer_; |
349 // The current path being explored, made up of CertIssuerIters. Each node | 385 // The current path being explored, made up of CertIssuerIters. Each node |
350 // keeps track of the state of searching for issuers of that cert, so that | 386 // keeps track of the state of searching for issuers of that cert, so that |
351 // when backtracking it can resume the search where it left off. | 387 // when backtracking it can resume the search where it left off. |
352 CertIssuerIterPath cur_path_; | 388 CertIssuerIterPath cur_path_; |
353 // The CertIssuerSources for retrieving candidate issuers. | 389 // The CertIssuerSources for retrieving candidate issuers. |
354 CertIssuerSources cert_issuer_sources_; | 390 CertIssuerSources cert_issuer_sources_; |
355 // The TrustStore for checking if a path ends in a trust anchor. | 391 // The TrustStore for checking if a path ends in a trust anchor. |
356 const TrustStore* trust_store_; | 392 const TrustStore* trust_store_; |
357 // The output variable for storing the next candidate path, which the client | 393 // The output variable for storing the next candidate path, which the client |
358 // passes in to GetNextPath. Only used for a single path output. | 394 // passes in to GetNextPath. Only used for a single path output. |
359 CertPath* out_path_; | 395 CertPath* out_path_; |
360 // Current state of the state machine. | 396 // Current state of the state machine. |
361 State next_state_; | 397 State next_state_; |
362 | 398 |
363 DISALLOW_COPY_AND_ASSIGN(CertPathIter); | 399 DISALLOW_COPY_AND_ASSIGN(CertPathIter); |
364 }; | 400 }; |
365 | 401 |
366 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, | 402 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, |
367 const TrustStore* trust_store) | 403 const TrustStore* trust_store) |
368 : next_issuer_(std::move(cert)), | 404 : trust_store_(trust_store), next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) { |
369 trust_store_(trust_store), | 405 // Initialize |next_issuer_| to the target certificate. |
370 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} | 406 next_issuer_.cert = std::move(cert); |
| 407 trust_store_->GetTrust(next_issuer_.cert, &next_issuer_.trust); |
| 408 } |
371 | 409 |
372 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { | 410 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { |
373 cert_issuer_sources_.push_back(cert_issuer_source); | 411 cert_issuer_sources_.push_back(cert_issuer_source); |
374 } | 412 } |
375 | 413 |
376 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). | 414 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
377 void CertPathIter::GetNextPath(CertPath* path) { | 415 void CertPathIter::GetNextPath(CertPath* path) { |
378 out_path_ = path; | 416 out_path_ = path; |
379 out_path_->Clear(); | 417 out_path_->Clear(); |
380 do { | 418 do { |
(...skipping 18 matching lines...) Expand all Loading... |
399 case STATE_BACKTRACK: | 437 case STATE_BACKTRACK: |
400 DoBackTrack(); | 438 DoBackTrack(); |
401 break; | 439 break; |
402 } | 440 } |
403 } while (next_state_ != STATE_NONE && next_state_ != STATE_RETURN_A_PATH); | 441 } while (next_state_ != STATE_NONE && next_state_ != STATE_RETURN_A_PATH); |
404 | 442 |
405 out_path_ = nullptr; | 443 out_path_ = nullptr; |
406 } | 444 } |
407 | 445 |
408 void CertPathIter::DoGetNextIssuer() { | 446 void CertPathIter::DoGetNextIssuer() { |
409 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; | 447 if (cur_path_.Empty()) { |
410 cur_path_.back()->GetNextIssuer(&next_issuer_); | 448 // Exhausted all paths. |
| 449 next_state_ = STATE_NONE; |
| 450 } else { |
| 451 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
| 452 cur_path_.back()->GetNextIssuer(&next_issuer_); |
| 453 } |
411 } | 454 } |
412 | 455 |
413 void CertPathIter::DoGetNextIssuerComplete() { | 456 void CertPathIter::DoGetNextIssuerComplete() { |
414 // If the issuer is a trust anchor signal readiness. | 457 if (!next_issuer_.cert) { |
415 if (next_issuer_.IsTrustAnchor()) { | |
416 DVLOG(1) << "CertPathIter got anchor(" | |
417 << CertDebugString(next_issuer_.anchor->cert().get()); | |
418 next_state_ = STATE_RETURN_A_PATH; | |
419 cur_path_.CopyPath(&out_path_->certs); | |
420 out_path_->trust_anchor = std::move(next_issuer_.anchor); | |
421 next_issuer_ = CertificateOrTrustAnchor(); | |
422 return; | |
423 } | |
424 | |
425 if (next_issuer_.IsCertificate()) { | |
426 // Skip this cert if it is already in the chain. | |
427 if (cur_path_.IsPresent(next_issuer_.cert.get())) { | |
428 next_state_ = STATE_GET_NEXT_ISSUER; | |
429 return; | |
430 } | |
431 | |
432 cur_path_.Append(base::MakeUnique<CertIssuersIter>( | |
433 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)); | |
434 next_issuer_ = CertificateOrTrustAnchor(); | |
435 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); | |
436 // Continue descending the tree. | |
437 next_state_ = STATE_GET_NEXT_ISSUER; | |
438 } else { | |
439 // TODO(mattm): should also include such paths in CertPathBuilder::Result, | 458 // TODO(mattm): should also include such paths in CertPathBuilder::Result, |
440 // maybe with a flag to enable it. Or use a visitor pattern so the caller | 459 // maybe with a flag to enable it. Or use a visitor pattern so the caller |
441 // can decide what to do with any failed paths. | 460 // can decide what to do with any failed paths. |
442 // No more issuers for current chain, go back up and see if there are any | 461 // No more issuers for current chain, go back up and see if there are any |
443 // more for the previous cert. | 462 // more for the previous cert. |
444 next_state_ = STATE_BACKTRACK; | 463 next_state_ = STATE_BACKTRACK; |
| 464 return; |
| 465 } |
| 466 |
| 467 switch (next_issuer_.trust.type) { |
| 468 // If the trust for this issuer is "known" (either becuase it is distrusted, |
| 469 // or because it is trusted) then stop building and return the path. |
| 470 case CertificateTrustType::DISTRUSTED: |
| 471 case CertificateTrustType::TRUSTED_ANCHOR: |
| 472 case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS: { |
| 473 // If the issuer has a known trust level, can stop building the path. |
| 474 DVLOG(1) << "CertPathIter got anchor: " |
| 475 << CertDebugString(next_issuer_.cert.get()); |
| 476 next_state_ = STATE_RETURN_A_PATH; |
| 477 cur_path_.CopyPath(&out_path_->certs); |
| 478 out_path_->certs.push_back(std::move(next_issuer_.cert)); |
| 479 out_path_->last_cert_trust = next_issuer_.trust; |
| 480 next_issuer_ = IssuerEntry(); |
| 481 break; |
| 482 } |
| 483 case CertificateTrustType::UNSPECIFIED: { |
| 484 // Skip this cert if it is already in the chain. |
| 485 if (cur_path_.IsPresent(next_issuer_.cert.get())) { |
| 486 next_state_ = STATE_GET_NEXT_ISSUER; |
| 487 break; |
| 488 } |
| 489 |
| 490 cur_path_.Append(base::MakeUnique<CertIssuersIter>( |
| 491 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)); |
| 492 next_issuer_ = IssuerEntry(); |
| 493 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); |
| 494 // Continue descending the tree. |
| 495 next_state_ = STATE_GET_NEXT_ISSUER; |
| 496 break; |
| 497 } |
445 } | 498 } |
446 } | 499 } |
447 | 500 |
448 void CertPathIter::DoBackTrack() { | 501 void CertPathIter::DoBackTrack() { |
449 DVLOG(1) << "CertPathIter backtracking..."; | 502 DVLOG(1) << "CertPathIter backtracking..."; |
450 cur_path_.Pop(); | 503 cur_path_.Pop(); |
451 if (cur_path_.Empty()) { | 504 if (cur_path_.Empty()) { |
452 // Exhausted all paths. | 505 // Exhausted all paths. |
453 next_state_ = STATE_NONE; | 506 next_state_ = STATE_NONE; |
454 } else { | 507 } else { |
455 // Continue exploring issuers of the previous path. | 508 // Continue exploring issuers of the previous path. |
456 next_state_ = STATE_GET_NEXT_ISSUER; | 509 next_state_ = STATE_GET_NEXT_ISSUER; |
457 } | 510 } |
458 } | 511 } |
459 | 512 |
460 CertPathBuilder::ResultPath::ResultPath() = default; | 513 CertPathBuilder::ResultPath::ResultPath() = default; |
461 CertPathBuilder::ResultPath::~ResultPath() = default; | 514 CertPathBuilder::ResultPath::~ResultPath() = default; |
462 | 515 |
463 bool CertPathBuilder::ResultPath::IsValid() const { | 516 bool CertPathBuilder::ResultPath::IsValid() const { |
464 return !path.certs.empty() && path.trust_anchor && | 517 return path.GetTrustedCert() && !errors.ContainsHighSeverityErrors(); |
465 !errors.ContainsHighSeverityErrors(); | |
466 } | 518 } |
467 | 519 |
468 CertPathBuilder::Result::Result() = default; | 520 CertPathBuilder::Result::Result() = default; |
469 CertPathBuilder::Result::~Result() = default; | 521 CertPathBuilder::Result::~Result() = default; |
470 | 522 |
471 const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath() | 523 const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath() |
472 const { | 524 const { |
473 DCHECK((paths.empty() && best_result_index == 0) || | 525 DCHECK((paths.empty() && best_result_index == 0) || |
474 best_result_index < paths.size()); | 526 best_result_index < paths.size()); |
475 | 527 |
476 if (best_result_index >= paths.size()) | 528 if (best_result_index >= paths.size()) |
477 return nullptr; | 529 return nullptr; |
478 | 530 |
479 const ResultPath* result_path = paths[best_result_index].get(); | 531 const ResultPath* result_path = paths[best_result_index].get(); |
480 if (result_path->IsValid()) | 532 if (result_path->IsValid()) |
481 return result_path; | 533 return result_path; |
482 | 534 |
483 return nullptr; | 535 return nullptr; |
484 } | 536 } |
485 | 537 |
486 bool CertPathBuilder::Result::HasValidPath() const { | 538 bool CertPathBuilder::Result::HasValidPath() const { |
487 return GetBestValidPath() != nullptr; | 539 return GetBestValidPath() != nullptr; |
488 } | 540 } |
489 | 541 |
490 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, | 542 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, |
491 const TrustStore* trust_store, | 543 TrustStore* trust_store, |
492 const SignaturePolicy* signature_policy, | 544 const SignaturePolicy* signature_policy, |
493 const der::GeneralizedTime& time, | 545 const der::GeneralizedTime& time, |
494 KeyPurpose key_purpose, | 546 KeyPurpose key_purpose, |
495 Result* result) | 547 Result* result) |
496 : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)), | 548 : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)), |
497 signature_policy_(signature_policy), | 549 signature_policy_(signature_policy), |
498 time_(time), | 550 time_(time), |
499 key_purpose_(key_purpose), | 551 key_purpose_(key_purpose), |
500 next_state_(STATE_NONE), | 552 next_state_(STATE_NONE), |
501 out_result_(result) {} | 553 out_result_(result) { |
| 554 // The TrustStore also implements the CertIssuerSource interface. |
| 555 AddCertIssuerSource(trust_store); |
| 556 } |
502 | 557 |
503 CertPathBuilder::~CertPathBuilder() {} | 558 CertPathBuilder::~CertPathBuilder() {} |
504 | 559 |
505 void CertPathBuilder::AddCertIssuerSource( | 560 void CertPathBuilder::AddCertIssuerSource( |
506 CertIssuerSource* cert_issuer_source) { | 561 CertIssuerSource* cert_issuer_source) { |
507 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); | 562 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); |
508 } | 563 } |
509 | 564 |
510 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). | 565 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
511 void CertPathBuilder::Run() { | 566 void CertPathBuilder::Run() { |
(...skipping 24 matching lines...) Expand all Loading... |
536 | 591 |
537 void CertPathBuilder::DoGetNextPathComplete() { | 592 void CertPathBuilder::DoGetNextPathComplete() { |
538 if (next_path_.IsEmpty()) { | 593 if (next_path_.IsEmpty()) { |
539 // No more paths to check, signal completion. | 594 // No more paths to check, signal completion. |
540 next_state_ = STATE_NONE; | 595 next_state_ = STATE_NONE; |
541 return; | 596 return; |
542 } | 597 } |
543 | 598 |
544 // Verify the entire certificate chain. | 599 // Verify the entire certificate chain. |
545 auto result_path = base::MakeUnique<ResultPath>(); | 600 auto result_path = base::MakeUnique<ResultPath>(); |
546 bool verify_result = VerifyCertificateChain( | 601 VerifyCertificateChain(next_path_.certs, next_path_.last_cert_trust, |
547 next_path_.certs, next_path_.trust_anchor.get(), signature_policy_, time_, | 602 signature_policy_, time_, key_purpose_, |
548 key_purpose_, &result_path->errors); | 603 &result_path->errors); |
| 604 bool verify_result = !result_path->errors.ContainsHighSeverityErrors(); |
| 605 |
549 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " | 606 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " |
550 << verify_result; | 607 << verify_result << "\n" |
| 608 << result_path->errors.ToDebugString(next_path_.certs); |
551 result_path->path = next_path_; | 609 result_path->path = next_path_; |
552 DCHECK_EQ(verify_result, !result_path->errors.ContainsHighSeverityErrors()); | |
553 AddResultPath(std::move(result_path)); | 610 AddResultPath(std::move(result_path)); |
554 | 611 |
555 if (verify_result) { | 612 if (verify_result) { |
556 // Found a valid path, return immediately. | 613 // Found a valid path, return immediately. |
557 // TODO(mattm): add debug/test mode that tries all possible paths. | 614 // TODO(mattm): add debug/test mode that tries all possible paths. |
558 next_state_ = STATE_NONE; | 615 next_state_ = STATE_NONE; |
559 return; | 616 return; |
560 } | 617 } |
561 | 618 |
562 // Path did not verify. Try more paths. If there are no more paths, the result | 619 // Path did not verify. Try more paths. If there are no more paths, the result |
563 // will be returned next time DoGetNextPathComplete is called with next_path_ | 620 // will be returned next time DoGetNextPathComplete is called with next_path_ |
564 // empty. | 621 // empty. |
565 next_state_ = STATE_GET_NEXT_PATH; | 622 next_state_ = STATE_GET_NEXT_PATH; |
566 } | 623 } |
567 | 624 |
568 void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { | 625 void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { |
569 // TODO(mattm): set best_result_index based on number or severity of errors. | 626 // TODO(mattm): set best_result_index based on number or severity of errors. |
570 if (result_path->IsValid()) | 627 if (result_path->IsValid()) |
571 out_result_->best_result_index = out_result_->paths.size(); | 628 out_result_->best_result_index = out_result_->paths.size(); |
572 // TODO(mattm): add flag to only return a single path or all attempted paths? | 629 // TODO(mattm): add flag to only return a single path or all attempted paths? |
573 out_result_->paths.push_back(std::move(result_path)); | 630 out_result_->paths.push_back(std::move(result_path)); |
574 } | 631 } |
575 | 632 |
576 } // namespace net | 633 } // namespace net |
OLD | NEW |