aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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));