Botan 3.13.0
Crypto and TLS for C&
Botan::PKIX Namespace Reference

Functions

Certificate_Status_Code build_all_certificate_paths (std::vector< std::vector< X509_Certificate > > &cert_paths, const std::vector< Certificate_Store * > &trusted_certstores, const X509_Certificate &end_entity, const std::vector< X509_Certificate > &end_entity_extra, std::optional< size_t > max_paths=std::nullopt)
Certificate_Status_Code build_certificate_path (std::vector< X509_Certificate > &cert_path_out, const std::vector< Certificate_Store * > &trusted_certstores, const X509_Certificate &end_entity, const std::vector< X509_Certificate > &end_entity_extra, std::optional< size_t > max_paths=std::nullopt)
CertificatePathStatusCodes check_chain (const std::vector< X509_Certificate > &cert_path, std::chrono::system_clock::time_point ref_time, std::string_view hostname, Usage_Type usage, const Path_Validation_Restrictions &restrictions)
CertificatePathStatusCodes check_crl (const std::vector< X509_Certificate > &cert_path, const std::vector< Certificate_Store * > &certstores, std::chrono::system_clock::time_point ref_time)
CertificatePathStatusCodes check_crl (const std::vector< X509_Certificate > &cert_path, const std::vector< std::optional< X509_CRL > > &crls, std::chrono::system_clock::time_point ref_time)
CertificatePathStatusCodes check_ocsp (const std::vector< X509_Certificate > &cert_path, const std::vector< std::optional< OCSP::Response > > &ocsp_responses, const std::vector< Certificate_Store * > &certstores, std::chrono::system_clock::time_point ref_time, const Path_Validation_Restrictions &restrictions)
void merge_revocation_status (CertificatePathStatusCodes &chain_status, const CertificatePathStatusCodes &crl_status, const CertificatePathStatusCodes &ocsp_status, const Path_Validation_Restrictions &restrictions)
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

◆ build_all_certificate_paths()

Certificate_Status_Code Botan::PKIX::build_all_certificate_paths ( std::vector< std::vector< X509_Certificate > > & cert_paths,
const std::vector< Certificate_Store * > & trusted_certstores,
const X509_Certificate & end_entity,
const std::vector< X509_Certificate > & end_entity_extra,
std::optional< size_t > max_paths = std::nullopt )

Create all certificate paths by identifying all possible routes from the end-entity certificate to any certificate in the certificate store list. Paths may also end in intermediate or leaf certificates found in the certificate stores.

WARNING: The validity (e.g. signatures or constraints) of the output path IS NOT checked.

Parameters
cert_pathsoutput parameter to be filled with all discovered certificate paths
trusted_certstoreslist of certificate stores that contain trusted certificates
end_entitythe cert to be validated
end_entity_extraoptional list of additional untrusted certs for path building
max_pathsif set, enumerate at most this many paths and return EXCEEDED_SEARCH_LIMITS if more paths exist; if nullopt, unbounded
Returns
result of the path building operation (OK or error)

Definition at line 1073 of file x509path.cpp.

1077 {
1078 if(!cert_paths_out.empty()) {
1079 throw Invalid_Argument("PKIX::build_all_certificate_paths: cert_paths_out must be empty");
1080 }
1081 CertificatePathBuilder builder(
1082 trusted_certstores, end_entity, end_entity_extra, PathBuildingDfsBudget, /*require_self_signed=*/false);
1083
1084 while(auto path = builder.next()) {
1085 BOTAN_ASSERT_NOMSG(path->empty() == false);
1086 if(max_paths.has_value() && cert_paths_out.size() >= max_paths.value()) {
1087 // More paths exist than the caller permitted us to enumerate
1089 }
1090 cert_paths_out.push_back(std::move(*path));
1091 }
1092
1093 if(!cert_paths_out.empty()) {
1094 // Was able to generate at least one potential path
1096 } else {
1097 // Could not construct any potentially valid path...
1098 return builder.error();
1099 }
1100}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75

References BOTAN_ASSERT_NOMSG, Botan::EXCEEDED_SEARCH_LIMITS, and Botan::OK.

