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