diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/tls_client.cpp | 7 | ||||
-rw-r--r-- | src/lib/tls/msg_client_hello.cpp | 14 | ||||
-rw-r--r-- | src/lib/tls/tls_alert.cpp | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_alert.h | 1 | ||||
-rw-r--r-- | src/lib/tls/tls_messages.h | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 15 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.h | 25 | ||||
-rw-r--r-- | src/lib/tls/tls_server.cpp | 18 | ||||
-rw-r--r-- | src/lib/tls/tls_version.cpp | 11 | ||||
-rw-r--r-- | src/lib/tls/tls_version.h | 7 |
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; |