◆ build_certificate_path()

Certificate_Status_Code Botan::PKIX::build_certificate_path ( std::vector< X509_Certificate > & cert_path_out,
const std::vector< Certificate_Store * > & trusted_certstores,
const X509_Certificate & end_entity,
const std::vector< X509_Certificate > & end_entity_extra,
std::optional< size_t > max_paths = std::nullopt )

Same as build_all_certificate_paths but only outputs a single path. If there are paths ending in self-signed certificates, these are prioritized over paths ending in intermediate or leaf certificates of the certificate store.

WARNING: The validity (e.g. signatures or constraints) of the output path IS NOT checked.

Parameters
cert_path_outoutput parameter, cert_path will be appended to this vector
trusted_certstoreslist of certificate stores that contain trusted certificates
end_entitythe cert to be validated
end_entity_extraoptional list of additional untrusted certs for path building
max_pathsif set, examine at most this many candidate paths; if nullopt, unbounded
Returns
result of the path building operation (OK or error)

Definition at line 1028 of file x509path.cpp.

1032 {
1033 if(max_paths.has_value() && max_paths.value() == 0) {
1035 }
1036
1037 CertificatePathBuilder builder(
1038 trusted_certstores, end_entity, end_entity_extra, PathBuildingDfsBudget, /*require_self_signed=*/false);
1039
1040 std::vector<X509_Certificate> first_path;
1041 size_t paths_examined = 0;
1042
1043 while(auto path = builder.next()) {
1044 BOTAN_ASSERT_NOMSG(path->empty() == false);
1045
1046 if(max_paths.has_value() && paths_examined >= max_paths.value()) {
1047 break;
1048 }
1049 paths_examined += 1;
1050
1051 // Prefer paths ending in self-signed certificates.
1052 if(path->back().is_self_signed()) {
1053 cert_path.insert(cert_path.end(), path->begin(), path->end());
1055 }
1056
1057 // Save the first path for later just in case we find nothing better
1058 if(first_path.empty()) {
1059 first_path = std::move(*path);
1060 }
1061 }
1062
1063 if(!first_path.empty()) {
1064 // We found a path, it's not self-signed but it's as good as can be formed...
1065 cert_path.insert(cert_path.end(), first_path.begin(), first_path.end());
1067 }
1068
1069 // Failed to build any path at all
1070 return builder.error();
1071}

References BOTAN_ASSERT_NOMSG, Botan::EXCEEDED_SEARCH_LIMITS, and Botan::OK.

◆ check_chain()

CertificatePathStatusCodes Botan::PKIX::check_chain ( const std::vector< X509_Certificate > & cert_path,
std::chrono::system_clock::time_point ref_time,
std::string_view hostname,
Usage_Type usage,
const Path_Validation_Restrictions & restrictions )

Check the certificate chain, but not any revocation data

Parameters
cert_pathpath built by build_certificate_path with OK result. The first element is the end entity certificate, the last element is the trusted root certificate.
ref_timewhatever time you want to perform the validation against (normally current system clock)
hostnamethe hostname
usageend entity usage checks
restrictionsthe relevant path validation restrictions object
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 344 of file x509path.cpp.

