diff options
author | lloyd <[email protected]> | 2012-01-24 16:42:18 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-01-24 16:42:18 +0000 |
commit | e4eb73dca7d7a74ecf8ef792d65640c4e44e2ab1 (patch) | |
tree | 5e7cd62ff1fe191c0369a41617b43ebf77d20ef9 | |
parent | b8a8ba0428cd4235e1ac2ba8530e8f817a166773 (diff) |
We can now actually handle multiple certificate types in the server
and will choose one depending on which ciphersuites the client
offered.
-rw-r--r-- | doc/examples/credentials.h | 30 | ||||
-rw-r--r-- | src/credentials/credentials_manager.cpp | 24 | ||||
-rw-r--r-- | src/credentials/credentials_manager.h | 19 | ||||
-rw-r--r-- | src/tls/s_hello.cpp | 17 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 5 | ||||
-rw-r--r-- | src/tls/tls_messages.h | 6 | ||||
-rw-r--r-- | src/tls/tls_policy.cpp | 22 | ||||
-rw-r--r-- | src/tls/tls_policy.h | 3 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 48 |
9 files changed, 112 insertions, 62 deletions
diff --git a/doc/examples/credentials.h b/doc/examples/credentials.h index 802e3233c..3d70a092d 100644 --- a/doc/examples/credentials.h +++ b/doc/examples/credentials.h @@ -4,13 +4,22 @@ #include <botan/credentials_manager.h> +bool value_exists(const std::vector<std::string>& vec, + const std::string& val) + { + for(size_t i = 0; i != vec.size(); ++i) + if(vec[i] == val) + return true; + return false; + } + class Credentials_Manager_Simple : public Botan::Credentials_Manager { public: Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) : rng(rng) {} std::vector<Botan::X509_Certificate> cert_chain( - const std::string& cert_key_type, + const std::vector<std::string>& cert_key_types, const std::string& type, const std::string& context) { @@ -20,11 +29,22 @@ class Credentials_Manager_Simple : public Botan::Credentials_Manager { const std::string hostname = (context == "" ? "localhost" : context); - Botan::X509_Certificate cert(hostname + ".crt"); - Botan::Private_Key* key = Botan::PKCS8::load_key(hostname + ".key", rng); + if(value_exists(cert_key_types, "RSA")) + { + Botan::X509_Certificate cert(hostname + ".crt"); + Botan::Private_Key* key = Botan::PKCS8::load_key(hostname + ".key", rng); - certs_and_keys[cert] = key; - certs.push_back(cert); + certs_and_keys[cert] = key; + certs.push_back(cert); + } + else if(value_exists(cert_key_types, "DSA")) + { + Botan::X509_Certificate cert(hostname + ".dsa.crt"); + Botan::Private_Key* key = Botan::PKCS8::load_key(hostname + ".dsa.key", rng); + + certs_and_keys[cert] = key; + certs.push_back(cert); + } } else if(type == "tls-client") { diff --git a/src/credentials/credentials_manager.cpp b/src/credentials/credentials_manager.cpp index 82da8a75d..2e46a314e 100644 --- a/src/credentials/credentials_manager.cpp +++ b/src/credentials/credentials_manager.cpp @@ -35,13 +35,23 @@ bool Credentials_Manager::srp_verifier(const std::string&, } std::vector<X509_Certificate> Credentials_Manager::cert_chain( - const std::string&, + const std::vector<std::string>&, const std::string&, const std::string&) { return std::vector<X509_Certificate>(); } +std::vector<X509_Certificate> Credentials_Manager::cert_chain_single_type( + const std::string& cert_key_type, + const std::string& type, + const std::string& context) + { + std::vector<std::string> cert_types; + cert_types.push_back(cert_key_type); + return cert_chain(cert_types, type, context); + } + Private_Key* Credentials_Manager::private_key_for(const X509_Certificate&, const std::string&, const std::string&) @@ -65,9 +75,6 @@ void Credentials_Manager::verify_certificate_chain( throw std::invalid_argument("Certificate chain was empty"); #if 0 - if(!cert_chain[0].matches_dns_name(purported_hostname)) - return false; - X509_Store store; std::vector<X509_Certificate> CAs = trusted_certificate_authorities(); @@ -76,6 +83,15 @@ void Credentials_Manager::verify_certificate_chain( store.add_cert(CAs[i], true); for(size_t i = 1; i != cert_chain.size(); ++i) store.add_cert(cert_chain[i]); + + X509_Code result = store.validate_cert(cert_chain[0], TLS_SERVER); + + if(result != VERIFIED) + throw std::runtime_error("Certificate did not validate"); + + if(!cert_chain[0].matches_dns_name(purported_hostname)) + throw std::runtime_error("Certificate did not match hostname"); + #endif } diff --git a/src/credentials/credentials_manager.h b/src/credentials/credentials_manager.h index fdcfa74da..5972dc2d4 100644 --- a/src/credentials/credentials_manager.h +++ b/src/credentials/credentials_manager.h @@ -66,10 +66,25 @@ class BOTAN_DLL Credentials_Manager * Assumed that we can get the private key of the leaf with * private_key_for * - * @param cert_key_type is a string representing the key type - * ("rsa", "dsa", "ecdsa", etc) or empty if no preference. + * @param cert_key_type is a set string representing the allowed + * key type ("RSA", "DSA", "ECDSA", etc) or empty if no + * preference. */ virtual std::vector<X509_Certificate> cert_chain( + const std::vector<std::string>& cert_key_types, + const std::string& type, + const std::string& context); + + /** + * Return a cert chain we can use, ordered from leaf to root. + * Assumed that we can get the private key of the leaf with + * private_key_for + * + * @param cert_key_type is a set string representing the allowed + * key type ("RSA", "DSA", "ECDSA", etc) or empty if no + * preference. + */ + std::vector<X509_Certificate> cert_chain_single_type( const std::string& cert_key_type, const std::string& type, const std::string& context); diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp index 7b7e4a753..caf89fb44 100644 --- a/src/tls/s_hello.cpp +++ b/src/tls/s_hello.cpp @@ -23,7 +23,7 @@ Server_Hello::Server_Hello(Record_Writer& writer, Handshake_Hash& hash, Protocol_Version version, const Client_Hello& c_hello, - const std::vector<X509_Certificate>& certs, + const std::vector<std::string>& available_cert_types, const Policy& policy, bool client_has_secure_renegotiation, const MemoryRegion<byte>& reneg_info, @@ -39,22 +39,11 @@ Server_Hello::Server_Hello(Record_Writer& writer, m_next_protocol(client_has_npn), m_next_protocols(next_protocols) { - bool have_rsa = false, have_dsa = false; - - for(size_t i = 0; i != certs.size(); ++i) - { - Public_Key* key = certs[i].subject_public_key(); - if(key->algo_name() == "RSA") - have_rsa = true; - - if(key->algo_name() == "DSA") - have_dsa = true; - } - suite = policy.choose_suite( c_hello.ciphersuites(), + available_cert_types, policy.choose_curve(c_hello.supported_ecc_curves()) != "", - have_rsa, have_dsa, false); + false); if(suite == 0) throw TLS_Exception(HANDSHAKE_FAILURE, diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 215ff6972..ba0d1e506 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -299,10 +299,11 @@ void Client::process_handshake_msg(Handshake_Type type, if(state->received_handshake_msg(CERTIFICATE_REQUEST)) { - std::vector<byte> types = state->cert_req->acceptable_types(); + const std::vector<std::string>& types = + state->cert_req->acceptable_cert_types(); std::vector<X509_Certificate> client_certs = - creds.cert_chain("", // FIXME use types here + creds.cert_chain(types, "tls-client", state->client_hello->sni_hostname()); diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index b5a651e7d..8391e185f 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -162,7 +162,7 @@ class Server_Hello : public Handshake_Message Handshake_Hash& hash, Protocol_Version version, const Client_Hello& other, - const std::vector<X509_Certificate>& certs, + const std::vector<std::string>& available_cert_types, const Policy& policies, bool client_has_secure_renegotiation, const MemoryRegion<byte>& reneg_info, @@ -260,7 +260,9 @@ class Certificate_Req : public Handshake_Message public: Handshake_Type type() const { return CERTIFICATE_REQUEST; } - std::vector<std::string> acceptable_keys() const { return cert_key_types; } + const std::vector<std::string>& acceptable_cert_types() const + { return cert_key_types; } + std::vector<X509_DN> acceptable_CAs() const { return names; } std::vector<std::pair<std::string, std::string> > supported_algos() const diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp index 77b103aa2..02263ffa2 100644 --- a/src/tls/tls_policy.cpp +++ b/src/tls/tls_policy.cpp @@ -213,9 +213,8 @@ std::string Policy::choose_curve(const std::vector<std::string>& curve_names) co * Choose which ciphersuite to use */ u16bit Policy::choose_suite(const std::vector<u16bit>& client_suites, + const std::vector<std::string>& available_cert_types, bool have_shared_ecc_curve, - bool have_rsa, - bool have_dsa, bool have_srp) const { for(size_t i = 0; i != client_suites.size(); ++i) @@ -226,25 +225,20 @@ u16bit Policy::choose_suite(const std::vector<u16bit>& client_suites, if(suite.cipher_keylen() == 0) continue; // not a ciphersuite we know - if(suite.kex_algo() == "ECDH" && !have_shared_ecc_curve) - continue; - - if(suite.sig_algo() == "RSA" && have_rsa) - return suite_id; - - if(suite.sig_algo() == "DSA" && have_dsa) - return suite_id; + if(!have_shared_ecc_curve) + { + if(suite.kex_algo() == "ECDH" || suite.sig_algo() == "ECDSA") + continue; + } if(suite.kex_algo() == "SRP" && have_srp) return suite_id; -#if 0 - if(suite.sig_algo() == "") // anonymous server + if(value_exists(available_cert_types, suite.sig_algo())) return suite_id; -#endif } - return 0; + return 0; // no shared cipersuite } /* diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h index 6b7387f46..72ce8df9e 100644 --- a/src/tls/tls_policy.h +++ b/src/tls/tls_policy.h @@ -102,9 +102,8 @@ class BOTAN_DLL Policy std::vector<u16bit> ciphersuite_list(bool have_srp) const; u16bit choose_suite(const std::vector<u16bit>& client_suites, + const std::vector<std::string>& available_cert_types, bool have_shared_ecc_curve, - bool have_rsa, - bool have_dsa, bool have_srp) const; byte choose_compression(const std::vector<byte>& client_algos) const; diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index 207d40990..8aff79793 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -1,6 +1,6 @@ /* * TLS Server -* (C) 2004-2011 Jack Lloyd +* (C) 2004-2011,2012 Jack Lloyd * * Released under the terms of the Botan license */ @@ -11,6 +11,7 @@ #include <botan/internal/stl_util.h> #include <botan/dh.h> #include <botan/ecdh.h> +#include <memory> namespace Botan { @@ -218,23 +219,27 @@ void Server::process_handshake_msg(Handshake_Type type, } else // new session { - std::vector<X509_Certificate> server_certs = - creds.cert_chain("", - "tls-server", - m_hostname); + std::map<std::string, std::vector<X509_Certificate> > cert_chains; - Private_Key* private_key = - server_certs.empty() ? 0 : - (creds.private_key_for(server_certs[0], - "tls-server", - m_hostname)); + cert_chains["RSA"] = creds.cert_chain_single_type("RSA", "tls-server", m_hostname); + cert_chains["DSA"] = creds.cert_chain_single_type("DSA", "tls-server", m_hostname); + cert_chains["ECDSA"] = creds.cert_chain_single_type("ECDSA", "tls-server", m_hostname); + + std::vector<std::string> available_cert_types; + + for(std::map<std::string, std::vector<X509_Certificate> >::const_iterator i = cert_chains.begin(); + i != cert_chains.end(); ++i) + { + if(!i->second.empty()) + available_cert_types.push_back(i->first); + } state->server_hello = new Server_Hello( writer, state->hash, state->version, *(state->client_hello), - server_certs, + available_cert_types, policy, secure_renegotiation.supported(), secure_renegotiation.for_server_hello(), @@ -250,19 +255,28 @@ void Server::process_handshake_msg(Handshake_Type type, state->suite = Ciphersuite::lookup_ciphersuite(state->server_hello->ciphersuite()); - if(state->suite.sig_algo() != "") + const std::string sig_algo = state->suite.sig_algo(); + const std::string kex_algo = state->suite.kex_algo(); + + std::auto_ptr<Private_Key> private_key(0); + + if(sig_algo != "") { state->server_certs = new Certificate(writer, state->hash, - server_certs); - } + cert_chains[sig_algo]); - const std::string kex_algo = state->suite.kex_algo(); + private_key.reset(creds.private_key_for(state->server_certs->cert_chain()[0], + "tls-server", + m_hostname)); + } if(kex_algo != "") { if(kex_algo == "DH") + { state->kex_priv = new DH_PrivateKey(rng, policy.dh_group()); + } else if(kex_algo == "ECDH") { const std::vector<std::string>& curves = @@ -284,10 +298,10 @@ void Server::process_handshake_msg(Handshake_Type type, kex_algo); state->server_kex = - new Server_Key_Exchange(writer, state, rng, private_key); + new Server_Key_Exchange(writer, state, rng, private_key.get()); } else - state->kex_priv = PKCS8::copy_key(*private_key, rng); + state->kex_priv = private_key.release(); std::vector<X509_Certificate> client_auth_CAs = creds.trusted_certificate_authorities("tls-server", m_hostname); |