8#include <botan/x509_crl.h>
10#include <botan/asn1_obj.h>
11#include <botan/asn1_time.h>
12#include <botan/assert.h>
13#include <botan/ber_dec.h>
14#include <botan/bigint.h>
15#include <botan/data_src.h>
16#include <botan/x509_ext.h>
17#include <botan/x509cert.h>
18#include <botan/internal/x509_utils.h>
26 CRL_Data(
const X509_DN& issuer,
29 const std::vector<CRL_Entry>& revoked) :
30 m_issuer(issuer), m_this_update(this_update), m_next_update(next_update), m_entries(revoked) {
37 m_revoked_serials.clear();
38 for(
const auto& entry : m_entries) {
39 m_revoked_serials.insert(entry.serial());
48 std::vector<CRL_Entry> m_entries;
49 Extensions m_extensions;
52 std::set<X509_Serial_Number> m_revoked_serials;
55 std::optional<BigInt> m_crl_number;
56 std::vector<uint8_t> m_auth_key_id;
57 std::vector<URI> m_idp_urls;
58 bool m_has_unknown_critical_extension =
false;
79#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
89 const std::vector<CRL_Entry>& revoked) {
97 const bool serial_appears = data().m_revoked_serials.contains(cert.
serial());
101 if(!serial_appears) {
116 if(!crl_akid.empty() && !cert_akid.empty()) {
117 if(crl_akid != cert_akid) {
122 return serial_appears;
130std::unique_ptr<CRL_Data> decode_crl_body(
const std::vector<uint8_t>& body,
const AlgorithmIdentifier& sig_algo) {
131 auto data = std::make_unique<CRL_Data>();
136 data->m_version += 1;
138 if(data->m_version != 1 && data->m_version != 2) {
139 throw Decoding_Error(
"Unknown X.509 CRL version " + std::to_string(data->m_version));
143 const bool supports_extensions = data->m_version > 1;
145 AlgorithmIdentifier sig_algo_inner;
146 tbs_crl.decode(sig_algo_inner);
148 if(sig_algo != sig_algo_inner) {
149 throw Decoding_Error(
"Algorithm identifier mismatch in CRL");
152 tbs_crl.decode(data->m_issuer).decode(data->m_this_update);
161 const auto& next_update = tbs_crl.peek_next_object();
164 tbs_crl.decode(data->m_next_update);
173 while(cert_list.more_items()) {
175 cert_list.decode(entry);
177 if(entry.extensions().has_unknown_critical_extension()) {
178 data->m_has_unknown_critical_extension =
true;
181 if(!supports_extensions && entry.extensions().count() > 0) {
182 throw Decoding_Error(
"X509 CRL included extensions in a version that doesn't support them");
185 data->m_entries.push_back(std::move(entry));
198 next = tbs_crl.get_next_object();
202 if(!supports_extensions) {
203 throw Decoding_Error(
"X509 CRL included extensions in a version that doesn't support them");
207 crl_options.verify_end();
208 if(data->m_extensions.has_unknown_critical_extension()) {
209 data->m_has_unknown_critical_extension =
true;
212 if(tbs_crl.get_next_object().is_set()) {
217 tbs_crl.verify_end(
"Unexpected trailing data after CRL");
221 data->m_crl_number = ext->crl_number();
224 data->m_auth_key_id = ext->get_key_id();
227 const auto& dpn = ext->distribution_point_name();
228 if(dpn.has_value() && dpn->full_name().has_value()) {
229 for(
const auto& uri : dpn->full_name()->uri_names()) {
230 data->m_idp_urls.push_back(uri);
235 data->update_index();
242void X509_CRL::force_decode() {
246const CRL_Data& X509_CRL::data()
const {
248 throw Invalid_State(
"X509_CRL uninitialized");
254 return data().m_extensions;
261 return data().m_entries;
265 return static_cast<uint32_t
>(data().m_version);
269 return data().m_has_unknown_critical_extension;
276 return data().m_issuer;
283 return data().m_auth_key_id;
290 return data().m_crl_number;
298 if(num->bits() > 32) {
299 throw Encoding_Error(
"CRL number is too large to fit in uint32_t");
302 return num->to_u32bit();
312 return data().m_this_update;
319 return data().m_next_update;
326 if(!data().m_idp_urls.empty()) {
327 return data().m_idp_urls[0].original_input();
336 std::vector<std::string> out;
337 out.reserve(data().m_idp_urls.size());
338 for(
const auto& uri : data().m_idp_urls) {
339 out.push_back(uri.original_input());
345 return data().m_idp_urls;
357 auto has_common = [](
const auto& s1,
const auto& s2) {
358 return std::ranges::any_of(s1, [&](
const auto& e) {
return s2.contains(e); });
377 if(dp.crl_issuer().has_value()) {
379 if(!dp.crl_issuer()->directory_names().contains(crl_issuer_dn)) {
383 if(idp_ext ==
nullptr || !idp_ext->indirect_crl()) {
389 return crl_issuer_dn == cert.issuer_dn();
405 if(idp_ext !=
nullptr) {
406 const auto& idp_dpn = idp_ext->distribution_point_name();
407 if(!idp_dpn.has_value()) {
410 const auto& cert_dpn = dp.distribution_point_name();
411 if(cert_dpn.has_value()) {
413 if(cert_dpn->full_name().has_value() && idp_dpn->full_name().has_value()) {
414 return dp_names_overlap(*cert_dpn->full_name(), *idp_dpn->full_name());
420 if(dp.crl_issuer().has_value() && idp_dpn->full_name().has_value()) {
421 return dp_names_overlap(*idp_dpn->full_name(), *dp.crl_issuer());
435bool implicit_dp_matches(
const X509_CRL& crl,
438 if(crl.issuer_dn() != cert.issuer_dn()) {
441 if(idp_ext ==
nullptr) {
444 const auto& idp_dpn = idp_ext->distribution_point_name();
445 if(!idp_dpn.has_value()) {
448 if(!idp_dpn->full_name().has_value()) {
452 implicit_full_name.
add_dn(cert.issuer_dn());
453 return dp_names_overlap(*idp_dpn->full_name(), implicit_full_name);
473 if(cdp_ext ==
nullptr || cdp_ext->distribution_points().empty()) {
474 const bool match = implicit_dp_matches(crl, cert, idp_ext);
475 return {match, match};
486 const auto name_matches = [&](
const auto& dp) {
487 return dp_issuer_and_scope_ok(dp, crl.
issuer_dn(), idp_ext, cert) && dp_idp_name_matches(dp, idp_ext);
491 bool any_with_absent_reasons =
false;
492 for(
const auto& dp : cdp_ext->distribution_points()) {
493 if(name_matches(dp)) {
495 if(!dp.reasons().has_value()) {
496 any_with_absent_reasons =
true;
501 return {
true, any_with_absent_reasons};
510 const bool implicit_dp_fallback = (idp_ext ==
nullptr || !idp_ext->distribution_point_name().has_value());
511 const bool implicit = implicit_dp_fallback && implicit_dp_matches(crl, cert, idp_ext);
512 return {implicit, implicit};
#define BOTAN_ASSERT_NOMSG(expr)
const std::set< X509_DN > & directory_names() const
Return the set of directory names included in this alternative name.
void add_dn(const X509_DN &dn)
Add a directory name to this AlternativeName.
const std::set< URI > & uri_names() const
Return the set of URIs included in this alternative name.
const T * get_extension_object_as(const OID &oid=T::static_oid()) const
const std::vector< CRL_Entry > & get_revoked() const
const std::vector< uint8_t > & authority_key_id() const
const X509_Time & this_update() const
std::vector< std::string > issuing_distribution_points() const
const Extensions & extensions() const
uint32_t crl_number() const
const std::vector< URI > & issuing_distribution_point_uris() const
const X509_Time & next_update() const
const X509_DN & issuer_dn() const
bool has_unknown_critical_extension() const
bool has_matching_distribution_point(const X509_Certificate &cert) const
bool is_revoked(const X509_Certificate &cert) const
std::string crl_issuing_distribution_point() const
uint32_t x509_version() const
const std::optional< BigInt > & crl_number_bigint() const
const X509_Serial_Number & serial() const
const std::vector< uint8_t > & authority_key_id() const
const Extensions & v3_extensions() const
const X509_DN & issuer_dn() const
const std::vector< uint8_t > & signed_body() const
const AlgorithmIdentifier & signature_algorithm() const
virtual std::vector< std::string > alternate_PEM_labels() const
void load_data(DataSource &src)
virtual std::string PEM_label() const =0
DistributionPointMatch distribution_point_match(const X509_CRL &crl, const X509_Certificate &cert)