348 {
349 if(cert_path.empty()) {
350 throw Invalid_Argument("PKIX::check_chain cert_path empty");
351 }
352
353 const bool is_end_entity_trust_anchor = (cert_path.size() == 1);
354
355 const X509_Time validation_time(ref_time);
356
357 CertificatePathStatusCodes cert_status(cert_path.size());
358
359 // Before anything else verify the entire chain of signatures
360 for(size_t i = 0; i != cert_path.size(); ++i) {
361 std::set<Certificate_Status_Code>& status = cert_status.at(i);
362
363 const bool at_trust_anchor = (i == cert_path.size() - 1);
364
365 const X509_Certificate& subject = cert_path[i];
366
367 // If using intermediate CAs as trust anchors, the signature of the trust
368 // anchor cannot be verified since the issuer is not part of the
369 // certificate chain
370 if(!restrictions.require_self_signed_trust_anchors() && at_trust_anchor && !subject.is_self_signed()) {
371 continue;
372 }
373
374 const X509_Certificate& issuer = cert_path[at_trust_anchor ? (i) : (i + 1)];
375
376 // Check the signature algorithm is known
377 if(!subject.signature_algorithm().oid().registered_oid()) {
379 } else {
380 std::unique_ptr<Public_Key> issuer_key;
381 try {
382 issuer_key = issuer.subject_public_key();
383 } catch(...) {
385 }
386
387 if(issuer_key) {
388 if(issuer_key->estimated_strength() < restrictions.minimum_key_strength()) {
390 }
391
392 const auto sig_status = subject.verify_signature(*issuer_key);
393
394 if(sig_status.first != Certificate_Status_Code::VERIFIED) {
395 status.insert(sig_status.first);
396 } else {
397 // Signature is valid, check if hash used was acceptable
398 const std::string hash_used_for_signature = sig_status.second;
399 BOTAN_ASSERT_NOMSG(!hash_used_for_signature.empty());
400 const auto& trusted_hashes = restrictions.trusted_hashes();
401
402 // Ignore untrusted hashes on self-signed roots
403 if(!trusted_hashes.empty() && !at_trust_anchor) {
404 if(!trusted_hashes.contains(hash_used_for_signature)) {
406 }
407 }
408 }
409 }
410 }
411 }
412
413 // If any of the signatures were invalid, return immediately; we know the
414 // chain is invalid and signature failure is always considered the most
415 // critical result. This does mean other problems in the certificate (eg
416 // expired) will not be reported, but we'd have to assume any such data is
417 // anyway arbitrary considering we couldn't verify the signature chain
418
419 for(size_t i = 0; i != cert_path.size(); ++i) {
420 for(auto status : cert_status.at(i)) {
421 // This ignores errors relating to the key or hash being weak since
422 // these are somewhat advisory
423 if(static_cast<uint32_t>(status) >= 5000) {
424 return cert_status;
425 }
426 }
427 }
428
429 if(!hostname.empty() && !cert_path[0].matches_dns_name(hostname)) {
430 cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH);
431 }
432
433 if(!cert_path[0].allowed_usage(usage)) {
434 if(usage == Usage_Type::OCSP_RESPONDER) {
436 }
437 cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE);
438 }
439
440 if(cert_path[0].has_constraints(Key_Constraints::KeyCertSign) && cert_path[0].is_CA_cert() == false) {
441 /*
442 "If the keyCertSign bit is asserted, then the cA bit in the
443 basic constraints extension (Section 4.2.1.9) MUST also be
444 asserted." - RFC 5280
445
446 We don't bother doing this check on the rest of the path since they
447 must have the cA bit asserted or the validation will fail anyway.
448 */
449 cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE);
450 }
451
452 for(size_t i = 0; i != cert_path.size(); ++i) {
453 std::set<Certificate_Status_Code>& status = cert_status.at(i);
454
455 const bool at_trust_anchor = (i == cert_path.size() - 1);
456
457 const X509_Certificate& subject = cert_path[i];
458 const auto issuer = [&]() -> std::optional<X509_Certificate> {
459 if(!at_trust_anchor) {
460 return cert_path[i + 1];
461 } else if(subject.is_self_signed()) {
462 return cert_path[i];
463 } else {
464 return {}; // Non self-signed trust anchors have no checkable issuers.
465 }
466 }();
467
468 if(restrictions.require_self_signed_trust_anchors() && !issuer.has_value()) {
470 }
471
472 // This should never happen; it indicates a bug in path building
473 if(issuer.has_value() && subject.issuer_dn() != issuer->subject_dn()) {
475 }
476
477 // Check the serial number
478 if(subject.serial().is_negative()) {
480 }
481
482 // Check the subject's DN components' length
483
484 for(const auto& rdn : subject.subject_dn().rdns()) {
485 for(const auto& ava : rdn) {
486 const size_t dn_ub = X509_DN::lookup_ub(ava.first);
487 if(dn_ub > 0 && ava.second.size() > dn_ub) {
489 }
490 }
491 }
492
493 // If so configured, allow trust anchors outside the validity period with
494 // a warning rather than a hard error
495 const bool enforce_validity_period = !at_trust_anchor || !restrictions.ignore_trusted_root_time_range();
496 // Check all certs for valid time range
497 if(validation_time < subject.not_before()) {
498 if(enforce_validity_period) {
500 } else {
501 status.insert(Certificate_Status_Code::TRUSTED_CERT_NOT_YET_VALID); // only warn
502 }
503 }
504
505 if(validation_time > subject.not_after()) {
506 if(enforce_validity_period) {
508 } else {
509 status.insert(Certificate_Status_Code::TRUSTED_CERT_HAS_EXPIRED); // only warn
510 }
511 }
512
513 // Check issuer constraints
514 if(issuer.has_value() && !issuer->is_CA_cert() && !is_end_entity_trust_anchor) {
516 }
517
518 // Check cert extensions
519
520 if(subject.x509_version() == 1) {
521 if(subject.v2_issuer_key_id().empty() == false || subject.v2_subject_key_id().empty() == false) {
523 }
524 }
525
526 const Extensions& extensions = subject.v3_extensions();
527 if(subject.x509_version() < 3 && !extensions.get_extension_oids().empty()) {
529 }
530
531 extensions.validate(subject, issuer, cert_path, cert_status, i);
532 }
533
534 // path len check
535 size_t max_path_length = cert_path.size();
536 for(size_t i = cert_path.size() - 1; i > 0; --i) {
537 std::set<Certificate_Status_Code>& status = cert_status.at(i);
538 const X509_Certificate& subject = cert_path[i];
539
540 /*
541 * If the certificate was not self-issued, verify that max_path_length is
542 * greater than zero and decrement max_path_length by 1.
543 */
544 if(subject.subject_dn() != subject.issuer_dn()) {
545 if(max_path_length > 0) {
546 max_path_length -= 1;
547 } else {
549 }
550 }
551
552 /*
553 * If pathLenConstraint is present in the certificate and is less than max_path_length,
554 * set max_path_length to the value of pathLenConstraint.
555 */
556 if(auto path_len_constraint = subject.path_length_constraint()) {
557 max_path_length = std::min(max_path_length, *path_len_constraint);
558 }
559 }
560
561 return cert_status;
562}
const OID & oid() const
Definition asn1_obj.h:688
bool registered_oid() const
Definition asn1_oid.cpp:153
const std::set< std::string > & trusted_hashes() const
Definition x509path.h:132
bool ignore_trusted_root_time_range() const
Definition x509path.h:163
bool require_self_signed_trust_anchors() const
Definition x509path.h:172
bool is_self_signed() const
Definition x509cert.cpp:384
static size_t lookup_ub(const OID &oid)
const AlgorithmIdentifier & signature_algorithm() const
Definition x509_obj.cpp:73
std::pair< Certificate_Status_Code, std::string > verify_signature(const Public_Key &key) const
Definition x509_obj.cpp:130
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition x509path.h:29
ASN1_Time X509_Time
Definition asn1_obj.h:27

