aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorlloyd <[email protected]>2014-10-31 10:18:47 +0000
committerlloyd <[email protected]>2014-10-31 10:18:47 +0000
commit05d29e973175889685a695d34cf810992497b316 (patch)
tree1863a1819f3c02a5b27f6f9266ce2c31bf408ab5 /src
parent8916b9e071503bc8033370c9806075e0b083e84d (diff)
Add TLS fallback signalling (draft-ietf-tls-downgrade-scsv-00)
Diffstat (limited to 'src')
-rw-r--r--src/cmd/tls_client.cpp7
-rw-r--r--src/lib/tls/msg_client_hello.cpp14
-rw-r--r--src/lib/tls/tls_alert.cpp2
-rw-r--r--src/lib/tls/tls_alert.h1
-rw-r--r--src/lib/tls/tls_messages.h2
-rw-r--r--src/lib/tls/tls_policy.cpp15
-rw-r--r--src/lib/tls/tls_policy.h25
-rw-r--r--src/lib/tls/tls_server.cpp18
-rw-r--r--src/lib/tls/tls_version.cpp11
-rw-r--r--src/lib/tls/tls_version.h7
10 files changed, 71 insertions, 31 deletions
diff --git a/src/cmd/tls_client.cpp b/src/cmd/tls_client.cpp
index 18b8044b5..9130cd085 100644
--- a/src/cmd/tls_client.cpp
+++ b/src/cmd/tls_client.cpp
@@ -158,7 +158,7 @@ int tls_client_main(int argc, char* argv[])
std::string host = argv[1];
u32bit port = argc >= 3 ? Botan::to_u32bit(argv[2]) : 443;
- std::string transport = argc >= 4 ? argv[3] : "tcp";
+ const std::string transport = argc >= 4 ? argv[3] : "tcp";
int sockfd = connect_to_host(host, port, transport);
@@ -167,10 +167,7 @@ int tls_client_main(int argc, char* argv[])
std::bind(stream_socket_write, sockfd, _1, _2) :
std::bind(dgram_socket_write, sockfd, _1, _2);
- auto version =
- (transport == "tcp") ?
- TLS::Protocol_Version::latest_tls_version() :
- TLS::Protocol_Version::latest_dtls_version();
+ auto version = policy.latest_supported_version(transport != "tcp");
TLS::Client client(socket_write,
process_data,
diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp
index 087fefcb4..744b40810 100644
--- a/src/lib/tls/msg_client_hello.cpp
+++ b/src/lib/tls/msg_client_hello.cpp
@@ -17,7 +17,8 @@ namespace Botan {
namespace TLS {
enum {
- TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF
+ TLS_EMPTY_RENEGOTIATION_INFO_SCSV = 0x00FF,
+ TLS_FALLBACK_SCSV = 0x5600
};
std::vector<byte> make_hello_random(RandomNumberGenerator& rng)
@@ -90,6 +91,12 @@ Client_Hello::Client_Hello(Handshake_IO& io,
if(reneg_info.empty() && next_protocol)
m_extensions.add(new Next_Protocol_Notification());
+ BOTAN_ASSERT(policy.acceptable_protocol_version(version),
+ "Our policy accepts the version we are offering");
+
+ if(policy.send_fallback_scsv(version))
+ m_suites.push_back(TLS_FALLBACK_SCSV);
+
hash.update(io.send(*this));
}
@@ -271,6 +278,11 @@ void Client_Hello::deserialize(const std::vector<byte>& buf)
}
}
+bool Client_Hello::sent_fallback_scsv() const
+ {
+ return offered_suite(static_cast<u16bit>(TLS_FALLBACK_SCSV));
+ }
+
/*
* Check if we offered this ciphersuite
*/
diff --git a/src/lib/tls/tls_alert.cpp b/src/lib/tls/tls_alert.cpp
index 15bb2a2dc..47e1730ea 100644
--- a/src/lib/tls/tls_alert.cpp
+++ b/src/lib/tls/tls_alert.cpp
@@ -84,6 +84,8 @@ std::string Alert::type_string() const
return "insufficient_security";
case INTERNAL_ERROR:
return "internal_error";
+ case INAPPROPRIATE_FALLBACK:
+ return "inappropriate_fallback";
case USER_CANCELED:
return "user_canceled";
case NO_RENEGOTIATION:
diff --git a/src/lib/tls/tls_alert.h b/src/lib/tls/tls_alert.h
index bf32178ee..089fe8ba3 100644
--- a/src/lib/tls/tls_alert.h
+++ b/src/lib/tls/tls_alert.h
@@ -47,6 +47,7 @@ class BOTAN_DLL Alert
PROTOCOL_VERSION = 70,
INSUFFICIENT_SECURITY = 71,
INTERNAL_ERROR = 80,
+ INAPPROPRIATE_FALLBACK = 86,
USER_CANCELED = 90,
NO_RENEGOTIATION = 100,
UNSUPPORTED_EXTENSION = 110,
diff --git a/src/lib/tls/tls_messages.h b/src/lib/tls/tls_messages.h
index 570ca9591..6cfb2f5bf 100644
--- a/src/lib/tls/tls_messages.h
+++ b/src/lib/tls/tls_messages.h
@@ -71,6 +71,8 @@ class Client_Hello : public Handshake_Message
bool offered_suite(u16bit ciphersuite) const;
+ bool sent_fallback_scsv() const;
+
std::vector<std::pair<std::string, std::string>> supported_algos() const
{
if(Signature_Algorithms* sigs = m_extensions.get<Signature_Algorithms>())
diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp
index c1f2c311c..602667f05 100644
--- a/src/lib/tls/tls_policy.cpp
+++ b/src/lib/tls/tls_policy.cpp
@@ -139,13 +139,26 @@ u32bit Policy::session_ticket_lifetime() const
return 86400; // 1 day
}
+bool Policy::send_fallback_scsv(const Protocol_Version& version) const
+ {
+ return version != latest_supported_version(version.is_datagram_protocol());
+ }
+
bool Policy::acceptable_protocol_version(Protocol_Version version) const
{
// By default require TLS to minimize surprise
if(version.is_datagram_protocol())
return false;
- return (version > Protocol_Version::SSL_V3);
+ return (version >= Protocol_Version::TLS_V10);
+ }
+
+Protocol_Version Policy::latest_supported_version(bool datagram) const
+ {
+ if(datagram)
+ return Protocol_Version::latest_dtls_version();
+ else
+ return Protocol_Version::latest_tls_version();
}
bool Policy::acceptable_ciphersuite(const Ciphersuite&) const
diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h
index 9aaa1745c..a109ecc44 100644
--- a/src/lib/tls/tls_policy.h
+++ b/src/lib/tls/tls_policy.h
@@ -123,11 +123,32 @@ class BOTAN_DLL Policy
/**
* @return true if and only if we are willing to accept this version
- * Default accepts only TLS, so override if you want to enable DTLS
- * in your application.
+ * Default accepts TLS v1.0 and later.
+
+ * Override if you want to allow negotiating SSLv3 (*not recommended*)
+ * Override if you want to enable DTLS in your application.
*/
virtual bool acceptable_protocol_version(Protocol_Version version) const;
+ /**
+ * Returns the more recent protocol version we are willing to
+ * use, for either TLS or DTLS depending on datagram param.
+ * Shouldn't ever need to override this unless you want to allow
+ * a user to disable use of TLS v1.2 (which is *not recommended*)
+ */
+ virtual Protocol_Version latest_supported_version(bool datagram) const;
+
+ /**
+ * When offering this version, should we send a fallback SCSV?
+ * Default returns true iff version is not the latest version the
+ * policy allows, exists to allow override in case of interop problems.
+ */
+ virtual bool send_fallback_scsv(const Protocol_Version& version) const;
+
+ /**
+ * Allows policy to reject any ciphersuites which are undesirable
+ * for whatever reason without having to reimplement ciphersuite_list
+ */
virtual bool acceptable_ciphersuite(const Ciphersuite& suite) const;
/**
diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp
index 6fe266989..71e8d1d14 100644
--- a/src/lib/tls/tls_server.cpp
+++ b/src/lib/tls/tls_server.cpp
@@ -291,10 +291,13 @@ void Server::process_handshake_msg(const Handshake_State* active_state,
state.client_hello(new Client_Hello(contents, type));
- Protocol_Version client_version = state.client_hello()->version();
+ const Protocol_Version client_version = state.client_hello()->version();
Protocol_Version negotiated_version;
+ const Protocol_Version latest_supported =
+ m_policy.latest_supported_version(client_version.is_datagram_protocol());
+
if((initial_handshake && client_version.known_version()) ||
(!initial_handshake && client_version == active_state->version()))
{
@@ -329,10 +332,10 @@ void Server::process_handshake_msg(const Handshake_State* active_state,
else
{
/*
- New negotiation using a version we don't know. Offer
- them the best we currently know.
+ New negotiation using a version we don't know. Offer them the
+ best we currently know and support
*/
- negotiated_version = client_version.best_known_match();
+ negotiated_version = latest_supported;
}
if(!m_policy.acceptable_protocol_version(negotiated_version))
@@ -342,6 +345,13 @@ void Server::process_handshake_msg(const Handshake_State* active_state,
" is unacceptable by policy");
}
+ if(state.client_hello()->sent_fallback_scsv())
+ {
+ if(latest_supported > client_version)
+ throw TLS_Exception(Alert::INAPPROPRIATE_FALLBACK,
+ "Client signalled fallback SCSV, possible attack");
+ }
+
if(!initial_handshake && state.client_hello()->next_protocol_notification())
throw TLS_Exception(Alert::HANDSHAKE_FAILURE,
"Client included NPN extension for renegotiation");
diff --git a/src/lib/tls/tls_version.cpp b/src/lib/tls/tls_version.cpp
index 7b880d98c..71dac4048 100644
--- a/src/lib/tls/tls_version.cpp
+++ b/src/lib/tls/tls_version.cpp
@@ -49,17 +49,6 @@ bool Protocol_Version::operator>(const Protocol_Version& other) const
return m_version > other.m_version;
}
-Protocol_Version Protocol_Version::best_known_match() const
- {
- if(known_version())
- return *this; // known version is its own best match
-
- if(is_datagram_protocol())
- return Protocol_Version::DTLS_V12;
- else
- return Protocol_Version::TLS_V12;
- }
-
bool Protocol_Version::known_version() const
{
return (m_version == Protocol_Version::SSL_V3 ||
diff --git a/src/lib/tls/tls_version.h b/src/lib/tls/tls_version.h
index 9fd71b629..2e2969fbf 100644
--- a/src/lib/tls/tls_version.h
+++ b/src/lib/tls/tls_version.h
@@ -82,13 +82,6 @@ class BOTAN_DLL Protocol_Version
std::string to_string() const;
/**
- * If this version is known, return that. Otherwise return the
- * best (most recent) version we know of.
- * @return best matching protocol version
- */
- Protocol_Version best_known_match() const;
-
- /**
* @return true iff this is a DTLS version
*/
bool is_datagram_protocol() const;