Chromium Code Reviews| 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/logging.h" | |
| 11 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
| 12 #include "net/base/net_errors.h" | 13 #include "net/base/net_errors.h" |
| 13 #include "net/cert/internal/cert_issuer_source.h" | 14 #include "net/cert/internal/cert_issuer_source.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" |
| 18 #include "net/cert/internal/verify_certificate_chain.h" | 19 #include "net/cert/internal/verify_certificate_chain.h" |
| 19 #include "net/cert/internal/verify_name_match.h" | 20 #include "net/cert/internal/verify_name_match.h" |
| 20 #include "net/der/parser.h" | 21 #include "net/der/parser.h" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 33 if (!ParseName(cert->tbs().subject_tlv, &subject) || | 34 if (!ParseName(cert->tbs().subject_tlv, &subject) || |
| 34 !ConvertToRFC2253(subject, &subject_str)) | 35 !ConvertToRFC2253(subject, &subject_str)) |
| 35 subject_str = "???"; | 36 subject_str = "???"; |
| 36 if (!ParseName(cert->tbs().issuer_tlv, &issuer) || | 37 if (!ParseName(cert->tbs().issuer_tlv, &issuer) || |
| 37 !ConvertToRFC2253(issuer, &issuer_str)) | 38 !ConvertToRFC2253(issuer, &issuer_str)) |
| 38 issuer_str = "???"; | 39 issuer_str = "???"; |
| 39 | 40 |
| 40 return subject_str + "(" + issuer_str + ")"; | 41 return subject_str + "(" + issuer_str + ")"; |
| 41 } | 42 } |
| 42 | 43 |
| 44 // This structure contains either a ParsedCertificate or a TrustAnchor. It is | |
| 45 // used to describe the result of getting a certificate's issuer, which may | |
| 46 // either be another certificate, or a trust anchor. | |
| 47 struct CertificateOrTrustAnchor { | |
| 48 CertificateOrTrustAnchor() {} | |
| 49 | |
| 50 explicit CertificateOrTrustAnchor(scoped_refptr<ParsedCertificate> cert) | |
| 51 : cert(std::move(cert)) {} | |
| 52 | |
| 53 explicit CertificateOrTrustAnchor(scoped_refptr<TrustAnchor> anchor) | |
| 54 : anchor(std::move(anchor)) {} | |
| 55 | |
| 56 bool IsTrustAnchor() const { return anchor.get() != nullptr; } | |
| 57 bool IsCertificate() const { return cert.get() != nullptr; } | |
| 58 bool IsEmpty() const { return !IsTrustAnchor() && !IsCertificate(); } | |
| 59 | |
| 60 scoped_refptr<ParsedCertificate> cert; | |
| 61 scoped_refptr<TrustAnchor> anchor; | |
| 62 }; | |
| 63 | |
| 43 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| | 64 // CertIssuersIter iterates through the intermediates from |cert_issuer_sources| |
| 44 // which may be issuers of |cert|. | 65 // which may be issuers of |cert|. |
| 45 class CertIssuersIter { | 66 class CertIssuersIter { |
| 46 public: | 67 public: |
| 47 // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for | 68 // Constructs the CertIssuersIter. |*cert_issuer_sources| must be valid for |
| 48 // the lifetime of the CertIssuersIter. | 69 // the lifetime of the CertIssuersIter. |
| 49 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, | 70 CertIssuersIter(scoped_refptr<ParsedCertificate> cert, |
| 50 CertIssuerSources* cert_issuer_sources, | 71 CertIssuerSources* cert_issuer_sources, |
| 51 const TrustStore& trust_store); | 72 const TrustStore& trust_store); |
| 52 | 73 |
| 53 // Gets the next candidate issuer. If an issuer is ready synchronously, SYNC | 74 // 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 | 75 // is returned and the cert is stored in |*cert|. If an issuer is not |
| 55 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has | 76 // ready, ASYNC is returned and |callback| will be called once |*out_cert| has |
| 56 // been set. If |callback| is null, always completes synchronously. | 77 // been set. If |callback| is null, always completes synchronously. |
| 57 // | 78 // |
| 58 // In either case, if all issuers have been exhausted, |*out_cert| is cleared. | 79 // In either case, if all issuers have been exhausted, |*out| is cleared. |
| 59 CompletionStatus GetNextIssuer(scoped_refptr<ParsedCertificate>* out_cert, | 80 CompletionStatus GetNextIssuer(CertificateOrTrustAnchor* out, |
| 60 const base::Closure& callback); | 81 const base::Closure& callback); |
| 61 | 82 |
| 62 // Returns the |cert| for which issuers are being retrieved. | 83 // Returns the |cert| for which issuers are being retrieved. |
| 63 const ParsedCertificate* cert() const { return cert_.get(); } | 84 const ParsedCertificate* cert() const { return cert_.get(); } |
| 64 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } | 85 scoped_refptr<ParsedCertificate> reference_cert() const { return cert_; } |
| 65 | 86 |
| 66 private: | 87 private: |
| 67 void GotAsyncCerts(CertIssuerSource::Request* request); | 88 void GotAsyncCerts(CertIssuerSource::Request* request); |
| 68 | 89 |
| 69 scoped_refptr<ParsedCertificate> cert_; | 90 scoped_refptr<ParsedCertificate> cert_; |
| 70 CertIssuerSources* cert_issuer_sources_; | 91 CertIssuerSources* cert_issuer_sources_; |
| 71 | 92 |
| 93 // The list of trust anchors that match the issuer name for |cert_|. | |
| 94 TrustAnchors anchors_; | |
| 95 // The index of the next trust anchor in |anchors_| to return. | |
| 96 size_t cur_anchor_ = 0; | |
| 97 | |
| 72 // The list of issuers for |cert_|. This is added to incrementally (first | 98 // The list of issuers for |cert_|. This is added to incrementally (first |
| 73 // synchronous results, then possibly multiple times as asynchronous results | 99 // synchronous results, then possibly multiple times as asynchronous results |
| 74 // arrive.) The issuers may be re-sorted each time new issuers are added, but | 100 // 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 | 101 // only the results from |cur_| onwards should be sorted, since the earlier |
| 76 // results were already returned. | 102 // results were already returned. |
| 77 // Elements should not be removed from |issuers_| once added, since | 103 // Elements should not be removed from |issuers_| once added, since |
| 78 // |present_issuers_| will point to data owned by the certs. | 104 // |present_issuers_| will point to data owned by the certs. |
| 79 ParsedCertificateList issuers_; | 105 ParsedCertificateList issuers_; |
| 80 // The index of the next cert in |issuers_| to return. | 106 // The index of the next cert in |issuers_| to return. |
| 81 size_t cur_ = 0; | 107 size_t cur_issuer_ = 0; |
| 108 | |
| 82 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent | 109 // 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 | 110 // 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. | 111 // versions of the same certificate to be tried in different candidate paths. |
| 85 // This points to data owned by |issuers_|. | 112 // This points to data owned by |issuers_|. |
| 86 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; | 113 std::unordered_set<base::StringPiece, base::StringPieceHash> present_issuers_; |
| 87 | 114 |
| 88 // Tracks whether asynchronous requests have been made yet. | 115 // Tracks whether asynchronous requests have been made yet. |
| 89 bool did_async_query_ = false; | 116 bool did_async_query_ = false; |
| 90 // If asynchronous requests were made, how many of them are still outstanding? | 117 // If asynchronous requests were made, how many of them are still outstanding? |
| 91 size_t pending_async_results_; | 118 size_t pending_async_results_; |
| 92 // Owns the Request objects for any asynchronous requests so that they will be | 119 // Owns the Request objects for any asynchronous requests so that they will be |
| 93 // cancelled if CertIssuersIter is destroyed. | 120 // cancelled if CertIssuersIter is destroyed. |
| 94 std::vector<std::unique_ptr<CertIssuerSource::Request>> | 121 std::vector<std::unique_ptr<CertIssuerSource::Request>> |
| 95 pending_async_requests_; | 122 pending_async_requests_; |
| 96 | 123 |
| 97 // When GetNextIssuer was called and returned asynchronously, |*out_cert_| is | 124 // When GetNextIssuer was called and returned asynchronously, |*out_| is |
| 98 // where the result will be stored, and |callback_| will be run when the | 125 // where the result will be stored, and |callback_| will be run when the |
| 99 // result is ready. | 126 // result is ready. |
| 100 scoped_refptr<ParsedCertificate>* out_cert_; | 127 CertificateOrTrustAnchor* out_; |
| 101 base::Closure callback_; | 128 base::Closure callback_; |
| 102 | 129 |
| 103 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); | 130 DISALLOW_COPY_AND_ASSIGN(CertIssuersIter); |
| 104 }; | 131 }; |
| 105 | 132 |
| 106 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, | 133 CertIssuersIter::CertIssuersIter(scoped_refptr<ParsedCertificate> in_cert, |
| 107 CertIssuerSources* cert_issuer_sources, | 134 CertIssuerSources* cert_issuer_sources, |
| 108 const TrustStore& trust_store) | 135 const TrustStore& trust_store) |
| 109 : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) { | 136 : cert_(in_cert), cert_issuer_sources_(cert_issuer_sources) { |
| 110 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; | 137 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) << ") created"; |
| 111 trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(), | 138 trust_store.FindTrustAnchorsByNormalizedName(in_cert->normalized_issuer(), |
| 112 &issuers_); | 139 &anchors_); |
| 113 // Insert matching roots into |present_issuers_| in case they also are | |
| 114 // returned by a CertIssuerSource. It is assumed | |
| 115 // FindTrustAnchorsByNormalizedName does not itself return dupes. | |
| 116 for (const auto& root : issuers_) | |
| 117 present_issuers_.insert(root->der_cert().AsStringPiece()); | |
|
mattm
2016/08/09 00:59:21
Since this is removed there would be the possibili
eroman
2016/08/09 01:37:20
I am not sure that limiting is needed for correctn
mattm
2016/08/09 19:51:04
Yeah, I was thinking of avoiding unnecessary work
eroman
2016/08/09 23:42:07
Thanks, I have added that as a test.
I have some
| |
| 118 | 140 |
| 119 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 141 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
| 120 ParsedCertificateList new_issuers; | 142 ParsedCertificateList new_issuers; |
| 121 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); | 143 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers); |
| 122 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { | 144 for (scoped_refptr<ParsedCertificate>& issuer : new_issuers) { |
| 123 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != | 145 if (present_issuers_.find(issuer->der_cert().AsStringPiece()) != |
| 124 present_issuers_.end()) | 146 present_issuers_.end()) |
| 125 continue; | 147 continue; |
| 126 present_issuers_.insert(issuer->der_cert().AsStringPiece()); | 148 present_issuers_.insert(issuer->der_cert().AsStringPiece()); |
| 127 issuers_.push_back(std::move(issuer)); | 149 issuers_.push_back(std::move(issuer)); |
| 128 } | 150 } |
| 129 } | 151 } |
| 130 // TODO(mattm): sort by notbefore, etc (eg if cert issuer matches a trust | 152 // 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. | 153 // anchor subject (or is a trust anchor), that should be sorted higher too. |
| 132 // See big list of possible sorting hints in RFC 4158.) | 154 // See big list of possible sorting hints in RFC 4158.) |
| 133 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that | 155 // (Update PathBuilderKeyRolloverTest.TestRolloverBothRootsTrusted once that |
| 134 // is done) | 156 // is done) |
| 135 } | 157 } |
| 136 | 158 |
| 137 CompletionStatus CertIssuersIter::GetNextIssuer( | 159 CompletionStatus CertIssuersIter::GetNextIssuer(CertificateOrTrustAnchor* out, |
| 138 scoped_refptr<ParsedCertificate>* out_cert, | 160 const base::Closure& callback) { |
| 139 const base::Closure& callback) { | |
| 140 // Should not be called again while already waiting for an async result. | 161 // Should not be called again while already waiting for an async result. |
| 141 DCHECK(callback_.is_null()); | 162 DCHECK(callback_.is_null()); |
| 142 | 163 |
| 143 if (cur_ < issuers_.size()) { | 164 // Return possible trust anchors first. |
| 165 if (cur_anchor_ < anchors_.size()) { | |
| 144 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 166 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 145 << "): returning item " << cur_ << " of " << issuers_.size(); | 167 << "): returning anchor " << cur_anchor_ << " of " |
| 168 << anchors_.size(); | |
| 169 // Still have anchors that haven't been returned yet, return one of them. | |
| 170 *out = CertificateOrTrustAnchor(anchors_[cur_anchor_++]); | |
| 171 return CompletionStatus::SYNC; | |
| 172 } | |
| 173 | |
| 174 if (cur_issuer_ < issuers_.size()) { | |
| 175 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | |
| 176 << "): returning issuer " << cur_issuer_ << " of " | |
| 177 << issuers_.size(); | |
| 146 // Still have issuers that haven't been returned yet, return one of them. | 178 // 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_| | 179 // A reference to the returned issuer is retained, since |present_issuers_| |
| 148 // points to data owned by it. | 180 // points to data owned by it. |
| 149 *out_cert = issuers_[cur_++]; | 181 *out = CertificateOrTrustAnchor(issuers_[cur_issuer_++]); |
| 150 return CompletionStatus::SYNC; | 182 return CompletionStatus::SYNC; |
| 151 } | 183 } |
| 152 if (did_async_query_) { | 184 if (did_async_query_) { |
| 153 if (pending_async_results_ == 0) { | 185 if (pending_async_results_ == 0) { |
| 154 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 186 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 155 << ") Reached the end of all available issuers."; | 187 << ") Reached the end of all available issuers."; |
| 156 // Reached the end of all available issuers. | 188 // Reached the end of all available issuers. |
| 157 *out_cert = nullptr; | 189 *out = CertificateOrTrustAnchor(); |
| 158 return CompletionStatus::SYNC; | 190 return CompletionStatus::SYNC; |
| 159 } | 191 } |
| 160 | 192 |
| 161 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 193 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 162 << ") Still waiting for async results from other " | 194 << ") Still waiting for async results from other " |
| 163 "CertIssuerSources."; | 195 "CertIssuerSources."; |
| 164 // Still waiting for async results from other CertIssuerSources. | 196 // Still waiting for async results from other CertIssuerSources. |
| 165 out_cert_ = out_cert; | 197 out_ = out; |
| 166 callback_ = callback; | 198 callback_ = callback; |
| 167 return CompletionStatus::ASYNC; | 199 return CompletionStatus::ASYNC; |
| 168 } | 200 } |
| 169 // Reached the end of synchronously gathered issuers. | 201 // Reached the end of synchronously gathered issuers. |
| 170 | 202 |
| 171 if (callback.is_null()) { | 203 if (callback.is_null()) { |
| 172 // Synchronous-only mode, don't try to query async sources. | 204 // Synchronous-only mode, don't try to query async sources. |
| 173 *out_cert = nullptr; | 205 *out = CertificateOrTrustAnchor(); |
| 174 return CompletionStatus::SYNC; | 206 return CompletionStatus::SYNC; |
| 175 } | 207 } |
| 176 | 208 |
| 177 // Now issue request(s) for async ones (AIA, etc). | 209 // Now issue request(s) for async ones (AIA, etc). |
| 178 did_async_query_ = true; | 210 did_async_query_ = true; |
| 179 pending_async_results_ = 0; | 211 pending_async_results_ = 0; |
| 180 for (auto* cert_issuer_source : *cert_issuer_sources_) { | 212 for (auto* cert_issuer_source : *cert_issuer_sources_) { |
| 181 std::unique_ptr<CertIssuerSource::Request> request; | 213 std::unique_ptr<CertIssuerSource::Request> request; |
| 182 cert_issuer_source->AsyncGetIssuersOf( | 214 cert_issuer_source->AsyncGetIssuersOf( |
| 183 cert(), | 215 cert(), |
| 184 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), | 216 base::Bind(&CertIssuersIter::GotAsyncCerts, base::Unretained(this)), |
| 185 &request); | 217 &request); |
| 186 if (request) { | 218 if (request) { |
| 187 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) | 219 DVLOG(1) << "AsyncGetIssuersOf(" << CertDebugString(cert()) |
| 188 << ") pending..."; | 220 << ") pending..."; |
| 189 pending_async_results_++; | 221 pending_async_results_++; |
| 190 pending_async_requests_.push_back(std::move(request)); | 222 pending_async_requests_.push_back(std::move(request)); |
| 191 } | 223 } |
| 192 } | 224 } |
| 193 | 225 |
| 194 if (pending_async_results_ == 0) { | 226 if (pending_async_results_ == 0) { |
| 195 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 227 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 196 << ") No cert sources have async results."; | 228 << ") No cert sources have async results."; |
| 197 // No cert sources have async results. | 229 // No cert sources have async results. |
| 198 *out_cert = nullptr; | 230 *out = CertificateOrTrustAnchor(); |
| 199 return CompletionStatus::SYNC; | 231 return CompletionStatus::SYNC; |
| 200 } | 232 } |
| 201 | 233 |
| 202 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 234 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 203 << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ | 235 << ") issued AsyncGetIssuersOf call(s) (n=" << pending_async_results_ |
| 204 << ")"; | 236 << ")"; |
| 205 out_cert_ = out_cert; | 237 out_ = out; |
| 206 callback_ = callback; | 238 callback_ = callback; |
| 207 return CompletionStatus::ASYNC; | 239 return CompletionStatus::ASYNC; |
| 208 } | 240 } |
| 209 | 241 |
| 210 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { | 242 void CertIssuersIter::GotAsyncCerts(CertIssuerSource::Request* request) { |
| 211 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) | 243 DVLOG(1) << "CertIssuersIter::GotAsyncCerts(" << CertDebugString(cert()) |
| 212 << ")"; | 244 << ")"; |
| 213 while (true) { | 245 while (true) { |
| 214 scoped_refptr<ParsedCertificate> cert; | 246 scoped_refptr<ParsedCertificate> cert; |
| 215 CompletionStatus status = request->GetNext(&cert); | 247 CompletionStatus status = request->GetNext(&cert); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 228 continue; | 260 continue; |
| 229 present_issuers_.insert(cert->der_cert().AsStringPiece()); | 261 present_issuers_.insert(cert->der_cert().AsStringPiece()); |
| 230 issuers_.push_back(std::move(cert)); | 262 issuers_.push_back(std::move(cert)); |
| 231 } | 263 } |
| 232 | 264 |
| 233 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may | 265 // TODO(mattm): re-sort remaining elements of issuers_ (remaining elements may |
| 234 // be more than the ones just inserted, depending on |cur_| value). | 266 // be more than the ones just inserted, depending on |cur_| value). |
| 235 | 267 |
| 236 // Notify that more results are available, if necessary. | 268 // Notify that more results are available, if necessary. |
| 237 if (!callback_.is_null()) { | 269 if (!callback_.is_null()) { |
| 238 if (cur_ < issuers_.size()) { | 270 DCHECK_GE(cur_anchor_, anchors_.size()); |
| 271 if (cur_issuer_ < issuers_.size()) { | |
| 239 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 272 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 240 << "): async returning item " << cur_ << " of " | 273 << "): async returning item " << cur_issuer_ << " of " |
| 241 << issuers_.size(); | 274 << issuers_.size(); |
| 242 *out_cert_ = std::move(issuers_[cur_++]); | 275 *out_ = CertificateOrTrustAnchor(std::move(issuers_[cur_issuer_++])); |
| 243 base::ResetAndReturn(&callback_).Run(); | 276 base::ResetAndReturn(&callback_).Run(); |
| 244 } else if (pending_async_results_ == 0) { | 277 } else if (pending_async_results_ == 0) { |
| 245 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 278 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 246 << "): async returning empty result"; | 279 << "): async returning empty result"; |
| 247 *out_cert_ = nullptr; | 280 *out_ = CertificateOrTrustAnchor(); |
| 248 base::ResetAndReturn(&callback_).Run(); | 281 base::ResetAndReturn(&callback_).Run(); |
| 249 } else { | 282 } else { |
| 250 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) | 283 DVLOG(1) << "CertIssuersIter(" << CertDebugString(cert()) |
| 251 << "): empty result, but other async results " | 284 << "): empty result, but other async results " |
| 252 "pending, waiting.."; | 285 "pending, waiting.."; |
| 253 } | 286 } |
| 254 } | 287 } |
| 255 } | 288 } |
| 256 | 289 |
| 257 // CertIssuerIterPath tracks which certs are present in the path and prevents | 290 // CertIssuerIterPath tracks which certs are present in the path and prevents |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 321 | 354 |
| 322 std::vector<std::unique_ptr<CertIssuersIter>> cur_path_; | 355 std::vector<std::unique_ptr<CertIssuersIter>> cur_path_; |
| 323 | 356 |
| 324 // This refers to data owned by |cur_path_|. | 357 // This refers to data owned by |cur_path_|. |
| 325 // TODO(mattm): use unordered_set. Requires making a hash function for Key. | 358 // TODO(mattm): use unordered_set. Requires making a hash function for Key. |
| 326 std::set<Key> present_certs_; | 359 std::set<Key> present_certs_; |
| 327 }; | 360 }; |
| 328 | 361 |
| 329 } // namespace | 362 } // namespace |
| 330 | 363 |
| 364 CertPath::CertPath() = default; | |
| 365 CertPath::~CertPath() = default; | |
| 366 | |
| 367 void CertPath::Clear() { | |
| 368 trust_anchor = nullptr; | |
| 369 certs.clear(); | |
| 370 } | |
| 371 | |
| 372 bool CertPath::IsEmpty() const { | |
| 373 return certs.empty(); | |
| 374 } | |
| 375 | |
| 331 // CertPathIter generates possible paths from |cert| to a trust anchor in | 376 // CertPathIter generates possible paths from |cert| to a trust anchor in |
| 332 // |trust_store|, using intermediates from the |cert_issuer_source| objects if | 377 // |trust_store|, using intermediates from the |cert_issuer_source| objects if |
| 333 // necessary. | 378 // necessary. |
| 334 class CertPathIter { | 379 class CertPathIter { |
| 335 public: | 380 public: |
| 336 CertPathIter(scoped_refptr<ParsedCertificate> cert, | 381 CertPathIter(scoped_refptr<ParsedCertificate> cert, |
| 337 const TrustStore* trust_store); | 382 const TrustStore* trust_store); |
| 338 | 383 |
| 339 // Adds a CertIssuerSource to provide intermediates for use in path building. | 384 // Adds a CertIssuerSource to provide intermediates for use in path building. |
| 340 // The |*cert_issuer_source| must remain valid for the lifetime of the | 385 // The |*cert_issuer_source| must remain valid for the lifetime of the |
| 341 // CertPathIter. | 386 // CertPathIter. |
| 342 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); | 387 void AddCertIssuerSource(CertIssuerSource* cert_issuer_source); |
| 343 | 388 |
| 344 // Gets the next candidate path. If a path is ready synchronously, SYNC is | 389 // 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, | 390 // 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. | 391 // 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. | 392 // In either case, if all paths have been exhausted, |*path| is cleared. |
| 348 CompletionStatus GetNextPath(ParsedCertificateList* path, | 393 CompletionStatus GetNextPath(CertPath* path, const base::Closure& callback); |
| 349 const base::Closure& callback); | |
| 350 | 394 |
| 351 private: | 395 private: |
| 352 enum State { | 396 enum State { |
| 353 STATE_NONE, | 397 STATE_NONE, |
| 354 STATE_GET_NEXT_ISSUER, | 398 STATE_GET_NEXT_ISSUER, |
| 355 STATE_GET_NEXT_ISSUER_COMPLETE, | 399 STATE_GET_NEXT_ISSUER_COMPLETE, |
| 356 STATE_RETURN_A_PATH, | 400 STATE_RETURN_A_PATH, |
| 357 STATE_BACKTRACK, | 401 STATE_BACKTRACK, |
| 358 }; | 402 }; |
| 359 | 403 |
| 360 CompletionStatus DoLoop(bool allow_async); | 404 CompletionStatus DoLoop(bool allow_async); |
| 361 | 405 |
| 362 CompletionStatus DoGetNextIssuer(bool allow_async); | 406 CompletionStatus DoGetNextIssuer(bool allow_async); |
| 363 CompletionStatus DoGetNextIssuerComplete(); | 407 CompletionStatus DoGetNextIssuerComplete(); |
| 364 CompletionStatus DoBackTrack(); | 408 CompletionStatus DoBackTrack(); |
| 365 | 409 |
| 366 void HandleGotNextIssuer(void); | 410 void HandleGotNextIssuer(void); |
| 367 | 411 |
| 368 // Stores the next candidate issuer certificate, until it is used during the | 412 // Stores the next candidate issuer, until it is used during the |
| 369 // STATE_GET_NEXT_ISSUER_COMPLETE step. | 413 // STATE_GET_NEXT_ISSUER_COMPLETE step. |
| 370 scoped_refptr<ParsedCertificate> next_cert_; | 414 CertificateOrTrustAnchor next_issuer_; |
| 371 // The current path being explored, made up of CertIssuerIters. Each node | 415 // 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 | 416 // 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. | 417 // when backtracking it can resume the search where it left off. |
| 374 CertIssuerIterPath cur_path_; | 418 CertIssuerIterPath cur_path_; |
| 375 // The CertIssuerSources for retrieving candidate issuers. | 419 // The CertIssuerSources for retrieving candidate issuers. |
| 376 CertIssuerSources cert_issuer_sources_; | 420 CertIssuerSources cert_issuer_sources_; |
| 377 // The TrustStore for checking if a path ends in a trust anchor. | 421 // The TrustStore for checking if a path ends in a trust anchor. |
| 422 // TODO: is this comment correct anymore? | |
| 378 const TrustStore* trust_store_; | 423 const TrustStore* trust_store_; |
| 379 // The output variable for storing the next candidate path, which the client | 424 // The output variable for storing the next candidate path, which the client |
| 380 // passes in to GetNextPath. Only used for a single path output. | 425 // passes in to GetNextPath. Only used for a single path output. |
| 381 ParsedCertificateList* out_path_; | 426 CertPath* out_path_; |
| 382 // The callback to be called if an async lookup generated a candidate path. | 427 // The callback to be called if an async lookup generated a candidate path. |
| 383 base::Closure callback_; | 428 base::Closure callback_; |
| 384 // Current state of the state machine. | 429 // Current state of the state machine. |
| 385 State next_state_; | 430 State next_state_; |
| 386 | 431 |
| 387 DISALLOW_COPY_AND_ASSIGN(CertPathIter); | 432 DISALLOW_COPY_AND_ASSIGN(CertPathIter); |
| 388 }; | 433 }; |
| 389 | 434 |
| 390 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, | 435 CertPathIter::CertPathIter(scoped_refptr<ParsedCertificate> cert, |
| 391 const TrustStore* trust_store) | 436 const TrustStore* trust_store) |
| 392 : next_cert_(std::move(cert)), | 437 : next_issuer_(std::move(cert)), |
| 393 trust_store_(trust_store), | 438 trust_store_(trust_store), |
| 394 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} | 439 next_state_(STATE_GET_NEXT_ISSUER_COMPLETE) {} |
| 395 | 440 |
| 396 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { | 441 void CertPathIter::AddCertIssuerSource(CertIssuerSource* cert_issuer_source) { |
| 397 cert_issuer_sources_.push_back(cert_issuer_source); | 442 cert_issuer_sources_.push_back(cert_issuer_source); |
| 398 } | 443 } |
| 399 | 444 |
| 400 CompletionStatus CertPathIter::GetNextPath(ParsedCertificateList* path, | 445 CompletionStatus CertPathIter::GetNextPath(CertPath* path, |
| 401 const base::Closure& callback) { | 446 const base::Closure& callback) { |
| 402 out_path_ = path; | 447 out_path_ = path; |
| 403 out_path_->clear(); | 448 out_path_->Clear(); |
| 404 CompletionStatus rv = DoLoop(!callback.is_null()); | 449 CompletionStatus rv = DoLoop(!callback.is_null()); |
| 405 if (rv == CompletionStatus::ASYNC) { | 450 if (rv == CompletionStatus::ASYNC) { |
| 406 callback_ = callback; | 451 callback_ = callback; |
| 407 } else { | 452 } else { |
| 408 // Clear the reference to the output parameter as a precaution. | 453 // Clear the reference to the output parameter as a precaution. |
| 409 out_path_ = nullptr; | 454 out_path_ = nullptr; |
| 410 } | 455 } |
| 411 return rv; | 456 return rv; |
| 412 } | 457 } |
| 413 | 458 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 439 } | 484 } |
| 440 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && | 485 } while (result == CompletionStatus::SYNC && next_state_ != STATE_NONE && |
| 441 next_state_ != STATE_RETURN_A_PATH); | 486 next_state_ != STATE_RETURN_A_PATH); |
| 442 | 487 |
| 443 return result; | 488 return result; |
| 444 } | 489 } |
| 445 | 490 |
| 446 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { | 491 CompletionStatus CertPathIter::DoGetNextIssuer(bool allow_async) { |
| 447 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; | 492 next_state_ = STATE_GET_NEXT_ISSUER_COMPLETE; |
| 448 CompletionStatus rv = cur_path_.back()->GetNextIssuer( | 493 CompletionStatus rv = cur_path_.back()->GetNextIssuer( |
| 449 &next_cert_, allow_async ? base::Bind(&CertPathIter::HandleGotNextIssuer, | 494 &next_issuer_, allow_async |
| 450 base::Unretained(this)) | 495 ? base::Bind(&CertPathIter::HandleGotNextIssuer, |
| 451 : base::Closure()); | 496 base::Unretained(this)) |
| 497 : base::Closure()); | |
| 452 return rv; | 498 return rv; |
| 453 } | 499 } |
| 454 | 500 |
| 455 CompletionStatus CertPathIter::DoGetNextIssuerComplete() { | 501 CompletionStatus CertPathIter::DoGetNextIssuerComplete() { |
| 456 if (next_cert_) { | 502 // If the issuer is a trust anchor signal readiness. |
| 503 if (next_issuer_.IsTrustAnchor()) { | |
| 504 DVLOG(1) << "CertPathIter got anchor(" | |
| 505 << CertDebugString(next_issuer_.anchor->cert().get()); | |
| 506 next_state_ = STATE_RETURN_A_PATH; | |
| 507 cur_path_.CopyPath(&out_path_->certs); | |
| 508 out_path_->trust_anchor = std::move(next_issuer_.anchor); | |
| 509 next_issuer_ = CertificateOrTrustAnchor(); | |
| 510 return CompletionStatus::SYNC; | |
| 511 } | |
| 512 | |
| 513 if (next_issuer_.IsCertificate()) { | |
| 457 // Skip this cert if it is already in the chain. | 514 // Skip this cert if it is already in the chain. |
| 458 if (cur_path_.IsPresent(next_cert_.get())) { | 515 if (cur_path_.IsPresent(next_issuer_.cert.get())) { |
| 459 next_state_ = STATE_GET_NEXT_ISSUER; | 516 next_state_ = STATE_GET_NEXT_ISSUER; |
| 460 return CompletionStatus::SYNC; | 517 return CompletionStatus::SYNC; |
| 461 } | 518 } |
| 462 // If the cert matches a trust root, this is a (possibly) complete path. | |
| 463 // Signal readiness. Don't add it to cur_path_, since that would cause an | |
| 464 // unnecessary lookup of issuers of the trust root. | |
| 465 if (trust_store_->IsTrustedCertificate(next_cert_.get())) { | |
| 466 DVLOG(1) << "CertPathIter IsTrustedCertificate(" | |
| 467 << CertDebugString(next_cert_.get()) << ") = true"; | |
| 468 next_state_ = STATE_RETURN_A_PATH; | |
| 469 cur_path_.CopyPath(out_path_); | |
| 470 out_path_->push_back(std::move(next_cert_)); | |
| 471 next_cert_ = nullptr; | |
| 472 return CompletionStatus::SYNC; | |
| 473 } | |
| 474 | 519 |
| 475 cur_path_.Append(base::WrapUnique(new CertIssuersIter( | 520 cur_path_.Append(base::WrapUnique(new CertIssuersIter( |
| 476 std::move(next_cert_), &cert_issuer_sources_, *trust_store_))); | 521 std::move(next_issuer_.cert), &cert_issuer_sources_, *trust_store_))); |
| 477 next_cert_ = nullptr; | 522 next_issuer_ = CertificateOrTrustAnchor(); |
| 478 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); | 523 DVLOG(1) << "CertPathIter cur_path_ = " << cur_path_.PathDebugString(); |
| 479 // Continue descending the tree. | 524 // Continue descending the tree. |
| 480 next_state_ = STATE_GET_NEXT_ISSUER; | 525 next_state_ = STATE_GET_NEXT_ISSUER; |
| 481 } else { | 526 } else { |
| 482 // TODO(mattm): should also include such paths in CertPathBuilder::Result, | 527 // 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 | 528 // 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. | 529 // 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 | 530 // No more issuers for current chain, go back up and see if there are any |
| 486 // more for the previous cert. | 531 // more for the previous cert. |
| 487 next_state_ = STATE_BACKTRACK; | 532 next_state_ = STATE_BACKTRACK; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 516 CertPathBuilder::ResultPath::~ResultPath() = default; | 561 CertPathBuilder::ResultPath::~ResultPath() = default; |
| 517 CertPathBuilder::Result::Result() = default; | 562 CertPathBuilder::Result::Result() = default; |
| 518 CertPathBuilder::Result::~Result() = default; | 563 CertPathBuilder::Result::~Result() = default; |
| 519 | 564 |
| 520 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, | 565 CertPathBuilder::CertPathBuilder(scoped_refptr<ParsedCertificate> cert, |
| 521 const TrustStore* trust_store, | 566 const TrustStore* trust_store, |
| 522 const SignaturePolicy* signature_policy, | 567 const SignaturePolicy* signature_policy, |
| 523 const der::GeneralizedTime& time, | 568 const der::GeneralizedTime& time, |
| 524 Result* result) | 569 Result* result) |
| 525 : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)), | 570 : cert_path_iter_(new CertPathIter(std::move(cert), trust_store)), |
| 526 trust_store_(trust_store), | |
| 527 signature_policy_(signature_policy), | 571 signature_policy_(signature_policy), |
| 528 time_(time), | 572 time_(time), |
| 529 next_state_(STATE_NONE), | 573 next_state_(STATE_NONE), |
| 530 out_result_(result) {} | 574 out_result_(result) {} |
| 531 | 575 |
| 532 CertPathBuilder::~CertPathBuilder() {} | 576 CertPathBuilder::~CertPathBuilder() {} |
| 533 | 577 |
| 534 void CertPathBuilder::AddCertIssuerSource( | 578 void CertPathBuilder::AddCertIssuerSource( |
| 535 CertIssuerSource* cert_issuer_source) { | 579 CertIssuerSource* cert_issuer_source) { |
| 536 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); | 580 cert_path_iter_->AddCertIssuerSource(cert_issuer_source); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 } | 623 } |
| 580 | 624 |
| 581 void CertPathBuilder::HandleGotNextPath() { | 625 void CertPathBuilder::HandleGotNextPath() { |
| 582 DCHECK(!callback_.is_null()); | 626 DCHECK(!callback_.is_null()); |
| 583 CompletionStatus rv = DoLoop(true /* allow_async */); | 627 CompletionStatus rv = DoLoop(true /* allow_async */); |
| 584 if (rv == CompletionStatus::SYNC) | 628 if (rv == CompletionStatus::SYNC) |
| 585 base::ResetAndReturn(&callback_).Run(); | 629 base::ResetAndReturn(&callback_).Run(); |
| 586 } | 630 } |
| 587 | 631 |
| 588 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { | 632 CompletionStatus CertPathBuilder::DoGetNextPathComplete() { |
| 589 if (next_path_.empty()) { | 633 if (next_path_.IsEmpty()) { |
| 590 // No more paths to check, signal completion. | 634 // No more paths to check, signal completion. |
| 591 next_state_ = STATE_NONE; | 635 next_state_ = STATE_NONE; |
| 592 return CompletionStatus::SYNC; | 636 return CompletionStatus::SYNC; |
| 593 } | 637 } |
| 594 | 638 |
| 595 bool verify_result = VerifyCertificateChainAssumingTrustedRoot( | 639 bool verify_result = |
| 596 next_path_, *trust_store_, signature_policy_, time_); | 640 next_path_.trust_anchor.get() && |
| 641 VerifyCertificateChain(next_path_.certs, next_path_.trust_anchor.get(), | |
| 642 signature_policy_, time_); | |
| 597 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " | 643 DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = " |
| 598 << verify_result; | 644 << verify_result; |
| 599 AddResultPath(next_path_, verify_result); | 645 AddResultPath(next_path_, verify_result); |
| 600 | 646 |
| 601 if (verify_result) { | 647 if (verify_result) { |
| 602 // Found a valid path, return immediately. | 648 // Found a valid path, return immediately. |
| 603 // TODO(mattm): add debug/test mode that tries all possible paths. | 649 // TODO(mattm): add debug/test mode that tries all possible paths. |
| 604 next_state_ = STATE_NONE; | 650 next_state_ = STATE_NONE; |
| 605 return CompletionStatus::SYNC; | 651 return CompletionStatus::SYNC; |
| 606 } | 652 } |
| 607 | 653 |
| 608 // Path did not verify. Try more paths. If there are no more paths, the result | 654 // Path did not verify. Try more paths. If there are no more paths, the result |
| 609 // will be returned next time DoGetNextPathComplete is called with next_path_ | 655 // will be returned next time DoGetNextPathComplete is called with next_path_ |
| 610 // empty. | 656 // empty. |
| 611 next_state_ = STATE_GET_NEXT_PATH; | 657 next_state_ = STATE_GET_NEXT_PATH; |
| 612 return CompletionStatus::SYNC; | 658 return CompletionStatus::SYNC; |
| 613 } | 659 } |
| 614 | 660 |
| 615 void CertPathBuilder::AddResultPath(const ParsedCertificateList& path, | 661 void CertPathBuilder::AddResultPath(const CertPath& path, bool is_success) { |
| 616 bool is_success) { | |
| 617 std::unique_ptr<ResultPath> result_path(new ResultPath()); | 662 std::unique_ptr<ResultPath> result_path(new ResultPath()); |
| 618 // TODO(mattm): better error reporting. | 663 // TODO(mattm): better error reporting. |
| 619 result_path->error = is_success ? OK : ERR_CERT_AUTHORITY_INVALID; | 664 result_path->error = is_success ? OK : ERR_CERT_AUTHORITY_INVALID; |
| 620 // TODO(mattm): set best_result_index based on number or severity of errors. | 665 // TODO(mattm): set best_result_index based on number or severity of errors. |
| 621 if (result_path->error == OK) | 666 if (result_path->error == OK) |
| 622 out_result_->best_result_index = out_result_->paths.size(); | 667 out_result_->best_result_index = out_result_->paths.size(); |
| 623 // TODO(mattm): add flag to only return a single path or all attempted paths? | 668 // TODO(mattm): add flag to only return a single path or all attempted paths? |
| 624 result_path->path = path; | 669 result_path->path = path; |
| 625 out_result_->paths.push_back(std::move(result_path)); | 670 out_result_->paths.push_back(std::move(result_path)); |
| 626 } | 671 } |
| 627 | 672 |
| 628 } // namespace net | 673 } // namespace net |
| OLD | NEW |