References BOTAN_ASSERT_NOMSG, 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::EXT_IN_V1_V2_CERT, Botan::Extensions::get_extension_oids(), Botan::Path_Validation_Restrictions::ignore_trusted_root_time_range(), Botan::INVALID_USAGE, Botan::X509_Serial_Number::is_negative(), Botan::X509_Certificate::is_self_signed(), Botan::X509_Certificate::issuer_dn(), Botan::Key_Constraints::KeyCertSign, Botan::X509_DN::lookup_ub(), Botan::Path_Validation_Restrictions::minimum_key_strength(), Botan::X509_Certificate::not_after(), Botan::X509_Certificate::not_before(), Botan::OCSP_RESPONDER, Botan::OCSP_RESPONSE_MISSING_KEYUSAGE, Botan::AlgorithmIdentifier::oid(), Botan::X509_Certificate::path_length_constraint(), Botan::X509_DN::rdns(), Botan::OID::registered_oid(), Botan::Path_Validation_Restrictions::require_self_signed_trust_anchors(), Botan::X509_Certificate::serial(), Botan::SIGNATURE_ALGO_UNKNOWN, Botan::X509_Object::signature_algorithm(), Botan::SIGNATURE_METHOD_TOO_WEAK, Botan::X509_Certificate::subject_dn(), Botan::X509_Certificate::subject_public_key(), Botan::TRUSTED_CERT_HAS_EXPIRED, Botan::TRUSTED_CERT_NOT_YET_VALID, Botan::Path_Validation_Restrictions::trusted_hashes(), Botan::UNTRUSTED_HASH, Botan::V2_IDENTIFIERS_IN_V1_CERT, Botan::X509_Certificate::v2_issuer_key_id(), Botan::X509_Certificate::v2_subject_key_id(), Botan::X509_Certificate::v3_extensions(), Botan::Extensions::validate(), Botan::VERIFIED, Botan::X509_Object::verify_signature(), and Botan::X509_Certificate::x509_version().

