Botan 3.4.0
Crypto and TLS for C&
x509path.h
Go to the documentation of this file.
1/*
2* X.509 Cert Path Validation
3* (C) 2010-2011 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#ifndef BOTAN_X509_CERT_PATH_VALIDATION_H_
9#define BOTAN_X509_CERT_PATH_VALIDATION_H_
10
11#include <botan/certstor.h>
12#include <botan/ocsp.h>
13#include <botan/pkix_enums.h>
14#include <botan/x509cert.h>
15#include <chrono>
16#include <functional>
17#include <set>
18
19#if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL)
20 #define BOTAN_HAS_ONLINE_REVOCATION_CHECKS
21#endif
22
23namespace Botan {
24
25/**
26* This type represents the validation status of an entire certificate path.
27* There is one set of status codes for each certificate in the path.
28*/
29typedef std::vector<std::set<Certificate_Status_Code>> CertificatePathStatusCodes;
30
31/**
32* Specifies restrictions on the PKIX path validation
33*/
35 public:
36 /**
37 * @param require_rev if true, revocation information is required
38
39 * @param minimum_key_strength is the minimum strength (in terms of
40 * operations, eg 80 means 2^80) of a signature. Signatures weaker than
41 * this are rejected. If more than 80, SHA-1 signatures are also
42 * rejected. If possible use at least setting 110.
43 *
44 * 80 bit strength requires 1024 bit RSA
45 * 110 bit strength requires 2k bit RSA
46 * 128 bit strength requires ~3k bit RSA or P-256
47 * @param ocsp_all_intermediates Make OCSP requests for all CAs as
48 * well as end entity (if OCSP enabled in path validation request)
49 * @param max_ocsp_age maximum age of OCSP responses w/o next_update.
50 * If zero, there is no maximum age
51 * @param trusted_ocsp_responders certificate store containing certificates
52 * of trusted OCSP responders (additionally to the CA's responders)
53 * @param ignore_trusted_root_time_range if true, validity checks on the
54 * time range of the trusted root certificate only produce warnings
55 */
57 bool require_rev = false,
58 size_t minimum_key_strength = 110,
59 bool ocsp_all_intermediates = false,
60 std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero(),
61 std::unique_ptr<Certificate_Store> trusted_ocsp_responders = std::make_unique<Certificate_Store_In_Memory>(),
62 bool ignore_trusted_root_time_range = false);
63
64 /**
65 * @param require_rev if true, revocation information is required
66 * @param minimum_key_strength is the minimum strength (in terms of
67 * operations, eg 80 means 2^80) of a signature. Signatures
68 * weaker than this are rejected.
69 * @param ocsp_all_intermediates Make OCSP requests for all CAs as
70 * well as end entity (if OCSP enabled in path validation request)
71 * @param trusted_hashes a set of trusted hashes. Any signatures
72 * created using a hash other than one of these will be
73 * rejected.
74 * @param max_ocsp_age maximum age of OCSP responses w/o next_update.
75 * If zero, there is no maximum age
76 * @param trusted_ocsp_responders certificate store containing certificates
77 * of trusted OCSP responders (additionally to the CA's responders)
78 * @param ignore_trusted_root_time_range if true, validity checks on the
79 * time range of the trusted root certificate only produce warnings
80 */
82 bool require_rev,
83 size_t minimum_key_strength,
84 bool ocsp_all_intermediates,
85 const std::set<std::string>& trusted_hashes,
86 std::chrono::seconds max_ocsp_age = std::chrono::seconds::zero(),
87 std::unique_ptr<Certificate_Store> trusted_ocsp_responders = std::make_unique<Certificate_Store_In_Memory>(),
88 bool ignore_trusted_root_time_range = false) :
89 m_require_revocation_information(require_rev),
90 m_ocsp_all_intermediates(ocsp_all_intermediates),
91 m_trusted_hashes(trusted_hashes),
92 m_minimum_key_strength(minimum_key_strength),
93 m_max_ocsp_age(max_ocsp_age),
94 m_trusted_ocsp_responders(std::move(trusted_ocsp_responders)),
95 m_ignore_trusted_root_time_range(ignore_trusted_root_time_range) {}
96
97 /**
98 * @return whether revocation information is required
99 */
100 bool require_revocation_information() const { return m_require_revocation_information; }
101
102 /**
103 * @return whether all intermediate CAs should also be OCSPed. If false
104 * then only end entity OCSP is required/requested.
105 */
106 bool ocsp_all_intermediates() const { return m_ocsp_all_intermediates; }
107
108 /**
109 * @return trusted signature hash functions
110 */
111 const std::set<std::string>& trusted_hashes() const { return m_trusted_hashes; }
112
113 /**
114 * @return minimum required key strength
115 */
116 size_t minimum_key_strength() const { return m_minimum_key_strength; }
117
118 /**
119 * @return maximum age of OCSP responses w/o next_update.
120 * If zero, there is no maximum age
121 */
122 std::chrono::seconds max_ocsp_age() const { return m_max_ocsp_age; }
123
124 /**
125 * Certificates in this store are trusted to sign OCSP responses
126 * additionally to the CA's responder certificates.
127 * @return certificate store containing trusted OCSP responder certs
128 */
129 const Certificate_Store* trusted_ocsp_responders() const { return m_trusted_ocsp_responders.get(); }
130
131 /**
132 * RFC 5280 does not disallow trusted anchors signing certificates with wider validity
133 * ranges than theirs. When checking a certificate chain at a specific
134 * point in time, this can lead to situations where a root certificate is expired, but
135 * the lower-chain certificates are not.
136 *
137 * If this flag is set to true, such chains are considered valid (with warning
138 * TRUSTED_CERT_HAS_EXPIRED). Otherwise, the chain is rejected with the error
139 * code CERT_HAS_EXPIRED. The same holds for not yet valid certificates with the
140 * error code CERT_NOT_YET_VALID (or warning TRUSTED_CERT_NOT_YET_VALID).
141 */
142 bool ignore_trusted_root_time_range() const { return m_ignore_trusted_root_time_range; }
143
144 private:
145 bool m_require_revocation_information;
146 bool m_ocsp_all_intermediates;
147 std::set<std::string> m_trusted_hashes;
148 size_t m_minimum_key_strength;
149 std::chrono::seconds m_max_ocsp_age;
150 std::unique_ptr<Certificate_Store> m_trusted_ocsp_responders;
151 bool m_ignore_trusted_root_time_range;
152};
153
154/**
155* Represents the result of a PKIX path validation
156*/
158 public:
160
161 /**
162 * @return the trust root of the validation if successful
163 * throws an exception if the validation failed
164 */
165 const X509_Certificate& trust_root() const;
166
167 /**
168 * @return the full path from subject to trust root
169 * This path may be empty
170 */
171 const std::vector<X509_Certificate>& cert_path() const { return m_cert_path; }
172
173 /**
174 * @return true iff the validation was successful
175 */
176 bool successful_validation() const;
177
178 /**
179 * @return true iff no warnings occured during validation
180 */
181 bool no_warnings() const;
182
183 /**
184 * @return overall validation result code
185 */
186 Certificate_Status_Code result() const { return m_overall; }
187
188 /**
189 * @return a set of status codes for each certificate in the chain
190 */
191 const CertificatePathStatusCodes& all_statuses() const { return m_all_status; }
192
193 /**
194 * @return the subset of status codes that are warnings
195 */
196 CertificatePathStatusCodes warnings() const;
197
198 /**
199 * @return string representation of the validation result
200 */
201 std::string result_string() const;
202
203 /**
204 * @return string representation of the warnings
205 */
206 std::string warnings_string() const;
207
208 /**
209 * @param code validation status code
210 * @return corresponding validation status message
211 */
212 static const char* status_string(Certificate_Status_Code code);
213
214 /**
215 * Create a Path_Validation_Result
216 * @param status list of validation status codes
217 * @param cert_chain the certificate chain that was validated
218 */
219 Path_Validation_Result(CertificatePathStatusCodes status, std::vector<X509_Certificate>&& cert_chain);
220
221 /**
222 * Create a Path_Validation_Result
223 * @param status validation status code
224 */
225 explicit Path_Validation_Result(Certificate_Status_Code status) : m_overall(status) {}
226
227 private:
228 CertificatePathStatusCodes m_all_status;
230 std::vector<X509_Certificate> m_cert_path;
231 Certificate_Status_Code m_overall;
232};
233
234/**
235* PKIX Path Validation
236* @param end_certs certificate chain to validate (with end entity certificate in end_certs[0])
237* @param restrictions path validation restrictions
238* @param trusted_roots list of certificate stores that contain trusted certificates
239* @param hostname if not empty, compared against the DNS name in end_certs[0]
240* @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0]
241* @param validation_time what reference time to use for validation
242* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check
243* @param ocsp_resp additional OCSP responses to consider (eg from peer)
244* @return result of the path validation
245* note: when enabled, OCSP check is softfail by default: if the OCSP server is not
246* reachable, Path_Validation_Result::successful_validation() will return true.
247* Hardfail OCSP check can be achieve by also calling Path_Validation_Result::no_warnings().
248*/
249Path_Validation_Result BOTAN_PUBLIC_API(2, 0)
250 x509_path_validate(const std::vector<X509_Certificate>& end_certs,
251 const Path_Validation_Restrictions& restrictions,
252 const std::vector<Certificate_Store*>& trusted_roots,
253 std::string_view hostname = "",
255 std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
256 std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
257 const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
258
259/**
260* PKIX Path Validation
261* @param end_cert certificate to validate
262* @param restrictions path validation restrictions
263* @param trusted_roots list of stores that contain trusted certificates
264* @param hostname if not empty, compared against the DNS name in end_cert
265* @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert
266* @param validation_time what reference time to use for validation
267* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check
268* @param ocsp_resp additional OCSP responses to consider (eg from peer)
269* @return result of the path validation
270*/
271Path_Validation_Result BOTAN_PUBLIC_API(2, 0)
272 x509_path_validate(const X509_Certificate& end_cert,
273 const Path_Validation_Restrictions& restrictions,
274 const std::vector<Certificate_Store*>& trusted_roots,
275 std::string_view hostname = "",
277 std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
278 std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
279 const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
280
281/**
282* PKIX Path Validation
283* @param end_cert certificate to validate
284* @param restrictions path validation restrictions
285* @param store store that contains trusted certificates
286* @param hostname if not empty, compared against the DNS name in end_cert
287* @param usage if not set to UNSPECIFIED, compared against the key usage in end_cert
288* @param validation_time what reference time to use for validation
289* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check
290* @param ocsp_resp additional OCSP responses to consider (eg from peer)
291* @return result of the path validation
292*/
293Path_Validation_Result BOTAN_PUBLIC_API(2, 0)
294 x509_path_validate(const X509_Certificate& end_cert,
295 const Path_Validation_Restrictions& restrictions,
296 const Certificate_Store& store,
297 std::string_view hostname = "",
299 std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
300 std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
301 const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
302
303/**
304* PKIX Path Validation
305* @param end_certs certificate chain to validate
306* @param restrictions path validation restrictions
307* @param store store that contains trusted certificates
308* @param hostname if not empty, compared against the DNS name in end_certs[0]
309* @param usage if not set to UNSPECIFIED, compared against the key usage in end_certs[0]
310* @param validation_time what reference time to use for validation
311* @param ocsp_timeout timeout for OCSP operations, 0 disables OCSP check
312* @param ocsp_resp additional OCSP responses to consider (eg from peer)
313* @return result of the path validation
314*/
315Path_Validation_Result BOTAN_PUBLIC_API(2, 0)
316 x509_path_validate(const std::vector<X509_Certificate>& end_certs,
317 const Path_Validation_Restrictions& restrictions,
318 const Certificate_Store& store,
319 std::string_view hostname = "",
321 std::chrono::system_clock::time_point validation_time = std::chrono::system_clock::now(),
322 std::chrono::milliseconds ocsp_timeout = std::chrono::milliseconds(0),
323 const std::vector<std::optional<OCSP::Response>>& ocsp_resp = {});
324
325/**
326* namespace PKIX holds the building blocks that are called by x509_path_validate.
327* This allows custom validation logic to be written by applications and makes
328* for easier testing, but unless you're positive you know what you're doing you
329* probably want to just call x509_path_validate instead.
330*/
331namespace PKIX {
332
333Certificate_Status_Code build_all_certificate_paths(std::vector<std::vector<X509_Certificate>>& cert_paths,
334 const std::vector<Certificate_Store*>& trusted_certstores,
335 const std::optional<X509_Certificate>& end_entity,
336 const std::vector<X509_Certificate>& end_entity_extra);
337
338/**
339* Build certificate path
340* @param cert_path_out output parameter, cert_path will be appended to this vector
341* @param trusted_certstores list of certificate stores that contain trusted certificates
342* @param end_entity the cert to be validated
343* @param end_entity_extra optional list of additional untrusted certs for path building
344* @return result of the path building operation (OK or error)
345*/
347 build_certificate_path(std::vector<X509_Certificate>& cert_path_out,
348 const std::vector<Certificate_Store*>& trusted_certstores,
349 const X509_Certificate& end_entity,
350 const std::vector<X509_Certificate>& end_entity_extra);
351
352/**
353* Check the certificate chain, but not any revocation data
354*
355* @param cert_path path built by build_certificate_path with OK result.
356* The first element is the end entity certificate, the last element is
357* the trusted root certificate.
358* @param ref_time whatever time you want to perform the validation
359* against (normally current system clock)
360* @param hostname the hostname
361* @param usage end entity usage checks
362* @param restrictions the relevant path validation restrictions object
363* @return vector of results on per certificate in the path, each containing a set of
364* results. If all codes in the set are < Certificate_Status_Code::FIRST_ERROR_STATUS,
365* then the result for that certificate is successful. If all results are
366*/
367CertificatePathStatusCodes BOTAN_PUBLIC_API(3, 0) check_chain(const std::vector<X509_Certificate>& cert_path,
368 std::chrono::system_clock::time_point ref_time,
369 std::string_view hostname,
370 Usage_Type usage,
371 const Path_Validation_Restrictions& restrictions);
372
373/**
374* Check OCSP responses for revocation information
375* @param cert_path path already validated by check_chain
376* @param ocsp_responses the OCSP responses to consider
377* @param certstores trusted roots
378* @param ref_time whatever time you want to perform the validation against
379* (normally current system clock)
380* @param restrictions the relevant path validation restrictions object
381* @return revocation status
382*/
384 check_ocsp(const std::vector<X509_Certificate>& cert_path,
385 const std::vector<std::optional<OCSP::Response>>& ocsp_responses,
386 const std::vector<Certificate_Store*>& certstores,
387 std::chrono::system_clock::time_point ref_time,
388 const Path_Validation_Restrictions& restrictions);
389
390/**
391* Check CRLs for revocation information
392* @param cert_path path already validated by check_chain
393* @param crls the list of CRLs to check, it is assumed that crls[i] (if not null)
394* is the associated CRL for the subject in cert_path[i].
395* @param ref_time whatever time you want to perform the validation against
396* (normally current system clock)
397* @return revocation status
398*/
399CertificatePathStatusCodes BOTAN_PUBLIC_API(2, 0) check_crl(const std::vector<X509_Certificate>& cert_path,
400 const std::vector<std::optional<X509_CRL>>& crls,
401 std::chrono::system_clock::time_point ref_time);
402
403/**
404* Check CRLs for revocation information
405* @param cert_path path already validated by check_chain
406* @param certstores a list of certificate stores to query for the CRL
407* @param ref_time whatever time you want to perform the validation against
408* (normally current system clock)
409* @return revocation status
410*/
411CertificatePathStatusCodes BOTAN_PUBLIC_API(2, 0) check_crl(const std::vector<X509_Certificate>& cert_path,
412 const std::vector<Certificate_Store*>& certstores,
413 std::chrono::system_clock::time_point ref_time);
414
415#if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
416
417/**
418* Check OCSP using online (HTTP) access. Current version creates a thread and
419* network connection per OCSP request made.
420*
421* @param cert_path path already validated by check_chain
422* @param trusted_certstores a list of certstores with trusted certs
423* @param ref_time whatever time you want to perform the validation against
424* (normally current system clock)
425* @param timeout for timing out the responses, though actually this function
426* may block for up to timeout*cert_path.size()*C for some small C.
427* @param restrictions the relevant path validation restrictions object
428* @return revocation status
429*/
431 check_ocsp_online(const std::vector<X509_Certificate>& cert_path,
432 const std::vector<Certificate_Store*>& trusted_certstores,
433 std::chrono::system_clock::time_point ref_time,
434 std::chrono::milliseconds timeout,
435 const Path_Validation_Restrictions& restrictions);
436
437/**
438* Check CRL using online (HTTP) access. Current version creates a thread and
439* network connection per CRL access.
440
441* @param cert_path path already validated by check_chain
442* @param trusted_certstores a list of certstores with trusted certs
443* @param certstore_to_recv_crls optional (nullptr to disable), all CRLs
444* retreived will be saved to this cert store.
445* @param ref_time whatever time you want to perform the validation against
446* (normally current system clock)
447* @param timeout for timing out the responses, though actually this function
448* may block for up to timeout*cert_path.size()*C for some small C.
449* @return revocation status
450*/
452 check_crl_online(const std::vector<X509_Certificate>& cert_path,
453 const std::vector<Certificate_Store*>& trusted_certstores,
454 Certificate_Store_In_Memory* certstore_to_recv_crls,
455 std::chrono::system_clock::time_point ref_time,
456 std::chrono::milliseconds timeout);
457
458#endif
459
460/**
461* Find overall status (OK, error) of a validation
462* @param cert_status result of merge_revocation_status or check_chain
463*/
465
466/**
467* Merge the results from CRL and/or OCSP checks into chain_status
468* @param chain_status the certificate status
469* @param crl_status results from check_crl
470* @param ocsp_status results from check_ocsp
471* @param restrictions the relevant path validation restrictions object
472*/
474 const CertificatePathStatusCodes& crl_status,
475 const CertificatePathStatusCodes& ocsp_status,
476 const Path_Validation_Restrictions& restrictions);
477
478} // namespace PKIX
479
480} // namespace Botan
481
482#endif
bool require_revocation_information() const
Definition x509path.h:100
const std::set< std::string > & trusted_hashes() const
Definition x509path.h:111
std::chrono::seconds max_ocsp_age() const
Definition x509path.h:122
Path_Validation_Restrictions(bool require_rev, size_t minimum_key_strength, bool ocsp_all_intermediates, const std::set< std::string > &trusted_hashes, std::chrono::seconds max_ocsp_age=std::chrono::seconds::zero(), std::unique_ptr< Certificate_Store > trusted_ocsp_responders=std::make_unique< Certificate_Store_In_Memory >(), bool ignore_trusted_root_time_range=false)
Definition x509path.h:81
bool ignore_trusted_root_time_range() const
Definition x509path.h:142
const Certificate_Store * trusted_ocsp_responders() const
Definition x509path.h:129
Certificate_Status_Code result() const
Definition x509path.h:186
Certificate_Status_Code Code
Definition x509path.h:159
Path_Validation_Result(Certificate_Status_Code status)
Definition x509path.h:225
const std::vector< X509_Certificate > & cert_path() const
Definition x509path.h:171
const CertificatePathStatusCodes & all_statuses() const
Definition x509path.h:191
int(* final)(unsigned char *, CTX *)
#define BOTAN_PUBLIC_API(maj, min)
Definition compiler.h:31
void merge_revocation_status(CertificatePathStatusCodes &chain_status, const CertificatePathStatusCodes &crl_status, const CertificatePathStatusCodes &ocsp_status, const Path_Validation_Restrictions &restrictions)
Definition x509path.cpp:788
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)
Definition x509path.cpp:569
Certificate_Status_Code overall_status(const CertificatePathStatusCodes &cert_status)
Definition x509path.cpp:830
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)
Definition x509path.cpp:277
Certificate_Status_Code build_all_certificate_paths(std::vector< std::vector< X509_Certificate > > &cert_paths, const std::vector< Certificate_Store * > &trusted_certstores, const std::optional< X509_Certificate > &end_entity, const std::vector< X509_Certificate > &end_entity_extra)
Definition x509path.cpp:664
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)
Definition x509path.cpp:36
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:332
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition x509path.h:29
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, std::string_view hostname, Usage_Type usage, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds ocsp_timeout, const std::vector< std::optional< OCSP::Response > > &ocsp_resp)
Definition x509path.cpp:850
Usage_Type
Definition x509cert.h:22
Certificate_Status_Code
Definition pkix_enums.h:20