Botan 2.1.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 BOTAN_DLL | 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 BOTAN_DLL | 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 BOTAN_DLL | 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 BOTAN_DLL | 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 BOTAN_DLL | 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)
void BOTAN_DLL | 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 BOTAN_DLL | 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_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 414 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.

Referenced by Botan::x509_path_validate().

418 {
419 if(end_entity->is_self_signed())
420 {
421 return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
422 }
423
424 /*
425 * This is an inelegant but functional way of preventing path loops
426 * (where C1 -> C2 -> C3 -> C1). We store a set of all the certificate
427 * fingerprints in the path. If there is a duplicate, we error out.
428 * TODO: save fingerprints in result struct? Maybe useful for blacklists, etc.
429 */
430 std::set<std::string> certs_seen;
431
432 cert_path.push_back(end_entity);
433 certs_seen.insert(end_entity->fingerprint("SHA-256"));
434
435 Certificate_Store_In_Memory ee_extras;
436 for(size_t i = 0; i != end_entity_extra.size(); ++i)
437 ee_extras.add_certificate(end_entity_extra[i]);
438
439 // iterate until we reach a root or cannot find the issuer
440 for(;;)
441 {
442 const X509_Certificate& last = *cert_path.back();
443 const X509_DN issuer_dn = last.issuer_dn();
444 const std::vector<uint8_t> auth_key_id = last.authority_key_id();
445
446 std::shared_ptr<const X509_Certificate> issuer;
447 bool trusted_issuer = false;
448
449 for(Certificate_Store* store : trusted_certstores)
450 {
451 issuer = store->find_cert(issuer_dn, auth_key_id);
452 if(issuer)
453 {
454 trusted_issuer = true;
455 break;
456 }
457 }
458
459 if(!issuer)
460 {
461 // fall back to searching supplemental certs
462 issuer = ee_extras.find_cert(issuer_dn, auth_key_id);
463 }
464
465 if(!issuer)
466 return Certificate_Status_Code::CERT_ISSUER_NOT_FOUND;
467
468 const std::string fprint = issuer->fingerprint("SHA-256");
469
470 if(certs_seen.count(fprint) > 0) // already seen?
471 return Certificate_Status_Code::CERT_CHAIN_LOOP;
472
473 certs_seen.insert(fprint);
474 cert_path.push_back(issuer);
475
476 if(issuer->is_self_signed())
477 {
478 if(trusted_issuer)
479 {
480 return Certificate_Status_Code::OK;
481 }
482 else
483 {
484 return Certificate_Status_Code::CANNOT_ESTABLISH_TRUST;
485 }
486 }
487 }
488 }

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 29 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::CHAIN_LACKS_TRUST_ROOT, Botan::CHAIN_NAME_MISMATCH, Botan::Extensions::extensions(), Botan::INVALID_USAGE, Botan::SIGNATURE_ERROR, Botan::SIGNATURE_METHOD_TOO_WEAK, Botan::UNTRUSTED_HASH, and Botan::UTC_OR_GENERALIZED_TIME.

Referenced by Botan::x509_path_validate().

