diff --git a/ChangeLog b/ChangeLog index 602ad64e0..39120372b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -37,6 +37,7 @@ Features * Add x509_crl_parse_der(). * Add compile-time option POLARSSL_X509_MAX_INTERMEDIATE_CA to limit the length of an X.509 verification chain. + * Support for renegotiation can now be disabled at compile-time Bugfix * Stack buffer overflow if ctr_drbg_update() is called with too large diff --git a/configs/config-ccm-psk-tls1_2.h b/configs/config-ccm-psk-tls1_2.h index 1da9f6a6b..00f92b77d 100644 --- a/configs/config-ccm-psk-tls1_2.h +++ b/configs/config-ccm-psk-tls1_2.h @@ -19,6 +19,7 @@ /* PolarSSL feature support */ #define POLARSSL_KEY_EXCHANGE_PSK_ENABLED #define POLARSSL_SSL_PROTO_TLS1_2 +#define POLARSSL_SSL_DISABLE_RENEGOTIATION /* PolarSSL modules */ #define POLARSSL_AES_C diff --git a/configs/config-mini-tls1_1.h b/configs/config-mini-tls1_1.h index 338fecf15..47c94c1ba 100644 --- a/configs/config-mini-tls1_1.h +++ b/configs/config-mini-tls1_1.h @@ -18,6 +18,7 @@ #define POLARSSL_PKCS1_V15 #define POLARSSL_KEY_EXCHANGE_RSA_ENABLED #define POLARSSL_SSL_PROTO_TLS1_1 +#define POLARSSL_SSL_DISABLE_RENEGOTIATION /* PolarSSL modules */ #define POLARSSL_AES_C diff --git a/configs/config-psk-rc4-tls1_0.h b/configs/config-psk-rc4-tls1_0.h index c967b4c4d..7eafb2496 100644 --- a/configs/config-psk-rc4-tls1_0.h +++ b/configs/config-psk-rc4-tls1_0.h @@ -19,6 +19,7 @@ /* PolarSSL feature support */ #define POLARSSL_KEY_EXCHANGE_PSK_ENABLED #define POLARSSL_SSL_PROTO_TLS1 +#define POLARSSL_SSL_DISABLE_RENEGOTIATION /* PolarSSL modules */ #define POLARSSL_AES_C diff --git a/configs/config-suite-b.h b/configs/config-suite-b.h index cd38f3334..cabc3d1f9 100644 --- a/configs/config-suite-b.h +++ b/configs/config-suite-b.h @@ -25,6 +25,7 @@ #define POLARSSL_ECP_DP_SECP384R1_ENABLED #define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED #define POLARSSL_SSL_PROTO_TLS1_2 +#define POLARSSL_SSL_DISABLE_RENEGOTIATION /* PolarSSL modules */ #define POLARSSL_AES_C diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 1346b88c2..860a40bbe 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -886,6 +886,24 @@ */ //#define POLARSSL_SSL_HW_RECORD_ACCEL +/** + * \def POLARSSL_SSL_DISABLE_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Warning: in the next stable branch, this switch will be replaced by + * POLARSSL_SSL_RENEGOTIATION to enable support for renegotiation. + * + * Uncomment this to disable support for renegotiation. + */ +//#define POLARSSL_SSL_DISABLE_RENEGOTIATION + /** * \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO * diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index a70750dfc..8e0ba5458 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -32,6 +32,12 @@ #else #include POLARSSL_CONFIG_FILE #endif + +/* Temporary compatibility trick for the current stable branch */ +#if !defined(POLARSSL_SSL_DISABLE_RENEGOTIATION) +#define POLARSSL_SSL_RENEGOTIATION +#endif + #include "net.h" #include "bignum.h" #include "ecp.h" @@ -345,6 +351,15 @@ + SSL_PADDING_ADD \ ) +/* + * Length of the verify data for secure renegotiation + */ +#if defined(POLARSSL_SSL_PROTO_SSL3) +#define SSL_VERIFY_DATA_MAX_LEN 36 +#else +#define SSL_VERIFY_DATA_MAX_LEN 12 +#endif + /* * Signaling ciphersuite values (SCSV) */ @@ -781,9 +796,11 @@ struct _ssl_context int state; /*!< SSL handshake: current state */ int transport; /*!< Transport: stream or datagram */ int renegotiation; /*!< Initial or renegotiation */ +#if defined(POLARSSL_SSL_RENEGOTIATION) int renego_records_seen; /*!< Records since renego request, or with DTLS, number of retransmissions of request if renego_max_records is < 0 */ +#endif int major_ver; /*!< equal to SSL_MAJOR_VERSION_3 */ int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ @@ -952,9 +969,13 @@ struct _ssl_context int authmode; /*!< verification mode */ int client_auth; /*!< flag for client auth. */ int verify_result; /*!< verification result */ +#if defined(POLARSSL_SSL_RENEGOTIATION) int disable_renegotiation; /*!< enable/disable renegotiation */ - int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ int renego_max_records; /*!< grace period for renegotiation */ + unsigned char renego_period[8]; /*!< value of the record counters + that triggers renegotiation */ +#endif + int allow_legacy_renegotiation; /*!< allow legacy renegotiation */ const int *ciphersuite_list[4]; /*!< allowed ciphersuites / version */ #if defined(POLARSSL_SSL_SET_CURVES) const ecp_group_id *curve_list; /*!< allowed curves */ @@ -1016,9 +1037,11 @@ struct _ssl_context */ int secure_renegotiation; /*!< does peer support legacy or secure renegotiation */ +#if defined(POLARSSL_SSL_RENEGOTIATION) size_t verify_data_len; /*!< length of verify data stored */ - char own_verify_data[36]; /*!< previous handshake verify data */ - char peer_verify_data[36]; /*!< previous handshake verify data */ + char own_verify_data[SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ + char peer_verify_data[SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ +#endif }; #if defined(POLARSSL_SSL_HW_RECORD_ACCEL) @@ -1863,6 +1886,7 @@ int ssl_set_session_tickets( ssl_context *ssl, int use_tickets ); void ssl_set_session_ticket_lifetime( ssl_context *ssl, int lifetime ); #endif /* POLARSSL_SSL_SESSION_TICKETS */ +#if defined(POLARSSL_SSL_RENEGOTIATION) /** * \brief Enable / Disable renegotiation support for connection when * initiated by peer @@ -1877,6 +1901,7 @@ void ssl_set_session_ticket_lifetime( ssl_context *ssl, int lifetime ); * SSL_RENEGOTIATION_DISABLED) */ void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ); +#endif /* POLARSSL_SSL_RENEGOTIATION */ /** * \brief Prevent or allow legacy renegotiation. @@ -1907,6 +1932,7 @@ void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ); */ void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ); +#if defined(POLARSSL_SSL_RENEGOTIATION) /** * \brief Enforce renegotiation requests. * (Default: enforced, max_records = 16) @@ -1946,6 +1972,27 @@ void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ); */ void ssl_set_renegotiation_enforced( ssl_context *ssl, int max_records ); +/** + * \brief Set record counter threshold for periodic renegotiation. + * (Default: 2^64 - 256.) + * + * Renegotiation is automatically triggered when a record + * counter (outgoing or ingoing) crosses the defined + * threshold. The default value is meant to prevent the + * connection from being closed when the counter is about to + * reached its maximal value (it is not allowed to wrap). + * + * Lower values can be used to enforce policies such as "keys + * must be refreshed every N packets with cipher X". + * + * \param ssl SSL context + * \param period The threshold value: a big-endian 64-bit number. + * Set to 2^64 - 1 to disable periodic renegotiation + */ +void ssl_set_renegotiation_period( ssl_context *ssl, + const unsigned char period[8] ); +#endif /* POLARSSL_SSL_RENEGOTIATION */ + /** * \brief Return the number of data bytes available to read * @@ -2060,6 +2107,7 @@ int ssl_handshake( ssl_context *ssl ); */ int ssl_handshake_step( ssl_context *ssl ); +#if defined(POLARSSL_SSL_RENEGOTIATION) /** * \brief Initiate an SSL renegotiation on the running connection. * Client: perform the renegotiation right now. @@ -2071,6 +2119,7 @@ int ssl_handshake_step( ssl_context *ssl ); * \return 0 if successful, or any ssl_handshake() return value. */ int ssl_renegotiate( ssl_context *ssl ); +#endif /* POLARSSL_SSL_RENEGOTIATION */ /** * \brief Read at most 'len' application data bytes diff --git a/library/ssl_cli.c b/library/ssl_cli.c index d37391006..98711cc86 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -114,6 +114,7 @@ static void ssl_write_hostname_ext( ssl_context *ssl, } #endif /* POLARSSL_SSL_SERVER_NAME_INDICATION */ +#if defined(POLARSSL_SSL_RENEGOTIATION) static void ssl_write_renegotiation_ext( ssl_context *ssl, unsigned char *buf, size_t *olen ) @@ -141,6 +142,7 @@ static void ssl_write_renegotiation_ext( ssl_context *ssl, *olen = 5 + ssl->verify_data_len; } +#endif /* POLARSSL_SSL_RENEGOTIATION */ /* * Only if we handle at least one key exchange that needs signatures. @@ -562,7 +564,9 @@ static int ssl_write_client_hello( ssl_context *ssl ) return( POLARSSL_ERR_SSL_NO_RNG ); } +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) +#endif { ssl->major_ver = ssl->min_major_ver; ssl->minor_ver = ssl->min_minor_ver; @@ -615,7 +619,10 @@ static int ssl_write_client_hello( ssl_context *ssl ) */ n = ssl->session_negotiate->length; - if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || n < 16 || n > 32 || + if( n < 16 || n > 32 || +#if defined(POLARSSL_SSL_RENEGOTIATION) + ssl->renegotiation != SSL_INITIAL_HANDSHAKE || +#endif ssl->handshake->resume == 0 ) { n = 0; @@ -626,8 +633,10 @@ static int ssl_write_client_hello( ssl_context *ssl ) * RFC 5077 section 3.4: "When presenting a ticket, the client MAY * generate and include a Session ID in the TLS ClientHello." */ - if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE && - ssl->session_negotiate->ticket != NULL && +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) +#endif + if( ssl->session_negotiate->ticket != NULL && ssl->session_negotiate->ticket_len != 0 ) { ret = ssl->f_rng( ssl->p_rng, ssl->session_negotiate->id, 32 ); @@ -682,8 +691,12 @@ static int ssl_write_client_hello( ssl_context *ssl ) q = p; p += 2; - /* Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ + /* + * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) +#endif { *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO >> 8 ); *p++ = (unsigned char)( SSL_EMPTY_RENEGOTIATION_INFO ); @@ -775,8 +788,10 @@ static int ssl_write_client_hello( ssl_context *ssl ) ext_len += olen; #endif +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); ext_len += olen; +#endif #if defined(POLARSSL_SSL_PROTO_TLS1_2) && \ defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED) @@ -822,6 +837,9 @@ static int ssl_write_client_hello( ssl_context *ssl ) ext_len += olen; #endif + /* olen unused if all extensions are disabled */ + ((void) olen); + SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", ext_len ) ); @@ -860,21 +878,8 @@ static int ssl_parse_renegotiation_info( ssl_context *ssl, { int ret; - if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) - { - if( len != 1 || buf[0] != 0x0 ) - { - SSL_DEBUG_MSG( 1, ( "non-zero length renegotiated connection field" ) ); - - if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) - return( ret ); - - return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); - } - - ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; - } - else +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) { /* Check verify-data in constant-time. The length OTOH is no secret */ if( len != 1 + ssl->verify_data_len * 2 || @@ -884,7 +889,7 @@ static int ssl_parse_renegotiation_info( ssl_context *ssl, safer_memcmp( buf + 1 + ssl->verify_data_len, ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) { - SSL_DEBUG_MSG( 1, ( "non-matching renegotiated connection field" ) ); + SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); @@ -892,6 +897,21 @@ static int ssl_parse_renegotiation_info( ssl_context *ssl, return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); } } + else +#endif /* POLARSSL_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x00 ) + { + SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; + } return( 0 ); } @@ -1150,7 +1170,9 @@ static int ssl_parse_server_hello( ssl_context *ssl ) size_t ext_len; unsigned char *buf, *ext; unsigned char comp, accept_comp; +#if defined(POLARSSL_SSL_RENEGOTIATION) int renegotiation_info_seen = 0; +#endif int handshake_failure = 0; #if defined(POLARSSL_DEBUG_C) uint32_t t; @@ -1168,6 +1190,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) if( ssl->in_msgtype != SSL_MSG_HANDSHAKE ) { +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_RENEGOTIATION ) { ssl->renego_records_seen++; @@ -1183,6 +1206,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) SSL_DEBUG_MSG( 1, ( "non-handshake message during renego" ) ); return( POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ); } +#endif /* POLARSSL_SSL_RENEGOTIATION */ SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); return( POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE ); @@ -1336,8 +1360,10 @@ static int ssl_parse_server_hello( ssl_context *ssl ) /* * Check if the session can be resumed */ - if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE || - ssl->handshake->resume == 0 || n == 0 || + if( ssl->handshake->resume == 0 || n == 0 || +#if defined(POLARSSL_SSL_RENEGOTIATION) + ssl->renegotiation != SSL_INITIAL_HANDSHAKE || +#endif ssl->session_negotiate->ciphersuite != i || ssl->session_negotiate->compression != comp || ssl->session_negotiate->length != n || @@ -1418,7 +1444,9 @@ static int ssl_parse_server_hello( ssl_context *ssl ) { case TLS_EXT_RENEGOTIATION_INFO: SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) renegotiation_info_seen = 1; +#endif if( ( ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ) ) != 0 ) @@ -1538,6 +1566,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); handshake_failure = 1; } +#if defined(POLARSSL_SSL_RENEGOTIATION) else if( ssl->renegotiation == SSL_RENEGOTIATION && ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION && renegotiation_info_seen == 0 ) @@ -1559,6 +1588,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); handshake_failure = 1; } +#endif /* POLARSSL_SSL_RENEGOTIATION */ if( handshake_failure == 1 ) { diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 2c596aba4..6621faa6b 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -461,11 +461,29 @@ static int ssl_parse_renegotiation_info( ssl_context *ssl, { int ret; - if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len || + buf[0] != ssl->verify_data_len || + safer_memcmp( buf + 1, ssl->peer_verify_data, + ssl->verify_data_len ) != 0 ) + { + SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + + if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else +#endif /* POLARSSL_SSL_RENEGOTIATION */ { if( len != 1 || buf[0] != 0x0 ) { - SSL_DEBUG_MSG( 1, ( "non-zero length renegotiated connection field" ) ); + SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) return( ret ); @@ -475,22 +493,6 @@ static int ssl_parse_renegotiation_info( ssl_context *ssl, ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; } - else - { - /* Check verify-data in constant-time. The length OTOH is no secret */ - if( len != 1 + ssl->verify_data_len || - buf[0] != ssl->verify_data_len || - safer_memcmp( buf + 1, ssl->peer_verify_data, - ssl->verify_data_len ) != 0 ) - { - SSL_DEBUG_MSG( 1, ( "non-matching renegotiated connection field" ) ); - - if( ( ret = ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) - return( ret ); - - return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); - } - } return( 0 ); } @@ -731,11 +733,13 @@ static int ssl_parse_session_ticket_ext( ssl_context *ssl, if( len == 0 ) return( 0 ); +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) { SSL_DEBUG_MSG( 3, ( "ticket rejected: renegotiating" ) ); return( 0 ); } +#endif /* POLARSSL_SSL_RENEGOTIATION */ /* * Failures are ok: just ignore the ticket and proceed. @@ -977,6 +981,7 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) { SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) ); @@ -986,6 +991,7 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } +#endif /* POLARSSL_SSL_RENEGOTIATION */ buf = ssl->in_hdr; @@ -1122,15 +1128,18 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) if( p[0] == 0 && p[1] == 0 && p[2] == SSL_EMPTY_RENEGOTIATION_INFO ) { SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_RENEGOTIATION ) { - SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during 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 ); } +#endif /* POLARSSL_SSL_RENEGOTIATION */ ssl->secure_renegotiation = SSL_SECURE_RENEGOTIATION; break; } @@ -1228,7 +1237,9 @@ static int ssl_parse_client_hello( ssl_context *ssl ) unsigned int cookie_offset, cookie_len; #endif unsigned char *buf, *p, *ext; +#if defined(POLARSSL_SSL_RENEGOTIATION) int renegotiation_info_seen = 0; +#endif int handshake_failure = 0; const int *ciphersuites; const ssl_ciphersuite_t *ciphersuite_info; @@ -1244,8 +1255,10 @@ read_record_header: * otherwise read it ourselves manually in order to support SSLv2 * ClientHello, which doesn't use the same record layer format. */ - if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE && - ( ret = ssl_fetch_input( ssl, ssl_hdr_len( ssl ) ) ) != 0 ) +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) +#endif + if( ( ret = ssl_fetch_input( ssl, 5 ) ) != 0 ) { SSL_DEBUG_RET( 1, "ssl_fetch_input", ret ); return( ret ); @@ -1331,7 +1344,9 @@ read_record_header: msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_INITIAL_HANDSHAKE ) +#endif { if( msg_len > SSL_MAX_CONTENT_LEN ) { @@ -1698,7 +1713,9 @@ read_record_header: case TLS_EXT_RENEGOTIATION_INFO: SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) renegotiation_info_seen = 1; +#endif ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ); if( ret != 0 ) @@ -1709,8 +1726,10 @@ read_record_header: defined(POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED) case TLS_EXT_SIG_ALG: SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_RENEGOTIATION ) break; +#endif ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); if( ret != 0 ) @@ -1861,12 +1880,13 @@ read_record_header: /* * Renegotiation security checks */ - if( ssl->secure_renegotiation == SSL_LEGACY_RENEGOTIATION && + if( ssl->secure_renegotiation != SSL_SECURE_RENEGOTIATION && ssl->allow_legacy_renegotiation == SSL_LEGACY_BREAK_HANDSHAKE ) { SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); handshake_failure = 1; } +#if defined(POLARSSL_SSL_RENEGOTIATION) else if( ssl->renegotiation == SSL_RENEGOTIATION && ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION && renegotiation_info_seen == 0 ) @@ -1888,6 +1908,7 @@ read_record_header: SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); handshake_failure = 1; } +#endif /* POLARSSL_SSL_RENEGOTIATION */ if( handshake_failure == 1 ) { @@ -2088,16 +2109,29 @@ static void ssl_write_renegotiation_ext( ssl_context *ssl, *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); *p++ = (unsigned char)( ( TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); - *p++ = 0x00; - *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; - *p++ = ssl->verify_data_len * 2 & 0xFF; +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ssl->renegotiation != SSL_INITIAL_HANDSHAKE ) + { + *p++ = 0x00; + *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; + *p++ = ssl->verify_data_len * 2 & 0xFF; - memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); - p += ssl->verify_data_len; - memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); - p += ssl->verify_data_len; + memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; - *olen = 5 + ssl->verify_data_len * 2; + *olen = 5 + ssl->verify_data_len * 2; + } + else +#endif /* POLARSSL_SSL_RENEGOTIATION */ + { + *p++ = 0x00; + *p++ = 0x01; + *p++ = 0x00; + + *olen = 5; + } } #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH) @@ -2331,7 +2365,9 @@ static int ssl_write_server_hello( ssl_context *ssl ) * If not, try looking up session ID in our cache. */ if( ssl->handshake->resume == 0 && +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl->renegotiation == SSL_INITIAL_HANDSHAKE && +#endif ssl->session_negotiate->length != 0 && ssl->f_get_cache != NULL && ssl->f_get_cache( ssl->p_get_cache, ssl->session_negotiate ) == 0 ) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 2292a074d..43f7f1464 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3942,7 +3942,7 @@ int ssl_parse_certificate( ssl_context *ssl ) * On client, make sure the server cert doesn't change during renego to * avoid "triple handshake" attack: https://secure-resumption.com/ */ -#if defined(POLARSSL_SSL_CLI_C) +#if defined(POLARSSL_SSL_RENEGOTIATION) && defined(POLARSSL_SSL_CLI_C) if( ssl->endpoint == SSL_IS_CLIENT && ssl->renegotiation == SSL_RENEGOTIATION ) { @@ -3962,7 +3962,7 @@ int ssl_parse_certificate( ssl_context *ssl ) return( POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE ); } } -#endif /* POLARSSL_SSL_CLI_C */ +#endif /* POLARSSL_SSL_RENEGOTIATION && POLARSSL_SSL_CLI_C */ if( ssl->authmode != SSL_VERIFY_NONE ) { @@ -4488,11 +4488,13 @@ void ssl_handshake_wrapup( ssl_context *ssl ) SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->renegotiation == SSL_RENEGOTIATION ) { ssl->renegotiation = SSL_RENEGOTIATION_DONE; ssl->renego_records_seen = 0; } +#endif /* * Free the previous session and switch in the current one @@ -4564,8 +4566,10 @@ int ssl_write_finished( ssl_context *ssl ) // TODO TLS/1.2 Hash length is determined by cipher suite (Page 63) hash_len = ( ssl->minor_ver == SSL_MINOR_VERSION_0 ) ? 36 : 12; +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl->verify_data_len = hash_len; memcpy( ssl->own_verify_data, ssl->out_msg + 4, hash_len ); +#endif ssl->out_msglen = 4 + hash_len; ssl->out_msgtype = SSL_MSG_HANDSHAKE; @@ -4703,8 +4707,10 @@ int ssl_parse_finished( ssl_context *ssl ) return( POLARSSL_ERR_SSL_BAD_HS_FINISHED ); } +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl->verify_data_len = hash_len; memcpy( ssl->peer_verify_data, buf, hash_len ); +#endif if( ssl->handshake->resume != 0 ) { @@ -4904,7 +4910,11 @@ int ssl_init( ssl_context *ssl ) ssl_set_ciphersuites( ssl, ssl_list_ciphersuites() ); +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl->renego_max_records = SSL_RENEGO_MAX_RECORDS_DEFAULT; + memset( ssl->renego_period, 0xFF, 7 ); + ssl->renego_period[7] = 0x00; +#endif #if defined(POLARSSL_DHM_C) if( ( ret = mpi_read_string( &ssl->dhm_P, 16, @@ -4984,12 +4994,16 @@ int ssl_session_reset( ssl_context *ssl ) int ret; ssl->state = SSL_HELLO_REQUEST; + +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl->renegotiation = SSL_INITIAL_HANDSHAKE; - ssl->secure_renegotiation = SSL_LEGACY_RENEGOTIATION; + ssl->renego_records_seen = 0; ssl->verify_data_len = 0; - memset( ssl->own_verify_data, 0, 36 ); - memset( ssl->peer_verify_data, 0, 36 ); + memset( ssl->own_verify_data, 0, SSL_VERIFY_DATA_MAX_LEN ); + memset( ssl->peer_verify_data, 0, SSL_VERIFY_DATA_MAX_LEN ); +#endif + ssl->secure_renegotiation = SSL_LEGACY_RENEGOTIATION; ssl->in_offt = NULL; @@ -5017,8 +5031,6 @@ int ssl_session_reset( ssl_context *ssl ) ssl->transform_in = NULL; ssl->transform_out = NULL; - ssl->renego_records_seen = 0; - memset( ssl->out_buf, 0, SSL_BUFFER_LEN ); memset( ssl->in_buf, 0, SSL_BUFFER_LEN ); @@ -5685,21 +5697,29 @@ int ssl_set_truncated_hmac( ssl_context *ssl, int truncate ) } #endif /* POLARSSL_SSL_TRUNCATED_HMAC */ -void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ) -{ - ssl->disable_renegotiation = renegotiation; -} - void ssl_legacy_renegotiation( ssl_context *ssl, int allow_legacy ) { ssl->allow_legacy_renegotiation = allow_legacy; } +#if defined(POLARSSL_SSL_RENEGOTIATION) +void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ) +{ + ssl->disable_renegotiation = renegotiation; +} + void ssl_set_renegotiation_enforced( ssl_context *ssl, int max_records ) { ssl->renego_max_records = max_records; } +void ssl_set_renegotiation_period( ssl_context *ssl, + const unsigned char period[8] ) +{ + memcpy( ssl->renego_period, period, 8 ); +} +#endif /* POLARSSL_SSL_RENEGOTIATION */ + #if defined(POLARSSL_SSL_SESSION_TICKETS) int ssl_set_session_tickets( ssl_context *ssl, int use_tickets ) { @@ -5884,6 +5904,7 @@ int ssl_handshake( ssl_context *ssl ) return( ret ); } +#if defined(POLARSSL_SSL_RENEGOTIATION) #if defined(POLARSSL_SSL_SRV_C) /* * Write HelloRequest to request renegotiation on server @@ -6009,6 +6030,30 @@ int ssl_renegotiate( ssl_context *ssl ) return( ret ); } +/* + * Check record counters and renegotiate if they're above the limit. + */ +static int ssl_check_ctr_renegotiate( ssl_context *ssl ) +{ + if( ssl->state != SSL_HANDSHAKE_OVER || + ssl->renegotiation == SSL_RENEGOTIATION_PENDING || + ssl->disable_renegotiation == SSL_RENEGOTIATION_DISABLED ) + { + return( 0 ); + } + + // TODO: adapt for DTLS + if( memcmp( ssl->in_ctr, ssl->renego_period, 8 ) <= 0 && + memcmp( ssl->out_ctr, ssl->renego_period, 8 ) <= 0 ) + { + return( 0 ); + } + + SSL_DEBUG_MSG( 0, ( "record counter limit reached: renegotiate" ) ); + return( ssl_renegotiate( ssl ) ); +} +#endif /* POLARSSL_SSL_RENEGOTIATION */ + /* * Receive application data decrypted from the SSL layer */ @@ -6034,6 +6079,14 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) } #endif +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + if( ssl->state != SSL_HANDSHAKE_OVER ) { ret = ssl_handshake( ssl ); @@ -6084,6 +6137,7 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) } } +#if defined(POLARSSL_SSL_RENEGOTIATION) if( ssl->in_msgtype == SSL_MSG_HANDSHAKE ) { SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); @@ -6194,6 +6248,7 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) } } } +#endif /* POLARSSL_SSL_RENEGOTIATION */ /* Fatal and closure alerts handled by ssl_read_record() */ if( ssl->in_msgtype == SSL_MSG_ALERT ) @@ -6263,6 +6318,14 @@ int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) SSL_DEBUG_MSG( 2, ( "=> write" ) ); +#if defined(POLARSSL_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + if( ssl->state != SSL_HANDSHAKE_OVER ) { if( ( ret = ssl_handshake( ssl ) ) != 0 ) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index c0e3cba94..b49a48e16 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -85,7 +85,7 @@ int main( int argc, char *argv[] ) #define DFL_PSK_IDENTITY "Client_identity" #define DFL_FORCE_CIPHER 0 #define DFL_RENEGOTIATION SSL_RENEGOTIATION_DISABLED -#define DFL_ALLOW_LEGACY SSL_LEGACY_NO_RENEGOTIATION +#define DFL_ALLOW_LEGACY -2 #define DFL_RENEGOTIATE 0 #define DFL_EXCHANGES 1 #define DFL_MIN_VERSION -1 @@ -330,6 +330,14 @@ static int my_verify( void *data, x509_crt *crt, int depth, int *flags ) #define USAGE_ETM "" #endif +#if defined(POLARSSL_SSL_RENEGOTIATION) +#define USAGE_RENEGO \ + " renegotiation=%%d default: 0 (disabled)\n" \ + " renegotiate=%%d default: 0 (disabled)\n" +#else +#define USAGE_RENEGO "" +#endif + #define USAGE \ "\n usage: ssl_client2 param=<>...\n" \ "\n acceptable parameters:\n" \ @@ -353,9 +361,8 @@ static int my_verify( void *data, x509_crt *crt, int depth, int *flags ) "\n" \ USAGE_PSK \ "\n" \ - " renegotiation=%%d default: 1 (enabled)\n" \ - " allow_legacy=%%d default: 0 (disabled)\n" \ - " renegotiate=%%d default: 0 (disabled)\n" \ + " allow_legacy=%%d default: (library default: no)\n" \ + USAGE_RENEGO \ " exchanges=%%d default: 1\n" \ " reconnect=%%d default: 0 (disabled)\n" \ USAGE_TIME \ @@ -560,9 +567,13 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "allow_legacy" ) == 0 ) { - opt.allow_legacy = atoi( q ); - if( opt.allow_legacy < 0 || opt.allow_legacy > 1 ) - goto usage; + switch( atoi( q ) ) + { + case -1: opt.allow_legacy = SSL_LEGACY_BREAK_HANDSHAKE; break; + case 0: opt.allow_legacy = SSL_LEGACY_NO_RENEGOTIATION; break; + case 1: opt.allow_legacy = SSL_LEGACY_ALLOW_RENEGOTIATION; break; + default: goto usage; + } } else if( strcmp( p, "renegotiate" ) == 0 ) { @@ -1082,8 +1093,11 @@ int main( int argc, char *argv[] ) if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER ) ssl_set_ciphersuites( &ssl, opt.force_ciphersuite ); + if( opt.allow_legacy != DFL_ALLOW_LEGACY ) + ssl_legacy_renegotiation( &ssl, opt.allow_legacy ); +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl_set_renegotiation( &ssl, opt.renegotiation ); - ssl_legacy_renegotiation( &ssl, opt.allow_legacy ); +#endif #if defined(POLARSSL_X509_CRT_PARSE_C) if( strcmp( opt.ca_path, "none" ) != 0 && @@ -1238,6 +1252,7 @@ int main( int argc, char *argv[] ) } #endif /* POLARSSL_X509_CRT_PARSE_C */ +#if defined(POLARSSL_SSL_RENEGOTIATION) if( opt.renegotiate ) { /* @@ -1257,6 +1272,7 @@ int main( int argc, char *argv[] ) } printf( " ok\n" ); } +#endif /* POLARSSL_SSL_RENEGOTIATION */ /* * 6. Write the GET request diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 58db85fa1..1f9e97f6d 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -106,9 +106,10 @@ int main( int argc, char *argv[] ) #define DFL_FORCE_CIPHER 0 #define DFL_VERSION_SUITES NULL #define DFL_RENEGOTIATION SSL_RENEGOTIATION_DISABLED -#define DFL_ALLOW_LEGACY SSL_LEGACY_NO_RENEGOTIATION +#define DFL_ALLOW_LEGACY -2 #define DFL_RENEGOTIATE 0 #define DFL_RENEGO_DELAY -2 +#define DFL_RENEGO_PERIOD -1 #define DFL_EXCHANGES 1 #define DFL_MIN_VERSION -1 #define DFL_MAX_VERSION -1 @@ -178,6 +179,7 @@ struct options int allow_legacy; /* allow legacy renegotiation */ int renegotiate; /* attempt renegotiation? */ int renego_delay; /* delay before enforcing renegotiation */ + int renego_period; /* period for automatic renegotiation */ int exchanges; /* number of data exchanges */ int min_version; /* minimum protocol version accepted */ int max_version; /* maximum protocol version accepted */ @@ -366,6 +368,16 @@ static int my_send( void *ctx, const unsigned char *buf, size_t len ) #define USAGE_ETM "" #endif +#if defined(POLARSSL_SSL_RENEGOTIATION) +#define USAGE_RENEGO \ + " renegotiation=%%d default: 0 (disabled)\n" \ + " renegotiate=%%d default: 0 (disabled)\n" \ + " renego_delay=%%d default: -2 (library default)\n" \ + " renego_period=%%d default: (library default)\n" +#else +#define USAGE_RENEGO "" +#endif + #define USAGE \ "\n usage: ssl_server2 param=<>...\n" \ "\n acceptable parameters:\n" \ @@ -388,10 +400,8 @@ static int my_send( void *ctx, const unsigned char *buf, size_t len ) "\n" \ USAGE_PSK \ "\n" \ - " renegotiation=%%d default: 1 (enabled)\n" \ - " allow_legacy=%%d default: 0 (disabled)\n" \ - " renegotiate=%%d default: 0 (disabled)\n" \ - " renego_delay=%%d default: -2 (library default)\n" \ + " allow_legacy=%%d default: (library default: no)\n" \ + USAGE_RENEGO \ " exchanges=%%d default: 1\n" \ "\n" \ USAGE_TICKETS \ @@ -681,6 +691,9 @@ int main( int argc, char *argv[] ) entropy_context entropy; ctr_drbg_context ctr_drbg; ssl_context ssl; +#if defined(POLARSSL_SSL_RENEGOTIATION) + unsigned char renego_period[8] = { 0 }; +#endif #if defined(POLARSSL_X509_CRT_PARSE_C) x509_crt cacert; x509_crt srvcert; @@ -786,6 +799,7 @@ int main( int argc, char *argv[] ) opt.allow_legacy = DFL_ALLOW_LEGACY; opt.renegotiate = DFL_RENEGOTIATE; opt.renego_delay = DFL_RENEGO_DELAY; + opt.renego_period = DFL_RENEGO_PERIOD; opt.exchanges = DFL_EXCHANGES; opt.min_version = DFL_MIN_VERSION; opt.max_version = DFL_MAX_VERSION; @@ -886,9 +900,13 @@ int main( int argc, char *argv[] ) } else if( strcmp( p, "allow_legacy" ) == 0 ) { - opt.allow_legacy = atoi( q ); - if( opt.allow_legacy < 0 || opt.allow_legacy > 1 ) - goto usage; + switch( atoi( q ) ) + { + case -1: opt.allow_legacy = SSL_LEGACY_BREAK_HANDSHAKE; break; + case 0: opt.allow_legacy = SSL_LEGACY_NO_RENEGOTIATION; break; + case 1: opt.allow_legacy = SSL_LEGACY_ALLOW_RENEGOTIATION; break; + default: goto usage; + } } else if( strcmp( p, "renegotiate" ) == 0 ) { @@ -900,6 +918,12 @@ int main( int argc, char *argv[] ) { opt.renego_delay = atoi( q ); } + else if( strcmp( p, "renego_period" ) == 0 ) + { + opt.renego_period = atoi( q ); + if( opt.renego_period < 2 || opt.renego_period > 255 ) + goto usage; + } else if( strcmp( p, "exchanges" ) == 0 ) { opt.exchanges = atoi( q ); @@ -1555,11 +1579,21 @@ int main( int argc, char *argv[] ) SSL_MINOR_VERSION_3 ); } + if( opt.allow_legacy != DFL_ALLOW_LEGACY ) + ssl_legacy_renegotiation( &ssl, opt.allow_legacy ); +#if defined(POLARSSL_SSL_RENEGOTIATION) ssl_set_renegotiation( &ssl, opt.renegotiation ); - ssl_legacy_renegotiation( &ssl, opt.allow_legacy ); + if( opt.renego_delay != DFL_RENEGO_DELAY ) ssl_set_renegotiation_enforced( &ssl, opt.renego_delay ); + if( opt.renego_period != DFL_RENEGO_PERIOD ) + { + renego_period[7] = opt.renego_period; + ssl_set_renegotiation_period( &ssl, renego_period ); + } +#endif + #if defined(POLARSSL_X509_CRT_PARSE_C) if( strcmp( opt.ca_path, "none" ) != 0 && strcmp( opt.ca_file, "none" ) != 0 ) @@ -1967,6 +2001,7 @@ data_exchange: * 7a. Request renegotiation while client is waiting for input from us. * (only on the first exchange, to be able to test retransmission) */ +#if defined(POLARSSL_SSL_RENEGOTIATION) if( opt.renegotiate && exchanges == opt.exchanges ) { printf( " . Requestion renegotiation..." ); @@ -1984,6 +2019,7 @@ data_exchange: printf( " ok\n" ); } +#endif /* POLARSSL_SSL_RENEGOTIATION */ /* * 7. Write the 200 Response diff --git a/scripts/config.pl b/scripts/config.pl index 8998fd6b0..c105a2321 100755 --- a/scripts/config.pl +++ b/scripts/config.pl @@ -28,6 +28,7 @@ POLARSSL_ECP_DP_M511_ENABLED POLARSSL_NO_DEFAULT_ENTROPY_SOURCES POLARSSL_NO_PLATFORM_ENTROPY POLARSSL_SSL_HW_RECORD_ACCEL +POLARSSL_SSL_DISABLE_RENEGOTIATION POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION POLARSSL_ZLIB_SUPPORT diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index f8c536d5e..2e6e1fde4 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -21,7 +21,7 @@ set -u O_SRV="$OPENSSL_CMD s_server -www -cert data_files/server5.crt -key data_files/server5.key" O_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_CMD s_client" G_SRV="$GNUTLS_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key" -G_CLI="$GNUTLS_CLI" +G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt" TESTS=0 FAILS=0 @@ -495,19 +495,20 @@ CLI_DELAY_FACTOR=1 # Pick a "unique" server port in the range 10000-19999, and a proxy port PORT_BASE="0000$$" -PORT_BASE="$( echo -n $PORT_BASE | tail -c 4 )" +PORT_BASE="$( echo -n $PORT_BASE | tail -c 5 )" SRV_PORT="1$PORT_BASE" PXY_PORT="2$PORT_BASE" unset PORT_BASE # fix commands to use this port, force IPv4 while at it +# +SRV_PORT will be replaced by either $SRV_PORT or $PXY_PORT later P_SRV="$P_SRV server_addr=127.0.0.1 server_port=$SRV_PORT" P_CLI="$P_CLI server_addr=127.0.0.1 server_port=+SRV_PORT" P_PXY="$P_PXY server_addr=127.0.0.1 server_port=$SRV_PORT listen_addr=127.0.0.1 listen_port=$PXY_PORT" O_SRV="$O_SRV -accept $SRV_PORT" O_CLI="$O_CLI -connect localhost:+SRV_PORT" G_SRV="$G_SRV -p $SRV_PORT" -G_CLI="$G_CLI -p +SRV_PORT" +G_CLI="$G_CLI -p +SRV_PORT localhost" # Also pick a unique name for intermediate files SRV_OUT="srv_out.$$" @@ -1168,6 +1169,70 @@ run_test "Renegotiation: server-initiated, client-accepted, delay 0" \ -S "SSL - An unexpected message was received from our peer" \ -S "failed" +run_test "Renegotiation: periodic, just below period" \ + "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3" \ + "$P_CLI debug_level=3 exchanges=2 renegotiation=1" \ + 0 \ + -C "client hello, adding renegotiation extension" \ + -s "received TLS_EMPTY_RENEGOTIATION_INFO" \ + -S "found renegotiation extension" \ + -s "server hello, secure renegotiation extension" \ + -c "found renegotiation extension" \ + -S "record counter limit reached: renegotiate" \ + -C "=> renegotiate" \ + -S "=> renegotiate" \ + -S "write hello request" \ + -S "SSL - An unexpected message was received from our peer" \ + -S "failed" + +run_test "Renegotiation: periodic, just above period" \ + "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3" \ + "$P_CLI debug_level=3 exchanges=3 renegotiation=1" \ + 0 \ + -c "client hello, adding renegotiation extension" \ + -s "received TLS_EMPTY_RENEGOTIATION_INFO" \ + -s "found renegotiation extension" \ + -s "server hello, secure renegotiation extension" \ + -c "found renegotiation extension" \ + -s "record counter limit reached: renegotiate" \ + -c "=> renegotiate" \ + -s "=> renegotiate" \ + -s "write hello request" \ + -S "SSL - An unexpected message was received from our peer" \ + -S "failed" + +run_test "Renegotiation: periodic, two times period" \ + "$P_SRV debug_level=3 exchanges=9 renegotiation=1 renego_period=3" \ + "$P_CLI debug_level=3 exchanges=6 renegotiation=1" \ + 0 \ + -c "client hello, adding renegotiation extension" \ + -s "received TLS_EMPTY_RENEGOTIATION_INFO" \ + -s "found renegotiation extension" \ + -s "server hello, secure renegotiation extension" \ + -c "found renegotiation extension" \ + -s "record counter limit reached: renegotiate" \ + -c "=> renegotiate" \ + -s "=> renegotiate" \ + -s "write hello request" \ + -S "SSL - An unexpected message was received from our peer" \ + -S "failed" + +run_test "Renegotiation: periodic, above period, disabled" \ + "$P_SRV debug_level=3 exchanges=9 renegotiation=0 renego_period=3" \ + "$P_CLI debug_level=3 exchanges=4 renegotiation=1" \ + 0 \ + -C "client hello, adding renegotiation extension" \ + -s "received TLS_EMPTY_RENEGOTIATION_INFO" \ + -S "found renegotiation extension" \ + -s "server hello, secure renegotiation extension" \ + -c "found renegotiation extension" \ + -S "record counter limit reached: renegotiate" \ + -C "=> renegotiate" \ + -S "=> renegotiate" \ + -S "write hello request" \ + -S "SSL - An unexpected message was received from our peer" \ + -S "failed" + run_test "Renegotiation: nbio, client-initiated" \ "$P_SRV debug_level=3 nbio=2 exchanges=2 renegotiation=1" \ "$P_CLI debug_level=3 nbio=2 exchanges=2 renegotiation=1 renegotiate=1" \ @@ -1201,18 +1266,53 @@ run_test "Renegotiation: openssl server, client-initiated" \ -c "client hello, adding renegotiation extension" \ -c "found renegotiation extension" \ -c "=> renegotiate" \ - -C "ssl_handshake returned" \ + -C "ssl_hanshake() returned" \ -C "error" \ -c "HTTP/1.0 200 [Oo][Kk]" -run_test "Renegotiation: gnutls server, client-initiated" \ - "$G_SRV" \ +run_test "Renegotiation: gnutls server strict, client-initiated" \ + "$G_SRV --priority=NORMAL:%SAFE_RENEGOTIATION" \ "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ 0 \ -c "client hello, adding renegotiation extension" \ -c "found renegotiation extension" \ -c "=> renegotiate" \ - -C "ssl_handshake returned" \ + -C "ssl_hanshake() returned" \ + -C "error" \ + -c "HTTP/1.0 200 [Oo][Kk]" + +run_test "Renegotiation: gnutls server unsafe, client-initiated default" \ + "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1" \ + 1 \ + -c "client hello, adding renegotiation extension" \ + -C "found renegotiation extension" \ + -c "=> renegotiate" \ + -c "ssl_handshake() returned" \ + -c "error" \ + -C "HTTP/1.0 200 [Oo][Kk]" + +run_test "Renegotiation: gnutls server unsafe, client-inititated no legacy" \ + "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1 \ + allow_legacy=0" \ + 1 \ + -c "client hello, adding renegotiation extension" \ + -C "found renegotiation extension" \ + -c "=> renegotiate" \ + -c "ssl_handshake() returned" \ + -c "error" \ + -C "HTTP/1.0 200 [Oo][Kk]" + +run_test "Renegotiation: gnutls server unsafe, client-inititated legacy" \ + "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + "$P_CLI debug_level=3 exchanges=1 renegotiation=1 renegotiate=1 \ + allow_legacy=1" \ + 0 \ + -c "client hello, adding renegotiation extension" \ + -C "found renegotiation extension" \ + -c "=> renegotiate" \ + -C "ssl_hanshake() returned" \ -C "error" \ -c "HTTP/1.0 200 [Oo][Kk]" @@ -1254,6 +1354,53 @@ run_test "Renegotiation: DTLS, gnutls server, client-initiated" \ -C "error" \ -s "Extra-header:" +# Test for the "secure renegotation" extension only (no actual renegotiation) + +run_test "Renego ext: gnutls server strict, client default" \ + "$G_SRV --priority=NORMAL:%SAFE_RENEGOTIATION" \ + "$P_CLI debug_level=3" \ + 0 \ + -c "found renegotiation extension" \ + -C "error" \ + -c "HTTP/1.0 200 [Oo][Kk]" + +run_test "Renego ext: gnutls server unsafe, client default" \ + "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + "$P_CLI debug_level=3" \ + 0 \ + -C "found renegotiation extension" \ + -C "error" \ + -c "HTTP/1.0 200 [Oo][Kk]" + +run_test "Renego ext: gnutls server unsafe, client break legacy" \ + "$G_SRV --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + "$P_CLI debug_level=3 allow_legacy=-1" \ + 1 \ + -C "found renegotiation extension" \ + -c "error" \ + -C "HTTP/1.0 200 [Oo][Kk]" + +run_test "Renego ext: gnutls client strict, server default" \ + "$P_SRV debug_level=3" \ + "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION" \ + 0 \ + -s "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \ + -s "server hello, secure renegotiation extension" + +run_test "Renego ext: gnutls client unsafe, server default" \ + "$P_SRV debug_level=3" \ + "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + 0 \ + -S "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \ + -S "server hello, secure renegotiation extension" + +run_test "Renego ext: gnutls client unsafe, server break legacy" \ + "$P_SRV debug_level=3 allow_legacy=-1" \ + "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \ + 1 \ + -S "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \ + -S "server hello, secure renegotiation extension" + # Tests for auth_mode run_test "Authentication: server badcert, client required" \