From 8f4ddaeea9dbde232070817f0d87817cfbddd1c5 Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 15 Apr 2013 15:09:54 +0200 Subject: [PATCH] Ability to specify allowed ciphersuites based on the protocol version. The ciphersuites parameter in the ssl_session structure changed from 'int *' to 'int *[4]'. The new function ssl_set_ciphersuite_for_version() sets specific entries inside this array. ssl_set_ciphersuite() sets all entries to the same value. (cherry picked from commit a62729888b9d8eafbfa952fca63a04100ed90f69) Conflicts: ChangeLog library/ssl_srv.c library/ssl_tls.c --- ChangeLog | 1 + include/polarssl/ssl.h | 20 +++++++++++++++++++- library/ssl_cli.c | 19 ++++++++++++------- library/ssl_srv.c | 24 ++++++++++++++---------- library/ssl_tls.c | 19 +++++++++++++++++-- 5 files changed, 63 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0e8939ecc..aacca2aa8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Features * Elliptic Curve Diffie Hellman module added * Ephemeral Elliptic Curve Diffie Hellman support for SSL/TLS (ECDHE-based ciphersuites) + * Ability to specify allowed ciphersuites based on the protocol version. Changes * Introduced separate SSL Ciphersuites module that is based on diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index a2235863f..43e80699c 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -476,7 +476,7 @@ struct _ssl_context int verify_result; /*!< verification result */ int disable_renegotiation; /*!< enable/disable renegotiation */ int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ - const int *ciphersuites; /*!< allowed ciphersuites */ + const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */ #if defined(POLARSSL_DHM_C) mpi dhm_P; /*!< prime modulus for DHM */ @@ -706,12 +706,30 @@ void ssl_set_session( ssl_context *ssl, const ssl_session *session ); /** * \brief Set the list of allowed ciphersuites + * (Overrides all version specific lists) * * \param ssl SSL context * \param ciphersuites 0-terminated list of allowed ciphersuites */ void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites ); +/** + * \brief Set the list of allowed ciphersuites for a specific + * version of the protocol. + * (Only useful on the server side) + * + * \param ssl SSL context + * \param ciphersuites 0-terminated list of allowed ciphersuites + * \param major Major version number (only SSL_MAJOR_VERSION_3 + * supported) + * \param minor Minor version number (SSL_MINOR_VERSION_0, + * SSL_MINOR_VERSION_1 and SSL_MINOR_VERSION_2, + * SSL_MINOR_VERSION_3 supported) + */ +void ssl_set_ciphersuites_for_version( ssl_context *ssl, + const int *ciphersuites, + int major, int minor ); + /** * \brief Set the data required to verify peer certificate * diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 9ad69dc6f..c7f959ff8 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -255,6 +255,7 @@ static int ssl_write_client_hello( ssl_context *ssl ) unsigned char *buf; unsigned char *p; time_t t; + const int *ciphersuites; SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); @@ -327,7 +328,8 @@ static int ssl_write_client_hello( ssl_context *ssl ) SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); - for( n = 0; ssl->ciphersuites[n] != 0; n++ ); + ciphersuites = ssl->ciphersuite_list[ssl->minor_ver]; + for( n = 0; ciphersuites[n] != 0; n++ ); if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) n++; *p++ = (unsigned char)( n >> 7 ); *p++ = (unsigned char)( n << 1 ); @@ -347,10 +349,10 @@ static int ssl_write_client_hello( ssl_context *ssl ) for( i = 0; i < n; i++ ) { SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %2d", - ssl->ciphersuites[i] ) ); + ciphersuites[i] ) ); - *p++ = (unsigned char)( ssl->ciphersuites[i] >> 8 ); - *p++ = (unsigned char)( ssl->ciphersuites[i] ); + *p++ = (unsigned char)( ciphersuites[i] >> 8 ); + *p++ = (unsigned char)( ciphersuites[i] ); } #if defined(POLARSSL_ZLIB_SUPPORT) @@ -571,7 +573,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) if( ssl->transform_negotiate->ciphersuite_info == NULL ) { SSL_DEBUG_MSG( 1, ( "ciphersuite info for %02x not found", - ssl->ciphersuites[i] ) ); + ssl->ciphersuite_list[ssl->minor_ver][i] ) ); return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); } @@ -616,14 +618,17 @@ static int ssl_parse_server_hello( ssl_context *ssl ) i = 0; while( 1 ) { - if( ssl->ciphersuites[i] == 0 ) + if( ssl->ciphersuite_list[ssl->minor_ver][i] == 0 ) { SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); } - if( ssl->ciphersuites[i++] == ssl->session_negotiate->ciphersuite ) + if( ssl->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { break; + } } if( comp != SSL_COMPRESS_NULL diff --git a/library/ssl_srv.c b/library/ssl_srv.c index b94ac92a1..fbc86abad 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -271,6 +271,7 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) size_t n; unsigned int ciph_len, sess_len, chal_len; unsigned char *buf, *p; + const int *ciphersuites; SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); @@ -431,7 +432,8 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) } } - for( i = 0; ssl->ciphersuites[i] != 0; i++ ) + ciphersuites = ssl->ciphersuite_list[ssl->minor_ver]; + for( i = 0; ciphersuites[i] != 0; i++ ) { for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) { @@ -439,8 +441,8 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) // if( p[0] == 0 && p[1] == 0 && - ( ( ssl->ciphersuites[i] >> 8 ) & 0xFF ) == 0 && - p[2] == ( ssl->ciphersuites[i] & 0xFF ) ) + ( ( ciphersuites[i] >> 8 ) & 0xFF ) == 0 && + p[2] == ( ciphersuites[i] & 0xFF ) ) goto have_ciphersuite_v2; } } @@ -450,7 +452,7 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); have_ciphersuite_v2: - ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i]; + ssl->session_negotiate->ciphersuite = ciphersuites[i]; ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); /* @@ -487,6 +489,7 @@ static int ssl_parse_client_hello( ssl_context *ssl ) unsigned char *buf, *p, *ext; int renegotiation_info_seen = 0; int handshake_failure = 0; + const int *ciphersuites; const ssl_ciphersuite_t *ciphersuite_info; SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); @@ -836,20 +839,21 @@ static int ssl_parse_client_hello( ssl_context *ssl ) * Search for a matching ciphersuite * (At the end because we need information from the EC-based extensions) */ - for( i = 0; ssl->ciphersuites[i] != 0; i++ ) + ciphersuites = ssl->ciphersuite_list[ssl->minor_ver]; + for( i = 0; ciphersuites[i] != 0; i++ ) { for( j = 0, p = buf + 41 + sess_len; j < ciph_len; j += 2, p += 2 ) { - if( p[0] == ( ( ssl->ciphersuites[i] >> 8 ) & 0xFF ) && - p[1] == ( ( ssl->ciphersuites[i] ) & 0xFF ) ) + if( p[0] == ( ( ciphersuites[i] >> 8 ) & 0xFF ) && + p[1] == ( ( ciphersuites[i] ) & 0xFF ) ) { - ciphersuite_info = ssl_ciphersuite_from_id( ssl->ciphersuites[i] ); + ciphersuite_info = ssl_ciphersuite_from_id( ciphersuites[i] ); if( ciphersuite_info == NULL ) { SSL_DEBUG_MSG( 1, ( "ciphersuite info for %02x not found", - ssl->ciphersuites[i] ) ); + ciphersuites[i] ) ); return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); } @@ -870,7 +874,7 @@ static int ssl_parse_client_hello( ssl_context *ssl ) return( POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN ); have_ciphersuite: - ssl->session_negotiate->ciphersuite = ssl->ciphersuites[i]; + ssl->session_negotiate->ciphersuite = ciphersuites[i]; ssl->transform_negotiate->ciphersuite_info = ciphersuite_info; ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 2d09c598b..4065318fc 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2677,7 +2677,7 @@ int ssl_init( ssl_context *ssl ) ssl->min_major_ver = SSL_MAJOR_VERSION_3; ssl->min_minor_ver = SSL_MINOR_VERSION_0; - ssl->ciphersuites = ssl_list_ciphersuites(); + ssl_set_ciphersuites( ssl, ssl_list_ciphersuites() ); #if defined(POLARSSL_DHM_C) if( ( ret = mpi_read_string( &ssl->dhm_P, 16, @@ -2862,7 +2862,22 @@ void ssl_set_session( ssl_context *ssl, const ssl_session *session ) void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites ) { - ssl->ciphersuites = ciphersuites; + ssl->ciphersuite_list[SSL_MINOR_VERSION_0] = ciphersuites; + ssl->ciphersuite_list[SSL_MINOR_VERSION_1] = ciphersuites; + ssl->ciphersuite_list[SSL_MINOR_VERSION_2] = ciphersuites; + ssl->ciphersuite_list[SSL_MINOR_VERSION_3] = ciphersuites; +} + +void ssl_set_ciphersuites_for_version( ssl_context *ssl, const int *ciphersuites, + int major, int minor ) +{ + if( major != SSL_MAJOR_VERSION_3 ) + return; + + if( minor < SSL_MINOR_VERSION_0 || minor > SSL_MINOR_VERSION_3 ) + return; + + ssl->ciphersuite_list[minor] = ciphersuites; } void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,