Botan 2.19.5 Crypto and TLS for C&

x509path.cpp
Go to the documentation of this file.
1/*
2* X.509 Certificate Path Validation
3* (C) 2010,2011,2012,2014,2016 Jack Lloyd
4* (C) 2017 Fabian Weissberg, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/x509path.h>
10#include <botan/x509_ext.h>
11#include <botan/pk_keys.h>
12#include <botan/ocsp.h>
13#include <botan/oids.h>
14#include <algorithm>
15#include <chrono>
16#include <vector>
17#include <set>
18#include <string>
19#include <sstream>
20
21#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
22 #include <future>
23 #include <botan/http_util.h>
24#endif
25
26 namespace Botan {
27
28/*
29* PKIX path validation
30*/
31 CertificatePathStatusCodes
32 PKIX::check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
33 std::chrono::system_clock::time_point ref_time,
34 const std::string& hostname,
35 Usage_Type usage,
36 size_t min_signature_algo_strength,
37 const std::set<std::string>& trusted_hashes)
38 {
39 if(cert_path.empty())
40 throw Invalid_Argument("PKIX::check_chain cert_path empty");
41
42 const bool self_signed_ee_cert = (cert_path.size() == 1);
43
44 X509_Time validation_time(ref_time);
45
46 CertificatePathStatusCodes cert_status(cert_path.size());
47
48 if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname))
49 cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH);
50
51 if(!cert_path[0]->allowed_usage(usage))
52 cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE);
53
54 for(size_t i = 0; i != cert_path.size(); ++i)
55 {
56 std::set<Certificate_Status_Code>& status = cert_status.at(i);
57
58 const bool at_self_signed_root = (i == cert_path.size() - 1);
59
60 const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
61
62 const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
63
64 std::unique_ptr<Public_Key> issuer_key(issuer->subject_public_key());
65
66 // Check the signature algorithm is known
67 if(OIDS::oid2str_or_empty(subject->signature_algorithm().get_oid()).empty())
68 {
69 status.insert(Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN);
70 }
71 else
72 {
73 // only perform the following checks if the signature algorithm is known
74 if(!issuer_key)
75 {
76 status.insert(Certificate_Status_Code::CERT_PUBKEY_INVALID);
77 }
78 else
79 {
80 const Certificate_Status_Code sig_status = subject->verify_signature(*issuer_key);
81
82 if(sig_status != Certificate_Status_Code::VERIFIED)
83 status.insert(sig_status);
84
85 if(issuer_key->estimated_strength() < min_signature_algo_strength)
86 status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK);
87 }
88
89 // Ignore untrusted hashes on self-signed roots
90 if(trusted_hashes.size() > 0 && !at_self_signed_root)
91 {
92 if(trusted_hashes.count(subject->hash_used_for_signature()) == 0)
93 status.insert(Certificate_Status_Code::UNTRUSTED_HASH);
94 }
95 }
96 }
97
98
99 // If any of the signatures were invalid, return immediately; we know the
100 // chain is invalid and signature failure is always considered the most
101 // critical result. This does mean other problems in the certificate (eg
102 // expired) will not be reported, but we'd have to assume any such data is
103 // anyway arbitrary considering we couldn't verify the signature chain
104
105 for(size_t i = 0; i != cert_path.size(); ++i)
106 {
107 for(auto status : cert_status.at(i))
108 {
109 // This ignores errors relating to the key or hash being weak since
110 // these are somewhat advisory
111 if(static_cast<uint32_t>(status) >= 5000)
112 {
113 return cert_status;
114 }
115 }
116 }
117
118 if(cert_path[0]->is_CA_cert() == false &&
119 cert_path[0]->has_constraints(KEY_CERT_SIGN))
120 {
121 /*
122 "If the keyCertSign bit is asserted, then the cA bit in the
123 basic constraints extension (Section 4.2.1.9) MUST also be
124 asserted." - RFC 5280
125
126 We don't bother doing this check on the rest of the path since they
127 must have the cA bit asserted or the validation will fail anyway.
128 */
129 cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE);
130 }
131
132 for(size_t i = 0; i != cert_path.size(); ++i)
133 {
134 std::set<Certificate_Status_Code>& status = cert_status.at(i);
135
136 const bool at_self_signed_root = (i == cert_path.size() - 1);
137
138 const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
139
140 const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
141
142 if(at_self_signed_root && (issuer->is_self_signed() == false))
143 {
144 status.insert(Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT);
145 }
146
147 if(subject->issuer_dn() != issuer->subject_dn())
148 {
149 status.insert(Certificate_Status_Code::CHAIN_NAME_MISMATCH);
150 }
151
152 // Check the serial number
153 if(subject->is_serial_negative())
154 {
155 status.insert(Certificate_Status_Code::CERT_SERIAL_NEGATIVE);
156 }
157
158 // Check the subject's DN components' length
159
160 for(const auto& dn_pair : subject->subject_dn().dn_info())
161 {
162 const size_t dn_ub = X509_DN::lookup_ub(dn_pair.first);
163 // dn_pair = <OID,str>
164 if(dn_ub > 0 && dn_pair.second.size() > dn_ub)
165 {
166 status.insert(Certificate_Status_Code::DN_TOO_LONG);
167 }
168 }
169
170 // Check all certs for valid time range
171 if(validation_time < subject->not_before())
172 status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID);
173
174 if(validation_time > subject->not_after())
175 status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED);
176
177 // Check issuer constraints
178 if(!issuer->is_CA_cert() && !self_signed_ee_cert)
179 status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER);
180
181 // Check cert extensions
182
183 if(subject->x509_version() == 1)
184 {
185 if(subject->v2_issuer_key_id().empty() == false ||
186 subject->v2_subject_key_id().empty() == false)
187 {
188 status.insert(Certificate_Status_Code::V2_IDENTIFIERS_IN_V1_CERT);
189 }
190 }
191
192 Extensions extensions = subject->v3_extensions();
193 const auto& extensions_vec = extensions.extensions();
194 if(subject->x509_version() < 3 && !extensions_vec.empty())
195 {
196 status.insert(Certificate_Status_Code::EXT_IN_V1_V2_CERT);
197 }
198 for(auto& extension : extensions_vec)
199 {
200 extension.first->validate(*subject, *issuer, cert_path, cert_status, i);
201 }
202 if(extensions.extensions().size() != extensions.get_extension_oids().size())
203 {
204 status.insert(Certificate_Status_Code::DUPLICATE_CERT_EXTENSION);
205 }
206 }
207
208 // path len check
209 size_t max_path_length = cert_path.size();
210 for(size_t i = cert_path.size() - 1; i > 0 ; --i)
211 {
212 std::set<Certificate_Status_Code>& status = cert_status.at(i);
213 const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
214
215 /*
216 * If the certificate was not self-issued, verify that max_path_length is
217 * greater than zero and decrement max_path_length by 1.
218 */
219 if(subject->subject_dn() != subject->issuer_dn())
220 {
221 if(max_path_length > 0)
222 {
223 --max_path_length;
224 }
225 else
226 {
227 status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG);
228 }
229 }
230
231 /*
232 * If pathLenConstraint is present in the certificate and is less than max_path_length,
233 * set max_path_length to the value of pathLenConstraint.
234 */
235 if(subject->path_limit() != Cert_Extension::NO_CERT_PATH_LIMIT && subject->path_limit() < max_path_length)
236 {
237 max_path_length = subject->path_limit();
238 }
239 }
240
241 return cert_status;
242 }
243
244 CertificatePathStatusCodes
245 PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
246 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
247 const std::vector<Certificate_Store*>& trusted_certstores,
248 std::chrono::system_clock::time_point ref_time,
249 std::chrono::seconds max_ocsp_age)
250 {
251 if(cert_path.empty())
252 throw Invalid_Argument("PKIX::check_ocsp cert_path empty");
253
254 CertificatePathStatusCodes cert_status(cert_path.size() - 1);
255
256 for(size_t i = 0; i != cert_path.size() - 1; ++i)
257 {
258 std::set<Certificate_Status_Code>& status = cert_status.at(i);
259
260 std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
261 std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
262
263 if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr)
264 && (ocsp_responses.at(i)->status() == OCSP::Response_Status_Code::Successful))
265 {
266 try
267 {
268 // When verifying intermediate certificates we need to truncate the
269 // cert_path so that the intermediate under investigation becomes the
270 // last certificate in the chain.
271 std::vector<std::shared_ptr<const X509_Certificate>> ocsp_cert_path(cert_path.begin() + i, cert_path.end());
272 Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, ocsp_cert_path);
273
274 if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK)
275 {
276 // Signature ok, so check the claimed status
277 Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time, max_ocsp_age);
278 status.insert(ocsp_status);
279 }
280 else
281 {
282 // Some signature problem
283 status.insert(ocsp_signature_status);
284 }
285 }
286 catch(Exception&)
287 {
288 status.insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID);
289 }
290 }
291 }
292
293 while(cert_status.size() > 0 && cert_status.back().empty())
294 cert_status.pop_back();
295
296 return cert_status;
297 }
298
299 CertificatePathStatusCodes
300 PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
301 const std::vector<std::shared_ptr<const X509_CRL>>& crls,
302 std::chrono::system_clock::time_point ref_time)
303 {
304 if(cert_path.empty())
305 throw Invalid_Argument("PKIX::check_crl cert_path empty");
306
307 CertificatePathStatusCodes cert_status(cert_path.size());
308 const X509_Time validation_time(ref_time);
309
310 for(size_t i = 0; i != cert_path.size() - 1; ++i)
311 {
312 std::set<Certificate_Status_Code>& status = cert_status.at(i);
313
314 if(i < crls.size() && crls.at(i))
315 {
316 std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
317 std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
318
319 if(!ca->allowed_usage(CRL_SIGN))
320 status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER);
321
322 if(validation_time < crls[i]->this_update())
323 status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID);
324
325 if(validation_time > crls[i]->next_update())
326 status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED);
327
328 if(crls[i]->check_signature(ca->subject_public_key()) == false)
329 status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE);
330
331 status.insert(Certificate_Status_Code::VALID_CRL_CHECKED);
332
333 if(crls[i]->is_revoked(*subject))
334 status.insert(Certificate_Status_Code::CERT_IS_REVOKED);
335
336 std::string dp = subject->crl_distribution_point();
337 if(!dp.empty())
338 {
339 if(dp != crls[i]->crl_issuing_distribution_point())
340 {
341 status.insert(Certificate_Status_Code::NO_MATCHING_CRLDP);
342 }
343 }
344
345 for(const auto& extension : crls[i]->extensions().extensions())
346 {
347 // XXX this is wrong - the OID might be defined but the extention not full parsed
348 // for example see #1652
349
350 // is the extension critical and unknown?
351 if(extension.second && OIDS::oid2str_or_empty(extension.first->oid_of()) == "")
352 {
353 /* NIST Certificate Path Valiadation Testing document: "When an implementation does not recognize a critical extension in the
354 * crlExtensions field, it shall assume that identified certificates have been revoked and are no longer valid"
355 */
356 status.insert(Certificate_Status_Code::CERT_IS_REVOKED);
357 }
358 }
359
360 }
361 }
362
363 while(cert_status.size() > 0 && cert_status.back().empty())
364 cert_status.pop_back();
365
366 return cert_status;
367 }
368
369 CertificatePathStatusCodes
370 PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
371 const std::vector<Certificate_Store*>& certstores,
372 std::chrono::system_clock::time_point ref_time)
373 {
374 if(cert_path.empty())
375 throw Invalid_Argument("PKIX::check_crl cert_path empty");
376
377 if(certstores.empty())
378 throw Invalid_Argument("PKIX::check_crl certstores empty");
379
380 std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
381
382 for(size_t i = 0; i != cert_path.size(); ++i)
383 {
384 BOTAN_ASSERT_NONNULL(cert_path[i]);
385 for(size_t c = 0; c != certstores.size(); ++c)
386 {
387 crls[i] = certstores[c]->find_crl_for(*cert_path[i]);
388 if(crls[i])
389 break;
390 }
391 }
392
393 return PKIX::check_crl(cert_path, crls, ref_time);
394 }
395
396#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
397
398 CertificatePathStatusCodes
399PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
400 const std::vector<Certificate_Store*>& trusted_certstores,
401 std::chrono::system_clock::time_point ref_time,
402 std::chrono::milliseconds timeout,
403 bool ocsp_check_intermediate_CAs,
404 std::chrono::seconds max_ocsp_age)
405 {
406 if(cert_path.empty())
407 throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty");
408
409 std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures;
410
411 size_t to_ocsp = 1;
412
413 if(ocsp_check_intermediate_CAs)
414 to_ocsp = cert_path.size() - 1;
415 if(cert_path.size() == 1)
416 to_ocsp = 0;
417
418 for(size_t i = 0; i < to_ocsp; ++i)
419 {
420 const std::shared_ptr<const X509_Certificate>& subject = cert_path.at(i);
421 const std::shared_ptr<const X509_Certificate>& issuer = cert_path.at(i+1);
422
423 if(subject->ocsp_responder() == "")
424 {
425 ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const OCSP::Response> {
426 return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OCSP_NO_REVOCATION_URL);
427 }));
428 }
429 else
430 {
431 ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const OCSP::Response> {
432 OCSP::Request req(*issuer, BigInt::decode(subject->serial_number()));
433
434 HTTP::Response http;
435 try
436 {
437 http = HTTP::POST_sync(subject->ocsp_responder(),
438 "application/ocsp-request",
439 req.BER_encode(),
440 /*redirects*/1,
441 timeout);
442 }
443 catch(std::exception&)
444 {
445 // log e.what() ?
446 }
447 if (http.status_code() != 200)
448 return std::make_shared<const OCSP::Response>(Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE);
449 // Check the MIME type?
450
451 return std::make_shared<const OCSP::Response>(http.body());
452 }));
453 }
454 }
455
456 std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses;
457
458 for(size_t i = 0; i < ocsp_response_futures.size(); ++i)
459 {
460 ocsp_responses.push_back(ocsp_response_futures[i].get());
461 }
462
463 return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time, max_ocsp_age);
464 }
465
466 CertificatePathStatusCodes
467PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
468 const std::vector<Certificate_Store*>& certstores,
469 Certificate_Store_In_Memory* crl_store,
470 std::chrono::system_clock::time_point ref_time,
471 std::chrono::milliseconds timeout)
472 {
473 if(cert_path.empty())
474 throw Invalid_Argument("PKIX::check_crl_online cert_path empty");
475 if(certstores.empty())
476 throw Invalid_Argument("PKIX::check_crl_online certstores empty");
477
478 std::vector<std::future<std::shared_ptr<const X509_CRL>>> future_crls;
479 std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
480
481 for(size_t i = 0; i != cert_path.size(); ++i)
482 {
483 const std::shared_ptr<const X509_Certificate>& cert = cert_path.at(i);
484 for(size_t c = 0; c != certstores.size(); ++c)
485 {
486 crls[i] = certstores[c]->find_crl_for(*cert);
487 if(crls[i])
488 break;
489 }
490
491 // TODO: check if CRL is expired and re-request?
492
493 // Only request if we don't already have a CRL
494 if(crls[i])
495 {
496 /*
497 We already have a CRL, so just insert this empty one to hold a place in the vector
498 so that indexes match up
499 */
500 future_crls.emplace_back(std::future<std::shared_ptr<const X509_CRL>>());
501 }
502 else if(cert->crl_distribution_point() == "")
503 {
504 // Avoid creating a thread for this case
505 future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const X509_CRL> {
506 throw Not_Implemented("No CRL distribution point for this certificate");
507 }));
508 }
509 else
510 {
511 future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const X509_CRL> {
512 auto http = HTTP::GET_sync(cert->crl_distribution_point(),
513 /*redirects*/ 1, timeout);
514
515 http.throw_unless_ok();
516 // check the mime type?
517 return std::make_shared<const X509_CRL>(http.body());
518 }));
519 }
520 }
521
522 for(size_t i = 0; i != future_crls.size(); ++i)
523 {
524 if(future_crls[i].valid())
525 {
526 try
527 {
528 crls[i] = future_crls[i].get();
529 }
530 catch(std::exception&)
531 {
532 // crls[i] left null
533 // todo: log exception e.what() ?
534 }
535 }
536 }
537
538 const CertificatePathStatusCodes crl_status = PKIX::check_crl(cert_path, crls, ref_time);
539
540 if(crl_store)
541 {
542 for(size_t i = 0; i != crl_status.size(); ++i)
543 {
544 if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED))
545 {
546 // better be non-null, we supposedly validated it
547 BOTAN_ASSERT_NONNULL(crls[i]);
548 crl_store->add_crl(crls[i]);
549 }
550 }
551 }
552
553 return crl_status;
554 }
555
556#endif
557
558 Certificate_Status_Code
559 PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
560 const std::vector<Certificate_Store*>& trusted_certstores,
561 const std::shared_ptr<const X509_Certificate>& end_entity,
562 const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
563 {
564 if(end_entity->is_self_signed())
565 {
566 return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
567 }
568
569 /*
570 * This is an inelegant but functional way of preventing path loops
571 * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate
572 * fingerprints in the path. If there is a duplicate, we error out.
573 * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc.
574 */
575 std::set<std::string> certs_seen;
576
577 cert_path.push_back(end_entity);
578 certs_seen.insert(end_entity->fingerprint("SHA-256"));
579
580 Certificate_Store_In_Memory ee_extras;
581 for(size_t i = 0; i != end_entity_extra.size(); ++i)
582 ee_extras.add_certificate(end_entity_extra[i]);
583
584 // iterate until we reach a root or cannot find the issuer
585 for(;;)
586 {
587 const X509_Certificate& last = *cert_path.back();
588 const X509_DN issuer_dn = last.issuer_dn();
589 const std::vector<uint8_t> auth_key_id = last.authority_key_id();
590
591 std::shared_ptr<const X509_Certificate> issuer;
592 bool trusted_issuer = false;
593
594 for(Certificate_Store* store : trusted_certstores)
595 {
596 issuer = store->find_cert(issuer_dn, auth_key_id);
597 if(issuer)
598 {
599 trusted_issuer = true;
600 break;
601 }
602 }
603
604 if(!issuer)
605 {
606 // fall back to searching supplemental certs
607 issuer = ee_extras.find_cert(issuer_dn, auth_key_id);
608 }
609
610 if(!issuer)
611 return Certificate_Status_Code::CERT_ISSUER_NOT_FOUND;
612
613 const std::string fprint = issuer->fingerprint("SHA-256");
614
615 if(certs_seen.count(fprint) > 0) // already seen?
616 {
617 return Certificate_Status_Code::CERT_CHAIN_LOOP;
618 }
619
620 certs_seen.insert(fprint);
621 cert_path.push_back(issuer);
622
623 if(issuer->is_self_signed())
624 {
625 if(trusted_issuer)
626 {
627 return Certificate_Status_Code::OK;
628 }
629 else
630 {
631 return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
632 }
633 }
634 }
635 }
636
637/**
638 * utilities for PKIX::build_all_certificate_paths
639 */
640 namespace
641{
642// <certificate, trusted?>
643 using cert_maybe_trusted = std::pair<std::shared_ptr<const X509_Certificate>,bool>;
644}
645
646/**
647 * Build all possible certificate paths from the end certificate to self-signed trusted roots.
648 *
649 * All potentially valid paths are put into the cert_paths vector. If no potentially valid paths are found,
650 * one of the encountered errors is returned arbitrarily.
651 *
652 * todo add a path building function that returns detailed information on errors encountered while building
653 * the potentially numerous path candidates.
654 *
655 * Basically, a DFS is performed starting from the end certificate. A stack (vector) serves to control the DFS.
656 * At the beginning of each iteration, a pair is popped from the stack that contains (1) the next certificate
657 * to add to the path (2) a bool that indicates if the certificate is part of a trusted certstore. Ideally, we
658 * follow the unique issuer of the current certificate until a trusted root is reached. However, the issuer DN +
659 * authority key id need not be unique among the certificates used for building the path. In such a case,
660 * we consider all the matching issuers by pushing <IssuerCert, trusted?> on the stack for each of them.
661 *
662 */
663 Certificate_Status_Code
664 PKIX::build_all_certificate_paths(std::vector<std::vector<std::shared_ptr<const X509_Certificate>>>& cert_paths_out,
665 const std::vector<Certificate_Store*>& trusted_certstores,
666 const std::shared_ptr<const X509_Certificate>& end_entity,
667 const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
668 {
669 if(!cert_paths_out.empty())
670 {
671 throw Invalid_Argument("PKIX::build_all_certificate_paths: cert_paths_out must be empty");
672 }
673
674 if(end_entity->is_self_signed())
675 {
676 return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
677 }
678
679 /*
680 * Pile up error messages
681 */
682 std::vector<Certificate_Status_Code> stats;
683
684 Certificate_Store_In_Memory ee_extras;
685 for(size_t i = 0; i != end_entity_extra.size(); ++i)
686 {
687 ee_extras.add_certificate(end_entity_extra[i]);
688 }
689
690 /*
691 * This is an inelegant but functional way of preventing path loops
692 * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate
693 * fingerprints in the path. If there is a duplicate, we error out.
694 * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc.
695 */
696 std::set<std::string> certs_seen;
697
698 // new certs are added and removed from the path during the DFS
699 // it is copied into cert_paths_out when we encounter a trusted root
700 std::vector<std::shared_ptr<const X509_Certificate>> path_so_far;
701
702 // todo can we assume that the end certificate is not trusted?
703 std::vector<cert_maybe_trusted> stack = { {end_entity, false} };
704
705 while(!stack.empty())
706 {
707 // found a deletion marker that guides the DFS, backtracing
708 if(stack.back().first == nullptr)
709 {
710 stack.pop_back();
711 std::string fprint = path_so_far.back()->fingerprint("SHA-256");
712 certs_seen.erase(fprint);
713 path_so_far.pop_back();
714 }
715 // process next cert on the path
716 else
717 {
718 std::shared_ptr<const X509_Certificate> last = stack.back().first;
719 bool trusted = stack.back().second;
720 stack.pop_back();
721
722 // certificate already seen?
723 const std::string fprint = last->fingerprint("SHA-256");
724 if(certs_seen.count(fprint) == 1)
725 {
726 stats.push_back(Certificate_Status_Code::CERT_CHAIN_LOOP);
727 // the current path ended in a loop
728 continue;
729 }
730
731 // the current path ends here
732 if(last->is_self_signed())
733 {
734 // found a trust anchor
735 if(trusted)
736 {
737 cert_paths_out.push_back(path_so_far);
738 cert_paths_out.back().push_back(last);
739
740 continue;
741 }
742 // found an untrustworthy root
743 else
744 {
745 stats.push_back(Certificate_Status_Code::CANNOT_ESTABLISH_TRUST);
746 continue;
747 }
748 }
749
750 const X509_DN issuer_dn = last->issuer_dn();
751 const std::vector<uint8_t> auth_key_id = last->authority_key_id();
752
753 // search for trusted issuers
754 std::vector<std::shared_ptr<const X509_Certificate>> trusted_issuers;
755 for(Certificate_Store* store : trusted_certstores)
756 {
757 auto new_issuers = store->find_all_certs(issuer_dn, auth_key_id);
758 trusted_issuers.insert(trusted_issuers.end(), new_issuers.begin(), new_issuers.end());
759 }
760
761 // search the supplemental certs
762 std::vector<std::shared_ptr<const X509_Certificate>> misc_issuers =
763 ee_extras.find_all_certs(issuer_dn, auth_key_id);
764
765 // if we could not find any issuers, the current path ends here
766 if(trusted_issuers.size() + misc_issuers.size() == 0)
767 {
768 stats.push_back(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND);
769 continue;
770 }
771
772 // push the latest certificate onto the path_so_far
773 path_so_far.push_back(last);
774 certs_seen.insert(fprint);
775
776 // push a deletion marker on the stack for backtracing later
777 stack.push_back({std::shared_ptr<const X509_Certificate>(nullptr),false});
778
779 for(const auto& trusted_cert : trusted_issuers)
780 {
781 stack.push_back({trusted_cert,true});
782 }
783
784 for(const auto& misc : misc_issuers)
785 {
786 stack.push_back({misc,false});
787 }
788 }
789 }
790
791 // could not construct any potentially valid path
792 if(cert_paths_out.empty())
793 {
794 if(stats.empty())
795 throw Internal_Error("X509 path building failed for unknown reasons");
796 else
797 // arbitrarily return the first error
798 return stats[0];
799 }
800 else
801 {
802 return Certificate_Status_Code::OK;
803 }
804 }
805
806
807 void PKIX::merge_revocation_status(CertificatePathStatusCodes& chain_status,
808 const CertificatePathStatusCodes& crl,
809 const CertificatePathStatusCodes& ocsp,
810 bool require_rev_on_end_entity,
811 bool require_rev_on_intermediates)
812 {
813 if(chain_status.empty())
814 throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty");
815
816 for(size_t i = 0; i != chain_status.size() - 1; ++i)
817 {
818 bool had_crl = false, had_ocsp = false;
819
820 if(i < crl.size() && crl[i].size() > 0)
821 {
822 for(auto&& code : crl[i])
823 {
824 if(code == Certificate_Status_Code::VALID_CRL_CHECKED)
825 {
826 had_crl = true;
827 }
828 chain_status[i].insert(code);
829 }
830 }
831
832 if(i < ocsp.size() && ocsp[i].size() > 0)
833 {
834 for(auto&& code : ocsp[i])
835 {
836 if(code == Certificate_Status_Code::OCSP_RESPONSE_GOOD ||
837 code == Certificate_Status_Code::OCSP_NO_REVOCATION_URL || // softfail
838 code == Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE) // softfail
839 {
840 had_ocsp = true;
841 }
842
843 chain_status[i].insert(code);
844 }
845 }
846
847 if(had_crl == false && had_ocsp == false)
848 {
849 if((require_rev_on_end_entity && i == 0) ||
850 (require_rev_on_intermediates && i > 0))
851 {
852 chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA);
853 }
854 }
855 }
856 }
857
858 Certificate_Status_Code PKIX::overall_status(const CertificatePathStatusCodes& cert_status)
859 {
860 if(cert_status.empty())
861 throw Invalid_Argument("PKIX::overall_status empty cert status");
862
863 Certificate_Status_Code overall_status = Certificate_Status_Code::OK;
864
865 // take the "worst" error as overall
866 for(const std::set<Certificate_Status_Code>& s : cert_status)
867 {
868 if(!s.empty())
869 {
870 auto worst = *s.rbegin();
871 // Leave informative OCSP/CRL confirmations on cert-level status only
872 if(worst >= Certificate_Status_Code::FIRST_ERROR_STATUS && worst > overall_status)
873 {
874 overall_status = worst;
875 }
876 }
877 }
878 return overall_status;
879 }
880
881 Path_Validation_Result x509_path_validate(
882 const std::vector<X509_Certificate>& end_certs,
883 const Path_Validation_Restrictions& restrictions,
884 const std::vector<Certificate_Store*>& trusted_roots,
885 const std::string& hostname,
886 Usage_Type usage,
887 std::chrono::system_clock::time_point ref_time,
888 std::chrono::milliseconds ocsp_timeout,
889 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
890 {
891 if(end_certs.empty())
892 {
893 throw Invalid_Argument("x509_path_validate called with no subjects");
894 }
895
896 std::shared_ptr<const X509_Certificate> end_entity(std::make_shared<const X509_Certificate>(end_certs[0]));
897 std::vector<std::shared_ptr<const X509_Certificate>> end_entity_extra;
898 for(size_t i = 1; i < end_certs.size(); ++i)
899 {
900 end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i]));
901 }
902
903 std::vector<std::vector<std::shared_ptr<const X509_Certificate>>> cert_paths;
904 Certificate_Status_Code path_building_result = PKIX::build_all_certificate_paths(cert_paths, trusted_roots, end_entity, end_entity_extra);
905
906 // If we cannot successfully build a chain to a trusted self-signed root, stop now
907 if(path_building_result != Certificate_Status_Code::OK)
908 {
909 return Path_Validation_Result(path_building_result);
910 }
911
912 std::vector<Path_Validation_Result> error_results;
913 // Try validating all the potentially valid paths and return the first one to validate properly
914 for(auto cert_path : cert_paths)
915 {
916 CertificatePathStatusCodes status =
917 PKIX::check_chain(cert_path, ref_time,
918 hostname, usage,
919 restrictions.minimum_key_strength(),
920 restrictions.trusted_hashes());
921
922 CertificatePathStatusCodes crl_status =
923 PKIX::check_crl(cert_path, trusted_roots, ref_time);
924
925 CertificatePathStatusCodes ocsp_status;
926
927 if(ocsp_resp.size() > 0)
928 {
929 ocsp_status = PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time, restrictions.max_ocsp_age());
930 }
931
932 if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0))
933 {
934#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL)
935 ocsp_status = PKIX::check_ocsp_online(cert_path, trusted_roots, ref_time,
936 ocsp_timeout, restrictions.ocsp_all_intermediates());
937#else
938 ocsp_status.resize(1);
939 ocsp_status[0].insert(Certificate_Status_Code::OCSP_NO_HTTP);
940#endif
941 }
942
943 PKIX::merge_revocation_status(status, crl_status, ocsp_status,
944 restrictions.require_revocation_information(),
945 restrictions.ocsp_all_intermediates());
946
947 Path_Validation_Result pvd(status, std::move(cert_path));
948 if(pvd.successful_validation())
949 {
950 return pvd;
951 }
952 else
953 {
954 error_results.push_back(std::move(pvd));
955 }
956 }
957 return error_results[0];
958 }
959
960 Path_Validation_Result x509_path_validate(
961 const X509_Certificate& end_cert,
962 const Path_Validation_Restrictions& restrictions,
963 const std::vector<Certificate_Store*>& trusted_roots,
964 const std::string& hostname,
965 Usage_Type usage,
966 std::chrono::system_clock::time_point when,
967 std::chrono::milliseconds ocsp_timeout,
968 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
969 {
970 std::vector<X509_Certificate> certs;
971 certs.push_back(end_cert);
972 return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
973 }
974
975 Path_Validation_Result x509_path_validate(
976 const std::vector<X509_Certificate>& end_certs,
977 const Path_Validation_Restrictions& restrictions,
978 const Certificate_Store& store,
979 const std::string& hostname,
980 Usage_Type usage,
981 std::chrono::system_clock::time_point when,
982 std::chrono::milliseconds ocsp_timeout,
983 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
984 {
985 std::vector<Certificate_Store*> trusted_roots;
986 trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
987
988 return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
989 }
990
991 Path_Validation_Result x509_path_validate(
992 const X509_Certificate& end_cert,
993 const Path_Validation_Restrictions& restrictions,
994 const Certificate_Store& store,
995 const std::string& hostname,
996 Usage_Type usage,
997 std::chrono::system_clock::time_point when,
998 std::chrono::milliseconds ocsp_timeout,
999 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
1000 {
1001 std::vector<X509_Certificate> certs;
1002 certs.push_back(end_cert);
1003
1004 std::vector<Certificate_Store*> trusted_roots;
1005 trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
1006
1007 return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
1008 }
1009
1010 Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev,
1011 size_t key_strength,
1012 bool ocsp_intermediates,
1013 std::chrono::seconds max_ocsp_age) :
1014 m_require_revocation_information(require_rev),
1015 m_ocsp_all_intermediates(ocsp_intermediates),
1016 m_minimum_key_strength(key_strength),
1017 m_max_ocsp_age(max_ocsp_age)
1018 {
1019 if(key_strength <= 80)
1020 { m_trusted_hashes.insert("SHA-160"); }
1021
1022 m_trusted_hashes.insert("SHA-224");
1023 m_trusted_hashes.insert("SHA-256");
1024 m_trusted_hashes.insert("SHA-384");
1025 m_trusted_hashes.insert("SHA-512");
1026 }
1027
1028 namespace {
1029 CertificatePathStatusCodes find_warnings(const CertificatePathStatusCodes& all_statuses)
1030 {
1031 CertificatePathStatusCodes warnings;
1032 for(const auto& status_set_i : all_statuses)
1033 {
1034 std::set<Certificate_Status_Code> warning_set_i;
1035 for(const auto& code : status_set_i)
1036 {
1037 if(code >= Certificate_Status_Code::FIRST_WARNING_STATUS &&
1038 code < Certificate_Status_Code::FIRST_ERROR_STATUS)
1039 {
1040 warning_set_i.insert(code);
1041 }
1042 }
1043 warnings.push_back(warning_set_i);
1044 }
1045 return warnings;
1046 }
1047}
1048
1049 Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status,
1050 std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) :
1051 m_all_status(status),
1052 m_warnings(find_warnings(m_all_status)),
1053 m_cert_path(cert_chain),
1054 m_overall(PKIX::overall_status(m_all_status))
1055 {
1056 }
1057
1058 const X509_Certificate& Path_Validation_Result::trust_root() const
1059 {
1060 if(m_cert_path.empty())
1061 throw Invalid_State("Path_Validation_Result::trust_root no path set");
1062 if(result() != Certificate_Status_Code::VERIFIED)
1063 throw Invalid_State("Path_Validation_Result::trust_root meaningless with invalid status");
1064
1065 return *m_cert_path[m_cert_path.size()-1];
1066 }
1067
1068std::set<std::string> Path_Validation_Result::trusted_hashes() const
1069 {
1070 std::set<std::string> hashes;
1071 for(size_t i = 0; i != m_cert_path.size(); ++i)
1072 hashes.insert(m_cert_path[i]->hash_used_for_signature());
1073 return hashes;
1074 }
1075
1076 bool Path_Validation_Result::successful_validation() const
1077 {
1078 return (result() == Certificate_Status_Code::VERIFIED ||
1079 result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD ||
1080 result() == Certificate_Status_Code::VALID_CRL_CHECKED);
1081 }
1082
1083 bool Path_Validation_Result::no_warnings() const
1084 {
1085 for(auto status_set_i : m_warnings)
1086 if(!status_set_i.empty())
1087 return false;
1088 return true;
1089 }
1090
1091 CertificatePathStatusCodes Path_Validation_Result::warnings() const
1092 {
1093 return m_warnings;
1094 }
1095
1096std::string Path_Validation_Result::result_string() const
1097 {
1098 return status_string(result());
1099 }
1100
1101 const char* Path_Validation_Result::status_string(Certificate_Status_Code code)
1102 {
1103 if(const char* s = to_string(code))
1104 return s;
1105
1106 return "Unknown error";
1107 }
1108
1109std::string Path_Validation_Result::warnings_string() const
1110 {
1111 const std::string sep(", ");
1112 std::string res;
1113 for(size_t i = 0; i < m_warnings.size(); i++)
1114 {
1115 for(auto code : m_warnings[i])
1116 res += "[" + std::to_string(i) + "] " + status_string(code) + sep;
1117 }
1118 // remove last sep
1119 if(res.size() >= sep.size())
1120 res = res.substr(0, res.size() - sep.size());
1121 return res;
1122 }
1123}
BOTAN_ASSERT_NONNULL
#define BOTAN_ASSERT_NONNULL(ptr)
Definition: assert.h:107
Botan::ASN1_Time
Definition: asn1_obj.h:328
Botan::BigInt::decode
static BigInt decode(const uint8_t buf[], size_t length)
Definition: bigint.h:817
Botan::Certificate_Store_In_Memory
Definition: certstor.h:85
Botan::Certificate_Store_In_Memory::find_cert
std::shared_ptr< const X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition: certstor.cpp:65
Botan::Certificate_Store_In_Memory::find_all_certs
std::vector< std::shared_ptr< const X509_Certificate > > find_all_certs(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition: certstor.cpp:86
Botan::Certificate_Store_In_Memory::add_certificate
void add_certificate(const X509_Certificate &cert)
Definition: certstor.cpp:38
Botan::Certificate_Store
Definition: certstor.h:20
Botan::Exception
Definition: exceptn.h:86
Botan::Extensions
Definition: pkix_types.h:436
Botan::Extensions::get_extension_oids
const std::vector< OID > & get_extension_oids() const
Definition: pkix_types.h:474
Botan::Extensions::extensions
std::vector< std::pair< std::unique_ptr< Certificate_Extension >, bool > > extensions() const
Definition: x509_ext.cpp:217
Botan::Internal_Error
Definition: exceptn.h:342
Botan::Invalid_Argument
Definition: exceptn.h:137
Botan::Invalid_State
Definition: exceptn.h:216
Botan::Path_Validation_Restrictions
Definition: x509path.h:35
Botan::Path_Validation_Restrictions::require_revocation_information
bool require_revocation_information() const
Definition: x509path.h:85
Botan::Path_Validation_Restrictions::ocsp_all_intermediates
bool ocsp_all_intermediates() const
Definition: x509path.h:92
Botan::Path_Validation_Restrictions::trusted_hashes
const std::set< std::string > & trusted_hashes() const
Definition: x509path.h:98
Botan::Path_Validation_Restrictions::max_ocsp_age
std::chrono::seconds max_ocsp_age() const
Definition: x509path.h:111
Botan::Path_Validation_Restrictions::Path_Validation_Restrictions
Path_Validation_Restrictions(bool require_rev=false, size_t minimum_key_strength=110, bool ocsp_all_intermediates=false, std::chrono::seconds max_ocsp_age=std::chrono::seconds::zero())
Definition: x509path.cpp:1010
Botan::Path_Validation_Restrictions::minimum_key_strength
size_t minimum_key_strength() const
Definition: x509path.h:104
Botan::Path_Validation_Result
Definition: x509path.h:126
Botan::Path_Validation_Result::result
Certificate_Status_Code result() const
Definition: x509path.h:161
Botan::Path_Validation_Result::Path_Validation_Result
Path_Validation_Result(CertificatePathStatusCodes status, std::vector< std::shared_ptr< const X509_Certificate > > &&cert_chain)
Definition: x509path.cpp:1049
Botan::Path_Validation_Result::successful_validation
bool successful_validation() const
Definition: x509path.cpp:1076
Botan::Path_Validation_Result::status_string
static const char * status_string(Certificate_Status_Code code)
Definition: x509path.cpp:1101
Botan::Path_Validation_Result::trust_root
const X509_Certificate & trust_root() const
Definition: x509path.cpp:1058
Botan::Path_Validation_Result::no_warnings
bool no_warnings() const
Definition: x509path.cpp:1083
Botan::Path_Validation_Result::result_string
std::string result_string() const
Definition: x509path.cpp:1096
Botan::Path_Validation_Result::trusted_hashes
std::set< std::string > trusted_hashes() const
Definition: x509path.cpp:1068
Botan::Path_Validation_Result::warnings_string
std::string warnings_string() const
Definition: x509path.cpp:1109
Botan::Path_Validation_Result::warnings
CertificatePathStatusCodes warnings() const
Definition: x509path.cpp:1091
Botan::X509_Certificate
Definition: x509cert.h:38
Botan::X509_Certificate::authority_key_id
const std::vector< uint8_t > & authority_key_id() const
Definition: x509cert.cpp:451
Botan::X509_Certificate::issuer_dn
const X509_DN & issuer_dn() const
Definition: x509cert.cpp:472
Botan::X509_DN
Definition: pkix_types.h:43
Botan::X509_DN::lookup_ub
static size_t lookup_ub(const OID &oid)
Definition: x509_dn_ub.cpp:47
Botan::ASN1::to_string
std::string to_string(const BER_Object &obj)
Definition: asn1_obj.cpp:213
Botan::HTTP::GET_sync
Response GET_sync(const std::string &url, size_t allowable_redirects, std::chrono::milliseconds timeout)
Definition: http_util.cpp:249
Botan::HTTP::POST_sync
Response POST_sync(const std::string &url, const std::string &content_type, const std::vector< uint8_t > &body, size_t allowable_redirects, std::chrono::milliseconds timeout)
Definition: http_util.cpp:256
Botan::OCSP::Response_Status_Code::Successful
@ Successful
Botan::OIDS::oid2str_or_empty
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
Definition: oids.cpp:111
Botan::PKIX::merge_revocation_status
void merge_revocation_status(CertificatePathStatusCodes &chain_status, const CertificatePathStatusCodes &crl_status, const CertificatePathStatusCodes &ocsp_status, bool require_rev_on_end_entity, bool require_rev_on_intermediates)
Definition: x509path.cpp:807
Botan::PKIX::check_chain
CertificatePathStatusCodes check_chain(const std::vector< std::shared_ptr< const X509_Certificate > > &cert_path, std::chrono::system_clock::time_point ref_time, const std::string &hostname, Usage_Type usage, size_t min_signature_algo_strength, const std::set< std::string > &trusted_hashes)
Definition: x509path.cpp:32
Botan::PKIX::check_crl
CertificatePathStatusCodes check_crl(const std::vector< std::shared_ptr< const X509_Certificate > > &cert_path, const std::vector< std::shared_ptr< const X509_CRL > > &crls, std::chrono::system_clock::time_point ref_time)
Definition: x509path.cpp:300
Botan::PKIX::overall_status
Certificate_Status_Code overall_status(const CertificatePathStatusCodes &cert_status)
Definition: x509path.cpp:858
Botan::PKIX::check_ocsp
CertificatePathStatusCodes check_ocsp(const std::vector< std::shared_ptr< const X509_Certificate > > &cert_path, const std::vector< std::shared_ptr< const OCSP::Response > > &ocsp_responses, const std::vector< Certificate_Store * > &certstores, std::chrono::system_clock::time_point ref_time, std::chrono::seconds max_ocsp_age=std::chrono::seconds::zero())
Definition: x509path.cpp:245
Botan::PKIX::build_certificate_path
Certificate_Status_Code build_certificate_path(std::vector< std::shared_ptr< const X509_Certificate > > &cert_path_out, const std::vector< Certificate_Store * > &trusted_certstores, const std::shared_ptr< const X509_Certificate > &end_entity, const std::vector< std::shared_ptr< const X509_Certificate > > &end_entity_extra)
Definition: x509path.cpp:559
Botan::PKIX::build_all_certificate_paths
Certificate_Status_Code build_all_certificate_paths(std::vector< std::vector< std::shared_ptr< const X509_Certificate > > > &cert_paths, const std::vector< Certificate_Store * > &trusted_certstores, const std::shared_ptr< const X509_Certificate > &end_entity, const std::vector< std::shared_ptr< const X509_Certificate > > &end_entity_extra)
Definition: x509path.cpp:664
Botan
Definition: alg_id.cpp:13
Botan::CertificatePathStatusCodes
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition: x509path.h:29
Botan::x509_path_validate
Path_Validation_Result x509_path_validate(const std::vector< X509_Certificate > &end_certs, const Path_Validation_Restrictions &restrictions, const std::vector< Certificate_Store * > &trusted_roots, const std::string &hostname, Usage_Type usage, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds ocsp_timeout, const std::vector< std::shared_ptr< const OCSP::Response > > &ocsp_resp)
Definition: x509path.cpp:881
Botan::Usage_Type
Usage_Type
Definition: x509cert.h:23
Botan::to_string
std::string to_string(ErrorType type)
Convert an ErrorType to string.
Definition: exceptn.cpp:11
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: pkix_enums.h:17
Botan::Certificate_Status_Code::DUPLICATE_CERT_EXTENSION
@ DUPLICATE_CERT_EXTENSION
Botan::Certificate_Status_Code::CERT_SERIAL_NEGATIVE
@ CERT_SERIAL_NEGATIVE
Botan::Certificate_Status_Code::INVALID_USAGE
@ INVALID_USAGE
Botan::Certificate_Status_Code::CERT_PUBKEY_INVALID
@ CERT_PUBKEY_INVALID
Botan::Certificate_Status_Code::FIRST_WARNING_STATUS
@ FIRST_WARNING_STATUS
Botan::Certificate_Status_Code::CERT_NAME_NOMATCH
@ CERT_NAME_NOMATCH
Botan::Certificate_Status_Code::VERIFIED
@ VERIFIED
Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER
@ CA_CERT_NOT_FOR_CRL_ISSUER
Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER
@ CA_CERT_NOT_FOR_CERT_ISSUER
Botan::Certificate_Status_Code::OCSP_NO_REVOCATION_URL
@ OCSP_NO_REVOCATION_URL
Botan::Certificate_Status_Code::CRL_BAD_SIGNATURE
@ CRL_BAD_SIGNATURE
Botan::Certificate_Status_Code::CRL_HAS_EXPIRED
@ CRL_HAS_EXPIRED
Botan::Certificate_Status_Code::CERT_CHAIN_LOOP
@ CERT_CHAIN_LOOP
Botan::Certificate_Status_Code::OCSP_RESPONSE_INVALID
@ OCSP_RESPONSE_INVALID
Botan::Certificate_Status_Code::OCSP_SERVER_NOT_AVAILABLE
@ OCSP_SERVER_NOT_AVAILABLE
Botan::Certificate_Status_Code::OCSP_NO_HTTP
@ OCSP_NO_HTTP
Botan::Certificate_Status_Code::UNTRUSTED_HASH
@ UNTRUSTED_HASH
Botan::Certificate_Status_Code::VALID_CRL_CHECKED
@ VALID_CRL_CHECKED
Botan::Certificate_Status_Code::FIRST_ERROR_STATUS
@ FIRST_ERROR_STATUS
Botan::Certificate_Status_Code::CERT_IS_REVOKED
@ CERT_IS_REVOKED
Botan::Certificate_Status_Code::CERT_HAS_EXPIRED
@ CERT_HAS_EXPIRED
Botan::Certificate_Status_Code::DN_TOO_LONG
@ DN_TOO_LONG
Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD
@ OCSP_RESPONSE_GOOD
Botan::Certificate_Status_Code::SIGNATURE_ALGO_UNKNOWN
@ SIGNATURE_ALGO_UNKNOWN
Botan::Certificate_Status_Code::OCSP_SIGNATURE_OK
@ OCSP_SIGNATURE_OK
Botan::Certificate_Status_Code::CERT_CHAIN_TOO_LONG
@ CERT_CHAIN_TOO_LONG
Botan::Certificate_Status_Code::NO_REVOCATION_DATA
@ NO_REVOCATION_DATA
Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND
@ CERT_ISSUER_NOT_FOUND
Botan::Certificate_Status_Code::CERT_NOT_YET_VALID
@ CERT_NOT_YET_VALID
Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST
@ CANNOT_ESTABLISH_TRUST
Botan::Certificate_Status_Code::CRL_NOT_YET_VALID
@ CRL_NOT_YET_VALID
Botan::Certificate_Status_Code::V2_IDENTIFIERS_IN_V1_CERT
@ V2_IDENTIFIERS_IN_V1_CERT
Botan::Certificate_Status_Code::NO_MATCHING_CRLDP
@ NO_MATCHING_CRLDP
Botan::Certificate_Status_Code::EXT_IN_V1_V2_CERT
@ EXT_IN_V1_V2_CERT
Botan::Certificate_Status_Code::OK
@ OK
Botan::Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK
@ SIGNATURE_METHOD_TOO_WEAK
Botan::Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT
@ CHAIN_LACKS_TRUST_ROOT
Botan::Certificate_Status_Code::CHAIN_NAME_MISMATCH
@ CHAIN_NAME_MISMATCH
Botan::CRL_SIGN
@ CRL_SIGN
Definition: pkix_enums.h:114
Botan::KEY_CERT_SIGN
@ KEY_CERT_SIGN
Definition: pkix_enums.h:113