diff options
-rw-r--r-- | doc/examples/tls_server.cpp | 66 | ||||
-rw-r--r-- | src/cert/x509cert/x509cert.cpp | 18 | ||||
-rw-r--r-- | src/cert/x509cert/x509cert.h | 6 | ||||
-rw-r--r-- | src/credentials/credentials_manager.cpp | 51 | ||||
-rw-r--r-- | src/credentials/credentials_manager.h | 78 | ||||
-rw-r--r-- | src/credentials/info.txt | 1 | ||||
-rw-r--r-- | src/tls/hello.cpp | 3 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 45 | ||||
-rw-r--r-- | src/tls/tls_client.h | 17 | ||||
-rw-r--r-- | src/tls/tls_magic.h | 3 | ||||
-rw-r--r-- | src/tls/tls_messages.h | 1 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 36 | ||||
-rw-r--r-- | src/tls/tls_server.h | 16 |
13 files changed, 250 insertions, 91 deletions
diff --git a/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp index d9334c47e..10f294a3f 100644 --- a/doc/examples/tls_server.cpp +++ b/doc/examples/tls_server.cpp @@ -16,6 +16,46 @@ using namespace Botan; #include <iostream> #include <memory> +class Credentials_Manager_Simple : public Credentials_Manager + { + public: + Credentials_Manager_Simple(RandomNumberGenerator& rng) : rng(rng) {} + + std::vector<X509_Certificate> cert_chain( + const std::string& cert_key_type, + const std::string& type, + const std::string& context) + { + const std::string hostname = (context == "" ? "localhost" : context); + + //RSA_PrivateKey key(rng, 1024); + DSA_PrivateKey key(rng, DL_Group("dsa/jce/1024")); + + X509_Cert_Options options( + hostname + "/US/Botan Library/Test Server"); + + X509_Certificate cert = + X509::create_self_signed_cert(options, key, "SHA-1", rng); + + certs_and_keys[cert] = PKCS8::copy_key(key, rng); + + std::vector<X509_Certificate> certs; + certs.push_back(cert); + return certs; + } + + Private_Key* private_key_for(const X509_Certificate& cert, + const std::string& type, + const std::string& context) + { + return certs_and_keys[cert]; + } + + private: + RandomNumberGenerator& rng; + std::map<X509_Certificate, Private_Key*> certs_and_keys; + }; + void handshake_complete(const TLS_Session& session) { printf("Handshake complete, protocol=%04X ciphersuite=%04X compression=%d\n", @@ -32,20 +72,18 @@ class Blocking_TLS_Server Blocking_TLS_Server(std::tr1::function<void (const byte[], size_t)> output_fn, std::tr1::function<size_t (byte[], size_t)> input_fn, TLS_Session_Manager& sessions, + Credentials_Manager& creds, TLS_Policy& policy, - RandomNumberGenerator& rng, - const X509_Certificate& cert, - const Private_Key& key) : + RandomNumberGenerator& rng) : input_fn(input_fn), server( output_fn, std::tr1::bind(&Blocking_TLS_Server::reader_fn, std::tr1::ref(*this), _1, _2, _3), handshake_complete, sessions, + creds, policy, - rng, - cert, - key), + rng), exit(false) { read_loop(); @@ -154,21 +192,14 @@ int main(int argc, char* argv[]) AutoSeeded_RNG rng; - RSA_PrivateKey key(rng, 1024); - //DSA_PrivateKey key(rng, DL_Group("dsa/jce/1024")); - - X509_Cert_Options options( - "localhost/US/Botan Library/Test Server"); - - X509_Certificate cert = - X509::create_self_signed_cert(options, key, "SHA-1", rng); - Server_Socket listener(port); Server_TLS_Policy policy; TLS_Session_Manager_In_Memory sessions; + Credentials_Manager_Simple creds(rng); + while(true) { try { @@ -182,10 +213,9 @@ int main(int argc, char* argv[]) std::tr1::bind(&Socket::write, std::tr1::ref(sock), _1, _2), std::tr1::bind(&Socket::read, std::tr1::ref(sock), _1, _2, true), sessions, + creds, policy, - rng, - cert, - key); + rng); const char* msg = "Welcome to the best echo server evar\n"; tls.write((const Botan::byte*)msg, strlen(msg)); diff --git a/src/cert/x509cert/x509cert.cpp b/src/cert/x509cert/x509cert.cpp index 7d9370f2a..88aeebd77 100644 --- a/src/cert/x509cert/x509cert.cpp +++ b/src/cert/x509cert/x509cert.cpp @@ -296,6 +296,24 @@ bool X509_Certificate::operator==(const X509_Certificate& other) const subject == other.subject); } +bool X509_Certificate::operator<(const X509_Certificate& other) const + { + /* If signature values are not equal, sort by lexicographic ordering of that */ + if(sig != other.sig) + { + if(sig < other.sig) + return true; + return false; + } + + /* + * same signatures, highly unlikely case, revert to compare + * of entire contents + */ + + return to_string() < other.to_string(); + } + /* * X.509 Certificate Comparison */ diff --git a/src/cert/x509cert/x509cert.h b/src/cert/x509cert/x509cert.h index 8798ef1c2..cd49aa02f 100644 --- a/src/cert/x509cert/x509cert.h +++ b/src/cert/x509cert/x509cert.h @@ -152,6 +152,12 @@ class BOTAN_DLL X509_Certificate : public X509_Object bool operator==(const X509_Certificate& other) const; /** + * Impose an arbitrary (but consistent) ordering + * @return true if this is less than other by some unspecified criteria + */ + bool operator<(const X509_Certificate& other) const; + + /** * Create a certificate from a data source providing the DER or * PEM encoded certificate. * @param source the data source diff --git a/src/credentials/credentials_manager.cpp b/src/credentials/credentials_manager.cpp new file mode 100644 index 000000000..46d9e300c --- /dev/null +++ b/src/credentials/credentials_manager.cpp @@ -0,0 +1,51 @@ +/* +* Credentials Manager +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/credentials_manager.h> + +namespace Botan { + +std::string Credentials_Manager::srp_identifier(const std::string& type, + const std::string& context) + { + return ""; + } + +std::string Credentials_Manager::srp_password(const std::string& identifier, + const std::string& type, + const std::string& context) + { + return ""; + } + +bool Credentials_Manager::srp_verifier(const std::string& identifier, + const std::string& type, + const std::string& context, + BigInt& group_prime, + BigInt& group_generator, + BigInt& verifier, + MemoryRegion<byte>& salt) + { + return false; + } + +std::vector<X509_Certificate> Credentials_Manager::cert_chain( + const std::string& cert_key_type, + const std::string& type, + const std::string& context) + { + return std::vector<X509_Certificate>(); + } + +Private_Key* Credentials_Manager::private_key_for(const X509_Certificate& cert, + const std::string& type, + const std::string& context) + { + return 0; + } + +} diff --git a/src/credentials/credentials_manager.h b/src/credentials/credentials_manager.h new file mode 100644 index 000000000..a54b2ec31 --- /dev/null +++ b/src/credentials/credentials_manager.h @@ -0,0 +1,78 @@ +/* +* Credentials Manager +* (C) 2011,2012 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_CREDENTIALS_MANAGER_H__ +#define BOTAN_CREDENTIALS_MANAGER_H__ + +#include <botan/x509cert.h> +#include <botan/secmem.h> +#include <string> + +namespace Botan { + +class BigInt; + +/** +* Interface for a credentials manager. +* +* A type is a fairly static value that represents the general nature +* of the transaction occuring. Currently defined are "tls-client" and +* "tls-server". Context represents a hostname, email address, +* username, or other identifier. +*/ +class BOTAN_DLL Credentials_Manager + { + public: + virtual ~Credentials_Manager() {} + + /** + * @return identifier for client-side SRP auth, if available + for this type/context + */ + virtual std::string srp_identifier(const std::string& type, + const std::string& context); + + /** + * @return password for client-side SRP auth, if available + for this identifier/type/context + */ + virtual std::string srp_password(const std::string& identifier, + const std::string& type, + const std::string& context); + + /** + * @todo add option for faking verifier if identifier is unknown + */ + virtual bool srp_verifier(const std::string& identifier, + const std::string& type, + const std::string& context, + BigInt& group_prime, + BigInt& group_generator, + BigInt& verifier, + MemoryRegion<byte>& salt); + + /** + * @param cert_key_type is a string representing the key type + * ("RSA", "DSA", "ECDSA") or empty if no preference. + */ + virtual std::vector<X509_Certificate> cert_chain( + const std::string& cert_key_type, + const std::string& type, + const std::string& context); + + /** + * @return private key associated with this certificate if we should + * use it with this context + */ + virtual Private_Key* private_key_for(const X509_Certificate& cert, + const std::string& type, + const std::string& context); + }; + +} + +#endif diff --git a/src/credentials/info.txt b/src/credentials/info.txt new file mode 100644 index 000000000..f6dcdd64d --- /dev/null +++ b/src/credentials/info.txt @@ -0,0 +1 @@ +define CREDENTIALS_MANAGER diff --git a/src/tls/hello.cpp b/src/tls/hello.cpp index 49115fd62..17a624381 100644 --- a/src/tls/hello.cpp +++ b/src/tls/hello.cpp @@ -282,10 +282,9 @@ Server_Hello::Server_Hello(Record_Writer& writer, const MemoryRegion<byte>& reneg_info, const std::vector<X509_Certificate>& certs, const Client_Hello& c_hello, - const MemoryRegion<byte>& session_id, Version_Code ver) : s_version(ver), - sess_id(session_id), + sess_id(rng.random_vec(32)), s_random(rng.random_vec(32)), m_fragment_size(c_hello.fragment_size()), has_secure_renegotiation(client_has_secure_renegotiation), diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 1d9554ee8..b7249081b 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -22,21 +22,23 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn std::tr1::function<void (const byte[], size_t, u16bit)> proc_fn, std::tr1::function<void (const TLS_Session&)> handshake_fn, TLS_Session_Manager& session_manager, + Credentials_Manager& creds, const TLS_Policy& policy, RandomNumberGenerator& rng, - const std::string& hostname, - const std::string& srp_identifier, - const std::string& srp_password) : + const std::string& hostname) : TLS_Channel(output_fn, proc_fn, handshake_fn), policy(policy), rng(rng), - session_manager(session_manager) + session_manager(session_manager), + creds(creds) { writer.set_version(SSL_V3); state = new Handshake_State; state->set_expected_next(SERVER_HELLO); + const std::string srp_identifier = creds.srp_identifier("tls-client", hostname); + if(hostname != "") { TLS_Session session_info; @@ -70,21 +72,6 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn secure_renegotiation.update(state->client_hello); } -void TLS_Client::add_client_cert(const X509_Certificate& cert, - Private_Key* cert_key) - { - certs.push_back(std::make_pair(cert, cert_key)); - } - -/* -* TLS Client Destructor -*/ -TLS_Client::~TLS_Client() - { - for(size_t i = 0; i != certs.size(); i++) - delete certs[i].second; - } - /* * Send a new client hello to renegotiate */ @@ -308,17 +295,19 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, state->server_hello_done = new Server_Hello_Done(contents); - std::vector<X509_Certificate> send_certs; - if(state->received_handshake_msg(CERTIFICATE_REQUEST)) { std::vector<Certificate_Type> types = state->cert_req->acceptable_types(); - // FIXME: Fill in useful certs here, if any + std::vector<X509_Certificate> client_certs = + creds.cert_chain("", // use types here + "tls-client", + state->client_hello->sni_hostname()); + state->client_certs = new Certificate(writer, state->hash, - send_certs); + client_certs); } state->client_kex = @@ -327,11 +316,15 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, state->client_hello->version()); if(state->received_handshake_msg(CERTIFICATE_REQUEST) && - !send_certs.empty()) + !state->client_certs->empty()) { - Private_Key* key_matching_cert = 0; // FIXME + Private_Key* private_key = + creds.private_key_for(state->client_certs->cert_chain()[0], + "tls-client", + state->client_hello->sni_hostname()); + state->client_verify = new Certificate_Verify(writer, state->hash, - rng, key_matching_cert); + rng, private_key); } state->keys = SessionKeys(state->suite, state->version, diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h index eccddef6f..543dda144 100644 --- a/src/tls/tls_client.h +++ b/src/tls/tls_client.h @@ -10,6 +10,7 @@ #include <botan/tls_channel.h> #include <botan/tls_session_manager.h> +#include <botan/credentials_manager.h> #include <vector> namespace Botan { @@ -26,28 +27,21 @@ class BOTAN_DLL TLS_Client : public TLS_Channel * @param proc_fn is called when new data (application or alerts) is received * @param handshake_complete is called when a handshake is completed * @param session_manager manages session state + * @param creds manages application/user credentials * @param policy specifies other connection policy information * @param rng a random number generator * @param servername the server's DNS name, if known - * @param srp_username a SRP identifier to use for SRP key exchange - * @param srp_password a SRP password to use for SRP key exchange */ TLS_Client(std::tr1::function<void (const byte[], size_t)> socket_output_fn, std::tr1::function<void (const byte[], size_t, u16bit)> proc_fn, std::tr1::function<void (const TLS_Session&)> handshake_complete, TLS_Session_Manager& session_manager, + Credentials_Manager& creds, const TLS_Policy& policy, RandomNumberGenerator& rng, - const std::string& servername = "", - const std::string& srp_username = "", - const std::string& srp_password = ""); - - void add_client_cert(const X509_Certificate& cert, - Private_Key* cert_key); + const std::string& servername = ""); void renegotiate(); - - ~TLS_Client(); private: void process_handshake_msg(Handshake_Type type, const MemoryRegion<byte>& contents); @@ -55,8 +49,7 @@ class BOTAN_DLL TLS_Client : public TLS_Channel const TLS_Policy& policy; RandomNumberGenerator& rng; TLS_Session_Manager& session_manager; - - std::vector<std::pair<X509_Certificate, Private_Key*> > certs; + Credentials_Manager& creds; }; } diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h index 3629cd112..d49ec1e48 100644 --- a/src/tls/tls_magic.h +++ b/src/tls/tls_magic.h @@ -164,11 +164,12 @@ enum TLS_Ciphersuite_Algos { TLS_ALGO_SIGNER_ECDSA = 0x04000000, TLS_ALGO_KEYEXCH_MASK = 0x00FF0000, - TLS_ALGO_KEYEXCH_NOKEX = 0x00010000, + TLS_ALGO_KEYEXCH_NOKEX = 0x00010000, // exchange via key in server cert TLS_ALGO_KEYEXCH_RSA = 0x00020000, TLS_ALGO_KEYEXCH_DH = 0x00030000, TLS_ALGO_KEYEXCH_ECDH = 0x00040000, TLS_ALGO_KEYEXCH_SRP = 0x00050000, + TLS_ALGO_KEYEXCH_ANON = 0x00060000, TLS_ALGO_MAC_MASK = 0x0000FF00, TLS_ALGO_MAC_MD5 = 0x00000100, diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index f0620003b..16069f048 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -150,7 +150,6 @@ class Server_Hello : public Handshake_Message const MemoryRegion<byte>& reneg_info, const std::vector<X509_Certificate>& certs, const Client_Hello& other, - const MemoryRegion<byte>& session_id, Version_Code version); Server_Hello(Record_Writer& writer, diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index 0e2e173cf..b981bdc69 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -85,25 +85,15 @@ TLS_Server::TLS_Server(std::tr1::function<void (const byte[], size_t)> output_fn std::tr1::function<void (const byte[], size_t, u16bit)> proc_fn, std::tr1::function<void (const TLS_Session&)> handshake_fn, TLS_Session_Manager& session_manager, + Credentials_Manager& creds, const TLS_Policy& policy, - RandomNumberGenerator& rng, - const X509_Certificate& cert, - const Private_Key& cert_key) : + RandomNumberGenerator& rng) : TLS_Channel(output_fn, proc_fn, handshake_fn), policy(policy), rng(rng), - session_manager(session_manager) + session_manager(session_manager), + creds(creds) { - cert_chain.push_back(cert); - private_key = PKCS8::copy_key(cert_key, rng); - } - -/* -* TLS Server Destructor -*/ -TLS_Server::~TLS_Server() - { - delete private_key; } /* @@ -183,7 +173,6 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, { // resume session - printf("Resuming a session\n"); state->server_hello = new Server_Hello( writer, state->hash, @@ -222,6 +211,17 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, } else // new session { + std::vector<X509_Certificate> server_certs = + creds.cert_chain("", + "tls-server", + client_requested_hostname); + + Private_Key* private_key = + server_certs.empty() ? 0 : + (creds.private_key_for(server_certs[0], + "tls-server", + client_requested_hostname)); + state->server_hello = new Server_Hello( writer, state->hash, @@ -229,9 +229,8 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, rng, secure_renegotiation.supported(), secure_renegotiation.for_server_hello(), - cert_chain, + server_certs, *(state->client_hello), - rng.random_vec(32), state->version); if(state->client_hello->fragment_size()) @@ -241,10 +240,9 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) { - // FIXME: should choose certs based on sig type state->server_certs = new Certificate(writer, state->hash, - cert_chain); + server_certs); } if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX) diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h index d684a4a11..e07f89eba 100644 --- a/src/tls/tls_server.h +++ b/src/tls/tls_server.h @@ -10,6 +10,7 @@ #include <botan/tls_channel.h> #include <botan/tls_session_manager.h> +#include <botan/credentials_manager.h> #include <vector> namespace Botan { @@ -20,23 +21,16 @@ namespace Botan { class BOTAN_DLL TLS_Server : public TLS_Channel { public: - /** * TLS_Server initialization - * - * FIXME: support cert chains (!) - * FIXME: support anonymous servers */ TLS_Server(std::tr1::function<void (const byte[], size_t)> socket_output_fn, std::tr1::function<void (const byte[], size_t, u16bit)> proc_fn, std::tr1::function<void (const TLS_Session&)> handshake_complete, TLS_Session_Manager& session_manager, + Credentials_Manager& creds, const TLS_Policy& policy, - RandomNumberGenerator& rng, - const X509_Certificate& cert, - const Private_Key& cert_key); - - ~TLS_Server(); + RandomNumberGenerator& rng); void renegotiate(); @@ -53,9 +47,7 @@ class BOTAN_DLL TLS_Server : public TLS_Channel const TLS_Policy& policy; RandomNumberGenerator& rng; TLS_Session_Manager& session_manager; - - std::vector<X509_Certificate> cert_chain; - Private_Key* private_key; + Credentials_Manager& creds; std::string client_requested_hostname; }; |