diff options
author | lloyd <[email protected]> | 2011-12-31 02:15:18 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2011-12-31 02:15:18 +0000 |
commit | 074ea8fdee34a668c57b19b474468a7e4d581567 (patch) | |
tree | 56a6c62787c51ac2d5aa64316d91c2f20010c8a9 /src | |
parent | bf41971fe4ee6a38609e0ea142010b03017e0329 (diff) |
Add support for client-side session resumption
Diffstat (limited to 'src')
-rw-r--r-- | src/tls/hello.cpp | 23 | ||||
-rw-r--r-- | src/tls/tls_channel.h | 13 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 143 | ||||
-rw-r--r-- | src/tls/tls_client.h | 2 | ||||
-rw-r--r-- | src/tls/tls_handshake_state.h | 5 | ||||
-rw-r--r-- | src/tls/tls_messages.h | 32 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 42 | ||||
-rw-r--r-- | src/tls/tls_session.h | 24 | ||||
-rw-r--r-- | src/tls/tls_session_manager.cpp | 8 | ||||
-rw-r--r-- | src/tls/tls_session_manager.h | 37 |
10 files changed, 228 insertions, 101 deletions
diff --git a/src/tls/hello.cpp b/src/tls/hello.cpp index fc19f6802..08d8eee8e 100644 --- a/src/tls/hello.cpp +++ b/src/tls/hello.cpp @@ -17,7 +17,7 @@ namespace Botan { /* * Encode and send a Handshake message */ -void HandshakeMessage::send(Record_Writer& writer, TLS_Handshake_Hash& hash) const +void Handshake_Message::send(Record_Writer& writer, TLS_Handshake_Hash& hash) const { MemoryVector<byte> buf = serialize(); MemoryVector<byte> send_buf(4); @@ -86,6 +86,27 @@ Client_Hello::Client_Hello(Record_Writer& writer, } /* +* Create a new Client Hello message +*/ +Client_Hello::Client_Hello(Record_Writer& writer, + TLS_Handshake_Hash& hash, + RandomNumberGenerator& rng, + const TLS_Session& session) : + c_version(session.version()), + sess_id(session.session_id()), + c_random(rng.random_vec(32)), + requested_hostname(session.sni_hostname()), + requested_srp_id(session.srp_identifier()), + m_fragment_size(session.fragment_size()), + has_secure_renegotiation(session.secure_renegotiation()) + { + suites.push_back(session.ciphersuite()); + comp_methods.push_back(session.compression_method()); + + send(writer, hash); + } + +/* * Serialize a Client Hello message */ MemoryVector<byte> Client_Hello::serialize() const diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h index 8eca71305..c1e9e1fda 100644 --- a/src/tls/tls_channel.h +++ b/src/tls/tls_channel.h @@ -24,9 +24,8 @@ class BOTAN_DLL TLS_Channel public: /** * Inject TLS traffic received from counterparty - * @return a hint as the how many more bytes we need to process the - current record (this may be 0 if on a record boundary) + * current record (this may be 0 if on a record boundary) */ virtual size_t received_data(const byte buf[], size_t buf_size); @@ -43,21 +42,23 @@ class BOTAN_DLL TLS_Channel /** * Send a TLS alert message. If the alert is fatal, the * internal state (keys, etc) will be reset + * @param level is warning or fatal + * @param type is the type of alert */ void alert(Alert_Level level, Alert_Type type); /** - * Is the connection active for sending application data? + * @return true iff the connection is active for sending application data */ bool is_active() const { return handshake_completed && !is_closed(); } /** - * Has the connection been definitely closed + * @return true iff the connection has been definitely closed */ bool is_closed() const { return connection_closed; } /** - * Return the negotiated version (if session is currently active) + * @return negotiated version (if session is currently active) */ Version_Code protocol_version() const; @@ -67,7 +68,7 @@ class BOTAN_DLL TLS_Channel virtual void renegotiate() = 0; /** - * Return the certificates of the peer + * @return certificate chain of the peer (may be empty) */ std::vector<X509_Certificate> peer_cert_chain() const { return peer_certs; } diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 1790151f9..9942c2d44 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -8,10 +8,13 @@ #include <botan/tls_client.h> #include <botan/internal/tls_session_key.h> #include <botan/internal/tls_handshake_state.h> +#include <botan/internal/stl_util.h> #include <botan/rsa.h> #include <botan/dsa.h> #include <botan/dh.h> +#include <stdio.h> + namespace Botan { /* @@ -24,7 +27,7 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn const TLS_Policy& policy, RandomNumberGenerator& rng, const std::string& hostname, - const std::string& srp_username) : + const std::string& srp_identifier) : TLS_Channel(output_fn, proc_fn, handshake_fn), policy(policy), rng(rng), @@ -34,13 +37,36 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn state = new Handshake_State; state->set_expected_next(SERVER_HELLO); - state->client_hello = new Client_Hello(writer, - state->hash, - policy, - rng, - secure_renegotiation.for_client_hello(), - hostname, - srp_username); + + if(hostname != "") + { + TLS_Session session_info; + if(session_manager.load_from_host_info(hostname, 0, session_info)) + { + if(session_info.srp_identifier() == srp_identifier) + { + state->client_hello = new Client_Hello( + writer, + state->hash, + rng, + session_info); + + state->resume_master_secret = session_info.master_secret(); + } + } + } + + if(!state->client_hello) // not resuming + { + state->client_hello = new Client_Hello( + writer, + state->hash, + policy, + rng, + secure_renegotiation.for_client_hello(), + hostname, + srp_identifier); + } secure_renegotiation.update(state->client_hello); } @@ -128,19 +154,14 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, "TLS_Client: Server replied with bad ciphersuite"); } - state->version = state->server_hello->version(); - - if(state->version > state->client_hello->version()) + if(!value_exists(state->client_hello->compression_methods(), + state->server_hello->compression_method())) { throw TLS_Exception(HANDSHAKE_FAILURE, - "TLS_Client: Server replied with bad version"); + "TLS_Client: Server replied with bad compression method"); } - if(state->version < policy.min_version()) - { - throw TLS_Exception(PROTOCOL_VERSION, - "TLS_Client: Server is too old for specified policy"); - } + state->version = state->server_hello->version(); writer.set_version(state->version); reader.set_version(state->version); @@ -149,20 +170,56 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, state->suite = TLS_Cipher_Suite(state->server_hello->ciphersuite()); - // if resuming, next is HANDSHAKE_CCS - - if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) - { - state->set_expected_next(CERTIFICATE); - } - else if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX) + if(!state->server_hello->session_id().empty() && + (state->server_hello->session_id() == state->client_hello->session_id())) { - state->set_expected_next(SERVER_KEX); + // successful resumption + + /* + In this case, we offered the original session and the server + must resume with it + */ + if(state->server_hello->version() != state->client_hello->version()) + throw TLS_Exception(HANDSHAKE_FAILURE, + "Server resumed session but with wrong version"); + + state->keys = SessionKeys(state->suite, state->version, + state->resume_master_secret, + state->client_hello->random(), + state->server_hello->random(), + true); + + state->set_expected_next(HANDSHAKE_CCS); } else { - state->set_expected_next(CERTIFICATE_REQUEST); // optional - state->set_expected_next(SERVER_HELLO_DONE); + // new session + + if(state->version > state->client_hello->version()) + { + throw TLS_Exception(HANDSHAKE_FAILURE, + "TLS_Client: Server replied with bad version"); + } + + if(state->version < policy.min_version()) + { + throw TLS_Exception(PROTOCOL_VERSION, + "TLS_Client: Server is too old for specified policy"); + } + + if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) + { + state->set_expected_next(CERTIFICATE); + } + else if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX) + { + state->set_expected_next(SERVER_KEX); + } + else + { + state->set_expected_next(CERTIFICATE_REQUEST); // optional + state->set_expected_next(SERVER_HELLO_DONE); + } } } else if(type == CERTIFICATE) @@ -308,6 +365,38 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, throw TLS_Exception(DECRYPT_ERROR, "Finished message didn't verify"); + state->hash.update(type, contents); + + if(!state->client_finished) // session resume case + { + writer.send(CHANGE_CIPHER_SPEC, 1); + + writer.activate(state->suite, state->keys, CLIENT); + + state->client_finished = new Finished(writer, state->hash, + state->version, CLIENT, + state->keys.master_secret()); + } + + TLS_Session session_info( + state->server_hello->session_id(), + state->keys.master_secret(), + state->server_hello->version(), + state->server_hello->ciphersuite(), + state->server_hello->compression_method(), + CLIENT, + secure_renegotiation.supported(), + state->server_hello->fragment_size(), + peer_certs, + state->client_hello->sni_hostname(), + "" + ); + + session_manager.save(session_info); + + if(handshake_fn) + handshake_fn(session_info); + secure_renegotiation.update(state->client_finished, state->server_finished); delete state; diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h index 75a85f74d..0f654a40f 100644 --- a/src/tls/tls_client.h +++ b/src/tls/tls_client.h @@ -25,7 +25,7 @@ class BOTAN_DLL TLS_Client : public TLS_Channel * @param socket_output_fn is called with data for the outbound socket * @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 resumption + * @param session_manager manages session state * @param policy specifies other connection policy information * @param rng a random number generator * @param servername the server's DNS name, if known diff --git a/src/tls/tls_handshake_state.h b/src/tls/tls_handshake_state.h index 1602ca17c..f57538478 100644 --- a/src/tls/tls_handshake_state.h +++ b/src/tls/tls_handshake_state.h @@ -50,6 +50,11 @@ class Handshake_State SecureQueue queue; + /* + * Only used by clients for session resumption + */ + SecureVector<byte> resume_master_secret; + Version_Code version; private: u32bit hand_expecting_mask, hand_received_mask; diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index 2d66dfa11..f0620003b 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -9,6 +9,7 @@ #define BOTAN_TLS_MESSAGES_H__ #include <botan/internal/tls_handshake_hash.h> +#include <botan/tls_session.h> #include <botan/tls_policy.h> #include <botan/tls_magic.h> #include <botan/tls_suites.h> @@ -25,16 +26,16 @@ class Record_Reader; /** * TLS Handshake Message Base Class */ -class HandshakeMessage +class Handshake_Message { public: void send(Record_Writer& writer, TLS_Handshake_Hash& hash) const; virtual Handshake_Type type() const = 0; - virtual ~HandshakeMessage() {} + virtual ~Handshake_Message() {} private: - HandshakeMessage& operator=(const HandshakeMessage&) { return (*this); } + Handshake_Message& operator=(const Handshake_Message&) { return (*this); } virtual MemoryVector<byte> serialize() const = 0; virtual void deserialize(const MemoryRegion<byte>&) = 0; }; @@ -42,7 +43,7 @@ class HandshakeMessage /** * Client Hello Message */ -class Client_Hello : public HandshakeMessage +class Client_Hello : public Handshake_Message { public: Handshake_Type type() const { return CLIENT_HELLO; } @@ -82,6 +83,11 @@ class Client_Hello : public HandshakeMessage const std::string& hostname = "", const std::string& srp_identifier = ""); + Client_Hello(Record_Writer& writer, + TLS_Handshake_Hash& hash, + RandomNumberGenerator& rng, + const TLS_Session& resumed_session); + Client_Hello(const MemoryRegion<byte>& buf, Handshake_Type type) { @@ -111,7 +117,7 @@ class Client_Hello : public HandshakeMessage /** * Server Hello Message */ -class Server_Hello : public HandshakeMessage +class Server_Hello : public Handshake_Message { public: Handshake_Type type() const { return SERVER_HELLO; } @@ -176,7 +182,7 @@ class Server_Hello : public HandshakeMessage /** * Client Key Exchange Message */ -class Client_Key_Exchange : public HandshakeMessage +class Client_Key_Exchange : public Handshake_Message { public: Handshake_Type type() const { return CLIENT_KEX; } @@ -209,7 +215,7 @@ class Client_Key_Exchange : public HandshakeMessage /** * Certificate Message */ -class Certificate : public HandshakeMessage +class Certificate : public Handshake_Message { public: Handshake_Type type() const { return CERTIFICATE; } @@ -232,7 +238,7 @@ class Certificate : public HandshakeMessage /** * Certificate Request Message */ -class Certificate_Req : public HandshakeMessage +class Certificate_Req : public Handshake_Message { public: Handshake_Type type() const { return CERTIFICATE_REQUEST; } @@ -258,7 +264,7 @@ class Certificate_Req : public HandshakeMessage /** * Certificate Verify Message */ -class Certificate_Verify : public HandshakeMessage +class Certificate_Verify : public Handshake_Message { public: Handshake_Type type() const { return CERTIFICATE_VERIFY; } @@ -291,7 +297,7 @@ class Certificate_Verify : public HandshakeMessage /** * Finished Message */ -class Finished : public HandshakeMessage +class Finished : public Handshake_Message { public: Handshake_Type type() const { return FINISHED; } @@ -327,7 +333,7 @@ class Finished : public HandshakeMessage /** * Hello Request Message */ -class Hello_Request : public HandshakeMessage +class Hello_Request : public Handshake_Message { public: Handshake_Type type() const { return HELLO_REQUEST; } @@ -342,7 +348,7 @@ class Hello_Request : public HandshakeMessage /** * Server Key Exchange Message */ -class Server_Key_Exchange : public HandshakeMessage +class Server_Key_Exchange : public Handshake_Message { public: Handshake_Type type() const { return SERVER_KEX; } @@ -373,7 +379,7 @@ class Server_Key_Exchange : public HandshakeMessage /** * Server Hello Done Message */ -class Server_Hello_Done : public HandshakeMessage +class Server_Hello_Done : public Handshake_Message { public: Handshake_Type type() const { return SERVER_HELLO_DONE; } diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index f0d1fb361..0e2e173cf 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -12,6 +12,8 @@ #include <botan/rsa.h> #include <botan/dh.h> +#include <stdio.h> + namespace Botan { namespace { @@ -180,6 +182,8 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, if(resuming) { // resume session + + printf("Resuming a session\n"); state->server_hello = new Server_Hello( writer, state->hash, @@ -377,27 +381,27 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, if(state->client_certs && state->client_verify) peer_certs = state->client_certs->cert_chain(); - - TLS_Session session_info( - state->server_hello->session_id(), - state->keys.master_secret(), - state->server_hello->version(), - state->server_hello->ciphersuite(), - state->server_hello->compression_method(), - SERVER, - secure_renegotiation.supported(), - state->server_hello->fragment_size(), - peer_certs, - client_requested_hostname, - "" - ); - - session_manager.save(session_info); - - if(handshake_fn) - handshake_fn(session_info); } + TLS_Session session_info( + state->server_hello->session_id(), + state->keys.master_secret(), + state->server_hello->version(), + state->server_hello->ciphersuite(), + state->server_hello->compression_method(), + SERVER, + secure_renegotiation.supported(), + state->server_hello->fragment_size(), + peer_certs, + client_requested_hostname, + "" + ); + + session_manager.save(session_info); + + if(handshake_fn) + handshake_fn(session_info); + secure_renegotiation.update(state->client_finished, state->server_finished); diff --git a/src/tls/tls_session.h b/src/tls/tls_session.h index c713efc87..b4b3861ed 100644 --- a/src/tls/tls_session.h +++ b/src/tls/tls_session.h @@ -38,16 +38,16 @@ class BOTAN_DLL TLS_Session * New session (sets session start time) */ TLS_Session(const MemoryRegion<byte>& session_id, - const MemoryRegion<byte>& master_secret, - Version_Code version, - u16bit ciphersuite, - byte compression_method, - Connection_Side side, - bool secure_renegotiation_supported, - size_t fragment_size, - const std::vector<X509_Certificate>& peer_certs, - const std::string& sni_hostname = "", - const std::string& srp_identifier = ""); + const MemoryRegion<byte>& master_secret, + Version_Code version, + u16bit ciphersuite, + byte compression_method, + Connection_Side side, + bool secure_renegotiation_supported, + size_t fragment_size, + const std::vector<X509_Certificate>& peer_certs, + const std::string& sni_hostname = "", + const std::string& srp_identifier = ""); /** * Load a session from BER (created by BER_encode) @@ -111,9 +111,9 @@ class BOTAN_DLL TLS_Session size_t fragment_size() const { return m_fragment_size; } /** - * Is secure negotiation supported? + * Is secure renegotiation supported? */ - bool secure_negotiation() const + bool secure_renegotiation() const { return m_secure_renegotiation_supported; } /** diff --git a/src/tls/tls_session_manager.cpp b/src/tls/tls_session_manager.cpp index 7503b7c28..4a0126fc0 100644 --- a/src/tls/tls_session_manager.cpp +++ b/src/tls/tls_session_manager.cpp @@ -9,6 +9,8 @@ #include <botan/hex.h> #include <botan/time.h> +#include <stdio.h> + namespace Botan { bool TLS_Session_Manager_In_Memory::load_from_session_str( @@ -21,7 +23,7 @@ bool TLS_Session_Manager_In_Memory::load_from_session_str( // session has expired, remove it const u64bit now = system_time(); - if(i->second.start_time() + session_lifetime >= now) + if(i->second.start_time() + session_lifetime < now) { sessions.erase(i); return false; @@ -32,7 +34,7 @@ bool TLS_Session_Manager_In_Memory::load_from_session_str( } bool TLS_Session_Manager_In_Memory::load_from_session_id( - const MemoryVector<byte>& session_id, TLS_Session& session) + const MemoryRegion<byte>& session_id, TLS_Session& session) { return load_from_session_str(hex_encode(session_id), session); } @@ -60,7 +62,7 @@ bool TLS_Session_Manager_In_Memory::load_from_host_info( } void TLS_Session_Manager_In_Memory::remove_entry( - const MemoryVector<byte>& session_id) + const MemoryRegion<byte>& session_id) { std::map<std::string, TLS_Session>::iterator i = sessions.find(hex_encode(session_id)); diff --git a/src/tls/tls_session_manager.h b/src/tls/tls_session_manager.h index b30de7364..289b76a3b 100644 --- a/src/tls/tls_session_manager.h +++ b/src/tls/tls_session_manager.h @@ -28,39 +28,38 @@ class BOTAN_DLL TLS_Session_Manager /** * Try to load a saved session (server side) * @param session_id the session identifier we are trying to resume - * @param params will be set to the saved session data (if found), + * @param session will be set to the saved session data (if found), or not modified if not found - * @return true if params was modified + * @return true if session was modified */ - virtual bool load_from_session_id(const MemoryVector<byte>& session_id, - TLS_Session& params) = 0; + virtual bool load_from_session_id(const MemoryRegion<byte>& session_id, + TLS_Session& session) = 0; /** * Try to load a saved session (client side) * @param hostname of the host we are connecting to * @param port the port number if we know it, or 0 if unknown - * @param params will be set to the saved session data (if found), + * @param session will be set to the saved session data (if found), or not modified if not found - * @return true if params was modified + * @return true if session was modified */ virtual bool load_from_host_info(const std::string& hostname, u16bit port, - TLS_Session& params) = 0; + TLS_Session& session) = 0; /** - * Remove this session id from the cache + * Remove this session id from the cache, if it exists */ - virtual void remove_entry(const MemoryVector<byte>& session_id) = 0; + virtual void remove_entry(const MemoryRegion<byte>& session_id) = 0; /** * Save a session on a best effort basis; the manager may not in - * fact be able to save the session for whatever reason, this is + * fact be able to save the session for whatever reason; this is * not an error. Caller cannot assume that calling save followed - * immediately by find will result in a successful lookup. + * immediately by load_from_* will result in a successful lookup. * - * @param session_id the session identifier - * @param params to save + * @param session to save */ - virtual void save(const TLS_Session& params) = 0; + virtual void save(const TLS_Session& session) = 0; virtual ~TLS_Session_Manager() {} }; @@ -86,19 +85,19 @@ class BOTAN_DLL TLS_Session_Manager_In_Memory : public TLS_Session_Manager session_lifetime(session_lifetime) {} - bool load_from_session_id(const MemoryVector<byte>& session_id, - TLS_Session& params); + bool load_from_session_id(const MemoryRegion<byte>& session_id, + TLS_Session& session); bool load_from_host_info(const std::string& hostname, u16bit port, - TLS_Session& params); + TLS_Session& session); - void remove_entry(const MemoryVector<byte>& session_id); + void remove_entry(const MemoryRegion<byte>& session_id); void save(const TLS_Session& session_data); private: bool load_from_session_str(const std::string& session_str, - TLS_Session& params); + TLS_Session& session); size_t max_sessions, session_lifetime; |