35 {
36 if(cert_path.empty())
37 throw Invalid_Argument("PKIX::check_chain cert_path empty");
38
39 const bool self_signed_ee_cert = (cert_path.size() == 1);
40
41 X509_Time validation_time(ref_time);
42
43 CertificatePathStatusCodes cert_status(cert_path.size());
44
45 if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname))
46 cert_status[0].insert(Certificate_Status_Code::CERT_NAME_NOMATCH);
47
48 if(!cert_path[0]->allowed_usage(usage))
49 cert_status[0].insert(Certificate_Status_Code::INVALID_USAGE);
50
51 for(size_t i = 0; i != cert_path.size(); ++i)
52 {
53 std::set<Certificate_Status_Code>& status = cert_status.at(i);
54
55 const bool at_self_signed_root = (i == cert_path.size() - 1);
56
57 const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
58
59 const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
60
61 if(at_self_signed_root && (issuer->is_self_signed() == false))
62 {
63 status.insert(Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT);
64 }
65
66 if(subject->issuer_dn() != issuer->subject_dn())
67 {
68 status.insert(Certificate_Status_Code::CHAIN_NAME_MISMATCH);
69 }
70
71 // Check all certs for valid time range
72 if(validation_time < X509_Time(subject->start_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
73 status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID);
74
75 if(validation_time > X509_Time(subject->end_time(), ASN1_Tag::UTC_OR_GENERALIZED_TIME))
76 status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED);
77
78 // Check issuer constraints
79
80 if(!issuer->is_CA_cert() && !self_signed_ee_cert)
81 status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER);
82
83 if(issuer->path_limit() < i)
84 status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG);
85
86 std::unique_ptr<Public_Key> issuer_key(issuer->subject_public_key());
87
88 if(!issuer_key)
89 {
90 status.insert(Certificate_Status_Code::CERT_PUBKEY_INVALID);
91 }
92 else
93 {
94 if(subject->check_signature(*issuer_key) == false)
95 {
96 status.insert(Certificate_Status_Code::SIGNATURE_ERROR);
97 }
98
99 if(issuer_key->estimated_strength() < min_signature_algo_strength)
100 status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK);
101 }
102
103 // Ignore untrusted hashes on self-signed roots
104 if(trusted_hashes.size() > 0 && !at_self_signed_root)
105 {
106 if(trusted_hashes.count(subject->hash_used_for_signature()) == 0)
107 status.insert(Certificate_Status_Code::UNTRUSTED_HASH);
108 }
109
110 // Check cert extensions
111 Extensions extensions = subject->v3_extensions();
112 for(auto& extension : extensions.extensions())
113 {
114 extension.first->validate(*subject, *issuer, cert_path, cert_status, i);
115 }
116 }
117
118 return cert_status;
119 }
Botan::UTC_OR_GENERALIZED_TIME
Definition: asn1_obj.h:52
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< std::shared_ptr< const X509_CRL >> & | crls,
|  | std::chrono::system_clock::time_point | ref_time
| ) |  |

Check CRLs for revocation infomration

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 171 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, and Botan::VALID_CRL_CHECKED.

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

174 {
175 if(cert_path.empty())
176 throw Invalid_Argument("PKIX::check_crl cert_path empty");
177
178 CertificatePathStatusCodes cert_status(cert_path.size());
179 const X509_Time validation_time(ref_time);
180
181 for(size_t i = 0; i != cert_path.size() - 1; ++i)
182 {
183 std::set<Certificate_Status_Code>& status = cert_status.at(i);
184
185 if(i < crls.size() && crls.at(i))
186 {
187 std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
188 std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
189
190 if(!ca->allowed_usage(CRL_SIGN))
191 status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER);
192
193 if(validation_time < X509_Time(crls[i]->this_update()))
194 status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID);
195
196 if(validation_time > X509_Time(crls[i]->next_update()))
197 status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED);
198
199 if(crls[i]->check_signature(ca->subject_public_key()) == false)
200 status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE);
201
202 status.insert(Certificate_Status_Code::VALID_CRL_CHECKED);
203
204 if(crls[i]->is_revoked(*subject))
205 status.insert(Certificate_Status_Code::CERT_IS_REVOKED);
206 }
207 }
208
209 while(cert_status.size() > 0 && cert_status.back().empty())
210 cert_status.pop_back();
211
212 return cert_status;
213 }
CRL_SIGN
Definition: ffi.h:934
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 infomration

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 216 of file x509path.cpp.

References BOTAN_ASSERT_NONNULL, and check_crl().

219 {
220 if(cert_path.empty())
221 throw Invalid_Argument("PKIX::check_crl cert_path empty");
222
223 if(certstores.empty())
224 throw Invalid_Argument("PKIX::check_crl certstores empty");
225
226 std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
227
228 for(size_t i = 0; i != cert_path.size(); ++i)
229 {
230 BOTAN_ASSERT_NONNULL(cert_path[i]);
231 for(size_t c = 0; c != certstores.size(); ++c)
232 {
233 crls[i] = certstores[c]->find_crl_for(*cert_path[i]);
234 if(crls[i])
235 break;
236 }
237 }
238
239 return PKIX::check_crl(cert_path, crls, ref_time);
240 }
BOTAN_ASSERT_NONNULL
#define BOTAN_ASSERT_NONNULL(ptr)
Definition: assert.h:79
Botan::PKIX::check_crl
CertificatePathStatusCodes BOTAN_DLL 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:171

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
| ) |  |

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)

