Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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