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>
18 #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
20 #include <botan/http_util.h>
30 std::chrono::system_clock::time_point ref_time,
31 const std::string& hostname,
33 size_t min_signature_algo_strength,
34 const std::set<std::string>& trusted_hashes)
39 const bool self_signed_ee_cert = (cert_path.size() == 1);
45 if(!hostname.empty() && !cert_path[0]->matches_dns_name(hostname))
48 if(!cert_path[0]->allowed_usage(usage))
51 for(
size_t i = 0; i != cert_path.size(); ++i)
53 std::set<Certificate_Status_Code>& status = cert_status.at(i);
55 const bool at_self_signed_root = (i == cert_path.size() - 1);
57 const std::shared_ptr<const X509_Certificate>& subject = cert_path[i];
59 const std::shared_ptr<const X509_Certificate>& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)];
61 if(at_self_signed_root && (issuer->is_self_signed() ==
false))
66 if(subject->issuer_dn() != issuer->subject_dn())
80 if(!issuer->is_CA_cert() && !self_signed_ee_cert)
83 if(issuer->path_limit() < i)
86 std::unique_ptr<Public_Key> issuer_key(issuer->subject_public_key());
94 if(subject->check_signature(*issuer_key) ==
false)
99 if(issuer_key->estimated_strength() < min_signature_algo_strength)
104 if(trusted_hashes.size() > 0 && !at_self_signed_root)
106 if(trusted_hashes.count(subject->hash_used_for_signature()) == 0)
111 Extensions extensions = subject->v3_extensions();
112 for(
auto& extension : extensions.
extensions())
114 extension.first->validate(*subject, *issuer, cert_path, cert_status, i);
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)
127 if(cert_path.empty())
132 for(
size_t i = 0; i != cert_path.size() - 1; ++i)
134 std::set<Certificate_Status_Code>& status = cert_status.at(i);
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);
139 if(i < ocsp_responses.size() && (ocsp_responses.at(i) !=
nullptr))
143 Certificate_Status_Code ocsp_signature_status = ocsp_responses.at(i)->check_signature(trusted_certstores, cert_path);
149 status.insert(ocsp_status);
154 status.insert(ocsp_signature_status);
164 while(cert_status.size() > 0 && cert_status.back().empty())
165 cert_status.pop_back();
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)
175 if(cert_path.empty())
179 const X509_Time validation_time(ref_time);
181 for(
size_t i = 0; i != cert_path.size() - 1; ++i)
183 std::set<Certificate_Status_Code>& status = cert_status.at(i);
185 if(i < crls.size() && crls.at(i))
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);
193 if(validation_time <
X509_Time(crls[i]->this_update()))
196 if(validation_time >
X509_Time(crls[i]->next_update()))
199 if(crls[i]->check_signature(ca->subject_public_key()) ==
false)
204 if(crls[i]->is_revoked(*subject))
209 while(cert_status.size() > 0 && cert_status.back().empty())
210 cert_status.pop_back();
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)
220 if(cert_path.empty())
223 if(certstores.empty())
226 std::vector<std::shared_ptr<const X509_CRL>> crls(cert_path.size());
228 for(
size_t i = 0; i != cert_path.size(); ++i)
231 for(
size_t c = 0; c != certstores.size(); ++c)
233 crls[i] = certstores[c]->find_crl_for(*cert_path[i]);
242 #if defined(BOTAN_HAS_ONLINE_REVOCATION_CHECKS)
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)
251 if(cert_path.empty())
254 std::vector<std::future<std::shared_ptr<const OCSP::Response>>> ocsp_response_futures;
258 if(ocsp_check_intermediate_CAs)
259 to_ocsp = cert_path.size() - 1;
260 if(cert_path.size() == 1)
263 for(
size_t i = 0; i < to_ocsp; ++i)
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);
268 if(subject->ocsp_responder() ==
"")
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");
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()));
280 "application/ocsp-request",
286 return std::make_shared<const OCSP::Response>(http.body());
291 std::vector<std::shared_ptr<const OCSP::Response>> ocsp_responses(ocsp_response_futures.size());
293 for(
size_t pass = 1; pass < 3; ++pass)
295 for(
size_t i = 0; i < ocsp_response_futures.size(); ++i)
299 if(ocsp_responses[i] ==
nullptr && ocsp_response_futures[i].valid())
301 std::future_status status = ocsp_response_futures[i].wait_for(timeout);
303 if(status == std::future_status::ready ||
304 status == std::future_status::deferred)
306 ocsp_responses[i] = ocsp_response_futures[i].get();
310 catch(std::exception&)
317 return PKIX::check_ocsp(cert_path, ocsp_responses, trusted_certstores, ref_time);
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)
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");
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());
335 for(
size_t i = 0; i != cert_path.size(); ++i)
337 for(
size_t c = 0; c != certstores.size(); ++i)
339 crls[i] = certstores[i]->find_crl_for(*cert_path[i]);
353 future_crls.emplace_back(std::future<std::shared_ptr<const X509_CRL>>());
355 else if(cert_path[i]->crl_distribution_point() ==
"")
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");
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();
368 return std::make_shared<const X509_CRL>(http.body());
373 for(
size_t i = 0; i != future_crls.size(); ++i)
375 if(future_crls[i].valid())
379 std::future_status status = future_crls[i].wait_for(timeout);
381 if(status == std::future_status::ready)
383 crls[i] = future_crls[i].get();
386 catch(std::exception& e)
397 for(
size_t i = 0; i != crl_status.size(); ++i)
403 crl_store->add_crl(crls[i]);
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)
419 if(end_entity->is_self_signed())
430 std::set<std::string> certs_seen;
432 cert_path.push_back(end_entity);
433 certs_seen.insert(end_entity->fingerprint(
"SHA-256"));
436 for(
size_t i = 0; i != end_entity_extra.size(); ++i)
446 std::shared_ptr<const X509_Certificate> issuer;
447 bool trusted_issuer =
false;
451 issuer = store->find_cert(issuer_dn, auth_key_id);
454 trusted_issuer =
true;
462 issuer = ee_extras.
find_cert(issuer_dn, auth_key_id);
468 const std::string fprint = issuer->fingerprint(
"SHA-256");
470 if(certs_seen.count(fprint) > 0)
473 certs_seen.insert(fprint);
474 cert_path.push_back(issuer);
476 if(issuer->is_self_signed())
493 bool require_rev_on_end_entity,
494 bool require_rev_on_intermediates)
496 if(chain_status.empty())
497 throw Invalid_Argument(
"PKIX::merge_revocation_status chain_status was empty");
499 for(
size_t i = 0; i != chain_status.size() - 1; ++i)
501 bool had_crl =
false, had_ocsp =
false;
503 if(i < crl.size() && crl[i].size() > 0)
505 for(
auto&& code : crl[i])
511 chain_status[i].insert(code);
515 if(i < ocsp.size() && ocsp[i].size() > 0)
517 for(
auto&& code : ocsp[i])
524 chain_status[i].insert(code);
528 if(had_crl ==
false && had_ocsp ==
false)
530 if((require_rev_on_end_entity && i == 0) ||
531 (require_rev_on_intermediates && i > 0))
541 if(cert_status.empty())
547 for(
const std::set<Certificate_Status_Code>& s : cert_status)
551 auto worst = *s.rbegin();
555 overall_status = worst;
563 const std::vector<X509_Certificate>& end_certs,
565 const std::vector<Certificate_Store*>& trusted_roots,
566 const std::string& hostname,
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)
572 if(end_certs.empty())
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)
579 end_entity_extra.push_back(std::make_shared<const X509_Certificate>(end_certs[i]));
582 std::vector<std::shared_ptr<const X509_Certificate>> cert_path;
603 if(ocsp_resp.size() > 0)
605 ocsp_status =
PKIX::check_ocsp(cert_path, ocsp_resp, trusted_roots, ref_time);
608 if(ocsp_status.empty() && ocsp_timeout != std::chrono::milliseconds(0))
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,
614 ocsp_status.resize(1);
629 const std::vector<Certificate_Store*>& trusted_roots,
630 const std::string& hostname,
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)
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);
642 const std::vector<X509_Certificate>& end_certs,
645 const std::string& hostname,
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)
651 std::vector<Certificate_Store*> trusted_roots;
652 trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
654 return x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
661 const std::string& hostname,
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)
667 std::vector<X509_Certificate> certs;
668 certs.push_back(end_cert);
670 std::vector<Certificate_Store*> trusted_roots;
671 trusted_roots.push_back(const_cast<Certificate_Store*>(&store));
673 return x509_path_validate(certs, restrictions, trusted_roots, hostname, usage, when, ocsp_timeout, ocsp_resp);
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)
683 if(key_strength <= 80)
684 m_trusted_hashes.insert(
"SHA-160");
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");
693 std::vector<std::shared_ptr<const X509_Certificate>>&& cert_chain) :
694 m_all_status(status),
695 m_cert_path(cert_chain),
702 if(m_cert_path.empty())
703 throw Exception(
"Path_Validation_Result::trust_root no path set");
705 throw Exception(
"Path_Validation_Result::trust_root meaningless with invalid status");
707 return *m_cert_path[m_cert_path.size()-1];
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());
735 return "Unknown error";
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)
Path_Validation_Result(CertificatePathStatusCodes status, std::vector< std::shared_ptr< const X509_Certificate >> &&cert_chain)
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)
Certificate_Status_Code BOTAN_DLL overall_status(const CertificatePathStatusCodes &cert_status)
std::shared_ptr< const X509_Certificate > find_cert(const X509_DN &subject_dn, const std::vector< uint8_t > &key_id) const override
std::vector< std::pair< std::unique_ptr< Certificate_Extension >, bool > > extensions() const
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)
bool require_revocation_information() const
#define BOTAN_ASSERT_NONNULL(ptr)
Certificate_Status_Code result() const
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)
Response POST_sync(const std::string &url, const std::string &content_type, const std::vector< uint8_t > &body, size_t allowable_redirects)
bool ocsp_all_intermediates() const
void add_certificate(const X509_Certificate &cert)
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)
std::set< std::string > trusted_hashes() const
std::string result_string() const
const std::set< std::string > & trusted_hashes() const
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)
std::string to_string(const secure_vector< uint8_t > &bytes)
static const char * status_string(Certificate_Status_Code code)
Path_Validation_Restrictions(bool require_rev=false, size_t minimum_key_strength=110, bool ocsp_all_intermediates=false)
std::vector< std::set< Certificate_Status_Code > > CertificatePathStatusCodes
X509_DN issuer_dn() const
Response GET_sync(const std::string &url, size_t allowable_redirects)
bool successful_validation() const
size_t minimum_key_strength() const
std::vector< uint8_t > authority_key_id() const
static BigInt decode(const uint8_t buf[], size_t length, Base base=Binary)
const X509_Certificate & trust_root() const