Merge pull request #616 from mpg/context-s11n

[baremetal] Implement context serialization
This commit is contained in:
Manuel Pégourié-Gonnard 2019-07-30 00:07:23 +02:00 committed by GitHub
commit cdb83e7c88
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 818 additions and 115 deletions

View file

@ -3903,6 +3903,7 @@ int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl );
*/
void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
/**
* \brief Save an active connection as serialized data in a buffer.
* This allows the freeing or re-using of the SSL context
@ -3918,10 +3919,10 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
* \note When this function succeeds, it calls
* mbedtls_ssl_session_reset() on \p ssl which as a result is
* no longer associated with the connection that has been
* serialized. This avoids creating copies of the session
* serialized. This avoids creating copies of the connection
* state. You're then free to either re-use the context
* structure for a different connection, or call
* mbedtls_ssl_session_free() on it. See the documentation of
* mbedtls_ssl_free() on it. See the documentation of
* mbedtls_ssl_session_reset() for more details.
*
* \param ssl The SSL context to save. On success, it is no longer
@ -3936,19 +3937,26 @@ 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.
* \return #MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed
* while reseting the context.
* \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if a handshake is in
* progress, or there is pending data for reading or sending,
* or the connection does not use DTLS 1.2 with and AEAD
* or the connection does not use DTLS 1.2 with an AEAD
* ciphersuite, or renegotiation is enabled.
*/
int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
unsigned char *buf,
size_t buf_len,
size_t *olen );
/**
* \brief Load serialized connection data to an SSL context.
*
@ -3982,15 +3990,12 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
* (unless they were already set before calling
* mbedtls_ssl_session_reset() and the values are suitable for
* the present connection). Specifically, you want to call
* at least mbedtls_ssl_set_bio(). If you're using a read
* timeout (that is, you called
* mbedtls_ssl_conf_read_timeout() with a non-zero timeout)
* and non-blocking I/O, you also need to set timer callbacks
* by calling mbedtls_ssl_set_timer_cb(). All other SSL setter
* functions are not necessary to call, either because they're
* only used in handshakes, or because the setting is already
* saved. You might choose to call them anyway, for example in
* order to share code between the cases of establishing a new
* at least mbedtls_ssl_set_bio() and
* mbedtls_ssl_set_timer_cb(). All other SSL setter functions
* are not necessary to call, either because they're only used
* in handshakes, or because the setting is already saved. You
* might choose to call them anyway, for example in order to
* share code between the cases of establishing a new
* connection and the case of loading an already-established
* connection.
*
@ -4000,6 +4005,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
@ -4008,11 +4018,14 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
*
* \return \c 0 if successful.
* \return #MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed.
* \return #MBEDTLS_ERR_SSL_VERSION_MISMATCH if the serialized data
* comes from a different Mbed TLS version or build.
* \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if input data is invalid.
*/
int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
const unsigned char *buf,
size_t len );
#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
/**
* \brief Initialize an SSL configuration context

View file

@ -728,6 +728,12 @@ struct mbedtls_ssl_transform
z_stream ctx_deflate; /*!< compression context */
z_stream ctx_inflate; /*!< decompression context */
#endif
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
/* We need the Hello random bytes in order to re-derive keys from the
* Master Secret and other session info, see ssl_populate_transform() */
unsigned char randbytes[64]; /*!< ServerHello.random+ClientHello.random */
#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
};
static inline int mbedtls_ssl_transform_get_minor_ver( mbedtls_ssl_transform const *transform )
@ -740,6 +746,21 @@ static inline int mbedtls_ssl_transform_get_minor_ver( mbedtls_ssl_transform con
#endif
}
/*
* Return 1 if the transform uses an AEAD cipher, 0 otherwise.
* Equivalently, return 0 if a separate MAC is used, 1 otherwise.
*/
static inline int mbedtls_ssl_transform_uses_aead(
const mbedtls_ssl_transform *transform )
{
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
return( transform->maclen == 0 && transform->taglen != 0 );
#else
(void) transform;
return( 1 );
#endif
}
/*
* Internal representation of record frames
*
@ -1222,6 +1243,17 @@ static inline int mbedtls_ssl_get_renego_status(
#endif
}
static inline int mbedtls_ssl_conf_is_renegotiation_enabled(
const mbedtls_ssl_config *conf )
{
#if defined(MBEDTLS_SSL_RENEGOTIATION)
return( conf->disable_renegotiation ==
MBEDTLS_SSL_RENEGOTIATION_ENABLED );
#else
(void) conf;
return( 0 );
#endif
}
/*
* Getter functions for fields in mbedtls_ssl_config which may

View file

@ -823,7 +823,9 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
(void) ssl;
#endif
/* Copy info about negotiated version and extensions */
/*
* Some data just needs copying into the structure
*/
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
transform->encrypt_then_mac = encrypt_then_mac;
@ -835,6 +837,10 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
((void) minor_ver);
#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
memcpy( transform->randbytes, randbytes, sizeof( transform->randbytes ) );
#endif
/*
* Get various info structures
*/
@ -9375,10 +9381,11 @@ static unsigned char ssl_serialized_session_header[] = {
* verify_result is put before peer_cert so that all mandatory fields come
* together in one block.
*/
int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
unsigned char *buf,
size_t buf_len,
size_t *olen )
static int ssl_session_save( const mbedtls_ssl_session *session,
unsigned char omit_header,
unsigned char *buf,
size_t buf_len,
size_t *olen )
{
unsigned char *p = buf;
size_t used = 0;
@ -9391,17 +9398,20 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
#endif
#endif
/*
* Add version identifier
*/
used += sizeof( ssl_serialized_session_header );
if( used <= buf_len )
if( !omit_header )
{
memcpy( p, ssl_serialized_session_header,
sizeof( ssl_serialized_session_header ) );
p += sizeof( ssl_serialized_session_header );
/*
* Add version identifier
*/
used += sizeof( ssl_serialized_session_header );
if( used <= buf_len )
{
memcpy( p, ssl_serialized_session_header,
sizeof( ssl_serialized_session_header ) );
p += sizeof( ssl_serialized_session_header );
}
}
/*
@ -9567,12 +9577,24 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
}
/*
* Unserialize session, see mbedtls_ssl_session_save() for format.
* Public wrapper for ssl_session_save()
*/
int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
unsigned char *buf,
size_t buf_len,
size_t *olen )
{
return( ssl_session_save( session, 0, buf, buf_len, olen ) );
}
/*
* Deserialize session, see mbedtls_ssl_session_save() for format.
*
* This internal version is wrapped by a public function that cleans up in
* case of error.
* case of error, and has an extra option omit_header.
*/
static int ssl_session_load( mbedtls_ssl_session *session,
unsigned char omit_header,
const unsigned char *buf,
size_t len )
{
@ -9588,19 +9610,22 @@ static int ssl_session_load( mbedtls_ssl_session *session,
#endif
#endif
/*
* Check version identifier
*/
if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( memcmp( p, ssl_serialized_session_header,
sizeof( ssl_serialized_session_header ) ) != 0 )
if( !omit_header )
{
return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
/*
* Check version identifier
*/
if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( memcmp( p, ssl_serialized_session_header,
sizeof( ssl_serialized_session_header ) ) != 0 )
{
return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
}
p += sizeof( ssl_serialized_session_header );
}
p += sizeof( ssl_serialized_session_header );
/*
* Time
@ -9807,13 +9832,13 @@ static int ssl_session_load( mbedtls_ssl_session *session,
}
/*
* Unserialize session: public wrapper for error cleaning
* Deserialize session: public wrapper for error cleaning
*/
int mbedtls_ssl_session_load( mbedtls_ssl_session *session,
const unsigned char *buf,
size_t len )
{
int ret = ssl_session_load( session, buf, len );
int ret = ssl_session_load( session, 0, buf, len );
if( ret != 0 )
mbedtls_ssl_session_free( session );
@ -10014,7 +10039,7 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl )
if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ||
ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ||
ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED )
! mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
{
return( 0 );
}
@ -10721,39 +10746,616 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) );
}
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID 1u
#else
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID 0u
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT 1u
#else
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT 0u
#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY 1u
#else
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY 0u
#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
#if defined(MBEDTLS_SSL_ALPN)
#define SSL_SERIALIZED_CONTEXT_CONFIG_ALPN 1u
#else
#define SSL_SERIALIZED_CONTEXT_CONFIG_ALPN 0u
#endif /* MBEDTLS_SSL_ALPN */
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT 0
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT 1
#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT 2
#define SSL_SERIALIZED_CONTEXT_CONFIG_ALPN_BIT 3
#define SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG \
( (uint32_t) ( \
( SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID << SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT ) | \
( SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT << SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT ) | \
( SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY << SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT ) | \
( SSL_SERIALIZED_CONTEXT_CONFIG_ALPN << SSL_SERIALIZED_CONTEXT_CONFIG_ALPN_BIT ) | \
0u ) )
static unsigned char ssl_serialized_context_header[] = {
MBEDTLS_VERSION_MAJOR,
MBEDTLS_VERSION_MINOR,
MBEDTLS_VERSION_PATCH,
( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG >> 8 ) & 0xFF,
( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG >> 0 ) & 0xFF,
( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >> 16 ) & 0xFF,
( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >> 8 ) & 0xFF,
( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >> 0 ) & 0xFF,
};
/*
* Serialize a full SSL context
*
* The format of the serialized data is:
* (in the presentation language of TLS, RFC 8446 section 3)
*
* // header
* opaque mbedtls_version[3]; // major, minor, patch
* opaque context_format[5]; // version-specific field determining
* // the format of the remaining
* // serialized data.
* Note: When updating the format, remember to keep these
* version+format bytes. (We may make their size part of the API.)
*
* // session sub-structure
* opaque session<1..2^32-1>; // see mbedtls_ssl_session_save()
* // transform sub-structure
* uint8 random[64]; // ServerHello.random+ClientHello.random
* uint8 in_cid<0..2^8-1> // Connection ID: expected incoming value
* uint8 out_cid<0..2^8-1> // Connection ID: outgoing value to use
* // fields from ssl_context
* uint32 badmac_seen; // DTLS: number of records with failing MAC
* uint64 in_window_top; // DTLS: last validated record seq_num
* uint64 in_window; // DTLS: bitmask for replay protection
* uint8 disable_datagram_packing; // DTLS: only one record per datagram
* uint64 cur_out_ctr; // Record layer: outgoing sequence number
* uint16 mtu; // DTLS: path mtu (max outgoing fragment size)
* uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
*
* Note that many fields of the ssl_context or sub-structures are not
* serialized, as they fall in one of the following categories:
*
* 1. forced value (eg in_left must be 0)
* 2. pointer to dynamically-allocated memory (eg session, transform)
* 3. value can be re-derived from other data (eg session keys from MS)
* 4. value was temporary (eg content of input buffer)
* 5. value will be provided by the user again (eg I/O callbacks and context)
*/
int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
unsigned char *buf,
size_t buf_len,
size_t *olen )
{
/* Unimplemented */
(void) ssl;
unsigned char *p = buf;
size_t used = 0;
size_t session_len;
int ret = 0;
if( buf != NULL )
memset( buf, 0, buf_len );
/*
* Enforce usage restrictions, see "return BAD_INPUT_DATA" in
* this function's documentation.
*
* These are due to assumptions/limitations in the implementation. Some of
* them are likely to stay (no handshake in progress) some might go away
* (only DTLS) but are currently used to simplify the implementation.
*/
/* The initial handshake must be over */
if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( ssl->handshake != NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
/* Double-check that sub-structures are indeed ready */
if( ssl->transform == NULL || ssl->session == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
/* There must be no pending incoming or outgoing data */
if( mbedtls_ssl_check_pending( ssl ) != 0 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( ssl->out_left != 0 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
/* Protocol must be DLTS, not TLS */
if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
/* Version must be 1.2 */
if( mbedtls_ssl_get_major_ver( ssl ) != MBEDTLS_SSL_MAJOR_VERSION_3 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
/* We must be using an AEAD ciphersuite */
if( mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
/* Renegotiation must not be enabled */
if( mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
*olen = 0;
/*
* Version and format identifier
*/
used += sizeof( ssl_serialized_context_header );
if( used <= buf_len )
{
memcpy( p, ssl_serialized_context_header,
sizeof( ssl_serialized_context_header ) );
p += sizeof( ssl_serialized_context_header );
}
/*
* Session (length + data)
*/
ret = ssl_session_save( ssl->session, 1, 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 = ssl_session_save( ssl->session, 1,
p, session_len, &session_len );
if( ret != 0 )
return( ret );
p += session_len;
}
/*
* Transform
*/
used += sizeof( ssl->transform->randbytes );
if( used <= buf_len )
{
memcpy( p, ssl->transform->randbytes,
sizeof( ssl->transform->randbytes ) );
p += sizeof( ssl->transform->randbytes );
}
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
used += 2 + ssl->transform->in_cid_len + ssl->transform->out_cid_len;
if( used <= buf_len )
{
*p++ = ssl->transform->in_cid_len;
memcpy( p, ssl->transform->in_cid, ssl->transform->in_cid_len );
p += ssl->transform->in_cid_len;
*p++ = ssl->transform->out_cid_len;
memcpy( p, ssl->transform->out_cid, ssl->transform->out_cid_len );
p += ssl->transform->out_cid_len;
}
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
/*
* Saved fields from top-level ssl_context structure
*/
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
used += 4;
if( used <= buf_len )
{
*p++ = (unsigned char)( ( ssl->badmac_seen >> 24 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->badmac_seen >> 16 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->badmac_seen >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->badmac_seen ) & 0xFF );
}
#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
used += 16;
if( used <= buf_len )
{
*p++ = (unsigned char)( ( ssl->in_window_top >> 56 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top >> 48 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top >> 40 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top >> 32 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top >> 24 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top >> 16 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window_top ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 56 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 48 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 40 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 32 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 24 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 16 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->in_window ) & 0xFF );
}
#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
used += 1;
if( used <= buf_len )
{
*p++ = ssl->disable_datagram_packing;
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
used += 8;
if( used <= buf_len )
{
memcpy( p, ssl->cur_out_ctr, 8 );
p += 8;
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
used += 2;
if( used <= buf_len )
{
*p++ = (unsigned char)( ( ssl->mtu >> 8 ) & 0xFF );
*p++ = (unsigned char)( ( ssl->mtu ) & 0xFF );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_ALPN)
{
const uint8_t alpn_len = ssl->alpn_chosen
? (uint8_t) strlen( ssl->alpn_chosen )
: 0;
used += 1 + alpn_len;
if( used <= buf_len )
{
*p++ = alpn_len;
if( ssl->alpn_chosen != NULL )
{
memcpy( p, ssl->alpn_chosen, alpn_len );
p += alpn_len;
}
}
}
#endif /* MBEDTLS_SSL_ALPN */
/*
* Done
*/
*olen = used;
if( used > buf_len )
return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
MBEDTLS_SSL_DEBUG_BUF( 4, "saved context", buf, used );
return( ssl_session_reset_int( ssl, 0 ) );
}
/*
* Helper to get TLS 1.2 PRF from ciphersuite
* (Duplicates bits of logic from ssl_set_handshake_prfs().)
*/
typedef int (*tls_prf_fn)( const unsigned char *secret, size_t slen,
const char *label,
const unsigned char *random, size_t rlen,
unsigned char *dstbuf, size_t dlen );
static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id )
{
mbedtls_ssl_ciphersuite_handle_t const info =
mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
const mbedtls_md_type_t hash = mbedtls_ssl_suite_get_mac( info );
#if defined(MBEDTLS_SHA512_C)
if( hash == MBEDTLS_MD_SHA384 )
return( tls_prf_sha384 );
#else
(void) hash;
#endif
return( tls_prf_sha256 );
}
/*
* Deserialize context, see mbedtls_ssl_context_save() for format.
*
* This internal version is wrapped by a public function that cleans up in
* case of error.
*/
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.
* Give the user an error in case of obvious misuse.
* (Checking session is useful because it won't be NULL if we're
* renegotiating, or if the user mistakenly loaded a session first.)
*/
if( ssl->state != MBEDTLS_SSL_HELLO_REQUEST ||
ssl->session != NULL )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
/*
* We can't check that the config matches the initial one, but we can at
* least check it matches the requirements for serializing.
*/
if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
mbedtls_ssl_conf_get_max_major_ver( ssl->conf ) <
MBEDTLS_SSL_MAJOR_VERSION_3 ||
mbedtls_ssl_conf_get_min_major_ver( ssl->conf ) >
MBEDTLS_SSL_MAJOR_VERSION_3 ||
mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) <
MBEDTLS_SSL_MINOR_VERSION_3 ||
mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) >
MBEDTLS_SSL_MINOR_VERSION_3 ||
mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
{
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
MBEDTLS_SSL_DEBUG_BUF( 4, "context to load", buf, len );
/*
* Check version identifier
*/
if( (size_t)( end - p ) < sizeof( ssl_serialized_context_header ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
if( memcmp( p, ssl_serialized_context_header,
sizeof( ssl_serialized_context_header ) ) != 0 )
{
return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
}
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;
/* This has been allocated by ssl_handshake_init(), called by
* by either ssl_session_reset_int() or mbedtls_ssl_setup(). */
ssl->session = ssl->session_negotiate;
ssl->session_in = ssl->session;
ssl->session_out = ssl->session;
ssl->session_negotiate = NULL;
if( (size_t)( end - p ) < session_len )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ret = ssl_session_load( ssl->session, 1, p, session_len );
if( ret != 0 )
{
mbedtls_ssl_session_free( ssl->session );
return( ret );
}
p += session_len;
/*
* Transform
*/
/* This has been allocated by ssl_handshake_init(), called by
* by either ssl_session_reset_int() or mbedtls_ssl_setup(). */
ssl->transform = ssl->transform_negotiate;
ssl->transform_in = ssl->transform;
ssl->transform_out = ssl->transform;
ssl->transform_negotiate = NULL;
/* Read random bytes and populate structure */
if( (size_t)( end - p ) < sizeof( ssl->transform->randbytes ) )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ret = ssl_populate_transform( ssl->transform,
mbedtls_ssl_session_get_ciphersuite( ssl->session ),
ssl->session->master,
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
ssl->session->encrypt_then_mac,
#endif
#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
ssl->session->trunc_hmac,
#endif
#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
#if defined(MBEDTLS_ZLIB_SUPPORT)
ssl->session->compression,
#endif
ssl_tls12prf_from_cs(
mbedtls_ssl_session_get_ciphersuite( ssl->session) ),
p, /* currently pointing to randbytes */
MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */
mbedtls_ssl_conf_get_endpoint( ssl->conf ),
ssl );
if( ret != 0 )
return( ret );
p += sizeof( ssl->transform->randbytes );
#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
/* Read connection IDs and store them */
if( (size_t)( end - p ) < 1 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ssl->transform->in_cid_len = *p++;
if( (size_t)( end - p ) < ssl->transform->in_cid_len + 1u )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
memcpy( ssl->transform->in_cid, p, ssl->transform->in_cid_len );
p += ssl->transform->in_cid_len;
ssl->transform->out_cid_len = *p++;
if( (size_t)( end - p ) < ssl->transform->out_cid_len )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
memcpy( ssl->transform->out_cid, p, ssl->transform->out_cid_len );
p += ssl->transform->out_cid_len;
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
/*
* Saved fields from top-level ssl_context structure
*/
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
if( (size_t)( end - p ) < 4 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ssl->badmac_seen = ( (uint32_t) p[0] << 24 ) |
( (uint32_t) p[1] << 16 ) |
( (uint32_t) p[2] << 8 ) |
( (uint32_t) p[3] );
p += 4;
#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
if( (size_t)( end - p ) < 16 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ssl->in_window_top = ( (uint64_t) p[0] << 56 ) |
( (uint64_t) p[1] << 48 ) |
( (uint64_t) p[2] << 40 ) |
( (uint64_t) p[3] << 32 ) |
( (uint64_t) p[4] << 24 ) |
( (uint64_t) p[5] << 16 ) |
( (uint64_t) p[6] << 8 ) |
( (uint64_t) p[7] );
p += 8;
ssl->in_window = ( (uint64_t) p[0] << 56 ) |
( (uint64_t) p[1] << 48 ) |
( (uint64_t) p[2] << 40 ) |
( (uint64_t) p[3] << 32 ) |
( (uint64_t) p[4] << 24 ) |
( (uint64_t) p[5] << 16 ) |
( (uint64_t) p[6] << 8 ) |
( (uint64_t) p[7] );
p += 8;
#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( (size_t)( end - p ) < 1 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ssl->disable_datagram_packing = *p++;
#endif /* MBEDTLS_SSL_PROTO_DTLS */
if( (size_t)( end - p ) < 8 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
memcpy( ssl->cur_out_ctr, p, 8 );
p += 8;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( (size_t)( end - p ) < 2 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
ssl->mtu = ( p[0] << 8 ) | p[1];
p += 2;
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_ALPN)
{
uint8_t alpn_len;
const char **cur;
if( (size_t)( end - p ) < 1 )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
alpn_len = *p++;
if( alpn_len != 0 && ssl->conf->alpn_list != NULL )
{
/* alpn_chosen should point to an item in the configured list */
for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ )
{
if( strlen( *cur ) == alpn_len &&
memcmp( p, cur, alpn_len ) == 0 )
{
ssl->alpn_chosen = *cur;
break;
}
}
}
/* can only happen on conf mismatch */
if( alpn_len != 0 && ssl->alpn_chosen == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
p += alpn_len;
}
#endif /* MBEDTLS_SSL_ALPN */
/*
* Forced fields from top-level ssl_context structure
*
* Most of them already set to the correct value by mbedtls_ssl_init() and
* mbedtls_ssl_reset(), so we only need to set the remaining ones.
*/
ssl->state = MBEDTLS_SSL_HANDSHAKE_OVER;
#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
#endif /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
ssl->minor_ver = MBEDTLS_SSL_MINOR_VERSION_3;
#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
ssl->in_epoch = 1;
#endif
/* mbedtls_ssl_reset() leaves the handshake sub-structure allocated,
* which we don't want - otherwise we'd end up freeing the wrong transform
* by calling ssl_handshake_wrapup_free_hs_transform() inappropriately. */
if( ssl->handshake != NULL )
{
mbedtls_ssl_handshake_free( ssl );
mbedtls_free( ssl->handshake );
ssl->handshake = NULL;
}
/*
* Done - should have consumed entire buffer
*/
if( p != end )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
return( 0 );
}
/*
* Deserialize a full SSL context
* Deserialize context: public wrapper for error cleaning
*/
int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
int mbedtls_ssl_context_load( mbedtls_ssl_context *context,
const unsigned char *buf,
size_t len )
{
/* Unimplemented */
(void) ssl;
(void) buf;
(void) len;
int ret = ssl_context_load( context, buf, len );
return( 0 );
if( ret != 0 )
mbedtls_ssl_free( context );
return( ret );
}
#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
/*
* Free an SSL context

View file

@ -807,6 +807,10 @@ int main( int argc, char *argv[] )
#endif
char *p, *q;
const int *list;
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
unsigned char *context_buf = NULL;
size_t context_buf_len;
#endif
/*
* Make sure memory references are valid.
@ -2493,16 +2497,11 @@ send_request:
if( opt.serialize != 0 )
{
size_t buf_len;
unsigned char *context_buf = NULL;
opt.serialize = 0;
mbedtls_printf( " Serializing live connection..." );
mbedtls_printf( " . Serializing live connection..." );
ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
/* Allow stub implementation returning 0 for now */
if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL &&
ret != 0 )
if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_context_save returned "
"-0x%x\n\n", -ret );
@ -2517,18 +2516,29 @@ send_request:
goto exit;
}
context_buf_len = buf_len;
if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
buf_len, &buf_len ) ) != 0 )
{
mbedtls_printf( "failed\n ! mbedtls_ssl_context_save returned "
mbedtls_printf( " failed\n ! mbedtls_ssl_context_save returned "
"-0x%x\n\n", -ret );
goto exit;
}
mbedtls_printf( " ok\n" );
if( opt.serialize == 1 )
{
/* nothing to do here, done by context_save() already */
mbedtls_printf( " . Context has been reset... ok" );
}
if( opt.serialize == 2 )
{
mbedtls_printf( " . Freeing and reinitializing context..." );
mbedtls_ssl_free( &ssl );
mbedtls_ssl_init( &ssl );
@ -2536,7 +2546,7 @@ send_request:
if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned "
" -0x%x\n\n", -ret );
"-0x%x\n\n", -ret );
goto exit;
}
@ -2544,26 +2554,25 @@ send_request:
mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv,
NULL );
else
mbedtls_ssl_set_bio( &ssl, &server_fd,
mbedtls_net_send, mbedtls_net_recv,
mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send,
mbedtls_net_recv,
opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
#if defined(MBEDTLS_TIMING_C)
if( opt.nbio != 0 && opt.read_timeout != 0 )
{
#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
!defined(MBEDTLS_SSL_CONF_GET_TIMER)
mbedtls_ssl_set_timer_cb( &ssl, &timer,
mbedtls_timing_set_delay,
mbedtls_timing_get_delay );
mbedtls_ssl_set_timer_cb( &ssl, &timer,
mbedtls_timing_set_delay,
mbedtls_timing_get_delay );
#else
mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
#endif
}
#endif /* MBEDTLS_TIMING_C */
mbedtls_printf( " ok\n" );
}
mbedtls_printf( " Deserializing connection..." );
mbedtls_printf( " . Deserializing connection..." );
if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
buf_len ) ) != 0 )
@ -2573,6 +2582,12 @@ send_request:
goto exit;
}
mbedtls_free( context_buf );
context_buf = NULL;
context_buf_len = 0;
mbedtls_printf( " ok\n" );
}
#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
@ -2711,6 +2726,11 @@ exit:
if( session_data != NULL )
mbedtls_platform_zeroize( session_data, session_data_len );
mbedtls_free( session_data );
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
if( context_buf != NULL )
mbedtls_platform_zeroize( context_buf, context_buf_len );
mbedtls_free( context_buf );
#endif
#if defined(_WIN32)
mbedtls_printf( " + Press Enter to exit this program.\n" );

