diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 89b560a27..bf7a320c1 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -3912,7 +3912,11 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl ); * \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. + * with \p buf set to \c NULL and \p buf_len to \c 0. However, + * the value of \p olen is only guaranteed to be correct when + * the function returns #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL or + * \c 0. If the return value is different, then the value of + * \p olen is undefined. * * \return \c 0 if successful. * \return #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small. @@ -3977,6 +3981,11 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl, * newly-configured value with the value that was active when * the context was saved. * + * \note When this function returns an error code, it calls + * mbedtls_ssl_free() on \p ssl. In this case, you need to + * prepare the context with the usual sequence starting with a + * call to mbedtls_ssl_init() if you want to use it again. + * * \param ssl The SSL context structure to be populated. It must have * been prepared as described in the note above. * \param buf The buffer holding the serialized connection data. It must diff --git a/library/ssl_tls.c b/library/ssl_tls.c index e838c20d1..f6d6156f9 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -11340,6 +11340,8 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl, { unsigned char *p = buf; size_t used = 0; + size_t session_len; + int ret = 0; /* * Enforce current usage restrictions @@ -11380,6 +11382,29 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl, p += sizeof( ssl_serialized_context_header ); } + /* + * Session (length + data) + */ + ret = mbedtls_ssl_session_save( ssl->session, NULL, 0, &session_len ); + if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ) + return( ret ); + + used += 4 + session_len; + if( used <= buf_len ) + { + *p++ = (unsigned char)( ( session_len >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( session_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( session_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( session_len ) & 0xFF ); + + ret = mbedtls_ssl_session_save( ssl->session, + p, session_len, &session_len ); + if( ret != 0 ) + return( ret ); + + p += session_len; + } + /* * Done */ @@ -11388,18 +11413,25 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl, if( used > buf_len ) return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + MBEDTLS_SSL_DEBUG_BUF( 4, "saved context", buf, used ); + return( 0 ); } /* - * Deserialize a full SSL context + * Unserialize context, see mbedtls_ssl_context_save() for format. + * + * This internal version is wrapped by a public function that cleans up in + * case of error. */ -int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl, - const unsigned char *buf, - size_t len ) +static int ssl_context_load( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) { const unsigned char *p = buf; const unsigned char * const end = buf + len; + size_t session_len; + int ret; /* * The context should have been freshly setup or reset. @@ -11430,6 +11462,8 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl, return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); } + MBEDTLS_SSL_DEBUG_BUF( 4, "context to load", buf, len ); + /* * Check version identifier */ @@ -11443,6 +11477,35 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl, } p += sizeof( ssl_serialized_context_header ); + /* + * Session + */ + if( (size_t)( end - p ) < 4 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session_len = ( (size_t) p[0] << 24 ) | + ( (size_t) p[1] << 16 ) | + ( (size_t) p[2] << 8 ) | + ( (size_t) p[3] ); + p += 4; + + ssl->session = mbedtls_calloc( 1, sizeof( mbedtls_ssl_session ) ); + if( ssl->session == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + mbedtls_ssl_session_init( ssl->session ); + + ssl->session_in = ssl->session; + ssl->session_out = ssl->session; + + if( (size_t)( end - p ) < session_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ret = mbedtls_ssl_session_load( ssl->session, p, session_len ); + if( ret != 0 ) + return( ret ); + + p += session_len; + /* * Done - should have consumed entire buffer */ @@ -11452,6 +11515,21 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl, return( 0 ); } +/* + * Unserialize context: public wrapper for error cleaning + */ +int mbedtls_ssl_context_load( mbedtls_ssl_context *context, + const unsigned char *buf, + size_t len ) +{ + int ret = ssl_context_load( context, buf, len ); + + if( ret != 0 ) + mbedtls_ssl_free( context ); + + return( ret ); +} + /* * Free an SSL context */