Re-added support for parsing and handling SSLv2 Client Hello messages
If the define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO is enabled,
the SSL Server module can handle the old SSLv2 Client Hello messages.
It has been updated to deny SSLv2 Client Hello messages during
renegotiation.
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index df57cb3..325440d 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -191,6 +191,216 @@
return( 0 );
}
+#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+static int ssl_parse_client_hello_v2( ssl_context *ssl )
+{
+ int ret;
+ unsigned int i, j;
+ size_t n;
+ unsigned int ciph_len, sess_len, chal_len;
+ unsigned char *buf, *p;
+
+ SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) );
+
+ if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE )
+ {
+ SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) );
+
+ if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+ return( ret );
+
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ buf = ssl->in_hdr;
+
+ SSL_DEBUG_BUF( 4, "record header", buf, 5 );
+
+ SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d",
+ buf[2] ) );
+ SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d",
+ ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) );
+ SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]",
+ buf[3], buf[4] ) );
+
+ /*
+ * SSLv2 Client Hello
+ *
+ * Record layer:
+ * 0 . 1 message length
+ *
+ * SSL layer:
+ * 2 . 2 message type
+ * 3 . 4 protocol version
+ */
+ if( buf[2] != SSL_HS_CLIENT_HELLO ||
+ buf[3] != SSL_MAJOR_VERSION_3 )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF;
+
+ if( n < 17 || n > 512 )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ ssl->major_ver = SSL_MAJOR_VERSION_3;
+ ssl->minor_ver = ( buf[4] <= SSL_MINOR_VERSION_3 )
+ ? buf[4] : SSL_MINOR_VERSION_3;
+
+ if( ssl->minor_ver < ssl->min_minor_ver )
+ {
+ SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum"
+ " [%d:%d] < [%d:%d]", ssl->major_ver, ssl->minor_ver,
+ ssl->min_major_ver, ssl->min_minor_ver ) );
+
+ ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL,
+ SSL_ALERT_MSG_PROTOCOL_VERSION );
+ return( POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
+ }
+
+ ssl->max_major_ver = buf[3];
+ ssl->max_minor_ver = buf[4];
+
+ if( ( ret = ssl_fetch_input( ssl, 2 + n ) ) != 0 )
+ {
+ SSL_DEBUG_RET( 1, "ssl_fetch_input", ret );
+ return( ret );
+ }
+
+ ssl->handshake->update_checksum( ssl, buf + 2, n );
+
+ buf = ssl->in_msg;
+ n = ssl->in_left - 5;
+
+ /*
+ * 0 . 1 ciphersuitelist length
+ * 2 . 3 session id length
+ * 4 . 5 challenge length
+ * 6 . .. ciphersuitelist
+ * .. . .. session id
+ * .. . .. challenge
+ */
+ SSL_DEBUG_BUF( 4, "record contents", buf, n );
+
+ ciph_len = ( buf[0] << 8 ) | buf[1];
+ sess_len = ( buf[2] << 8 ) | buf[3];
+ chal_len = ( buf[4] << 8 ) | buf[5];
+
+ SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d",
+ ciph_len, sess_len, chal_len ) );
+
+ /*
+ * Make sure each parameter length is valid
+ */
+ if( ciph_len < 3 || ( ciph_len % 3 ) != 0 )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ if( sess_len > 32 )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ if( chal_len < 8 || chal_len > 32 )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ if( n != 6 + ciph_len + sess_len + chal_len )
+ {
+ SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist",
+ buf + 6, ciph_len );
+ SSL_DEBUG_BUF( 3, "client hello, session id",
+ buf + 6 + ciph_len, sess_len );
+ SSL_DEBUG_BUF( 3, "client hello, challenge",
+ buf + 6 + ciph_len + sess_len, chal_len );
+
+ p = buf + 6 + ciph_len;
+ ssl->session_negotiate->length = sess_len;
+ memset( ssl->session_negotiate->id, 0, sizeof( ssl->session_negotiate->id ) );
+ memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->length );
+
+ p += sess_len;
+ memset( ssl->handshake->randbytes, 0, 64 );
+ memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len );
+
+ /*
+ * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+ */
+ for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 )
+ {
+ if( p[0] == 0 && p[1] == 0 && p[2] == SSL_EMPTY_RENEGOTIATION_INFO )
+ {
+ SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) );
+ if( ssl->renegotiation == SSL_RENEGOTIATION )
+ {
+ SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) );
+
+ if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+ return( ret );
+
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+ ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION;
+ break;
+ }
+ }
+
+ for( i = 0; ssl->ciphersuites[i] != 0; i++ )
+ {
+ for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 )
+ {
+ if( p[0] == 0 &&
+ p[1] == 0 &&
+ p[2] == ssl->ciphersuites[i] )
+ goto have_ciphersuite_v2;
+ }
+ }
+
+ SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
+
+ return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN );
+
+have_ciphersuite_v2:
+ ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i];
+ ssl_optimize_checksum( ssl, ssl->session_negotiate->ciphersuite );
+
+ /*
+ * SSLv2 Client Hello relevant renegotiation security checks
+ */
+ if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION &&
+ ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE )
+ {
+ SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) );
+
+ if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 )
+ return( ret );
+
+ return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO );
+ }
+
+ ssl->in_left = 0;
+ ssl->state++;
+
+ SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) );
+
+ return( 0 );
+}
+#endif /* POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */
+
static int ssl_parse_client_hello( ssl_context *ssl )
{
int ret;
@@ -214,6 +424,11 @@
buf = ssl->in_hdr;
+#if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO)
+ if( ( buf[0] & 0x80 ) != 0 )
+ return ssl_parse_client_hello_v2( ssl );
+#endif
+
SSL_DEBUG_BUF( 4, "record header", buf, 5 );
SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d",