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