View file

@ -1443,6 +1443,10 @@ int main( int argc, char *argv[] )
size_t cid_len = 0;
size_t cid_renego_len = 0;
#endif
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
unsigned char *context_buf = NULL;
size_t context_buf_len;
#endif
int i;
char *p, *q;
@ -3508,16 +3512,11 @@ data_exchange:
if( opt.serialize != 0 )
{
size_t buf_len;
unsigned char *context_buf = NULL;
opt.serialize = 0;
mbedtls_printf( " Serializing live connection..." );
mbedtls_printf( " . Serializing live connection..." );
ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
/* Allow stub implementation returning 0 for now */
if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL &&
ret != 0 )
if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
{
mbedtls_printf( " failed\n ! mbedtls_ssl_context_save returned "
"-0x%x\n\n", -ret );
@ -3532,18 +3531,44 @@ data_exchange:
goto exit;
}
context_buf_len = buf_len;
if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
buf_len, &buf_len ) ) != 0 )
{
mbedtls_printf( "failed\n ! mbedtls_ssl_context_save returned "
mbedtls_printf( " failed\n ! mbedtls_ssl_context_save returned "
"-0x%x\n\n", -ret );
goto exit;
}
mbedtls_printf( " ok\n" );
/*
* This simulates a workflow where you have a long-lived server
* instance, potentially with a pool of ssl_context objects, and you
* just want to re-use one while the connection is inactive: in that
* case you can just reset() it, and then it's ready to receive
* serialized data from another connection (or the same here).
*/
if( opt.serialize == 1 )
{
/* nothing to do here, done by context_save() already */
mbedtls_printf( " . Context has been reset... ok" );
}
/*
* This simulates a workflow where you have one server instance per
* connection, and want to release it entire when the connection is
* inactive, and spawn it again when needed again - this would happen
* between ssl_free() and ssl_init() below, together with any other
* teardown/startup code needed - for example, preparing the
* ssl_config again (see section 3 "setup stuff" in this file).
*/
if( opt.serialize == 2 )
{
mbedtls_printf( " . Freeing and reinitializing context..." );
mbedtls_ssl_free( &ssl );
mbedtls_ssl_init( &ssl );
@ -3555,6 +3580,12 @@ data_exchange:
goto exit;
}
/*
* This illustrates the minimum amount of things you need to set
* up, however you could set up much more if desired, for example
* if you want to share your set up code between the case of
* establishing a new connection and this case.
*/
if( opt.nbio == 2 )
mbedtls_ssl_set_bio( &ssl, &client_fd, my_send, my_recv,
NULL );
@ -3564,21 +3595,20 @@ data_exchange:
opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
#if defined(MBEDTLS_TIMING_C)
if( opt.nbio != 0 && opt.read_timeout != 0 )
{
#if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
!defined(MBEDTLS_SSL_CONF_GET_TIMER)
mbedtls_ssl_set_timer_cb( &ssl, &timer,
mbedtls_timing_set_delay,
mbedtls_timing_get_delay );
mbedtls_ssl_set_timer_cb( &ssl, &timer,
mbedtls_timing_set_delay,
mbedtls_timing_get_delay );
#else
mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
#endif
}
#endif /* MBEDTLS_TIMING_C */
mbedtls_printf( " ok\n" );
}
mbedtls_printf( " Deserializing connection..." );
mbedtls_printf( " . Deserializing connection..." );
if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
buf_len ) ) != 0 )
@ -3588,6 +3618,12 @@ data_exchange:
goto exit;
}
mbedtls_free( context_buf );
context_buf = NULL;
context_buf_len = 0;
mbedtls_printf( " ok\n" );
}
#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
@ -3679,6 +3715,12 @@ exit:
mbedtls_free( buf );
#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
if( context_buf != NULL )
mbedtls_platform_zeroize( context_buf, context_buf_len );
mbedtls_free( context_buf );
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
#if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_memory_buffer_alloc_status();

