blob: 806cef966fd7677b76acfd3b7d0fee26b6e96fd7 [file] [log] [blame]
Bob Beckbc97b7a2023-04-18 08:35:15 -06001// Copyright 2016 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "path_builder.h"
6
7#include <cassert>
8#include <memory>
9#include <set>
10#include <unordered_set>
11
Bob Beck5c7a2a02023-11-20 17:28:21 -070012#include <openssl/base.h>
Bob Beck021ec332024-02-16 16:34:46 +000013#include <openssl/pki/verify_error.h>
Bob Beck5c7a2a02023-11-20 17:28:21 -070014#include <openssl/sha.h>
David Benjamin2a5db682024-02-06 21:56:57 -050015
Bob Beckbc97b7a2023-04-18 08:35:15 -060016#include "cert_issuer_source.h"
17#include "certificate_policies.h"
18#include "common_cert_errors.h"
19#include "parse_certificate.h"
20#include "parse_name.h" // For CertDebugString.
Bob Beck5c7a2a02023-11-20 17:28:21 -070021#include "parser.h"
Bob Beckbc97b7a2023-04-18 08:35:15 -060022#include "string_util.h"
23#include "trust_store.h"
24#include "verify_certificate_chain.h"
25#include "verify_name_match.h"
Bob Beckbc97b7a2023-04-18 08:35:15 -060026
David Benjamin0fbc17a2024-08-21 15:13:10 -040027BSSL_NAMESPACE_BEGIN
Bob Beckbc97b7a2023-04-18 08:35:15 -060028
29namespace {
30
Bob Beck5c7a2a02023-11-20 17:28:21 -070031using CertIssuerSources = std::vector<CertIssuerSource *>;
Bob Beckbc97b7a2023-04-18 08:35:15 -060032
33// Returns a hex-encoded sha256 of the DER-encoding of |cert|.
Bob Beck5c7a2a02023-11-20 17:28:21 -070034std::string FingerPrintParsedCertificate(const bssl::ParsedCertificate *cert) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060035 uint8_t digest[SHA256_DIGEST_LENGTH];
David Benjamin90ceeb02024-01-23 14:25:39 -050036 SHA256(cert->der_cert().data(), cert->der_cert().size(), digest);
37 return bssl::string_util::HexEncode(digest);
Bob Beckbc97b7a2023-04-18 08:35:15 -060038}
39
40// TODO(mattm): decide how much debug logging to keep.
Bob Beck5c7a2a02023-11-20 17:28:21 -070041std::string CertDebugString(const ParsedCertificate *cert) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060042 RDNSequence subject;
43 std::string subject_str;
44 if (!ParseName(cert->tbs().subject_tlv, &subject) ||
Bob Beck6beabf32023-11-21 09:43:52 -070045 !ConvertToRFC2253(subject, &subject_str)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060046 subject_str = "???";
Bob Beck6beabf32023-11-21 09:43:52 -070047 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060048
49 return FingerPrintParsedCertificate(cert) + " " + subject_str;
50}
51
Bob Beck5c7a2a02023-11-20 17:28:21 -070052std::string PathDebugString(const ParsedCertificateList &certs) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060053 std::string s;
Bob Beck5c7a2a02023-11-20 17:28:21 -070054 for (const auto &cert : certs) {
Bob Beck6beabf32023-11-21 09:43:52 -070055 if (!s.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060056 s += "\n";
Bob Beck6beabf32023-11-21 09:43:52 -070057 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060058 s += " " + CertDebugString(cert.get());
59 }
60 return s;
61}
Bob Beckbc97b7a2023-04-18 08:35:15 -060062
63// This structure describes a certificate and its trust level. Note that |cert|
64// may be null to indicate an "empty" entry.
65struct IssuerEntry {
66 std::shared_ptr<const ParsedCertificate> cert;
67 CertificateTrust trust;
68 int trust_and_key_id_match_ordering;
69};
70
71enum KeyIdentifierMatch {
72 // |target| has a keyIdentifier and it matches |issuer|'s
73 // subjectKeyIdentifier.
74 kMatch = 0,
75 // |target| does not have authorityKeyIdentifier or |issuer| does not have
76 // subjectKeyIdentifier.
77 kNoData = 1,
78 // |target|'s authorityKeyIdentifier does not match |issuer|.
79 kMismatch = 2,
80};
81
82// Returns an integer that represents the relative ordering of |issuer| for
83// prioritizing certificates in path building based on |issuer|'s
84// subjectKeyIdentifier and |target|'s authorityKeyIdentifier. Lower return
85// values indicate higer priority.
86KeyIdentifierMatch CalculateKeyIdentifierMatch(
Bob Beck5c7a2a02023-11-20 17:28:21 -070087 const ParsedCertificate *target, const ParsedCertificate *issuer) {
Bob Beck6beabf32023-11-21 09:43:52 -070088 if (!target->authority_key_identifier()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -060089 return kNoData;
Bob Beck6beabf32023-11-21 09:43:52 -070090 }
Bob Beckbc97b7a2023-04-18 08:35:15 -060091
92 // TODO(crbug.com/635205): If issuer does not have a subjectKeyIdentifier,
93 // could try synthesizing one using the standard SHA-1 method. Ideally in a
94 // way where any issuers that do have a matching subjectKeyIdentifier could
95 // be tried first before doing the extra work.
96 if (target->authority_key_identifier()->key_identifier &&
97 issuer->subject_key_identifier()) {
98 if (target->authority_key_identifier()->key_identifier !=
99 issuer->subject_key_identifier().value()) {
100 return kMismatch;
101 }
102 return kMatch;
103 }
104
105 return kNoData;
106}
107
108// Returns an integer that represents the relative ordering of |issuer| based
109// on |issuer_trust| and authorityKeyIdentifier matching for prioritizing
110// certificates in path building. Lower return values indicate higer priority.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700111int TrustAndKeyIdentifierMatchToOrder(const ParsedCertificate *target,
112 const ParsedCertificate *issuer,
113 const CertificateTrust &issuer_trust) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600114 enum {
115 kTrustedAndKeyIdMatch = 0,
116 kTrustedAndKeyIdNoData = 1,
117 kKeyIdMatch = 2,
118 kKeyIdNoData = 3,
119 kTrustedAndKeyIdMismatch = 4,
120 kKeyIdMismatch = 5,
121 kDistrustedAndKeyIdMatch = 6,
122 kDistrustedAndKeyIdNoData = 7,
123 kDistrustedAndKeyIdMismatch = 8,
124 };
125
126 KeyIdentifierMatch key_id_match = CalculateKeyIdentifierMatch(target, issuer);
127 switch (issuer_trust.type) {
128 case CertificateTrustType::TRUSTED_ANCHOR:
129 case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF:
130 switch (key_id_match) {
131 case kMatch:
132 return kTrustedAndKeyIdMatch;
133 case kNoData:
134 return kTrustedAndKeyIdNoData;
135 case kMismatch:
136 return kTrustedAndKeyIdMismatch;
137 }
138 break;
139 case CertificateTrustType::UNSPECIFIED:
140 case CertificateTrustType::TRUSTED_LEAF:
141 switch (key_id_match) {
142 case kMatch:
143 return kKeyIdMatch;
144 case kNoData:
145 return kKeyIdNoData;
146 case kMismatch:
147 return kKeyIdMismatch;
148 }
149 break;
150 case CertificateTrustType::DISTRUSTED:
151 switch (key_id_match) {
152 case kMatch:
153 return kDistrustedAndKeyIdMatch;
154 case kNoData:
155 return kDistrustedAndKeyIdNoData;
156 case kMismatch:
157 return kDistrustedAndKeyIdMismatch;
158 }
159 break;
160 }
161 assert(0); // NOTREACHED
162 return -1;
163}
164
165// CertIssuersIter iterates through the intermediates from |cert_issuer_sources|
166// which may be issuers of |cert|.
167class CertIssuersIter {
168 public:
Bob Beckd24a3822023-09-26 17:06:37 -0600169 // Constructs the CertIssuersIter. |*cert_issuer_sources|, and
170 // |*trust_store| must be valid for the lifetime of the CertIssuersIter.
Bob Beckbc97b7a2023-04-18 08:35:15 -0600171 CertIssuersIter(std::shared_ptr<const ParsedCertificate> cert,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700172 CertIssuerSources *cert_issuer_sources,
173 TrustStore *trust_store);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600174
Bob Beck5c7a2a02023-11-20 17:28:21 -0700175 CertIssuersIter(const CertIssuersIter &) = delete;
176 CertIssuersIter &operator=(const CertIssuersIter &) = delete;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600177
178 // Gets the next candidate issuer, or clears |*out| when all issuers have been
179 // exhausted.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700180 void GetNextIssuer(IssuerEntry *out);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600181
182 // Returns true if candidate issuers were found for |cert_|.
183 bool had_non_skipped_issuers() const {
184 return issuers_.size() > skipped_issuer_count_;
185 }
186
187 void increment_skipped_issuer_count() { skipped_issuer_count_++; }
188
189 // Returns the |cert| for which issuers are being retrieved.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700190 const ParsedCertificate *cert() const { return cert_.get(); }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600191 std::shared_ptr<const ParsedCertificate> reference_cert() const {
192 return cert_;
193 }
194
195 private:
196 void AddIssuers(ParsedCertificateList issuers);
197 void DoAsyncIssuerQuery();
198
199 // Returns true if |issuers_| contains unconsumed certificates.
200 bool HasCurrentIssuer() const { return cur_issuer_ < issuers_.size(); }
201
202 // Sorts the remaining entries in |issuers_| in the preferred order to
203 // explore. Does not change the ordering for indices before cur_issuer_.
204 void SortRemainingIssuers();
205
206 std::shared_ptr<const ParsedCertificate> cert_;
Bob Beck5c7a2a02023-11-20 17:28:21 -0700207 CertIssuerSources *cert_issuer_sources_;
208 TrustStore *trust_store_;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600209
210 // The list of issuers for |cert_|. This is added to incrementally (first
211 // synchronous results, then possibly multiple times as asynchronous results
212 // arrive.) The issuers may be re-sorted each time new issuers are added, but
213 // only the results from |cur_| onwards should be sorted, since the earlier
214 // results were already returned.
215 // Elements should not be removed from |issuers_| once added, since
216 // |present_issuers_| will point to data owned by the certs.
217 std::vector<IssuerEntry> issuers_;
218 // The index of the next cert in |issuers_| to return.
219 size_t cur_issuer_ = 0;
220 // The number of issuers that were skipped due to the loop checker.
221 size_t skipped_issuer_count_ = 0;
222 // Set to true whenever new issuers are appended at the end, to indicate the
223 // ordering needs to be checked.
224 bool issuers_needs_sort_ = false;
225
226 // Set of DER-encoded values for the certs in |issuers_|. Used to prevent
227 // duplicates. This is based on the full DER of the cert to allow different
228 // versions of the same certificate to be tried in different candidate paths.
229 // This points to data owned by |issuers_|.
230 std::unordered_set<std::string_view> present_issuers_;
231
232 // Tracks which requests have been made yet.
233 bool did_initial_query_ = false;
234 bool did_async_issuer_query_ = false;
235 // Index into pending_async_requests_ that is the next one to process.
236 size_t cur_async_request_ = 0;
237 // Owns the Request objects for any asynchronous requests so that they will be
238 // cancelled if CertIssuersIter is destroyed.
239 std::vector<std::unique_ptr<CertIssuerSource::Request>>
240 pending_async_requests_;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600241};
242
243CertIssuersIter::CertIssuersIter(
244 std::shared_ptr<const ParsedCertificate> in_cert,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700245 CertIssuerSources *cert_issuer_sources, TrustStore *trust_store)
Bob Beckbc97b7a2023-04-18 08:35:15 -0600246 : cert_(std::move(in_cert)),
247 cert_issuer_sources_(cert_issuer_sources),
Bob Beck64a9fb12023-11-22 17:37:31 -0700248 trust_store_(trust_store) {}
Bob Beckbc97b7a2023-04-18 08:35:15 -0600249
Bob Beck5c7a2a02023-11-20 17:28:21 -0700250void CertIssuersIter::GetNextIssuer(IssuerEntry *out) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600251 if (!did_initial_query_) {
252 did_initial_query_ = true;
Bob Beck5c7a2a02023-11-20 17:28:21 -0700253 for (auto *cert_issuer_source : *cert_issuer_sources_) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600254 ParsedCertificateList new_issuers;
255 cert_issuer_source->SyncGetIssuersOf(cert(), &new_issuers);
256 AddIssuers(std::move(new_issuers));
257 }
258 }
259
260 // If there aren't any issuers, block until async results are ready.
261 if (!HasCurrentIssuer()) {
262 if (!did_async_issuer_query_) {
263 // Now issue request(s) for async ones (AIA, etc).
264 DoAsyncIssuerQuery();
265 }
266
267 // TODO(eroman): Rather than blocking on the async requests in FIFO order,
268 // consume in the order they become ready.
269 while (!HasCurrentIssuer() &&
270 cur_async_request_ < pending_async_requests_.size()) {
271 ParsedCertificateList new_issuers;
Bob Beckd24a3822023-09-26 17:06:37 -0600272 pending_async_requests_[cur_async_request_]->GetNext(&new_issuers);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600273 if (new_issuers.empty()) {
274 // Request is exhausted, no more results pending from that
275 // CertIssuerSource.
276 pending_async_requests_[cur_async_request_++].reset();
277 } else {
278 AddIssuers(std::move(new_issuers));
279 }
280 }
281 }
282
283 if (HasCurrentIssuer()) {
284 SortRemainingIssuers();
285
Bob Beckbc97b7a2023-04-18 08:35:15 -0600286 // Still have issuers that haven't been returned yet, return the highest
287 // priority one (head of remaining list). A reference to the returned issuer
288 // is retained, since |present_issuers_| points to data owned by it.
289 *out = issuers_[cur_issuer_++];
290 return;
291 }
292
Bob Beckbc97b7a2023-04-18 08:35:15 -0600293 // Reached the end of all available issuers.
294 *out = IssuerEntry();
295}
296
297void CertIssuersIter::AddIssuers(ParsedCertificateList new_issuers) {
Bob Beck5c7a2a02023-11-20 17:28:21 -0700298 for (std::shared_ptr<const ParsedCertificate> &issuer : new_issuers) {
David Benjamin71c58962024-01-29 22:20:18 -0500299 if (present_issuers_.find(BytesAsStringView(issuer->der_cert())) !=
Bob Beck6beabf32023-11-21 09:43:52 -0700300 present_issuers_.end()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600301 continue;
Bob Beck6beabf32023-11-21 09:43:52 -0700302 }
David Benjamin71c58962024-01-29 22:20:18 -0500303 present_issuers_.insert(BytesAsStringView(issuer->der_cert()));
Bob Beckbc97b7a2023-04-18 08:35:15 -0600304
305 // Look up the trust for this issuer.
306 IssuerEntry entry;
307 entry.cert = std::move(issuer);
Bob Beckd24a3822023-09-26 17:06:37 -0600308 entry.trust = trust_store_->GetTrust(entry.cert.get());
Bob Beckbc97b7a2023-04-18 08:35:15 -0600309 entry.trust_and_key_id_match_ordering = TrustAndKeyIdentifierMatchToOrder(
310 cert(), entry.cert.get(), entry.trust);
311
312 issuers_.push_back(std::move(entry));
313 issuers_needs_sort_ = true;
314 }
315}
316
317void CertIssuersIter::DoAsyncIssuerQuery() {
Bob Beck05007562023-08-17 20:22:17 +0000318 BSSL_CHECK(!did_async_issuer_query_);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600319 did_async_issuer_query_ = true;
320 cur_async_request_ = 0;
Bob Beck5c7a2a02023-11-20 17:28:21 -0700321 for (auto *cert_issuer_source : *cert_issuer_sources_) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600322 std::unique_ptr<CertIssuerSource::Request> request;
323 cert_issuer_source->AsyncGetIssuersOf(cert(), &request);
324 if (request) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600325 pending_async_requests_.push_back(std::move(request));
326 }
327 }
328}
329
330void CertIssuersIter::SortRemainingIssuers() {
Bob Beck6beabf32023-11-21 09:43:52 -0700331 if (!issuers_needs_sort_) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600332 return;
Bob Beck6beabf32023-11-21 09:43:52 -0700333 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600334
335 std::stable_sort(
336 issuers_.begin() + cur_issuer_, issuers_.end(),
Bob Beck5c7a2a02023-11-20 17:28:21 -0700337 [](const IssuerEntry &issuer1, const IssuerEntry &issuer2) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600338 // TODO(crbug.com/635205): Add other prioritization hints. (See big list
339 // of possible sorting hints in RFC 4158.)
340 const bool issuer1_self_issued = issuer1.cert->normalized_subject() ==
341 issuer1.cert->normalized_issuer();
342 const bool issuer2_self_issued = issuer2.cert->normalized_subject() ==
343 issuer2.cert->normalized_issuer();
344 return std::tie(issuer1.trust_and_key_id_match_ordering,
345 issuer2_self_issued,
346 // Newer(larger) notBefore & notAfter dates are
347 // preferred, hence |issuer2| is on the LHS of
348 // the comparison and |issuer1| on the RHS.
349 issuer2.cert->tbs().validity_not_before,
350 issuer2.cert->tbs().validity_not_after) <
351 std::tie(issuer2.trust_and_key_id_match_ordering,
352 issuer1_self_issued,
353 issuer1.cert->tbs().validity_not_before,
354 issuer1.cert->tbs().validity_not_after);
355 });
356
357 issuers_needs_sort_ = false;
358}
359
360// CertIssuerIterPath tracks which certs are present in the path and prevents
361// paths from being built which repeat any certs (including different versions
362// of the same cert, based on Subject+SubjectAltName+SPKI).
363// (RFC 5280 forbids duplicate certificates per section 6.1, and RFC 4158
364// further recommends disallowing the same Subject+SubjectAltName+SPKI in
365// section 2.4.2.)
366class CertIssuerIterPath {
367 public:
368 // Returns true if |cert| is already present in the path.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700369 bool IsPresent(const ParsedCertificate *cert) const {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600370 return present_certs_.find(GetKey(cert)) != present_certs_.end();
371 }
372
373 // Appends |cert_issuers_iter| to the path. The cert referred to by
374 // |cert_issuers_iter| must not be present in the path already.
375 void Append(std::unique_ptr<CertIssuersIter> cert_issuers_iter) {
376 bool added =
377 present_certs_.insert(GetKey(cert_issuers_iter->cert())).second;
Bob Beck05007562023-08-17 20:22:17 +0000378 BSSL_CHECK(added);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600379 cur_path_.push_back(std::move(cert_issuers_iter));
380 }
381
382 // Pops the last CertIssuersIter off the path.
383 void Pop() {
384 size_t num_erased = present_certs_.erase(GetKey(cur_path_.back()->cert()));
Bob Beck05007562023-08-17 20:22:17 +0000385 BSSL_CHECK(num_erased == 1U);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600386 cur_path_.pop_back();
387 }
388
389 // Copies the ParsedCertificate elements of the current path to |*out_path|.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700390 void CopyPath(ParsedCertificateList *out_path) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600391 out_path->clear();
Bob Beck6beabf32023-11-21 09:43:52 -0700392 for (const auto &node : cur_path_) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600393 out_path->push_back(node->reference_cert());
Bob Beck6beabf32023-11-21 09:43:52 -0700394 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600395 }
396
397 // Returns true if the path is empty.
398 bool Empty() const { return cur_path_.empty(); }
399
400 // Returns the last CertIssuersIter in the path.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700401 CertIssuersIter *back() { return cur_path_.back().get(); }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600402
403 // Returns the length of the path.
404 size_t Length() const { return cur_path_.size(); }
405
406 std::string PathDebugString() {
407 std::string s;
Bob Beck5c7a2a02023-11-20 17:28:21 -0700408 for (const auto &node : cur_path_) {
Bob Beck6beabf32023-11-21 09:43:52 -0700409 if (!s.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600410 s += "\n";
Bob Beck6beabf32023-11-21 09:43:52 -0700411 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600412 s += " " + CertDebugString(node->cert());
413 }
414 return s;
415 }
416
417 private:
418 using Key = std::tuple<std::string_view, std::string_view, std::string_view>;
419
Bob Beck5c7a2a02023-11-20 17:28:21 -0700420 static Key GetKey(const ParsedCertificate *cert) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600421 // TODO(mattm): ideally this would use a normalized version of
422 // SubjectAltName, but it's not that important just for LoopChecker.
423 //
424 // Note that subject_alt_names_extension().value will be empty if the cert
425 // had no SubjectAltName extension, so there is no need for a condition on
426 // has_subject_alt_names().
David Benjamin71c58962024-01-29 22:20:18 -0500427 return Key(BytesAsStringView(cert->normalized_subject()),
428 BytesAsStringView(cert->subject_alt_names_extension().value),
429 BytesAsStringView(cert->tbs().spki_tlv));
Bob Beckbc97b7a2023-04-18 08:35:15 -0600430 }
431
432 std::vector<std::unique_ptr<CertIssuersIter>> cur_path_;
433
434 // This refers to data owned by |cur_path_|.
435 // TODO(mattm): use unordered_set. Requires making a hash function for Key.
436 std::set<Key> present_certs_;
437};
438
439} // namespace
440
Bob Beck5c7a2a02023-11-20 17:28:21 -0700441const ParsedCertificate *CertPathBuilderResultPath::GetTrustedCert() const {
Bob Beck6beabf32023-11-21 09:43:52 -0700442 if (certs.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600443 return nullptr;
Bob Beck6beabf32023-11-21 09:43:52 -0700444 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600445
446 switch (last_cert_trust.type) {
447 case CertificateTrustType::TRUSTED_ANCHOR:
448 case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF:
449 case CertificateTrustType::TRUSTED_LEAF:
450 return certs.back().get();
451 case CertificateTrustType::UNSPECIFIED:
452 case CertificateTrustType::DISTRUSTED:
453 return nullptr;
454 }
455
456 assert(0); // NOTREACHED
457 return nullptr;
458}
459
460// CertPathIter generates possible paths from |cert| to a trust anchor in
461// |trust_store|, using intermediates from the |cert_issuer_source| objects if
462// necessary.
463class CertPathIter {
464 public:
465 CertPathIter(std::shared_ptr<const ParsedCertificate> cert,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700466 TrustStore *trust_store);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600467
Bob Beck5c7a2a02023-11-20 17:28:21 -0700468 CertPathIter(const CertPathIter &) = delete;
469 CertPathIter &operator=(const CertPathIter &) = delete;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600470
471 // Adds a CertIssuerSource to provide intermediates for use in path building.
472 // The |*cert_issuer_source| must remain valid for the lifetime of the
473 // CertPathIter.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700474 void AddCertIssuerSource(CertIssuerSource *cert_issuer_source);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600475
476 // Gets the next candidate path, and fills it into |out_certs| and
477 // |out_last_cert_trust|. Note that the returned path is unverified and must
478 // still be run through a chain validator. If a candidate path could not be
479 // built, a partial path will be returned and |out_errors| will have an error
480 // added.
481 // If the return value is true, GetNextPath may be called again to backtrack
482 // and continue path building. Once all paths have been exhausted returns
483 // false. If deadline or iteration limit is exceeded, sets |out_certs| to the
484 // current path being explored and returns false.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700485 bool GetNextPath(ParsedCertificateList *out_certs,
486 CertificateTrust *out_last_cert_trust,
487 CertPathErrors *out_errors,
488 CertPathBuilderDelegate *delegate, uint32_t *iteration_count,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600489 const uint32_t max_iteration_count,
490 const uint32_t max_path_building_depth);
491
492 private:
493 // Stores the next candidate issuer, until it is used during the
494 // STATE_GET_NEXT_ISSUER_COMPLETE step.
495 IssuerEntry next_issuer_;
496 // The current path being explored, made up of CertIssuerIters. Each node
497 // keeps track of the state of searching for issuers of that cert, so that
498 // when backtracking it can resume the search where it left off.
499 CertIssuerIterPath cur_path_;
500 // The CertIssuerSources for retrieving candidate issuers.
501 CertIssuerSources cert_issuer_sources_;
502 // The TrustStore for checking if a path ends in a trust anchor.
Bob Beck5c7a2a02023-11-20 17:28:21 -0700503 TrustStore *trust_store_;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600504};
505
506CertPathIter::CertPathIter(std::shared_ptr<const ParsedCertificate> cert,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700507 TrustStore *trust_store)
Bob Beckd24a3822023-09-26 17:06:37 -0600508 : trust_store_(trust_store) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600509 // Initialize |next_issuer_| to the target certificate.
510 next_issuer_.cert = std::move(cert);
Bob Beckd24a3822023-09-26 17:06:37 -0600511 next_issuer_.trust = trust_store_->GetTrust(next_issuer_.cert.get());
Bob Beckbc97b7a2023-04-18 08:35:15 -0600512}
513
Bob Beck5c7a2a02023-11-20 17:28:21 -0700514void CertPathIter::AddCertIssuerSource(CertIssuerSource *cert_issuer_source) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600515 cert_issuer_sources_.push_back(cert_issuer_source);
516}
517
Bob Beck5c7a2a02023-11-20 17:28:21 -0700518bool CertPathIter::GetNextPath(ParsedCertificateList *out_certs,
519 CertificateTrust *out_last_cert_trust,
520 CertPathErrors *out_errors,
521 CertPathBuilderDelegate *delegate,
522 uint32_t *iteration_count,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600523 const uint32_t max_iteration_count,
524 const uint32_t max_path_building_depth) {
525 out_certs->clear();
526 *out_last_cert_trust = CertificateTrust::ForUnspecified();
527
528 while (true) {
529 if (delegate->IsDeadlineExpired()) {
530 if (cur_path_.Empty()) {
531 // If the deadline is already expired before the first call to
532 // GetNextPath, cur_path_ will be empty. Return the leaf cert in that
533 // case.
Bob Beck6beabf32023-11-21 09:43:52 -0700534 if (next_issuer_.cert) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600535 out_certs->push_back(next_issuer_.cert);
Bob Beck6beabf32023-11-21 09:43:52 -0700536 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600537 } else {
538 cur_path_.CopyPath(out_certs);
539 }
540 out_errors->GetOtherErrors()->AddError(cert_errors::kDeadlineExceeded);
541 return false;
542 }
543
544 // We are not done yet, so if the current path is at the depth limit then
545 // we must backtrack to find an acceptable solution.
546 if (max_path_building_depth > 0 &&
547 cur_path_.Length() >= max_path_building_depth) {
548 cur_path_.CopyPath(out_certs);
549 out_errors->GetOtherErrors()->AddError(cert_errors::kDepthLimitExceeded);
Bob Beck1fa9cc22023-11-21 13:58:30 -0700550 if (delegate->IsDebugLogEnabled()) {
551 delegate->DebugLog(
552 "CertPathIter reached depth limit. Returning "
553 "partial path and backtracking:\n" +
554 PathDebugString(*out_certs));
555 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600556 cur_path_.Pop();
557 return true;
558 }
559
560 if (!next_issuer_.cert) {
561 if (cur_path_.Empty()) {
Bob Beck1fa9cc22023-11-21 13:58:30 -0700562 if (delegate->IsDebugLogEnabled()) {
563 delegate->DebugLog("CertPathIter exhausted all paths...");
564 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600565 return false;
566 }
567
568 (*iteration_count)++;
569 if (max_iteration_count > 0 && *iteration_count > max_iteration_count) {
570 cur_path_.CopyPath(out_certs);
571 out_errors->GetOtherErrors()->AddError(
572 cert_errors::kIterationLimitExceeded);
573 return false;
574 }
575
576 cur_path_.back()->GetNextIssuer(&next_issuer_);
577 if (!next_issuer_.cert) {
578 if (!cur_path_.back()->had_non_skipped_issuers()) {
579 // If the end of a path was reached without finding an anchor, return
580 // the partial path before backtracking.
581 cur_path_.CopyPath(out_certs);
582 out_errors->GetErrorsForCert(out_certs->size() - 1)
583 ->AddError(cert_errors::kNoIssuersFound);
Bob Beck1fa9cc22023-11-21 13:58:30 -0700584 if (delegate->IsDebugLogEnabled()) {
585 delegate->DebugLog(
586 "CertPathIter returning partial path and backtracking:\n" +
587 PathDebugString(*out_certs));
588 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600589 cur_path_.Pop();
590 return true;
591 } else {
592 // No more issuers for current chain, go back up and see if there are
593 // any more for the previous cert.
Bob Beck1fa9cc22023-11-21 13:58:30 -0700594 if (delegate->IsDebugLogEnabled()) {
595 delegate->DebugLog("CertPathIter backtracking...");
596 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600597 cur_path_.Pop();
598 continue;
599 }
600 }
601 }
602
603 // Overrides for cert with trust appearing in the wrong place for the type
604 // of trust (trusted leaf in non-leaf position, or trust anchor in leaf
605 // position.)
606 switch (next_issuer_.trust.type) {
607 case CertificateTrustType::TRUSTED_ANCHOR:
608 // If the leaf cert is trusted only as an anchor, treat it as having
609 // unspecified trust. This may allow a successful path to be built to a
610 // different root (or to the same cert if it's self-signed).
611 if (cur_path_.Empty()) {
Bob Beck1fa9cc22023-11-21 13:58:30 -0700612 if (delegate->IsDebugLogEnabled()) {
613 delegate->DebugLog(
614 "Leaf is a trust anchor, considering as UNSPECIFIED");
615 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600616 next_issuer_.trust = CertificateTrust::ForUnspecified();
617 }
618 break;
619 case CertificateTrustType::TRUSTED_LEAF:
620 // If a non-leaf cert is trusted only as a leaf, treat it as having
621 // unspecified trust. This may allow a successful path to be built to a
622 // trusted root.
623 if (!cur_path_.Empty()) {
Bob Beck1fa9cc22023-11-21 13:58:30 -0700624 if (delegate->IsDebugLogEnabled()) {
David Benjamin81138bc2024-01-23 14:53:40 -0500625 delegate->DebugLog(
626 "Issuer is a trust leaf, considering as UNSPECIFIED");
Bob Beck1fa9cc22023-11-21 13:58:30 -0700627 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600628 next_issuer_.trust = CertificateTrust::ForUnspecified();
629 }
630 break;
631 case CertificateTrustType::DISTRUSTED:
632 case CertificateTrustType::UNSPECIFIED:
633 case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF:
634 // No override necessary.
635 break;
636 }
637
638 // Overrides for trusted leaf cert with require_leaf_selfsigned. If the leaf
639 // isn't actually self-signed, treat it as unspecified.
640 switch (next_issuer_.trust.type) {
641 case CertificateTrustType::TRUSTED_LEAF:
642 case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF:
643 if (cur_path_.Empty() && next_issuer_.trust.require_leaf_selfsigned &&
644 !VerifyCertificateIsSelfSigned(*next_issuer_.cert,
645 delegate->GetVerifyCache(),
646 /*errors=*/nullptr)) {
Bob Beck1fa9cc22023-11-21 13:58:30 -0700647 if (delegate->IsDebugLogEnabled()) {
648 delegate->DebugLog(
649 "Leaf is trusted with require_leaf_selfsigned but is "
650 "not self-signed, considering as UNSPECIFIED");
651 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600652 next_issuer_.trust = CertificateTrust::ForUnspecified();
653 }
654 break;
655 case CertificateTrustType::TRUSTED_ANCHOR:
656 case CertificateTrustType::DISTRUSTED:
657 case CertificateTrustType::UNSPECIFIED:
658 // No override necessary.
659 break;
660 }
661
662 switch (next_issuer_.trust.type) {
663 // If the trust for this issuer is "known" (either because it is
664 // distrusted, or because it is trusted) then stop building and return the
665 // path.
666 case CertificateTrustType::DISTRUSTED:
667 case CertificateTrustType::TRUSTED_ANCHOR:
668 case CertificateTrustType::TRUSTED_ANCHOR_OR_LEAF:
669 case CertificateTrustType::TRUSTED_LEAF: {
670 // If the issuer has a known trust level, can stop building the path.
Bob Beckbc97b7a2023-04-18 08:35:15 -0600671 cur_path_.CopyPath(out_certs);
672 out_certs->push_back(std::move(next_issuer_.cert));
Bob Beck1fa9cc22023-11-21 13:58:30 -0700673 if (delegate->IsDebugLogEnabled()) {
674 delegate->DebugLog("CertPathIter returning path:\n" +
675 PathDebugString(*out_certs));
676 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600677 *out_last_cert_trust = next_issuer_.trust;
678 next_issuer_ = IssuerEntry();
679 return true;
680 }
681 case CertificateTrustType::UNSPECIFIED: {
682 // Skip this cert if it is already in the chain.
683 if (cur_path_.IsPresent(next_issuer_.cert.get())) {
684 cur_path_.back()->increment_skipped_issuer_count();
Bob Beck1fa9cc22023-11-21 13:58:30 -0700685 if (delegate->IsDebugLogEnabled()) {
686 delegate->DebugLog("CertPathIter skipping dupe cert: " +
687 CertDebugString(next_issuer_.cert.get()));
688 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600689 next_issuer_ = IssuerEntry();
690 continue;
691 }
692
693 cur_path_.Append(std::make_unique<CertIssuersIter>(
Bob Beckd24a3822023-09-26 17:06:37 -0600694 std::move(next_issuer_.cert), &cert_issuer_sources_, trust_store_));
Bob Beckbc97b7a2023-04-18 08:35:15 -0600695 next_issuer_ = IssuerEntry();
Bob Beck1fa9cc22023-11-21 13:58:30 -0700696 if (delegate->IsDebugLogEnabled()) {
David Benjamin81138bc2024-01-23 14:53:40 -0500697 delegate->DebugLog("CertPathIter cur_path_ =\n" +
698 cur_path_.PathDebugString());
Bob Beck1fa9cc22023-11-21 13:58:30 -0700699 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600700 // Continue descending the tree.
701 continue;
702 }
703 }
704 }
705}
706
707CertPathBuilderResultPath::CertPathBuilderResultPath() = default;
708CertPathBuilderResultPath::~CertPathBuilderResultPath() = default;
709
710bool CertPathBuilderResultPath::IsValid() const {
711 return GetTrustedCert() && !errors.ContainsHighSeverityErrors();
712}
713
Bob Beck021ec332024-02-16 16:34:46 +0000714VerifyError CertPathBuilderResultPath::GetVerifyError() const {
715 // Diagnostic string is always "everything" about the path.
716 std::string diagnostic = errors.ToDebugString(certs);
717 if (!errors.ContainsHighSeverityErrors()) {
718 // TODO(bbe3): Having to check this after seems awkward: crbug.com/boringssl/713
719 if (GetTrustedCert()) {
720 return VerifyError(VerifyError::StatusCode::PATH_VERIFIED, 0,
721 std::move(diagnostic));
722 } else {
723 return VerifyError(VerifyError::StatusCode::VERIFICATION_FAILURE, -1,
724 std::move(diagnostic));
725 }
726 }
727
728 // Check for the presence of things that amount to Internal errors in the
729 // verification code. We deliberately prioritize this to not hide it in
730 // multiple error cases.
731 if (errors.ContainsError(cert_errors::kInternalError) ||
732 errors.ContainsError(cert_errors::kChainIsEmpty)) {
733 return VerifyError(VerifyError::StatusCode::VERIFICATION_FAILURE, -1,
734 std::move(diagnostic));
735 }
736
737 // Similarly, for the deadline and limit cases, there will often be other
738 // errors that we probably do not care about, since path building was
739 // aborted. Surface these errors instead of having them hidden in the multiple
740 // error case.
741 //
742 // Normally callers should check for these in the path builder result before
743 // calling this on a single path, but this is here in case they do not and
744 // these errors are actually present on this path.
745 if (errors.ContainsError(cert_errors::kDeadlineExceeded)) {
746 return VerifyError(VerifyError::StatusCode::PATH_DEADLINE_EXCEEDED, -1,
747 std::move(diagnostic));
748 }
749 if (errors.ContainsError(cert_errors::kIterationLimitExceeded)) {
750 return VerifyError(VerifyError::StatusCode::PATH_ITERATION_COUNT_EXCEEDED,
751 -1, std::move(diagnostic));
752 }
753 if (errors.ContainsError(cert_errors::kDepthLimitExceeded)) {
754 return VerifyError(VerifyError::StatusCode::PATH_DEPTH_LIMIT_REACHED, -1,
755 std::move(diagnostic));
756 }
757
758 // If the chain has multiple high severity errors, indicate that.
759 ptrdiff_t depth = -1;
760 std::optional<CertErrorId> single_error =
761 errors.FindSingleHighSeverityError(depth);
762 if (!single_error.has_value()) {
763 return VerifyError(VerifyError::StatusCode::PATH_MULTIPLE_ERRORS, -1,
764 std::move(diagnostic));
765 }
766
767 // Otherwise it has a single error, map it appropriately at the
768 // depth it first occurs.
769 if (single_error.value() == cert_errors::kValidityFailedNotAfter) {
770 return VerifyError(VerifyError::StatusCode::CERTIFICATE_EXPIRED, depth,
771 std::move(diagnostic));
772 }
773 if (single_error.value() == cert_errors::kValidityFailedNotBefore) {
774 return VerifyError(VerifyError::StatusCode::CERTIFICATE_NOT_YET_VALID,
775 depth, std::move(diagnostic));
776 }
777 if (single_error.value() == cert_errors::kDistrustedByTrustStore ||
778 single_error.value() == cert_errors::kCertIsNotTrustAnchor ||
779 single_error.value() == cert_errors::kMaxPathLengthViolated ||
780 single_error.value() == cert_errors::kSubjectDoesNotMatchIssuer ||
781 single_error.value() == cert_errors::kNoIssuersFound) {
782 return VerifyError(VerifyError::StatusCode::PATH_NOT_FOUND, depth,
783 std::move(diagnostic));
784 }
785 if (single_error.value() == cert_errors::kVerifySignedDataFailed) {
786 return VerifyError(VerifyError::StatusCode::CERTIFICATE_INVALID_SIGNATURE,
787 depth, std::move(diagnostic));
788 }
789 if (single_error.value() == cert_errors::kUnacceptableSignatureAlgorithm) {
790 return VerifyError(
791 VerifyError::StatusCode::CERTIFICATE_UNSUPPORTED_SIGNATURE_ALGORITHM,
792 depth, std::move(diagnostic));
793 }
794 if (single_error.value() == cert_errors::kUnacceptablePublicKey) {
795 return VerifyError(VerifyError::StatusCode::CERTIFICATE_UNSUPPORTED_KEY,
796 depth, std::move(diagnostic));
797 }
798 if (single_error.value() == cert_errors::kEkuLacksServerAuth ||
799 single_error.value() == cert_errors::kEkuLacksServerAuthButHasAnyEKU ||
800 single_error.value() == cert_errors::kEkuLacksClientAuth ||
801 single_error.value() == cert_errors::kEkuLacksClientAuthButHasAnyEKU ||
802 single_error.value() == cert_errors::kEkuLacksClientAuthOrServerAuth) {
803 return VerifyError(VerifyError::StatusCode::CERTIFICATE_NO_MATCHING_EKU,
804 depth, std::move(diagnostic));
805 }
806 if (single_error.value() == cert_errors::kCertificateRevoked) {
807 return VerifyError(VerifyError::StatusCode::CERTIFICATE_REVOKED, depth,
808 std::move(diagnostic));
809 }
810 if (single_error.value() == cert_errors::kNoRevocationMechanism) {
811 return VerifyError(
812 VerifyError::StatusCode::CERTIFICATE_NO_REVOCATION_MECHANISM, depth,
813 std::move(diagnostic));
814 }
815 if (single_error.value() == cert_errors::kUnableToCheckRevocation) {
816 return VerifyError(
817 VerifyError::StatusCode::CERTIFICATE_UNABLE_TO_CHECK_REVOCATION, depth,
818 std::move(diagnostic));
819 }
820 // All other High severity errors map to CERTIFICATE_INVALID if associated
821 // to a certificate, or VERIFICATION_FAILURE if not associated to a
822 // certificate.
823 return VerifyError((depth < 0) ? VerifyError::StatusCode::VERIFICATION_FAILURE
824 : VerifyError::StatusCode::CERTIFICATE_INVALID,
825 depth, std::move(diagnostic));
826}
827
828
Bob Beckbc97b7a2023-04-18 08:35:15 -0600829CertPathBuilder::Result::Result() = default;
Bob Beck5c7a2a02023-11-20 17:28:21 -0700830CertPathBuilder::Result::Result(Result &&) = default;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600831CertPathBuilder::Result::~Result() = default;
Bob Beck5c7a2a02023-11-20 17:28:21 -0700832CertPathBuilder::Result &CertPathBuilder::Result::operator=(Result &&) =
833 default;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600834
835bool CertPathBuilder::Result::HasValidPath() const {
836 return GetBestValidPath() != nullptr;
837}
838
839bool CertPathBuilder::Result::AnyPathContainsError(CertErrorId error_id) const {
Bob Beck5c7a2a02023-11-20 17:28:21 -0700840 for (const auto &path : paths) {
Bob Beck6beabf32023-11-21 09:43:52 -0700841 if (path->errors.ContainsError(error_id)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600842 return true;
Bob Beck6beabf32023-11-21 09:43:52 -0700843 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600844 }
845
846 return false;
847}
848
Bob Beck021ec332024-02-16 16:34:46 +0000849const VerifyError CertPathBuilder::Result::GetBestPathVerifyError() const {
850 if (HasValidPath()) {
851 return GetBestValidPath()->GetVerifyError();
852 }
853 // We can only return one error. Returning the errors corresponding to the
854 // limits if they they appear on any path will make this error prominent even
855 // if there are other paths with different or multiple errors.
856 if (exceeded_iteration_limit) {
857 return VerifyError(
858 VerifyError::StatusCode::PATH_ITERATION_COUNT_EXCEEDED, -1,
859 "Iteration count exceeded, could not find a trusted path.");
860 }
861 if (exceeded_deadline) {
862 return VerifyError(VerifyError::StatusCode::PATH_DEADLINE_EXCEEDED, -1,
863 "Deadline exceeded. Could not find a trusted path.");
864 }
865 if (AnyPathContainsError(cert_errors::kDepthLimitExceeded)) {
866 return VerifyError(VerifyError::StatusCode::PATH_DEPTH_LIMIT_REACHED, -1,
867 "Depth limit reached. Could not find a trusted path.");
868 }
869
870 // If there are no paths to report an error on, this probably indicates
871 // something is wrong with this path builder result.
872 if (paths.empty()) {
873 return VerifyError(VerifyError::StatusCode::VERIFICATION_FAILURE, -1,
874 "No paths in path builder result.");
875 }
876
877 // If there are paths, report the VerifyError from the best path.
878 CertPathBuilderResultPath *path = paths[best_result_index].get();
879 return path->GetVerifyError();
880}
881
Bob Beck5c7a2a02023-11-20 17:28:21 -0700882const CertPathBuilderResultPath *CertPathBuilder::Result::GetBestValidPath()
Bob Beckbc97b7a2023-04-18 08:35:15 -0600883 const {
Bob Beck5c7a2a02023-11-20 17:28:21 -0700884 const CertPathBuilderResultPath *result_path = GetBestPathPossiblyInvalid();
Bob Beckbc97b7a2023-04-18 08:35:15 -0600885
Bob Beck6beabf32023-11-21 09:43:52 -0700886 if (result_path && result_path->IsValid()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600887 return result_path;
Bob Beck6beabf32023-11-21 09:43:52 -0700888 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600889
890 return nullptr;
891}
892
Bob Beck5c7a2a02023-11-20 17:28:21 -0700893const CertPathBuilderResultPath *
Bob Beckbc97b7a2023-04-18 08:35:15 -0600894CertPathBuilder::Result::GetBestPathPossiblyInvalid() const {
Bob Beck05007562023-08-17 20:22:17 +0000895 BSSL_CHECK((paths.empty() && best_result_index == 0) ||
896 best_result_index < paths.size());
Bob Beckbc97b7a2023-04-18 08:35:15 -0600897
Bob Beck6beabf32023-11-21 09:43:52 -0700898 if (best_result_index >= paths.size()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600899 return nullptr;
Bob Beck6beabf32023-11-21 09:43:52 -0700900 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600901
902 return paths[best_result_index].get();
903}
904
905CertPathBuilder::CertPathBuilder(
Bob Beck5c7a2a02023-11-20 17:28:21 -0700906 std::shared_ptr<const ParsedCertificate> cert, TrustStore *trust_store,
907 CertPathBuilderDelegate *delegate, const der::GeneralizedTime &time,
908 KeyPurpose key_purpose, InitialExplicitPolicy initial_explicit_policy,
909 const std::set<der::Input> &user_initial_policy_set,
Bob Beckbc97b7a2023-04-18 08:35:15 -0600910 InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
911 InitialAnyPolicyInhibit initial_any_policy_inhibit)
912 : cert_path_iter_(
Bob Beckd24a3822023-09-26 17:06:37 -0600913 std::make_unique<CertPathIter>(std::move(cert), trust_store)),
Bob Beckbc97b7a2023-04-18 08:35:15 -0600914 delegate_(delegate),
915 time_(time),
916 key_purpose_(key_purpose),
917 initial_explicit_policy_(initial_explicit_policy),
918 user_initial_policy_set_(user_initial_policy_set),
919 initial_policy_mapping_inhibit_(initial_policy_mapping_inhibit),
920 initial_any_policy_inhibit_(initial_any_policy_inhibit) {
Bob Beck05007562023-08-17 20:22:17 +0000921 BSSL_CHECK(delegate);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600922 // The TrustStore also implements the CertIssuerSource interface.
923 AddCertIssuerSource(trust_store);
924}
925
926CertPathBuilder::~CertPathBuilder() = default;
927
928void CertPathBuilder::AddCertIssuerSource(
Bob Beck5c7a2a02023-11-20 17:28:21 -0700929 CertIssuerSource *cert_issuer_source) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600930 cert_path_iter_->AddCertIssuerSource(cert_issuer_source);
931}
932
933void CertPathBuilder::SetIterationLimit(uint32_t limit) {
934 max_iteration_count_ = limit;
935}
936
937void CertPathBuilder::SetDepthLimit(uint32_t limit) {
938 max_path_building_depth_ = limit;
939}
940
Bob Beck936fcd32023-12-11 23:19:27 +0000941void CertPathBuilder::SetValidPathLimit(size_t limit) {
942 valid_path_limit_ = limit;
943}
944
Bob Beckbc97b7a2023-04-18 08:35:15 -0600945void CertPathBuilder::SetExploreAllPaths(bool explore_all_paths) {
Bob Beck936fcd32023-12-11 23:19:27 +0000946 valid_path_limit_ = explore_all_paths ? 0 : 1;
Bob Beckbc97b7a2023-04-18 08:35:15 -0600947}
948
949CertPathBuilder::Result CertPathBuilder::Run() {
950 uint32_t iteration_count = 0;
951
952 while (true) {
953 std::unique_ptr<CertPathBuilderResultPath> result_path =
954 std::make_unique<CertPathBuilderResultPath>();
955
956 if (!cert_path_iter_->GetNextPath(
957 &result_path->certs, &result_path->last_cert_trust,
958 &result_path->errors, delegate_, &iteration_count,
959 max_iteration_count_, max_path_building_depth_)) {
960 // There are no more paths to check or limits were exceeded.
961 if (result_path->errors.ContainsError(
962 cert_errors::kIterationLimitExceeded)) {
963 out_result_.exceeded_iteration_limit = true;
964 }
965 if (result_path->errors.ContainsError(cert_errors::kDeadlineExceeded)) {
966 out_result_.exceeded_deadline = true;
967 }
968 if (!result_path->certs.empty()) {
969 // It shouldn't be possible to get here without adding one of the
970 // errors above, but just in case, add an error if there isn't one
971 // already.
972 if (!result_path->errors.ContainsHighSeverityErrors()) {
973 result_path->errors.GetOtherErrors()->AddError(
974 cert_errors::kInternalError);
975 }
Matt Mueller73c4a5d2023-12-08 18:37:42 -0800976
977 // Allow the delegate to do any processing or logging of the partial
978 // path. (This is for symmetry for the other CheckPathAfterVerification
979 // which also gets called on partial paths.)
980 delegate_->CheckPathAfterVerification(*this, result_path.get());
981
Bob Beckbc97b7a2023-04-18 08:35:15 -0600982 AddResultPath(std::move(result_path));
983 }
984 out_result_.iteration_count = iteration_count;
985 return std::move(out_result_);
986 }
987
988 if (result_path->last_cert_trust.HasUnspecifiedTrust()) {
989 // Partial path, don't attempt to verify. Just double check that it is
990 // marked with an error, and move on.
991 if (!result_path->errors.ContainsHighSeverityErrors()) {
992 result_path->errors.GetOtherErrors()->AddError(
993 cert_errors::kInternalError);
994 }
995 } else {
996 // Verify the entire certificate chain.
997 VerifyCertificateChain(
998 result_path->certs, result_path->last_cert_trust, delegate_, time_,
999 key_purpose_, initial_explicit_policy_, user_initial_policy_set_,
1000 initial_policy_mapping_inhibit_, initial_any_policy_inhibit_,
1001 &result_path->user_constrained_policy_set, &result_path->errors);
1002 }
1003
Bob Beckbc97b7a2023-04-18 08:35:15 -06001004 // Give the delegate a chance to add errors to the path.
1005 delegate_->CheckPathAfterVerification(*this, result_path.get());
1006
1007 bool path_is_good = result_path->IsValid();
1008
1009 AddResultPath(std::move(result_path));
1010
Bob Beck936fcd32023-12-11 23:19:27 +00001011 if (path_is_good) {
1012 valid_path_count_++;
1013 if (valid_path_limit_ > 0 && valid_path_count_ == valid_path_limit_) {
1014 out_result_.iteration_count = iteration_count;
1015 // Found enough paths, return immediately.
1016 return std::move(out_result_);
1017 }
Bob Beckbc97b7a2023-04-18 08:35:15 -06001018 }
1019 // Path did not verify. Try more paths.
1020 }
1021}
1022
1023void CertPathBuilder::AddResultPath(
1024 std::unique_ptr<CertPathBuilderResultPath> result_path) {
1025 // TODO(mattm): If there are no valid paths, set best_result_index based on
1026 // number or severity of errors. If there are multiple valid paths, could set
1027 // best_result_index based on prioritization (since due to AIA and such, the
1028 // actual order results were discovered may not match the ideal).
1029 if (!out_result_.HasValidPath()) {
Bob Beck5c7a2a02023-11-20 17:28:21 -07001030 const CertPathBuilderResultPath *old_best_path =
Bob Beckbc97b7a2023-04-18 08:35:15 -06001031 out_result_.GetBestPathPossiblyInvalid();
1032 // If |result_path| is a valid path or if the previous best result did not
1033 // end in a trust anchor but the |result_path| does, then update the best
1034 // result to the new result.
1035 if (result_path->IsValid() ||
1036 (!result_path->last_cert_trust.HasUnspecifiedTrust() && old_best_path &&
1037 old_best_path->last_cert_trust.HasUnspecifiedTrust())) {
1038 out_result_.best_result_index = out_result_.paths.size();
1039 }
1040 }
1041 if (result_path->certs.size() > out_result_.max_depth_seen) {
1042 out_result_.max_depth_seen = result_path->certs.size();
1043 }
1044 out_result_.paths.push_back(std::move(result_path));
1045}
1046
David Benjamin0fbc17a2024-08-21 15:13:10 -04001047BSSL_NAMESPACE_END