From a9964dbcd518bcbf33a8fcac512e99d8e563ca8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 3 Jul 2014 19:29:16 +0200 Subject: [PATCH] Add ssl_set_renegotiation_enforced() --- include/polarssl/ssl.h | 32 ++++++++++++++++++++++++++++++++ library/ssl_tls.c | 24 +++++++++++++++++++++--- tests/ssl-opt.sh | 4 ++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 91e398144..b90b232a5 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -221,6 +221,9 @@ #define SSL_RENEGOTIATION_DISABLED 0 #define SSL_RENEGOTIATION_ENABLED 1 +#define SSL_RENEGOTIATION_NOT_ENFORCED -1 +#define SSL_RENEGO_MAX_RECORDS_DEFAULT 16 + #define SSL_LEGACY_NO_RENEGOTIATION 0 #define SSL_LEGACY_ALLOW_RENEGOTIATION 1 #define SSL_LEGACY_BREAK_HANDSHAKE 2 @@ -620,6 +623,7 @@ struct _ssl_context */ int state; /*!< SSL handshake: current state */ int renegotiation; /*!< Initial or renegotiation */ + int renego_records_seen; /*!< Records since renego request */ int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */ int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ @@ -744,6 +748,7 @@ struct _ssl_context int verify_result; /*!< verification result */ int disable_renegotiation; /*!< enable/disable renegotiation */ int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ + int renego_max_records; /*!< grace period for renegotiation */ const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */ #if defined(POLARSSL_SSL_SET_CURVES) const ecp_group_id *curve_list; /*!< allowed curves */ @@ -1421,6 +1426,33 @@ void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ); */ void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ); +/** + * \brief Enforce server-requested renegotiation. + * (Default: enforced, max_records = 16) + * (No effect on client.) + * + * When a server requests a renegotiation, the client can + * comply or ignore the request. This function allows the + * server to decide if it should enforce its renegotiation + * requests by closing the connection if the client doesn't + * initiate a renegotiation. + * + * However, records could already be in transit from the + * client to the server when the request is emitted. In order + * to increase reliability, the server can accept a number of + * records containing application data before the ClientHello + * that was requested. + * + * The optimal value is highly dependent on the specific usage + * scenario. + * + * \param ssl SSL context + * \param max_records Use SSL_RENEGOTIATION_NOT_ENFORCED if you don't want to + * enforce renegotiation, or a non-negative value to enforce + * it but allow for a grace period of max_records records. + */ +void ssl_set_renegotiation_enforced( ssl_context *ssl, int max_records ); + /** * \brief Return the number of data bytes available to read * diff --git a/library/ssl_tls.c b/library/ssl_tls.c index a1428dccf..7c8f3064b 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3055,7 +3055,10 @@ void ssl_handshake_wrapup( ssl_context *ssl ) ssl->handshake = NULL; if( ssl->renegotiation == SSL_RENEGOTIATION ) + { ssl->renegotiation = SSL_RENEGOTIATION_DONE; + ssl->renego_records_seen = 0; + } /* * Switch in our now active transform context @@ -3345,6 +3348,8 @@ int ssl_init( ssl_context *ssl ) ssl_set_ciphersuites( ssl, ssl_list_ciphersuites() ); + ssl->renego_max_records = SSL_RENEGO_MAX_RECORDS_DEFAULT; + #if defined(POLARSSL_DHM_C) if( ( ret = mpi_read_string( &ssl->dhm_P, 16, POLARSSL_DHM_RFC5114_MODP_1024_P) ) != 0 || @@ -3435,6 +3440,8 @@ int ssl_session_reset( ssl_context *ssl ) ssl->transform_in = NULL; ssl->transform_out = NULL; + ssl->renego_records_seen = 0; + memset( ssl->out_ctr, 0, SSL_BUFFER_LEN ); memset( ssl->in_ctr, 0, SSL_BUFFER_LEN ); @@ -3952,6 +3959,11 @@ void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ) ssl->allow_legacy_renegotiation = allow_legacy; } +void ssl_set_renegotiation_enforced( ssl_context *ssl, int max_records ) +{ + ssl->renego_max_records = max_records; +} + #if defined(POLARSSL_SSL_SESSION_TICKETS) int ssl_set_session_tickets( ssl_context *ssl, int use_tickets ) { @@ -4296,9 +4308,15 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) } else if( ssl->renegotiation == SSL_RENEGOTIATION_PENDING ) { - SSL_DEBUG_MSG( 1, ( "renegotiation requested, " - "but not honored by client" ) ); - return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + ssl->renego_records_seen++; + + if( ssl->renego_max_records >= 0 && + ssl->renego_records_seen > ssl->renego_max_records ) + { + SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by client" ) ); + return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); + } } else if( ssl->in_msgtype != SSL_MSG_APPLICATION_DATA ) { diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 102a5b50c..6c2a92d5c 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -630,8 +630,8 @@ run_test "Renegotiation #5 (server-initiated, client-rejected)" \ -C "=> renegotiate" \ -S "=> renegotiate" \ -s "write hello request" \ - -s "SSL - An unexpected message was received from our peer" \ - -s "failed" + -S "SSL - An unexpected message was received from our peer" \ + -S "failed" # Tests for auth_mode