Botan 3.8.1
Crypto and TLS for C&
x509_ca.cpp
Go to the documentation of this file.
1/*
2* X.509 Certificate Authority
3* (C) 1999-2010,2023 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/x509_ca.h>
9
10#include <botan/bigint.h>
11#include <botan/der_enc.h>
12#include <botan/pkcs10.h>
13#include <botan/pubkey.h>
14#include <botan/x509_ext.h>
15#include <botan/x509_key.h>
16
17namespace Botan {
18
19/*
20* Load the certificate and private key
21*/
23 const Private_Key& key,
24 std::string_view hash_fn,
25 std::string_view padding_method,
27 m_ca_cert(cert) {
28 if(!m_ca_cert.is_CA_cert()) {
29 throw Invalid_Argument("X509_CA: This certificate is not for a CA");
30 }
31
32 m_signer = X509_Object::choose_sig_format(key, rng, hash_fn, padding_method);
33 m_ca_sig_algo = m_signer->algorithm_identifier();
34 m_hash_fn = m_signer->hash_function();
35}
36
37X509_CA::X509_CA(X509_CA&&) = default;
39
40X509_CA::~X509_CA() = default;
41
43 const X509_Certificate& ca_cert,
44 std::string_view hash_fn) {
45 const auto constraints = req.is_CA() ? Key_Constraints::ca_constraints() : req.constraints();
46
47 auto key = req.subject_public_key();
48 if(!constraints.compatible_with(*key)) {
49 throw Invalid_Argument("The requested key constraints are incompatible with the algorithm");
50 }
51
52 Extensions extensions = req.extensions();
53
54 extensions.replace(std::make_unique<Cert_Extension::Basic_Constraints>(req.is_CA(), req.path_limit()), true);
55
56 if(!constraints.empty()) {
57 extensions.replace(std::make_unique<Cert_Extension::Key_Usage>(constraints), true);
58 }
59
60 extensions.replace(std::make_unique<Cert_Extension::Authority_Key_ID>(ca_cert.subject_key_id()));
61 extensions.replace(std::make_unique<Cert_Extension::Subject_Key_ID>(req.raw_public_key(), hash_fn));
62
63 extensions.replace(std::make_unique<Cert_Extension::Subject_Alternative_Name>(req.subject_alt_name()));
64
65 extensions.replace(std::make_unique<Cert_Extension::Extended_Key_Usage>(req.ex_constraints()));
66
67 return extensions;
68}
69
72 const BigInt& serial_number,
73 const X509_Time& not_before,
74 const X509_Time& not_after) const {
75 auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn);
76
77 return make_cert(*m_signer,
78 rng,
79 serial_number,
81 req.raw_public_key(),
82 not_before,
83 not_after,
84 ca_certificate().subject_dn(),
85 req.subject_dn(),
86 extensions);
87}
88
89/*
90* Sign a PKCS #10 certificate request
91*/
94 const X509_Time& not_before,
95 const X509_Time& not_after) const {
96 auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn);
97
98 return make_cert(*m_signer,
99 rng,
101 req.raw_public_key(),
102 not_before,
103 not_after,
104 ca_certificate().subject_dn(),
105 req.subject_dn(),
106 extensions);
107}
108
111 const AlgorithmIdentifier& sig_algo,
112 const std::vector<uint8_t>& pub_key,
113 const X509_Time& not_before,
114 const X509_Time& not_after,
115 const X509_DN& issuer_dn,
116 const X509_DN& subject_dn,
117 const Extensions& extensions) {
118 const size_t SERIAL_BITS = 128;
119 BigInt serial_no(rng, SERIAL_BITS);
120
121 return make_cert(
122 signer, rng, serial_no, sig_algo, pub_key, not_before, not_after, issuer_dn, subject_dn, extensions);
123}
124
125/*
126* Create a new certificate
127*/
130 const BigInt& serial_no,
131 const AlgorithmIdentifier& sig_algo,
132 const std::vector<uint8_t>& pub_key,
133 const X509_Time& not_before,
134 const X509_Time& not_after,
135 const X509_DN& issuer_dn,
136 const X509_DN& subject_dn,
137 const Extensions& extensions) {
138 const size_t X509_CERT_VERSION = 3;
139
140 // clang-format off
142 signer, rng, sig_algo,
143 DER_Encoder().start_sequence()
144 .start_explicit(0)
145 .encode(X509_CERT_VERSION-1)
146 .end_explicit()
147
148 .encode(serial_no)
149
150 .encode(sig_algo)
151 .encode(issuer_dn)
152
153 .start_sequence()
154 .encode(not_before)
155 .encode(not_after)
156 .end_cons()
157
158 .encode(subject_dn)
159 .raw_bytes(pub_key)
160
161 .start_explicit(3)
162 .start_sequence()
163 .encode(extensions)
164 .end_cons()
165 .end_explicit()
166 .end_cons()
167 .get_contents()
168 ));
169 // clang-format on
170}
171
172/*
173* Create a new, empty CRL
174*/
175X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng, uint32_t next_update) const {
176 return new_crl(rng, std::chrono::system_clock::now(), std::chrono::seconds(next_update));
177}
178
179/*
180* Update a CRL with new entries
181*/
183 const std::vector<CRL_Entry>& new_revoked,
185 uint32_t next_update) const {
186 return update_crl(crl, new_revoked, rng, std::chrono::system_clock::now(), std::chrono::seconds(next_update));
187}
188
190 std::chrono::system_clock::time_point issue_time,
191 std::chrono::seconds next_update) const {
192 std::vector<CRL_Entry> empty;
193 return make_crl(empty, 1, rng, issue_time, next_update);
194}
195
197 const std::vector<CRL_Entry>& new_revoked,
199 std::chrono::system_clock::time_point issue_time,
200 std::chrono::seconds next_update) const {
201 std::vector<CRL_Entry> revoked = last_crl.get_revoked();
202
203 std::copy(new_revoked.begin(), new_revoked.end(), std::back_inserter(revoked));
204
205 return make_crl(revoked, last_crl.crl_number() + 1, rng, issue_time, next_update);
206}
207
208/*
209* Create a CRL
210*/
211X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
212 uint32_t crl_number,
214 std::chrono::system_clock::time_point issue_time,
215 std::chrono::seconds next_update) const {
216 const size_t X509_CRL_VERSION = 2;
217
218 auto expire_time = issue_time + next_update;
219
220 Extensions extensions;
221 extensions.add(std::make_unique<Cert_Extension::Authority_Key_ID>(m_ca_cert.subject_key_id()));
222 extensions.add(std::make_unique<Cert_Extension::CRL_Number>(crl_number));
223
224 // clang-format off
225 const std::vector<uint8_t> crl = X509_Object::make_signed(
226 *m_signer, rng, m_ca_sig_algo,
227 DER_Encoder().start_sequence()
228 .encode(X509_CRL_VERSION-1)
229 .encode(m_ca_sig_algo)
230 .encode(m_ca_cert.subject_dn())
231 .encode(X509_Time(issue_time))
232 .encode(X509_Time(expire_time))
233 .encode_if(!revoked.empty(),
235 .start_sequence()
236 .encode_list(revoked)
237 .end_cons()
238 )
239 .start_explicit(0)
240 .start_sequence()
241 .encode(extensions)
242 .end_cons()
243 .end_explicit()
244 .end_cons()
245 .get_contents());
246 // clang-format on
247
248 return X509_CRL(crl);
249}
250
251} // namespace Botan
void replace(std::unique_ptr< Certificate_Extension > extn, bool critical=false)
Definition x509_ext.cpp:172
void add(std::unique_ptr< Certificate_Extension > extn, bool critical=false)
Definition x509_ext.cpp:137
static Key_Constraints ca_constraints()
Definition pkix_enums.h:155
std::unique_ptr< Public_Key > subject_public_key() const
Definition pkcs10.cpp:203
const X509_DN & subject_dn() const
Definition pkcs10.cpp:189
std::vector< OID > ex_constraints() const
Definition pkcs10.cpp:236
size_t path_limit() const
Definition pkcs10.cpp:258
const std::vector< uint8_t > & raw_public_key() const
Definition pkcs10.cpp:196
Key_Constraints constraints() const
Definition pkcs10.cpp:225
bool is_CA() const
Definition pkcs10.cpp:247
const AlternativeName & subject_alt_name() const
Definition pkcs10.cpp:211
const Extensions & extensions() const
Definition pkcs10.cpp:218
X509_CRL new_crl(RandomNumberGenerator &rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const
Definition x509_ca.cpp:189
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
X509_CRL update_crl(const X509_CRL &last_crl, const std::vector< CRL_Entry > &new_entries, RandomNumberGenerator &rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const
Definition x509_ca.cpp:196
X509_CA & operator=(const X509_CA &)=delete
X509_CA(const X509_Certificate &ca_certificate, const Private_Key &key, std::string_view hash_fn, std::string_view padding_method, RandomNumberGenerator &rng)
Definition x509_ca.cpp:22
const AlgorithmIdentifier & algorithm_identifier() const
Definition x509_ca.h:33
const X509_Certificate & ca_certificate() const
Definition x509_ca.h:38
static Extensions choose_extensions(const PKCS10_Request &req, const X509_Certificate &ca_certificate, std::string_view hash_fn)
Definition x509_ca.cpp:42
X509_Certificate sign_request(const PKCS10_Request &req, RandomNumberGenerator &rng, const X509_Time &not_before, const X509_Time &not_after) const
Definition x509_ca.cpp:92
const std::vector< CRL_Entry > & get_revoked() const
Definition x509_crl.cpp:203
uint32_t crl_number() const
Definition x509_crl.cpp:228
const X509_DN & subject_dn() const
Definition x509cert.cpp:409
const std::vector< uint8_t > & subject_key_id() const
Definition x509cert.cpp:393
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:209
static std::vector< uint8_t > make_signed(PK_Signer &signer, RandomNumberGenerator &rng, const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &tbs)
Definition x509_obj.cpp:125
ASN1_Time X509_Time
Definition asn1_obj.h:417