Referenced by Botan::x509_path_validate().

◆ check_crl() [1/2]

CertificatePathStatusCodes Botan::PKIX::check_crl ( const std::vector< 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_pathpath already validated by check_chain
certstoresa list of certificate stores to query for the CRL
ref_timewhatever time you want to perform the validation against (normally current system clock)
Returns
revocation status

Definition at line 830 of file x509path.cpp.

832 {
833 if(cert_path.empty()) {
834 throw Invalid_Argument("PKIX::check_crl cert_path empty");
835 }
836
837 if(certstores.empty()) {
838 throw Invalid_Argument("PKIX::check_crl certstores empty");
839 }
840
841 std::vector<std::optional<X509_CRL>> crls(cert_path.size());
842
843 for(size_t i = 0; i != cert_path.size(); ++i) {
844 if(cert_path[i].skip_revocation_check()) {
845 continue;
846 }
847 for(auto* certstore : certstores) {
848 crls[i] = certstore->find_crl_for(cert_path[i]);
849 if(crls[i]) {
850 break;
851 }
852 }
853 }
854
855 return PKIX::check_crl(cert_path, crls, ref_time);
856}
CertificatePathStatusCodes check_crl(const std::vector< X509_Certificate > &cert_path, const std::vector< std::optional< X509_CRL > > &crls, std::chrono::system_clock::time_point ref_time)
Definition x509path.cpp:744

References check_crl().

◆ check_crl() [2/2]

CertificatePathStatusCodes Botan::PKIX::check_crl ( const std::vector< X509_Certificate > & cert_path,
const std::vector< std::optional< X509_CRL > > & crls,
std::chrono::system_clock::time_point ref_time )

Check CRLs for revocation information

Parameters
cert_pathpath already validated by check_chain
crlsthe 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_timewhatever time you want to perform the validation against (normally current system clock)
Returns
revocation status

Definition at line 744 of file x509path.cpp.

746 {
747 if(cert_path.empty()) {
748 throw Invalid_Argument("PKIX::check_crl cert_path empty");
749 }
750
751 CertificatePathStatusCodes cert_status(cert_path.size());
752 const X509_Time validation_time(ref_time);
753
754 for(size_t i = 0; i != cert_path.size() - 1; ++i) {
755 std::set<Certificate_Status_Code>& status = cert_status.at(i);
756
757 if(cert_path.at(i).skip_revocation_check()) {
758 continue;
759 }
760
761 if(i < crls.size() && crls[i].has_value()) {
762 const X509_Certificate& subject = cert_path.at(i);
763 const X509_Certificate& ca = cert_path.at(i + 1);
764
765 // RFC 5280 6.3.3 step (b)(2): if the CRL's IDP scope or
766 // distributionPoint name excludes this certificate, do not use it
767 // to determine revocation status. Treat as if no CRL was supplied
768 // so the caller's policy (strict revocation or soft fail) decides
769 // the outcome.
770 const auto applic = crl_applicability_for(*crls[i], subject);
771 if(!applic.usable) {
772 continue;
773 }
774
775 if(!ca.allowed_usage(Key_Constraints::CrlSign)) {
777 }
778
779 if(validation_time < crls[i]->this_update()) {
781 }
782
783 if(crls[i]->next_update().time_is_set() && validation_time > crls[i]->next_update()) {
785 }
786
787 auto ca_key = ca.subject_public_key();
788 if(crls[i]->check_signature(*ca_key) == false) {
790 } else {
791 /*
792 RFC 5280 5.2 "If a CRL contains a critical extension that the
793 application cannot process, then the application MUST NOT use that
794 CRL to determine the status of certificates."
795
796 RFC 5280 5.3 "If a CRL contains a critical CRL entry extension that
797 the application cannot process, then the application MUST NOT use
798 that CRL to determine the status of any certificates."
799 */
800 const bool crl_is_not_usable = crls[i]->has_unknown_critical_extension();
801
802 if(crl_is_not_usable) {
804 } else if(crls[i]->is_revoked(subject)) {
805 // A reason-limited CRL that lists the cert still proves the
806 // cert is revoked (the cert was revoked for whichever reason
807 // the CRL covers). Surface CERT_IS_REVOKED regardless of
808 // full-coverage status.
810 } else if(applic.full_coverage) {
811 // Cert not listed AND the CRL covers every reason: positive
812 // non-revocation evidence.
814 }
815 // else: cert not listed but CRL only covers some reasons. No
816 // positive evidence is recorded; the caller's policy (strict
817 // revocation -> NO_REVOCATION_DATA, soft fail -> validates)
818 // decides what happens next.
819 }
820 }
821 }
822
823 while(!cert_status.empty() && cert_status.back().empty()) {
824 cert_status.pop_back();
825 }
826
827 return cert_status;
828}

References Botan::X509_Certificate::allowed_usage(), Botan::CA_CERT_NOT_FOR_CRL_ISSUER, Botan::CERT_IS_REVOKED, Botan::CRL_BAD_SIGNATURE, Botan::CRL_HAS_EXPIRED, Botan::CRL_HAS_UNKNOWN_CRITICAL_EXTENSION, Botan::CRL_NOT_YET_VALID, Botan::Key_Constraints::CrlSign, Botan::X509_Certificate::subject_public_key(), and Botan::VALID_CRL_CHECKED.

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

◆ check_ocsp()

CertificatePathStatusCodes Botan::PKIX::check_ocsp ( const std::vector< X509_Certificate > & cert_path,
const std::vector< std::optional< OCSP::Response > > & ocsp_responses,
const std::vector< Certificate_Store * > & certstores,
std::chrono::system_clock::time_point ref_time,
const Path_Validation_Restrictions & restrictions )

Check OCSP responses for revocation information

Parameters
cert_pathpath already validated by check_chain
ocsp_responsesthe OCSP responses to consider
certstorestrusted roots
ref_timewhatever time you want to perform the validation against (normally current system clock)
restrictionsthe relevant path validation restrictions object
Returns
revocation status

Definition at line 711 of file x509path.cpp.

715 {
716 if(cert_path.empty()) {
717 throw Invalid_Argument("PKIX::check_ocsp cert_path empty");
718 }
719
720 CertificatePathStatusCodes cert_status(cert_path.size() - 1);
721
722 for(size_t i = 0; i != cert_path.size() - 1; ++i) {
723 const X509_Certificate& subject = cert_path.at(i);
724 const X509_Certificate& ca = cert_path.at(i + 1);
725
726 if(subject.skip_revocation_check()) {
727 continue;
728 }
729
730 if(i < ocsp_responses.size() && ocsp_responses.at(i).has_value() &&
731 ocsp_responses.at(i)->status() == OCSP::Response_Status_Code::Successful) {
732 try {
733 cert_status.at(i) = evaluate_ocsp_response(
734 ocsp_responses.at(i).value(), subject, ca, cert_path, certstores, ref_time, restrictions);
735 } catch(Exception&) {
736 cert_status.at(i).insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID);
737 }
738 }
739 }
740
741 return cert_status;
742}
bool skip_revocation_check() const
Definition x509cert.cpp:452

