diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index eca6879e3..4e1d25a83 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -117,6 +117,15 @@ #define SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ #define SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ +/* RFC 6066 section 4, see also mfl_code_to_length in ssl_tls.c + * NONE must be zero so that memset()ing structure to zero works */ +#define SSL_MAX_FRAG_LEN_NONE 0 /*!< don't use this extension */ +#define SSL_MAX_FRAG_LEN_512 1 /*!< MaxFragmentLength 2^9 */ +#define SSL_MAX_FRAG_LEN_1024 2 /*!< MaxFragmentLength 2^10 */ +#define SSL_MAX_FRAG_LEN_2048 3 /*!< MaxFragmentLength 2^11 */ +#define SSL_MAX_FRAG_LEN_4096 4 /*!< MaxFragmentLength 2^12 */ +#define SSL_MAX_FRAG_LEN_INVALID 5 /*!< first invalid value */ + #define SSL_IS_CLIENT 0 #define SSL_IS_SERVER 1 #define SSL_COMPRESS_NULL 0 @@ -240,6 +249,8 @@ #define TLS_EXT_SERVERNAME 0 #define TLS_EXT_SERVERNAME_HOSTNAME 0 +#define TLS_EXT_MAX_FRAGMENT_LENGTH 1 + #define TLS_EXT_SUPPORTED_ELLIPTIC_CURVES 10 #define TLS_EXT_SUPPORTED_POINT_FORMATS 11 @@ -320,6 +331,8 @@ struct _ssl_session #if defined(POLARSSL_X509_PARSE_C) x509_cert *peer_cert; /*!< peer X.509 cert chain */ #endif /* POLARSSL_X509_PARSE_C */ + + unsigned char mfl_code; /*!< MaxFragmentLength negotiated by peer */ }; /* @@ -498,6 +511,8 @@ struct _ssl_context size_t out_msglen; /*!< record header: message length */ size_t out_left; /*!< amount of data not yet written */ + unsigned char mfl_code; /*!< MaxFragmentLength chosen by us */ + /* * PKI layer */ @@ -944,6 +959,23 @@ void ssl_set_max_version( ssl_context *ssl, int major, int minor ); */ void ssl_set_min_version( ssl_context *ssl, int major, int minor ); +/** + * \brief Set the maximum fragment length to emit and/or negotiate + * (Default: SSL_MAX_CONTENT_LEN, usually 2^14 bytes) + * (Server: set maximum fragment length to emit, + * usually negotiated by the client during handshake + * (Client: set maximum fragment length to emit *and* + * negotiate with the server during handshake) + * + * \param ssl SSL context + * \param mfl Code for maximum fragment length (allowed values: + * SSL_MAX_FRAG_LEN_512, SSL_MAX_FRAG_LEN_1024, + * SSL_MAX_FRAG_LEN_2048, SSL_MAX_FRAG_LEN_4096) + * + * \return O if successful or POLARSSL_ERR_SSL_BAD_INPUT_DATA + */ +int ssl_set_max_frag_len( ssl_context *ssl, unsigned char mfl_code ); + /** * \brief Enable / Disable renegotiation support for connection when * initiated by peer diff --git a/library/ssl_cli.c b/library/ssl_cli.c index aeba799cb..c89bf0cb0 100644 --- a/library/ssl_cli.c +++ b/library/ssl_cli.c @@ -269,6 +269,30 @@ static void ssl_write_supported_point_formats_ext( ssl_context *ssl, } #endif +static void ssl_write_max_fragment_length_ext( ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->mfl_code == SSL_MAX_FRAG_LEN_NONE ) { + *olen = 0; + return; + } + + SSL_DEBUG_MSG( 3, ( "client hello, adding max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->mfl_code; + + *olen = 5; +} + static int ssl_write_client_hello( ssl_context *ssl ) { int ret; @@ -436,6 +460,9 @@ static int ssl_write_client_hello( ssl_context *ssl ) ext_len += olen; #endif + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", ext_len ) ); @@ -461,7 +488,7 @@ static int ssl_write_client_hello( ssl_context *ssl ) } static int ssl_parse_renegotiation_info( ssl_context *ssl, - unsigned char *buf, + const unsigned char *buf, size_t len ) { int ret; @@ -499,6 +526,23 @@ static int ssl_parse_renegotiation_info( ssl_context *ssl, return( 0 ); } +static int ssl_parse_max_fragment_length_ext( ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + /* + * server should use the extension only if we did, + * and if so the server's value should match ours (and len is always 1) + */ + if( ssl->mfl_code == SSL_MAX_FRAG_LEN_NONE || + len != 1 || + buf[0] != ssl->mfl_code ) + { + return( POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + return( 0 ); +} static int ssl_parse_server_hello( ssl_context *ssl ) { @@ -690,6 +734,8 @@ static int ssl_parse_server_hello( ssl_context *ssl ) ext = buf + 44 + n; + SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d", ext_len ) ); + while( ext_len ) { unsigned int ext_id = ( ( ext[0] << 8 ) @@ -714,6 +760,17 @@ static int ssl_parse_server_hello( ssl_context *ssl ) break; + case TLS_EXT_MAX_FRAGMENT_LENGTH: + SSL_DEBUG_MSG( 3, ( "found max_fragment_length extension" ) ); + + if( ( ret = ssl_parse_max_fragment_length_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; + default: SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", ext_id ) ); diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 2aef9c415..3e1838667 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -291,6 +291,21 @@ static int ssl_parse_supported_point_formats( ssl_context *ssl, } #endif /* POLARSSL_ECP_C */ +static int ssl_parse_max_fragment_length_ext( ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 1 || buf[0] >= SSL_MAX_FRAG_LEN_INVALID ) + { + SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->mfl_code = buf[0]; + + return( 0 ); +} + #if defined(POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) static int ssl_parse_client_hello_v2( ssl_context *ssl ) { @@ -825,6 +840,14 @@ static int ssl_parse_client_hello( ssl_context *ssl ) break; #endif /* POLARSSL_ECP_C */ + case TLS_EXT_MAX_FRAGMENT_LENGTH: + SSL_DEBUG_MSG( 3, ( "found max fragment length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + default: SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", ext_id ) ); @@ -934,13 +957,67 @@ have_ciphersuite: return( 0 ); } +static void ssl_write_renegotiation_ext( ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->secure_renegotiation != SSL_SECURE_RENEGOTIATION ) + { + *olen = 0; + return; + } + + SSL_DEBUG_MSG( 3, ( "server hello, secure renegotiation extension" ) ); + + *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; + + 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; +} + +static void ssl_write_max_fragment_length_ext( ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->mfl_code == SSL_MAX_FRAG_LEN_NONE ) + { + *olen = 0; + return; + } + + SSL_DEBUG_MSG( 3, ( "server hello, max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->session_negotiate->mfl_code; + + *olen = 5; +} + static int ssl_write_server_hello( ssl_context *ssl ) { #if defined(POLARSSL_HAVE_TIME) time_t t; #endif int ret, n; - size_t ext_len = 0; + size_t olen, ext_len = 0; unsigned char *buf, *p; SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); @@ -986,10 +1063,12 @@ static int ssl_write_server_hello( ssl_context *ssl ) SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); /* - * 38 . 38 session id length - * 39 . 38+n session id - * 39+n . 40+n chosen ciphersuite - * 41+n . 41+n chosen compression alg. + * 38 . 38 session id length + * 39 . 38+n session id + * 39+n . 40+n chosen ciphersuite + * 41+n . 41+n chosen compression alg. + * 42+n . 43+n extensions length + * 44+n . 43+n+m extensions */ ssl->session_negotiate->length = n = 32; *p++ = (unsigned char) ssl->session_negotiate->length; @@ -1040,34 +1119,20 @@ static int ssl_write_server_hello( ssl_context *ssl ) SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", ssl->session_negotiate->compression ) ); - if( ssl->secure_renegotiation == SSL_SECURE_RENEGOTIATION ) - { - SSL_DEBUG_MSG( 3, ( "server hello, prepping for secure renegotiation extension" ) ); - ext_len += 5 + ssl->verify_data_len * 2; + /* + * First write extensions, then the total length + */ + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; - SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", - ext_len ) ); + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; - *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); - *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); - /* - * Secure renegotiation - */ - SSL_DEBUG_MSG( 3, ( "client hello, secure renegotiation extension" ) ); - - *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; - - 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; - } + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; ssl->out_msglen = p - buf; ssl->out_msgtype = SSL_MSG_HANDSHAKE; diff --git a/library/ssl_tls.c b/library/ssl_tls.c index dfeed3377..f701a8a1f 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -59,6 +59,23 @@ #define strcasecmp _stricmp #endif +/* + * Convert max_fragment_length codes to length. + * RFC 6066 says: + * enum{ + * 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255) + * } MaxFragmentLength; + * and we add 0 -> extension unused + */ +static unsigned int mfl_code_to_length[SSL_MAX_FRAG_LEN_INVALID] = +{ + SSL_MAX_CONTENT_LEN, /* SSL_MAX_FRAG_LEN_NONE */ + 512, /* SSL_MAX_FRAG_LEN_512 */ + 1024, /* SSL_MAX_FRAG_LEN_1024 */ + 2048, /* SSL_MAX_FRAG_LEN_2048 */ + 4096, /* SSL_MAX_FRAG_LEN_4096 */ +}; + #if defined(POLARSSL_SSL_HW_RECORD_ACCEL) int (*ssl_hw_record_init)(ssl_context *ssl, const unsigned char *key_enc, const unsigned char *key_dec, @@ -3111,6 +3128,19 @@ void ssl_set_min_version( ssl_context *ssl, int major, int minor ) ssl->min_minor_ver = minor; } +int ssl_set_max_frag_len( ssl_context *ssl, unsigned char mfl_code ) +{ + if( mfl_code >= sizeof( mfl_code_to_length ) || + mfl_code_to_length[mfl_code] > SSL_MAX_CONTENT_LEN ) + { + return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + } + + ssl->mfl_code = mfl_code; + + return( 0 ); +} + void ssl_set_renegotiation( ssl_context *ssl, int renegotiation ) { ssl->disable_renegotiation = renegotiation; @@ -3372,6 +3402,7 @@ int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) { int ret; size_t n; + unsigned int max_len; SSL_DEBUG_MSG( 2, ( "=> write" ) ); @@ -3384,8 +3415,21 @@ int ssl_write( ssl_context *ssl, const unsigned char *buf, size_t len ) } } - n = ( len < SSL_MAX_CONTENT_LEN ) - ? len : SSL_MAX_CONTENT_LEN; + /* + * Assume mfl_code is correct since it was checked when set + */ + max_len = mfl_code_to_length[ssl->mfl_code]; + + /* + * Check if a smaller max length was negociated + */ + if( ssl->session_out != NULL && + mfl_code_to_length[ssl->session_out->mfl_code] < max_len ) + { + max_len = mfl_code_to_length[ssl->session_out->mfl_code]; + } + + n = ( len < max_len) ? len : max_len; if( ssl->out_left != 0 ) { diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 036cc67ae..56d0e9112 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -57,8 +57,20 @@ #define DFL_MIN_VERSION -1 #define DFL_MAX_VERSION -1 #define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL +#define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE -#define GET_REQUEST "GET %s HTTP/1.0\r\n\r\n" +#define LONG_HEADER "User-agent: blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-01--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-02--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-03--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-04--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-05--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-06--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-" \ + "-07--blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-END\r\n" + +/* Uncomment LONG_HEADER in the definition of GET_REQUEST to test sending + * longer paquets (for fragmentation purposes) */ +#define GET_REQUEST "GET %s HTTP/1.0\r\n" /* LONG_HEADER */ "\r\n" /* * global options @@ -81,6 +93,7 @@ struct options int min_version; /* minimum protocol version accepted */ int max_version; /* maximum protocol version accepted */ int auth_mode; /* verify mode for connection */ + unsigned char mfl_code; /* code for maximum fragment length */ } opt; static void my_debug( void *ctx, int level, const char *str ) @@ -176,6 +189,8 @@ static int my_verify( void *data, x509_cert *crt, int depth, int *flags ) " options: ssl3, tls1, tls1_1, tls1_2\n" \ " auth_mode=%%s default: \"optional\"\n" \ " options: none, optional, required\n" \ + " max_frag_len=%%d default: 16384 (tls default)" \ + " options: 512, 1024, 2048, 4096" \ USAGE_PSK \ "\n" \ " force_ciphersuite= default: all enabled\n"\ @@ -197,7 +212,7 @@ int main( int argc, char *argv[] ) #else int main( int argc, char *argv[] ) { - int ret = 0, len, server_fd, i; + int ret = 0, len, server_fd, i, written, frags; unsigned char buf[1024]; #if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED) unsigned char psk[256]; @@ -265,6 +280,7 @@ int main( int argc, char *argv[] ) opt.min_version = DFL_MIN_VERSION; opt.max_version = DFL_MAX_VERSION; opt.auth_mode = DFL_AUTH_MODE; + opt.mfl_code = DFL_MFL_CODE; for( i = 1; i < argc; i++ ) { @@ -387,6 +403,19 @@ int main( int argc, char *argv[] ) else goto usage; } + else if( strcmp( p, "max_frag_len" ) == 0 ) + { + if( strcmp( q, "512" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_512; + else if( strcmp( q, "1024" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_1024; + else if( strcmp( q, "2048" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_2048; + else if( strcmp( q, "4096" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_4096; + else + goto usage; + } else goto usage; } @@ -592,6 +621,8 @@ int main( int argc, char *argv[] ) ssl_set_endpoint( &ssl, SSL_IS_CLIENT ); ssl_set_authmode( &ssl, opt.auth_mode ); + ssl_set_max_frag_len( &ssl, opt.mfl_code ); + ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg ); ssl_set_dbg( &ssl, my_debug, stdout ); ssl_set_bio( &ssl, net_recv, &server_fd, @@ -682,17 +713,20 @@ int main( int argc, char *argv[] ) len = sprintf( (char *) buf, GET_REQUEST, opt.request_page ); - while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 ) + for( written = 0, frags = 0; written < len; written += ret, frags++ ) { - if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) + while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 ) { - printf( " failed\n ! ssl_write returned -0x%x\n\n", -ret ); - goto exit; + if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) + { + printf( " failed\n ! ssl_write returned -0x%x\n\n", -ret ); + goto exit; + } } } - len = ret; - printf( " %d bytes written\n\n%s", len, (char *) buf ); + buf[written] = '\0'; + printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf ); /* * 7. Read the HTTP response diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 5b7639aed..d5ebb812b 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -68,11 +68,22 @@ #define DFL_MIN_VERSION -1 #define DFL_MAX_VERSION -1 #define DFL_AUTH_MODE SSL_VERIFY_OPTIONAL +#define DFL_MFL_CODE SSL_MAX_FRAG_LEN_NONE +#define LONG_RESPONSE "

