Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- Namespace List
- Namespace Members

Functions
Botan::PKIX Namespace Reference

## Functions
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)
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)
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)
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)
CertificatePathStatusCodes | check_crl (const std::vector< std::shared_ptr< const X509_Certificate >> &cert_path, const std::vector< Certificate_Store * > &certstores, std::chrono::system_clock::time_point ref_time)
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())
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)
Certificate_Status_Code | overall_status (const CertificatePathStatusCodes &cert_status)

## Detailed Description

namespace PKIX holds the building blocks that are called by x509_path_validate. This allows custom validation logic to be written by applications and makes for easier testing, but unless you're positive you know what you're doing you probably want to just call x509_path_validate instead.

## Function Documentation

Certificate_Status_Code Botan::PKIX::build_all_certificate_paths | ( | std::vector< std::vector< std::shared_ptr< const X509_Certificate >>> & | cert_paths_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
| ) |  |

Build all possible certificate paths from the end certificate to self-signed trusted roots.

All potentially valid paths are put into the cert_paths vector. If no potentially valid paths are found, one of the encountered errors is returned arbitrarily.

todo add a path building function that returns detailed information on errors encountered while building the potentially numerous path candidates.

Basically, a DFS is performed starting from the end certificate. A stack (vector) serves to control the DFS. At the beginning of each iteration, a pair is popped from the stack that contains (1) the next certificate to add to the path (2) a bool that indicates if the certificate is part of a trusted certstore. Ideally, we follow the unique issuer of the current certificate until a trusted root is reached. However, the issuer DN + authority key id need not be unique among the certificates used for building the path. In such a case, we consider all the matching issuers by pushing <IssuerCert, trusted?> on the stack for each of them.

Definition at line 619 of file x509path.cpp.

References Botan::Certificate_Store_In_Memory::add_certificate(), Botan::CANNOT_ESTABLISH_TRUST, Botan::CERT_CHAIN_LOOP, Botan::CERT_ISSUER_NOT_FOUND, Botan::Certificate_Store_In_Memory::find_all_certs(), and Botan::OK.

Referenced by Botan::x509_path_validate().

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 }
Botan::OCSP::Response_Status_Code::Internal_Error

Certificate_Status_Code Botan::PKIX::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
| ) |  |

Build certificate path

Parameters

  cert_path_out | output parameter, cert_path will be appended to this vector
  trusted_certstores | list of certificate stores that contain trusted certificates
  end_entity | the cert to be validated
  end_entity_extra | optional list of additional untrusted certs for path building

Returns
  result of the path building operation (OK or error)

Definition at line 514 of file x509path.cpp.

References Botan::Certificate_Store_In_Memory::add_certificate(), Botan::X509_Certificate::authority_key_id(), Botan::CANNOT_ESTABLISH_TRUST, Botan::CERT_CHAIN_LOOP, Botan::CERT_ISSUER_NOT_FOUND, Botan::Certificate_Store_In_Memory::find_cert(), Botan::X509_Certificate::issuer_dn(), and Botan::OK.

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 }

CertificatePathStatusCodes Botan::PKIX::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
| ) |  |

Check the certificate chain, but not any revocation data

Parameters

  cert_path | path built by build_certificate_path with OK result
  ref_time | whatever time you want to perform the validation against (normally current system clock)
  hostname | the hostname
  usage | end entity usage checks
  min_signature_algo_strength | 80 or 110 typically Note 80 allows 1024 bit RSA and SHA-1. 110 allows 2048 bit RSA and SHA-2. Using 128 requires ECC (P-256) or ~3000 bit RSA keys.
  trusted_hashes | set of trusted hash functions, empty means accept any hash we have an OID for

Returns
  vector of results on per certificate in the path, each containing a set of results. If all codes in the set are < Certificate_Status_Code::FIRST_ERROR_STATUS, then the result for that certificate is successful. If all results are

Definition at line 32 of file x509path.cpp.

References Botan::CA_CERT_NOT_FOR_CERT_ISSUER, Botan::CERT_CHAIN_TOO_LONG, Botan::CERT_HAS_EXPIRED, Botan::CERT_NAME_NOMATCH, Botan::CERT_NOT_YET_VALID, Botan::CERT_PUBKEY_INVALID, Botan::CERT_SERIAL_NEGATIVE, Botan::CHAIN_LACKS_TRUST_ROOT, Botan::CHAIN_NAME_MISMATCH, Botan::DN_TOO_LONG, Botan::DUPLICATE_CERT_EXTENSION, Botan::EXT_IN_V1_V2_CERT, Botan::Extensions::extensions(), Botan::Extensions::get_extension_oids(), Botan::INVALID_USAGE, Botan::KEY_CERT_SIGN, Botan::X509_DN::lookup_ub(), Botan::OIDS::oid2str_or_empty(), Botan::SIGNATURE_ALGO_UNKNOWN, Botan::SIGNATURE_METHOD_TOO_WEAK, Botan::UNTRUSTED_HASH, and Botan::VERIFIED.

