diff --git a/ChangeLog b/ChangeLog index 518650373..6928c8677 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,7 @@ Features example application (programs/ssl/o_p_test) (Requires OpenSSL) * Added X509 CA Path support * Added Thumb assembly optimizations + * Added DEFLATE compression support as per RFC3749 (requires zlib) Changes * Removed redundant POLARSSL_DEBUG_MSG define diff --git a/include/polarssl/config.h b/include/polarssl/config.h index a14e27124..a336067dd 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -248,6 +248,22 @@ * #define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION */ + +/** + * \def POLARSSL_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB +#define POLARSSL_ZLIB_SUPPORT + */ /* \} name */ /** diff --git a/include/polarssl/error.h b/include/polarssl/error.h index fb739b187..508546eca 100644 --- a/include/polarssl/error.h +++ b/include/polarssl/error.h @@ -75,7 +75,7 @@ * RSA 4 9 * MD 5 4 * CIPHER 6 5 - * SSL 6 1 (Started from top) + * SSL 6 2 (Started from top) * SSL 7 31 * * Module dependent error code (5 bits 0x.08.-0x.F8.) diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index 1d7e7fd3f..40a57a7dc 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -43,6 +43,10 @@ #include "pkcs11.h" #endif +#if defined(POLARSSL_ZLIB_SUPPORT) +#include "zlib.h" +#endif + #if defined(_MSC_VER) && !defined(inline) #define inline _inline #else @@ -86,6 +90,7 @@ #define POLARSSL_ERR_SSL_MALLOC_FAILED -0x7F00 /**< Memory allocation failed */ #define POLARSSL_ERR_SSL_HW_ACCEL_FAILED -0x7F80 /**< Hardware acceleration function returned with error */ #define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */ +#define POLARSSL_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */ /* * Various constants @@ -99,6 +104,7 @@ #define SSL_IS_CLIENT 0 #define SSL_IS_SERVER 1 #define SSL_COMPRESS_NULL 0 +#define SSL_COMPRESS_DEFLATE 1 #define SSL_VERIFY_NONE 0 #define SSL_VERIFY_OPTIONAL 1 @@ -108,9 +114,17 @@ /* * Allow an extra 512 bytes for the record header - * and encryption overhead (counter + MAC + padding). + * and encryption overhead (counter + MAC + padding) + * and allow for a maximum of 1024 of compression expansion if + * enabled. */ -#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + 512) +#if defined(POLARSSL_ZLIB_SUPPORT) +#define SSL_COMPRESSION_ADD 1024 +#else +#define SSL_COMPRESSION_ADD 0 +#endif + +#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + SSL_COMPRESSION_ADD + 512) /* * Supported ciphersuites @@ -253,6 +267,7 @@ struct _ssl_session { time_t start; /*!< starting time */ int ciphersuite; /*!< chosen ciphersuite */ + int compression; /*!< chosen compression */ size_t length; /*!< session id length */ unsigned char id[32]; /*!< session identifier */ unsigned char master[48]; /*!< the master secret */ @@ -374,6 +389,11 @@ struct _ssl_context unsigned long ctx_enc[134]; /*!< encryption context */ unsigned long ctx_dec[134]; /*!< decryption context */ +#if defined(POLARSSL_ZLIB_SUPPORT) + z_stream ctx_deflate; /*!< compression context */ + z_stream ctx_inflate; /*!< decompression context */ +#endif + /* * TLS extensions */ @@ -445,8 +465,10 @@ int ssl_init( ssl_context *ssl ); * pointers and data. * * \param ssl SSL context + * \return 0 if successful, or POLARSSL_ERR_SSL_HW_ACCEL_FAILED or + * POLARSSL_ERR_SSL_COMPRESSION_FAILED */ -void ssl_session_reset( ssl_context *ssl ); +int ssl_session_reset( ssl_context *ssl ); /** * \brief Set the current endpoint type diff --git a/library/ssl_cli.c b/library/ssl_cli.c index 99120d569..49123795f 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -135,11 +135,21 @@ static int ssl_write_client_hello( ssl_context *ssl ) *p++ = (unsigned char)( ssl->ciphersuites[i] ); } +#if defined(POLARSSL_ZLIB_SUPPORT) + SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) ); + SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d", + SSL_COMPRESS_NULL, SSL_COMPRESS_DEFLATE ) ); + + *p++ = 2; + *p++ = SSL_COMPRESS_NULL; + *p++ = SSL_COMPRESS_DEFLATE; +#else SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); - SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", 0 ) ); + SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", SSL_COMPRESS_NULL ) ); *p++ = 1; *p++ = SSL_COMPRESS_NULL; +#endif if ( ssl->hostname != NULL ) { @@ -281,7 +291,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) #if defined(POLARSSL_DEBUG_C) time_t t; #endif - int ret, i; + int ret, i, comp; size_t n; int ext_len; unsigned char *buf; @@ -367,6 +377,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) } i = ( buf[39 + n] << 8 ) | buf[40 + n]; + comp = buf[41 + n]; /* * Initialize update checksum functions @@ -381,6 +392,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) */ if( ssl->resume == 0 || n == 0 || ssl->session->ciphersuite != i || + ssl->session->compression != comp || ssl->session->length != n || memcmp( ssl->session->id, buf + 39, n ) != 0 ) { @@ -388,6 +400,7 @@ static int ssl_parse_server_hello( ssl_context *ssl ) ssl->resume = 0; ssl->session->start = time( NULL ); ssl->session->ciphersuite = i; + ssl->session->compression = comp; ssl->session->length = n; memcpy( ssl->session->id, buf + 39, n ); } @@ -421,11 +434,16 @@ static int ssl_parse_server_hello( ssl_context *ssl ) break; } - if( buf[41 + n] != SSL_COMPRESS_NULL ) + if( comp != SSL_COMPRESS_NULL +#if defined(POLARSSL_ZLIB_SUPPORT) + && comp != SSL_COMPRESS_DEFLATE +#endif + ) { SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); } + ssl->session->compression = comp; /* TODO: Process extensions */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index ecf153609..e4de68e8d 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -316,6 +316,18 @@ static int ssl_parse_client_hello( ssl_context *ssl ) return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); } + ssl->session->compression = SSL_COMPRESS_NULL; +#if defined(POLARSSL_ZLIB_SUPPORT) + for( i = 0; i < comp_len; ++i ) + { + if( buf[41 + sess_len + ciph_len + i] == SSL_COMPRESS_DEFLATE ) + { + ssl->session->compression = SSL_COMPRESS_DEFLATE; + break; + } + } +#endif + SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 6, 32 ); SSL_DEBUG_BUF( 3, "client hello, session id", @@ -449,11 +461,12 @@ static int ssl_write_server_hello( ssl_context *ssl ) *p++ = (unsigned char)( ssl->session->ciphersuite >> 8 ); *p++ = (unsigned char)( ssl->session->ciphersuite ); - *p++ = SSL_COMPRESS_NULL; + *p++ = (unsigned char)( ssl->session->compression ); SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %d", ssl->session->ciphersuite ) ); - SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", 0 ) ); + SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", + ssl->session->compression ) ); ssl->out_msglen = p - buf; ssl->out_msgtype = SSL_MSG_HANDSHAKE; diff --git a/library/ssl_tls.c b/library/ssl_tls.c index fab20046a..a458e6287 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -639,6 +639,25 @@ int ssl_derive_keys( ssl_context *ssl ) memset( keyblk, 0, sizeof( keyblk ) ); +#if defined(POLARSSL_ZLIB_SUPPORT) + // Initialize compression + // + if( ssl->session->compression == SSL_COMPRESS_DEFLATE ) + { + SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) ); + + memset( &ssl->ctx_deflate, 0, sizeof( ssl->ctx_deflate ) ); + memset( &ssl->ctx_inflate, 0, sizeof( ssl->ctx_inflate ) ); + + if( deflateInit( &ssl->ctx_deflate, Z_DEFAULT_COMPRESSION ) != Z_OK || + inflateInit( &ssl->ctx_inflate ) != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + } +#endif /* POLARSSL_ZLIB_SUPPORT */ + SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); return( 0 ); @@ -1397,6 +1416,113 @@ static int ssl_decrypt_buf( ssl_context *ssl ) return( 0 ); } +#if defined(POLARSSL_ZLIB_SUPPORT) +/* + * Compression/decompression functions + */ +static int ssl_compress_buf( ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->out_msg; + size_t len_pre = ssl->out_msglen; + unsigned char *msg_pre; + + SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); + + msg_pre = (unsigned char*) malloc( len_pre ); + if( msg_pre == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len_pre ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memcpy( msg_pre, ssl->out_msg, len_pre ); + + SSL_DEBUG_MSG( 3, ( "before compression: msglen = %d, ", + ssl->out_msglen ) ); + + SSL_DEBUG_BUF( 4, "before compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + ssl->ctx_deflate.next_in = msg_pre; + ssl->ctx_deflate.avail_in = len_pre; + ssl->ctx_deflate.next_out = msg_post; + ssl->ctx_deflate.avail_out = SSL_BUFFER_LEN; + + ret = deflate( &ssl->ctx_deflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "failed to perform compression (%d)", ret ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->out_msglen = SSL_BUFFER_LEN - ssl->ctx_deflate.avail_out; + + free( msg_pre ); + + SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", + ssl->out_msglen ) ); + + SSL_DEBUG_BUF( 4, "after compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + SSL_DEBUG_MSG( 2, ( "<= compress buf" ) ); + + return( 0 ); +} + +static int ssl_decompress_buf( ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->in_msg; + size_t len_pre = ssl->in_msglen; + unsigned char *msg_pre; + + SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); + + msg_pre = (unsigned char*) malloc( len_pre ); + if( msg_pre == NULL ) + { + SSL_DEBUG_MSG( 1, ( "malloc(%d bytes) failed", len_pre ) ); + return( POLARSSL_ERR_SSL_MALLOC_FAILED ); + } + + memcpy( msg_pre, ssl->in_msg, len_pre ); + + SSL_DEBUG_MSG( 3, ( "before decompression: msglen = %d, ", + ssl->in_msglen ) ); + + SSL_DEBUG_BUF( 4, "before decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + ssl->ctx_inflate.next_in = msg_pre; + ssl->ctx_inflate.avail_in = len_pre; + ssl->ctx_inflate.next_out = msg_post; + ssl->ctx_inflate.avail_out = SSL_MAX_CONTENT_LEN; + + ret = inflate( &ssl->ctx_inflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "failed to perform decompression (%d)", ret ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->in_msglen = SSL_MAX_CONTENT_LEN - ssl->ctx_inflate.avail_out; + + free( msg_pre ); + + SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", + ssl->in_msglen ) ); + + SSL_DEBUG_BUF( 4, "after decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + SSL_DEBUG_MSG( 2, ( "<= decompress buf" ) ); + + return( 0 ); +} +#endif /* POLARSSL_ZLIB_SUPPORT */ + /* * Fill the input message buffer */ @@ -1495,6 +1621,20 @@ int ssl_write_record( ssl_context *ssl ) ssl->update_checksum( ssl, ssl->out_msg, len ); } +#if defined(POLARSSL_ZLIB_SUPPORT) + if( ssl->do_crypt != 0 && + ssl->session->compression == SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_compress_buf( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_compress_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + } +#endif /*POLARSSL_ZLIB_SUPPORT */ + #if defined(POLARSSL_SSL_HW_RECORD_ACCEL) if( ssl_hw_record_write != NULL) { @@ -1708,6 +1848,21 @@ int ssl_read_record( ssl_context *ssl ) } } +#if defined(POLARSSL_ZLIB_SUPPORT) + if( ssl->do_crypt != 0 && + ssl->session->compression == SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_decompress_buf( ssl ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_decompress_buf", ret ); + return( ret ); + } + + ssl->in_hdr[3] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_hdr[4] = (unsigned char)( ssl->in_msglen ); + } +#endif /* POLARSSL_ZLIB_SUPPORT */ + if( ssl->in_msgtype != SSL_MSG_HANDSHAKE && ssl->in_msgtype != SSL_MSG_ALERT && ssl->in_msgtype != SSL_MSG_CHANGE_CIPHER_SPEC && @@ -1761,12 +1916,13 @@ int ssl_read_record( ssl_context *ssl ) */ if( ssl->in_msg[0] == SSL_ALERT_LEVEL_FATAL ) { - SSL_DEBUG_MSG( 1, ( "is a fatal alert message" ) ); + SSL_DEBUG_MSG( 1, ( "is a fatal alert message (msg %d)", + ssl->in_msg[1] ) ); /** * Subtract from error code as ssl->in_msg[1] is 7-bit positive * error identifier. */ - return( POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE - ssl->in_msg[1] ); + return( POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE ); } if( ssl->in_msg[0] == SSL_ALERT_LEVEL_WARNING && @@ -2514,7 +2670,7 @@ int ssl_init( ssl_context *ssl ) * Reset an initialized and used SSL context for re-use while retaining * all application-set variables, function pointers and data. */ -void ssl_session_reset( ssl_context *ssl ) +int ssl_session_reset( ssl_context *ssl ) { ssl->state = SSL_HELLO_REQUEST; @@ -2555,9 +2711,39 @@ void ssl_session_reset( ssl_context *ssl ) if( ssl_hw_record_reset != NULL) { SSL_DEBUG_MSG( 2, ( "going for ssl_hw_record_reset()" ) ); - ssl_hw_record_reset( ssl ); + if( ssl_hw_record_reset( ssl ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_hw_record_reset", ret ); + return( POLARSSL_ERR_SSL_HW_ACCEL_FAILED ); + } } #endif + +#if defined(POLARSSL_ZLIB_SUPPORT) + // Reset compression state + // + if( ssl->session->compression == SSL_COMPRESS_DEFLATE ) + { + ssl->ctx_deflate.next_in = Z_NULL; + ssl->ctx_deflate.next_out = Z_NULL; + ssl->ctx_deflate.avail_in = 0; + ssl->ctx_deflate.avail_out = 0; + + ssl->ctx_inflate.next_in = Z_NULL; + ssl->ctx_inflate.next_out = Z_NULL; + ssl->ctx_inflate.avail_in = 0; + ssl->ctx_inflate.avail_out = 0; + + if( deflateReset( &ssl->ctx_deflate ) != Z_OK || + inflateReset( &ssl->ctx_inflate ) != Z_OK ) + { + SSL_DEBUG_MSG( 1, ( "Failed to reset compression" ) ); + return( POLARSSL_ERR_SSL_COMPRESSION_FAILED ); + } + } +#endif /* POLARSSL_ZLIB_SUPPORT */ + + return( 0 ); } /* @@ -3265,6 +3451,11 @@ void ssl_free( ssl_context *ssl ) } #endif +#if defined(POLARSSL_ZLIB_SUPPORT) + deflateEnd( &ssl->ctx_deflate ); + inflateEnd( &ssl->ctx_inflate ); +#endif + SSL_DEBUG_MSG( 2, ( "<= free" ) ); /* Actually free after last debug message */ diff --git a/programs/Makefile b/programs/Makefile index d28bc53ce..3aab43c14 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -15,6 +15,11 @@ ifdef WINDOWS LDFLAGS += -lws2_32 endif +# Zlib shared library extensions: +ifdef ZLIB +LDFLAGS += -lz +endif + APPS = aes/aescrypt2 aes/crypt_and_hash \ hash/hello hash/generic_sum \ hash/md5sum hash/sha1sum \ diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c index 0d2478718..d38683425 100644 --- a/programs/ssl/ssl_server.c +++ b/programs/ssl/ssl_server.c @@ -151,7 +151,7 @@ int my_ciphersuites[] = 0 }; -#define DEBUG_LEVEL 0 +#define DEBUG_LEVEL 5 void my_debug( void *ctx, int level, const char *str ) { diff --git a/tests/Makefile b/tests/Makefile index fd5d6a53d..3ceb19f69 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -17,6 +17,11 @@ ifdef WINDOWS LDFLAGS += -lws2_32 endif +# Zlib shared library extensions: +ifdef ZLIB +LDFLAGS += -lz +endif + APPS = test_suite_aes test_suite_arc4 \ test_suite_base64 test_suite_camellia \ test_suite_cipher.aes test_suite_cipher.camellia \