9#include <botan/x509cert.h>
11#include <botan/asn1_obj.h>
12#include <botan/asn1_time.h>
13#include <botan/ber_dec.h>
14#include <botan/bigint.h>
15#include <botan/hash.h>
17#include <botan/pk_keys.h>
19#include <botan/x509_ext.h>
20#include <botan/x509_key.h>
21#include <botan/internal/charset.h>
26class X509_Certificate_Data final {
28 X509_Serial_Number m_serial;
30 std::vector<uint8_t> m_serial_bits;
31 AlgorithmIdentifier m_sig_algo_inner;
34 std::vector<uint8_t> m_issuer_dn_bits;
35 std::vector<uint8_t> m_subject_dn_bits;
38 std::vector<uint8_t> m_subject_public_key_bits;
39 std::vector<uint8_t> m_subject_public_key_bits_seq;
40 std::vector<uint8_t> m_subject_public_key_bitstring;
41 AlgorithmIdentifier m_subject_public_key_algid;
44 std::vector<uint8_t> m_subject_public_key_bitstring_sha1;
45 std::array<uint8_t, 32> m_subject_public_key_bitstring_sha256 = {};
47 std::vector<uint8_t> m_v2_issuer_key_id;
48 std::vector<uint8_t> m_v2_subject_key_id;
49 Extensions m_v3_extensions;
51 std::vector<OID> m_extended_key_usage;
52 std::vector<uint8_t> m_authority_key_id;
53 std::vector<uint8_t> m_subject_key_id;
54 std::vector<OID> m_cert_policies;
56 std::vector<URI> m_crl_distribution_points;
57 std::vector<URI> m_ocsp_responders;
58 std::vector<URI> m_ca_issuers;
61 std::vector<uint8_t> m_issuer_dn_bits_sha256;
63 std::vector<uint8_t> m_subject_dn_bits_sha256;
64 std::array<uint8_t, 20> m_issuer_dn_bits_sha1 = {};
65 std::array<uint8_t, 20> m_subject_dn_bits_sha1 = {};
67 std::string m_fingerprint_sha1;
68 std::string m_fingerprint_sha256;
70 std::array<uint8_t, 20> m_cert_data_sha1 = {};
71 std::array<uint8_t, 32> m_cert_data_sha256 = {};
73 AlternativeName m_subject_alt_name;
74 AlternativeName m_issuer_alt_name;
75 NameConstraints m_name_constraints;
78 std::optional<size_t> m_path_len_constraint;
79 Key_Constraints m_key_constraints;
80 bool m_self_signed =
false;
81 bool m_is_ca_certificate =
false;
82 bool m_subject_alt_name_exists =
false;
83 bool m_skip_revocation_check =
false;
93 return {
"X509 CERTIFICATE"};
105#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
114std::unique_ptr<X509_Certificate_Data> parse_x509_cert_body(
const X509_Object& obj) {
115 auto data = std::make_unique<X509_Certificate_Data>();
117 BER_Object public_key;
118 BER_Object v3_exts_data;
122 .decode(data->m_serial)
123 .decode(data->m_sig_algo_inner)
124 .decode(data->m_issuer_dn)
126 .decode(data->m_not_before)
127 .decode(data->m_not_after)
129 .decode(data->m_subject_dn)
130 .get_next(public_key)
133 .get_next(v3_exts_data)
134 .verify_end(
"TBSCertificate has extra data after extensions block");
136 if(data->m_version > 2) {
137 throw Decoding_Error(
"Unknown X.509 cert version " + std::to_string(data->m_version));
139 if(obj.signature_algorithm() != data->m_sig_algo_inner) {
140 throw Decoding_Error(
"X.509 Certificate had differing algorithm identifiers in inner and outer ID fields");
146 data->m_version += 1;
148 data->m_serial_bits = data->m_serial.magnitude();
152 data->m_subject_public_key_bits.assign(public_key.bits(), public_key.bits() + public_key.length());
157 .
decode(data->m_subject_public_key_algid)
165 cert_extensions.verify_end();
166 }
else if(v3_exts_data.is_set()) {
167 throw BER_Bad_Tag(
"Unknown tag in X.509 cert", v3_exts_data.tagging());
172 data->m_key_constraints = ext->get_constraints();
177 if(data->m_key_constraints.empty()) {
178 throw Decoding_Error(
"Certificate has invalid encoding for KeyUsage");
183 data->m_subject_key_id = ext->get_key_id();
187 data->m_authority_key_id = ext->get_key_id();
191 data->m_name_constraints = ext->get_name_constraints();
195 data->m_extended_key_usage = ext->object_identifiers();
207 if(data->m_extended_key_usage.empty()) {
208 throw Decoding_Error(
"Certificate has invalid empty EKU extension");
218 if(ext->is_ca() ==
true) {
226 const bool allowed_by_ku =
241 const bool allowed_by_ext_ku = [](
const std::vector<OID>& ext_ku) ->
bool {
249 const auto any_eku =
OID::from_name(
"X509v3.AnyExtendedKeyUsage");
251 for(
const auto& oid : ext_ku) {
252 if(oid == any_eku || oid == server_auth || oid == client_auth || oid == ocsp_sign) {
258 }(data->m_extended_key_usage);
260 if(allowed_by_ku && allowed_by_ext_ku) {
261 data->m_is_ca_certificate =
true;
262 data->m_path_len_constraint = ext->path_length_constraint();
268 data->m_issuer_alt_name = ext->get_alt_name();
272 data->m_subject_alt_name = ext->get_alt_name();
279 data->m_subject_alt_name_exists = data->m_v3_extensions.extension_set(san_oid);
289 data->m_skip_revocation_check =
294 data->m_cert_policies = ext->get_policy_oids();
298 data->m_ocsp_responders = ext->ocsp_responder_uris();
299 data->m_ca_issuers = ext->ca_issuer_uris();
303 data->m_crl_distribution_points = ext->crl_distribution_point_uris();
311 if(data->m_subject_dn == data->m_issuer_dn) {
312 if(!data->m_subject_key_id.empty() && !data->m_authority_key_id.empty()) {
317 data->m_self_signed = (data->m_subject_key_id == data->m_authority_key_id);
323 data->m_self_signed =
true;
327 const std::vector<uint8_t> full_encoding = obj.BER_encode();
330 sha1->update(data->m_subject_public_key_bitstring);
331 data->m_subject_public_key_bitstring_sha1 = sha1->final_stdvec();
334 sha1->update(full_encoding);
335 sha1->final(data->m_cert_data_sha1);
338 sha1->update(data->m_issuer_dn_bits);
339 sha1->final(data->m_issuer_dn_bits_sha1);
341 sha1->update(data->m_subject_dn_bits);
342 sha1->final(data->m_subject_dn_bits_sha1);
347 sha256->update(data->m_issuer_dn_bits);
348 data->m_issuer_dn_bits_sha256 = sha256->final_stdvec();
350 sha256->update(data->m_subject_dn_bits);
351 data->m_subject_dn_bits_sha256 = sha256->final_stdvec();
353 sha256->update(full_encoding);
354 sha256->final(data->m_cert_data_sha256);
357 sha256->update(data->m_subject_public_key_bitstring);
358 sha256->final(data->m_subject_public_key_bitstring_sha256);
368void X509_Certificate::force_decode() {
370 m_data = parse_x509_cert_body(*
this);
373const X509_Certificate_Data& X509_Certificate::data()
const {
374 if(m_data ==
nullptr) {
375 throw Invalid_State(
"X509_Certificate uninitialized");
381 return static_cast<uint32_t
>(data().m_version);
385 return data().m_self_signed;
389 return data().m_not_before;
393 return data().m_not_after;
397 return data().m_subject_public_key_algid;
401 return data().m_v2_issuer_key_id;
405 return data().m_v2_subject_key_id;
409 return data().m_subject_public_key_bits;
413 return data().m_subject_public_key_bits_seq;
417 return data().m_subject_public_key_bitstring;
421 if(data().m_subject_public_key_bitstring_sha1.empty()) {
422 throw Encoding_Error(
"X509_Certificate::subject_public_key_bitstring_sha1 called but SHA-1 disabled in build");
425 return data().m_subject_public_key_bitstring_sha1;
429 return data().m_subject_public_key_bitstring_sha256;
433 return data().m_authority_key_id;
437 return data().m_subject_key_id;
441 return data().m_serial_bits;
445 return data().m_serial;
453 return data().m_skip_revocation_check;
457 return data().m_issuer_dn;
461 return data().m_subject_dn;
465 return data().m_issuer_dn_bits;
469 return data().m_subject_dn_bits;
473 if(data().m_fingerprint_sha1.empty()) {
476 return data().m_cert_data_sha1;
480 return data().m_cert_data_sha256;
484 if(data().m_version < 3 && data().m_self_signed) {
488 return data().m_is_ca_certificate;
492 if(data().m_version < 3 && data().m_self_signed) {
496 return static_cast<uint32_t
>(data().m_path_len_constraint.value_or(Cert_Extension::NO_CERT_PATH_LIMIT));
500 return data().m_path_len_constraint;
504 return data().m_key_constraints;
508 return data().m_extended_key_usage;
512 return data().m_cert_policies;
516 return data().m_name_constraints;
520 return data().m_v3_extensions;
587 const auto any_eku =
OID::from_name(
"X509v3.AnyExtendedKeyUsage");
591 if(ext_ku == usage) {
602 if(ext_ku == any_eku && usage != ocsp_eku) {
619std::vector<std::string> uris_as_strings(
const std::vector<URI>& uris) {
620 std::vector<std::string> out;
621 out.reserve(uris.size());
622 for(
const auto& uri : uris) {
623 out.push_back(uri.original_input());
631 if(data().m_ocsp_responders.empty()) {
634 return data().m_ocsp_responders[0].original_input();
638 return uris_as_strings(data().m_ocsp_responders);
642 return data().m_ocsp_responders;
646 return uris_as_strings(data().m_ca_issuers);
650 return data().m_ca_issuers;
654 return uris_as_strings(data().m_crl_distribution_points);
658 return data().m_crl_distribution_points;
663 if(!data().m_crl_distribution_points.empty()) {
664 return data().m_crl_distribution_points[0].original_input();
672 std::vector<EmailAddress> out;
673 out.reserve(san_emails.size());
675 for(
const auto& addr : san_emails) {
679 for(
const auto& dn_email_str :
subject_dn().get_attribute(
"PKCS9.EmailAddress")) {
681 out.push_back(std::move(*parsed));
689 return data().m_subject_alt_name;
693 return data().m_issuer_alt_name;
698std::vector<std::string> get_cert_user_info(std::string_view req,
const X509_DN& dn,
const AlternativeName& alt_name) {
701 }
else if(req ==
"RFC822" || req ==
"Email") {
702 std::vector<std::string> out;
705 out.push_back(addr.to_string());
708 }
else if(req ==
"DNS") {
709 std::vector<std::string> out;
710 out.reserve(alt_name.
dns_names().size());
711 for(
const auto& dns : alt_name.
dns_names()) {
712 out.push_back(dns.to_string());
715 }
else if(req ==
"URI") {
716 std::vector<std::string> out;
717 out.reserve(alt_name.
uri_names().size());
718 for(
const auto& uri : alt_name.
uri_names()) {
719 out.push_back(uri.original_input());
722 }
else if(req ==
"IP") {
723 std::vector<std::string> ip_str;
725 ip_str.push_back(ipv4.to_string());
728 }
else if(req ==
"IPv6") {
729 std::vector<std::string> ip_str;
731 ip_str.push_back(ipv6.to_string());
761 }
catch(std::exception& e) {
771 if(data().m_issuer_dn_bits_sha256.empty()) {
772 throw Encoding_Error(
"X509_Certificate::raw_issuer_dn_sha256 called but SHA-256 disabled in build");
774 return data().m_issuer_dn_bits_sha256;
778 if(data().m_subject_dn_bits_sha256.empty()) {
779 throw Encoding_Error(
"X509_Certificate::raw_subject_dn_sha256 called but SHA-256 disabled in build");
781 return data().m_subject_dn_bits_sha256;
785 return data().m_issuer_dn_bits_sha1;
789 return data().m_subject_dn_bits_sha1;
802 if(hash_name ==
"SHA-256" && !data().m_fingerprint_sha256.empty()) {
803 return data().m_fingerprint_sha256;
804 }
else if(hash_name ==
"SHA-1" && !data().m_fingerprint_sha1.empty()) {
805 return data().m_fingerprint_sha1;
812 return Tag(data().m_cert_data_sha256);
818 for(
const auto& san : sans) {
831 if(!data().m_subject_alt_name_exists) {
832 for(
const auto& cn :
subject_dn().get_attribute(
"CN")) {
894 return !(cert1 == cert2);
899void format_alt_name(std::ostream& out, std::string_view label,
const AlternativeName& alt_name) {
900 if(alt_name.is_empty()) {
904 out << label <<
":\n";
906 for(
const auto& dns : alt_name.dns_names()) {
909 for(
const auto& ipv4 : alt_name.ipv4_addresses()) {
910 out <<
" IP: " << ipv4.to_string() <<
"\n";
912 for(
const auto& ipv6 : alt_name.ipv6_addresses()) {
913 out <<
" IP: " << ipv6.to_string() <<
"\n";
915 for(
const auto& uri : alt_name.uri_names()) {
918 for(
const auto& email : alt_name.email_addresses()) {
921 for(
const auto& mbox : alt_name.smtp_utf8_mailboxes()) {
924 for(
const auto& dn : alt_name.directory_names()) {
925 out <<
" DirName: " << dn <<
"\n";
927 for(
const auto& oid : alt_name.registered_ids()) {
928 out <<
" RegisteredID: " << oid.to_formatted_string() <<
"\n";
934 for(
const auto& other : alt_name.other_name_values()) {
935 if(other.oid() == smtp_utf8_oid) {
938 out <<
" OtherName " << other.oid().to_formatted_string() <<
": " <<
hex_encode(other.value()) <<
"\n";
945 std::ostringstream out;
949 out <<
"Issuer: " <<
issuer_dn() <<
"\n";
955 out <<
"Public Key [" << pubkey->algo_name() <<
"-" << pubkey->key_length() <<
"]\n\n";
959 out <<
"Public Key Invalid!\n"
961 <<
" Error: " << ex.
what() <<
"\n"
967 out <<
"Constraints:\n";
969 if(constraints.
empty()) {
970 out <<
" No key constraints set\n";
973 out <<
" Digital Signature\n";
976 out <<
" Non-Repudiation\n";
979 out <<
" Key Encipherment\n";
982 out <<
" Data Encipherment\n";
985 out <<
" Key Agreement\n";
988 out <<
" Cert Sign\n";
991 out <<
" CRL Sign\n";
994 out <<
" Encipher Only\n";
997 out <<
" Decipher Only\n";
1002 out <<
"Basic Constraints: CA";
1004 out <<
", path length " << *path_len;
1010 if(!policies.empty()) {
1013 for(
const auto& oid : policies) {
1014 out <<
" " << oid.to_string() <<
"\n";
1019 if(!ex_constraints.empty()) {
1020 out <<
"Extended Constraints:\n";
1021 for(
auto&& oid : ex_constraints) {
1022 out <<
" " << oid.to_formatted_string() <<
"\n";
1029 out <<
"Name Constraints:\n";
1034 out <<
" " << st.base();
1042 out <<
" " << st.base();
1050 out <<
"OCSP Responders:\n";
1058 out <<
"CA Issuers:\n";
1060 out <<
" URI: " << ca_issuer.original_input() <<
"\n";
1065 out <<
"CRL " << cdp.original_input() <<
"\n";
1080 format_alt_name(out,
"Issuer Alternative Name", this->
issuer_alt_name());
1083 out <<
"Revocation status checking is disabled for this certificate\n";
1087 out <<
"Certificate is self signed\n";
std::vector< uint8_t > BER_encode() const
std::string readable_string() const
Returns a human friendly string representation of no particular formatting.
const std::set< IPv6Address > & ipv6_addresses() const
Return the set of IPv6 addresses included in this alternative name.
const std::set< DNSName > & dns_names() const
Return the set of DNS names included in this alternative name.
const std::set< EmailAddress > & email_addresses() const
Return the set of email addresses included in this alternative name.
const std::set< IPv4Address > & ipv4_addresses() const
Return the set of IPv4 addresses included in this alternative name.
const std::set< URI > & uri_names() const
Return the set of URIs included in this alternative name.
BER_Decoder & decode(bool &out)
BER_Decoder & verify_end()
BER_Decoder & decode_octet_aligned_bitstring(std::vector< uint8_t, Alloc > &out, ASN1_Type type_tag=ASN1_Type::BitString, ASN1_Class class_tag=ASN1_Class::Universal)
bool matches_wildcard(std::string_view wildcard) const
static std::optional< DNSName > from_san_string(std::string_view name)
static std::optional< DNSName > from_string(std::string_view name)
static std::optional< EmailAddress > from_string(std::string_view addr)
const char * what() const noexcept override
bool critical_extension_set(const OID &oid) const
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< HashFunction > create(std::string_view algo_spec, std::string_view provider="")
static std::optional< IPv4Address > from_string(std::string_view str)
static std::optional< IPv6Address > from_string(std::string_view str)
bool includes(Key_Constraints::Bits other) const
const std::vector< GeneralSubtree > & permitted() const
std::string to_formatted_string() const
static std::optional< OID > from_name(std::string_view name)
static OID from_string(std::string_view str)
const std::vector< OID > & extended_key_usage() const
Key_Constraints constraints() const
bool operator==(const X509_Certificate &other) const
const NameConstraints & name_constraints() const
X509_Certificate()=default
std::vector< std::string > ocsp_responders() const
bool is_critical(std::string_view ex_name) const
const std::vector< uint8_t > & serial_number() const
std::string fingerprint(std::string_view hash_name="SHA-1") const
const std::vector< URI > & ocsp_responder_uris() const
const X509_DN & subject_dn() const
bool skip_revocation_check() const
uint32_t path_limit() const
const X509_Serial_Number & serial() const
const X509_Time & not_after() const
const std::vector< uint8_t > & authority_key_id() const
std::span< const uint8_t, 32 > certificate_data_sha256() const
bool allowed_extended_usage(std::string_view usage) const
const AlternativeName & issuer_alt_name() const
const std::vector< uint8_t > & raw_subject_dn() const
const std::vector< uint8_t > & subject_key_id() const
~X509_Certificate() override
std::span< const uint8_t, 32 > subject_public_key_bitstring_sha256() const
const std::vector< uint8_t > & subject_public_key_bits() const
bool has_constraints(Key_Constraints constraints) const
std::optional< size_t > path_length_constraint() const
const Extensions & v3_extensions() const
bool has_ex_constraint(std::string_view ex_constraint) const
std::vector< std::string > crl_distribution_points() const
const std::vector< uint8_t > & subject_public_key_bitstring_sha1() const
bool allowed_usage(Key_Constraints usage) const
const X509_DN & issuer_dn() const
const std::vector< uint8_t > & v2_issuer_key_id() const
std::string ocsp_responder() const
std::span< const uint8_t, 20 > certificate_data_sha1() const
bool matches_dns_name(std::string_view name) const
std::vector< std::string > subject_info(std::string_view name) const
const std::vector< uint8_t > & raw_subject_dn_sha256() const
const std::vector< URI > & crl_distribution_point_uris() const
uint32_t x509_version() const
const std::vector< URI > & ca_issuer_uris() const
std::string crl_distribution_point() const
const std::vector< OID > & certificate_policy_oids() const
std::unique_ptr< Public_Key > load_subject_public_key() const
X509_Certificate(DataSource &source)
bool is_self_signed() const
bool matches_ip(const IPv4Address &address) const
const std::vector< uint8_t > & raw_issuer_dn() const
bool operator<(const X509_Certificate &other) const
std::span< const uint8_t, 20 > raw_subject_dn_sha1() const
const std::vector< uint8_t > & raw_issuer_dn_sha256() const
const AlgorithmIdentifier & subject_public_key_algo() const
const AlternativeName & subject_alt_name() const
std::vector< std::string > ca_issuers() const
const std::vector< uint8_t > & subject_public_key_info() const
std::vector< EmailAddress > subject_email_addresses() const
bool is_serial_negative() const
const std::vector< uint8_t > & subject_public_key_bitstring() const
std::unique_ptr< Public_Key > subject_public_key() const
const std::vector< uint8_t > & v2_subject_key_id() const
const X509_Time & not_before() const
std::vector< std::string > issuer_info(std::string_view name) const
std::span< const uint8_t, 20 > raw_issuer_dn_sha1() const
std::string to_string() const
bool has_field(const OID &oid) const
std::vector< std::string > get_attribute(std::string_view attr) const
const std::vector< uint8_t > & signed_body() const
const AlgorithmIdentifier & signature_algorithm() const
virtual std::vector< std::string > alternate_PEM_labels() const
const std::vector< uint8_t > & signature() const
void load_data(DataSource &src)
virtual std::string PEM_label() const =0
std::string to_string() const
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
std::unique_ptr< Public_Key > load_key(DataSource &source)
std::string PEM_encode(const Public_Key &key)
std::string create_hex_fingerprint(std::span< const uint8_t > bits, std::string_view hash_name)
void hex_encode(char output[], const uint8_t input[], size_t input_length, bool uppercase)
bool operator!=(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
std::string format_hex_fingerprint(std::span< const uint8_t > bits)
std::string escape_control_chars(std::string_view utf8)