Referenced by Botan::x509_path_validate().

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 }
KEY_CERT_SIGN
Definition: ffi.h:1553
Botan::OIDS::oid2str_or_empty
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
Definition: oids.cpp:111
Botan::CertificatePathStatusCodes
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition: x509path.h:29
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:19

CertificatePathStatusCodes Botan::PKIX::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
| ) |  |

Check CRLs for revocation information

Parameters

  cert_path | path already validated by check_chain
  crls | the list of CRLs to check, it is assumed that crls[i] (if not null) is the associated CRL for the subject in cert_path[i].
  ref_time | whatever time you want to perform the validation against (normally current system clock)

Returns
  revocation status

Definition at line 255 of file x509path.cpp.

References Botan::CA_CERT_NOT_FOR_CRL_ISSUER, Botan::CERT_IS_REVOKED, Botan::CRL_BAD_SIGNATURE, Botan::CRL_HAS_EXPIRED, Botan::CRL_NOT_YET_VALID, Botan::CRL_SIGN, Botan::NO_MATCHING_CRLDP, Botan::OIDS::oid2str_or_empty(), and Botan::VALID_CRL_CHECKED.

Referenced by check_crl(), and Botan::x509_path_validate().

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 }
CRL_SIGN
Definition: ffi.h:1554
Botan::OIDS::oid2str_or_empty
BOTAN_UNSTABLE_API std::string oid2str_or_empty(const OID &oid)
Definition: oids.cpp:111
Botan::CertificatePathStatusCodes
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition: x509path.h:29

CertificatePathStatusCodes Botan::PKIX::check_crl | ( | const std::vector< std::shared_ptr< const X509_Certificate >> & | cert_path,
|  | const std::vector< Certificate_Store * > & | certstores,
|  | std::chrono::system_clock::time_point | ref_time
| ) |  |

Check CRLs for revocation information

Parameters

  cert_path | path already validated by check_chain
  certstores | a list of certificate stores to query for the CRL
  ref_time | whatever time you want to perform the validation against (normally current system clock)

Returns
  revocation status

Definition at line 325 of file x509path.cpp.

References BOTAN_ASSERT_NONNULL, and check_crl().

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 }
BOTAN_ASSERT_NONNULL
#define BOTAN_ASSERT_NONNULL(ptr)
Definition: assert.h:107
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

CertificatePathStatusCodes Botan::PKIX::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()`
| ) |  |

Check OCSP responses for revocation information

Parameters

  cert_path | path already validated by check_chain
  ocsp_responses | the OCSP responses to consider
  certstores | trusted roots
  ref_time | whatever time you want to perform the validation against (normally current system clock)
  max_ocsp_age | maximum age of OCSP responses w/o next_update. If zero, there is no maximum age

Returns
  revocation status

Definition at line 204 of file x509path.cpp.

References Botan::OCSP_RESPONSE_INVALID, Botan::OCSP_SIGNATURE_OK, and Botan::OCSP::Successful.

Referenced by Botan::x509_path_validate().

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 }
Botan::CertificatePathStatusCodes
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition: x509path.h:29
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:19

void Botan::PKIX::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
| ) |  |

Merge the results from CRL and/or OCSP checks into chain_status

Parameters

  chain_status | the certificate status
  crl_status | results from check_crl
  ocsp_status | results from check_ocsp
  require_rev_on_end_entity | require valid CRL or OCSP on end-entity cert
  require_rev_on_intermediates | require valid CRL or OCSP on all intermediate certificates

Definition at line 762 of file x509path.cpp.

References Botan::NO_REVOCATION_DATA, Botan::OCSP_NO_REVOCATION_URL, Botan::OCSP_RESPONSE_GOOD, Botan::OCSP_SERVER_NOT_AVAILABLE, and Botan::VALID_CRL_CHECKED.

Referenced by Botan::x509_path_validate().

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 }

Certificate_Status_Code Botan::PKIX::overall_status | ( | const CertificatePathStatusCodes & | cert_status | ) |

Find overall status (OK, error) of a validation

Parameters

  cert_status | result of merge_revocation_status or check_chain

Definition at line 813 of file x509path.cpp.

References Botan::FIRST_ERROR_STATUS, and Botan::OK.

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 }
Botan::PKIX::overall_status
Certificate_Status_Code overall_status(const CertificatePathStatusCodes &cert_status)
Definition: x509path.cpp:813
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:19