Botan 2.1.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

x509path.cpp
Go to the documentation of this file.
1 /*
2 * X.509 Certificate Path Validation
3 * (C) 2010,2011,2012,2014,2016 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8 #include <botan/x509path.h>
9 #include <botan/ocsp.h>
10 #include <botan/parsing.h>
11 #include <botan/pubkey.h>
12 #include <botan/oids.h>
13 #include <algorithm>
14 #include <chrono>
15 #include <vector>
16 #include <set>
17
18 #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
19 #include <future>
20 #include <botan/http_util.h>
21 #endif
22
23 namespace Botan {
24
25 /*
26 * PKIX path validation
27 */
28 CertificatePathStatusCodes
29 PKIX::check_chain(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
30 std::chrono::system_clock::time_point ref_time,
31 const std::string& hostname,
32 Usage_Type usage,
33 size_t min_signature_algo_strength,
34 const std::set<std::string>& trusted_hashes)
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 }
120
121 CertificatePathStatusCodes
122 PKIX::check_ocsp(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
123 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_responses,
124 const std::vector<Certificate_Store*>& trusted_certstores,
125 std::chrono::system_clock::time_point ref_time)
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 }
169
170 CertificatePathStatusCodes
171 PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
172 const std::vector<std::shared_ptr<const X509_CRL>>& crls,
173 std::chrono::system_clock::time_point ref_time)
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 }
214
215 CertificatePathStatusCodes
216 PKIX::check_crl(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
217 const std::vector<Certificate_Store*>& certstores,
218 std::chrono::system_clock::time_point ref_time)
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 }
241
242 #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
243
244 CertificatePathStatusCodes
245 PKIX::check_ocsp_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
246 const std::vector<Certificate_Store*>& trusted_certstores,
247 std::chrono::system_clock::time_point ref_time,
248 std::chrono::milliseconds timeout,
249 bool ocsp_check_intermediate_CAs)
250 {
251 if(cert_path.empty())
252 throw Invalid_Argument("PKIX::check_ocsp_online cert_path empty");
253
254 std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures;
255
256 size_t to_ocsp = 1;
257
258 if(ocsp_check_intermediate_CAs)
259 to_ocsp = cert_path.size() - 1;
260 if(cert_path.size() == 1)
261 to_ocsp = 0;
262
263 for(size_t i = 0; i < to_ocsp; ++i)
264 {
265 const std::shared_ptr<const X509_Certificate>& subject = cert_path.at(i);
266 const std::shared_ptr<const X509_Certificate>& issuer = cert_path.at(i+1);
267
268 if(subject->ocsp_responder() == "")
269 {
270 ocsp_response_futures.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const OCSP::Response> {
271 throw Exception("No OCSP responder URL set for this certificate");
272 }));
273 }
274 else
275 {
276 ocsp_response_futures.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const OCSP::Response> {
277 OCSP::Request req(*issuer, BigInt::decode(subject->serial_number()));
278
279 auto http = HTTP::POST_sync(subject->ocsp_responder(),
280 "application/ocsp-request",
281 req.BER_encode());
282
283 http.throw_unless_ok();
284 // Check the MIME type?
285
286 return std::make_shared<const OCSP::Response>(http.body());
287 }));
288 }
289 }
290
291 std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses(ocsp_response_futures.size());
292
293 for(size_t pass = 1; pass < 3; ++pass)
294 {
295 for(size_t i = 0; i < ocsp_response_futures.size(); ++i)
296 {
297 try
298 {
299 if(ocsp_responses[i] == nullptr && ocsp_response_futures[i].valid())
300 {
301 std::future_status status = ocsp_response_futures[i].wait_for(timeout);
302
303 if(status == std::future_status::ready ||
304 status == std::future_status::deferred)
305 {
306 ocsp_responses[i] = ocsp_response_futures[i].get();
307 }
308 }
309 }
310 catch(std::exception&)
311 {
312 // value is default initialized to null, no need to do anything
313 }
314 }
315 }
316
317 return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time);
318 }
319
320 CertificatePathStatusCodes
321 PKIX::check_crl_online(const std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
322 const std::vector<Certificate_Store*>& certstores,
323 Certificate_Store_In_Memory* crl_store,
324 std::chrono::system_clock::time_point ref_time,
325 std::chrono::milliseconds timeout)
326 {
327 if(cert_path.empty())
328 throw Invalid_Argument("PKIX::check_crl_online cert_path empty");
329 if(certstores.empty())
330 throw Invalid_Argument("PKIX::check_crl_online certstores empty");
331
332 std::vector<std::future<std::shared_ptr<const X509_CRL>>> future_crls;
333 std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
334
335 for(size_t i = 0; i != cert_path.size(); ++i)
336 {
337 for(size_t c = 0; c != certstores.size(); ++i)
338 {
339 crls[i] = certstores[i]->find_crl_for(*cert_path[i]);
340 if(crls[i])
341 break;
342 }
343
344 // TODO: check if CRL is expired and re-request?
345
346 // Only request if we don't already have a CRL
347 if(crls[i])
348 {
349 /*
350 We already have a CRL, so just insert this empty one to hold a place in the vector
351 so that indexes match up
352 */
353 future_crls.emplace_back(std::future<std::shared_ptr<const X509_CRL>>());
354 }
355 else if(cert_path[i]->crl_distribution_point() == "")
356 {
357 // Avoid creating a thread for this case
358 future_crls.emplace_back(std::async(std::launch::deferred, [&]() -> std::shared_ptr<const X509_CRL> {
359 throw Exception("No CRL distribution point for this certificate");
360 }));
361 }
362 else
363 {
364 future_crls.emplace_back(std::async(std::launch::async, [&]() -> std::shared_ptr<const X509_CRL> {
365 auto http = HTTP::GET_sync(cert_path[i]->crl_distribution_point());
366 http.throw_unless_ok();
367 // check the mime type?
368 return std::make_shared<const X509_CRL>(http.body());
369 }));
370 }
371 }
372
373 for(size_t i = 0; i != future_crls.size(); ++i)
374 {
375 if(future_crls[i].valid())
376 {
377 try
378 {
379 std::future_status status = future_crls[i].wait_for(timeout);
380
381 if(status == std::future_status::ready)
382 {
383 crls[i] = future_crls[i].get();
384 }
385 }
386 catch(std::exception& e)
387 {
388 // crls[i] left null
389 }
390 }
391 }
392
393 const CertificatePathStatusCodes crl_status = PKIX::check_crl(cert_path, crls, ref_time);
394
395 if(crl_store)
396 {
397 for(size_t i = 0; i != crl_status.size(); ++i)
398 {
399 if(crl_status[i].count(Certificate_Status_Code::VALID_CRL_CHECKED))
400 {
401 // better be non-null, we supposedly validated it
402 BOTAN_ASSERT_NONNULL(crls[i]);
403 crl_store->add_crl(crls[i]);
404 }
405 }
406 }
407
408 return crl_status;
409 }
410
411 #endif
412
413 Certificate_Status_Code
414 PKIX::build_certificate_path(std::vector<std::shared_ptr<const X509_Certificate>>& cert_path,
415 const std::vector<Certificate_Store*>& trusted_certstores,
416 const std::shared_ptr<const X509_Certificate>& end_entity,
417 const std::vector<std::shared_ptr<const X509_Certificate>>& end_entity_extra)
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 }
489
490 void PKIX::merge_revocation_status(CertificatePathStatusCodes& chain_status,
491 const CertificatePathStatusCodes& crl,
492 const CertificatePathStatusCodes& ocsp,
493 bool require_rev_on_end_entity,
494 bool require_rev_on_intermediates)
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 }
538
539 Certificate_Status_Code PKIX::overall_status(const CertificatePathStatusCodes& cert_status)
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 }
561
562 Path_Validation_Result x509_path_validate(
563 const std::vector<X509_Certificate>& end_certs,
564 const Path_Validation_Restrictions& restrictions,
565 const std::vector<Certificate_Store*>& trusted_roots,
566 const std::string& hostname,
567 Usage_Type usage,
568 std::chrono::system_clock::time_point ref_time,
569 std::chrono::milliseconds ocsp_timeout,
570 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
571 {
572 if(end_certs.empty())
573 throw Invalid_Argument("x509_path_validate called with no subjects");
574
575 std::shared_ptr<const X509_Certificate> end_entity(std::make_shared<const X509_Certificate>(end_certs[0]));
576 std::vector<std::shared_ptr<const X509_Certificate>> end_entity_extra;
577 for(size_t i = 1; i < end_certs.size(); ++i)
578 {
579 end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i]));
580 }
581
582 std::vector<std::shared_ptr<const X509_Certificate>> cert_path;
583 Certificate_Status_Code path_building_result =
584 PKIX::build_certificate_path(cert_path, trusted_roots, end_entity, end_entity_extra);
585
586 // If we cannot successfully build a chain to a trusted self-signed root, stop now
587 if(path_building_result != Certificate_Status_Code::OK)
588 {
589 return Path_Validation_Result(path_building_result);
590 }
591
592 CertificatePathStatusCodes status =
593 PKIX::check_chain(cert_path, ref_time,
594 hostname, usage,
595 restrictions.minimum_key_strength(),
596 restrictions.trusted_hashes());
597
598 CertificatePathStatusCodes crl_status =
599 PKIX::check_crl(cert_path, trusted_roots, ref_time);
600
601 CertificatePathStatusCodes ocsp_status;
602
603 if(ocsp_resp.size() > 0)
604 {
605 ocsp_status = PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time);
606 }
607
608 if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0))
609 {
610 #if defined(BOTAN_TARGET_OS_HAS_THREADS) && defined(BOTAN_HAS_HTTP_UTIL)
611 ocsp_status = PKIX::check_ocsp_online(cert_path, trusted_roots, ref_time,
612 ocsp_timeout, restrictions.ocsp_all_intermediates());
613 #else
614 ocsp_status.resize(1);
615 ocsp_status[0].insert(Certificate_Status_Code::OCSP_NO_HTTP);
616 #endif
617 }
618
619 PKIX::merge_revocation_status(status, crl_status, ocsp_status,
620 restrictions.require_revocation_information(),
621 restrictions.ocsp_all_intermediates());
622
623 return Path_Validation_Result(status, std::move(cert_path));
624 }
625
626 Path_Validation_Result x509_path_validate(
627 const X509_Certificate& end_cert,
628 const Path_Validation_Restrictions& restrictions,
629 const std::vector<Certificate_Store*>& trusted_roots,
630 const std::string& hostname,
631 Usage_Type usage,
632 std::chrono::system_clock::time_point when,
633 std::chrono::milliseconds ocsp_timeout,
634 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
635 {
636 std::vector<X509_Certificate> certs;
637 certs.push_back(end_cert);
638 return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
639 }
640
641 Path_Validation_Result x509_path_validate(
642 const std::vector<X509_Certificate>& end_certs,
643 const Path_Validation_Restrictions& restrictions,
644 const Certificate_Store& store,
645 const std::string& hostname,
646 Usage_Type usage,
647 std::chrono::system_clock::time_point when,
648 std::chrono::milliseconds ocsp_timeout,
649 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
650 {
651 std::vector<Certificate_Store*> trusted_roots;
652 trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
653
654 return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
655 }
656
657 Path_Validation_Result x509_path_validate(
658 const X509_Certificate& end_cert,
659 const Path_Validation_Restrictions& restrictions,
660 const Certificate_Store& store,
661 const std::string& hostname,
662 Usage_Type usage,
663 std::chrono::system_clock::time_point when,
664 std::chrono::milliseconds ocsp_timeout,
665 const std::vector<std::shared_ptr<const OCSP::Response>>& ocsp_resp)
666 {
667 std::vector<X509_Certificate> certs;
668 certs.push_back(end_cert);
669
670 std::vector<Certificate_Store*> trusted_roots;
671 trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
672
673 return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
674 }
675
676 Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev,
677 size_t key_strength,
678 bool ocsp_intermediates) :
679 m_require_revocation_information(require_rev),
680 m_ocsp_all_intermediates(ocsp_intermediates),
681 m_minimum_key_strength(key_strength)
682 {
683 if(key_strength <= 80)
684 m_trusted_hashes.insert("SHA-160");
685
686 m_trusted_hashes.insert("SHA-224");
687 m_trusted_hashes.insert("SHA-256");
688 m_trusted_hashes.insert("SHA-384");
689 m_trusted_hashes.insert("SHA-512");
690 }
691
692 Path_Validation_Result::Path_Validation_Result(CertificatePathStatusCodes status,
693 std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) :
694 m_all_status(status),
695 m_cert_path(cert_chain),
696 m_overall(PKIX::overall_status(m_all_status))
697 {
698 }
699
700 const X509_Certificate& Path_Validation_Result::trust_root() const
701 {
702 if(m_cert_path.empty())
703 throw Exception("Path_Validation_Result::trust_root no path set");
704 if(result() != Certificate_Status_Code::VERIFIED)
705 throw Exception("Path_Validation_Result::trust_root meaningless with invalid status");
706
707 return *m_cert_path[m_cert_path.size()-1];
708 }
709
710 std::set<std::string> Path_Validation_Result::trusted_hashes() const
711 {
712 std::set<std::string> hashes;
713 for(size_t i = 0; i != m_cert_path.size(); ++i)
714 hashes.insert(m_cert_path[i]->hash_used_for_signature());
715 return hashes;
716 }
717
718 bool Path_Validation_Result::successful_validation() const
719 {
720 return (result() == Certificate_Status_Code::VERIFIED ||
721 result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD ||
722 result() == Certificate_Status_Code::VALID_CRL_CHECKED);
723 }
724
725 std::string Path_Validation_Result::result_string() const
726 {
727 return status_string(result());
728 }
729
730 const char* Path_Validation_Result::status_string(Certificate_Status_Code code)
731 {
732 if(const char* s = to_string(code))
733 return s;
734
735 return "Unknown error";
736 }
737
738 }
Botan::PKIX::check_chain
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)
Definition: x509path.cpp:29
Botan::Certificate_Status_Code::CERT_NAME_NOMATCH
Botan::Invalid_Argument
Definition: exceptn.h:34
Botan::Path_Validation_Result::Path_Validation_Result
Path_Validation_Result(CertificatePathStatusCodes status, std::vector< std::shared_ptr< const X509_Certificate >> &&cert_chain)
Definition: x509path.cpp:692
Botan::Exception
Definition: exceptn.h:21
Botan::UTC_OR_GENERALIZED_TIME
Definition: asn1_obj.h:52
Botan::Path_Validation_Restrictions
Definition: x509path.h:34
Botan::PKIX::check_ocsp
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)
Definition: x509path.cpp:122
Botan::Certificate_Status_Code::OK
Botan::PKIX::overall_status
Certificate_Status_Code BOTAN_DLL overall_status(const CertificatePathStatusCodes &cert_status)
Definition: x509path.cpp:539
Botan::HTTP::Response::throw_unless_ok
void throw_unless_ok()
Definition: http_util.h:43
Botan::Certificate_Store_In_Memory::find_cert
std::shared_ptr< const X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
Definition: certstor.cpp:46
Botan::Extensions
Definition: x509_ext.h:86
Botan::Certificate_Status_Code::CANNOT_ESTABLISH_TRUST
Botan::Extensions::extensions
std::vector< std::pair< std::unique_ptr< Certificate_Extension >, bool > > extensions() const
Definition: x509_ext.cpp:139
Botan::Certificate_Status_Code::CERT_PUBKEY_INVALID
Botan::Certificate_Status_Code::SIGNATURE_ERROR
Botan::PKIX::merge_revocation_status
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)
Definition: x509path.cpp:490
Botan::Certificate_Status_Code::VALID_CRL_CHECKED
Botan::Certificate_Status_Code::CRL_BAD_SIGNATURE
Botan::Path_Validation_Restrictions::require_revocation_information
bool require_revocation_information() const
Definition: x509path.h:78
Botan::CRL_SIGN
Definition: key_constraint.h:29
Botan::X509_Certificate
Definition: x509cert.h:36
Botan::Certificate_Status_Code::CRL_NOT_YET_VALID
Botan::Certificate_Status_Code::OCSP_RESPONSE_GOOD
Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER
Botan::Certificate_Status_Code::CHAIN_LACKS_TRUST_ROOT
BOTAN_ASSERT_NONNULL
#define BOTAN_ASSERT_NONNULL(ptr)
Definition: assert.h:79
Botan::Certificate_Status_Code::CHAIN_NAME_MISMATCH
Botan::Path_Validation_Result::result
Certificate_Status_Code result() const
Definition: x509path.h:141
Botan::Certificate_Status_Code::CERT_CHAIN_TOO_LONG
Botan::Certificate_Status_Code::CERT_HAS_EXPIRED
Botan::Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK
Botan::Certificate_Status_Code::UNTRUSTED_HASH
Botan::Certificate_Status_Code::CERT_ISSUER_NOT_FOUND
Botan::X509_DN
Definition: x509_dn.h:22
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
Botan::Certificate_Status_Code::CERT_CHAIN_LOOP
Botan::HTTP::POST_sync
Response POST_sync(const std::string &url, const std::string &content_type, const std::vector< uint8_t > &body, size_t allowable_redirects)
Definition: http_util.cpp:294
Botan::Path_Validation_Result
Definition: x509path.h:110
Botan::Certificate_Status_Code::FIRST_ERROR_STATUS
Botan
Definition: alg_id.cpp:13
Botan::Path_Validation_Restrictions::ocsp_all_intermediates
bool ocsp_all_intermediates() const
Definition: x509path.h:85
Botan::Certificate_Status_Code::CRL_HAS_EXPIRED
Botan::Certificate_Store_In_Memory::add_certificate
void add_certificate(const X509_Certificate &cert)
Definition: certstor.cpp:19
Botan::x509_path_validate
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, const std::string &hostname, Usage_Type usage, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds ocsp_timeout, const std::vector< std::shared_ptr< const OCSP::Response >> &ocsp_resp)
Definition: x509path.cpp:562
Botan::Path_Validation_Result::trusted_hashes
std::set< std::string > trusted_hashes() const
Definition: x509path.cpp:710
Botan::Path_Validation_Result::result_string
std::string result_string() const
Definition: x509path.cpp:725
Botan::Path_Validation_Restrictions::trusted_hashes
const std::set< std::string > & trusted_hashes() const
Definition: x509path.h:91
Botan::PKIX::build_certificate_path
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)
Definition: x509path.cpp:414
Botan::to_string
std::string to_string(const secure_vector< uint8_t > &bytes)
Definition: stl_util.h:25
Botan::Path_Validation_Result::status_string
static const char * status_string(Certificate_Status_Code code)
Definition: x509path.cpp:730
Botan::Path_Validation_Restrictions::Path_Validation_Restrictions
Path_Validation_Restrictions(bool require_rev=false, size_t minimum_key_strength=110, bool ocsp_all_intermediates=false)
Definition: x509path.cpp:676
Botan::CertificatePathStatusCodes
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
Definition: x509path.h:29
Botan::X509_Certificate::issuer_dn
X509_DN issuer_dn() const
Definition: x509cert.cpp:432
Botan::Certificate_Status_Code::CERT_NOT_YET_VALID
Botan::Certificate_Status_Code::OCSP_SIGNATURE_OK
Botan::HTTP::GET_sync
Response GET_sync(const std::string &url, size_t allowable_redirects)
Definition: http_util.cpp:289
Botan::Certificate_Store_In_Memory
Definition: certstor.h:74
Botan::Certificate_Store
Definition: certstor.h:19
Botan::Certificate_Status_Code
Certificate_Status_Code
Definition: cert_status.h:18
Botan::Path_Validation_Result::successful_validation
bool successful_validation() const
Definition: x509path.cpp:718
Botan::Path_Validation_Restrictions::minimum_key_strength
size_t minimum_key_strength() const
Definition: x509path.h:97
Botan::Certificate_Status_Code::OCSP_RESPONSE_INVALID
Botan::Certificate_Status_Code::VERIFIED
Botan::X509_Time
Definition: asn1_time.h:19
Botan::X509_Certificate::authority_key_id
std::vector< uint8_t > authority_key_id() const
Definition: x509cert.cpp:411
Botan::BigInt::decode
static BigInt decode(const uint8_t buf[], size_t length, Base base=Binary)
Definition: big_code.cpp:114
Botan::Certificate_Status_Code::CERT_IS_REVOKED
Botan::Certificate_Status_Code::OCSP_NO_HTTP
Botan::Usage_Type
Usage_Type
Definition: x509cert.h:24
Botan::Certificate_Status_Code::NO_REVOCATION_DATA
Botan::Certificate_Status_Code::INVALID_USAGE
Botan::Path_Validation_Result::trust_root
const X509_Certificate & trust_root() const
Definition: x509path.cpp:700
Botan::Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER