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" | 10 #include "base/callback_helpers.h" |
11 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
12 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
13 #include "net/cert/internal/cert_issuer_source.h" | 13 #include "net/cert/internal/cert_issuer_source.h" |
| 14 #include "net/cert/internal/cert_issuer_source_collection.h" |
14 #include "net/cert/internal/parse_certificate.h" | 15 #include "net/cert/internal/parse_certificate.h" |
15 #include "net/cert/internal/parse_name.h" // For CertDebugString. | 16 #include "net/cert/internal/parse_name.h" // For CertDebugString. |
16 #include "net/cert/internal/signature_policy.h" | 17 #include "net/cert/internal/signature_policy.h" |
17 #include "net/cert/internal/trust_store.h" | 18 #include "net/cert/internal/trust_store.h" |
| 19 #include "net/cert/internal/trust_store_collection.h" |
18 #include "net/cert/internal/verify_certificate_chain.h" | 20 #include "net/cert/internal/verify_certificate_chain.h" |
19 #include "net/cert/internal/verify_name_match.h" | 21 #include "net/cert/internal/verify_name_match.h" |
20 #include "net/der/parser.h" | 22 #include "net/der/parser.h" |
21 #include "net/der/tag.h" | 23 #include "net/der/tag.h" |
22 | 24 |
23 namespace net { | 25 namespace net { |
24 | 26 |
25 namespace { | 27 namespace { |
26 | 28 |
27 using CertIssuerSources = std::vector<CertIssuerSource*>; | |
28 | |
29 // TODO(mattm): decide how much debug logging to keep. | 29 // TODO(mattm): decide how much debug logging to keep. |
30 std::string CertDebugString(const ParsedCertificate* cert) { | 30 std::string CertDebugString(const ParsedCertificate* cert) { |
31 RDNSequence subject, issuer; | 31 RDNSequence subject, issuer; |
32 std::string subject_str, issuer_str; | 32 std::string subject_str, issuer_str; |
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 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| | 43 // CertIssuersIter iterates through the intermediates from |cert_issuer_source| |
44 // which may be issuers of |cert|. | 44 // which may be issuers of |cert|. |
45 class CertIssuersIter { | 45 class CertIssuersIter { |
46 public: | 46 public: |
47 // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for | 47 // Constructs the CertIssuersIter. |*cert_issuer_source| must be valid for |
48 // the lifetime of the CertIssuersIter. | 48 // the lifetime of the CertIssuersIter. |
49 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, | 49 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, |
50 CertIssuerSources* cert_issuer_sources, | 50 CertIssuerSource* cert_issuer_source); |
51 const TrustStore& trust_store); | |
52 | 51 |
53 // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC | 52 // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC |
54 // is returned and the cert is stored in |*out_cert|. If an issuer is not | 53 // is returned and the cert is stored in |*out_cert|. If an issuer is not |
55 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has | 54 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has |
56 // been set. If |callback| is null, always completes synchronously. | 55 // been set. If |callback| is null, always completes synchronously. |
57 // | 56 // |
58 // In either case, if all issuers have been exhausted, |*out_cert| is cleared. | 57 // In either case, if all issuers have been exhausted, |*out_cert| is cleared. |
59 CompletionStatus GetNextIssuer(scoped_refptr<ParsedCertificate>* out_cert, | 58 CompletionStatus GetNextIssuer(scoped_refptr<ParsedCertificate>* out_cert, |
60 const base::Closure& callback); | 59 const base::Closure& callback); |
61 | 60 |
62 // Returns the |cert| for which issuers are being retrieved. | 61 // Returns the |cert| for which issuers are being retrieved. |
63 const ParsedCertificate* cert() const { return cert_.get(); } | 62 const ParsedCertificate* cert() const { return cert_.get(); } |
64 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } | 63 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
65 | 64 |
66 private: | 65 private: |
67 void GotAsyncCerts(CertIssuerSource::Request* request); | 66 void GotAsyncCerts(CertIssuerSource::Request* request); |
68 | 67 |
69 scoped_refptr<ParsedCertificate> cert_; | 68 scoped_refptr<ParsedCertificate> cert_; |
70 CertIssuerSources* cert_issuer_sources_; | 69 CertIssuerSource* cert_issuer_source_; |
71 | 70 |
72 // The list of issuers for |cert_|. This is added to incrementally (first | 71 // The list of issuers for |cert_|. This is added to incrementally (first |
73 // synchronous results, then possibly multiple times as asynchronous results | 72 // synchronous results, then possibly multiple times as asynchronous results |
74 // arrive.) The issuers may be re-sorted each time new issuers are added, but | 73 // arrive.) The issuers may be re-sorted each time new issuers are added, but |
75 // only the results from |cur_| onwards should be sorted, since the earlier | 74 // only the results from |cur_| onwards should be sorted, since the earlier |
76 // results were already returned. | 75 // results were already returned. |
77 // Elements should not be removed from |issuers_| once added, since | 76 // Elements should not be removed from |issuers_| once added, since |
78 // |present_issuers_| will point to data owned by the certs. | 77 // |present_issuers_| will point to data owned by the certs. |
79 ParsedCertificateList issuers_; | 78 ParsedCertificateList issuers_; |
80 // The index of the next cert in |issuers_| to return. | 79 // The index of the next cert in |issuers_| to return. |
81 size_t cur_ = 0; | 80 size_t cur_ = 0; |
82 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent | 81 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent |
83 // duplicates. This is based on the full DER of the cert to allow different | 82 // duplicates. This is based on the full DER of the cert to allow different |
84 // versions of the same certificate to be tried in different candidate paths. | 83 // versions of the same certificate to be tried in different candidate paths. |
85 // This points to data owned by |issuers_|. | 84 // This points to data owned by |issuers_|. |
86 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; | 85 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; |
87 | 86 |
88 // Tracks whether asynchronous requests have been made yet. | 87 // Tracks whether asynchronous requests have been made yet. |
89 bool did_async_query_ = false; | 88 bool did_async_query_ = false; |
90 // If asynchronous requests were made, how many of them are still outstanding? | 89 // Owns the Request object for any asynchronous request so that it will be |
91 size_t pending_async_results_; | |
92 // Owns the Request objects for any asynchronous requests so that they will be | |
93 // cancelled if CertIssuersIter is destroyed. | 90 // cancelled if CertIssuersIter is destroyed. |
94 std::vector<std::unique_ptr<CertIssuerSource::Request>> | 91 std::unique_ptr<CertIssuerSource::Request> pending_async_request_; |
95 pending_async_requests_; | |
96 | 92 |
97 // When GetNextIssuer was called and returned asynchronously, |*out_cert_| is | 93 // When GetNextIssuer was called and returned asynchronously, |*out_cert_| is |
98 // where the result will be stored, and |callback_| will be run when the | 94 // where the result will be stored, and |callback_| will be run when the |
99 // result is ready. | 95 // result is ready. |
100 scoped_refptr<ParsedCertificate>* out_cert_; | 96 scoped_refptr<ParsedCertificate>* out_cert_; |
101 base::Closure callback_; | 97 base::Closure callback_; |
102 | 98 |
103 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); | 99 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
104 }; | 100 }; |
105 | 101 |
106 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, | 102 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, |
107 CertIssuerSources* cert_issuer_sources, | 103 CertIssuerSource* cert_issuer_source) |
108 const TrustStore& trust_store) | 104 : cert_(in_cert), cert_issuer_source_(cert_issuer_source) { |
109 : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) { | |
110 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; | 105 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
111 trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(), | 106 ParsedCertificateList new_issuers; |
112 &issuers_); | 107 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); |
113 // Insert matching roots into |present_issuers_| in case they also are | 108 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { |
114 // returned by a CertIssuerSource. It is assumed | 109 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != |
115 // FindTrustAnchorsByNormalizedName does not itself return dupes. | 110 present_issuers_.end()) |
116 for (const auto& root : issuers_) | 111 continue; |
117 present_issuers_.insert(root->der_cert().AsStringPiece()); | 112 present_issuers_.insert(issuer->der_cert().AsStringPiece()); |
118 | 113 issuers_.push_back(std::move(issuer)); |
119 for (auto* cert_issuer_source : *cert_issuer_sources_) { | |
120 ParsedCertificateList new_issuers; | |
121 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); | |
122 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { | |
123 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != | |
124 present_issuers_.end()) | |
125 continue; | |
126 present_issuers_.insert(issuer->der_cert().AsStringPiece()); | |
127 issuers_.push_back(std::move(issuer)); | |
128 } | |
129 } | 114 } |
130 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust | 115 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust |
131 // anchor subject (or is a trust anchor), that should be sorted higher too. | 116 // anchor subject (or is a trust anchor), that should be sorted higher too. |
132 // See big list of possible sorting hints in RFC 4158.) | 117 // See big list of possible sorting hints in RFC 4158.) |
133 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that | 118 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
134 // is done) | 119 // is done) |
135 } | 120 } |
136 | 121 |
137 CompletionStatus CertIssuersIter::GetNextIssuer( | 122 CompletionStatus CertIssuersIter::GetNextIssuer( |
138 scoped_refptr<ParsedCertificate>* out_cert, | 123 scoped_refptr<ParsedCertificate>* out_cert, |
139 const base::Closure& callback) { | 124 const base::Closure& callback) { |
140 // Should not be called again while already waiting for an async result. | 125 // Should not be called again while already waiting for an async result. |
141 DCHECK(callback_.is_null()); | 126 DCHECK(callback_.is_null()); |
142 | 127 |
143 if (cur_ < issuers_.size()) { | 128 if (cur_ < issuers_.size()) { |
144 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 129 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
145 << "): returning item " << cur_ << " of " << issuers_.size(); | 130 << "): returning item " << cur_ << " of " << issuers_.size(); |
146 // Still have issuers that haven't been returned yet, return one of them. | 131 // Still have issuers that haven't been returned yet, return one of them. |
147 // A reference to the returned issuer is retained, since |present_issuers_| | 132 // A reference to the returned issuer is retained, since |present_issuers_| |
148 // points to data owned by it. | 133 // points to data owned by it. |
149 *out_cert = issuers_[cur_++]; | 134 *out_cert = issuers_[cur_++]; |
150 return CompletionStatus::SYNC; | 135 return CompletionStatus::SYNC; |
151 } | 136 } |
152 if (did_async_query_) { | 137 if (did_async_query_) { |
153 if (pending_async_results_ == 0) { | 138 if (!pending_async_request_) { |
154 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 139 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
155 << ") Reached the end of all available issuers."; | 140 << ") Reached the end of all available issuers."; |
156 // Reached the end of all available issuers. | 141 // Reached the end of all available issuers. |
157 *out_cert = nullptr; | 142 *out_cert = nullptr; |
158 return CompletionStatus::SYNC; | 143 return CompletionStatus::SYNC; |
159 } | 144 } |
160 | 145 |
161 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 146 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
162 << ") Still waiting for async results from other " | 147 << ") Still waiting for more async results."; |
163 "CertIssuerSources."; | |
164 // Still waiting for async results from other CertIssuerSources. | 148 // Still waiting for async results from other CertIssuerSources. |
165 out_cert_ = out_cert; | 149 out_cert_ = out_cert; |
166 callback_ = callback; | 150 callback_ = callback; |
167 return CompletionStatus::ASYNC; | 151 return CompletionStatus::ASYNC; |
168 } | 152 } |
169 // Reached the end of synchronously gathered issuers. | 153 // Reached the end of synchronously gathered issuers. |
170 | 154 |
171 if (callback.is_null()) { | 155 if (callback.is_null()) { |
172 // Synchronous-only mode, don't try to query async sources. | 156 // Synchronous-only mode, don't try to query async sources. |
173 *out_cert = nullptr; | 157 *out_cert = nullptr; |
174 return CompletionStatus::SYNC; | 158 return CompletionStatus::SYNC; |
175 } | 159 } |
176 | 160 |
177 // Now issue request(s) for async ones (AIA, etc). | 161 // Now issue request(s) for async ones (AIA, etc). |
178 did_async_query_ = true; | 162 did_async_query_ = true; |
179 pending_async_results_ = 0; | 163 std::unique_ptr<CertIssuerSource::Request> request; |
180 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 164 cert_issuer_source_->AsyncGetIssuersOf( |
181 std::unique_ptr<CertIssuerSource::Request> request; | 165 reference_cert(), |
182 cert_issuer_source->AsyncGetIssuersOf( | 166 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), |
183 cert(), | 167 &request); |
184 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), | 168 if (request) { |
185 &request); | 169 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) |
186 if (request) { | 170 << ") pending..."; |
187 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) | 171 pending_async_request_ = std::move(request); |
188 << ") pending..."; | |
189 pending_async_results_++; | |
190 pending_async_requests_.push_back(std::move(request)); | |
191 } | |
192 } | 172 } |
193 | 173 |
194 if (pending_async_results_ == 0) { | 174 if (!pending_async_request_) { |
195 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 175 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
196 << ") No cert sources have async results."; | 176 << ") No cert sources have async results."; |
197 // No cert sources have async results. | 177 // No cert sources have async results. |
198 *out_cert = nullptr; | 178 *out_cert = nullptr; |
199 return CompletionStatus::SYNC; | 179 return CompletionStatus::SYNC; |
200 } | 180 } |
201 | 181 |
202 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
203 << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ | |
204 << ")"; | |
205 out_cert_ = out_cert; | 182 out_cert_ = out_cert; |
206 callback_ = callback; | 183 callback_ = callback; |
207 return CompletionStatus::ASYNC; | 184 return CompletionStatus::ASYNC; |
208 } | 185 } |
209 | 186 |
210 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { | 187 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { |
211 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) | 188 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) |
212 << ")"; | 189 << ")"; |
| 190 DCHECK_EQ(pending_async_request_.get(), request); |
213 while (true) { | 191 while (true) { |
214 scoped_refptr<ParsedCertificate> cert; | 192 scoped_refptr<ParsedCertificate> cert; |
215 CompletionStatus status = request->GetNext(&cert); | 193 CompletionStatus status = request->GetNext(&cert); |
216 if (!cert) { | 194 if (!cert) { |
217 if (status == CompletionStatus::SYNC) { | 195 if (status == CompletionStatus::SYNC) { |
218 // Request is exhausted, no more results pending from that | 196 // Request is exhausted, no more results pending from the |
219 // CertIssuerSource. | 197 // CertIssuerSource. |
220 DCHECK_GT(pending_async_results_, 0U); | 198 pending_async_request_.reset(); |
221 pending_async_results_--; | |
222 } | 199 } |
223 break; | 200 break; |
224 } | 201 } |
225 DCHECK_EQ(status, CompletionStatus::SYNC); | 202 DCHECK_EQ(status, CompletionStatus::SYNC); |
226 if (present_issuers_.find(cert->der_cert().AsStringPiece()) != | 203 if (present_issuers_.find(cert->der_cert().AsStringPiece()) != |
227 present_issuers_.end()) | 204 present_issuers_.end()) |
228 continue; | 205 continue; |
229 present_issuers_.insert(cert->der_cert().AsStringPiece()); | 206 present_issuers_.insert(cert->der_cert().AsStringPiece()); |
230 issuers_.push_back(std::move(cert)); | 207 issuers_.push_back(std::move(cert)); |
231 } | 208 } |
232 | 209 |
233 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may | 210 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may |
234 // be more than the ones just inserted, depending on |cur_| value). | 211 // be more than the ones just inserted, depending on |cur_| value). |
235 | 212 |
236 // Notify that more results are available, if necessary. | 213 // Notify that more results are available, if necessary. |
237 if (!callback_.is_null()) { | 214 if (!callback_.is_null()) { |
238 if (cur_ < issuers_.size()) { | 215 if (cur_ < issuers_.size()) { |
239 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 216 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
240 << "): async returning item " << cur_ << " of " | 217 << "): async returning item " << cur_ << " of " |
241 << issuers_.size(); | 218 << issuers_.size(); |
242 *out_cert_ = std::move(issuers_[cur_++]); | 219 *out_cert_ = std::move(issuers_[cur_++]); |
243 base::ResetAndReturn(&callback_).Run(); | 220 base::ResetAndReturn(&callback_).Run(); |
244 } else if (pending_async_results_ == 0) { | 221 } else if (!pending_async_request_) { |
245 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 222 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
246 << "): async returning empty result"; | 223 << "): async returning empty result"; |
247 *out_cert_ = nullptr; | 224 *out_cert_ = nullptr; |
248 base::ResetAndReturn(&callback_).Run(); | 225 base::ResetAndReturn(&callback_).Run(); |
249 } else { | 226 } else { |
250 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 227 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
251 << "): empty result, but other async results " | 228 << "): empty result, but other async results " |
252 "pending, waiting.."; | 229 "pending, waiting.."; |
253 } | 230 } |
254 } | 231 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 std::set<Key> present_certs_; | 303 std::set<Key> present_certs_; |
327 }; | 304 }; |
328 | 305 |
329 } // namespace | 306 } // namespace |
330 | 307 |
331 // CertPathIter generates possible paths from |cert| to a trust anchor in | 308 // CertPathIter generates possible paths from |cert| to a trust anchor in |
332 // |trust_store|, using intermediates from the |cert_issuer_source| objects if | 309 // |trust_store|, using intermediates from the |cert_issuer_source| objects if |
333 // necessary. | 310 // necessary. |
334 class CertPathIter { | 311 class CertPathIter { |
335 public: | 312 public: |
336 CertPathIter(scoped_refptr<ParsedCertificate> cert, | 313 explicit CertPathIter(scoped_refptr<ParsedCertificate> cert); |
337 const TrustStore* trust_store); | 314 |
| 315 // Adds a TrustStore to check if certificates are trust anchors during path |
| 316 // building. The |*trust_store| must remain valid for the lifetime of the |
| 317 // CertPathIter. |
| 318 void AddTrustStore(TrustStore* trust_store); |
338 | 319 |
339 // Adds a CertIssuerSource to provide intermediates for use in path building. | 320 // Adds a CertIssuerSource to provide intermediates for use in path building. |
340 // The |*cert_issuer_source| must remain valid for the lifetime of the | 321 // The |*cert_issuer_source| must remain valid for the lifetime of the |
341 // CertPathIter. | 322 // CertPathIter. |
342 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); | 323 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); |
343 | 324 |
344 // Gets the next candidate path. If a path is ready synchronously, SYNC is | 325 // Gets the next candidate path. If a path is ready synchronously, SYNC is |
345 // returned and the path is stored in |*path|. If a path is not ready, | 326 // returned and the path is stored in |*path|. If a path is not ready, |
346 // ASYNC is returned and |callback| will be called once |*path| has been set. | 327 // ASYNC is returned and |callback| will be called once |*path| has been set. |
347 // In either case, if all paths have been exhausted, |*path| is cleared. | 328 // In either case, if all paths have been exhausted, |*path| is cleared. |
348 CompletionStatus GetNextPath(ParsedCertificateList* path, | 329 CompletionStatus GetNextPath(ParsedCertificateList* path, |
349 const base::Closure& callback); | 330 const base::Closure& callback); |
350 | 331 |
351 private: | 332 private: |
352 enum State { | 333 enum State { |
353 STATE_NONE, | 334 STATE_NONE, |
354 STATE_GET_NEXT_ISSUER, | 335 STATE_GET_NEXT_ISSUER, |
355 STATE_GET_NEXT_ISSUER_COMPLETE, | 336 STATE_GET_NEXT_ISSUER_COMPLETE, |
| 337 STATE_IS_NEXT_CERT_TRUSTED_COMPLETE, |
356 STATE_RETURN_A_PATH, | 338 STATE_RETURN_A_PATH, |
357 STATE_BACKTRACK, | 339 STATE_BACKTRACK, |
358 }; | 340 }; |
359 | 341 |
360 CompletionStatus DoLoop(bool allow_async); | 342 CompletionStatus DoLoop(bool allow_async); |
361 | 343 |
362 CompletionStatus DoGetNextIssuer(bool allow_async); | 344 CompletionStatus DoGetNextIssuer(bool allow_async); |
363 CompletionStatus DoGetNextIssuerComplete(); | 345 CompletionStatus DoGetNextIssuerComplete(bool allow_async); |
| 346 CompletionStatus DoIsNextCertTrustedComplete(); |
364 CompletionStatus DoBackTrack(); | 347 CompletionStatus DoBackTrack(); |
365 | 348 |
366 void HandleGotNextIssuer(void); | 349 void HandleGotNextIssuer(void); |
| 350 void HandleIsTrustedCertificate(bool is_trusted); |
367 | 351 |
368 // Stores the next candidate issuer certificate, until it is used during the | 352 // Stores the next candidate issuer certificate, until it is used during the |
369 // STATE_GET_NEXT_ISSUER_COMPLETE step. | 353 // STATE_GET_NEXT_ISSUER_COMPLETE step. |
370 scoped_refptr<ParsedCertificate> next_cert_; | 354 scoped_refptr<ParsedCertificate> next_cert_; |
371 // The current path being explored, made up of CertIssuerIters. Each node | 355 // The current path being explored, made up of CertIssuerIters. Each node |
372 // keeps track of the state of searching for issuers of that cert, so that | 356 // keeps track of the state of searching for issuers of that cert, so that |
373 // when backtracking it can resume the search where it left off. | 357 // when backtracking it can resume the search where it left off. |
374 CertIssuerIterPath cur_path_; | 358 CertIssuerIterPath cur_path_; |
375 // The CertIssuerSources for retrieving candidate issuers. | 359 // The CertIssuerSources for retrieving candidate issuers. |
376 CertIssuerSources cert_issuer_sources_; | 360 CertIssuerSourceCollection cert_issuer_source_collection_; |
377 // The TrustStore for checking if a path ends in a trust anchor. | 361 // The TrustStores for checking if a path ends in a trust anchor. |
378 const TrustStore* trust_store_; | 362 TrustStoreCollection trust_store_collection_; |
| 363 // Request handle for querying the TrustStoreCollection. |
| 364 std::unique_ptr<TrustStore::Request> trust_request_; |
| 365 // Stores the result of trust query for use in the |
| 366 // STATE_IS_NEXT_CERT_TRUSTED_COMPLETE state. |
| 367 bool is_pending_cert_trusted_; |
379 // The output variable for storing the next candidate path, which the client | 368 // The output variable for storing the next candidate path, which the client |
380 // passes in to GetNextPath. Only used for a single path output. | 369 // passes in to GetNextPath. Only used for a single path output. |
381 ParsedCertificateList* out_path_; | 370 ParsedCertificateList* out_path_; |
382 // The callback to be called if an async lookup generated a candidate path. | 371 // The callback to be called if an async lookup generated a candidate path. |
383 base::Closure callback_; | 372 base::Closure callback_; |
384 // Current state of the state machine. | 373 // Current state of the state machine. |
385 State next_state_; | 374 State next_state_; |
386 | 375 |
387 DISALLOW_COPY_AND_ASSIGN(CertPathIter); | 376 DISALLOW_COPY_AND_ASSIGN(CertPathIter); |
388 }; | 377 }; |
389 | 378 |
390 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, | 379 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert) |
391 const TrustStore* trust_store) | |
392 : next_cert_(std::move(cert)), | 380 : next_cert_(std::move(cert)), |
393 trust_store_(trust_store), | |
394 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} | 381 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} |
395 | 382 |
| 383 void CertPathIter::AddTrustStore(TrustStore* trust_store) { |
| 384 trust_store_collection_.AddStore(trust_store); |
| 385 cert_issuer_source_collection_.AddSource(trust_store); |
| 386 } |
| 387 |
396 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { | 388 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { |
397 cert_issuer_sources_.push_back(cert_issuer_source); | 389 cert_issuer_source_collection_.AddSource(cert_issuer_source); |
398 } | 390 } |
399 | 391 |
400 CompletionStatus CertPathIter::GetNextPath(ParsedCertificateList* path, | 392 CompletionStatus CertPathIter::GetNextPath(ParsedCertificateList* path, |
401 const base::Closure& callback) { | 393 const base::Closure& callback) { |
402 out_path_ = path; | 394 out_path_ = path; |
403 out_path_->clear(); | 395 out_path_->clear(); |
404 CompletionStatus rv = DoLoop(!callback.is_null()); | 396 CompletionStatus rv = DoLoop(!callback.is_null()); |
405 if (rv == CompletionStatus::ASYNC) { | 397 if (rv == CompletionStatus::ASYNC) { |
406 callback_ = callback; | 398 callback_ = callback; |
407 } else { | 399 } else { |
408 // Clear the reference to the output parameter as a precaution. | 400 // Clear the reference to the output parameter as a precaution. |
409 out_path_ = nullptr; | 401 out_path_ = nullptr; |
410 } | 402 } |
411 return rv; | 403 return rv; |
412 } | 404 } |
413 | 405 |
414 CompletionStatus CertPathIter::DoLoop(bool allow_async) { | 406 CompletionStatus CertPathIter::DoLoop(bool allow_async) { |
415 CompletionStatus result = CompletionStatus::SYNC; | 407 CompletionStatus result = CompletionStatus::SYNC; |
416 do { | 408 do { |
417 State state = next_state_; | 409 State state = next_state_; |
418 next_state_ = STATE_NONE; | 410 next_state_ = STATE_NONE; |
419 switch (state) { | 411 switch (state) { |
420 case STATE_NONE: | 412 case STATE_NONE: |
421 NOTREACHED(); | 413 NOTREACHED(); |
422 break; | 414 break; |
423 case STATE_GET_NEXT_ISSUER: | 415 case STATE_GET_NEXT_ISSUER: |
424 result = DoGetNextIssuer(allow_async); | 416 result = DoGetNextIssuer(allow_async); |
425 break; | 417 break; |
426 case STATE_GET_NEXT_ISSUER_COMPLETE: | 418 case STATE_GET_NEXT_ISSUER_COMPLETE: |
427 result = DoGetNextIssuerComplete(); | 419 result = DoGetNextIssuerComplete(allow_async); |
| 420 break; |
| 421 case STATE_IS_NEXT_CERT_TRUSTED_COMPLETE: |
| 422 result = DoIsNextCertTrustedComplete(); |
428 break; | 423 break; |
429 case STATE_RETURN_A_PATH: | 424 case STATE_RETURN_A_PATH: |
430 // If the returned path did not verify, keep looking for other paths | 425 // If the returned path did not verify, keep looking for other paths |
431 // (the trust root is not part of cur_path_, so don't need to | 426 // (the trust root is not part of cur_path_, so don't need to |
432 // backtrack). | 427 // backtrack). |
433 next_state_ = STATE_GET_NEXT_ISSUER; | 428 next_state_ = STATE_GET_NEXT_ISSUER; |
434 result = CompletionStatus::SYNC; | 429 result = CompletionStatus::SYNC; |
435 break; | 430 break; |
436 case STATE_BACKTRACK: | 431 case STATE_BACKTRACK: |
437 result = DoBackTrack(); | 432 result = DoBackTrack(); |
438 break; | 433 break; |
439 } | 434 } |
440 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && | 435 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && |
441 next_state_ != STATE_RETURN_A_PATH); | 436 next_state_ != STATE_RETURN_A_PATH); |
442 | 437 |
443 return result; | 438 return result; |
444 } | 439 } |
445 | 440 |
446 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { | 441 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { |
| 442 if (cur_path_.Empty()) { |
| 443 // If the target cert matched a trust root, but did not verify |
| 444 // successfully, cur_path_ will be empty. |
| 445 next_state_ = STATE_NONE; |
| 446 return CompletionStatus::SYNC; |
| 447 } |
447 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; | 448 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
448 CompletionStatus rv = cur_path_.back()->GetNextIssuer( | 449 CompletionStatus rv = cur_path_.back()->GetNextIssuer( |
449 &next_cert_, allow_async ? base::Bind(&CertPathIter::HandleGotNextIssuer, | 450 &next_cert_, allow_async ? base::Bind(&CertPathIter::HandleGotNextIssuer, |
450 base::Unretained(this)) | 451 base::Unretained(this)) |
451 : base::Closure()); | 452 : base::Closure()); |
452 return rv; | 453 return rv; |
453 } | 454 } |
454 | 455 |
455 CompletionStatus CertPathIter::DoGetNextIssuerComplete() { | 456 CompletionStatus CertPathIter::DoGetNextIssuerComplete(bool allow_async) { |
456 if (next_cert_) { | 457 if (next_cert_) { |
457 // Skip this cert if it is already in the chain. | 458 // Skip this cert if it is already in the chain. |
458 if (cur_path_.IsPresent(next_cert_.get())) { | 459 if (cur_path_.IsPresent(next_cert_.get())) { |
459 next_state_ = STATE_GET_NEXT_ISSUER; | 460 next_state_ = STATE_GET_NEXT_ISSUER; |
460 return CompletionStatus::SYNC; | 461 return CompletionStatus::SYNC; |
461 } | 462 } |
462 // If the cert matches a trust root, this is a (possibly) complete path. | 463 next_state_ = STATE_IS_NEXT_CERT_TRUSTED_COMPLETE; |
463 // Signal readiness. Don't add it to cur_path_, since that would cause an | 464 trust_store_collection_.IsTrustedCertificate( |
464 // unnecessary lookup of issuers of the trust root. | 465 next_cert_.get(), |
465 if (trust_store_->IsTrustedCertificate(next_cert_.get())) { | 466 allow_async ? base::Bind(&CertPathIter::HandleIsTrustedCertificate, |
466 DVLOG(1) << "CertPathIter IsTrustedCertificate(" | 467 base::Unretained(this)) |
467 << CertDebugString(next_cert_.get()) << ") = true"; | 468 : TrustStore::TrustCallback(), |
468 next_state_ = STATE_RETURN_A_PATH; | 469 &is_pending_cert_trusted_, &trust_request_); |
469 cur_path_.CopyPath(out_path_); | 470 return trust_request_ ? CompletionStatus::ASYNC : CompletionStatus::SYNC; |
470 out_path_->push_back(std::move(next_cert_)); | |
471 next_cert_ = nullptr; | |
472 return CompletionStatus::SYNC; | |
473 } | |
474 | |
475 cur_path_.Append(base::WrapUnique(new CertIssuersIter( | |
476 std::move(next_cert_), &cert_issuer_sources_, *trust_store_))); | |
477 next_cert_ = nullptr; | |
478 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); | |
479 // Continue descending the tree. | |
480 next_state_ = STATE_GET_NEXT_ISSUER; | |
481 } else { | 471 } else { |
482 // TODO(mattm): should also include such paths in CertPathBuilder::Result, | 472 // TODO(mattm): should also include such paths in CertPathBuilder::Result, |
483 // maybe with a flag to enable it. Or use a visitor pattern so the caller | 473 // maybe with a flag to enable it. Or use a visitor pattern so the caller |
484 // can decide what to do with any failed paths. | 474 // can decide what to do with any failed paths. |
485 // No more issuers for current chain, go back up and see if there are any | 475 // No more issuers for current chain, go back up and see if there are any |
486 // more for the previous cert. | 476 // more for the previous cert. |
487 next_state_ = STATE_BACKTRACK; | 477 next_state_ = STATE_BACKTRACK; |
488 } | 478 } |
489 return CompletionStatus::SYNC; | 479 return CompletionStatus::SYNC; |
490 } | 480 } |
491 | 481 |
| 482 CompletionStatus CertPathIter::DoIsNextCertTrustedComplete() { |
| 483 // If the cert matches a trust root, this is a (possibly) complete path. |
| 484 // Signal readiness. Don't add it to cur_path_, since that would cause an |
| 485 // unnecessary lookup of issuers of the trust root. |
| 486 if (is_pending_cert_trusted_) { |
| 487 DVLOG(1) << "CertPathIter IsTrustedCertificate(" |
| 488 << CertDebugString(next_cert_.get()) << ") = true"; |
| 489 next_state_ = STATE_RETURN_A_PATH; |
| 490 cur_path_.CopyPath(out_path_); |
| 491 out_path_->push_back(std::move(next_cert_)); |
| 492 next_cert_ = nullptr; |
| 493 return CompletionStatus::SYNC; |
| 494 } |
| 495 |
| 496 cur_path_.Append(base::WrapUnique(new CertIssuersIter( |
| 497 std::move(next_cert_), &cert_issuer_source_collection_))); |
| 498 next_cert_ = nullptr; |
| 499 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); |
| 500 // Continue descending the tree. |
| 501 next_state_ = STATE_GET_NEXT_ISSUER; |
| 502 return CompletionStatus::SYNC; |
| 503 } |
| 504 |
492 CompletionStatus CertPathIter::DoBackTrack() { | 505 CompletionStatus CertPathIter::DoBackTrack() { |
493 DVLOG(1) << "CertPathIter backtracking..."; | 506 DVLOG(1) << "CertPathIter backtracking..."; |
494 cur_path_.Pop(); | 507 cur_path_.Pop(); |
495 if (cur_path_.Empty()) { | 508 if (cur_path_.Empty()) { |
496 // Exhausted all paths. | 509 // Exhausted all paths. |
497 next_state_ = STATE_NONE; | 510 next_state_ = STATE_NONE; |
498 } else { | 511 } else { |
499 // Continue exploring issuers of the previous path. | 512 // Continue exploring issuers of the previous path. |
500 next_state_ = STATE_GET_NEXT_ISSUER; | 513 next_state_ = STATE_GET_NEXT_ISSUER; |
501 } | 514 } |
502 return CompletionStatus::SYNC; | 515 return CompletionStatus::SYNC; |
503 } | 516 } |
504 | 517 |
505 void CertPathIter::HandleGotNextIssuer(void) { | 518 void CertPathIter::HandleGotNextIssuer(void) { |
506 DCHECK(!callback_.is_null()); | 519 DCHECK(!callback_.is_null()); |
507 CompletionStatus rv = DoLoop(true /* allow_async */); | 520 CompletionStatus rv = DoLoop(true /* allow_async */); |
508 if (rv == CompletionStatus::SYNC) { | 521 if (rv == CompletionStatus::SYNC) { |
509 // Clear the reference to the output parameter as a precaution. | 522 // Clear the reference to the output parameter as a precaution. |
510 out_path_ = nullptr; | 523 out_path_ = nullptr; |
511 base::ResetAndReturn(&callback_).Run(); | 524 base::ResetAndReturn(&callback_).Run(); |
512 } | 525 } |
513 } | 526 } |
514 | 527 |
| 528 void CertPathIter::HandleIsTrustedCertificate(bool is_trusted) { |
| 529 DCHECK(!callback_.is_null()); |
| 530 is_pending_cert_trusted_ = is_trusted; |
| 531 CompletionStatus rv = DoLoop(true /* allow_async */); |
| 532 if (rv == CompletionStatus::SYNC) |
| 533 base::ResetAndReturn(&callback_).Run(); |
| 534 } |
| 535 |
515 CertPathBuilder::ResultPath::ResultPath() = default; | 536 CertPathBuilder::ResultPath::ResultPath() = default; |
516 CertPathBuilder::ResultPath::~ResultPath() = default; | 537 CertPathBuilder::ResultPath::~ResultPath() = default; |
517 CertPathBuilder::Result::Result() = default; | 538 CertPathBuilder::Result::Result() = default; |
518 CertPathBuilder::Result::~Result() = default; | 539 CertPathBuilder::Result::~Result() = default; |
519 | 540 |
520 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, | 541 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, |
521 const TrustStore* trust_store, | |
522 const SignaturePolicy* signature_policy, | 542 const SignaturePolicy* signature_policy, |
523 const der::GeneralizedTime& time, | 543 const der::GeneralizedTime& time, |
524 Result* result) | 544 Result* result) |
525 : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)), | 545 : cert_path_iter_(new CertPathIter(std::move(cert))), |
526 trust_store_(trust_store), | |
527 signature_policy_(signature_policy), | 546 signature_policy_(signature_policy), |
528 time_(time), | 547 time_(time), |
529 next_state_(STATE_NONE), | 548 next_state_(STATE_NONE), |
530 out_result_(result) {} | 549 out_result_(result) {} |
531 | 550 |
532 CertPathBuilder::~CertPathBuilder() {} | 551 CertPathBuilder::~CertPathBuilder() {} |
533 | 552 |
| 553 void CertPathBuilder::AddTrustStore(TrustStore* trust_store) { |
| 554 cert_path_iter_->AddTrustStore(trust_store); |
| 555 } |
| 556 |
534 void CertPathBuilder::AddCertIssuerSource( | 557 void CertPathBuilder::AddCertIssuerSource( |
535 CertIssuerSource* cert_issuer_source) { | 558 CertIssuerSource* cert_issuer_source) { |
536 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); | 559 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); |
537 } | 560 } |
538 | 561 |
539 CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { | 562 CompletionStatus CertPathBuilder::Run(const base::Closure& callback) { |
540 DCHECK_EQ(STATE_NONE, next_state_); | 563 DCHECK_EQ(STATE_NONE, next_state_); |
541 next_state_ = STATE_GET_NEXT_PATH; | 564 next_state_ = STATE_GET_NEXT_PATH; |
542 CompletionStatus rv = DoLoop(!callback.is_null()); | 565 CompletionStatus rv = DoLoop(!callback.is_null()); |
543 | 566 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 } | 609 } |
587 | 610 |
588 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { | 611 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { |
589 if (next_path_.empty()) { | 612 if (next_path_.empty()) { |
590 // No more paths to check, signal completion. | 613 // No more paths to check, signal completion. |
591 next_state_ = STATE_NONE; | 614 next_state_ = STATE_NONE; |
592 return CompletionStatus::SYNC; | 615 return CompletionStatus::SYNC; |
593 } | 616 } |
594 | 617 |
595 bool verify_result = VerifyCertificateChainAssumingTrustedRoot( | 618 bool verify_result = VerifyCertificateChainAssumingTrustedRoot( |
596 next_path_, *trust_store_, signature_policy_, time_); | 619 next_path_, signature_policy_, time_); |
597 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " | 620 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " |
598 << verify_result; | 621 << verify_result; |
599 AddResultPath(next_path_, verify_result); | 622 AddResultPath(next_path_, verify_result); |
600 | 623 |
601 if (verify_result) { | 624 if (verify_result) { |
602 // Found a valid path, return immediately. | 625 // Found a valid path, return immediately. |
603 // TODO(mattm): add debug/test mode that tries all possible paths. | 626 // TODO(mattm): add debug/test mode that tries all possible paths. |
604 next_state_ = STATE_NONE; | 627 next_state_ = STATE_NONE; |
605 return CompletionStatus::SYNC; | 628 return CompletionStatus::SYNC; |
606 } | 629 } |
(...skipping 12 matching lines...) Expand all Loading... |
619 result_path->error = is_success ? OK : ERR_CERT_AUTHORITY_INVALID; | 642 result_path->error = is_success ? OK : ERR_CERT_AUTHORITY_INVALID; |
620 // TODO(mattm): set best_result_index based on number or severity of errors. | 643 // TODO(mattm): set best_result_index based on number or severity of errors. |
621 if (result_path->error == OK) | 644 if (result_path->error == OK) |
622 out_result_->best_result_index = out_result_->paths.size(); | 645 out_result_->best_result_index = out_result_->paths.size(); |
623 // TODO(mattm): add flag to only return a single path or all attempted paths? | 646 // TODO(mattm): add flag to only return a single path or all attempted paths? |
624 result_path->path = path; | 647 result_path->path = path; |
625 out_result_->paths.push_back(std::move(result_path)); | 648 out_result_->paths.push_back(std::move(result_path)); |
626 } | 649 } |
627 | 650 |
628 } // namespace net | 651 } // namespace net |
OLD | NEW |