Botan  1.11.15
src/lib/cert/x509/x509_ca.cpp
Go to the documentation of this file.
00001 /*
00002 * X.509 Certificate Authority
00003 * (C) 1999-2010 Jack Lloyd
00004 *
00005 * Botan is released under the Simplified BSD License (see license.txt)
00006 */
00007 
00008 #include <botan/x509_ca.h>
00009 #include <botan/pubkey.h>
00010 #include <botan/der_enc.h>
00011 #include <botan/ber_dec.h>
00012 #include <botan/bigint.h>
00013 #include <botan/parsing.h>
00014 #include <botan/lookup.h>
00015 #include <botan/oids.h>
00016 #include <botan/hash.h>
00017 #include <botan/key_constraint.h>
00018 #include <algorithm>
00019 #include <typeinfo>
00020 #include <iterator>
00021 #include <set>
00022 
00023 namespace Botan {
00024 
00025 /*
00026 * Load the certificate and private key
00027 */
00028 X509_CA::X509_CA(const X509_Certificate& c,
00029                  const Private_Key& key,
00030                  const std::string& hash_fn) : cert(c)
00031    {
00032    if(!cert.is_CA_cert())
00033       throw Invalid_Argument("X509_CA: This certificate is not for a CA");
00034 
00035    signer = choose_sig_format(key, hash_fn, ca_sig_algo);
00036    }
00037 
00038 /*
00039 * X509_CA Destructor
00040 */
00041 X509_CA::~X509_CA()
00042    {
00043    delete signer;
00044    }
00045 
00046 /*
00047 * Sign a PKCS #10 certificate request
00048 */
00049 X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
00050                                        RandomNumberGenerator& rng,
00051                                        const X509_Time& not_before,
00052                                        const X509_Time& not_after)
00053    {
00054    Key_Constraints constraints;
00055    if(req.is_CA())
00056       constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
00057    else
00058       {
00059       std::unique_ptr<Public_Key> key(req.subject_public_key());
00060       constraints = find_constraints(*key, req.constraints());
00061       }
00062 
00063    Extensions extensions;
00064 
00065    extensions.add(
00066       new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
00067       true);
00068 
00069    extensions.add(new Cert_Extension::Key_Usage(constraints), true);
00070 
00071    extensions.add(new Cert_Extension::Authority_Key_ID(cert.subject_key_id()));
00072    extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));
00073 
00074    extensions.add(
00075       new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name()));
00076 
00077    extensions.add(
00078       new Cert_Extension::Extended_Key_Usage(req.ex_constraints()));
00079 
00080    return make_cert(signer, rng, ca_sig_algo,
00081                     req.raw_public_key(),
00082                     not_before, not_after,
00083                     cert.subject_dn(), req.subject_dn(),
00084                     extensions);
00085    }
00086 
00087 /*
00088 * Create a new certificate
00089 */
00090 X509_Certificate X509_CA::make_cert(PK_Signer* signer,
00091                                     RandomNumberGenerator& rng,
00092                                     const AlgorithmIdentifier& sig_algo,
00093                                     const std::vector<byte>& pub_key,
00094                                     const X509_Time& not_before,
00095                                     const X509_Time& not_after,
00096                                     const X509_DN& issuer_dn,
00097                                     const X509_DN& subject_dn,
00098                                     const Extensions& extensions)
00099    {
00100    const size_t X509_CERT_VERSION = 3;
00101    const size_t SERIAL_BITS = 128;
00102 
00103    BigInt serial_no(rng, SERIAL_BITS);
00104 
00105    return X509_Certificate(X509_Object::make_signed(
00106       signer, rng, sig_algo,
00107       DER_Encoder().start_cons(SEQUENCE)
00108          .start_explicit(0)
00109             .encode(X509_CERT_VERSION-1)
00110          .end_explicit()
00111 
00112          .encode(serial_no)
00113 
00114          .encode(sig_algo)
00115          .encode(issuer_dn)
00116 
00117          .start_cons(SEQUENCE)
00118             .encode(not_before)
00119             .encode(not_after)
00120          .end_cons()
00121 
00122          .encode(subject_dn)
00123          .raw_bytes(pub_key)
00124 
00125          .start_explicit(3)
00126             .start_cons(SEQUENCE)
00127                .encode(extensions)
00128              .end_cons()
00129          .end_explicit()
00130       .end_cons()
00131       .get_contents()
00132       ));;
00133    }
00134 
00135 /*
00136 * Create a new, empty CRL
00137 */
00138 X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng,
00139                           u32bit next_update) const
00140    {
00141    std::vector<CRL_Entry> empty;
00142    return make_crl(empty, 1, next_update, rng);
00143    }
00144 
00145 /*
00146 * Update a CRL with new entries
00147 */
00148 X509_CRL X509_CA::update_crl(const X509_CRL& crl,
00149                              const std::vector<CRL_Entry>& new_revoked,
00150                              RandomNumberGenerator& rng,
00151                              u32bit next_update) const
00152    {
00153    std::vector<CRL_Entry> revoked = crl.get_revoked();
00154 
00155    std::copy(new_revoked.begin(), new_revoked.end(),
00156              std::back_inserter(revoked));
00157 
00158    return make_crl(revoked, crl.crl_number() + 1, next_update, rng);
00159    }
00160 
00161 /*
00162 * Create a CRL
00163 */
00164 X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
00165                            u32bit crl_number, u32bit next_update,
00166                            RandomNumberGenerator& rng) const
00167    {
00168    const size_t X509_CRL_VERSION = 2;
00169 
00170    if(next_update == 0)
00171       next_update = timespec_to_u32bit("7d");
00172 
00173    // Totally stupid: ties encoding logic to the return of std::time!!
00174    auto current_time = std::chrono::system_clock::now();
00175    auto expire_time = current_time + std::chrono::seconds(next_update);
00176 
00177    Extensions extensions;
00178    extensions.add(
00179       new Cert_Extension::Authority_Key_ID(cert.subject_key_id()));
00180    extensions.add(new Cert_Extension::CRL_Number(crl_number));
00181 
00182    const std::vector<byte> crl = X509_Object::make_signed(
00183       signer, rng, ca_sig_algo,
00184       DER_Encoder().start_cons(SEQUENCE)
00185          .encode(X509_CRL_VERSION-1)
00186          .encode(ca_sig_algo)
00187          .encode(cert.issuer_dn())
00188          .encode(X509_Time(current_time))
00189          .encode(X509_Time(expire_time))
00190          .encode_if(revoked.size() > 0,
00191               DER_Encoder()
00192                  .start_cons(SEQUENCE)
00193                     .encode_list(revoked)
00194                  .end_cons()
00195             )
00196          .start_explicit(0)
00197             .start_cons(SEQUENCE)
00198                .encode(extensions)
00199             .end_cons()
00200          .end_explicit()
00201       .end_cons()
00202       .get_contents());
00203 
00204    return X509_CRL(crl);
00205    }
00206 
00207 /*
00208 * Return the CA's certificate
00209 */
00210 X509_Certificate X509_CA::ca_certificate() const
00211    {
00212    return cert;
00213    }
00214 
00215 /*
00216 * Choose a signing format for the key
00217 */
00218 PK_Signer* choose_sig_format(const Private_Key& key,
00219                              const std::string& hash_fn,
00220                              AlgorithmIdentifier& sig_algo)
00221    {
00222    const std::string algo_name = key.algo_name();
00223 
00224    std::unique_ptr<HashFunction> hash(get_hash(hash_fn));
00225    if(!hash)
00226       throw Algorithm_Not_Found(hash_fn);
00227 
00228    if(key.max_input_bits() < hash->output_length() * 8)
00229       throw Invalid_Argument("Key is too small for chosen hash function");
00230 
00231    std::string padding;
00232    if(algo_name == "RSA")
00233       padding = "EMSA3";
00234    else if(algo_name == "DSA")
00235       padding = "EMSA1";
00236    else if(algo_name == "ECDSA")
00237       padding = "EMSA1_BSI";
00238    else
00239       throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
00240 
00241    const Signature_Format format = (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
00242 
00243    padding = padding + '(' + hash->name() + ')';
00244 
00245    sig_algo.oid = OIDS::lookup(algo_name + "/" + padding);
00246    sig_algo.parameters = key.algorithm_identifier().parameters;
00247 
00248    return new PK_Signer(key, padding, format);
00249    }
00250 
00251 }