01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "03-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "04-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "05-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "06-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ + "07-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah

\r\n" + +/* Uncomment LONG_RESPONSE at the end of HTTP_RESPONSE to test sending longer + * packets (for fragmentation purposes) */ #define HTTP_RESPONSE \ "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ "

PolarSSL Test Server

\r\n" \ - "

Successful connection using: %s

\r\n" + "

Successful connection using: %s

\r\n" // LONG_RESPONSE /* * global options @@ -93,6 +104,7 @@ struct options int min_version; /* minimum protocol version accepted */ int max_version; /* maximum protocol version accepted */ int auth_mode; /* verify mode for connection */ + unsigned char mfl_code; /* code for maximum fragment length */ } opt; static void my_debug( void *ctx, int level, const char *str ) @@ -147,6 +159,8 @@ static void my_debug( void *ctx, int level, const char *str ) " options: ssl3, tls1, tls1_1, tls1_2\n" \ " auth_mode=%%s default: \"optional\"\n" \ " options: none, optional, required\n" \ + " max_frag_len=%%d default: 16384 (tls default)" \ + " options: 512, 1024, 2048, 4096" \ USAGE_PSK \ "\n" \ " force_ciphersuite= default: all enabled\n"\ @@ -168,7 +182,7 @@ int main( int argc, char *argv[] ) #else int main( int argc, char *argv[] ) { - int ret = 0, len; + int ret = 0, len, written, frags; int listen_fd; int client_fd = -1; unsigned char buf[1024]; @@ -250,6 +264,7 @@ int main( int argc, char *argv[] ) opt.min_version = DFL_MIN_VERSION; opt.max_version = DFL_MAX_VERSION; opt.auth_mode = DFL_AUTH_MODE; + opt.mfl_code = DFL_MFL_CODE; for( i = 1; i < argc; i++ ) { @@ -368,6 +383,19 @@ int main( int argc, char *argv[] ) else goto usage; } + else if( strcmp( p, "max_frag_len" ) == 0 ) + { + if( strcmp( q, "512" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_512; + else if( strcmp( q, "1024" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_1024; + else if( strcmp( q, "2048" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_2048; + else if( strcmp( q, "4096" ) == 0 ) + opt.mfl_code = SSL_MAX_FRAG_LEN_4096; + else + goto usage; + } else goto usage; } @@ -562,6 +590,8 @@ int main( int argc, char *argv[] ) ssl_set_endpoint( &ssl, SSL_IS_SERVER ); ssl_set_authmode( &ssl, opt.auth_mode ); + ssl_set_max_frag_len( &ssl, opt.mfl_code ); + ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg ); ssl_set_dbg( &ssl, my_debug, stdout ); @@ -748,7 +778,7 @@ reset: } len = ret; - printf( " %d bytes read\n\n%s", len, (char *) buf ); + printf( " %d bytes read\n\n%s\n", len, (char *) buf ); if( memcmp( buf, "SERVERQUIT", 10 ) == 0 ) goto exit; @@ -767,23 +797,26 @@ reset: len = sprintf( (char *) buf, HTTP_RESPONSE, ssl_get_ciphersuite( &ssl ) ); - while( ( ret = ssl_write( &ssl, buf, len ) ) <= 0 ) + for( written = 0, frags = 0; written < len; written += ret, frags++ ) { - if( ret == POLARSSL_ERR_NET_CONN_RESET ) + while( ( ret = ssl_write( &ssl, buf + written, len - written ) ) <= 0 ) { - printf( " failed\n ! peer closed the connection\n\n" ); - goto reset; - } + if( ret == POLARSSL_ERR_NET_CONN_RESET ) + { + printf( " failed\n ! peer closed the connection\n\n" ); + goto reset; + } - if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) - { - printf( " failed\n ! ssl_write returned %d\n\n", ret ); - goto exit; + if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE ) + { + printf( " failed\n ! ssl_write returned %d\n\n", ret ); + goto exit; + } } } - len = ret; - printf( " %d bytes written\n\n%s\n", len, (char *) buf ); + buf[written] = '\0'; + printf( " %d bytes written in %d fragments\n\n%s\n", written, frags, (char *) buf ); ret = 0; goto reset;