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/callback_helpers.h" | |
11 #include "base/logging.h" | 10 #include "base/logging.h" |
12 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
13 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
14 #include "net/cert/internal/cert_issuer_source.h" | 13 #include "net/cert/internal/cert_issuer_source.h" |
15 #include "net/cert/internal/parse_certificate.h" | 14 #include "net/cert/internal/parse_certificate.h" |
16 #include "net/cert/internal/parse_name.h" // For CertDebugString. | 15 #include "net/cert/internal/parse_name.h" // For CertDebugString. |
17 #include "net/cert/internal/signature_policy.h" | 16 #include "net/cert/internal/signature_policy.h" |
18 #include "net/cert/internal/trust_store.h" | 17 #include "net/cert/internal/trust_store.h" |
19 #include "net/cert/internal/verify_certificate_chain.h" | 18 #include "net/cert/internal/verify_certificate_chain.h" |
20 #include "net/cert/internal/verify_name_match.h" | 19 #include "net/cert/internal/verify_name_match.h" |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
64 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| | 63 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| |
65 // which may be issuers of |cert|. | 64 // which may be issuers of |cert|. |
66 class CertIssuersIter { | 65 class CertIssuersIter { |
67 public: | 66 public: |
68 // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| | 67 // Constructs the CertIssuersIter. |*cert_issuer_sources| and |*trust_store| |
69 // must be valid for the lifetime of the CertIssuersIter. | 68 // must be valid for the lifetime of the CertIssuersIter. |
70 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, | 69 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, |
71 CertIssuerSources* cert_issuer_sources, | 70 CertIssuerSources* cert_issuer_sources, |
72 const TrustStore* trust_store); | 71 const TrustStore* trust_store); |
73 | 72 |
74 // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC | 73 // Gets the next candidate issuer, or clears |*out| when all issuers have been |
75 // is returned and the cert is stored in |*cert|. If an issuer is not | 74 // exhausted. |
76 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has | 75 void GetNextIssuer(CertificateOrTrustAnchor* out); |
77 // been set. If |callback| is null, always completes synchronously. | |
78 // | |
79 // In either case, if all issuers have been exhausted, |*out| is cleared. | |
80 CompletionStatus GetNextIssuer(CertificateOrTrustAnchor* out, | |
81 const base::Closure& callback); | |
82 | 76 |
83 // Returns the |cert| for which issuers are being retrieved. | 77 // Returns the |cert| for which issuers are being retrieved. |
84 const ParsedCertificate* cert() const { return cert_.get(); } | 78 const ParsedCertificate* cert() const { return cert_.get(); } |
85 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } | 79 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
86 | 80 |
87 private: | 81 private: |
| 82 void AddIssuers(ParsedCertificateList issuers); |
88 void DoAsyncIssuerQuery(); | 83 void DoAsyncIssuerQuery(); |
89 void GotAsyncAnchors(TrustAnchors anchors); | |
90 void GotAsyncCerts(CertIssuerSource::Request* request); | |
91 void NotifyIfNecessary(); | |
92 | 84 |
93 scoped_refptr<ParsedCertificate> cert_; | 85 scoped_refptr<ParsedCertificate> cert_; |
94 CertIssuerSources* cert_issuer_sources_; | 86 CertIssuerSources* cert_issuer_sources_; |
95 const TrustStore* trust_store_; | 87 const TrustStore* trust_store_; |
96 | 88 |
97 // The list of trust anchors that match the issuer name for |cert_|. | 89 // The list of trust anchors that match the issuer name for |cert_|. |
98 TrustAnchors anchors_; | 90 TrustAnchors anchors_; |
99 // The index of the next trust anchor in |anchors_| to return. | 91 // The index of the next trust anchor in |anchors_| to return. |
100 size_t cur_anchor_ = 0; | 92 size_t cur_anchor_ = 0; |
101 | 93 |
(...skipping 10 matching lines...) Expand all Loading... |
112 | 104 |
113 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent | 105 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent |
114 // duplicates. This is based on the full DER of the cert to allow different | 106 // duplicates. This is based on the full DER of the cert to allow different |
115 // versions of the same certificate to be tried in different candidate paths. | 107 // versions of the same certificate to be tried in different candidate paths. |
116 // This points to data owned by |issuers_|. | 108 // This points to data owned by |issuers_|. |
117 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; | 109 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; |
118 | 110 |
119 // Tracks which requests have been made yet. | 111 // Tracks which requests have been made yet. |
120 bool did_initial_query_ = false; | 112 bool did_initial_query_ = false; |
121 bool did_async_issuer_query_ = false; | 113 bool did_async_issuer_query_ = false; |
122 // If asynchronous requests were made, how many of them are still outstanding? | 114 // Index into pending_async_requests_ that is the next one to process. |
123 size_t pending_async_results_; | 115 size_t cur_async_request_ = 0; |
124 // Owns the Request objects for any asynchronous requests so that they will be | 116 // Owns the Request objects for any asynchronous requests so that they will be |
125 // cancelled if CertIssuersIter is destroyed. | 117 // cancelled if CertIssuersIter is destroyed. |
126 std::vector<std::unique_ptr<CertIssuerSource::Request>> | 118 std::vector<std::unique_ptr<CertIssuerSource::Request>> |
127 pending_async_requests_; | 119 pending_async_requests_; |
128 std::unique_ptr<TrustStore::Request> pending_anchor_request_; | |
129 | |
130 // When GetNextIssuer was called and returned asynchronously, |*out_| is | |
131 // where the result will be stored, and |callback_| will be run when the | |
132 // result is ready. | |
133 CertificateOrTrustAnchor* out_; | |
134 base::Closure callback_; | |
135 | 120 |
136 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); | 121 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
137 }; | 122 }; |
138 | 123 |
139 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, | 124 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, |
140 CertIssuerSources* cert_issuer_sources, | 125 CertIssuerSources* cert_issuer_sources, |
141 const TrustStore* trust_store) | 126 const TrustStore* trust_store) |
142 : cert_(in_cert), | 127 : cert_(in_cert), |
143 cert_issuer_sources_(cert_issuer_sources), | 128 cert_issuer_sources_(cert_issuer_sources), |
144 trust_store_(trust_store) { | 129 trust_store_(trust_store) { |
145 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; | 130 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
146 } | 131 } |
147 | 132 |
148 CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, | 133 void CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out) { |
149 const base::Closure& callback) { | |
150 // Should not be called again while already waiting for an async result. | |
151 DCHECK(callback_.is_null()); | |
152 | |
153 if (!did_initial_query_) { | 134 if (!did_initial_query_) { |
154 did_initial_query_ = true; | 135 did_initial_query_ = true; |
155 trust_store_->FindTrustAnchorsForCert( | 136 trust_store_->FindTrustAnchorsForCert(cert_, &anchors_); |
156 cert_, | |
157 callback.is_null() ? TrustStore::TrustAnchorsCallback() | |
158 : base::Bind(&CertIssuersIter::GotAsyncAnchors, | |
159 base::Unretained(this)), | |
160 &anchors_, &pending_anchor_request_); | |
161 | 137 |
162 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 138 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
163 ParsedCertificateList new_issuers; | 139 ParsedCertificateList new_issuers; |
164 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); | 140 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); |
165 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { | 141 AddIssuers(std::move(new_issuers)); |
166 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != | |
167 present_issuers_.end()) | |
168 continue; | |
169 present_issuers_.insert(issuer->der_cert().AsStringPiece()); | |
170 issuers_.push_back(std::move(issuer)); | |
171 } | |
172 } | 142 } |
173 DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() | 143 DVLOG(1) << anchors_.size() << " sync anchors, " << issuers_.size() |
174 << " sync issuers"; | 144 << " sync issuers"; |
175 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust | 145 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust |
176 // anchor subject (or is a trust anchor), that should be sorted higher too. | 146 // anchor subject (or is a trust anchor), that should be sorted higher too. |
177 // See big list of possible sorting hints in RFC 4158.) | 147 // See big list of possible sorting hints in RFC 4158.) |
178 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that | 148 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
179 // is done) | 149 // is done) |
180 } | 150 } |
181 | 151 |
182 // Return possible trust anchors first. | 152 // Return possible trust anchors first. |
183 if (cur_anchor_ < anchors_.size()) { | 153 if (cur_anchor_ < anchors_.size()) { |
184 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 154 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
185 << "): returning anchor " << cur_anchor_ << " of " | 155 << "): returning anchor " << cur_anchor_ << " of " |
186 << anchors_.size(); | 156 << anchors_.size(); |
187 // Still have anchors that haven't been returned yet, return one of them. | 157 // Still have anchors that haven't been returned yet, return one of them. |
188 *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); | 158 *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); |
189 return CompletionStatus::SYNC; | 159 return; |
190 } | 160 } |
191 | 161 |
192 if (pending_anchor_request_) { | 162 // If there aren't any issuers left, block until async results are ready. |
193 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 163 if (cur_issuer_ >= issuers_.size()) { |
194 << ") Still waiting for async trust anchor results."; | 164 if (!did_async_issuer_query_) { |
195 out_ = out; | 165 // Now issue request(s) for async ones (AIA, etc). |
196 callback_ = callback; | 166 DoAsyncIssuerQuery(); |
197 return CompletionStatus::ASYNC; | 167 } |
| 168 |
| 169 // TODO(eroman): Rather than blocking on the async requests in FIFO order, |
| 170 // consume in the order they become ready. |
| 171 while (cur_async_request_ < pending_async_requests_.size()) { |
| 172 ParsedCertificateList new_issuers; |
| 173 pending_async_requests_[cur_async_request_]->GetNext(&new_issuers); |
| 174 if (new_issuers.empty()) { |
| 175 // Request is exhausted, no more results pending from that |
| 176 // CertIssuerSource. |
| 177 pending_async_requests_[cur_async_request_++].reset(); |
| 178 continue; |
| 179 } |
| 180 |
| 181 AddIssuers(std::move(new_issuers)); |
| 182 break; |
| 183 } |
198 } | 184 } |
199 | 185 |
200 if (cur_issuer_ < issuers_.size()) { | 186 if (cur_issuer_ < issuers_.size()) { |
201 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 187 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
202 << "): returning issuer " << cur_issuer_ << " of " | 188 << "): returning issuer " << cur_issuer_ << " of " |
203 << issuers_.size(); | 189 << issuers_.size(); |
204 // Still have issuers that haven't been returned yet, return one of them. | 190 // Still have issuers that haven't been returned yet, return one of them. |
205 // A reference to the returned issuer is retained, since |present_issuers_| | 191 // A reference to the returned issuer is retained, since |present_issuers_| |
206 // points to data owned by it. | 192 // points to data owned by it. |
207 *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); | 193 *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); |
208 return CompletionStatus::SYNC; | 194 return; |
209 } | |
210 | |
211 if (did_async_issuer_query_) { | |
212 if (pending_async_results_ == 0) { | |
213 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
214 << ") Reached the end of all available issuers."; | |
215 // Reached the end of all available issuers. | |
216 *out = CertificateOrTrustAnchor(); | |
217 return CompletionStatus::SYNC; | |
218 } | |
219 | |
220 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
221 << ") Still waiting for async results from other " | |
222 "CertIssuerSources."; | |
223 // Still waiting for async results from other CertIssuerSources. | |
224 out_ = out; | |
225 callback_ = callback; | |
226 return CompletionStatus::ASYNC; | |
227 } | |
228 // Reached the end of synchronously gathered issuers. | |
229 | |
230 if (callback.is_null()) { | |
231 // Synchronous-only mode, don't try to query async sources. | |
232 *out = CertificateOrTrustAnchor(); | |
233 return CompletionStatus::SYNC; | |
234 } | |
235 | |
236 // Now issue request(s) for async ones (AIA, etc). | |
237 DoAsyncIssuerQuery(); | |
238 | |
239 if (pending_async_results_ == 0) { | |
240 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
241 << ") No cert sources have async results."; | |
242 // No cert sources have async results. | |
243 *out = CertificateOrTrustAnchor(); | |
244 return CompletionStatus::SYNC; | |
245 } | 195 } |
246 | 196 |
247 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 197 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
248 << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ | 198 << ") Reached the end of all available issuers."; |
249 << ")"; | 199 // Reached the end of all available issuers. |
250 out_ = out; | 200 *out = CertificateOrTrustAnchor(); |
251 callback_ = callback; | 201 } |
252 return CompletionStatus::ASYNC; | 202 |
| 203 void CertIssuersIter::AddIssuers(ParsedCertificateList new_issuers) { |
| 204 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { |
| 205 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != |
| 206 present_issuers_.end()) |
| 207 continue; |
| 208 present_issuers_.insert(issuer->der_cert().AsStringPiece()); |
| 209 issuers_.push_back(std::move(issuer)); |
| 210 } |
253 } | 211 } |
254 | 212 |
255 void CertIssuersIter::DoAsyncIssuerQuery() { | 213 void CertIssuersIter::DoAsyncIssuerQuery() { |
256 DCHECK(!did_async_issuer_query_); | 214 DCHECK(!did_async_issuer_query_); |
257 did_async_issuer_query_ = true; | 215 did_async_issuer_query_ = true; |
258 pending_async_results_ = 0; | 216 cur_async_request_ = 0; |
259 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 217 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
260 std::unique_ptr<CertIssuerSource::Request> request; | 218 std::unique_ptr<CertIssuerSource::Request> request; |
261 cert_issuer_source->AsyncGetIssuersOf( | 219 cert_issuer_source->AsyncGetIssuersOf(cert(), &request); |
262 cert(), | |
263 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), | |
264 &request); | |
265 if (request) { | 220 if (request) { |
266 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) | 221 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) |
267 << ") pending..."; | 222 << ") pending..."; |
268 pending_async_results_++; | |
269 pending_async_requests_.push_back(std::move(request)); | 223 pending_async_requests_.push_back(std::move(request)); |
270 } | 224 } |
271 } | 225 } |
272 } | 226 } |
273 | 227 |
274 void CertIssuersIter::GotAsyncAnchors(TrustAnchors anchors) { | |
275 DVLOG(1) << "CertIssuersIter::GotAsyncAnchors(" << CertDebugString(cert()) | |
276 << "): " << anchors.size() << " anchors"; | |
277 for (scoped_refptr<TrustAnchor>& anchor : anchors) | |
278 anchors_.push_back(std::move(anchor)); | |
279 pending_anchor_request_.reset(); | |
280 | |
281 NotifyIfNecessary(); | |
282 } | |
283 | |
284 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { | |
285 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) | |
286 << ")"; | |
287 while (true) { | |
288 scoped_refptr<ParsedCertificate> cert; | |
289 CompletionStatus status = request->GetNext(&cert); | |
290 if (!cert) { | |
291 if (status == CompletionStatus::SYNC) { | |
292 // Request is exhausted, no more results pending from that | |
293 // CertIssuerSource. | |
294 DCHECK_GT(pending_async_results_, 0U); | |
295 pending_async_results_--; | |
296 } | |
297 break; | |
298 } | |
299 DCHECK_EQ(status, CompletionStatus::SYNC); | |
300 if (present_issuers_.find(cert->der_cert().AsStringPiece()) != | |
301 present_issuers_.end()) | |
302 continue; | |
303 present_issuers_.insert(cert->der_cert().AsStringPiece()); | |
304 issuers_.push_back(std::move(cert)); | |
305 } | |
306 | |
307 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may | |
308 // be more than the ones just inserted, depending on |cur_| value). | |
309 | |
310 NotifyIfNecessary(); | |
311 } | |
312 | |
313 void CertIssuersIter::NotifyIfNecessary() { | |
314 // Notify that more results are available, if necessary. | |
315 if (!callback_.is_null()) { | |
316 if (cur_anchor_ < anchors_.size()) { | |
317 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
318 << "): async returning anchor " << cur_anchor_ << " of " | |
319 << anchors_.size(); | |
320 *out_ = CertificateOrTrustAnchor(std::move(anchors_[cur_anchor_++])); | |
321 base::ResetAndReturn(&callback_).Run(); | |
322 return; | |
323 } | |
324 if (cur_issuer_ < issuers_.size()) { | |
325 DCHECK(!pending_anchor_request_); | |
326 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
327 << "): async returning issuer " << cur_issuer_ << " of " | |
328 << issuers_.size(); | |
329 *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++])); | |
330 base::ResetAndReturn(&callback_).Run(); | |
331 return; | |
332 } | |
333 | |
334 if (!did_async_issuer_query_) | |
335 DoAsyncIssuerQuery(); | |
336 | |
337 if (pending_async_results_ == 0) { | |
338 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
339 << "): async returning empty result"; | |
340 *out_ = CertificateOrTrustAnchor(); | |
341 base::ResetAndReturn(&callback_).Run(); | |
342 return; | |
343 } | |
344 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
345 << "): empty result, but other async results " | |
346 "pending, waiting.."; | |
347 } | |
348 } | |
349 | |
350 // CertIssuerIterPath tracks which certs are present in the path and prevents | 228 // CertIssuerIterPath tracks which certs are present in the path and prevents |
351 // paths from being built which repeat any certs (including different versions | 229 // paths from being built which repeat any certs (including different versions |
352 // of the same cert, based on Subject+SubjectAltName+SPKI). | 230 // of the same cert, based on Subject+SubjectAltName+SPKI). |
353 class CertIssuerIterPath { | 231 class CertIssuerIterPath { |
354 public: | 232 public: |
355 // Returns true if |cert| is already present in the path. | 233 // Returns true if |cert| is already present in the path. |
356 bool IsPresent(const ParsedCertificate* cert) const { | 234 bool IsPresent(const ParsedCertificate* cert) const { |
357 return present_certs_.find(GetKey(cert)) != present_certs_.end(); | 235 return present_certs_.find(GetKey(cert)) != present_certs_.end(); |
358 } | 236 } |
359 | 237 |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 class CertPathIter { | 317 class CertPathIter { |
440 public: | 318 public: |
441 CertPathIter(scoped_refptr<ParsedCertificate> cert, | 319 CertPathIter(scoped_refptr<ParsedCertificate> cert, |
442 const TrustStore* trust_store); | 320 const TrustStore* trust_store); |
443 | 321 |
444 // Adds a CertIssuerSource to provide intermediates for use in path building. | 322 // Adds a CertIssuerSource to provide intermediates for use in path building. |
445 // The |*cert_issuer_source| must remain valid for the lifetime of the | 323 // The |*cert_issuer_source| must remain valid for the lifetime of the |
446 // CertPathIter. | 324 // CertPathIter. |
447 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); | 325 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); |
448 | 326 |
449 // Gets the next candidate path. If a path is ready synchronously, SYNC is | 327 // Gets the next candidate path, or clears |*path| when all paths have been |
450 // returned and the path is stored in |*path|. If a path is not ready, | 328 // exhausted. |
451 // ASYNC is returned and |callback| will be called once |*path| has been set. | 329 void GetNextPath(CertPath* path); |
452 // In either case, if all paths have been exhausted, |*path| is cleared. | |
453 CompletionStatus GetNextPath(CertPath* path, const base::Closure& callback); | |
454 | 330 |
455 private: | 331 private: |
456 enum State { | 332 enum State { |
457 STATE_NONE, | 333 STATE_NONE, |
458 STATE_GET_NEXT_ISSUER, | 334 STATE_GET_NEXT_ISSUER, |
459 STATE_GET_NEXT_ISSUER_COMPLETE, | 335 STATE_GET_NEXT_ISSUER_COMPLETE, |
460 STATE_RETURN_A_PATH, | 336 STATE_RETURN_A_PATH, |
461 STATE_BACKTRACK, | 337 STATE_BACKTRACK, |
462 }; | 338 }; |
463 | 339 |
464 CompletionStatus DoLoop(bool allow_async); | 340 void DoGetNextIssuer(); |
465 | 341 void DoGetNextIssuerComplete(); |
466 CompletionStatus DoGetNextIssuer(bool allow_async); | 342 void DoBackTrack(); |
467 CompletionStatus DoGetNextIssuerComplete(); | |
468 CompletionStatus DoBackTrack(); | |
469 | |
470 void HandleGotNextIssuer(void); | |
471 | 343 |
472 // Stores the next candidate issuer, until it is used during the | 344 // Stores the next candidate issuer, until it is used during the |
473 // STATE_GET_NEXT_ISSUER_COMPLETE step. | 345 // STATE_GET_NEXT_ISSUER_COMPLETE step. |
474 CertificateOrTrustAnchor next_issuer_; | 346 CertificateOrTrustAnchor next_issuer_; |
475 // The current path being explored, made up of CertIssuerIters. Each node | 347 // The current path being explored, made up of CertIssuerIters. Each node |
476 // keeps track of the state of searching for issuers of that cert, so that | 348 // keeps track of the state of searching for issuers of that cert, so that |
477 // when backtracking it can resume the search where it left off. | 349 // when backtracking it can resume the search where it left off. |
478 CertIssuerIterPath cur_path_; | 350 CertIssuerIterPath cur_path_; |
479 // The CertIssuerSources for retrieving candidate issuers. | 351 // The CertIssuerSources for retrieving candidate issuers. |
480 CertIssuerSources cert_issuer_sources_; | 352 CertIssuerSources cert_issuer_sources_; |
481 // The TrustStore for checking if a path ends in a trust anchor. | 353 // The TrustStore for checking if a path ends in a trust anchor. |
482 const TrustStore* trust_store_; | 354 const TrustStore* trust_store_; |
483 // The output variable for storing the next candidate path, which the client | 355 // The output variable for storing the next candidate path, which the client |
484 // passes in to GetNextPath. Only used for a single path output. | 356 // passes in to GetNextPath. Only used for a single path output. |
485 CertPath* out_path_; | 357 CertPath* out_path_; |
486 // The callback to be called if an async lookup generated a candidate path. | |
487 base::Closure callback_; | |
488 // Current state of the state machine. | 358 // Current state of the state machine. |
489 State next_state_; | 359 State next_state_; |
490 | 360 |
491 DISALLOW_COPY_AND_ASSIGN(CertPathIter); | 361 DISALLOW_COPY_AND_ASSIGN(CertPathIter); |
492 }; | 362 }; |
493 | 363 |
494 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, | 364 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, |
495 const TrustStore* trust_store) | 365 const TrustStore* trust_store) |
496 : next_issuer_(std::move(cert)), | 366 : next_issuer_(std::move(cert)), |
497 trust_store_(trust_store), | 367 trust_store_(trust_store), |
498 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} | 368 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} |
499 | 369 |
500 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { | 370 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { |
501 cert_issuer_sources_.push_back(cert_issuer_source); | 371 cert_issuer_sources_.push_back(cert_issuer_source); |
502 } | 372 } |
503 | 373 |
504 CompletionStatus CertPathIter::GetNextPath(CertPath* path, | 374 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
505 const base::Closure& callback) { | 375 void CertPathIter::GetNextPath(CertPath* path) { |
506 out_path_ = path; | 376 out_path_ = path; |
507 out_path_->Clear(); | 377 out_path_->Clear(); |
508 CompletionStatus rv = DoLoop(!callback.is_null()); | |
509 if (rv == CompletionStatus::ASYNC) { | |
510 callback_ = callback; | |
511 } else { | |
512 // Clear the reference to the output parameter as a precaution. | |
513 out_path_ = nullptr; | |
514 } | |
515 return rv; | |
516 } | |
517 | |
518 CompletionStatus CertPathIter::DoLoop(bool allow_async) { | |
519 CompletionStatus result = CompletionStatus::SYNC; | |
520 do { | 378 do { |
521 State state = next_state_; | 379 State state = next_state_; |
522 next_state_ = STATE_NONE; | 380 next_state_ = STATE_NONE; |
523 switch (state) { | 381 switch (state) { |
524 case STATE_NONE: | 382 case STATE_NONE: |
525 NOTREACHED(); | 383 NOTREACHED(); |
526 break; | 384 break; |
527 case STATE_GET_NEXT_ISSUER: | 385 case STATE_GET_NEXT_ISSUER: |
528 result = DoGetNextIssuer(allow_async); | 386 DoGetNextIssuer(); |
529 break; | 387 break; |
530 case STATE_GET_NEXT_ISSUER_COMPLETE: | 388 case STATE_GET_NEXT_ISSUER_COMPLETE: |
531 result = DoGetNextIssuerComplete(); | 389 DoGetNextIssuerComplete(); |
532 break; | 390 break; |
533 case STATE_RETURN_A_PATH: | 391 case STATE_RETURN_A_PATH: |
534 // If the returned path did not verify, keep looking for other paths | 392 // If the returned path did not verify, keep looking for other paths |
535 // (the trust root is not part of cur_path_, so don't need to | 393 // (the trust root is not part of cur_path_, so don't need to |
536 // backtrack). | 394 // backtrack). |
537 next_state_ = STATE_GET_NEXT_ISSUER; | 395 next_state_ = STATE_GET_NEXT_ISSUER; |
538 result = CompletionStatus::SYNC; | |
539 break; | 396 break; |
540 case STATE_BACKTRACK: | 397 case STATE_BACKTRACK: |
541 result = DoBackTrack(); | 398 DoBackTrack(); |
542 break; | 399 break; |
543 } | 400 } |
544 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && | 401 } while (next_state_ != STATE_NONE && next_state_ != STATE_RETURN_A_PATH); |
545 next_state_ != STATE_RETURN_A_PATH); | |
546 | 402 |
547 return result; | 403 out_path_ = nullptr; |
548 } | 404 } |
549 | 405 |
550 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { | 406 void CertPathIter::DoGetNextIssuer() { |
551 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; | 407 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
552 CompletionStatus rv = cur_path_.back()->GetNextIssuer( | 408 cur_path_.back()->GetNextIssuer(&next_issuer_); |
553 &next_issuer_, allow_async | |
554 ? base::Bind(&CertPathIter::HandleGotNextIssuer, | |
555 base::Unretained(this)) | |
556 : base::Closure()); | |
557 return rv; | |
558 } | 409 } |
559 | 410 |
560 CompletionStatus CertPathIter::DoGetNextIssuerComplete() { | 411 void CertPathIter::DoGetNextIssuerComplete() { |
561 // If the issuer is a trust anchor signal readiness. | 412 // If the issuer is a trust anchor signal readiness. |
562 if (next_issuer_.IsTrustAnchor()) { | 413 if (next_issuer_.IsTrustAnchor()) { |
563 DVLOG(1) << "CertPathIter got anchor(" | 414 DVLOG(1) << "CertPathIter got anchor(" |
564 << CertDebugString(next_issuer_.anchor->cert().get()); | 415 << CertDebugString(next_issuer_.anchor->cert().get()); |
565 next_state_ = STATE_RETURN_A_PATH; | 416 next_state_ = STATE_RETURN_A_PATH; |
566 cur_path_.CopyPath(&out_path_->certs); | 417 cur_path_.CopyPath(&out_path_->certs); |
567 out_path_->trust_anchor = std::move(next_issuer_.anchor); | 418 out_path_->trust_anchor = std::move(next_issuer_.anchor); |
568 next_issuer_ = CertificateOrTrustAnchor(); | 419 next_issuer_ = CertificateOrTrustAnchor(); |
569 return CompletionStatus::SYNC; | 420 return; |
570 } | 421 } |
571 | 422 |
572 if (next_issuer_.IsCertificate()) { | 423 if (next_issuer_.IsCertificate()) { |
573 // Skip this cert if it is already in the chain. | 424 // Skip this cert if it is already in the chain. |
574 if (cur_path_.IsPresent(next_issuer_.cert.get())) { | 425 if (cur_path_.IsPresent(next_issuer_.cert.get())) { |
575 next_state_ = STATE_GET_NEXT_ISSUER; | 426 next_state_ = STATE_GET_NEXT_ISSUER; |
576 return CompletionStatus::SYNC; | 427 return; |
577 } | 428 } |
578 | 429 |
579 cur_path_.Append(base::MakeUnique<CertIssuersIter>( | 430 cur_path_.Append(base::MakeUnique<CertIssuersIter>( |
580 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)); | 431 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_)); |
581 next_issuer_ = CertificateOrTrustAnchor(); | 432 next_issuer_ = CertificateOrTrustAnchor(); |
582 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); | 433 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); |
583 // Continue descending the tree. | 434 // Continue descending the tree. |
584 next_state_ = STATE_GET_NEXT_ISSUER; | 435 next_state_ = STATE_GET_NEXT_ISSUER; |
585 } else { | 436 } else { |
586 // TODO(mattm): should also include such paths in CertPathBuilder::Result, | 437 // TODO(mattm): should also include such paths in CertPathBuilder::Result, |
587 // maybe with a flag to enable it. Or use a visitor pattern so the caller | 438 // maybe with a flag to enable it. Or use a visitor pattern so the caller |
588 // can decide what to do with any failed paths. | 439 // can decide what to do with any failed paths. |
589 // No more issuers for current chain, go back up and see if there are any | 440 // No more issuers for current chain, go back up and see if there are any |
590 // more for the previous cert. | 441 // more for the previous cert. |
591 next_state_ = STATE_BACKTRACK; | 442 next_state_ = STATE_BACKTRACK; |
592 } | 443 } |
593 return CompletionStatus::SYNC; | |
594 } | 444 } |
595 | 445 |
596 CompletionStatus CertPathIter::DoBackTrack() { | 446 void CertPathIter::DoBackTrack() { |
597 DVLOG(1) << "CertPathIter backtracking..."; | 447 DVLOG(1) << "CertPathIter backtracking..."; |
598 cur_path_.Pop(); | 448 cur_path_.Pop(); |
599 if (cur_path_.Empty()) { | 449 if (cur_path_.Empty()) { |
600 // Exhausted all paths. | 450 // Exhausted all paths. |
601 next_state_ = STATE_NONE; | 451 next_state_ = STATE_NONE; |
602 } else { | 452 } else { |
603 // Continue exploring issuers of the previous path. | 453 // Continue exploring issuers of the previous path. |
604 next_state_ = STATE_GET_NEXT_ISSUER; | 454 next_state_ = STATE_GET_NEXT_ISSUER; |
605 } | 455 } |
606 return CompletionStatus::SYNC; | |
607 } | |
608 | |
609 void CertPathIter::HandleGotNextIssuer(void) { | |
610 DCHECK(!callback_.is_null()); | |
611 CompletionStatus rv = DoLoop(true /* allow_async */); | |
612 if (rv == CompletionStatus::SYNC) { | |
613 // Clear the reference to the output parameter as a precaution. | |
614 out_path_ = nullptr; | |
615 base::ResetAndReturn(&callback_).Run(); | |
616 } | |
617 } | 456 } |
618 | 457 |
619 CertPathBuilder::ResultPath::ResultPath() = default; | 458 CertPathBuilder::ResultPath::ResultPath() = default; |
620 CertPathBuilder::ResultPath::~ResultPath() = default; | 459 CertPathBuilder::ResultPath::~ResultPath() = default; |
621 CertPathBuilder::Result::Result() = default; | 460 CertPathBuilder::Result::Result() = default; |
622 CertPathBuilder::Result::~Result() = default; | 461 CertPathBuilder::Result::~Result() = default; |
623 | 462 |
624 const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath() | 463 const CertPathBuilder::ResultPath* CertPathBuilder::Result::GetBestValidPath() |
625 const { | 464 const { |
626 DCHECK((paths.empty() && best_result_index == 0) || | 465 DCHECK((paths.empty() && best_result_index == 0) || |
(...skipping 24 matching lines...) Expand all Loading... |
651 next_state_(STATE_NONE), | 490 next_state_(STATE_NONE), |
652 out_result_(result) {} | 491 out_result_(result) {} |
653 | 492 |
654 CertPathBuilder::~CertPathBuilder() {} | 493 CertPathBuilder::~CertPathBuilder() {} |
655 | 494 |
656 void CertPathBuilder::AddCertIssuerSource( | 495 void CertPathBuilder::AddCertIssuerSource( |
657 CertIssuerSource* cert_issuer_source) { | 496 CertIssuerSource* cert_issuer_source) { |
658 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); | 497 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); |
659 } | 498 } |
660 | 499 |
661 CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { | 500 // TODO(eroman): Simplify (doesn't need to use the "DoLoop" pattern). |
| 501 void CertPathBuilder::Run() { |
662 DCHECK_EQ(STATE_NONE, next_state_); | 502 DCHECK_EQ(STATE_NONE, next_state_); |
663 next_state_ = STATE_GET_NEXT_PATH; | 503 next_state_ = STATE_GET_NEXT_PATH; |
664 CompletionStatus rv = DoLoop(!callback.is_null()); | |
665 | |
666 if (rv == CompletionStatus::ASYNC) | |
667 callback_ = callback; | |
668 | |
669 return rv; | |
670 } | |
671 | |
672 CompletionStatus CertPathBuilder::DoLoop(bool allow_async) { | |
673 CompletionStatus result = CompletionStatus::SYNC; | |
674 | 504 |
675 do { | 505 do { |
676 State state = next_state_; | 506 State state = next_state_; |
677 next_state_ = STATE_NONE; | 507 next_state_ = STATE_NONE; |
678 switch (state) { | 508 switch (state) { |
679 case STATE_NONE: | 509 case STATE_NONE: |
680 NOTREACHED(); | 510 NOTREACHED(); |
681 break; | 511 break; |
682 case STATE_GET_NEXT_PATH: | 512 case STATE_GET_NEXT_PATH: |
683 result = DoGetNextPath(allow_async); | 513 DoGetNextPath(); |
684 break; | 514 break; |
685 case STATE_GET_NEXT_PATH_COMPLETE: | 515 case STATE_GET_NEXT_PATH_COMPLETE: |
686 result = DoGetNextPathComplete(); | 516 DoGetNextPathComplete(); |
687 break; | 517 break; |
688 } | 518 } |
689 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE); | 519 } while (next_state_ != STATE_NONE); |
690 | |
691 return result; | |
692 } | 520 } |
693 | 521 |
694 CompletionStatus CertPathBuilder::DoGetNextPath(bool allow_async) { | 522 void CertPathBuilder::DoGetNextPath() { |
695 next_state_ = STATE_GET_NEXT_PATH_COMPLETE; | 523 next_state_ = STATE_GET_NEXT_PATH_COMPLETE; |
696 CompletionStatus rv = cert_path_iter_->GetNextPath( | 524 cert_path_iter_->GetNextPath(&next_path_); |
697 &next_path_, allow_async ? base::Bind(&CertPathBuilder::HandleGotNextPath, | |
698 base::Unretained(this)) | |
699 : base::Closure()); | |
700 return rv; | |
701 } | 525 } |
702 | 526 |
703 void CertPathBuilder::HandleGotNextPath() { | 527 void CertPathBuilder::DoGetNextPathComplete() { |
704 DCHECK(!callback_.is_null()); | |
705 CompletionStatus rv = DoLoop(true /* allow_async */); | |
706 if (rv == CompletionStatus::SYNC) | |
707 base::ResetAndReturn(&callback_).Run(); | |
708 } | |
709 | |
710 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { | |
711 if (next_path_.IsEmpty()) { | 528 if (next_path_.IsEmpty()) { |
712 // No more paths to check, signal completion. | 529 // No more paths to check, signal completion. |
713 next_state_ = STATE_NONE; | 530 next_state_ = STATE_NONE; |
714 return CompletionStatus::SYNC; | 531 return; |
715 } | 532 } |
716 | 533 |
717 // Verify the entire certificate chain. | 534 // Verify the entire certificate chain. |
718 auto result_path = base::MakeUnique<ResultPath>(); | 535 auto result_path = base::MakeUnique<ResultPath>(); |
719 bool verify_result = | 536 bool verify_result = |
720 VerifyCertificateChain(next_path_.certs, next_path_.trust_anchor.get(), | 537 VerifyCertificateChain(next_path_.certs, next_path_.trust_anchor.get(), |
721 signature_policy_, time_, &result_path->errors); | 538 signature_policy_, time_, &result_path->errors); |
722 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " | 539 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " |
723 << result_path->valid; | 540 << result_path->valid; |
724 result_path->path = next_path_; | 541 result_path->path = next_path_; |
725 result_path->valid = verify_result; | 542 result_path->valid = verify_result; |
726 AddResultPath(std::move(result_path)); | 543 AddResultPath(std::move(result_path)); |
727 | 544 |
728 if (verify_result) { | 545 if (verify_result) { |
729 // Found a valid path, return immediately. | 546 // Found a valid path, return immediately. |
730 // TODO(mattm): add debug/test mode that tries all possible paths. | 547 // TODO(mattm): add debug/test mode that tries all possible paths. |
731 next_state_ = STATE_NONE; | 548 next_state_ = STATE_NONE; |
732 return CompletionStatus::SYNC; | 549 return; |
733 } | 550 } |
734 | 551 |
735 // Path did not verify. Try more paths. If there are no more paths, the result | 552 // Path did not verify. Try more paths. If there are no more paths, the result |
736 // will be returned next time DoGetNextPathComplete is called with next_path_ | 553 // will be returned next time DoGetNextPathComplete is called with next_path_ |
737 // empty. | 554 // empty. |
738 next_state_ = STATE_GET_NEXT_PATH; | 555 next_state_ = STATE_GET_NEXT_PATH; |
739 return CompletionStatus::SYNC; | |
740 } | 556 } |
741 | 557 |
742 void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { | 558 void CertPathBuilder::AddResultPath(std::unique_ptr<ResultPath> result_path) { |
743 // TODO(mattm): set best_result_index based on number or severity of errors. | 559 // TODO(mattm): set best_result_index based on number or severity of errors. |
744 if (result_path->valid) | 560 if (result_path->valid) |
745 out_result_->best_result_index = out_result_->paths.size(); | 561 out_result_->best_result_index = out_result_->paths.size(); |
746 // TODO(mattm): add flag to only return a single path or all attempted paths? | 562 // TODO(mattm): add flag to only return a single path or all attempted paths? |
747 out_result_->paths.push_back(std::move(result_path)); | 563 out_result_->paths.push_back(std::move(result_path)); |
748 } | 564 } |
749 | 565 |
750 } // namespace net | 566 } // namespace net |
OLD | NEW |