Botan 2.13.0 Crypto and TLS for C++11

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

x509_ca.cpp
Go to the documentation of this file.
1 /*
2 * X.509 Certificate Authority
3 * (C) 1999-2010 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7
8 #include <botan/x509_ca.h>
9 #include <botan/x509self.h>
10 #include <botan/pkcs10.h>
11 #include <botan/pubkey.h>
12 #include <botan/der_enc.h>
13 #include <botan/bigint.h>
14 #include <botan/parsing.h>
15 #include <botan/oids.h>
16 #include <botan/hash.h>
17 #include <botan/key_constraint.h>
18 #include <botan/emsa.h>
19 #include <botan/scan_name.h>
20 #include <algorithm>
21 #include <iterator>
22 #include <map>
23
24 namespace Botan {
25
26 /*
27 * Load the certificate and private key
28 */
29 X509_CA::X509_CA(const X509_Certificate& c,
30 const Private_Key& key,
31 const std::string& hash_fn,
32 RandomNumberGenerator& rng) :
33 m_ca_cert(c),
34 m_hash_fn(hash_fn)
35 {
36 if(!m_ca_cert.is_CA_cert())
37 throw Invalid_Argument("X509_CA: This certificate is not for a CA");
38
39 std::map<std::string,std::string> opts;
40 // constructor without additional options: use the padding used in the CA certificate
41 // sig_oid_str = <sig_alg>/<padding>, so padding with all its options will look
42 // like a cipher mode to the scanner
43 std::string sig_oid_str = OIDS::oid2str_or_throw(c.signature_algorithm().get_oid());
44 SCAN_Name scanner(sig_oid_str);
45 std::string pad = scanner.cipher_mode();
46 if(!pad.empty())
47 opts.insert({"padding",pad});
48
49 m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo));
50 }
51
52 /*
53 * Load the certificate and private key, and additional options
54 */
55 X509_CA::X509_CA(const X509_Certificate& ca_certificate,
56 const Private_Key& key,
57 const std::map<std::string,std::string>& opts,
58 const std::string& hash_fn,
59 RandomNumberGenerator& rng) : m_ca_cert(ca_certificate), m_hash_fn(hash_fn)
60 {
61 if(!m_ca_cert.is_CA_cert())
62 throw Invalid_Argument("X509_CA: This certificate is not for a CA");
63
64 m_signer.reset(choose_sig_format(key, opts, rng, hash_fn, m_ca_sig_algo));
65 }
66
67 /*
68 * X509_CA Destructor
69 */
70 X509_CA::~X509_CA()
71 {
72 /* for unique_ptr */
73 }
74
75 namespace {
76
77 Extensions choose_extensions(const PKCS10_Request& req,
78 const X509_Certificate& ca_cert,
79 const std::string& hash_fn)
80 {
81 Key_Constraints constraints;
82 if(req.is_CA())
83 {
84 constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
85 }
86 else
87 {
88 std::unique_ptr<Public_Key> key(req.subject_public_key());
89 verify_cert_constraints_valid_for_key_type(*key, req.constraints());
90 constraints = req.constraints();
91 }
92
93 Extensions extensions = req.extensions();
94
95 extensions.replace(
96 new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
97 true);
98
99 if(constraints != NO_CONSTRAINTS)
100 {
101 extensions.replace(new Cert_Extension::Key_Usage(constraints), true);
102 }
103
104 extensions.replace(new Cert_Extension::Authority_Key_ID(ca_cert.subject_key_id()));
105 extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key(), hash_fn));
106
107 extensions.replace(
108 new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name()));
109
110 extensions.replace(
111 new Cert_Extension::Extended_Key_Usage(req.ex_constraints()));
112
113 return extensions;
114 }
115
116 }
117
118 X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
119 RandomNumberGenerator& rng,
120 const BigInt& serial_number,
121 const X509_Time& not_before,
122 const X509_Time& not_after) const
123 {
124 auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn);
125
126 return make_cert(m_signer.get(), rng, serial_number,
127 m_ca_sig_algo, req.raw_public_key(),
128 not_before, not_after,
129 m_ca_cert.subject_dn(), req.subject_dn(),
130 extensions);
131 }
132
133 /*
134 * Sign a PKCS #10 certificate request
135 */
136 X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
137 RandomNumberGenerator& rng,
138 const X509_Time& not_before,
139 const X509_Time& not_after) const
140 {
141 auto extensions = choose_extensions(req, m_ca_cert, m_hash_fn);
142
143 return make_cert(m_signer.get(), rng, m_ca_sig_algo,
144 req.raw_public_key(),
145 not_before, not_after,
146 m_ca_cert.subject_dn(), req.subject_dn(),
147 extensions);
148 }
149
150 X509_Certificate X509_CA::make_cert(PK_Signer* signer,
151 RandomNumberGenerator& rng,
152 const AlgorithmIdentifier& sig_algo,
153 const std::vector<uint8_t>& pub_key,
154 const X509_Time& not_before,
155 const X509_Time& not_after,
156 const X509_DN& issuer_dn,
157 const X509_DN& subject_dn,
158 const Extensions& extensions)
159 {
160 const size_t SERIAL_BITS = 128;
161 BigInt serial_no(rng, SERIAL_BITS);
162
163 return make_cert(signer, rng, serial_no, sig_algo, pub_key,
164 not_before, not_after, issuer_dn, subject_dn, extensions);
165 }
166
167 /*
168 * Create a new certificate
169 */
170 X509_Certificate X509_CA::make_cert(PK_Signer* signer,
171 RandomNumberGenerator& rng,
172 const BigInt& serial_no,
173 const AlgorithmIdentifier& sig_algo,
174 const std::vector<uint8_t>& pub_key,
175 const X509_Time& not_before,
176 const X509_Time& not_after,
177 const X509_DN& issuer_dn,
178 const X509_DN& subject_dn,
179 const Extensions& extensions)
180 {
181 const size_t X509_CERT_VERSION = 3;
182
183 // clang-format off
184 return X509_Certificate(X509_Object::make_signed(
185 signer, rng, sig_algo,
186 DER_Encoder().start_cons(SEQUENCE)
187 .start_explicit(0)
188 .encode(X509_CERT_VERSION-1)
189 .end_explicit()
190
191 .encode(serial_no)
192
193 .encode(sig_algo)
194 .encode(issuer_dn)
195
196 .start_cons(SEQUENCE)
197 .encode(not_before)
198 .encode(not_after)
199 .end_cons()
200
201 .encode(subject_dn)
202 .raw_bytes(pub_key)
203
204 .start_explicit(3)
205 .start_cons(SEQUENCE)
206 .encode(extensions)
207 .end_cons()
208 .end_explicit()
209 .end_cons()
210 .get_contents()
211 ));
212 // clang-format on
213 }
214
215 /*
216 * Create a new, empty CRL
217 */
218 X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng,
219 uint32_t next_update) const
220 {
221 return new_crl(rng,
222 std::chrono::system_clock::now(),
223 std::chrono::seconds(next_update));
224 }
225
226 /*
227 * Update a CRL with new entries
228 */
229 X509_CRL X509_CA::update_crl(const X509_CRL& crl,
230 const std::vector<CRL_Entry>& new_revoked,
231 RandomNumberGenerator& rng,
232 uint32_t next_update) const
233 {
234 return update_crl(crl, new_revoked, rng,
235 std::chrono::system_clock::now(),
236 std::chrono::seconds(next_update));
237 }
238
239
240 X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng,
241 std::chrono::system_clock::time_point issue_time,
242 std::chrono::seconds next_update) const
243 {
244 std::vector<CRL_Entry> empty;
245 return make_crl(empty, 1, rng, issue_time, next_update);
246 }
247
248 X509_CRL X509_CA::update_crl(const X509_CRL& last_crl,
249 const std::vector<CRL_Entry>& new_revoked,
250 RandomNumberGenerator& rng,
251 std::chrono::system_clock::time_point issue_time,
252 std::chrono::seconds next_update) const
253 {
254 std::vector<CRL_Entry> revoked = last_crl.get_revoked();
255
256 std::copy(new_revoked.begin(), new_revoked.end(),
257 std::back_inserter(revoked));
258
259 return make_crl(revoked, last_crl.crl_number() + 1, rng, issue_time, next_update);
260 }
261
262 /*
263 * Create a CRL
264 */
265 X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
266 uint32_t crl_number,
267 RandomNumberGenerator& rng,
268 std::chrono::system_clock::time_point issue_time,
269 std::chrono::seconds next_update) const
270 {
271 const size_t X509_CRL_VERSION = 2;
272
273 auto expire_time = issue_time + next_update;
274
275 Extensions extensions;
276 extensions.add(new Cert_Extension::Authority_Key_ID(m_ca_cert.subject_key_id()));
277 extensions.add(new Cert_Extension::CRL_Number(crl_number));
278
279 // clang-format off
280 const std::vector<uint8_t> crl = X509_Object::make_signed(
281 m_signer.get(), rng, m_ca_sig_algo,
282 DER_Encoder().start_cons(SEQUENCE)
283 .encode(X509_CRL_VERSION-1)
284 .encode(m_ca_sig_algo)
285 .encode(m_ca_cert.subject_dn())
286 .encode(X509_Time(issue_time))
287 .encode(X509_Time(expire_time))
288 .encode_if(revoked.size() > 0,
289 DER_Encoder()
290 .start_cons(SEQUENCE)
291 .encode_list(revoked)
292 .end_cons()
293 )
294 .start_explicit(0)
295 .start_cons(SEQUENCE)
296 .encode(extensions)
297 .end_cons()
298 .end_explicit()
299 .end_cons()
300 .get_contents());
301 // clang-format on
302
303 return X509_CRL(crl);
304 }
305
306 /*
307 * Return the CA's certificate
308 */
309 X509_Certificate X509_CA::ca_certificate() const
310 {
311 return m_ca_cert;
312 }
313
314 /*
315 * Choose a signing format for the key
316 */
317
318 PK_Signer* choose_sig_format(const Private_Key& key,
319 RandomNumberGenerator& rng,
320 const std::string& hash_fn,
321 AlgorithmIdentifier& sig_algo)
322 {
323 return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, "").release();
324 }
325
326 PK_Signer* choose_sig_format(const Private_Key& key,
327 const std::map<std::string,std::string>& opts,
328 RandomNumberGenerator& rng,
329 const std::string& hash_fn,
330 AlgorithmIdentifier& sig_algo)
331 {
332 std::string padding;
333 if(opts.count("padding"))
334 padding = opts.at("padding");
335 return X509_Object::choose_sig_format(sig_algo, key, rng, hash_fn, padding).release();
336 }
337
338 }
Botan::OIDS::oid2str_or_throw
BOTAN_UNSTABLE_API std::string oid2str_or_throw(const OID &oid)
Definition: oids.cpp:121
Botan::X509_Certificate::subject_key_id
const std::vector< uint8_t > & subject_key_id() const
Definition: x509cert.cpp:417
Botan::PKCS10_Request::subject_dn
const X509_DN & subject_dn() const
Definition: pkcs10.cpp:211
Botan::Invalid_Argument
Definition: exceptn.h:136
Botan::DER_Encoder::encode_list
DER_Encoder & encode_list(const std::vector< T > &values)
Definition: der_enc.h:129
Botan::PKCS10_Request::subject_alt_name
const AlternativeName & subject_alt_name() const
Definition: pkcs10.cpp:236
Botan::X509_CA::make_cert
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:150
Botan::BigInt
Definition: bigint.h:24
Botan::X509_CA::~X509_CA
~X509_CA()
Definition: x509_ca.cpp:70
Botan::PKCS10_Request::path_limit
size_t path_limit() const
Definition: pkcs10.cpp:291
Botan::PKCS10_Request::ex_constraints
std::vector< OID > ex_constraints() const
Definition: pkcs10.cpp:265
Botan::RandomNumberGenerator
Definition: rng.h:24
Botan::PKCS10_Request::subject_public_key
Public_Key * subject_public_key() const
Definition: pkcs10.cpp:227
Botan::Private_Key
Definition: pk_keys.h:181
Botan::PKCS10_Request::is_CA
bool is_CA() const
Definition: pkcs10.cpp:278
Botan::X509_Object::make_signed
static std::vector< uint8_t > make_signed(class PK_Signer *signer, RandomNumberGenerator &rng, const AlgorithmIdentifier &alg_id, const secure_vector< uint8_t > &tbs)
Definition: x509_obj.cpp:268
Botan::X509_Certificate::is_CA_cert
bool is_CA_cert() const
Definition: x509cert.cpp:453
Botan::Extensions::replace
void replace(Certificate_Extension *extn, bool critical=false)
Definition: x509_ext.cpp:166
Botan::Extensions
Definition: x509_ext.h:90
Botan::PKCS10_Request::extensions
const Extensions & extensions() const
Definition: pkcs10.cpp:244
Botan::DER_Encoder::end_cons
DER_Encoder & end_cons()
Definition: der_enc.cpp:191
Botan::X509_CRL::get_revoked
const std::vector< CRL_Entry > & get_revoked() const
Definition: x509_crl.cpp:216
Botan::X509_Object::signature_algorithm
const AlgorithmIdentifier & signature_algorithm() const
Definition: x509_obj.h:48
Botan::PKCS10_Request::raw_public_key
const std::vector< uint8_t > & raw_public_key() const
Definition: pkcs10.cpp:219
Botan::Extensions::add
void add(Certificate_Extension *extn, bool critical=false)
Definition: x509_ext.cpp:123
Botan::NO_CONSTRAINTS
Definition: key_constraint.h:22
Botan::X509_CA::X509_CA
X509_CA(const X509_Certificate &ca_certificate, const Private_Key &key, const std::string &hash_fn, RandomNumberGenerator &rng)
Definition: x509_ca.cpp:29
Botan::DER_Encoder::encode
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:285
Botan::SEQUENCE
Definition: asn1_obj.h:40
Botan::DER_Encoder
Definition: der_enc.h:23
Botan::X509_Object::choose_sig_format
static std::unique_ptr< PK_Signer > choose_sig_format(AlgorithmIdentifier &sig_algo, const Private_Key &key, RandomNumberGenerator &rng, const std::string &hash_fn, const std::string &padding_algo)
Definition: x509_obj.cpp:376
Botan::CRL_SIGN
Definition: key_constraint.h:29
Botan::X509_Certificate
Definition: x509cert.h:40
Botan::PEM_Code::encode
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
Botan::X509_CA::ca_certificate
X509_Certificate ca_certificate() const
Definition: x509_ca.cpp:309
Botan::X509_DN
Definition: x509_dn.h:24
Botan::PKCS10_Request
Definition: pkcs10.h:28
Botan
Definition: alg_id.cpp:13
Botan::AlgorithmIdentifier::get_oid
const OID & get_oid() const
Definition: alg_id.h:37
Botan::X509_CA::new_crl
X509_CRL new_crl(RandomNumberGenerator &rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const
Definition: x509_ca.cpp:240
Botan::verify_cert_constraints_valid_for_key_type
void verify_cert_constraints_valid_for_key_type(const Public_Key &pub_key, Key_Constraints constraints)
Definition: key_constraint.cpp:70
Botan::SCAN_Name
Definition: scan_name.h:23
Botan::X509_CA::update_crl
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:248
Botan::PKCS10_Request::constraints
Key_Constraints constraints() const
Definition: pkcs10.cpp:252
Botan::X509_CA::sign_request
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:136
Botan::Cert_Extension::CRL_Number
Definition: x509_ext.h:605
Botan::choose_sig_format
PK_Signer * choose_sig_format(const Private_Key &key, RandomNumberGenerator &rng, const std::string &hash_fn, AlgorithmIdentifier &sig_algo)
Definition: x509_ca.cpp:318
Botan::AlgorithmIdentifier
Definition: alg_id.h:21
Botan::DER_Encoder::start_cons
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:181
Botan::Cert_Extension::Authority_Key_ID
Definition: x509_ext.h:387
Botan::X509_CRL
Definition: x509_crl.h:26
Botan::X509_Certificate::subject_dn
const X509_DN & subject_dn() const
Definition: x509cert.cpp:438
Botan::PK_Signer
Definition: pubkey.h:166
Botan::Key_Constraints
Key_Constraints
Definition: key_constraint.h:21
Botan::X509_Time
Definition: asn1_time.h:19
Botan::KEY_CERT_SIGN
Definition: key_constraint.h:28
Botan::X509_CRL::crl_number
uint32_t crl_number() const
Definition: x509_crl.cpp:240