Returns
  revocation status

Definition at line 122 of file x509path.cpp.

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

Referenced by Botan::x509_path_validate().

126 {
127 if(cert_path.empty())
128 throw Invalid_Argument("PKIX::check_ocsp cert_path empty");
129
130 CertificatePathStatusCodes cert_status(cert_path.size() - 1);
131
132 for(size_t i = 0; i != cert_path.size() - 1; ++i)
133 {
134 std::set<Certificate_Status_Code>& status = cert_status.at(i);
135
136 std::shared_ptr<const X509_Certificate> subject = cert_path.at(i);
137 std::shared_ptr<const X509_Certificate> ca = cert_path.at(i+1);
138
139 if(i < ocsp_responses.size() && (ocsp_responses.at(i) != nullptr))
140 {
141 try
142 {
143 Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, cert_path);
144
145 if(ocsp_signature_status == Certificate_Status_Code::OCSP_SIGNATURE_OK)
146 {
147 // Signature ok, so check the claimed status
148 Certificate_Status_Code ocsp_status = ocsp_responses.at(i)->status_for(*ca, *subject, ref_time);
149 status.insert(ocsp_status);
150 }
151 else
152 {
153 // Some signature problem
154 status.insert(ocsp_signature_status);
155 }
156 }
157 catch(Exception& e)
158 {
159 status.insert(Certificate_Status_Code::OCSP_RESPONSE_INVALID);
160 }
161 }
162 }
163
164 while(cert_status.size() > 0 && cert_status.back().empty())
165 cert_status.pop_back();
166
167 return cert_status;
168 }
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:18

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 490 of file x509path.cpp.

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

Referenced by Botan::x509_path_validate().

495 {
496 if(chain_status.empty())
497 throw Invalid_Argument("PKIX::merge_revocation_status chain_status was empty");
498
499 for(size_t i = 0; i != chain_status.size() - 1; ++i)
500 {
501 bool had_crl = false, had_ocsp = false;
502
503 if(i < crl.size() && crl[i].size() > 0)
504 {
505 for(auto&& code : crl[i])
506 {
507 if(code == Certificate_Status_Code::VALID_CRL_CHECKED)
508 {
509 had_crl = true;
510 }
511 chain_status[i].insert(code);
512 }
513 }
514
515 if(i < ocsp.size() && ocsp[i].size() > 0)
516 {
517 for(auto&& code : ocsp[i])
518 {
519 if(code == Certificate_Status_Code::OCSP_RESPONSE_GOOD)
520 {
521 had_ocsp = true;
522 }
523
524 chain_status[i].insert(code);
525 }
526 }
527
528 if(had_crl == false && had_ocsp == false)
529 {
530 if((require_rev_on_end_entity && i == 0) ||
531 (require_rev_on_intermediates && i > 0))
532 {
533 chain_status[i].insert(Certificate_Status_Code::NO_REVOCATION_DATA);
534 }
535 }
536 }
537 }

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 539 of file x509path.cpp.

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

540 {
541 if(cert_status.empty())
542 throw Invalid_Argument("PKIX::overall_status empty cert status");
543
544 Certificate_Status_Code overall_status = Certificate_Status_Code::OK;
545
546 // take the "worst" error as overall
547 for(const std::set<Certificate_Status_Code>& s : cert_status)
548 {
549 if(!s.empty())
550 {
551 auto worst = *s.rbegin();
552 // Leave informative OCSP/CRL confirmations on cert-level status only
553 if(worst >= Certificate_Status_Code::FIRST_ERROR_STATUS && worst > overall_status)
554 {
555 overall_status = worst;
556 }
557 }
558 }
559 return overall_status;
560 }
Botan::PKIX::overall_status
Certificate_Status_Code BOTAN_DLL overall_status(const CertificatePathStatusCodes &cert_status)
Definition: x509path.cpp:539
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:18