aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2011-12-30 15:37:36 +0000
committerlloyd <[email protected]>2011-12-30 15:37:36 +0000
commitfc626d62f464a7dee5e62134781f5a6ccdfafc72 (patch)
tree6658020f1836b2faacffabca03897ca871b2880d
parentca850112360e48a3a140f08fa07f02806d61393b (diff)
Many renegotiation fixes. Add support for the secure renegotiation
extension (client side only at the moment). Add an interface that allows applications to request renegotiation.
-rw-r--r--src/tls/finished.cpp16
-rw-r--r--src/tls/hello.cpp32
-rw-r--r--src/tls/tls_channel.cpp48
-rw-r--r--src/tls/tls_channel.h39
-rw-r--r--src/tls/tls_client.cpp70
-rw-r--r--src/tls/tls_client.h2
-rw-r--r--src/tls/tls_extensions.cpp2
-rw-r--r--src/tls/tls_magic.h5
-rw-r--r--src/tls/tls_messages.h6
-rw-r--r--src/tls/tls_policy.h2
-rw-r--r--src/tls/tls_server.cpp18
-rw-r--r--src/tls/tls_server.h2
-rw-r--r--src/tls/tls_session_state.cpp3
13 files changed, 209 insertions, 36 deletions
diff --git a/src/tls/finished.cpp b/src/tls/finished.cpp
index c8d0173da..70b714bfd 100644
--- a/src/tls/finished.cpp
+++ b/src/tls/finished.cpp
@@ -10,7 +10,7 @@
namespace Botan {
-/**
+/*
* Create a new Finished message
*/
Finished::Finished(Record_Writer& writer,
@@ -23,7 +23,7 @@ Finished::Finished(Record_Writer& writer,
send(writer, hash);
}
-/**
+/*
* Serialize a Finished message
*/
MemoryVector<byte> Finished::serialize() const
@@ -31,7 +31,7 @@ MemoryVector<byte> Finished::serialize() const
return verification_data;
}
-/**
+/*
* Deserialize a Finished message
*/
void Finished::deserialize(const MemoryRegion<byte>& buf)
@@ -39,11 +39,13 @@ void Finished::deserialize(const MemoryRegion<byte>& buf)
verification_data = buf;
}
-/**
+/*
* Verify a Finished message
*/
-bool Finished::verify(const MemoryRegion<byte>& secret, Version_Code version,
- const TLS_Handshake_Hash& hash, Connection_Side side)
+bool Finished::verify(const MemoryRegion<byte>& secret,
+ Version_Code version,
+ const TLS_Handshake_Hash& hash,
+ Connection_Side side)
{
MemoryVector<byte> computed = compute_verify(secret, hash, side, version);
if(computed == verification_data)
@@ -51,7 +53,7 @@ bool Finished::verify(const MemoryRegion<byte>& secret, Version_Code version,
return false;
}
-/**
+/*
* Compute the verify_data
*/
MemoryVector<byte> Finished::compute_verify(const MemoryRegion<byte>& secret,
diff --git a/src/tls/hello.cpp b/src/tls/hello.cpp
index 8136eaa6b..055f92018 100644
--- a/src/tls/hello.cpp
+++ b/src/tls/hello.cpp
@@ -70,6 +70,7 @@ Client_Hello::Client_Hello(Record_Writer& writer,
TLS_Handshake_Hash& hash,
const TLS_Policy& policy,
RandomNumberGenerator& rng,
+ const MemoryRegion<byte>& reneg_info,
const std::string& hostname,
const std::string& srp_identifier) :
c_version(policy.pref_version()),
@@ -77,7 +78,9 @@ Client_Hello::Client_Hello(Record_Writer& writer,
suites(policy.ciphersuites()),
comp_methods(policy.compression()),
requested_hostname(hostname),
- requested_srp_id(srp_identifier)
+ requested_srp_id(srp_identifier),
+ has_secure_renegotiation(false),
+ renegotiation_info_bits(reneg_info)
{
send(writer, hash);
}
@@ -97,17 +100,28 @@ MemoryVector<byte> Client_Hello::serialize() const
append_tls_length_value(buf, suites, 2);
append_tls_length_value(buf, comp_methods, 1);
- printf("Requesting hostname '%s'\n", requested_hostname.c_str());
-
/*
* May not want to send extensions at all in some cases.
- * If so, should include SCSV value
+ * If so, should include SCSV value (if reneg info is empty, if
+ * not we are renegotiating with a modern server and should only
+ * send that extension.
*/
TLS_Extensions extensions;
- extensions.push_back(new Renegotation_Extension());
- extensions.push_back(new Server_Name_Indicator(requested_hostname));
- extensions.push_back(new SRP_Identifier(requested_srp_id));
+
+ // Initial handshake
+ if(renegotiation_info_bits.empty())
+ {
+ extensions.push_back(new Renegotation_Extension(renegotiation_info_bits));
+ extensions.push_back(new Server_Name_Indicator(requested_hostname));
+ extensions.push_back(new SRP_Identifier(requested_srp_id));
+ }
+ else
+ {
+ // renegotiation
+ extensions.push_back(new Renegotation_Extension(renegotiation_info_bits));
+ }
+
buf += extensions.serialize();
return buf;
@@ -285,6 +299,8 @@ MemoryVector<byte> Server_Hello::serialize() const
*/
void Server_Hello::deserialize(const MemoryRegion<byte>& buf)
{
+ has_secure_renegotiation = false;
+
if(buf.size() < 38)
throw Decoding_Error("Server_Hello: Packet corrupted");
@@ -312,6 +328,8 @@ void Server_Hello::deserialize(const MemoryRegion<byte>& buf)
{
TLS_Extension* extn = extensions.at(i);
+ printf("Extension from server %d\n", extn->type());
+
if(Renegotation_Extension* reneg = dynamic_cast<Renegotation_Extension*>(extn))
{
// checked by TLS_Client / TLS_Server as they know the handshake state
diff --git a/src/tls/tls_channel.cpp b/src/tls/tls_channel.cpp
index 8cfb15ad6..144ca659f 100644
--- a/src/tls/tls_channel.cpp
+++ b/src/tls/tls_channel.cpp
@@ -10,6 +10,8 @@
#include <botan/internal/tls_state.h>
#include <botan/loadstor.h>
+#include <stdio.h>
+
namespace Botan {
TLS_Channel::TLS_Channel(std::tr1::function<void (const byte[], size_t)> socket_output_fn,
@@ -17,8 +19,7 @@ TLS_Channel::TLS_Channel(std::tr1::function<void (const byte[], size_t)> socket_
proc_fn(proc_fn),
writer(socket_output_fn),
state(0),
- active(false),
- secure_renegotiation(false)
+ active(false)
{
}
@@ -110,7 +111,11 @@ void TLS_Channel::read_handshake(byte rec_type,
const MemoryRegion<byte>& rec_buf)
{
if(rec_type == HANDSHAKE)
+ {
+ if(!state)
+ state = new Handshake_State;
state->queue.write(&rec_buf[0], rec_buf.size());
+ }
while(true)
{
@@ -193,4 +198,43 @@ void TLS_Channel::alert(Alert_Level alert_level, Alert_Type alert_code)
}
}
+void TLS_Channel::Secure_Renegotiation_State::update(Client_Hello* client_hello)
+ {
+
+ }
+
+void TLS_Channel::Secure_Renegotiation_State::update(Server_Hello* server_hello)
+ {
+ secure_renegotiation = server_hello->secure_renegotiation();
+
+ printf("server hello says sec reneg: %d\n", secure_renegotiation);
+
+ if(secure_renegotiation)
+ {
+ const MemoryVector<byte>& data = server_hello->renegotiation_info();
+
+ if(initial_handshake)
+ {
+ if(!data.empty())
+ throw TLS_Exception(HANDSHAKE_FAILURE,
+ "Server sent renegotiation data on initial handshake");
+ }
+ else
+ {
+ if(data != for_server_hello())
+ throw TLS_Exception(HANDSHAKE_FAILURE,
+ "Server sent bad renegotiation data");
+ }
+ }
+
+ initial_handshake = false;
+ }
+
+void TLS_Channel::Secure_Renegotiation_State::update(Finished* client_finished,
+ Finished* server_finished)
+ {
+ client_verify = client_finished->verify_data();
+ server_verify = server_finished->verify_data();
+ }
+
}
diff --git a/src/tls/tls_channel.h b/src/tls/tls_channel.h
index f8b53684d..5f06181de 100644
--- a/src/tls/tls_channel.h
+++ b/src/tls/tls_channel.h
@@ -51,6 +51,11 @@ class BOTAN_DLL TLS_Channel
bool is_active() const { return active; }
/**
+ * Attempt to renegotiate the session
+ */
+ virtual void renegotiate() = 0;
+
+ /**
* Return the certificates of the peer
*/
std::vector<X509_Certificate> peer_cert_chain() const { return peer_certs; }
@@ -77,8 +82,38 @@ class BOTAN_DLL TLS_Channel
class Handshake_State* state;
- bool secure_renegotiation;
- MemoryVector<byte> client_verify_data, server_verify_data;
+ class Secure_Renegotiation_State
+ {
+ public:
+ Secure_Renegotiation_State() : initial_handshake(true),
+ secure_renegotiation(false)
+ {}
+
+ void update(class Client_Hello* client_hello);
+ void update(class Server_Hello* server_hello);
+
+ void update(class Finished* client_finished,
+ class Finished* server_finished);
+
+ const MemoryVector<byte>& for_client_hello() const
+ { return client_verify; }
+
+ MemoryVector<byte> for_server_hello() const
+ {
+ MemoryVector<byte> buf = client_verify;
+ buf += server_verify;
+ return buf;
+ }
+
+ bool supported() const { return secure_renegotiation; }
+ bool renegotiation() const { return !initial_handshake; }
+ private:
+ bool initial_handshake;
+ bool secure_renegotiation;
+ MemoryVector<byte> client_verify, server_verify;
+ };
+
+ Secure_Renegotiation_State secure_renegotiation;
bool active;
};
diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp
index 2119ca44e..a97ac65b3 100644
--- a/src/tls/tls_client.cpp
+++ b/src/tls/tls_client.cpp
@@ -12,6 +12,8 @@
#include <botan/dsa.h>
#include <botan/dh.h>
+#include <stdio.h>
+
namespace Botan {
/*
@@ -37,8 +39,11 @@ TLS_Client::TLS_Client(std::tr1::function<void (const byte[], size_t)> output_fn
state->hash,
policy,
rng,
+ secure_renegotiation.for_client_hello(),
hostname,
srp_username);
+
+ secure_renegotiation.update(state->client_hello);
}
void TLS_Client::add_client_cert(const X509_Certificate& cert,
@@ -57,33 +62,66 @@ TLS_Client::~TLS_Client()
}
/*
+* Send a new client hello to renegotiate
+*/
+void TLS_Client::renegotiate()
+ {
+ if(state)
+ return; // currently in handshake
+
+ 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());
+
+ secure_renegotiation.update(state->client_hello);
+ }
+
+/*
* Process a handshake message
*/
void TLS_Client::process_handshake_msg(Handshake_Type type,
const MemoryRegion<byte>& contents)
{
+ if(state == 0)
+ throw Unexpected_Message("Unexpected handshake message from server");
+
if(type == HELLO_REQUEST)
{
- if(state == 0)
- state = new Handshake_State();
- else
- return; // hello request in middle of handshake?
- }
+ printf("got a hello request\n");
- if(state == 0)
- throw Unexpected_Message("Unexpected handshake message");
+ Hello_Request hello_request(contents);
+
+ // Ignore request entirely if we are currently negotiating a handshake
+ if(state->client_hello)
+ return;
+
+ if(!secure_renegotiation.supported() && policy.require_secure_renegotiation())
+ {
+ delete state;
+ state = 0;
+
+ // RFC 5746 section 4.2
+ alert(WARNING, NO_RENEGOTIATION);
+ return;
+ }
+
+ state->set_expected_next(SERVER_HELLO);
+ state->client_hello = new Client_Hello(writer, state->hash, policy, rng,
+ secure_renegotiation.for_client_hello());
+
+ secure_renegotiation.update(state->client_hello);
+
+ return;
+ }
state->confirm_transition_to(type);
- if(type != HANDSHAKE_CCS && type != HELLO_REQUEST && type != FINISHED)
+ if(type != HANDSHAKE_CCS && type != FINISHED)
state->hash.update(type, contents);
- if(type == HELLO_REQUEST)
- {
- Hello_Request hello_request(contents);
- state->client_hello = new Client_Hello(writer, state->hash, policy, rng);
- }
- else if(type == SERVER_HELLO)
+ if(type == SERVER_HELLO)
{
state->server_hello = new Server_Hello(contents);
@@ -110,6 +148,8 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
writer.set_version(state->version);
reader.set_version(state->version);
+ secure_renegotiation.update(state->server_hello);
+
state->suite = CipherSuite(state->server_hello->ciphersuite());
// if resuming, next is HANDSHAKE_CCS
@@ -271,6 +311,8 @@ void TLS_Client::process_handshake_msg(Handshake_Type type,
throw TLS_Exception(DECRYPT_ERROR,
"Finished message didn't verify");
+ secure_renegotiation.update(state->client_finished, state->server_finished);
+
delete state;
state = 0;
active = true;
diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h
index a2ad232c8..279f4bc16 100644
--- a/src/tls/tls_client.h
+++ b/src/tls/tls_client.h
@@ -41,6 +41,8 @@ class BOTAN_DLL TLS_Client : public TLS_Channel
void add_client_cert(const X509_Certificate& cert,
Private_Key* cert_key);
+ void renegotiate();
+
~TLS_Client();
private:
void process_handshake_msg(Handshake_Type type,
diff --git a/src/tls/tls_extensions.cpp b/src/tls/tls_extensions.cpp
index 28523abf2..1e8060821 100644
--- a/src/tls/tls_extensions.cpp
+++ b/src/tls/tls_extensions.cpp
@@ -30,6 +30,8 @@ TLS_Extensions::TLS_Extensions(class TLS_Data_Reader& reader)
extensions.push_back(new Server_Name_Indicator(reader));
else if(extension_code == TLSEXT_SRP_IDENTIFIER)
extensions.push_back(new SRP_Identifier(reader));
+ else if(extension_code == TLSEXT_SAFE_RENEGOTIATION)
+ extensions.push_back(new Renegotation_Extension(reader));
else // unknown/unhandled extension
{
printf("Unknown extension code %d\n", extension_code);
diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h
index 535319d41..e20788ea3 100644
--- a/src/tls/tls_magic.h
+++ b/src/tls/tls_magic.h
@@ -148,7 +148,10 @@ enum Ciphersuite_Code {
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028,
+
+ /* signalling values that cannot be negotiated */
+ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF
};
/*
diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h
index 38d347d28..5ac655bec 100644
--- a/src/tls/tls_messages.h
+++ b/src/tls/tls_messages.h
@@ -76,6 +76,7 @@ class Client_Hello : public HandshakeMessage
TLS_Handshake_Hash& hash,
const TLS_Policy& policy,
RandomNumberGenerator& rng,
+ const MemoryRegion<byte>& reneg_info,
const std::string& hostname = "",
const std::string& srp_identifier = "");
@@ -284,6 +285,9 @@ class Finished : public HandshakeMessage
public:
Handshake_Type type() const { return FINISHED; }
+ MemoryVector<byte> verify_data() const
+ { return verification_data; }
+
bool verify(const MemoryRegion<byte>& buf,
Version_Code version,
const TLS_Handshake_Hash& hash,
@@ -317,7 +321,7 @@ class Hello_Request : public HandshakeMessage
public:
Handshake_Type type() const { return HELLO_REQUEST; }
- Hello_Request(Record_Writer&);
+ Hello_Request(Record_Writer& writer);
Hello_Request(const MemoryRegion<byte>& buf) { deserialize(buf); }
private:
MemoryVector<byte> serialize() const;
diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h
index 461164d2f..dd38f3574 100644
--- a/src/tls/tls_policy.h
+++ b/src/tls/tls_policy.h
@@ -36,6 +36,8 @@ class BOTAN_DLL TLS_Policy
virtual bool allow_edh_dsa() const { return true; }
virtual bool require_client_auth() const { return false; }
+ virtual bool require_secure_renegotiation() const { return true; }
+
virtual DL_Group dh_group() const;
virtual size_t rsa_export_keysize() const { return 512; }
diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp
index 090a55566..197ed4b2c 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 {
@@ -106,6 +108,20 @@ TLS_Server::~TLS_Server()
}
/*
+* Send a hello request to the client
+*/
+void TLS_Server::renegotiate()
+ {
+ if(state)
+ return; // currently in handshake
+
+ state = new Handshake_State;
+ state->set_expected_next(CLIENT_HELLO);
+ Hello_Request hello_req(writer);
+ printf("sent new hello request\n");
+ }
+
+/*
* Split up and process handshake messages
*/
void TLS_Server::read_handshake(byte rec_type,
@@ -127,7 +143,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type,
const MemoryRegion<byte>& contents)
{
if(state == 0)
- throw Unexpected_Message("Unexpected handshake message");
+ throw Unexpected_Message("Unexpected handshake message from client");
state->confirm_transition_to(type);
diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h
index a1f99a0ff..45e25f0f9 100644
--- a/src/tls/tls_server.h
+++ b/src/tls/tls_server.h
@@ -37,6 +37,8 @@ class BOTAN_DLL TLS_Server : public TLS_Channel
~TLS_Server();
+ void renegotiate();
+
/**
* Return the server name indicator, if set by the client
*/
diff --git a/src/tls/tls_session_state.cpp b/src/tls/tls_session_state.cpp
index 3b54a795e..9d8d4215d 100644
--- a/src/tls/tls_session_state.cpp
+++ b/src/tls/tls_session_state.cpp
@@ -104,7 +104,8 @@ bool TLS_Session_Manager_In_Memory::find(const MemoryVector<byte>& session_id,
return true;
}
-void TLS_Session_Manager_In_Memory::prohibit_resumption(const MemoryVector<byte>& session_id)
+void TLS_Session_Manager_In_Memory::prohibit_resumption(
+ const MemoryVector<byte>& session_id)
{
std::map<std::string, TLS_Session_Params>::iterator i =
sessions.find(hex_encode(session_id));