From d76314c44cedb8e5af8dc27d84ecf6ff8ecbaa33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 7 Jan 2015 12:39:44 +0100 Subject: [PATCH] Add 1/n-1 record splitting --- include/polarssl/check_config.h | 5 ++++ include/polarssl/config.h | 12 +++++++++ include/polarssl/ssl.h | 3 +++ library/ssl_tls.c | 44 +++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/include/polarssl/check_config.h b/include/polarssl/check_config.h index 328b881ea..38d63fb42 100644 --- a/include/polarssl/check_config.h +++ b/include/polarssl/check_config.h @@ -263,6 +263,11 @@ #error "POLARSSL_SSL_SESSION_TICKETS_C defined, but not all prerequisites" #endif +#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) && \ + !defined(POLARSSL_SSL_PROTO_SSL3) && !defined(POLARSSL_SSL_PROTO_TLS1) +#error "POLARSSL_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites" +#endif + #if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) && \ !defined(POLARSSL_X509_CRT_PARSE_C) #error "POLARSSL_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites" diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 50b4e339e..584319210 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -821,6 +821,18 @@ */ //#define POLARSSL_SSL_HW_RECORD_ACCEL +/** + * \def POLARSSL_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +#define POLARSSL_SSL_CBC_RECORD_SPLITTING + /** * \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO * diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 4310ed6b7..718e6d559 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -784,6 +784,9 @@ struct _ssl_context #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH) unsigned char mfl_code; /*!< MaxFragmentLength chosen by us */ #endif /* POLARSSL_SSL_MAX_FRAGMENT_LENGTH */ +#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) + unsigned char split_done; /*!< flag for record splitting */ +#endif /* * PKI layer diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 5f080defe..00e99f798 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3482,6 +3482,9 @@ int ssl_session_reset( ssl_context *ssl ) ssl->out_msgtype = 0; ssl->out_msglen = 0; ssl->out_left = 0; +#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) + ssl->split_done = 0; +#endif ssl->transform_in = NULL; ssl->transform_out = NULL; @@ -4431,7 +4434,11 @@ int ssl_read( ssl_context *ssl, unsigned char *buf, size_t len ) /* * Send application data to be encrypted by the SSL layer */ +#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) +static int ssl_write_real( ssl_context *ssl, const unsigned char *buf, size_t len ) +#else int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) +#endif { int ret; size_t n; @@ -4492,6 +4499,43 @@ int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) return( (int) n ); } +/* + * Write application data, doing 1/n-1 splitting if necessary. + * + * With non-blocking I/O, ssl_write_real() may return WANT_WRITE, + * then the caller wil call us again with the same arguments. + */ +#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING) +int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + int ret; + + if( ssl->minor_ver > SSL_MINOR_VERSION_1 || + len == 0 || + cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ) + != POLARSSL_MODE_CBC ) + { + return( ssl_write_real( ssl, buf, len ) ); + } + + if( ssl->split_done == 0 ) + { + ssl->split_done = 1; + if( ( ret = ssl_write_real( ssl, buf, 1 ) ) < 0 ) + return( ret ); + } + + if( ssl->split_done == 1 && len > 1 ) + { + ssl->split_done = 0; + if( ( ret = ssl_write_real( ssl, buf + 1, len - 1 ) ) < 0 ) + return( ret ); + } + + return( ret + 1 ); +} +#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */ + /* * Notify the peer that the connection is being closed */