aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/x509/x509_ca.cpp
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2016-11-03 10:30:13 -0400
committerJack Lloyd <[email protected]>2016-11-03 10:30:13 -0400
commit341fd32b46363cad4c2caee3fca166695100ba07 (patch)
tree89a98aa28a431f2625268cf61e7adf903fd24a98 /src/lib/x509/x509_ca.cpp
parent1e72720661383466807ac496b941af41d756a2ce (diff)
Move cert/x509 to top level and pem and pbes2 to pubkey.
The `cert` dir was just an artifact of having previously supported CVC (smartcard cert format), removed a long time ago. The pem and pbes2 code is directly related to the pubkey code, in fact the only caller of pbes2 (likely anywhere, not just in the library) is in pkcs8.cpp
Diffstat (limited to 'src/lib/x509/x509_ca.cpp')
-rw-r--r--src/lib/x509/x509_ca.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/lib/x509/x509_ca.cpp b/src/lib/x509/x509_ca.cpp
new file mode 100644
index 000000000..179d903c4
--- /dev/null
+++ b/src/lib/x509/x509_ca.cpp
@@ -0,0 +1,266 @@
+/*
+* X.509 Certificate Authority
+* (C) 1999-2010 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#include <botan/x509_ca.h>
+#include <botan/pubkey.h>
+#include <botan/der_enc.h>
+#include <botan/ber_dec.h>
+#include <botan/bigint.h>
+#include <botan/parsing.h>
+#include <botan/oids.h>
+#include <botan/hash.h>
+#include <botan/key_constraint.h>
+#include <algorithm>
+#include <typeinfo>
+#include <iterator>
+#include <set>
+
+namespace Botan {
+
+/*
+* Load the certificate and private key
+*/
+X509_CA::X509_CA(const X509_Certificate& c,
+ const Private_Key& key,
+ const std::string& hash_fn,
+ RandomNumberGenerator& rng) : m_cert(c)
+ {
+ if(!m_cert.is_CA_cert())
+ throw Invalid_Argument("X509_CA: This certificate is not for a CA");
+
+ m_signer = choose_sig_format(key, rng, hash_fn, m_ca_sig_algo);
+ }
+
+/*
+* X509_CA Destructor
+*/
+X509_CA::~X509_CA()
+ {
+ delete m_signer;
+ }
+
+/*
+* Sign a PKCS #10 certificate request
+*/
+X509_Certificate X509_CA::sign_request(const PKCS10_Request& req,
+ RandomNumberGenerator& rng,
+ const X509_Time& not_before,
+ const X509_Time& not_after)
+ {
+ Key_Constraints constraints;
+ if(req.is_CA())
+ {
+ constraints = Key_Constraints(KEY_CERT_SIGN | CRL_SIGN);
+ }
+ else
+ {
+ std::unique_ptr<Public_Key> key(req.subject_public_key());
+ verify_cert_constraints_valid_for_key_type(*key, req.constraints());
+ constraints = req.constraints();
+ }
+
+ Extensions extensions;
+
+ extensions.add(
+ new Cert_Extension::Basic_Constraints(req.is_CA(), req.path_limit()),
+ true);
+
+ if(constraints != NO_CONSTRAINTS)
+ {
+ extensions.add(new Cert_Extension::Key_Usage(constraints), true);
+ }
+
+ extensions.add(new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id()));
+ extensions.add(new Cert_Extension::Subject_Key_ID(req.raw_public_key()));
+
+ extensions.add(
+ new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name()));
+
+ extensions.add(
+ new Cert_Extension::Extended_Key_Usage(req.ex_constraints()));
+
+ return make_cert(m_signer, rng, m_ca_sig_algo,
+ req.raw_public_key(),
+ not_before, not_after,
+ m_cert.subject_dn(), req.subject_dn(),
+ extensions);
+ }
+
+/*
+* Create a new certificate
+*/
+X509_Certificate X509_CA::make_cert(PK_Signer* signer,
+ RandomNumberGenerator& rng,
+ const AlgorithmIdentifier& sig_algo,
+ const std::vector<byte>& 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)
+ {
+ const size_t X509_CERT_VERSION = 3;
+ const size_t SERIAL_BITS = 128;
+
+ BigInt serial_no(rng, SERIAL_BITS);
+
+ // clang-format off
+ return X509_Certificate(X509_Object::make_signed(
+ signer, rng, sig_algo,
+ DER_Encoder().start_cons(SEQUENCE)
+ .start_explicit(0)
+ .encode(X509_CERT_VERSION-1)
+ .end_explicit()
+
+ .encode(serial_no)
+
+ .encode(sig_algo)
+ .encode(issuer_dn)
+
+ .start_cons(SEQUENCE)
+ .encode(not_before)
+ .encode(not_after)
+ .end_cons()
+
+ .encode(subject_dn)
+ .raw_bytes(pub_key)
+
+ .start_explicit(3)
+ .start_cons(SEQUENCE)
+ .encode(extensions)
+ .end_cons()
+ .end_explicit()
+ .end_cons()
+ .get_contents()
+ ));;
+ // clang-format on
+ }
+
+/*
+* Create a new, empty CRL
+*/
+X509_CRL X509_CA::new_crl(RandomNumberGenerator& rng,
+ u32bit next_update) const
+ {
+ std::vector<CRL_Entry> empty;
+ return make_crl(empty, 1, next_update, rng);
+ }
+
+/*
+* Update a CRL with new entries
+*/
+X509_CRL X509_CA::update_crl(const X509_CRL& crl,
+ const std::vector<CRL_Entry>& new_revoked,
+ RandomNumberGenerator& rng,
+ u32bit next_update) const
+ {
+ std::vector<CRL_Entry> revoked = crl.get_revoked();
+
+ std::copy(new_revoked.begin(), new_revoked.end(),
+ std::back_inserter(revoked));
+
+ return make_crl(revoked, crl.crl_number() + 1, next_update, rng);
+ }
+
+/*
+* Create a CRL
+*/
+X509_CRL X509_CA::make_crl(const std::vector<CRL_Entry>& revoked,
+ u32bit crl_number, u32bit next_update,
+ RandomNumberGenerator& rng) const
+ {
+ const size_t X509_CRL_VERSION = 2;
+
+ if(next_update == 0)
+ next_update = timespec_to_u32bit("7d");
+
+ // Totally stupid: ties encoding logic to the return of std::time!!
+ auto current_time = std::chrono::system_clock::now();
+ auto expire_time = current_time + std::chrono::seconds(next_update);
+
+ Extensions extensions;
+ extensions.add(
+ new Cert_Extension::Authority_Key_ID(m_cert.subject_key_id()));
+ extensions.add(new Cert_Extension::CRL_Number(crl_number));
+
+ // clang-format off
+ const std::vector<byte> crl = X509_Object::make_signed(
+ m_signer, rng, m_ca_sig_algo,
+ DER_Encoder().start_cons(SEQUENCE)
+ .encode(X509_CRL_VERSION-1)
+ .encode(m_ca_sig_algo)
+ .encode(m_cert.issuer_dn())
+ .encode(X509_Time(current_time))
+ .encode(X509_Time(expire_time))
+ .encode_if(revoked.size() > 0,
+ DER_Encoder()
+ .start_cons(SEQUENCE)
+ .encode_list(revoked)
+ .end_cons()
+ )
+ .start_explicit(0)
+ .start_cons(SEQUENCE)
+ .encode(extensions)
+ .end_cons()
+ .end_explicit()
+ .end_cons()
+ .get_contents());
+ // clang-format on
+
+ return X509_CRL(crl);
+ }
+
+/*
+* Return the CA's certificate
+*/
+X509_Certificate X509_CA::ca_certificate() const
+ {
+ return m_cert;
+ }
+
+/*
+* Choose a signing format for the key
+*/
+PK_Signer* choose_sig_format(const Private_Key& key,
+ RandomNumberGenerator& rng,
+ const std::string& hash_fn,
+ AlgorithmIdentifier& sig_algo)
+ {
+ const std::string algo_name = key.algo_name();
+
+ std::unique_ptr<HashFunction> hash(HashFunction::create(hash_fn));
+ if(!hash)
+ throw Algorithm_Not_Found(hash_fn);
+
+ if(key.max_input_bits() < hash->output_length() * 8)
+ throw Invalid_Argument("Key is too small for chosen hash function");
+
+ std::string padding;
+ if(algo_name == "RSA")
+ {
+ padding = "EMSA3";
+ }
+ else if(algo_name == "DSA" || algo_name == "ECDSA" || algo_name == "ECGDSA" || algo_name == "ECKCDSA")
+ {
+ padding = "EMSA1";
+ }
+ else
+ {
+ throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name);
+ }
+
+ const Signature_Format format = (key.message_parts() > 1) ? DER_SEQUENCE : IEEE_1363;
+
+ padding = padding + "(" + hash->name() + ")";
+
+ sig_algo.oid = OIDS::lookup(algo_name + "/" + padding);
+ sig_algo.parameters = key.algorithm_identifier().parameters;
+
+ return new PK_Signer(key, rng, padding, format);
+ }
+
+}