Add session saving/loading
For now, the header (version+format bytes) is duplicated. This might be
optimized later.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 2913b4f..485d1cd 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3926,7 +3926,11 @@
* \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.
@@ -3991,6 +3995,11 @@
* 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 37a7c22..e6d27e7 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10775,6 +10775,8 @@
{
unsigned char *p = buf;
size_t used = 0;
+ size_t session_len;
+ int ret = 0;
/*
* Enforce current usage restrictions
@@ -10816,6 +10818,29 @@
}
/*
+ * 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
*/
*olen = used;
@@ -10823,18 +10848,25 @@
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.
@@ -10865,6 +10897,8 @@
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
+ MBEDTLS_SSL_DEBUG_BUF( 4, "context to load", buf, len );
+
/*
* Check version identifier
*/
@@ -10879,6 +10913,35 @@
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
*/
if( p != end )
@@ -10888,6 +10951,21 @@
}
/*
+ * 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
*/
void mbedtls_ssl_free( mbedtls_ssl_context *ssl )