Botan  2.4.0
Crypto and TLS for C++11
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 */
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::lookup(c.signature_algorithm().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 */
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 */
71  {
72  /* for unique_ptr */
73  }
74 
75 /*
76 * Sign a PKCS #10 certificate request
77 */
80  const X509_Time& not_before,
81  const X509_Time& not_after) const
82  {
83  Key_Constraints constraints;
84  if(req.is_CA())
85  {
86  constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
87  }
88  else
89  {
90  std::unique_ptr<Public_Key> key(req.subject_public_key());
92  constraints = req.constraints();
93  }
94 
95  Extensions extensions = req.extensions();
96 
97  extensions.replace(
99  true);
100 
101  if(constraints != NO_CONSTRAINTS)
102  {
103  extensions.replace(new Cert_Extension::Key_Usage(constraints), true);
104  }
105 
106  extensions.replace(new Cert_Extension::Authority_Key_ID(m_ca_cert.subject_key_id()));
107  extensions.replace(new Cert_Extension::Subject_Key_ID(req.raw_public_key(), m_hash_fn));
108 
109  extensions.replace(
111 
112  extensions.replace(
114 
115  return make_cert(m_signer.get(), rng, m_ca_sig_algo,
116  req.raw_public_key(),
117  not_before, not_after,
118  m_ca_cert.subject_dn(), req.subject_dn(),
119  extensions);
120  }
121 
122 /*
123 * Create a new certificate
124 */
127  const AlgorithmIdentifier& sig_algo,
128  const std::vector<uint8_t>& pub_key,
129  const X509_Time& not_before,
130  const X509_Time& not_after,
131  const X509_DN& issuer_dn,
132  const X509_DN& subject_dn,
133  const Extensions& extensions)
134  {
135  const size_t X509_CERT_VERSION = 3;
136  const size_t SERIAL_BITS = 128;
137 
138  BigInt serial_no(rng, SERIAL_BITS);
139 
140  // clang-format off
142  signer, rng, sig_algo,
143  DER_Encoder().start_cons(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_cons(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_cons(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 */
176  uint32_t next_update) const
177  {
178  return new_crl(rng,
179  std::chrono::system_clock::now(),
180  std::chrono::seconds(next_update));
181  }
182 
183 /*
184 * Update a CRL with new entries
185 */
187  const std::vector<CRL_Entry>& new_revoked,
189  uint32_t next_update) const
190  {
191  return update_crl(crl, new_revoked, rng,
192  std::chrono::system_clock::now(),
193  std::chrono::seconds(next_update));
194  }
195 
196 
198  std::chrono::system_clock::time_point issue_time,
199  std::chrono::seconds next_update) const
200  {
201  std::vector<CRL_Entry> empty;
202  return make_crl(empty, 1, rng, issue_time, next_update);
203  }
204 
206  const std::vector<CRL_Entry>& new_revoked,
208  std::chrono::system_clock::time_point issue_time,
209  std::chrono::seconds next_update) const
210  {
211  std::vector<CRL_Entry> revoked = last_crl.get_revoked();
212 
213  std::copy(new_revoked.begin(), new_revoked.end(),
214  std::back_inserter(revoked));
215 
216  return make_crl(revoked, last_crl.crl_number() + 1, rng, issue_time, next_update);
217  }
218 
219 /*
220 * Create a CRL
221 */
222 X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
223  uint32_t crl_number,
225  std::chrono::system_clock::time_point issue_time,
226  std::chrono::seconds next_update) const
227  {
228  const size_t X509_CRL_VERSION = 2;
229 
230  auto expire_time = issue_time + next_update;
231 
232  Extensions extensions;
233  extensions.add(new Cert_Extension::Authority_Key_ID(m_ca_cert.subject_key_id()));
234  extensions.add(new Cert_Extension::CRL_Number(crl_number));
235 
236  // clang-format off
237  const std::vector<uint8_t> crl = X509_Object::make_signed(
238  m_signer.get(), rng, m_ca_sig_algo,
240  .encode(X509_CRL_VERSION-1)
241  .encode(m_ca_sig_algo)
242  .encode(m_ca_cert.subject_dn())
243  .encode(X509_Time(issue_time))
244  .encode(X509_Time(expire_time))
245  .encode_if(revoked.size() > 0,
246  DER_Encoder()
248  .encode_list(revoked)
249  .end_cons()
250  )
251  .start_explicit(0)
252  .start_cons(SEQUENCE)
253  .encode(extensions)
254  .end_cons()
255  .end_explicit()
256  .end_cons()
257  .get_contents());
258  // clang-format on
259 
260  return X509_CRL(crl);
261  }
262 
263 /*
264 * Return the CA's certificate
265 */
267  {
268  return m_ca_cert;
269  }
270 
271 /*
272 * Choose a signing format for the key
273 */
274 
277  const std::string& hash_fn,
278  AlgorithmIdentifier& sig_algo)
279  {
280  return choose_sig_format(key, std::map<std::string,std::string>(),
281  rng, hash_fn, sig_algo);
282  }
283 
284 /*
285 * Choose a signing format for the key
286 */
288  const std::map<std::string,std::string>& opts,
290  const std::string& hash_fn,
291  AlgorithmIdentifier& sig_algo)
292  {
293  const std::string algo_name = key.algo_name();
294 
295  std::unique_ptr<HashFunction> hash(HashFunction::create_or_throw(hash_fn));
296  std::string hash_name = hash->name();
297 
298  // check algo_name and set default
299  std::string padding;
300  if(algo_name == "RSA")
301  {
302  // set to EMSA3 for compatibility reasons, originally it was the only option
303  padding = "EMSA3(" + hash_name + ")";
304  }
305  else if(algo_name == "DSA" ||
306  algo_name == "ECDSA" ||
307  algo_name == "ECGDSA" ||
308  algo_name == "ECKCDSA" ||
309  algo_name == "GOST-34.10")
310  {
311  padding = "EMSA1(" + hash_name + ")";
312  }
313  else
314  {
315  throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
316  }
317 
318  if(opts.count("padding") > 0 && !opts.at("padding").empty())
319  {
320  padding = opts.at("padding");
321  }
322 
323  // try to construct an EMSA object from the padding options or default
324  std::unique_ptr<EMSA> emsa = nullptr;
325  try
326  {
327  emsa.reset(get_emsa(padding));
328  }
329  /*
330  * get_emsa will throw if opts contains {"padding",<valid_padding>} but
331  * <valid_padding> does not specify a hash function.
332  * Omitting it is valid since it needs to be identical to hash_fn.
333  * If it still throws, something happened that we cannot repair here,
334  * e.g. the algorithm/padding combination is not supported.
335  */
336  catch(...)
337  {
338  emsa.reset(get_emsa(padding + "(" + hash_fn + ")"));
339  }
340  if(emsa == nullptr)
341  {
342  throw Invalid_Argument("Could not parse padding scheme " + padding);
343  }
344 
345  const Signature_Format format = (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
346 
347  sig_algo = emsa->config_for_x509(key, hash_name);
348 
349  return new PK_Signer(key, rng, emsa->name(), format);
350  }
351 
352 }
DER_Encoder & encode_list(const std::vector< T > &values)
Definition: der_enc.h:96
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:78
const AlternativeName & subject_alt_name() const
Definition: pkcs10.cpp:192
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:125
const AlgorithmIdentifier & signature_algorithm() const
Definition: x509_obj.h:47
static std::unique_ptr< HashFunction > create_or_throw(const std::string &algo_spec, const std::string &provider="")
Definition: hash.cpp:345
const std::vector< uint8_t > & raw_public_key() const
Definition: pkcs10.cpp:175
size_t path_limit() const
Definition: pkcs10.cpp:247
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:271
X509_Certificate ca_certificate() const
Definition: x509_ca.cpp:266
Signature_Format
Definition: pubkey.h:27
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:205
void replace(Certificate_Extension *extn, bool critical=false)
Definition: x509_ext.cpp:134
virtual std::string algo_name() const =0
DER_Encoder & end_cons()
Definition: der_enc.cpp:146
const std::vector< uint8_t > & subject_key_id() const
Definition: x509cert.cpp:394
const Extensions & extensions() const
Definition: pkcs10.cpp:200
bool is_CA_cert() const
Definition: x509cert.cpp:430
void add(Certificate_Extension *extn, bool critical=false)
Definition: x509_ext.cpp:122
X509_CA(const X509_Certificate &ca_certificate, const Private_Key &key, const std::string &hash_fn, RandomNumberGenerator &rng)
Definition: x509_ca.cpp:29
DER_Encoder & encode(bool b)
Definition: der_enc.cpp:202
virtual std::string name() const =0
std::string encode(const uint8_t der[], size_t length, const std::string &label, size_t width)
Definition: pem.cpp:43
const X509_DN & subject_dn() const
Definition: x509cert.cpp:415
X509_CRL new_crl(RandomNumberGenerator &rng, std::chrono::system_clock::time_point issue_time, std::chrono::seconds next_update) const
Definition: x509_ca.cpp:197
bool is_CA() const
Definition: pkcs10.cpp:234
Key_Constraints constraints() const
Definition: pkcs10.cpp:208
Definition: alg_id.cpp:13
void verify_cert_constraints_valid_for_key_type(const Public_Key &pub_key, Key_Constraints constraints)
PK_Signer * choose_sig_format(const Private_Key &key, RandomNumberGenerator &rng, const std::string &hash_fn, AlgorithmIdentifier &sig_algo)
Definition: x509_ca.cpp:275
const X509_DN & subject_dn() const
Definition: pkcs10.cpp:167
DER_Encoder & start_cons(ASN1_Tag type_tag, ASN1_Tag class_tag=UNIVERSAL)
Definition: der_enc.cpp:136
uint32_t crl_number() const
Definition: x509_crl.cpp:241
EMSA * get_emsa(const std::string &algo_spec)
Definition: emsa.cpp:44
Public_Key * subject_public_key() const
Definition: pkcs10.cpp:183
const std::vector< CRL_Entry > & get_revoked() const
Definition: x509_crl.cpp:217
std::string lookup(const OID &oid)
Definition: oids.cpp:18
MechanismType hash
virtual size_t message_parts() const
Definition: pk_keys.h:107
std::vector< OID > ex_constraints() const
Definition: pkcs10.cpp:221