Botan 3.10.0
Crypto and TLS for C&
x509self.cpp
Go to the documentation of this file.
1/*
2* PKCS #10/Self Signed Cert Creation
3* (C) 1999-2008,2018 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/x509self.h>
9
10#include <botan/assert.h>
11#include <botan/pubkey.h>
12#include <botan/x509_ca.h>
13#include <botan/x509_ext.h>
14#include <botan/x509_key.h>
15#include <botan/internal/fmt.h>
16#include <botan/internal/parsing.h>
17
18namespace Botan {
19
20namespace {
21
22/*
23* Load information from the X509_Cert_Options
24*/
25X509_DN load_dn_info(const X509_Cert_Options& opts) {
26 X509_DN subject_dn;
27
28 subject_dn.add_attribute("X520.CommonName", opts.common_name);
29 subject_dn.add_attribute("X520.Country", opts.country);
30 subject_dn.add_attribute("X520.State", opts.state);
31 subject_dn.add_attribute("X520.Locality", opts.locality);
32 subject_dn.add_attribute("X520.Organization", opts.organization);
33 subject_dn.add_attribute("X520.OrganizationalUnit", opts.org_unit);
34 subject_dn.add_attribute("X520.SerialNumber", opts.serial_number);
35
36 for(const auto& extra_ou : opts.more_org_units) {
37 subject_dn.add_attribute("X520.OrganizationalUnit", extra_ou);
38 }
39
40 return subject_dn;
41}
42
43auto create_alt_name_ext(const X509_Cert_Options& opts, const Extensions& extensions) {
44 AlternativeName subject_alt;
45
46 /*
47 If the extension was already created in opts.extension we need to
48 merge the values provided in opts with the values set in the extension.
49 */
50 if(const auto* ext = extensions.get_extension_object_as<Cert_Extension::Subject_Alternative_Name>()) {
51 subject_alt = ext->get_alt_name();
52 }
53
54 subject_alt.add_dns(opts.dns);
55 for(const auto& nm : opts.more_dns) {
56 subject_alt.add_dns(nm);
57 }
58 subject_alt.add_uri(opts.uri);
59 subject_alt.add_email(opts.email);
60 if(!opts.ip.empty()) {
61 if(auto ipv4 = string_to_ipv4(opts.ip)) {
62 subject_alt.add_ipv4_address(*ipv4);
63 } else {
64 throw Invalid_Argument(fmt("Invalid IPv4 address '{}'", opts.ip));
65 }
66 }
67
68 if(!opts.xmpp.empty()) {
69 subject_alt.add_other_name(OID::from_string("PKIX.XMPPAddr"), ASN1_String(opts.xmpp, ASN1_Type::Utf8String));
70 }
71
72 return std::make_unique<Cert_Extension::Subject_Alternative_Name>(subject_alt);
73}
74
75} // namespace
76
77namespace X509 {
78
79/*
80* Create a new self-signed X.509 certificate
81*/
83 const Private_Key& key,
84 std::string_view hash_fn,
86 const std::vector<uint8_t> pub_key = X509::BER_encode(key);
87 auto signer = X509_Object::choose_sig_format(key, rng, hash_fn, opts.padding_scheme);
88 const AlgorithmIdentifier sig_algo = signer->algorithm_identifier();
89 BOTAN_ASSERT_NOMSG(sig_algo.oid().has_value());
90
91 const auto subject_dn = load_dn_info(opts);
92
93 Extensions extensions = opts.extensions;
94
95 const auto constraints = opts.is_CA ? Key_Constraints::ca_constraints() : opts.constraints;
96
97 if(!constraints.compatible_with(key)) {
98 throw Invalid_Argument("The requested key constraints are incompatible with the algorithm");
99 }
100
101 extensions.add_new(std::make_unique<Cert_Extension::Basic_Constraints>(opts.is_CA, opts.path_limit), true);
102
103 if(!constraints.empty()) {
104 extensions.add_new(std::make_unique<Cert_Extension::Key_Usage>(constraints), true);
105 }
106
107 auto skid = std::make_unique<Cert_Extension::Subject_Key_ID>(pub_key, signer->hash_function());
108
109 extensions.add_new(std::make_unique<Cert_Extension::Authority_Key_ID>(skid->get_key_id()));
110 extensions.add_new(std::move(skid));
111
112 extensions.replace(create_alt_name_ext(opts, extensions));
113
114 extensions.add_new(std::make_unique<Cert_Extension::Extended_Key_Usage>(opts.ex_constraints));
115
116 return X509_CA::make_cert(*signer, rng, sig_algo, pub_key, opts.start, opts.end, subject_dn, subject_dn, extensions);
117}
118
119/*
120* Create a PKCS #10 certificate request
121*/
123 const Private_Key& key,
124 std::string_view hash_fn,
126 const auto subject_dn = load_dn_info(opts);
127
128 const auto constraints = opts.is_CA ? Key_Constraints::ca_constraints() : opts.constraints;
129
130 if(!constraints.compatible_with(key)) {
131 throw Invalid_Argument("The requested key constraints are incompatible with the algorithm");
132 }
133
134 Extensions extensions = opts.extensions;
135
136 extensions.add_new(std::make_unique<Cert_Extension::Basic_Constraints>(opts.is_CA, opts.path_limit));
137
138 if(!constraints.empty()) {
139 extensions.add_new(std::make_unique<Cert_Extension::Key_Usage>(constraints));
140 }
141
142 extensions.replace(create_alt_name_ext(opts, extensions));
143
144 if(!opts.ex_constraints.empty()) {
145 extensions.add_new(std::make_unique<Cert_Extension::Extended_Key_Usage>(opts.ex_constraints));
146 }
147
148 return PKCS10_Request::create(key, subject_dn, extensions, hash_fn, rng, opts.padding_scheme, opts.challenge);
149}
150
151} // namespace X509
152
153} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
const OID & oid() const
Definition asn1_obj.h:479
void add_dns(std::string_view dns)
Add a DNS name to this AlternativeName.
Definition alt_name.cpp:30
void replace(std::unique_ptr< Certificate_Extension > extn, bool critical=false)
Definition x509_ext.cpp:178
bool add_new(std::unique_ptr< Certificate_Extension > extn, bool critical=false)
Definition x509_ext.cpp:156
static Key_Constraints ca_constraints()
Definition pkix_enums.h:161
bool has_value() const
Definition asn1_obj.h:271
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
static PKCS10_Request create(const Private_Key &key, const X509_DN &subject_dn, const Extensions &extensions, std::string_view hash_fn, RandomNumberGenerator &rng, std::string_view padding_scheme="", std::string_view challenge="")
Definition pkcs10.cpp:53
static X509_Certificate make_cert(PK_Signer &signer, RandomNumberGenerator &rng, const AlgorithmIdentifier &sig_algo, const std::vector< uint8_t > &pub_key, const X509_Time &not_before, const X509_Time &not_after, const X509_DN &issuer_dn, const X509_DN &subject_dn, const Extensions &extensions)
Definition x509_ca.cpp:109
std::vector< OID > ex_constraints
Definition x509self.h:132
Key_Constraints constraints
Definition x509self.h:127
std::string challenge
Definition x509self.h:98
std::string padding_scheme
Definition x509self.h:122
void add_attribute(std::string_view key, std::string_view val)
Definition x509_dn.cpp:100
static std::unique_ptr< PK_Signer > choose_sig_format(const Private_Key &key, RandomNumberGenerator &rng, std::string_view hash_fn, std::string_view padding_algo)
Definition x509_obj.cpp:208
PKCS10_Request create_cert_req(const X509_Cert_Options &opts, const Private_Key &key, std::string_view hash_fn, RandomNumberGenerator &rng)
Definition x509self.cpp:122
std::vector< uint8_t > BER_encode(const Public_Key &key)
Definition x509_key.h:24
X509_Certificate create_self_signed_cert(const X509_Cert_Options &opts, const Private_Key &key, std::string_view hash_fn, RandomNumberGenerator &rng)
Definition x509self.cpp:82
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
std::optional< uint32_t > string_to_ipv4(std::string_view str)
Definition parsing.cpp:156