Botan  1.11.4
x509_ca.cpp
Go to the documentation of this file.
1 /*
2 * X.509 Certificate Authority
3 * (C) 1999-2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/x509_ca.h>
9 #include <botan/pubkey.h>
10 #include <botan/der_enc.h>
11 #include <botan/ber_dec.h>
12 #include <botan/bigint.h>
13 #include <botan/parsing.h>
14 #include <botan/lookup.h>
15 #include <botan/oids.h>
16 #include <botan/key_constraint.h>
17 #include <algorithm>
18 #include <typeinfo>
19 #include <iterator>
20 #include <memory>
21 #include <set>
22 
23 namespace Botan {
24 
25 /*
26 * Load the certificate and private key
27 */
29  const Private_Key& key,
30  const std::string& hash_fn) : cert(c)
31  {
32  if(!cert.is_CA_cert())
33  throw Invalid_Argument("X509_CA: This certificate is not for a CA");
34 
35  signer = choose_sig_format(key, hash_fn, ca_sig_algo);
36  }
37 
38 /*
39 * X509_CA Destructor
40 */
42  {
43  delete signer;
44  }
45 
46 /*
47 * Sign a PKCS #10 certificate request
48 */
51  const X509_Time& not_before,
52  const X509_Time& not_after)
53  {
54  Key_Constraints constraints;
55  if(req.is_CA())
56  constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
57  else
58  {
59  std::unique_ptr<Public_Key> key(req.subject_public_key());
60  constraints = find_constraints(*key, req.constraints());
61  }
62 
63  Extensions extensions;
64 
65  extensions.add(
67  true);
68 
69  extensions.add(new Cert_Extension::Key_Usage(constraints), true);
70 
71  extensions.add(new Cert_Extension::Authority_Key_ID(cert.subject_key_id()));
72  extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));
73 
74  extensions.add(
76 
77  extensions.add(
79 
80  return make_cert(signer, rng, ca_sig_algo,
81  req.raw_public_key(),
82  not_before, not_after,
83  cert.subject_dn(), req.subject_dn(),
84  extensions);
85  }
86 
87 /*
88 * Create a new certificate
89 */
92  const AlgorithmIdentifier& sig_algo,
93  const std::vector<byte>& pub_key,
94  const X509_Time& not_before,
95  const X509_Time& not_after,
96  const X509_DN& issuer_dn,
97  const X509_DN& subject_dn,
98  const Extensions& extensions)
99  {
100  const size_t X509_CERT_VERSION = 3;
101  const size_t SERIAL_BITS = 128;
102 
103  BigInt serial_no(rng, SERIAL_BITS);
104 
105  const std::vector<byte> cert = X509_Object::make_signed(
106  signer, rng, sig_algo,
107  DER_Encoder().start_cons(SEQUENCE)
108  .start_explicit(0)
109  .encode(X509_CERT_VERSION-1)
110  .end_explicit()
111 
112  .encode(serial_no)
113 
114  .encode(sig_algo)
115  .encode(issuer_dn)
116 
117  .start_cons(SEQUENCE)
118  .encode(not_before)
119  .encode(not_after)
120  .end_cons()
121 
122  .encode(subject_dn)
123  .raw_bytes(pub_key)
124 
125  .start_explicit(3)
126  .start_cons(SEQUENCE)
127  .encode(extensions)
128  .end_cons()
129  .end_explicit()
130  .end_cons()
131  .get_contents());
132 
133  return X509_Certificate(cert);
134  }
135 
136 /*
137 * Create a new, empty CRL
138 */
140  u32bit next_update) const
141  {
142  std::vector<CRL_Entry> empty;
143  return make_crl(empty, 1, next_update, rng);
144  }
145 
146 /*
147 * Update a CRL with new entries
148 */
150  const std::vector<CRL_Entry>& new_revoked,
152  u32bit next_update) const
153  {
154  std::vector<CRL_Entry> revoked = crl.get_revoked();
155 
156  std::copy(new_revoked.begin(), new_revoked.end(),
157  std::back_inserter(revoked));
158 
159  return make_crl(revoked, crl.crl_number() + 1, next_update, rng);
160  }
161 
162 /*
163 * Create a CRL
164 */
165 X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
166  u32bit crl_number, u32bit next_update,
167  RandomNumberGenerator& rng) const
168  {
169  const size_t X509_CRL_VERSION = 2;
170 
171  if(next_update == 0)
172  next_update = timespec_to_u32bit("7d");
173 
174  // Totally stupid: ties encoding logic to the return of std::time!!
175  auto current_time = std::chrono::system_clock::now();
176  auto expire_time = current_time + std::chrono::seconds(next_update);
177 
178  Extensions extensions;
179  extensions.add(
181  extensions.add(new Cert_Extension::CRL_Number(crl_number));
182 
183  const std::vector<byte> crl = X509_Object::make_signed(
184  signer, rng, ca_sig_algo,
185  DER_Encoder().start_cons(SEQUENCE)
186  .encode(X509_CRL_VERSION-1)
187  .encode(ca_sig_algo)
188  .encode(cert.issuer_dn())
189  .encode(X509_Time(current_time))
190  .encode(X509_Time(expire_time))
191  .encode_if(revoked.size() > 0,
192  DER_Encoder()
194  .encode_list(revoked)
195  .end_cons()
196  )
197  .start_explicit(0)
198  .start_cons(SEQUENCE)
199  .encode(extensions)
200  .end_cons()
201  .end_explicit()
202  .end_cons()
203  .get_contents());
204 
205  return X509_CRL(crl);
206  }
207 
208 /*
209 * Return the CA's certificate
210 */
212  {
213  return cert;
214  }
215 
216 /*
217 * Choose a signing format for the key
218 */
220  const std::string& hash_fn,
221  AlgorithmIdentifier& sig_algo)
222  {
223  std::string padding;
224 
225  const std::string algo_name = key.algo_name();
226 
227  const HashFunction* proto_hash = retrieve_hash(hash_fn);
228  if(!proto_hash)
229  throw Algorithm_Not_Found(hash_fn);
230 
231  if(key.max_input_bits() < proto_hash->output_length()*8)
232  throw Invalid_Argument("Key is too small for chosen hash function");
233 
234  if(algo_name == "RSA")
235  padding = "EMSA3";
236  else if(algo_name == "DSA")
237  padding = "EMSA1";
238  else if(algo_name == "ECDSA")
239  padding = "EMSA1_BSI";
240  else
241  throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
242 
243  Signature_Format format =
244  (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
245 
246  padding = padding + '(' + proto_hash->name() + ')';
247 
248  sig_algo.oid = OIDS::lookup(algo_name + "/" + padding);
249  sig_algo.parameters = key.algorithm_identifier().parameters;
250 
251  return new PK_Signer(key, padding, format);
252  }
253 
254 }