diff options
author | lloyd <[email protected]> | 2009-11-09 13:22:52 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2009-11-09 13:22:52 +0000 |
commit | 4049ba134674d78c07c8b0453cb5e5f312469639 (patch) | |
tree | b9214ede8da1600a46560fe061017fa124b2b465 | |
parent | b5d4cf01a893718c8796652f3cf0f68b867bab94 (diff) |
In creating X.509 certificates and PKCS #10 requests, let (actually: require)
the user to specify the hash function to use, instead of always using SHA-1.
This was a sensible default a few years ago, when there wasn't a ~2^60 attack
on SHA-1 and support for SHA-2 was pretty much nil, but using something else
makes a lot more sense these days.
-rw-r--r-- | checks/x509.cpp | 10 | ||||
-rw-r--r-- | doc/examples/ca.cpp | 2 | ||||
-rw-r--r-- | doc/examples/gen_certs.cpp | 6 | ||||
-rw-r--r-- | doc/examples/pkcs10.cpp | 2 | ||||
-rw-r--r-- | doc/examples/self_sig.cpp | 3 | ||||
-rw-r--r-- | doc/log.txt | 1 | ||||
-rw-r--r-- | src/cert/x509/x509_ca.cpp | 52 | ||||
-rw-r--r-- | src/cert/x509/x509_ca.h | 44 | ||||
-rw-r--r-- | src/cert/x509/x509self.cpp | 6 | ||||
-rw-r--r-- | src/cert/x509/x509self.h | 4 |
10 files changed, 91 insertions, 39 deletions
diff --git a/checks/x509.cpp b/checks/x509.cpp index 6f191285c..69dd29492 100644 --- a/checks/x509.cpp +++ b/checks/x509.cpp @@ -129,6 +129,8 @@ void do_x509_tests(RandomNumberGenerator& rng) { std::cout << "Testing X.509 CA/CRL/cert/cert request: " << std::flush; + std::string hash_fn = "SHA-256"; + /* Create the CA's key and self-signed cert */ std::cout << '.' << std::flush; RSA_PrivateKey ca_key(rng, 1024); @@ -136,6 +138,7 @@ void do_x509_tests(RandomNumberGenerator& rng) std::cout << '.' << std::flush; X509_Certificate ca_cert = X509::create_self_signed_cert(ca_opts(), ca_key, + hash_fn, rng); std::cout << '.' << std::flush; @@ -146,12 +149,14 @@ void do_x509_tests(RandomNumberGenerator& rng) std::cout << '.' << std::flush; PKCS10_Request user1_req = X509::create_cert_req(req_opts1(), user1_key, + "SHA-1", rng); /* Create user #2's key and cert request */ std::cout << '.' << std::flush; #if defined(BOTAN_HAS_ECDSA) - ECDSA_PrivateKey user2_key(rng, get_EC_Dom_Pars_by_oid("1.3.132.0.8")); + EC_Domain_Params ecc_domain = get_EC_Dom_Pars_by_oid("1.2.840.10045.3.1.7"); + ECDSA_PrivateKey user2_key(rng, ecc_domain); #else RSA_PrivateKey user2_key(rng, 1024); #endif @@ -159,11 +164,12 @@ void do_x509_tests(RandomNumberGenerator& rng) std::cout << '.' << std::flush; PKCS10_Request user2_req = X509::create_cert_req(req_opts2(), user2_key, + hash_fn, rng); /* Create the CA object */ std::cout << '.' << std::flush; - X509_CA ca(ca_cert, ca_key); + X509_CA ca(ca_cert, ca_key, hash_fn); std::cout << '.' << std::flush; /* Sign the requests to create the certs */ diff --git a/doc/examples/ca.cpp b/doc/examples/ca.cpp index 41dd409d5..9195be418 100644 --- a/doc/examples/ca.cpp +++ b/doc/examples/ca.cpp @@ -47,7 +47,7 @@ int main(int argc, char* argv[]) PKCS8::load_key(arg_ca_key, rng, arg_passphrase) ); - X509_CA ca(ca_cert, *privkey); + X509_CA ca(ca_cert, *privkey, "SHA-256"); // got a request PKCS10_Request req(arg_req_file); diff --git a/doc/examples/gen_certs.cpp b/doc/examples/gen_certs.cpp index f635e1ccf..90cb80038 100644 --- a/doc/examples/gen_certs.cpp +++ b/doc/examples/gen_certs.cpp @@ -34,7 +34,7 @@ X509_Certificate make_ca_cert(RandomNumberGenerator& rng, opts.end = later; opts.CA_key(); - return X509::create_self_signed_cert(opts, priv_key, rng); + return X509::create_self_signed_cert(opts, priv_key, "SHA-256", rng); } PKCS10_Request make_server_cert_req(const Private_Key& key, @@ -47,7 +47,7 @@ PKCS10_Request make_server_cert_req(const Private_Key& key, opts.add_ex_constraint("PKIX.ServerAuth"); - return X509::create_cert_req(opts, key, rng); + return X509::create_cert_req(opts, key, "SHA-1", rng); } void save_pair(const std::string& name, @@ -92,7 +92,7 @@ int main() save_pair("ca", ca_password, ca_cert, ca_key, rng); - X509_CA ca(ca_cert, ca_key); + X509_CA ca(ca_cert, ca_key, "SHA-256"); RSA_PrivateKey httpd_key(rng, 1536); X509_Certificate httpd_cert = ca.sign_request( diff --git a/doc/examples/pkcs10.cpp b/doc/examples/pkcs10.cpp index d719baf72..d9fa9accb 100644 --- a/doc/examples/pkcs10.cpp +++ b/doc/examples/pkcs10.cpp @@ -59,7 +59,7 @@ int main(int argc, char* argv[]) opts.xmpp = "[email protected]"; - PKCS10_Request req = X509::create_cert_req(opts, priv_key, rng); + PKCS10_Request req = X509::create_cert_req(opts, priv_key, "SHA-1", rng); std::ofstream req_file("req.pem"); req_file << req.PEM_encode(); diff --git a/doc/examples/self_sig.cpp b/doc/examples/self_sig.cpp index 0bf17e3bc..93161f7d2 100644 --- a/doc/examples/self_sig.cpp +++ b/doc/examples/self_sig.cpp @@ -64,7 +64,8 @@ int main(int argc, char* argv[]) if(do_CA) opts.CA_key(); - X509_Certificate cert = X509::create_self_signed_cert(opts, key, rng); + X509_Certificate cert = + X509::create_self_signed_cert(opts, key, "SHA-256", rng); std::ofstream cert_file("cert.pem"); cert_file << cert.PEM_encode(); diff --git a/doc/log.txt b/doc/log.txt index 75fde9a5f..f1c58be71 100644 --- a/doc/log.txt +++ b/doc/log.txt @@ -1,5 +1,6 @@ * 1.9.3-dev, ????-??-?? + - Allow use of any hash function in X.509 certificate creation - Set macros for available SIMD instructions in build.h * 1.9.2, 2009-11-03 diff --git a/src/cert/x509/x509_ca.cpp b/src/cert/x509/x509_ca.cpp index f0eb9c3e5..48ec0bd1c 100644 --- a/src/cert/x509/x509_ca.cpp +++ b/src/cert/x509/x509_ca.cpp @@ -9,9 +9,10 @@ #include <botan/x509stor.h> #include <botan/der_enc.h> #include <botan/ber_dec.h> -#include <botan/look_pk.h> #include <botan/bigint.h> #include <botan/parsing.h> +#include <botan/lookup.h> +#include <botan/look_pk.h> #include <botan/oids.h> #include <botan/timer.h> #include <algorithm> @@ -20,22 +21,33 @@ #include <memory> #include <set> +#include <stdio.h> + namespace Botan { /* * Load the certificate and private key */ X509_CA::X509_CA(const X509_Certificate& c, - const Private_Key& key) : cert(c) + const Private_Key& key, + const std::string& hash_fn) : cert(c) { - const Private_Key* key_pointer = &key; - if(!dynamic_cast<const PK_Signing_Key*>(key_pointer)) + // Use pointer dynamic_cast to avoid exception if cast fails + if(!dynamic_cast<const PK_Signing_Key*>(&key)) throw Invalid_Argument("X509_CA: " + key.algo_name() + " cannot sign"); if(!cert.is_CA_cert()) throw Invalid_Argument("X509_CA: This certificate is not for a CA"); - signer = choose_sig_format(key, ca_sig_algo); + signer = choose_sig_format(key, hash_fn, ca_sig_algo); + } + +/* +* X509_CA Destructor +*/ +X509_CA::~X509_CA() + { + delete signer; } /* @@ -70,7 +82,8 @@ X509_Certificate X509_CA::sign_request(const PKCS10_Request& req, extensions.add( new Cert_Extension::Subject_Alternative_Name(req.subject_alt_name())); - return make_cert(signer, rng, ca_sig_algo, req.raw_public_key(), + return make_cert(signer, rng, ca_sig_algo, + req.raw_public_key(), not_before, not_after, cert.subject_dn(), req.subject_dn(), extensions); @@ -231,17 +244,10 @@ X509_Certificate X509_CA::ca_certificate() const } /* -* X509_CA Destructor -*/ -X509_CA::~X509_CA() - { - delete signer; - } - -/* * Choose a signing format for the key */ PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, AlgorithmIdentifier& sig_algo) { std::string padding; @@ -249,24 +255,36 @@ PK_Signer* choose_sig_format(const Private_Key& key, const std::string algo_name = key.algo_name(); + const HashFunction* proto_hash = retrieve_hash(hash_fn); + if(!proto_hash) + throw Algorithm_Not_Found(hash_fn); + + if(key.max_input_bits() < proto_hash->OUTPUT_LENGTH*8) + { + printf("%d %d\n", key.max_input_bits(), proto_hash->OUTPUT_LENGTH*8); + throw Invalid_Argument("Key is too small for chosen hash function"); + } + if(algo_name == "RSA") { - padding = "EMSA3(SHA-160)"; + padding = "EMSA3"; format = IEEE_1363; } else if(algo_name == "DSA") { - padding = "EMSA1(SHA-160)"; + padding = "EMSA1"; format = DER_SEQUENCE; } else if(algo_name == "ECDSA") { - padding = "EMSA1_BSI(SHA-160)"; + padding = "EMSA1_BSI"; format = IEEE_1363; } else throw Invalid_Argument("Unknown X.509 signing key type: " + algo_name); + padding = padding + '(' + proto_hash->name() + ')'; + sig_algo.oid = OIDS::lookup(algo_name + "/" + padding); std::auto_ptr<X509_Encoder> encoding(key.x509_encoder()); diff --git a/src/cert/x509/x509_ca.h b/src/cert/x509/x509_ca.h index ef2a8d134..6eb4bbbef 100644 --- a/src/cert/x509/x509_ca.h +++ b/src/cert/x509/x509_ca.h @@ -50,7 +50,8 @@ class BOTAN_DLL X509_CA * as the offset from the current time * @return the new CRL */ - X509_CRL new_crl(RandomNumberGenerator& rng, u32bit = 0) const; + X509_CRL new_crl(RandomNumberGenerator& rng, + u32bit next_update = 0) const; /** * Create a new CRL by with additional entries. @@ -65,27 +66,45 @@ class BOTAN_DLL X509_CA RandomNumberGenerator& rng, u32bit next_update = 0) const; - static X509_Certificate make_cert(PK_Signer*, - RandomNumberGenerator&, - const AlgorithmIdentifier&, - const MemoryRegion<byte>&, - const X509_Time&, const X509_Time&, - const X509_DN&, const X509_DN&, - const Extensions&); + /** + * Interface for creating new certificates + * @param signer a signing object + * @param rng a random number generator + * @param sig_algo the signature algorithm identifier + * @param not_before the start time of the certificate + * @param not_after the end time of the certificate + * @param issuer_dn the DN of the issuer + * @param subject_dn the DN of the subject + * @param extensions an optional list of certificate extensions + * @returns newly minted certificate + */ + static X509_Certificate make_cert(PK_Signer* signer, + RandomNumberGenerator& rng, + const AlgorithmIdentifier& sig_algo, + const MemoryRegion<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); /** * Create a new CA object. * @param ca_certificate the certificate of the CA * @param key the private key of the CA */ - X509_CA(const X509_Certificate& ca_certificate, const Private_Key& key); + X509_CA(const X509_Certificate& ca_certificate, + const Private_Key& key, + const std::string& hash_fn); + ~X509_CA(); private: X509_CA(const X509_CA&) {} X509_CA& operator=(const X509_CA&) { return (*this); } - X509_CRL make_crl(const std::vector<CRL_Entry>&, - u32bit, u32bit, RandomNumberGenerator&) const; + X509_CRL make_crl(const std::vector<CRL_Entry>& entries, + u32bit crl_number, u32bit next_update, + RandomNumberGenerator& rng) const; AlgorithmIdentifier ca_sig_algo; X509_Certificate cert; @@ -96,13 +115,14 @@ class BOTAN_DLL X509_CA * Choose the default signature format for a certain public key signature * scheme. * @param key will be the key to choose a padding scheme for +* @param hash_fn is the desired hash function * @param alg_id will be set to the chosen scheme * @return A PK_Signer object for generating signatures */ BOTAN_DLL PK_Signer* choose_sig_format(const Private_Key& key, + const std::string& hash_fn, AlgorithmIdentifier& alg_id); - } #endif diff --git a/src/cert/x509/x509self.cpp b/src/cert/x509/x509self.cpp index 8afb22a7e..f915c6ff5 100644 --- a/src/cert/x509/x509self.cpp +++ b/src/cert/x509/x509self.cpp @@ -65,6 +65,7 @@ namespace X509 { */ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng) { AlgorithmIdentifier sig_algo; @@ -72,7 +73,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, AlternativeName subject_alt; MemoryVector<byte> pub_key = shared_setup(opts, key); - std::auto_ptr<PK_Signer> signer(choose_sig_format(key, sig_algo)); + std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo)); load_info(opts, subject_dn, subject_alt); Key_Constraints constraints; @@ -103,6 +104,7 @@ X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, */ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng) { AlgorithmIdentifier sig_algo; @@ -110,7 +112,7 @@ PKCS10_Request create_cert_req(const X509_Cert_Options& opts, AlternativeName subject_alt; MemoryVector<byte> pub_key = shared_setup(opts, key); - std::auto_ptr<PK_Signer> signer(choose_sig_format(key, sig_algo)); + std::auto_ptr<PK_Signer> signer(choose_sig_format(key, hash_fn, sig_algo)); load_info(opts, subject_dn, subject_alt); const u32bit PKCS10_VERSION = 0; diff --git a/src/cert/x509/x509self.h b/src/cert/x509/x509self.h index bd3e29179..741350067 100644 --- a/src/cert/x509/x509self.h +++ b/src/cert/x509/x509self.h @@ -172,12 +172,14 @@ namespace X509 { * @param opts the options defining the certificate to create * @param key the private key used for signing, i.e. the key * associated with this self-signed certificate +* @param hash_fn the hash function to use * @param rng the rng to use * @return the newly created self-signed certificate */ BOTAN_DLL X509_Certificate create_self_signed_cert(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng); /** @@ -185,10 +187,12 @@ create_self_signed_cert(const X509_Cert_Options& opts, * @param opts the options defining the request to create * @param key the key used to sign this request * @param rng the rng to use +* @param hash_fn the hash function to use * @return the newly created PKCS#10 request */ BOTAN_DLL PKCS10_Request create_cert_req(const X509_Cert_Options& opts, const Private_Key& key, + const std::string& hash_fn, RandomNumberGenerator& rng); } |