From ee353b33dae5fd2a664ac56556e2037284735a47 Mon Sep 17 00:00:00 2001 From: lloyd Date: Sat, 17 Apr 2010 21:28:30 +0000 Subject: Add support for reading SSLv2 client hellos --- src/ssl/hello.cpp | 34 ++++++++++++++++++++++++++++++++++ src/ssl/rec_read.cpp | 29 +++++++++++++++++++++++++++++ src/ssl/tls_magic.h | 1 + src/ssl/tls_messages.h | 11 ++++++++++- src/ssl/tls_server.cpp | 19 ++++++++++++------- 5 files changed, 86 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp index a23d51c24..b93234813 100644 --- a/src/ssl/hello.cpp +++ b/src/ssl/hello.cpp @@ -106,6 +106,40 @@ SecureVector Client_Hello::serialize() const return buf; } +void Client_Hello::deserialize_sslv2(const MemoryRegion& buf) + { + if(buf.size() < 12 || buf[0] != 1) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + const u32bit cipher_spec_len = make_u16bit(buf[3], buf[4]); + const u32bit sess_id_len = make_u16bit(buf[5], buf[6]); + const u32bit challenge_len = make_u16bit(buf[7], buf[8]); + + const u32bit expected_size = + (9 + sess_id_len + cipher_spec_len + challenge_len); + + if(buf.size() != expected_size) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + if(sess_id_len != 0 || cipher_spec_len % 3 != 0 || + (challenge_len < 16 || challenge_len > 32)) + { + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + } + + for(u32bit i = 9; i != 9 + cipher_spec_len; i += 3) + { + if(buf[i] != 0) // a SSLv2 cipherspec; ignore it + continue; + + suites.push_back(make_u16bit(buf[i+1], buf[i+2])); + } + + c_version = static_cast(make_u16bit(buf[1], buf[2])); + + c_random.set(&buf[9+cipher_spec_len+sess_id_len], challenge_len); + } + /** * Deserialize a Client Hello message */ diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp index 8f8e5dc1e..f07744c2a 100644 --- a/src/ssl/rec_read.cpp +++ b/src/ssl/rec_read.cpp @@ -124,6 +124,35 @@ u32bit Record_Reader::get_record(byte& msg_type, */ input_queue.peek(header, sizeof(header)); + // SSLv2-format client hello? + if(header[0] & 0x80 && header[2] == 1 && header[3] == 3) + { + u32bit record_len = make_u16bit(header[0], header[1]) & 0x7FFF; + + if(have_in_queue < record_len + 2) + return (record_len + 2 - have_in_queue); + + msg_type = HANDSHAKE; + output.resize(record_len + 4); + + input_queue.read(&output[2], record_len + 2); + output[0] = CLIENT_HELLO_SSLV2; + output[1] = 0; + output[2] = header[0] & 0x7F; + output[3] = header[1]; + + return 0; + } + + if(header[0] != CHANGE_CIPHER_SPEC && + header[0] != ALERT && + header[0] != HANDSHAKE && + header[0] != APPLICATION_DATA) + { + throw TLS_Exception(UNEXPECTED_MESSAGE, + "Record_Reader: Unknown record type"); + } + const u16bit version = make_u16bit(header[1], header[2]); const u16bit record_len = make_u16bit(header[3], header[4]); diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h index 35a9fc925..25cd0986a 100644 --- a/src/ssl/tls_magic.h +++ b/src/ssl/tls_magic.h @@ -40,6 +40,7 @@ enum Record_Type { enum Handshake_Type { HELLO_REQUEST = 0, CLIENT_HELLO = 1, + CLIENT_HELLO_SSLV2 = 255, // not a wire value SERVER_HELLO = 2, CERTIFICATE = 11, SERVER_KEX = 12, diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h index 1f72c05f7..42f81b1fe 100644 --- a/src/ssl/tls_messages.h +++ b/src/ssl/tls_messages.h @@ -56,10 +56,19 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage Client_Hello(RandomNumberGenerator& rng, Record_Writer&, const TLS_Policy*, HandshakeHash&); - Client_Hello(const MemoryRegion& buf) { deserialize(buf); } + Client_Hello(const MemoryRegion& buf, + Handshake_Type type) + { + if(type == CLIENT_HELLO) + deserialize(buf); + else + deserialize_sslv2(buf); + } + private: SecureVector serialize() const; void deserialize(const MemoryRegion&); + void deserialize_sslv2(const MemoryRegion&); Version_Code c_version; SecureVector sess_id, c_random; diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp index 4e9c3583f..1c8d28c95 100644 --- a/src/ssl/tls_server.cpp +++ b/src/ssl/tls_server.cpp @@ -43,7 +43,7 @@ void server_check_state(Handshake_Type new_msg, Handshake_State* state) Unexpected_Message("State transition error from " + err) {} }; - if(new_msg == CLIENT_HELLO) + if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2) { if(state->server_hello) throw State_Transition_Error("ClientHello"); @@ -330,18 +330,23 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, if(type != HANDSHAKE_CCS && type != FINISHED) { - state->hash.update(static_cast(type)); - u32bit record_length = contents.size(); - for(u32bit j = 0; j != 3; j++) - state->hash.update(get_byte(j+1, record_length)); + + if(type != CLIENT_HELLO_SSLV2) + { + state->hash.update(static_cast(type)); + u32bit record_length = contents.size(); + for(u32bit j = 0; j != 3; j++) + state->hash.update(get_byte(j+1, record_length)); + } + state->hash.update(contents); } - if(type == CLIENT_HELLO) + if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) { server_check_state(type, state); - state->client_hello = new Client_Hello(contents); + state->client_hello = new Client_Hello(contents, type); client_requested_hostname = state->client_hello->hostname(); -- cgit v1.2.3