diff options
author | lloyd <[email protected]> | 2012-07-12 21:25:46 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-07-12 21:25:46 +0000 |
commit | 43836c6fd15a944dce1ca25bb0d019ede3ef75e7 (patch) | |
tree | a6ea3bd16cb4b4d2ea94428ccafaa2bd54d8ba6a | |
parent | 71c8f3803819464db90226c22e77f5a13ef2c38d (diff) |
Changes to version handling in support of DTLS work.
Add a few 'feature tests' to Protocol_Version which helps avoid some
explicit comparisons. Additionally, remove the relational comparisons,
except for operator> which is still used in a few locations.
TLS::Policy has changed and no longer has min_version. The new hook
that replaces it is acceptable_protocol_version, which should return
true if and only if we are willing to negotiate the version
returned. This leads to a somewhat cleaner result and additionally
allows one to do maybe interesting though mostly useless things like
allowing TLS 1.0 or 1.2 but not 1.1.
Fix the version sent in the (unused) DTLS hello verify message.
-rw-r--r-- | src/tls/c_hello.cpp | 2 | ||||
-rw-r--r-- | src/tls/c_kex.cpp | 6 | ||||
-rw-r--r-- | src/tls/cert_req.cpp | 4 | ||||
-rw-r--r-- | src/tls/cert_ver.cpp | 2 | ||||
-rw-r--r-- | src/tls/hello_verify.cpp | 2 | ||||
-rw-r--r-- | src/tls/rec_read.cpp | 2 | ||||
-rw-r--r-- | src/tls/rec_wri.cpp | 2 | ||||
-rw-r--r-- | src/tls/s_hello.cpp | 9 | ||||
-rw-r--r-- | src/tls/s_kex.cpp | 2 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 6 | ||||
-rw-r--r-- | src/tls/tls_handshake_state.cpp | 20 | ||||
-rw-r--r-- | src/tls/tls_policy.cpp | 7 | ||||
-rw-r--r-- | src/tls/tls_policy.h | 4 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 21 | ||||
-rw-r--r-- | src/tls/tls_version.cpp | 53 | ||||
-rw-r--r-- | src/tls/tls_version.h | 50 |
16 files changed, 114 insertions, 78 deletions
diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp index 9956c5e28..c9249ab9a 100644 --- a/src/tls/c_hello.cpp +++ b/src/tls/c_hello.cpp @@ -190,7 +190,7 @@ std::vector<byte> Client_Hello::serialize() const extensions.add(new Supported_Elliptic_Curves(m_supported_curves)); - if(m_version >= Protocol_Version::TLS_V12) + if(m_version.supports_negotiable_signature_algorithms()) extensions.add(new Signature_Algorithms(m_supported_algos)); extensions.add(new Heartbeat_Support_Indicator(true)); diff --git a/src/tls/c_kex.cpp b/src/tls/c_kex.cpp index 836edf8ce..28449e614 100644 --- a/src/tls/c_kex.cpp +++ b/src/tls/c_kex.cpp @@ -238,11 +238,11 @@ Client_Key_Exchange::Client_Key_Exchange(Record_Writer& writer, if(const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(pub_key.get())) { - const Protocol_Version pref_version = state->client_hello->version(); + const Protocol_Version offered_version = state->client_hello->version(); pre_master = rng.random_vec(48); - pre_master[0] = pref_version.major_version(); - pre_master[1] = pref_version.minor_version(); + pre_master[0] = offered_version.major_version(); + pre_master[1] = offered_version.minor_version(); PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); diff --git a/src/tls/cert_req.cpp b/src/tls/cert_req.cpp index f97238d54..4578148f5 100644 --- a/src/tls/cert_req.cpp +++ b/src/tls/cert_req.cpp @@ -64,7 +64,7 @@ Certificate_Req::Certificate_Req(Record_Writer& writer, cert_key_types.push_back("DSA"); cert_key_types.push_back("ECDSA"); - if(version >= Protocol_Version::TLS_V12) + if(version.supports_negotiable_signature_algorithms()) { std::vector<std::string> hashes = policy.allowed_signature_hashes(); std::vector<std::string> sigs = policy.allowed_signature_methods(); @@ -100,7 +100,7 @@ Certificate_Req::Certificate_Req(const std::vector<byte>& buf, cert_key_types.push_back(cert_type_name); } - if(version >= Protocol_Version::TLS_V12) + if(version.supports_negotiable_signature_algorithms()) { std::vector<byte> sig_hash_algs = reader.get_range_vector<byte>(2, 2, 65534); diff --git a/src/tls/cert_ver.cpp b/src/tls/cert_ver.cpp index ae00536df..870d70951 100644 --- a/src/tls/cert_ver.cpp +++ b/src/tls/cert_ver.cpp @@ -58,7 +58,7 @@ Certificate_Verify::Certificate_Verify(const std::vector<byte>& buf, { TLS_Data_Reader reader(buf); - if(version >= Protocol_Version::TLS_V12) + if(version.supports_negotiable_signature_algorithms()) { hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte()); sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte()); diff --git a/src/tls/hello_verify.cpp b/src/tls/hello_verify.cpp index c77076e4c..c735d9987 100644 --- a/src/tls/hello_verify.cpp +++ b/src/tls/hello_verify.cpp @@ -47,7 +47,7 @@ std::vector<byte> Hello_Verify_Request::serialize() const negotiated (RFC 6347, section 4.2.1) */ - Protocol_Version format_version(Protocol_Version::TLS_V11); + Protocol_Version format_version(Protocol_Version::DTLS_V10); std::vector<byte> bits; bits.push_back(format_version.major_version()); diff --git a/src/tls/rec_read.cpp b/src/tls/rec_read.cpp index fa4d9d00c..5f01ef719 100644 --- a/src/tls/rec_read.cpp +++ b/src/tls/rec_read.cpp @@ -110,7 +110,7 @@ void Record_Reader::activate(Connection_Side side, ); m_block_size = block_size_of(cipher_algo); - if(m_version >= Protocol_Version::TLS_V11) + if(m_version.supports_explicit_cbc_ivs()) m_iv_size = m_block_size; else m_iv_size = 0; diff --git a/src/tls/rec_wri.cpp b/src/tls/rec_wri.cpp index 082cdd880..b5b9e826c 100644 --- a/src/tls/rec_wri.cpp +++ b/src/tls/rec_wri.cpp @@ -118,7 +118,7 @@ void Record_Writer::activate(Connection_Side side, ); m_block_size = block_size_of(cipher_algo); - if(m_version >= Protocol_Version::TLS_V11) + if(m_version.supports_explicit_cbc_ivs()) m_iv_size = m_block_size; else m_iv_size = 0; diff --git a/src/tls/s_hello.cpp b/src/tls/s_hello.cpp index d4cc4a1ab..3b65b39f1 100644 --- a/src/tls/s_hello.cpp +++ b/src/tls/s_hello.cpp @@ -69,15 +69,6 @@ Server_Hello::Server_Hello(const std::vector<byte>& buf) m_version = Protocol_Version(major_version, minor_version); - if(m_version != Protocol_Version::SSL_V3 && - m_version != Protocol_Version::TLS_V10 && - m_version != Protocol_Version::TLS_V11 && - m_version != Protocol_Version::TLS_V12) - { - throw TLS_Exception(Alert::PROTOCOL_VERSION, - "Server_Hello: Unsupported server version"); - } - m_random = reader.get_fixed<byte>(32); m_session_id = reader.get_range<byte>(1, 0, 32); diff --git a/src/tls/s_kex.cpp b/src/tls/s_kex.cpp index e6ea14dbe..834dff979 100644 --- a/src/tls/s_kex.cpp +++ b/src/tls/s_kex.cpp @@ -216,7 +216,7 @@ Server_Key_Exchange::Server_Key_Exchange(const std::vector<byte>& buf, if(sig_algo != "") { - if(version >= Protocol_Version::TLS_V12) + if(version.supports_negotiable_signature_algorithms()) { m_hash_algo = Signature_Algorithms::hash_algo_name(reader.get_byte()); m_sig_algo = Signature_Algorithms::sig_algo_name(reader.get_byte()); diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 2915fc68d..5b9b4868c 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -256,13 +256,13 @@ void Client::process_handshake_msg(Handshake_Type type, if(m_state->version() > m_state->client_hello->version()) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "Client: Server replied with bad version"); + "Server replied with later version than in hello"); } - if(m_state->version() < m_policy.min_version()) + if(!m_policy.acceptable_protocol_version(m_state->version())) { throw TLS_Exception(Alert::PROTOCOL_VERSION, - "Client: Server is too old for specified policy"); + "Server version is unacceptable by policy"); } if(m_state->suite.sig_algo() != "") diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp index d730bb492..8bb251b73 100644 --- a/src/tls/tls_handshake_state.cpp +++ b/src/tls/tls_handshake_state.cpp @@ -202,7 +202,7 @@ std::string choose_hash(const std::string& sig_algo, Client_Hello* client_hello, Certificate_Req* cert_req) { - if(negotiated_version < Protocol_Version::TLS_V12) + if(!negotiated_version.supports_negotiable_signature_algorithms()) { if(for_client_auth && negotiated_version == Protocol_Version::SSL_V3) return "Raw"; @@ -264,7 +264,7 @@ Handshake_State::choose_sig_format(const Private_Key* key, client_hello, cert_req); - if(this->version() >= Protocol_Version::TLS_V12) + if(this->version().supports_negotiable_signature_algorithms()) { hash_algo_out = hash_algo; sig_algo_out = sig_algo; @@ -302,12 +302,7 @@ Handshake_State::understand_sig_format(const Public_Key* key, Or not? */ - if(this->version() < Protocol_Version::TLS_V12) - { - if(hash_algo != "" || sig_algo != "") - throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); - } - else + if(this->version().supports_negotiable_signature_algorithms()) { if(hash_algo == "") throw Decoding_Error("Counterparty did not send hash/sig IDS"); @@ -315,6 +310,11 @@ Handshake_State::understand_sig_format(const Public_Key* key, if(sig_algo != algo_name) throw Decoding_Error("Counterparty sent inconsistent key and sig types"); } + else + { + if(hash_algo != "" || sig_algo != "") + throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); + } if(algo_name == "RSA") { @@ -322,7 +322,7 @@ Handshake_State::understand_sig_format(const Public_Key* key, { hash_algo = "Raw"; } - else if(this->version() < Protocol_Version::TLS_V12) + else if(!this->version().supports_negotiable_signature_algorithms()) { hash_algo = "TLS.Digest.0"; } @@ -336,7 +336,7 @@ Handshake_State::understand_sig_format(const Public_Key* key, { hash_algo = "Raw"; } - else if(this->version() < Protocol_Version::TLS_V12) + else if(!this->version().supports_negotiable_signature_algorithms()) { hash_algo = "SHA-1"; } diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp index c48ed274e..99ac66369 100644 --- a/src/tls/tls_policy.cpp +++ b/src/tls/tls_policy.cpp @@ -130,9 +130,12 @@ u32bit Policy::session_ticket_lifetime() const return 86400; // 1 day } -Protocol_Version Policy::min_version() const +bool Policy::acceptable_protocol_version(const Protocol_Version& version) const { - return Protocol_Version::SSL_V3; + return (version == Protocol_Version::SSL_V3 || + version == Protocol_Version::TLS_V10 || + version == Protocol_Version::TLS_V11 || + version == Protocol_Version::TLS_V12); } Protocol_Version Policy::pref_version() const diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h index f6d276af9..798ecfaee 100644 --- a/src/tls/tls_policy.h +++ b/src/tls/tls_policy.h @@ -110,9 +110,9 @@ class BOTAN_DLL Policy virtual u32bit session_ticket_lifetime() const; /** - * @return the minimum version that we are willing to negotiate + * @return true if and only if we are willing to accept this version */ - virtual Protocol_Version min_version() const; + virtual bool acceptable_protocol_version(const Protocol_Version& version) const; /** * @return the version we would prefer to negotiate diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index e89ec7b4a..20430be86 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -282,13 +282,20 @@ void Server::process_handshake_msg(Handshake_Type type, Protocol_Version client_version = m_state->client_hello->version(); - if(client_version < m_policy.min_version()) + if(!m_policy.acceptable_protocol_version(m_state->version())) + { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client version is unacceptable by policy"); + } - if(client_version > m_policy.pref_version()) + if(!client_version.known_version()) { - m_state->set_version(m_policy.pref_version()); + /* + This isn't a version we know. This implies this is a later + version than any version defined as of 2012. Offer them + the latest version we know. + */ + m_state->set_version(Protocol_Version::TLS_V12); } else { @@ -304,11 +311,7 @@ void Server::process_handshake_msg(Handshake_Type type, * than what it initially negotiated, reject as a probable * attack. */ - if(client_version > prev_version) - { - m_state->set_version(prev_version); - } - else + if(prev_version > client_version) { throw TLS_Exception(Alert::PROTOCOL_VERSION, "Client negotiated " + @@ -316,6 +319,8 @@ void Server::process_handshake_msg(Handshake_Type type, " then renegotiated with " + client_version.to_string()); } + + m_state->set_version(prev_version); } else { diff --git a/src/tls/tls_version.cpp b/src/tls/tls_version.cpp index 82dce0be9..4ab1664d8 100644 --- a/src/tls/tls_version.cpp +++ b/src/tls/tls_version.cpp @@ -6,6 +6,7 @@ */ #include <botan/tls_version.h> +#include <botan/tls_exceptn.h> #include <botan/parsing.h> namespace Botan { @@ -17,15 +18,55 @@ std::string Protocol_Version::to_string() const const byte maj = major_version(); const byte min = minor_version(); - // Some very new or very old protocol? - if(maj != 3) - return "Protocol " + std::to_string(maj) + "." + std::to_string(min); - if(maj == 3 && min == 0) return "SSL v3"; - // The TLS v1.[0123...] case - return "TLS v1." + std::to_string(min-1); + if(maj == 3 && min >= 1) // TLS v1.x + return "TLS v1." + std::to_string(min-1); + + if(maj == 254) // DTLS 1.x + return "DTLS v1." + std::to_string(256 - min); + + // Some very new or very old protocol (or bogus data) + return "Unknown " + std::to_string(maj) + "." + std::to_string(min); + } + +bool Protocol_Version::is_datagram_protocol() const + { + return major_version() == 254; + } + +bool Protocol_Version::operator>(const Protocol_Version& other) const + { + if(this->is_datagram_protocol() != other.is_datagram_protocol()) + throw TLS_Exception(Alert::PROTOCOL_VERSION, + "Version comparing " + to_string() + + " with " + other.to_string()); + + return m_version > other.m_version; + } + +bool Protocol_Version::known_version() const + { + // Don't include DTLS yet here as we can't actually process it + return (m_version == Protocol_Version::SSL_V3 || + m_version == Protocol_Version::TLS_V10 || + m_version == Protocol_Version::TLS_V11 || + m_version == Protocol_Version::TLS_V12); + } + +bool Protocol_Version::supports_negotiable_signature_algorithms() const + { + return (m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V12); + } + +bool Protocol_Version::supports_explicit_cbc_ivs() const + { + return (m_version == Protocol_Version::TLS_V11 || + m_version == Protocol_Version::TLS_V12 || + m_version == Protocol_Version::DTLS_V10 || + m_version == Protocol_Version::DTLS_V12); } } diff --git a/src/tls/tls_version.h b/src/tls/tls_version.h index 18d9f1674..4d1beb8cb 100644 --- a/src/tls/tls_version.h +++ b/src/tls/tls_version.h @@ -25,7 +25,10 @@ class BOTAN_DLL Protocol_Version SSL_V3 = 0x0300, TLS_V10 = 0x0301, TLS_V11 = 0x0302, - TLS_V12 = 0x0303 + TLS_V12 = 0x0303, + + DTLS_V10 = 0xFEFF, + DTLS_V12 = 0xFEFD }; Protocol_Version() : m_version(0) {} @@ -49,6 +52,11 @@ class BOTAN_DLL Protocol_Version bool valid() const { return (m_version != 0); } /** + * @return true if this is a protocol version we know about + */ + bool known_version() const; + + /** * @return major version of the protocol version */ byte major_version() const { return get_byte(0, m_version); } @@ -64,52 +72,40 @@ class BOTAN_DLL Protocol_Version std::string to_string() const; /** - * @return if this version is equal to other + * @return true iff this is a DTLS version */ - bool operator==(const Protocol_Version& other) const - { - return (m_version == other.m_version); - } + bool is_datagram_protocol() const; /** - * @return if this version is not equal to other + * @return true if this version supports negotiable signature algorithms */ - bool operator!=(const Protocol_Version& other) const - { - return (m_version != other.m_version); - } + bool supports_negotiable_signature_algorithms() const; /** - * @return if this version is later than or equal to other + * @return true if this version uses explicit IVs for block ciphers */ - bool operator>=(const Protocol_Version& other) const - { - return (m_version >= other.m_version); - } + bool supports_explicit_cbc_ivs() const; /** - * @return if this version is later than other + * @return if this version is equal to other */ - bool operator>(const Protocol_Version& other) const + bool operator==(const Protocol_Version& other) const { - return (m_version > other.m_version); + return (m_version == other.m_version); } /** - * @return if this version is earlier than or equal to other + * @return if this version is not equal to other */ - bool operator<=(const Protocol_Version& other) const + bool operator!=(const Protocol_Version& other) const { - return (m_version <= other.m_version); + return (m_version != other.m_version); } /** - * @return if this version is earlier than other + * @return if this version is later than other */ - bool operator<(const Protocol_Version& other) const - { - return (m_version < other.m_version); - } + bool operator>(const Protocol_Version& other) const; private: u16bit m_version; |