aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlloyd <lloyd@randombit.net>2012-01-24 16:42:18 +0000
committerlloyd <lloyd@randombit.net>2012-01-24 16:42:18 +0000
commite4eb73dca7d7a74ecf8ef792d65640c4e44e2ab1 (patch)
tree5e7cd62ff1fe191c0369a41617b43ebf77d20ef9 /src
parentb8a8ba0428cd4235e1ac2ba8530e8f817a166773 (diff)
We can now actually handle multiple certificate types in the server
and will choose one depending on which ciphersuites the client offered.
Diffstat (limited to 'src')
-rw-r--r--src/credentials/credentials_manager.cpp24
-rw-r--r--src/credentials/credentials_manager.h19
-rw-r--r--src/tls/s_hello.cpp17
-rw-r--r--src/tls/tls_client.cpp5
-rw-r--r--src/tls/tls_messages.h6
-rw-r--r--src/tls/tls_policy.cpp22
-rw-r--r--src/tls/tls_policy.h3
-rw-r--r--src/tls/tls_server.cpp48
8 files changed, 87 insertions, 57 deletions
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);