View file

@ -1322,56 +1322,50 @@ run_test "Truncated HMAC, DTLS: client enabled, server enabled" \
# Tests for Context serialization
skip_next_test
requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
run_test "(STUB) Context serialization, client serializes" \
"$P_SRV serialize=0 exchanges=2" \
"$P_CLI serialize=1 exchanges=2" \
run_test "Context serialization, client serializes" \
"$P_SRV dtls=1 serialize=0 exchanges=2" \
"$P_CLI dtls=1 serialize=1 exchanges=2" \
0 \
-c "Deserializing connection..." \
-S "Deserializing connection..."
skip_next_test
requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
run_test "(STUB) Context serialization, server serializes" \
"$P_SRV serialize=1 exchanges=2" \
"$P_CLI serialize=0 exchanges=2" \
run_test "Context serialization, server serializes" \
"$P_SRV dtls=1 serialize=1 exchanges=2" \
"$P_CLI dtls=1 serialize=0 exchanges=2" \
0 \
-C "Deserializing connection..." \
-s "Deserializing connection..."
skip_next_test
requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
run_test "(STUB) Context serialization, both serialize" \
"$P_SRV serialize=1 exchanges=2" \
"$P_CLI serialize=1 exchanges=2" \
run_test "Context serialization, both serialize" \
"$P_SRV dtls=1 serialize=1 exchanges=2" \
"$P_CLI dtls=1 serialize=1 exchanges=2" \
0 \
-c "Deserializing connection..." \
-s "Deserializing connection..."
skip_next_test
requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
run_test "(STUB) Context serialization, re-init, client serializes" \
"$P_SRV serialize=0 exchanges=2" \
"$P_CLI serialize=2 exchanges=2" \
run_test "Context serialization, re-init, client serializes" \
"$P_SRV dtls=1 serialize=0 exchanges=2" \
"$P_CLI dtls=1 serialize=2 exchanges=2" \
0 \
-c "Deserializing connection..." \
-S "Deserializing connection..."
skip_next_test
requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
run_test "(STUB) Context serialization, re-init, server serializes" \
"$P_SRV serialize=2 exchanges=2" \
"$P_CLI serialize=0 exchanges=2" \
run_test "Context serialization, re-init, server serializes" \
"$P_SRV dtls=1 serialize=2 exchanges=2" \
"$P_CLI dtls=1 serialize=0 exchanges=2" \
0 \
-C "Deserializing connection..." \
-s "Deserializing connection..."
skip_next_test
requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
run_test "(STUB) Context serialization, re-init, both serialize" \
"$P_SRV serialize=2 exchanges=2" \
"$P_CLI serialize=2 exchanges=2" \
run_test "Context serialization, re-init, both serialize" \
"$P_SRV dtls=1 serialize=2 exchanges=2" \
"$P_CLI dtls=1 serialize=2 exchanges=2" \
0 \
-c "Deserializing connection..." \
-s "Deserializing connection..."