References Botan::OCSP_RESPONSE_INVALID, Botan::X509_Certificate::skip_revocation_check(), and Botan::OCSP::Successful.

Referenced by Botan::x509_path_validate().

◆ merge_revocation_status()

void Botan::PKIX::merge_revocation_status ( CertificatePathStatusCodes & chain_status,
const CertificatePathStatusCodes & crl_status,
const CertificatePathStatusCodes & ocsp_status,
const Path_Validation_Restrictions & restrictions )

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

Parameters
chain_statusthe certificate status
crl_statusresults from check_crl
ocsp_statusresults from check_ocsp
restrictionsthe relevant path validation restrictions object

Definition at line 1102 of file x509path.cpp.

1105 {
1106 if(chain_status.empty()) {
1107 throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty");
1108 }
1109
1110 for(size_t i = 0; i != chain_status.size() - 1; ++i) {
1111 bool had_crl = false;
1112 bool had_ocsp = false;
1113
1114 // RFC 5280 6.3.3 treats revocation status as determined once cert_status
1115 // is not UNREVOKED, so CERT_IS_REVOKED (whether from CRL or OCSP) is
1116 // revocation evidence on a par with VALID_CRL_CHECKED / OCSP_RESPONSE_GOOD;
1117 // omitting it would surface a spurious NO_REVOCATION_DATA alongside the
1118 // revocation, e.g. when a reason-limited CRL lists the cert.
1119 if(i < crl_status.size() && !crl_status[i].empty()) {
1120 for(auto&& code : crl_status[i]) {
1122 had_crl = true;
1123 }
1124 chain_status[i].insert(code);
1125 }
1126 }
1127
1128 if(i < ocsp_status.size() && !ocsp_status[i].empty()) {
1129 for(auto&& code : ocsp_status[i]) {
1130 const bool was_definitive =
1132
1133 const bool was_softfail = code == Certificate_Status_Code::OCSP_NO_REVOCATION_URL ||
1136
1137 const bool accepted_softfail = was_softfail && restrictions.accept_ocsp_softfail();
1138
1139 if(was_definitive || accepted_softfail) {
1140 had_ocsp = true;
1141 }
1142
1143 chain_status[i].insert(code);
1144 }
1145 }
1146
1147 if(had_crl == false && had_ocsp == false) {
1148 if((restrictions.require_revocation_information() && i == 0) ||
1149 (restrictions.ocsp_all_intermediates() && i > 0)) {
1150 chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA);
1151 }
1152 }
1153 }
1154}
bool require_revocation_information() const
Definition x509path.h:121

