diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 746bb1ee0..3610faeee 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -2188,10 +2188,16 @@ int mbedtls_ssl_session_load( mbedtls_ssl_session *session, * * \param session The session structure to be saved. * \param buf The buffer to write the serialized data to. It must be a - * writeable buffer of at least \p len bytes. + * writeable buffer of at least \p len bytes, or may be \c + * NULL if \p len is \c 0. * \param buf_len The number of bytes available for writing in \p buf. - * \param olen The size of the written data in bytes. It must point to a - * valid \c size_t. + * \param olen The size in bytes of the data that has been or would have + * been written. It must point to a valid \c size_t. + * + * \note \p olen is updated to the correct value regardless of + * whether \p buf_len was large enough. This makes it possible + * to determine the necessary size by calling this function + * with \p buf set to \c NULL and \p buf_len to \c 0. * * \return \c 0 if successful. * \return #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small. diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 459f519ef..2d7cd18d8 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -8791,7 +8791,7 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, size_t *olen ) { unsigned char *p = buf; - size_t left = buf_len; + size_t used = 0; #if defined(MBEDTLS_X509_CRT_PARSE_C) size_t cert_len; #endif /* MBEDTLS_X509_CRT_PARSE_C */ @@ -8799,12 +8799,13 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, /* * Shallow copy of the session structure */ - if( left < sizeof( mbedtls_ssl_session ) ) - return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); - left -= sizeof( mbedtls_ssl_session ); + used += sizeof( mbedtls_ssl_session ); - memcpy( p, session, sizeof( mbedtls_ssl_session ) ); - p += sizeof( mbedtls_ssl_session ); + if( used <= buf_len ) + { + memcpy( p, session, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + } /* * Copy of the peer's end-entity certificate @@ -8815,18 +8816,19 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, else cert_len = session->peer_cert->raw.len; - if( left < 3 + cert_len ) - return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); - left -= 3 + cert_len; + used += 3 + cert_len; - *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF ); - *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF ); - *p++ = (unsigned char)( ( cert_len ) & 0xFF ); - - if( session->peer_cert != NULL ) + if( used <= buf_len ) { - memcpy( p, session->peer_cert->raw.p, cert_len ); - p += cert_len; + *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( cert_len ) & 0xFF ); + + if( session->peer_cert != NULL ) + { + memcpy( p, session->peer_cert->raw.p, cert_len ); + p += cert_len; + } } #endif /* MBEDTLS_X509_CRT_PARSE_C */ @@ -8834,24 +8836,27 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session, * Copy of the session ticket if any */ #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) - if( left < 3 + session->ticket_len ) - return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); - left -= 3 + session->ticket_len; + used += 3 + session->ticket_len; - *p++ = (unsigned char)( ( session->ticket_len >> 16 ) & 0xFF ); - *p++ = (unsigned char)( ( session->ticket_len >> 8 ) & 0xFF ); - *p++ = (unsigned char)( ( session->ticket_len ) & 0xFF ); - - if( session->ticket != NULL ) + if( used <= buf_len ) { - memcpy( p, session->ticket, session->ticket_len ); - p += session->ticket_len; + *p++ = (unsigned char)( ( session->ticket_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session->ticket_len ) & 0xFF ); + + if( session->ticket != NULL ) + { + memcpy( p, session->ticket, session->ticket_len ); + p += session->ticket_len; + } } #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ /* Done */ - (void) left; - *olen = p - buf; + *olen = used; + + if( used > buf_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); return( 0 ); } diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 4b5674a0c..eae234e54 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -36,6 +36,8 @@ #define mbedtls_fprintf fprintf #define mbedtls_snprintf snprintf #define mbedtls_exit exit +#define mbedtls_calloc calloc +#define mbedtls_free free #define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS #define MBEDTLS_EXIT_FAILURE EXIT_FAILURE #endif @@ -721,8 +723,8 @@ int main( int argc, char *argv[] ) mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_ssl_session saved_session; - unsigned char session_data[MBEDTLS_SSL_MAX_CONTENT_LEN]; - size_t session_data_len; + unsigned char *session_data = NULL; + size_t session_data_len = 0; #if defined(MBEDTLS_TIMING_C) mbedtls_timing_delay_context timer; #endif @@ -1879,8 +1881,25 @@ int main( int argc, char *argv[] ) if( opt.reco_mode == 1 ) { + /* free any previously saved data */ + mbedtls_free( session_data ); + session_data = NULL; + + /* get size of the buffer needed */ + mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), + NULL, 0, &session_data_len ); + session_data = mbedtls_calloc( 1, session_data_len ); + if( session_data == NULL ) + { + mbedtls_printf( " failed\n ! alloc %u bytes for session data\n", + (unsigned) session_data_len ); + ret = MBEDTLS_ERR_SSL_ALLOC_FAILED; + goto exit; + } + + /* actually save session data */ if( ( ret = mbedtls_ssl_session_save( mbedtls_ssl_get_session_pointer( &ssl ), - session_data, sizeof( session_data ), + session_data, session_data_len, &session_data_len ) ) != 0 ) { mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n", @@ -1899,6 +1918,12 @@ int main( int argc, char *argv[] ) } mbedtls_printf( " ok\n" ); + + if( opt.reco_mode == 1 ) + { + mbedtls_printf( " [ Saved %u bytes of session data]\n", + (unsigned) session_data_len ); + } } #if defined(MBEDTLS_X509_CRT_PARSE_C) @@ -2416,6 +2441,7 @@ exit: mbedtls_ssl_config_free( &conf ); mbedtls_ctr_drbg_free( &ctr_drbg ); mbedtls_entropy_free( &entropy ); + mbedtls_free( session_data ); #if defined(_WIN32) mbedtls_printf( " + Press Enter to exit this program.\n" );