From 1cbd39dbebdb46e46a8f30d4c40292b001c147b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 20 Oct 2014 13:34:59 +0200 Subject: [PATCH 1/3] Implement FALLBACK_SCSV client-side --- include/polarssl/config.h | 17 ++++++++++++ include/polarssl/ssl.h | 32 +++++++++++++++++++++- library/ssl_cli.c | 11 ++++++++ library/ssl_tls.c | 7 +++++ programs/ssl/ssl_client2.c | 24 +++++++++++++++++ tests/ssl-opt.sh | 54 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 1 deletion(-) diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 50b4e339e..ff0ccecbd 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -811,6 +811,23 @@ */ //#define POLARSSL_SSL_DEBUG_ALL +/** + * \def POLARSSL_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +#define POLARSSL_SSL_FALLBACK_SCSV + /** * \def POLARSSL_SSL_HW_RECORD_ACCEL * diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 194e94471..a36e74219 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -206,6 +206,9 @@ #define SSL_IS_CLIENT 0 #define SSL_IS_SERVER 1 +#define SSL_IS_NOT_FALLBACK 0 +#define SSL_IS_FALLBACK 1 + #define SSL_COMPRESS_NULL 0 #define SSL_COMPRESS_DEFLATE 1 @@ -308,6 +311,7 @@ * Signaling ciphersuite values (SCSV) */ #define SSL_EMPTY_RENEGOTIATION_INFO 0xFF /**< renegotiation info ext */ +#define SSL_FALLBACK_SCSV 0x5600 /**< draft-ietf-tls-downgrade-scsv-00 */ /* * Supported Signature and Hash algorithms (For TLS 1.2) @@ -697,6 +701,10 @@ struct _ssl_context int min_major_ver; /*!< min. major version used */ int min_minor_ver; /*!< min. minor version used */ +#if defined(POLARSSL_SSL_FALLBACK_SCSV) && defined(POLARSSL_SSL_CLI_C) + char fallback; /*!< flag for fallback connections */ +#endif + /* * Callbacks (RNG, debug, I/O, verification) */ @@ -1367,7 +1375,6 @@ const char *ssl_get_alpn_protocol( const ssl_context *ssl ); */ void ssl_set_max_version( ssl_context *ssl, int major, int minor ); - /** * \brief Set the minimum accepted SSL/TLS protocol version * (Default: SSL_MIN_MAJOR_VERSION, SSL_MIN_MINOR_VERSION) @@ -1383,6 +1390,29 @@ void ssl_set_max_version( ssl_context *ssl, int major, int minor ); */ void ssl_set_min_version( ssl_context *ssl, int major, int minor ); +#if defined(POLARSSL_SSL_FALLBACK_SCSV) && defined(POLARSSL_SSL_CLI_C) +/** + * \brief Set the fallback flag (client-side only). + * (Default: SSL_IS_NOT_FALLBACK). + * + * \note Set to SSL_IS_FALLBACK when preparing a fallback + * connection, that is a connection with max_version set to a + * lower value than the value you're willing to use. Such + * fallback connections are not recommended but are sometimes + * necessary to interoperate with buggy (version-intolerant) + * servers. + * + * \warning You should NOT set this to SSL_IS_FALLBACK for + * non-fallback connections! This would appear to work for a + * while, then cause failures when the server is upgraded to + * support a newer TLS version. + * + * \param ssl SSL context + * \param fallback SSL_IS_NOT_FALLBACK or SSL_IS_FALLBACK + */ +void ssl_set_fallback( ssl_context *ssl, char fallback ); +#endif /* POLARSSL_SSL_FALLBACK_SCSV && POLARSSL_SSL_CLI_C */ + #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH) /** * \brief Set the maximum fragment length to emit and/or negotiate diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 27abb3efe..50ab05f2c 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -596,6 +596,17 @@ static int ssl_write_client_hello( ssl_context *ssl ) *p++ = (unsigned char)( ciphersuites[i] ); } + /* Some versions of OpenSSL don't handle it correctly if not at end */ +#if defined(POLARSSL_SSL_FALLBACK_SCSV) + if( ssl->fallback == SSL_IS_FALLBACK ) + { + SSL_DEBUG_MSG( 3, ( "adding FALLBACK_SCSV" ) ); + *p++ = (unsigned char)( SSL_FALLBACK_SCSV >> 8 ); + *p++ = (unsigned char)( SSL_FALLBACK_SCSV ); + n++; + } +#endif + *q++ = (unsigned char)( n >> 7 ); *q++ = (unsigned char)( n << 1 ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 5f080defe..bd4494f55 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3977,6 +3977,13 @@ void ssl_set_min_version( ssl_context *ssl, int major, int minor ) } } +#if defined(POLARSSL_SSL_FALLBACK_SCSV) && defined(POLARSSL_SSL_CLI_C) +void ssl_set_fallback( ssl_context *ssl, char fallback ) +{ + ssl->fallback = fallback; +} +#endif + #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH) int ssl_set_max_frag_len( ssl_context *ssl, unsigned char mfl_code ) { diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 5b7a488c9..8ca83ebe3 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -95,6 +95,7 @@ int main( int argc, char *argv[] ) #define DFL_RECO_DELAY 0 #define DFL_TICKETS SSL_SESSION_TICKETS_ENABLED #define DFL_ALPN_STRING NULL +#define DFL_FALLBACK -1 #define GET_REQUEST "GET %s HTTP/1.0\r\nExtra-header: " #define GET_REQUEST_END "\r\n\r\n" @@ -132,6 +133,7 @@ struct options int reco_delay; /* delay in seconds before resuming session */ int tickets; /* enable / disable session tickets */ const char *alpn_string; /* ALPN supported protocols */ + int fallback; /* is this a fallback connection? */ } opt; static void my_debug( void *ctx, int level, const char *str ) @@ -284,6 +286,13 @@ static int my_verify( void *data, x509_crt *crt, int depth, int *flags ) #define USAGE_ALPN "" #endif /* POLARSSL_SSL_ALPN */ +#if defined(POLARSSL_SSL_FALLBACK_SCSV) +#define USAGE_FALLBACK \ + " fallback=0/1 default: (library default: off)\n" +#else +#define USAGE_FALLBACK "" +#endif + #define USAGE \ "\n usage: ssl_client2 param=<>...\n" \ "\n acceptable parameters:\n" \ @@ -313,6 +322,7 @@ static int my_verify( void *data, x509_crt *crt, int depth, int *flags ) USAGE_MAX_FRAG_LEN \ USAGE_TRUNC_HMAC \ USAGE_ALPN \ + USAGE_FALLBACK \ "\n" \ " min_version=%%s default: \"\" (ssl3)\n" \ " max_version=%%s default: \"\" (tls1_2)\n" \ @@ -413,6 +423,7 @@ int main( int argc, char *argv[] ) opt.reco_delay = DFL_RECO_DELAY; opt.tickets = DFL_TICKETS; opt.alpn_string = DFL_ALPN_STRING; + opt.fallback = DFL_FALLBACK; for( i = 1; i < argc; i++ ) { @@ -519,6 +530,15 @@ int main( int argc, char *argv[] ) { opt.alpn_string = q; } + else if( strcmp( p, "fallback" ) == 0 ) + { + switch( atoi( q ) ) + { + case 0: opt.fallback = SSL_IS_NOT_FALLBACK; break; + case 1: opt.fallback = SSL_IS_FALLBACK; break; + default: goto usage; + } + } else if( strcmp( p, "min_version" ) == 0 ) { if( strcmp( q, "ssl3" ) == 0 ) @@ -952,6 +972,10 @@ int main( int argc, char *argv[] ) ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version ); if( opt.max_version != -1 ) ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version ); +#if defined(POLARSSL_SSL_FALLBACK_SCSV) + if( opt.fallback != DFL_FALLBACK ) + ssl_set_fallback( &ssl, opt.fallback ); +#endif /* * 4. Handshake diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 4eafed436..ab7793a42 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -80,6 +80,21 @@ requires_openssl_with_sslv2() { fi } +# skip next test if OpenSSL doesn't support FALLBACK_SCSV +requires_openssl_with_fallback_scsv() { + if [ -z "${OPENSSL_HAS_FBSCSV:-}" ]; then + if $OPENSSL_CMD s_client -help 2>&1 | grep fallback_scsv >/dev/null + then + OPENSSL_HAS_FBSCSV="YES" + else + OPENSSL_HAS_FBSCSV="NO" + fi + fi + if [ "$OPENSSL_HAS_FBSCSV" = "NO" ]; then + SKIP_NEXT="YES" + fi +} + # skip next test if GnuTLS isn't available requires_gnutls() { if [ -z "${GNUTLS_AVAILABLE:-}" ]; then @@ -425,6 +440,45 @@ run_test "Truncated HMAC: actual test" \ 0 \ -s "dumping 'computed mac' (10 bytes)" +# Tests for FALLBACK_SCSV + +run_test "Fallback SCSV: default" \ + "$P_SRV" \ + "$P_CLI debug_level=3 force_version=tls1_1" \ + 0 \ + -C "adding FALLBACK_SCSV" \ + -C "is a fatal alert message (msg 86)" + +run_test "Fallback SCSV: explicitly disabled" \ + "$P_SRV" \ + "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ + 0 \ + -C "adding FALLBACK_SCSV" \ + -C "is a fatal alert message (msg 86)" + +run_test "Fallback SCSV: enabled" \ + "$P_SRV" \ + "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ + 0 \ + -c "adding FALLBACK_SCSV" \ + -C "is a fatal alert message (msg 86)" + +requires_openssl_with_fallback_scsv +run_test "Fallback SCSV: default, openssl server" \ + "$O_SRV" \ + "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ + 0 \ + -C "adding FALLBACK_SCSV" \ + -C "is a fatal alert message (msg 86)" + +requires_openssl_with_fallback_scsv +run_test "Fallback SCSV: enabled, openssl server" \ + "$O_SRV" \ + "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ + 1 \ + -c "adding FALLBACK_SCSV" \ + -c "is a fatal alert message (msg 86)" + # Tests for Session Tickets run_test "Session resume using tickets: basic" \ From 01b26991988f28d285164bf66108fab7f67ddabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 20 Oct 2014 14:05:28 +0200 Subject: [PATCH 2/3] Implement FALLBACK_SCSV server-side --- include/polarssl/ssl.h | 1 + library/ssl_srv.c | 47 ++++++++++++++++++++++++++++++++++++++++++ tests/ssl-opt.sh | 39 +++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+) diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index a36e74219..875709c7b 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -369,6 +369,7 @@ #define SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ #define SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ #define SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ #define SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ #define SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ #define SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 01b0aca20..57b0ecf30 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -1052,6 +1052,30 @@ static int ssl_parse_client_hello_v2( ssl_context *ssl ) } } +#if defined(POLARSSL_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && + p[1] == (unsigned char)( ( SSL_FALLBACK_SCSV >> 8 ) & 0xff ) && + p[2] == (unsigned char)( ( SSL_FALLBACK_SCSV ) & 0xff ) ) + { + SSL_DEBUG_MSG( 3, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->max_minor_ver ) + { + SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* POLARSSL_SSL_FALLBACK_SCSV */ + ciphersuites = ssl->ciphersuite_list[ssl->minor_ver]; ciphersuite_info = NULL; #if defined(POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE) @@ -1365,6 +1389,29 @@ static int ssl_parse_client_hello( ssl_context *ssl ) } } +#if defined(POLARSSL_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == (unsigned char)( ( SSL_FALLBACK_SCSV >> 8 ) & 0xff ) && + p[1] == (unsigned char)( ( SSL_FALLBACK_SCSV ) & 0xff ) ) + { + SSL_DEBUG_MSG( 0, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->max_minor_ver ) + { + SSL_DEBUG_MSG( 0, ( "inapropriate fallback" ) ); + + ssl_send_alert_message( ssl, SSL_ALERT_LEVEL_FATAL, + SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* POLARSSL_SSL_FALLBACK_SCSV */ + ext = buf + 44 + sess_len + ciph_len + comp_len; while( ext_len ) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index ab7793a42..b0dcad95f 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -447,6 +447,8 @@ run_test "Fallback SCSV: default" \ "$P_CLI debug_level=3 force_version=tls1_1" \ 0 \ -C "adding FALLBACK_SCSV" \ + -S "received FALLBACK_SCSV" \ + -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" run_test "Fallback SCSV: explicitly disabled" \ @@ -454,13 +456,26 @@ run_test "Fallback SCSV: explicitly disabled" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=0" \ 0 \ -C "adding FALLBACK_SCSV" \ + -S "received FALLBACK_SCSV" \ + -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" run_test "Fallback SCSV: enabled" \ "$P_SRV" \ "$P_CLI debug_level=3 force_version=tls1_1 fallback=1" \ + 1 \ + -c "adding FALLBACK_SCSV" \ + -s "received FALLBACK_SCSV" \ + -s "inapropriate fallback" \ + -c "is a fatal alert message (msg 86)" + +run_test "Fallback SCSV: enabled, max version" \ + "$P_SRV" \ + "$P_CLI debug_level=3 fallback=1" \ 0 \ -c "adding FALLBACK_SCSV" \ + -s "received FALLBACK_SCSV" \ + -S "inapropriate fallback" \ -C "is a fatal alert message (msg 86)" requires_openssl_with_fallback_scsv @@ -479,6 +494,30 @@ run_test "Fallback SCSV: enabled, openssl server" \ -c "adding FALLBACK_SCSV" \ -c "is a fatal alert message (msg 86)" +requires_openssl_with_fallback_scsv +run_test "Fallback SCSV: disabled, openssl client" \ + "$P_SRV" \ + "$O_CLI -tls1_1" \ + 0 \ + -S "received FALLBACK_SCSV" \ + -S "inapropriate fallback" + +requires_openssl_with_fallback_scsv +run_test "Fallback SCSV: enabled, openssl client" \ + "$P_SRV" \ + "$O_CLI -tls1_1 -fallback_scsv" \ + 1 \ + -s "received FALLBACK_SCSV" \ + -s "inapropriate fallback" + +requires_openssl_with_fallback_scsv +run_test "Fallback SCSV: enabled, max version, openssl client" \ + "$P_SRV" \ + "$O_CLI -fallback_scsv" \ + 0 \ + -s "received FALLBACK_SCSV" \ + -S "inapropriate fallback" + # Tests for Session Tickets run_test "Session resume using tickets: basic" \ From 178f9d6e190d0f19ee9485e059e258650b5dac98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 20 Oct 2014 14:56:56 +0200 Subject: [PATCH 3/3] Update Changelog for FALLBACK_SCSV --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index fd83b9e60..900361a88 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ PolarSSL ChangeLog (Sorted per branch, date) += 1.3 branch + +Reminder: bump SONAME for ABI change (FALLBACK_SCSV) + +Features + * Add support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv) + = PolarSSL 1.3.9 released 2014-10-20 Security * Lowest common hash was selected from signature_algorithms extension in