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