References Botan::Path_Validation_Restrictions::accept_ocsp_softfail(), Botan::CERT_IS_REVOKED, Botan::NO_REVOCATION_DATA, Botan::Path_Validation_Restrictions::ocsp_all_intermediates(), Botan::OCSP_NO_HTTP, Botan::OCSP_NO_REVOCATION_URL, Botan::OCSP_RESPONSE_GOOD, Botan::OCSP_SERVER_NOT_AVAILABLE, Botan::Path_Validation_Restrictions::require_revocation_information(), and Botan::VALID_CRL_CHECKED.

Referenced by Botan::x509_path_validate().

◆ overall_status()

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

Find overall status (OK, error) of a validation

Parameters
cert_statusresult of merge_revocation_status or check_chain

Definition at line 1156 of file x509path.cpp.

1156 {
1157 if(cert_status.empty()) {
1158 throw Invalid_Argument("PKIX::overall_status empty cert status");
1159 }
1160
1162
1163 // take the "worst" error as overall
1164 for(const std::set<Certificate_Status_Code>& s : cert_status) {
1165 if(!s.empty()) {
1166 auto worst = *s.rbegin();
1167 // Leave informative OCSP/CRL confirmations on cert-level status only
1169 overall_status = worst;
1170 }
1171 }
1172 }
1173 return overall_status;
1174}
Certificate_Status_Code overall_status(const CertificatePathStatusCodes &cert_status)
Certificate_Status_Code
Definition pkix_enums.h:21

References Botan::FIRST_ERROR_STATUS, Botan::OK, and overall_status().

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