Merge remote-tracking branch 'origin/pr/2792' into development
Merged from the top PR in a multi-part PR series:
- https://github.com/ARMmbed/mbedtls/pull/2792 (merged from here)
- https://github.com/ARMmbed/mbedtls/pull/2791
- https://github.com/ARMmbed/mbedtls/pull/2789
- https://github.com/ARMmbed/mbedtls/pull/2788
- https://github.com/ARMmbed/mbedtls/pull/2785
- https://github.com/ARMmbed/mbedtls/pull/2766
- https://github.com/ARMmbed/mbedtls/pull/2764
* origin/pr/2792: (114 commits)
Don't redefine calloc and free
Add changelog entry to record checking
Fix compiler warning
Add debug messages
Remove duplicate entries from ChangeLog
Fix parameter name in doxygen
Add missing guards for mac usage
Improve reability and debugability of large if
Fix a typo in a comment
Fix MSVC warning
Fix compile error in reduced configurations
Avoid duplication of session format header
Implement config-checking header to context s11n
Provide serialisation API only if it's enabled
Fix compiler warning: comparing signed to unsigned
Actually reset the context on save as advertised
Re-use buffer allocated by handshake_init()
Enable serialisation tests in ssl-opt.sh
Change requirements for setting timer callback
Add setting of forced fields when deserializing
...
diff --git a/ChangeLog b/ChangeLog
index d847692..a0eee53 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -31,6 +31,15 @@
changed its IP or port. The feature is enabled at compile-time by setting
MBEDTLS_SSL_DTLS_CONNECTION_ID (disabled by default), and at run-time
through the new APIs mbedtls_ssl_conf_cid() and mbedtls_ssl_set_cid().
+ * Add new API functions mbedtls_ssl_session_save() and
+ mbedtls_ssl_session_load() to allow serializing a session, for example to
+ store it in non-volatile storage, and later using it for TLS session
+ resumption.
+ * Add a new API function mbedtls_ssl_check_record() to allow checking that
+ an incoming record is valid, authentic and has not been seen before. This
+ feature can be used alongside Connection ID and SSL context serialisation.
+ The feature is enabled at compile-time by MBEDTLS_SSL_RECORD_CHECKING
+ option.
API Changes
* Extend the MBEDTLS_SSL_EXPORT_KEYS to export the handshake randbytes,
@@ -96,7 +105,6 @@
* Fix propagation of restart contexts in restartable EC operations.
This could previously lead to segmentation faults in builds using an
address-sanitizer and enabling but not using MBEDTLS_ECP_RESTARTABLE.
-
Changes
* Server's RSA certificate in certs.c was SHA-1 signed. In the default
mbedTLS configuration only SHA-2 signed certificates are accepted.
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 8e00fc4..877d52e 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1404,6 +1404,33 @@
//#define MBEDTLS_SSL_ASYNC_PRIVATE
/**
+ * \def MBEDTLS_SSL_CONTEXT_SERIALIZATION
+ *
+ * Enable serialization of the TLS context structures, through use of the
+ * functions mbedtls_ssl_context_save() and mbedtls_ssl_context_load().
+ *
+ * This pair of functions allows one side of a connection to serialize the
+ * context associated with the connection, then free or re-use that context
+ * while the serialized state is persisted elsewhere, and finally deserialize
+ * that state to a live context for resuming read/write operations on the
+ * connection. From a protocol perspective, the state of the connection is
+ * unaffected, in particular this is entirely transparent to the peer.
+ *
+ * Note: this is distinct from TLS session resumption, which is part of the
+ * protocol and fully visible by the peer. TLS session resumption enables
+ * establishing new connections associated to a saved session with shorter,
+ * lighter handshakes, while context serialization is a local optimization in
+ * handling a single, potentially long-lived connection.
+ *
+ * Enabling these APIs makes some SSL structures larger, as 64 extra bytes are
+ * saved after the handshake to allow for more efficient serialization, so if
+ * you don't need this feature you'll save RAM by disabling it.
+ *
+ * Comment to disable the context serialization APIs.
+ */
+#define MBEDTLS_SSL_CONTEXT_SERIALIZATION
+
+/**
* \def MBEDTLS_SSL_DEBUG_ALL
*
* Enable the debug messages in SSL module for all issues.
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index 20a245a..06bb1c9 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -100,6 +100,7 @@
* ECP 4 10 (Started from top)
* MD 5 5
* HKDF 5 1 (Started from top)
+ * SSL 5 1 (Started from 0x5F00)
* CIPHER 6 8 (Started from 0x6080)
* SSL 6 24 (Started from top, plus 0x6000)
* SSL 7 32
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 652c4f5..458857f 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -127,6 +127,7 @@
#define MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -0x6500 /**< The asynchronous operation is not completed yet. */
#define MBEDTLS_ERR_SSL_EARLY_MESSAGE -0x6480 /**< Internal-only message signaling that a message arrived early. */
#define MBEDTLS_ERR_SSL_UNEXPECTED_CID -0x6000 /**< An encrypted DTLS-frame with an unexpected CID was received. */
+#define MBEDTLS_ERR_SSL_VERSION_MISMATCH -0x5F00 /**< An operation failed due to an unexpected version or configuration. */
#define MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -0x7000 /**< A cryptographic operation is in progress. Try again later. */
/*
@@ -845,6 +846,14 @@
/*
* This structure is used for storing current session data.
+ *
+ * Note: when changing this definition, we need to check and update:
+ * - in tests/suites/test_suite_ssl.function:
+ * ssl_populate_session() and ssl_serialize_session_save_load()
+ * - in library/ssl_tls.c:
+ * mbedtls_ssl_session_init() and mbedtls_ssl_session_free()
+ * mbedtls_ssl_session_save() and ssl_session_load()
+ * ssl_session_copy()
*/
struct mbedtls_ssl_session
{
@@ -2349,6 +2358,90 @@
#endif /* MBEDTLS_SSL_CLI_C */
/**
+ * \brief Load serialized session data into a session structure.
+ * On client, this can be used for loading saved sessions
+ * before resuming them with mbedstls_ssl_set_session().
+ * On server, this can be used for alternative implementations
+ * of session cache or session tickets.
+ *
+ * \warning If a peer certificate chain is associated with the session,
+ * the serialized state will only contain the peer's
+ * end-entity certificate and the result of the chain
+ * verification (unless verification was disabled), but not
+ * the rest of the chain.
+ *
+ * \see mbedtls_ssl_session_save()
+ * \see mbedtls_ssl_set_session()
+ *
+ * \param session The session structure to be populated. It must have been
+ * initialised with mbedtls_ssl_session_init() but not
+ * populated yet.
+ * \param buf The buffer holding the serialized session data. It must be a
+ * readable buffer of at least \p len bytes.
+ * \param len The size of the serialized data in bytes.
+ *
+ * \return \c 0 if successful.
+ * \return #MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed.
+ * \return #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if input data is invalid.
+ * \return #MBEDTLS_ERR_SSL_VERSION_MISMATCH if the serialized data
+ * was generated in a different version or configuration of
+ * Mbed TLS.
+ * \return Another negative value for other kinds of errors (for
+ * example, unsupported features in the embedded certificate).
+ */
+int mbedtls_ssl_session_load( mbedtls_ssl_session *session,
+ const unsigned char *buf,
+ size_t len );
+
+/**
+ * \brief Save session structure as serialized data in a buffer.
+ * On client, this can be used for saving session data,
+ * potentially in non-volatile storage, for resuming later.
+ * On server, this can be used for alternative implementations
+ * of session cache or session tickets.
+ *
+ * \see mbedtls_ssl_session_load()
+ * \see mbedtls_ssl_get_session_pointer()
+ *
+ * \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, 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 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.
+ */
+int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
+ unsigned char *buf,
+ size_t buf_len,
+ size_t *olen );
+
+/**
+ * \brief Get a pointer to the current session structure, for example
+ * to serialize it.
+ *
+ * \warning Ownership of the session remains with the SSL context, and
+ * the returned pointer is only guaranteed to be valid until
+ * the next API call operating on the same \p ssl context.
+ *
+ * \see mbedtls_ssl_session_save()
+ *
+ * \param ssl The SSL context.
+ *
+ * \return A pointer to the current session if successful.
+ * \return \c NULL if no session is active.
+ */
+const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl );
+
+/**
* \brief Set the list of allowed ciphersuites and the preference
* order. First in the list has the highest preference.
* (Overrides all version-specific lists)
@@ -3786,6 +3879,130 @@
*/
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
+ * while still picking up the connection later in a way that
+ * it entirely transparent to the peer.
+ *
+ * \see mbedtls_ssl_context_load()
+ *
+ * \note This feature is currently only available under certain
+ * conditions, see the documentation of the return value
+ * #MBEDTLS_ERR_SSL_BAD_INPUT_DATA for details.
+ *
+ * \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 connection
+ * state. You're then free to either re-use the context
+ * structure for a different connection, or call
+ * 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
+ * associated with the connection that has been serialized.
+ * \param buf The buffer to write the serialized data to. It must be a
+ * writeable buffer of at least \p buf_len bytes, or may be \c
+ * NULL if \p buf_len is \c 0.
+ * \param buf_len The number of bytes available for writing in \p buf.
+ * \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. 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 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.
+ *
+ * \see mbedtls_ssl_context_save()
+ *
+ * \warning The same serialized data must never be loaded into more
+ * that one context. In order to ensure that, after
+ * successfully loading serialized data to an SSL context, you
+ * should immediately destroy or invalidate all copies of the
+ * serialized data that was loaded. Loading the same data in
+ * more than one context would cause severe security failures
+ * including but not limited to loss of confidentiality.
+ *
+ * \note Before calling this function, the SSL context must be
+ * prepared in one of the two following ways. The first way is
+ * to take a context freshly initialised with
+ * mbedtls_ssl_init() and call mbedtls_ssl_setup() on it with
+ * the same ::mbedtls_ssl_config structure that was used in
+ * the original connection. The second way is to
+ * call mbedtls_ssl_session_reset() on a context that was
+ * previously prepared as above but used in the meantime.
+ * Either way, you must not use the context to perform a
+ * handshake between calling mbedtls_ssl_setup() or
+ * mbedtls_ssl_session_reset() and calling this function. You
+ * may however call other setter functions in that time frame
+ * as indicated in the note below.
+ *
+ * \note Before or after calling this function successfully, you
+ * also need to configure some connection-specific callbacks
+ * and settings before you can use the connection again
+ * (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() 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.
+ *
+ * \note If you have new information about the path MTU, you want to
+ * call mbedtls_ssl_set_mtu() after calling this function, as
+ * otherwise this function would overwrite your
+ * 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
+ * be a readable buffer of at least \p len bytes.
+ * \param len The size of the serialized data in bytes.
+ *
+ * \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
* Just makes the context ready for
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 63a0633..f703da9 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -458,7 +458,7 @@
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t);
- void (*calc_verify)(mbedtls_ssl_context *, unsigned char *);
+ void (*calc_verify)(const mbedtls_ssl_context *, unsigned char *, size_t *);
void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int);
mbedtls_ssl_tls_prf_cb *tls_prf;
@@ -642,9 +642,30 @@
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 */
};
/*
+ * 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
*
* Instances come in two flavors:
diff --git a/library/error.c b/library/error.c
index e401a84..23a0f97 100644
--- a/library/error.c
+++ b/library/error.c
@@ -525,6 +525,8 @@
mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" );
if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_CID) )
mbedtls_snprintf( buf, buflen, "SSL - An encrypted DTLS-frame with an unexpected CID was received" );
+ if( use_ret == -(MBEDTLS_ERR_SSL_VERSION_MISMATCH) )
+ mbedtls_snprintf( buf, buflen, "SSL - An operation failed due to an unexpected version or configuration" );
if( use_ret == -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) )
mbedtls_snprintf( buf, buflen, "SSL - A cryptographic operation is in progress. Try again later" );
#endif /* MBEDTLS_SSL_TLS_C */
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index f403aa0..57e5d8a 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -3625,7 +3625,7 @@
unsigned char hash[48];
unsigned char *hash_start = hash;
mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE;
- unsigned int hashlen;
+ size_t hashlen;
void *rs_ctx = NULL;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) );
@@ -3674,7 +3674,7 @@
sign:
#endif
- ssl->handshake->calc_verify( ssl, hash );
+ ssl->handshake->calc_verify( ssl, hash, &hashlen );
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_1)
@@ -3692,7 +3692,6 @@
* sha_hash
* SHA(handshake_messages);
*/
- hashlen = 36;
md_alg = MBEDTLS_MD_NONE;
/*
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index a19179a..b1da073 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -4361,7 +4361,10 @@
}
/* Calculate hash and verify signature */
- ssl->handshake->calc_verify( ssl, hash );
+ {
+ size_t dummy_hlen;
+ ssl->handshake->calc_verify( ssl, hash, &dummy_hlen );
+ }
if( ( ret = mbedtls_pk_verify( peer_pk,
md_alg, hash_start, hashlen,
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index ed65bcd..6dad5d1 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -186,189 +186,6 @@
}
/*
- * Serialize a session in the following format:
- *
- * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is enabled:
- * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
- * n . n+2 peer_cert length = m (0 if no certificate)
- * n+3 . n+2+m peer cert ASN.1
- *
- * - If MBEDTLS_SSL_KEEP_PEER_CERTIFICATE is disabled:
- * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
- * n . n length of peer certificate digest = k (0 if no digest)
- * n+1 . n+k peer certificate digest (digest type encoded in session)
- */
-static int ssl_save_session( const mbedtls_ssl_session *session,
- unsigned char *buf, size_t buf_len,
- size_t *olen )
-{
- unsigned char *p = buf;
- size_t left = buf_len;
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- size_t cert_len;
-#else
- size_t cert_digest_len;
-#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
- if( left < sizeof( mbedtls_ssl_session ) )
- return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
-
- /* This also copies the values of pointer fields in the
- * session to be serialized, but they'll be ignored when
- * loading the session through ssl_load_session(). */
- memcpy( p, session, sizeof( mbedtls_ssl_session ) );
- p += sizeof( mbedtls_ssl_session );
- left -= sizeof( mbedtls_ssl_session );
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- if( session->peer_cert == NULL )
- cert_len = 0;
- else
- cert_len = session->peer_cert->raw.len;
-
- if( left < 3 + cert_len )
- return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
-
- *p++ = (unsigned char)( ( cert_len >> 16 ) & 0xFF );
- *p++ = (unsigned char)( ( cert_len >> 8 ) & 0xFF );
- *p++ = (unsigned char)( ( cert_len ) & 0xFF );
- left -= 3;
-
- if( session->peer_cert != NULL )
- memcpy( p, session->peer_cert->raw.p, cert_len );
-
- p += cert_len;
- left -= cert_len;
-#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
- if( session->peer_cert_digest != NULL )
- cert_digest_len = 0;
- else
- cert_digest_len = session->peer_cert_digest_len;
-
- if( left < 1 + cert_digest_len )
- return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
-
- *p++ = (unsigned char) cert_digest_len;
- left--;
-
- if( session->peer_cert_digest != NULL )
- memcpy( p, session->peer_cert_digest, cert_digest_len );
-
- p += cert_digest_len;
- left -= cert_digest_len;
-#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
- *olen = p - buf;
-
- return( 0 );
-}
-
-/*
- * Unserialise session, see ssl_save_session()
- */
-static int ssl_load_session( mbedtls_ssl_session *session,
- const unsigned char *buf, size_t len )
-{
- const unsigned char *p = buf;
- const unsigned char * const end = buf + len;
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- size_t cert_len;
-#else
- size_t cert_digest_len;
-#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
- if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
- memcpy( session, p, sizeof( mbedtls_ssl_session ) );
- p += sizeof( mbedtls_ssl_session );
-
- /* Non-NULL pointer fields of `session` are meaningless
- * and potentially harmful. Zeroize them for safety. */
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- session->peer_cert = NULL;
-#else
- session->peer_cert_digest = NULL;
-#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
- session->ticket = NULL;
-#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
-
-#if defined(MBEDTLS_X509_CRT_PARSE_C)
-#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
- /* Deserialize CRT from the end of the ticket. */
- if( 3 > (size_t)( end - p ) )
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
- cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
- p += 3;
-
- if( cert_len != 0 )
- {
- int ret;
-
- if( cert_len > (size_t)( end - p ) )
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
- session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
-
- if( session->peer_cert == NULL )
- return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-
- mbedtls_x509_crt_init( session->peer_cert );
-
- if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
- p, cert_len ) ) != 0 )
- {
- mbedtls_x509_crt_free( session->peer_cert );
- mbedtls_free( session->peer_cert );
- session->peer_cert = NULL;
- return( ret );
- }
-
- p += cert_len;
- }
-#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
- /* Deserialize CRT digest from the end of the ticket. */
- if( 1 > (size_t)( end - p ) )
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
- cert_digest_len = (size_t) p[0];
- p++;
-
- if( cert_digest_len != 0 )
- {
- if( cert_digest_len > (size_t)( end - p ) ||
- cert_digest_len != session->peer_cert_digest_len )
- {
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
- }
-
- session->peer_cert_digest = mbedtls_calloc( 1, cert_digest_len );
- if( session->peer_cert_digest == NULL )
- return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-
- memcpy( session->peer_cert_digest, p, cert_digest_len );
- p += cert_digest_len;
- }
-#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
-
- if( p != end )
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
- return( 0 );
-}
-
-/*
* Create session ticket, with the following structure:
*
* struct {
@@ -427,8 +244,9 @@
goto cleanup;
/* Dump session state */
- if( ( ret = ssl_save_session( session,
- state, end - state, &clear_len ) ) != 0 ||
+ if( ( ret = mbedtls_ssl_session_save( session,
+ state, end - state,
+ &clear_len ) ) != 0 ||
(unsigned long) clear_len > 65535 )
{
goto cleanup;
@@ -551,7 +369,7 @@
}
/* Actually load session */
- if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
+ if( ( ret = mbedtls_ssl_session_load( session, ticket, clear_len ) ) != 0 )
goto cleanup;
#if defined(MBEDTLS_HAVE_TIME)
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 913d6f9..99d3065 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -47,6 +47,7 @@
#include "mbedtls/ssl.h"
#include "mbedtls/ssl_internal.h"
#include "mbedtls/platform_util.h"
+#include "mbedtls/version.h"
#include <string.h>
@@ -855,25 +856,25 @@
#endif
#if defined(MBEDTLS_SSL_PROTO_SSL3)
-static void ssl_calc_verify_ssl( mbedtls_ssl_context *, unsigned char * );
+static void ssl_calc_verify_ssl( const mbedtls_ssl_context *, unsigned char *, size_t * );
static void ssl_calc_finished_ssl( mbedtls_ssl_context *, unsigned char *, int );
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
-static void ssl_calc_verify_tls( mbedtls_ssl_context *, unsigned char * );
+static void ssl_calc_verify_tls( const mbedtls_ssl_context *, unsigned char *, size_t * );
static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int );
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t );
-static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *,unsigned char * );
+static void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *,unsigned char *, size_t * );
static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int );
#endif
#if defined(MBEDTLS_SHA512_C)
static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t );
-static void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *, unsigned char * );
+static void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *, unsigned char *, size_t * );
static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int );
#endif
#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
@@ -977,13 +978,57 @@
return( tls_prf( secret, slen, label, random, rlen, dstbuf, dlen ) );
}
-int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
+/* Type for the TLS PRF */
+typedef int ssl_tls_prf_t(const unsigned char *, size_t, const char *,
+ const unsigned char *, size_t,
+ unsigned char *, size_t);
+
+/*
+ * Populate a transform structure with session keys and all the other
+ * necessary information.
+ *
+ * Parameters:
+ * - [in/out]: transform: structure to populate
+ * [in] must be just initialised with mbedtls_ssl_transform_init()
+ * [out] fully populated, ready for use by mbedtls_ssl_{en,de}crypt_buf()
+ * - [in] ciphersuite
+ * - [in] master
+ * - [in] encrypt_then_mac
+ * - [in] trunc_hmac
+ * - [in] compression
+ * - [in] tls_prf: pointer to PRF to use for key derivation
+ * - [in] randbytes: buffer holding ServerHello.random + ClientHello.random
+ * - [in] minor_ver: SSL/TLS minor version
+ * - [in] endpoint: client or server
+ * - [in] ssl: optionally used for:
+ * - MBEDTLS_SSL_HW_RECORD_ACCEL: whole context
+ * - MBEDTLS_SSL_EXPORT_KEYS: ssl->conf->{f,p}_export_keys
+ * - MBEDTLS_DEBUG_C: ssl->conf->{f,p}_dbg
+ */
+static int ssl_populate_transform( mbedtls_ssl_transform *transform,
+ int ciphersuite,
+ const unsigned char master[48],
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ int encrypt_then_mac,
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+ int trunc_hmac,
+#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+ int compression,
+#endif
+ ssl_tls_prf_t tls_prf,
+ const unsigned char randbytes[64],
+ int minor_ver,
+ unsigned endpoint,
+ const mbedtls_ssl_context *ssl )
{
int ret = 0;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
int psa_fallthrough;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
- unsigned char tmp[64];
unsigned char keyblk[256];
unsigned char *key1;
unsigned char *key2;
@@ -996,27 +1041,37 @@
const mbedtls_cipher_info_t *cipher_info;
const mbedtls_md_info_t *md_info;
- /* cf. RFC 5246, Section 8.1:
- * "The master secret is always exactly 48 bytes in length." */
- size_t const master_secret_len = 48;
+#if !defined(MBEDTLS_SSL_HW_RECORD_ACCEL) && \
+ !defined(MBEDTLS_SSL_EXPORT_KEYS) && \
+ !defined(MBEDTLS_DEBUG_C)
+ ssl = NULL; /* make sure we don't use it except for those cases */
+ (void) ssl;
+#endif
-#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
- unsigned char session_hash[48];
-#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
-
- mbedtls_ssl_session *session = ssl->session_negotiate;
- mbedtls_ssl_transform *transform = ssl->transform_negotiate;
- mbedtls_ssl_handshake_params *handshake = ssl->handshake;
-
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
-
+ /*
+ * 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 = session->encrypt_then_mac;
+ transform->encrypt_then_mac = encrypt_then_mac;
#endif
- transform->minor_ver = ssl->minor_ver;
+ transform->minor_ver = minor_ver;
- ciphersuite_info = handshake->ciphersuite_info;
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ memcpy( transform->randbytes, randbytes, sizeof( transform->randbytes ) );
+#endif
+
+ /*
+ * Get various info structures
+ */
+ ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuite );
+ if( ciphersuite_info == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %d not found",
+ ciphersuite ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+
cipher_info = mbedtls_cipher_info_from_type( ciphersuite_info->cipher );
if( cipher_info == NULL )
{
@@ -1054,204 +1109,9 @@
#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
/*
- * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions
+ * Compute key block using the PRF
*/
-#if defined(MBEDTLS_SSL_PROTO_SSL3)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
- {
- handshake->tls_prf = ssl3_prf;
- handshake->calc_verify = ssl_calc_verify_ssl;
- handshake->calc_finished = ssl_calc_finished_ssl;
- }
- else
-#endif
-#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
- if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
- {
- handshake->tls_prf = tls1_prf;
- handshake->calc_verify = ssl_calc_verify_tls;
- handshake->calc_finished = ssl_calc_finished_tls;
- }
- else
-#endif
-#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
-#if defined(MBEDTLS_SHA512_C)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 &&
- ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
- {
- handshake->tls_prf = tls_prf_sha384;
- handshake->calc_verify = ssl_calc_verify_tls_sha384;
- handshake->calc_finished = ssl_calc_finished_tls_sha384;
- }
- else
-#endif
-#if defined(MBEDTLS_SHA256_C)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
- {
- handshake->tls_prf = tls_prf_sha256;
- handshake->calc_verify = ssl_calc_verify_tls_sha256;
- handshake->calc_finished = ssl_calc_finished_tls_sha256;
- }
- else
-#endif
-#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
- return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
- }
-
- /*
- * SSLv3:
- * master =
- * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) +
- * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) +
- * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) )
- *
- * TLSv1+:
- * master = PRF( premaster, "master secret", randbytes )[0..47]
- */
- if( handshake->resume != 0 )
- {
- MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) );
- }
- else
- {
- /* The label for the KDF used for key expansion.
- * This is either "master secret" or "extended master secret"
- * depending on whether the Extended Master Secret extension
- * is used. */
- char const *lbl = "master secret";
-
- /* The salt for the KDF used for key expansion.
- * - If the Extended Master Secret extension is not used,
- * this is ClientHello.Random + ServerHello.Random
- * (see Sect. 8.1 in RFC 5246).
- * - If the Extended Master Secret extension is used,
- * this is the transcript of the handshake so far.
- * (see Sect. 4 in RFC 7627). */
- unsigned char const *salt = handshake->randbytes;
- size_t salt_len = 64;
-
-#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
- if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED )
- {
- MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) );
-
- lbl = "extended master secret";
- salt = session_hash;
- ssl->handshake->calc_verify( ssl, session_hash );
-#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
- {
-#if defined(MBEDTLS_SHA512_C)
- if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
- {
- salt_len = 48;
- }
- else
-#endif /* MBEDTLS_SHA512_C */
- salt_len = 32;
- }
- else
-#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
- salt_len = 36;
-
- MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, salt_len );
- }
-#endif /* MBEDTLS_SSL_EXTENDED_MS_ENABLED */
-
-#if defined(MBEDTLS_USE_PSA_CRYPTO) && \
- defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
- if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK &&
- ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 &&
- ssl_use_opaque_psk( ssl ) == 1 )
- {
- /* Perform PSK-to-MS expansion in a single step. */
- psa_status_t status;
- psa_algorithm_t alg;
- psa_key_handle_t psk;
- psa_key_derivation_operation_t derivation =
- PSA_KEY_DERIVATION_OPERATION_INIT;
-
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) );
-
- psk = ssl->conf->psk_opaque;
- if( ssl->handshake->psk_opaque != 0 )
- psk = ssl->handshake->psk_opaque;
-
- if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
- alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384);
- else
- alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256);
-
- status = psa_key_derivation( &derivation, psk, alg,
- salt, salt_len,
- (unsigned char const *) lbl,
- (size_t) strlen( lbl ),
- master_secret_len );
- if( status != PSA_SUCCESS )
- {
- psa_key_derivation_abort( &derivation );
- return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
- }
-
- status = psa_key_derivation_output_bytes( &derivation,
- session->master,
- master_secret_len );
- if( status != PSA_SUCCESS )
- {
- psa_key_derivation_abort( &derivation );
- return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
- }
-
- status = psa_key_derivation_abort( &derivation );
- if( status != PSA_SUCCESS )
- return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
- }
- else
-#endif
- {
- ret = handshake->tls_prf( handshake->premaster, handshake->pmslen,
- lbl, salt, salt_len,
- session->master,
- master_secret_len );
- if( ret != 0 )
- {
- MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret );
- return( ret );
- }
-
- MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret",
- handshake->premaster,
- handshake->pmslen );
-
- mbedtls_platform_zeroize( handshake->premaster,
- sizeof(handshake->premaster) );
- }
- }
-
- /*
- * Swap the client and server random values.
- */
- memcpy( tmp, handshake->randbytes, 64 );
- memcpy( handshake->randbytes, tmp + 32, 32 );
- memcpy( handshake->randbytes + 32, tmp, 32 );
- mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
-
- /*
- * SSLv3:
- * key block =
- * MD5( master + SHA1( 'A' + master + randbytes ) ) +
- * MD5( master + SHA1( 'BB' + master + randbytes ) ) +
- * MD5( master + SHA1( 'CCC' + master + randbytes ) ) +
- * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) +
- * ...
- *
- * TLSv1:
- * key block = PRF( master, "key expansion", randbytes )
- */
- ret = handshake->tls_prf( session->master, 48, "key expansion",
- handshake->randbytes, 64, keyblk, 256 );
+ ret = tls_prf( master, 48, "key expansion", randbytes, 64, keyblk, 256 );
if( ret != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret );
@@ -1259,9 +1119,9 @@
}
MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite = %s",
- mbedtls_ssl_get_ciphersuite_name( session->ciphersuite ) ) );
- MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", session->master, 48 );
- MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 );
+ mbedtls_ssl_get_ciphersuite_name( ciphersuite ) ) );
+ MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", master, 48 );
+ MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", randbytes, 64 );
MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 );
/*
@@ -1322,7 +1182,7 @@
* (rfc 6066 page 13 or rfc 2104 section 4),
* so we only need to adjust the length here.
*/
- if( session->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED )
+ if( trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED )
{
transform->maclen = MBEDTLS_SSL_TRUNCATED_HMAC_LEN;
@@ -1350,7 +1210,7 @@
* 2. IV except for SSL3 and TLS 1.0
*/
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
- if( session->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED )
+ if( encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED )
{
transform->minlen = transform->maclen
+ cipher_info->block_size;
@@ -1364,14 +1224,14 @@
}
#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ||
- ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 )
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ||
+ minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 )
; /* No need to adjust minlen */
else
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 ||
- ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 ||
+ minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
{
transform->minlen += transform->ivlen;
}
@@ -1401,7 +1261,7 @@
* Finally setup the cipher contexts, IVs and MAC secrets.
*/
#if defined(MBEDTLS_SSL_CLI_C)
- if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT )
+ if( endpoint == MBEDTLS_SSL_IS_CLIENT )
{
key1 = keyblk + mac_key_len * 2;
key2 = keyblk + mac_key_len * 2 + keylen;
@@ -1421,7 +1281,7 @@
else
#endif /* MBEDTLS_SSL_CLI_C */
#if defined(MBEDTLS_SSL_SRV_C)
- if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER )
+ if( endpoint == MBEDTLS_SSL_IS_SERVER )
{
key1 = keyblk + mac_key_len * 2 + keylen;
key2 = keyblk + mac_key_len * 2;
@@ -1448,7 +1308,7 @@
#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
#if defined(MBEDTLS_SSL_PROTO_SSL3)
- if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
{
if( mac_key_len > sizeof( transform->mac_enc ) )
{
@@ -1464,7 +1324,7 @@
#endif /* MBEDTLS_SSL_PROTO_SSL3 */
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \
defined(MBEDTLS_SSL_PROTO_TLS1_2)
- if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
+ if( minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 )
{
/* For HMAC-based ciphersuites, initialize the HMAC transforms.
For AEAD-based ciphersuites, there is nothing to do here. */
@@ -1510,7 +1370,7 @@
if( ssl->conf->f_export_keys != NULL )
{
ssl->conf->f_export_keys( ssl->conf->p_export_keys,
- session->master, keyblk,
+ master, keyblk,
mac_key_len, keylen,
iv_copy_len );
}
@@ -1518,12 +1378,13 @@
if( ssl->conf->f_export_keys_ext != NULL )
{
ssl->conf->f_export_keys_ext( ssl->conf->p_export_keys,
- session->master, keyblk,
+ master, keyblk,
mac_key_len, keylen,
iv_copy_len,
- handshake->randbytes + 32,
- handshake->randbytes,
- tls_prf_get_type( handshake->tls_prf ) );
+ /* work around bug in exporter type */
+ (unsigned char *) randbytes + 32,
+ (unsigned char *) randbytes,
+ tls_prf_get_type( tls_prf ) );
}
#endif
@@ -1650,24 +1511,10 @@
#endif /* MBEDTLS_CIPHER_MODE_CBC */
+ /* Initialize Zlib contexts */
#if defined(MBEDTLS_ZLIB_SUPPORT)
- // Initialize compression
- //
- if( session->compression == MBEDTLS_SSL_COMPRESS_DEFLATE )
+ if( compression == MBEDTLS_SSL_COMPRESS_DEFLATE )
{
- if( ssl->compress_buf == NULL )
- {
- MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) );
- ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_COMPRESS_BUFFER_LEN );
- if( ssl->compress_buf == NULL )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
- MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) );
- ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
- goto end;
- }
- }
-
MBEDTLS_SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) );
memset( &transform->ctx_deflate, 0, sizeof( transform->ctx_deflate ) );
@@ -1684,16 +1531,312 @@
}
#endif /* MBEDTLS_ZLIB_SUPPORT */
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) );
end:
mbedtls_platform_zeroize( keyblk, sizeof( keyblk ) );
- mbedtls_platform_zeroize( handshake->randbytes,
- sizeof( handshake->randbytes ) );
return( ret );
}
+/*
+ * Set appropriate PRF function and other SSL / TLS 1.0/1.1 / TLS1.2 functions
+ *
+ * Inputs:
+ * - SSL/TLS minor version
+ * - hash associated with the ciphersuite (only used by TLS 1.2)
+ *
+ * Outputs:
+ * - the tls_prf, calc_verify and calc_finished members of handshake structure
+ */
+static int ssl_set_handshake_prfs( mbedtls_ssl_handshake_params *handshake,
+ int minor_ver,
+ mbedtls_md_type_t hash )
+{
+#if !defined(MBEDTLS_SSL_PROTO_TLS1_2) || !defined(MBEDTLS_SHA512_C)
+ (void) hash;
+#endif
+
#if defined(MBEDTLS_SSL_PROTO_SSL3)
-void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] )
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
+ {
+ handshake->tls_prf = ssl3_prf;
+ handshake->calc_verify = ssl_calc_verify_ssl;
+ handshake->calc_finished = ssl_calc_finished_ssl;
+ }
+ else
+#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
+ if( minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 )
+ {
+ handshake->tls_prf = tls1_prf;
+ handshake->calc_verify = ssl_calc_verify_tls;
+ handshake->calc_finished = ssl_calc_finished_tls;
+ }
+ else
+#endif
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
+#if defined(MBEDTLS_SHA512_C)
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 &&
+ hash == MBEDTLS_MD_SHA384 )
+ {
+ handshake->tls_prf = tls_prf_sha384;
+ handshake->calc_verify = ssl_calc_verify_tls_sha384;
+ handshake->calc_finished = ssl_calc_finished_tls_sha384;
+ }
+ else
+#endif
+#if defined(MBEDTLS_SHA256_C)
+ if( minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
+ {
+ handshake->tls_prf = tls_prf_sha256;
+ handshake->calc_verify = ssl_calc_verify_tls_sha256;
+ handshake->calc_finished = ssl_calc_finished_tls_sha256;
+ }
+ else
+#endif
+#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
+ {
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Compute master secret if needed
+ *
+ * Parameters:
+ * [in/out] handshake
+ * [in] resume, premaster, extended_ms, calc_verify, tls_prf
+ * (PSA-PSK) ciphersuite_info, psk_opaque
+ * [out] premaster (cleared)
+ * [out] master
+ * [in] ssl: optionally used for debugging, EMS and PSA-PSK
+ * debug: conf->f_dbg, conf->p_dbg
+ * EMS: passed to calc_verify (debug + (SSL3) session_negotiate)
+ * PSA-PSA: minor_ver, conf
+ */
+static int ssl_compute_master( mbedtls_ssl_handshake_params *handshake,
+ unsigned char *master,
+ const mbedtls_ssl_context *ssl )
+{
+ int ret;
+
+ /* cf. RFC 5246, Section 8.1:
+ * "The master secret is always exactly 48 bytes in length." */
+ size_t const master_secret_len = 48;
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+ unsigned char session_hash[48];
+#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */
+
+ /* The label for the KDF used for key expansion.
+ * This is either "master secret" or "extended master secret"
+ * depending on whether the Extended Master Secret extension
+ * is used. */
+ char const *lbl = "master secret";
+
+ /* The salt for the KDF used for key expansion.
+ * - If the Extended Master Secret extension is not used,
+ * this is ClientHello.Random + ServerHello.Random
+ * (see Sect. 8.1 in RFC 5246).
+ * - If the Extended Master Secret extension is used,
+ * this is the transcript of the handshake so far.
+ * (see Sect. 4 in RFC 7627). */
+ unsigned char const *salt = handshake->randbytes;
+ size_t salt_len = 64;
+
+#if !defined(MBEDTLS_DEBUG_C) && \
+ !defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
+ !(defined(MBEDTLS_USE_PSA_CRYPTO) && \
+ defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED))
+ ssl = NULL; /* make sure we don't use it except for those cases */
+ (void) ssl;
+#endif
+
+ if( handshake->resume != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) );
+ return( 0 );
+ }
+
+#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET)
+ if( handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED )
+ {
+ lbl = "extended master secret";
+ salt = session_hash;
+ handshake->calc_verify( ssl, session_hash, &salt_len );
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "session hash for extended master secret",
+ session_hash, salt_len );
+ }
+#endif /* MBEDTLS_SSL_EXTENDED_MS_ENABLED */
+
+#if defined(MBEDTLS_USE_PSA_CRYPTO) && \
+ defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED)
+ if( handshake->ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK &&
+ ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 &&
+ ssl_use_opaque_psk( ssl ) == 1 )
+ {
+ /* Perform PSK-to-MS expansion in a single step. */
+ psa_status_t status;
+ psa_algorithm_t alg;
+ psa_key_handle_t psk;
+ psa_key_derivation_operation_t derivation =
+ PSA_KEY_DERIVATION_OPERATION_INIT;
+ mbedtls_md_type_t hash_alg = handshake->ciphersuite_info->mac;
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "perform PSA-based PSK-to-MS expansion" ) );
+
+ psk = ssl->conf->psk_opaque;
+ if( handshake->psk_opaque != 0 )
+ psk = handshake->psk_opaque;
+
+ if( hash_alg == MBEDTLS_MD_SHA384 )
+ alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_384);
+ else
+ alg = PSA_ALG_TLS12_PSK_TO_MS(PSA_ALG_SHA_256);
+
+ status = psa_key_derivation( &derivation, psk, alg,
+ salt, salt_len,
+ (unsigned char const *) lbl,
+ (size_t) strlen( lbl ),
+ master_secret_len );
+ if( status != PSA_SUCCESS )
+ {
+ psa_key_derivation_abort( &derivation );
+ return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+ }
+
+ status = psa_key_derivation_output_bytes( &derivation,
+ master,
+ master_secret_len );
+ if( status != PSA_SUCCESS )
+ {
+ psa_key_derivation_abort( &derivation );
+ return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+ }
+
+ status = psa_key_derivation_abort( &derivation );
+ if( status != PSA_SUCCESS )
+ return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
+ }
+ else
+#endif
+ {
+ ret = handshake->tls_prf( handshake->premaster, handshake->pmslen,
+ lbl, salt, salt_len,
+ master,
+ master_secret_len );
+ if( ret != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret );
+ return( ret );
+ }
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret",
+ handshake->premaster,
+ handshake->pmslen );
+
+ mbedtls_platform_zeroize( handshake->premaster,
+ sizeof(handshake->premaster) );
+ }
+
+ return( 0 );
+}
+
+int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl )
+{
+ int ret;
+ const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
+ ssl->handshake->ciphersuite_info;
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) );
+
+ /* Set PRF, calc_verify and calc_finished function pointers */
+ ret = ssl_set_handshake_prfs( ssl->handshake,
+ ssl->minor_ver,
+ ciphersuite_info->mac );
+ if( ret != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "ssl_set_handshake_prfs", ret );
+ return( ret );
+ }
+
+ /* Compute master secret if needed */
+ ret = ssl_compute_master( ssl->handshake,
+ ssl->session_negotiate->master,
+ ssl );
+ if( ret != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compute_master", ret );
+ return( ret );
+ }
+
+ /* Swap the client and server random values:
+ * - MS derivation wanted client+server (RFC 5246 8.1)
+ * - key derivation wants server+client (RFC 5246 6.3) */
+ {
+ unsigned char tmp[64];
+ memcpy( tmp, ssl->handshake->randbytes, 64 );
+ memcpy( ssl->handshake->randbytes, tmp + 32, 32 );
+ memcpy( ssl->handshake->randbytes + 32, tmp, 32 );
+ mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
+ }
+
+ /* Populate transform structure */
+ ret = ssl_populate_transform( ssl->transform_negotiate,
+ ssl->session_negotiate->ciphersuite,
+ ssl->session_negotiate->master,
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ ssl->session_negotiate->encrypt_then_mac,
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+ ssl->session_negotiate->trunc_hmac,
+#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+ ssl->session_negotiate->compression,
+#endif
+ ssl->handshake->tls_prf,
+ ssl->handshake->randbytes,
+ ssl->minor_ver,
+ ssl->conf->endpoint,
+ ssl );
+ if( ret != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "ssl_populate_transform", ret );
+ return( ret );
+ }
+
+ /* We no longer need Server/ClientHello.random values */
+ mbedtls_platform_zeroize( ssl->handshake->randbytes,
+ sizeof( ssl->handshake->randbytes ) );
+
+ /* Allocate compression buffer */
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+ if( session->compression == MBEDTLS_SSL_COMPRESS_DEFLATE &&
+ ssl->compress_buf == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) );
+ ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_COMPRESS_BUFFER_LEN );
+ if( ssl->compress_buf == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
+ MBEDTLS_SSL_COMPRESS_BUFFER_LEN ) );
+ return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+ }
+ }
+#endif
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) );
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_SSL_PROTO_SSL3)
+void ssl_calc_verify_ssl( const mbedtls_ssl_context *ssl,
+ unsigned char hash[36],
+ size_t *hlen )
{
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
@@ -1731,7 +1874,9 @@
mbedtls_sha1_update_ret( &sha1, hash + 16, 20 );
mbedtls_sha1_finish_ret( &sha1, hash + 16 );
- MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 );
+ *hlen = 36;
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_md5_free( &md5 );
@@ -1742,7 +1887,9 @@
#endif /* MBEDTLS_SSL_PROTO_SSL3 */
#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1)
-void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] )
+void ssl_calc_verify_tls( const mbedtls_ssl_context *ssl,
+ unsigned char hash[36],
+ size_t *hlen )
{
mbedtls_md5_context md5;
mbedtls_sha1_context sha1;
@@ -1758,7 +1905,9 @@
mbedtls_md5_finish_ret( &md5, hash );
mbedtls_sha1_finish_ret( &sha1, hash + 16 );
- MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 );
+ *hlen = 36;
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_md5_free( &md5 );
@@ -1770,7 +1919,9 @@
#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
#if defined(MBEDTLS_SHA256_C)
-void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32] )
+void ssl_calc_verify_tls_sha256( const mbedtls_ssl_context *ssl,
+ unsigned char hash[32],
+ size_t *hlen )
{
#if defined(MBEDTLS_USE_PSA_CRYPTO)
size_t hash_size;
@@ -1791,7 +1942,9 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) );
return;
}
- MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, 32 );
+
+ *hlen = 32;
+ MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) );
#else
mbedtls_sha256_context sha256;
@@ -1803,7 +1956,9 @@
mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 );
mbedtls_sha256_finish_ret( &sha256, hash );
- MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 );
+ *hlen = 32;
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_sha256_free( &sha256 );
@@ -1813,7 +1968,9 @@
#endif /* MBEDTLS_SHA256_C */
#if defined(MBEDTLS_SHA512_C)
-void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] )
+void ssl_calc_verify_tls_sha384( const mbedtls_ssl_context *ssl,
+ unsigned char hash[48],
+ size_t *hlen )
{
#if defined(MBEDTLS_USE_PSA_CRYPTO)
size_t hash_size;
@@ -1834,7 +1991,9 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "PSA hash finish failed" ) );
return;
}
- MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, 48 );
+
+ *hlen = 48;
+ MBEDTLS_SSL_DEBUG_BUF( 3, "PSA calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= PSA calc verify" ) );
#else
mbedtls_sha512_context sha512;
@@ -1846,7 +2005,9 @@
mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 );
mbedtls_sha512_finish_ret( &sha512, hash );
- MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 );
+ *hlen = 48;
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, *hlen );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) );
mbedtls_sha512_free( &sha512 );
@@ -2186,6 +2347,7 @@
/* The SSL context is only used for debugging purposes! */
#if !defined(MBEDTLS_DEBUG_C)
+ ssl = NULL; /* make sure we don't use it except for debug */
((void) ssl);
#endif
@@ -2615,6 +2777,7 @@
size_t add_data_len;
#if !defined(MBEDTLS_DEBUG_C)
+ ssl = NULL; /* make sure we don't use it except for debug */
((void) ssl);
#endif
@@ -9682,6 +9845,573 @@
}
#endif /* MBEDTLS_SSL_CLI_C */
+const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_context *ssl )
+{
+ if( ssl == NULL )
+ return( NULL );
+
+ return( ssl->session );
+}
+
+/*
+ * Define ticket header determining Mbed TLS version
+ * and structure of the ticket.
+ */
+
+/*
+ * Define bitflag determining compile-time settings influencing
+ * structure of serialized SSL sessions.
+ */
+
+#if defined(MBEDTLS_HAVE_TIME)
+#define SSL_SERIALIZED_SESSION_CONFIG_TIME 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_TIME 0
+#endif /* MBEDTLS_HAVE_TIME */
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#define SSL_SERIALIZED_SESSION_CONFIG_CRT 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_CRT 0
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+#if defined(MBEDTLS_SSL_CLI_C) && defined(MBEDTLS_SSL_SESSION_TICKETS)
+#define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET 0
+#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_SESSION_TICKETS */
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+#define SSL_SERIALIZED_SESSION_CONFIG_MFL 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_MFL 0
+#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+#define SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC 0
+#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+#define SSL_SERIALIZED_SESSION_CONFIG_ETM 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_ETM 0
+#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+#define SSL_SERIALIZED_SESSION_CONFIG_TICKET 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_TICKET 0
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+
+#define SSL_SERIALIZED_SESSION_CONFIG_TIME_BIT 0
+#define SSL_SERIALIZED_SESSION_CONFIG_CRT_BIT 1
+#define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT 2
+#define SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT 3
+#define SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC_BIT 4
+#define SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT 5
+#define SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT 6
+
+#define SSL_SERIALIZED_SESSION_CONFIG_BITFLAG \
+ ( (uint16_t) ( \
+ ( SSL_SERIALIZED_SESSION_CONFIG_TIME << SSL_SERIALIZED_SESSION_CONFIG_TIME_BIT ) | \
+ ( SSL_SERIALIZED_SESSION_CONFIG_CRT << SSL_SERIALIZED_SESSION_CONFIG_CRT_BIT ) | \
+ ( SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET << SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT ) | \
+ ( SSL_SERIALIZED_SESSION_CONFIG_MFL << SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT ) | \
+ ( SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC << SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC_BIT ) | \
+ ( SSL_SERIALIZED_SESSION_CONFIG_ETM << SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT ) | \
+ ( SSL_SERIALIZED_SESSION_CONFIG_TICKET << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT ) ) )
+
+static unsigned char ssl_serialized_session_header[] = {
+ MBEDTLS_VERSION_MAJOR,
+ MBEDTLS_VERSION_MINOR,
+ MBEDTLS_VERSION_PATCH,
+ ( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG >> 8 ) & 0xFF,
+ ( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG >> 0 ) & 0xFF,
+};
+
+/*
+ * Serialize a session in the following format:
+ * (in the presentation language of TLS, RFC 8446 section 3)
+ *
+ * opaque mbedtls_version[3]; // major, minor, patch
+ * opaque session_format[2]; // version-specific 16-bit field determining
+ * // the format of the remaining
+ * // serialized data.
+ *
+ * Note: When updating the format, remember to keep
+ * these version+format bytes.
+ *
+ * // In this version, `session_format` determines
+ * // the setting of those compile-time
+ * // configuration options which influence
+ * // the structure of mbedtls_ssl_session.
+ * uint64 start_time;
+ * uint8 ciphersuite[2]; // defined by the standard
+ * uint8 compression; // 0 or 1
+ * uint8 session_id_len; // at most 32
+ * opaque session_id[32];
+ * opaque master[48]; // fixed length in the standard
+ * uint32 verify_result;
+ * opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
+ * opaque ticket<0..2^24-1>; // length 0 means no ticket
+ * uint32 ticket_lifetime;
+ * uint8 mfl_code; // up to 255 according to standard
+ * uint8 trunc_hmac; // 0 or 1
+ * uint8 encrypt_then_mac; // 0 or 1
+ *
+ * The order is the same as in the definition of the structure, except
+ * verify_result is put before peer_cert so that all mandatory fields come
+ * together in one block.
+ */
+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;
+#if defined(MBEDTLS_HAVE_TIME)
+ uint64_t start;
+#endif
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ size_t cert_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+
+ if( !omit_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 );
+ }
+ }
+
+ /*
+ * Time
+ */
+#if defined(MBEDTLS_HAVE_TIME)
+ used += 8;
+
+ if( used <= buf_len )
+ {
+ start = (uint64_t) session->start;
+
+ *p++ = (unsigned char)( ( start >> 56 ) & 0xFF );
+ *p++ = (unsigned char)( ( start >> 48 ) & 0xFF );
+ *p++ = (unsigned char)( ( start >> 40 ) & 0xFF );
+ *p++ = (unsigned char)( ( start >> 32 ) & 0xFF );
+ *p++ = (unsigned char)( ( start >> 24 ) & 0xFF );
+ *p++ = (unsigned char)( ( start >> 16 ) & 0xFF );
+ *p++ = (unsigned char)( ( start >> 8 ) & 0xFF );
+ *p++ = (unsigned char)( ( start ) & 0xFF );
+ }
+#endif /* MBEDTLS_HAVE_TIME */
+
+ /*
+ * Basic mandatory fields
+ */
+ used += 2 /* ciphersuite */
+ + 1 /* compression */
+ + 1 /* id_len */
+ + sizeof( session->id )
+ + sizeof( session->master )
+ + 4; /* verify_result */
+
+ if( used <= buf_len )
+ {
+ *p++ = (unsigned char)( ( session->ciphersuite >> 8 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->ciphersuite ) & 0xFF );
+
+ *p++ = (unsigned char)( session->compression & 0xFF );
+
+ *p++ = (unsigned char)( session->id_len & 0xFF );
+ memcpy( p, session->id, 32 );
+ p += 32;
+
+ memcpy( p, session->master, 48 );
+ p += 48;
+
+ *p++ = (unsigned char)( ( session->verify_result >> 24 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->verify_result >> 16 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->verify_result >> 8 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->verify_result ) & 0xFF );
+ }
+
+ /*
+ * Peer's end-entity certificate
+ */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ if( session->peer_cert == NULL )
+ cert_len = 0;
+ else
+ cert_len = session->peer_cert->raw.len;
+
+ used += 3 + cert_len;
+
+ if( used <= buf_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;
+ }
+ }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ if( session->peer_cert_digest != NULL )
+ {
+ used += 1 /* type */ + 1 /* length */ + session->peer_cert_digest_len;
+ if( used <= buf_len )
+ {
+ *p++ = (unsigned char) session->peer_cert_digest_type;
+ *p++ = (unsigned char) session->peer_cert_digest_len;
+ memcpy( p, session->peer_cert_digest,
+ session->peer_cert_digest_len );
+ p += session->peer_cert_digest_len;
+ }
+ }
+ else
+ {
+ used += 2;
+ if( used <= buf_len )
+ {
+ *p++ = (unsigned char) MBEDTLS_MD_NONE;
+ *p++ = 0;
+ }
+ }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+ /*
+ * Session ticket if any, plus associated data
+ */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+ used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */
+
+ if( used <= buf_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;
+ }
+
+ *p++ = (unsigned char)( ( session->ticket_lifetime >> 24 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->ticket_lifetime >> 16 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->ticket_lifetime >> 8 ) & 0xFF );
+ *p++ = (unsigned char)( ( session->ticket_lifetime ) & 0xFF );
+ }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
+ /*
+ * Misc extension-related info
+ */
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ used += 1;
+
+ if( used <= buf_len )
+ *p++ = session->mfl_code;
+#endif
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+ used += 1;
+
+ if( used <= buf_len )
+ *p++ = (unsigned char)( ( session->trunc_hmac ) & 0xFF );
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ used += 1;
+
+ if( used <= buf_len )
+ *p++ = (unsigned char)( ( session->encrypt_then_mac ) & 0xFF );
+#endif
+
+ /* Done */
+ *olen = used;
+
+ if( used > buf_len )
+ return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+ return( 0 );
+}
+
+/*
+ * 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, 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 )
+{
+ const unsigned char *p = buf;
+ const unsigned char * const end = buf + len;
+#if defined(MBEDTLS_HAVE_TIME)
+ uint64_t start;
+#endif
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ size_t cert_len;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+ if( !omit_header )
+ {
+ /*
+ * 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 );
+ }
+
+ /*
+ * Time
+ */
+#if defined(MBEDTLS_HAVE_TIME)
+ if( 8 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ start = ( (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;
+
+ session->start = (time_t) start;
+#endif /* MBEDTLS_HAVE_TIME */
+
+ /*
+ * Basic mandatory fields
+ */
+ if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->ciphersuite = ( p[0] << 8 ) | p[1];
+ p += 2;
+
+ session->compression = *p++;
+
+ session->id_len = *p++;
+ memcpy( session->id, p, 32 );
+ p += 32;
+
+ memcpy( session->master, p, 48 );
+ p += 48;
+
+ session->verify_result = ( (uint32_t) p[0] << 24 ) |
+ ( (uint32_t) p[1] << 16 ) |
+ ( (uint32_t) p[2] << 8 ) |
+ ( (uint32_t) p[3] );
+ p += 4;
+
+ /* Immediately clear invalid pointer values that have been read, in case
+ * we exit early before we replaced them with valid ones. */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ session->peer_cert = NULL;
+#else
+ session->peer_cert_digest = NULL;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+ session->ticket = NULL;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
+ /*
+ * Peer certificate
+ */
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ /* Deserialize CRT from the end of the ticket. */
+ if( 3 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
+ p += 3;
+
+ if( cert_len != 0 )
+ {
+ int ret;
+
+ if( cert_len > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) );
+
+ if( session->peer_cert == NULL )
+ return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+ mbedtls_x509_crt_init( session->peer_cert );
+
+ if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert,
+ p, cert_len ) ) != 0 )
+ {
+ mbedtls_x509_crt_free( session->peer_cert );
+ mbedtls_free( session->peer_cert );
+ session->peer_cert = NULL;
+ return( ret );
+ }
+
+ p += cert_len;
+ }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ /* Deserialize CRT digest from the end of the ticket. */
+ if( 2 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->peer_cert_digest_type = (mbedtls_md_type_t) *p++;
+ session->peer_cert_digest_len = (size_t) *p++;
+
+ if( session->peer_cert_digest_len != 0 )
+ {
+ const mbedtls_md_info_t *md_info =
+ mbedtls_md_info_from_type( session->peer_cert_digest_type );
+ if( md_info == NULL )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ if( session->peer_cert_digest_len != mbedtls_md_get_size( md_info ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ if( session->peer_cert_digest_len > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->peer_cert_digest =
+ mbedtls_calloc( 1, session->peer_cert_digest_len );
+ if( session->peer_cert_digest == NULL )
+ return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+ memcpy( session->peer_cert_digest, p,
+ session->peer_cert_digest_len );
+ p += session->peer_cert_digest_len;
+ }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+
+ /*
+ * Session ticket and associated data
+ */
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+ if( 3 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->ticket_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2];
+ p += 3;
+
+ if( session->ticket_len != 0 )
+ {
+ if( session->ticket_len > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->ticket = mbedtls_calloc( 1, session->ticket_len );
+ if( session->ticket == NULL )
+ return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+ memcpy( session->ticket, p, session->ticket_len );
+ p += session->ticket_len;
+ }
+
+ if( 4 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->ticket_lifetime = ( (uint32_t) p[0] << 24 ) |
+ ( (uint32_t) p[1] << 16 ) |
+ ( (uint32_t) p[2] << 8 ) |
+ ( (uint32_t) p[3] );
+ p += 4;
+#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
+
+ /*
+ * Misc extension-related info
+ */
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ if( 1 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->mfl_code = *p++;
+#endif
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+ if( 1 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->trunc_hmac = *p++;
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ if( 1 > (size_t)( end - p ) )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ session->encrypt_then_mac = *p++;
+#endif
+
+ /* Done, should have consumed entire buffer */
+ if( p != end )
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+ return( 0 );
+}
+
+/*
+ * 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, 0, buf, len );
+
+ if( ret != 0 )
+ mbedtls_ssl_session_free( session );
+
+ return( ret );
+}
+
/*
* Perform a single step of the SSL handshake
*/
@@ -10577,6 +11307,642 @@
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 )
+{
+ unsigned char *p = buf;
+ size_t used = 0;
+ size_t session_len;
+ int ret = 0;
+
+ /*
+ * 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 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Initial handshake isn't over" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ if( ssl->handshake != NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Handshake isn't completed" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ /* Double-check that sub-structures are indeed ready */
+ if( ssl->transform == NULL || ssl->session == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Serialised structures aren't ready" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ /* There must be no pending incoming or outgoing data */
+ if( mbedtls_ssl_check_pending( ssl ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "There is pending incoming data" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ if( ssl->out_left != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "There is pending outgoing data" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ /* Protocol must be DLTS, not TLS */
+ if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only DTLS is supported" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ /* Version must be 1.2 */
+ if( ssl->major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only version 1.2 supported" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only version 1.2 supported" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ /* We must be using an AEAD ciphersuite */
+ if( mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Only AEAD ciphersuites supported" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+ /* Renegotiation must not be enabled */
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ if( ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Renegotiation must not be enabled" ) );
+ return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+#endif
+
+ /*
+ * 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 )
+{
+#if defined(MBEDTLS_SHA512_C)
+ const mbedtls_ssl_ciphersuite_t * const ciphersuite_info =
+ mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
+
+ if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 )
+ return( tls_prf_sha384 );
+#else
+ (void) ciphersuite_id;
+#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( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM ||
+ ssl->conf->max_major_ver < MBEDTLS_SSL_MAJOR_VERSION_3 ||
+ ssl->conf->min_major_ver > MBEDTLS_SSL_MAJOR_VERSION_3 ||
+ ssl->conf->max_minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ||
+ ssl->conf->min_minor_ver > MBEDTLS_SSL_MINOR_VERSION_3 ||
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
+#endif
+ 0 )
+ {
+ 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,
+ ssl->session->ciphersuite,
+ 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( ssl->session->ciphersuite ),
+ p, /* currently pointing to randbytes */
+ MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */
+ ssl->conf->endpoint,
+ 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;
+
+ ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
+ ssl->minor_ver = MBEDTLS_SSL_MINOR_VERSION_3;
+
+#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 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 );
+}
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
+
/*
* Free an SSL context
*/
diff --git a/library/version_features.c b/library/version_features.c
index e83899d..cc47dac 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -459,6 +459,9 @@
#if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
"MBEDTLS_SSL_ASYNC_PRIVATE",
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ "MBEDTLS_SSL_CONTEXT_SERIALIZATION",
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
#if defined(MBEDTLS_SSL_DEBUG_ALL)
"MBEDTLS_SSL_DEBUG_ALL",
#endif /* MBEDTLS_SSL_DEBUG_ALL */
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index c6d19bf..361ec00 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -1266,6 +1266,14 @@
}
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if( strcmp( "MBEDTLS_SSL_CONTEXT_SERIALIZATION", config ) == 0 )
+ {
+ MACRO_EXPANSION_TO_STR( MBEDTLS_SSL_CONTEXT_SERIALIZATION );
+ return( 0 );
+ }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
+
#if defined(MBEDTLS_SSL_DEBUG_ALL)
if( strcmp( "MBEDTLS_SSL_DEBUG_ALL", config ) == 0 )
{
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 7ba4565..61b88d1 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -113,6 +113,7 @@
#define DFL_DHMLEN -1
#define DFL_RECONNECT 0
#define DFL_RECO_DELAY 0
+#define DFL_RECO_MODE 1
#define DFL_CID_ENABLED 0
#define DFL_CID_VALUE ""
#define DFL_CID_ENABLED_RENEGO -1
@@ -129,6 +130,8 @@
#define DFL_FALLBACK -1
#define DFL_EXTENDED_MS -1
#define DFL_ETM -1
+#define DFL_SERIALIZE 0
+#define DFL_EXTENDED_MS_ENFORCE -1
#define DFL_CA_CALLBACK 0
#define DFL_EAP_TLS 0
#define DFL_REPRODUCIBLE 0
@@ -339,6 +342,15 @@
#define USAGE_ECRESTART ""
#endif
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+#define USAGE_SERIALIZATION \
+ " serialize=%%d default: 0 (do not serialize/deserialize)\n" \
+ " options: 1 (serialize)\n" \
+ " 2 (serialize with re-initialization)\n"
+#else
+#define USAGE_SERIALIZATION ""
+#endif
+
#define USAGE \
"\n usage: ssl_client2 param=<>...\n" \
"\n acceptable parameters:\n" \
@@ -376,8 +388,11 @@
" allow_legacy=%%d default: (library default: no)\n" \
USAGE_RENEGO \
" exchanges=%%d default: 1\n" \
- " reconnect=%%d default: 0 (disabled)\n" \
+ " reconnect=%%d number of reconnections using session resumption\n" \
+ " default: 0 (disabled)\n" \
" reco_delay=%%d default: 0 seconds\n" \
+ " reco_mode=%%d 0: copy session, 1: serialize session\n" \
+ " default: 1\n" \
" reconnect_hard=%%d default: 0 (disabled)\n" \
USAGE_TICKETS \
USAGE_EAP_TLS \
@@ -405,6 +420,7 @@
" configuration macro is defined and 1\n" \
" otherwise. The expansion of the macro\n" \
" is printed if it is defined\n" \
+ USAGE_SERIALIZATION \
" acceptable ciphersuite names:\n"
#define ALPN_LIST_SIZE 10
@@ -458,6 +474,7 @@
int dhmlen; /* minimum DHM params len in bits */
int reconnect; /* attempt to resume session */
int reco_delay; /* delay in seconds before resuming session */
+ int reco_mode; /* how to keep the session around */
int reconnect_hard; /* unexpectedly reconnect from the same port */
int tickets; /* enable / disable session tickets */
const char *curves; /* list of supported elliptic curves */
@@ -476,6 +493,7 @@
int cid_enabled_renego; /* whether to use the CID extension or not
* during renegotiation */
const char *cid_val; /* the CID to use for incoming messages */
+ int serialize; /* serialize/deserialize connection */
const char *cid_val_renego; /* the CID to use for incoming messages
* after renegotiation */
int reproducible; /* make communication reproducible */
@@ -1047,6 +1065,8 @@
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_ssl_session saved_session;
+ unsigned char *session_data = NULL;
+ size_t session_data_len = 0;
#if defined(MBEDTLS_TIMING_C)
mbedtls_timing_delay_context timer;
#endif
@@ -1061,6 +1081,10 @@
#endif
char *p, *q;
const int *list;
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ unsigned char *context_buf = NULL;
+ size_t context_buf_len;
+#endif
#if defined(MBEDTLS_SSL_EXPORT_KEYS)
unsigned char eap_tls_keymaterial[16];
unsigned char eap_tls_iv[8];
@@ -1164,6 +1188,7 @@
opt.dhmlen = DFL_DHMLEN;
opt.reconnect = DFL_RECONNECT;
opt.reco_delay = DFL_RECO_DELAY;
+ opt.reco_mode = DFL_RECO_MODE;
opt.reconnect_hard = DFL_RECONNECT_HARD;
opt.tickets = DFL_TICKETS;
opt.alpn_string = DFL_ALPN_STRING;
@@ -1176,6 +1201,7 @@
opt.extended_ms = DFL_EXTENDED_MS;
opt.etm = DFL_ETM;
opt.dgram_packing = DFL_DGRAM_PACKING;
+ opt.serialize = DFL_SERIALIZE;
opt.eap_tls = DFL_EAP_TLS;
opt.reproducible = DFL_REPRODUCIBLE;
@@ -1350,6 +1376,12 @@
if( opt.reco_delay < 0 )
goto usage;
}
+ else if( strcmp( p, "reco_mode" ) == 0 )
+ {
+ opt.reco_mode = atoi( q );
+ if( opt.reco_mode < 0 )
+ goto usage;
+ }
else if( strcmp( p, "reconnect_hard" ) == 0 )
{
opt.reconnect_hard = atoi( q );
@@ -1558,6 +1590,12 @@
{
return query_config( q );
}
+ else if( strcmp( p, "serialize") == 0 )
+ {
+ opt.serialize = atoi( q );
+ if( opt.serialize < 0 || opt.serialize > 2)
+ goto usage;
+ }
else if( strcmp( p, "eap_tls" ) == 0 )
{
opt.eap_tls = atoi( q );
@@ -2440,14 +2478,55 @@
mbedtls_printf(" . Saving session for reuse..." );
fflush( stdout );
- if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 )
+ if( opt.reco_mode == 1 )
{
- mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n",
- -ret );
- goto exit;
+ /* free any previously saved data */
+ if( session_data != NULL )
+ {
+ mbedtls_platform_zeroize( session_data, session_data_len );
+ 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, session_data_len,
+ &session_data_len ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_session_saved returned -0x%04x\n\n",
+ -ret );
+ goto exit;
+ }
+ }
+ else
+ {
+ if( ( ret = mbedtls_ssl_get_session( &ssl, &saved_session ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_get_session returned -0x%x\n\n",
+ -ret );
+ goto exit;
+ }
}
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)
@@ -2839,7 +2918,103 @@
}
/*
- * 7c. Continue doing data exchanges?
+ * 7c. Simulate serialize/deserialize and go back to data exchange
+ */
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if( opt.serialize != 0 )
+ {
+ size_t buf_len;
+
+ mbedtls_printf( " . Serializing live connection..." );
+
+ ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
+ if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_context_save returned "
+ "-0x%x\n\n", -ret );
+
+ goto exit;
+ }
+
+ if( ( context_buf = mbedtls_calloc( 1, buf_len ) ) == NULL )
+ {
+ mbedtls_printf( " failed\n ! Couldn't allocate buffer for "
+ "serialized context" );
+
+ 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 "
+ "-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 );
+
+ if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned "
+ "-0x%x\n\n", -ret );
+ goto exit;
+ }
+
+ if( opt.nbio == 2 )
+ mbedtls_ssl_set_bio( &ssl, &server_fd, delayed_send,
+ delayed_recv, NULL );
+ else
+ 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)
+ mbedtls_ssl_set_timer_cb( &ssl, &timer,
+ mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay );
+#endif /* MBEDTLS_TIMING_C */
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ mbedtls_printf( " . Deserializing connection..." );
+
+ if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
+ buf_len ) ) != 0 )
+ {
+ mbedtls_printf( "failed\n ! mbedtls_ssl_context_load returned "
+ "-0x%x\n\n", -ret );
+
+ goto exit;
+ }
+
+ mbedtls_free( context_buf );
+ context_buf = NULL;
+ context_buf_len = 0;
+
+ mbedtls_printf( " ok\n" );
+ }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
+
+ /*
+ * 7d. Continue doing data exchanges?
*/
if( --opt.exchanges > 0 )
goto send_request;
@@ -2886,10 +3061,22 @@
goto exit;
}
+ if( opt.reco_mode == 1 )
+ {
+ if( ( ret = mbedtls_ssl_session_load( &saved_session,
+ session_data,
+ session_data_len ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_session_load returned -0x%x\n\n",
+ -ret );
+ goto exit;
+ }
+ }
+
if( ( ret = mbedtls_ssl_set_session( &ssl, &saved_session ) ) != 0 )
{
- mbedtls_printf( " failed\n ! mbedtls_ssl_conf_session returned %d\n\n",
- ret );
+ mbedtls_printf( " failed\n ! mbedtls_ssl_set_session returned -0x%x\n\n",
+ -ret );
goto exit;
}
@@ -2959,6 +3146,14 @@
mbedtls_ssl_config_free( &conf );
mbedtls_ctr_drbg_free( &ctr_drbg );
mbedtls_entropy_free( &entropy );
+ 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(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) && \
defined(MBEDTLS_USE_PSA_CRYPTO)
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 3279cda..102951b 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -171,6 +171,8 @@
#define DFL_DGRAM_PACKING 1
#define DFL_EXTENDED_MS -1
#define DFL_ETM -1
+#define DFL_SERIALIZE 0
+#define DFL_EXTENDED_MS_ENFORCE -1
#define DFL_CA_CALLBACK 0
#define DFL_EAP_TLS 0
#define DFL_REPRODUCIBLE 0
@@ -435,6 +437,15 @@
#define USAGE_CURVES ""
#endif
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+#define USAGE_SERIALIZATION \
+ " serialize=%%d default: 0 (do not serialize/deserialize)\n" \
+ " options: 1 (serialize)\n" \
+ " 2 (serialize with re-initialization)\n"
+#else
+#define USAGE_SERIALIZATION ""
+#endif
+
#define USAGE \
"\n usage: ssl_server2 param=<>...\n" \
"\n acceptable parameters:\n" \
@@ -499,6 +510,7 @@
" configuration macro is defined and 1\n" \
" otherwise. The expansion of the macro\n" \
" is printed if it is defined\n" \
+ USAGE_SERIALIZATION \
" acceptable ciphersuite names:\n"
#define ALPN_LIST_SIZE 10
@@ -590,6 +602,7 @@
int cid_enabled_renego; /* whether to use the CID extension or not
* during renegotiation */
const char *cid_val; /* the CID to use for incoming messages */
+ int serialize; /* serialize/deserialize connection */
const char *cid_val_renego; /* the CID to use for incoming messages
* after renegotiation */
int reproducible; /* make communication reproducible */
@@ -1714,6 +1727,10 @@
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;
@@ -1872,6 +1889,7 @@
opt.badmac_limit = DFL_BADMAC_LIMIT;
opt.extended_ms = DFL_EXTENDED_MS;
opt.etm = DFL_ETM;
+ opt.serialize = DFL_SERIALIZE;
opt.eap_tls = DFL_EAP_TLS;
opt.reproducible = DFL_REPRODUCIBLE;
@@ -2286,6 +2304,12 @@
{
return query_config( q );
}
+ else if( strcmp( p, "serialize") == 0 )
+ {
+ opt.serialize = atoi( q );
+ if( opt.serialize < 0 || opt.serialize > 2)
+ goto usage;
+ }
else if( strcmp( p, "eap_tls" ) == 0 )
{
opt.eap_tls = atoi( q );
@@ -3907,7 +3931,124 @@
ret = 0;
/*
- * 7b. Continue doing data exchanges?
+ * 7b. Simulate serialize/deserialize and go back to data exchange
+ */
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+ if( opt.serialize != 0 )
+ {
+ size_t buf_len;
+
+ mbedtls_printf( " . Serializing live connection..." );
+
+ ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
+ if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_context_save returned "
+ "-0x%x\n\n", -ret );
+
+ goto exit;
+ }
+
+ if( ( context_buf = mbedtls_calloc( 1, buf_len ) ) == NULL )
+ {
+ mbedtls_printf( " failed\n ! Couldn't allocate buffer for "
+ "serialized context" );
+
+ 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 "
+ "-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 );
+
+ if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
+ {
+ mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned "
+ "-0x%x\n\n", -ret );
+ 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, delayed_send,
+ delayed_recv, NULL );
+ else
+ mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send,
+ mbedtls_net_recv,
+ opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
+
+#if defined(MBEDTLS_TIMING_C)
+ mbedtls_ssl_set_timer_cb( &ssl, &timer,
+ mbedtls_timing_set_delay,
+ mbedtls_timing_get_delay );
+#endif /* MBEDTLS_TIMING_C */
+
+ mbedtls_printf( " ok\n" );
+ }
+
+ mbedtls_printf( " . Deserializing connection..." );
+
+ if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
+ buf_len ) ) != 0 )
+ {
+ mbedtls_printf( "failed\n ! mbedtls_ssl_context_load returned "
+ "-0x%x\n\n", -ret );
+
+ goto exit;
+ }
+
+ mbedtls_free( context_buf );
+ context_buf = NULL;
+ context_buf_len = 0;
+
+ mbedtls_printf( " ok\n" );
+ }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
+
+ /*
+ * 7c. Continue doing data exchanges?
*/
if( --exchanges_left > 0 )
goto data_exchange;
@@ -4013,6 +4154,12 @@
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();
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 6017680..9037394 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -743,7 +743,7 @@
component_test_small_mbedtls_ssl_dtls_max_buffering () {
msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
- scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
+ scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 190
CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
make
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 44743d4..67d3b9f 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1280,6 +1280,56 @@
-S "dumping 'expected mac' (20 bytes)" \
-s "dumping 'expected mac' (10 bytes)"
+# Tests for Context serialization
+
+requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
+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..."
+
+requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
+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..."
+
+requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
+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..."
+
+requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
+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..."
+
+requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
+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..."
+
+requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
+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..."
+
# Tests for DTLS Connection ID extension
# So far, the CID API isn't implemented, so we can't
@@ -1939,8 +1989,8 @@
-s "found extended master secret extension" \
-s "server hello, adding extended master secret extension" \
-c "found extended_master_secret extension" \
- -c "using extended master secret" \
- -s "using extended master secret"
+ -c "session hash for extended master secret" \
+ -s "session hash for extended master secret"
run_test "Extended Master Secret: client enabled, server disabled" \
"$P_SRV debug_level=3 extended_ms=0" \
@@ -1950,8 +2000,8 @@
-s "found extended master secret extension" \
-S "server hello, adding extended master secret extension" \
-C "found extended_master_secret extension" \
- -C "using extended master secret" \
- -S "using extended master secret"
+ -C "session hash for extended master secret" \
+ -S "session hash for extended master secret"
run_test "Extended Master Secret: client disabled, server enabled" \
"$P_SRV debug_level=3 extended_ms=1" \
@@ -1961,8 +2011,8 @@
-S "found extended master secret extension" \
-S "server hello, adding extended master secret extension" \
-C "found extended_master_secret extension" \
- -C "using extended master secret" \
- -S "using extended master secret"
+ -C "session hash for extended master secret" \
+ -S "session hash for extended master secret"
requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
run_test "Extended Master Secret: client SSLv3, server enabled" \
@@ -1973,8 +2023,8 @@
-S "found extended master secret extension" \
-S "server hello, adding extended master secret extension" \
-C "found extended_master_secret extension" \
- -C "using extended master secret" \
- -S "using extended master secret"
+ -C "session hash for extended master secret" \
+ -S "session hash for extended master secret"
requires_config_enabled MBEDTLS_SSL_PROTO_SSL3
run_test "Extended Master Secret: client enabled, server SSLv3" \
@@ -1985,8 +2035,8 @@
-S "found extended master secret extension" \
-S "server hello, adding extended master secret extension" \
-C "found extended_master_secret extension" \
- -C "using extended master secret" \
- -S "using extended master secret"
+ -C "session hash for extended master secret" \
+ -S "session hash for extended master secret"
# Tests for FALLBACK_SCSV
@@ -2239,6 +2289,20 @@
-S "a session has been resumed" \
-C "a session has been resumed"
+run_test "Session resume using tickets: session copy" \
+ "$P_SRV debug_level=3 tickets=1 cache_max=0" \
+ "$P_CLI debug_level=3 tickets=1 reconnect=1 reco_mode=0" \
+ 0 \
+ -c "client hello, adding session ticket extension" \
+ -s "found session ticket extension" \
+ -s "server hello, adding session ticket extension" \
+ -c "found session_ticket extension" \
+ -c "parse new session ticket" \
+ -S "session successfully restored from cache" \
+ -s "session successfully restored from ticket" \
+ -s "a session has been resumed" \
+ -c "a session has been resumed"
+
run_test "Session resume using tickets: openssl server" \
"$O_SRV" \
"$P_CLI debug_level=3 tickets=1 reconnect=1" \
@@ -2304,6 +2368,20 @@
-S "a session has been resumed" \
-C "a session has been resumed"
+run_test "Session resume using tickets, DTLS: session copy" \
+ "$P_SRV debug_level=3 dtls=1 tickets=1 cache_max=0" \
+ "$P_CLI debug_level=3 dtls=1 tickets=1 reconnect=1 reco_mode=0" \
+ 0 \
+ -c "client hello, adding session ticket extension" \
+ -s "found session ticket extension" \
+ -s "server hello, adding session ticket extension" \
+ -c "found session_ticket extension" \
+ -c "parse new session ticket" \
+ -S "session successfully restored from cache" \
+ -s "session successfully restored from ticket" \
+ -s "a session has been resumed" \
+ -c "a session has been resumed"
+
run_test "Session resume using tickets, DTLS: openssl server" \
"$O_SRV -dtls1" \
"$P_CLI dtls=1 debug_level=3 tickets=1 reconnect=1" \
@@ -2400,6 +2478,15 @@
-s "a session has been resumed" \
-c "a session has been resumed"
+run_test "Session resume using cache: session copy" \
+ "$P_SRV debug_level=3 tickets=0" \
+ "$P_CLI debug_level=3 tickets=0 reconnect=1 reco_mode=0" \
+ 0 \
+ -s "session successfully restored from cache" \
+ -S "session successfully restored from ticket" \
+ -s "a session has been resumed" \
+ -c "a session has been resumed"
+
run_test "Session resume using cache: openssl client" \
"$P_SRV debug_level=3 tickets=0" \
"( $O_CLI -sess_out $SESSION; \
@@ -2495,6 +2582,15 @@
-s "a session has been resumed" \
-c "a session has been resumed"
+run_test "Session resume using cache, DTLS: session copy" \
+ "$P_SRV dtls=1 debug_level=3 tickets=0" \
+ "$P_CLI dtls=1 debug_level=3 tickets=0 reconnect=1 reco_mode=0" \
+ 0 \
+ -s "session successfully restored from cache" \
+ -S "session successfully restored from ticket" \
+ -s "a session has been resumed" \
+ -c "a session has been resumed"
+
run_test "Session resume using cache, DTLS: openssl client" \
"$P_SRV dtls=1 debug_level=3 tickets=0" \
"( $O_CLI -dtls1 -sess_out $SESSION; \
@@ -4782,8 +4878,8 @@
0 \
-c "skip PMS generation for opaque PSK"\
-S "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4796,8 +4892,8 @@
0 \
-c "skip PMS generation for opaque PSK"\
-S "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4810,8 +4906,8 @@
0 \
-c "skip PMS generation for opaque PSK"\
-S "skip PMS generation for opaque PSK"\
- -c "using extended master secret"\
- -s "using extended master secret"\
+ -c "session hash for extended master secret"\
+ -s "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4824,8 +4920,8 @@
0 \
-c "skip PMS generation for opaque PSK"\
-S "skip PMS generation for opaque PSK"\
- -c "using extended master secret"\
- -s "using extended master secret"\
+ -c "session hash for extended master secret"\
+ -s "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4838,8 +4934,8 @@
0 \
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4852,8 +4948,8 @@
0 \
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4865,8 +4961,8 @@
"$P_CLI debug_level=3 min_version=tls1_2 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
psk_identity=foo psk=abc123 extended_ms=1" \
0 \
- -c "using extended master secret"\
- -s "using extended master secret"\
+ -c "session hash for extended master secret"\
+ -s "session hash for extended master secret"\
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
-S "SSL - None of the common ciphersuites is usable" \
@@ -4880,8 +4976,8 @@
"$P_CLI debug_level=3 min_version=tls1_2 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \
psk_identity=foo psk=abc123 extended_ms=1" \
0 \
- -c "using extended master secret"\
- -s "using extended master secret"\
+ -c "session hash for extended master secret"\
+ -s "session hash for extended master secret"\
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
-S "SSL - None of the common ciphersuites is usable" \
@@ -4896,8 +4992,8 @@
0 \
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4910,8 +5006,8 @@
0 \
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4923,8 +5019,8 @@
"$P_CLI debug_level=3 min_version=tls1_2 force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \
psk_identity=abc psk=dead extended_ms=1" \
0 \
- -c "using extended master secret"\
- -s "using extended master secret"\
+ -c "session hash for extended master secret"\
+ -s "session hash for extended master secret"\
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
-S "SSL - None of the common ciphersuites is usable" \
@@ -4938,8 +5034,8 @@
"$P_CLI debug_level=3 min_version=tls1_2 force_ciphersuite=TLS-PSK-WITH-AES-256-CBC-SHA384 \
psk_identity=abc psk=dead extended_ms=1" \
0 \
- -c "using extended master secret"\
- -s "using extended master secret"\
+ -c "session hash for extended master secret"\
+ -s "session hash for extended master secret"\
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
-S "SSL - None of the common ciphersuites is usable" \
@@ -4954,8 +5050,8 @@
0 \
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4968,8 +5064,8 @@
0 \
-C "skip PMS generation for opaque PSK"\
-s "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4981,8 +5077,8 @@
psk_identity=def psk=beef" \
0 \
-C "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -4994,8 +5090,8 @@
psk_identity=def psk=beef" \
0 \
-C "skip PMS generation for opaque PSK"\
- -C "using extended master secret"\
- -S "using extended master secret"\
+ -C "session hash for extended master secret"\
+ -S "session hash for extended master secret"\
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - Unknown identity received" \
-S "SSL - Verification of the message MAC failed"
@@ -8272,11 +8368,11 @@
# without fragmentation or be reassembled within the bounds of
# MBEDTLS_SSL_DTLS_MAX_BUFFERING. Achieve this by testing with a PSK-based
# handshake, omitting CRTs.
-requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 240
-requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 280
+requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 190
+requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 230
run_test "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket" \
-p "$P_PXY delay_srv=NewSessionTicket delay_srv=NewSessionTicket delay_ccs=1" \
- "$P_SRV mtu=190 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \
+ "$P_SRV mtu=140 response_size=90 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \
"$P_CLI dgram_packing=0 dtls=1 debug_level=2 force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8 psk=abc123 psk_identity=foo" \
0 \
-s "Buffer record from epoch 1" \
diff --git a/tests/suites/test_suite_ssl.data b/tests/suites/test_suite_ssl.data
index 72092cd..45765de 100644
--- a/tests/suites/test_suite_ssl.data
+++ b/tests/suites/test_suite_ssl.data
@@ -58,6 +58,18 @@
SSL SET_HOSTNAME memory leak: call ssl_set_hostname twice
ssl_set_hostname_twice:"server0":"server1"
+SSL session serialization: Wrong major version
+ssl_session_serialize_version_check:1:0:0:0
+
+SSL session serialization: Wrong minor version
+ssl_session_serialize_version_check:0:1:0:0
+
+SSL session serialization: Wrong patch version
+ssl_session_serialize_version_check:0:0:1:0
+
+SSL session serialization: Wrong config
+ssl_session_serialize_version_check:0:0:0:1
+
Record crypt, AES-128-CBC, 1.2, SHA-384
depends_on:MBEDTLS_CIPHER_MODE_CBC:MBEDTLS_AES_C:MBEDTLS_SSL_PROTO_TLS1_2:MBEDTLS_SHA512_C
ssl_crypt_record:MBEDTLS_CIPHER_AES_128_CBC:MBEDTLS_MD_SHA384:0:0:MBEDTLS_SSL_MINOR_VERSION_3:0:0
@@ -8752,3 +8764,95 @@
SSL TLS_PRF MBEDTLS_SSL_TLS_PRF_SHA256 SHA-256 not enabled
depends_on:!MBEDTLS_SHA256_C
ssl_tls_prf:MBEDTLS_SSL_TLS_PRF_SHA256:"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef":"test tls_prf label":"7f9998393198a02c8d731ccc2ef90b2c":MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE
+
+Session serialization, save-load: no ticket, no cert
+ssl_serialize_session_save_load:0:""
+
+Session serialization, save-load: small ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_save_load:42:""
+
+Session serialization, save-load: large ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_save_load:1023:""
+
+Session serialization, save-load: no ticket, cert
+depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_save_load:0:"data_files/server5.crt"
+
+Session serialization, save-load: small ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_save_load:42:"data_files/server5.crt"
+
+Session serialization, save-load: large ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_save_load:1023:"data_files/server5.crt"
+
+Session serialization, load-save: no ticket, no cert
+ssl_serialize_session_load_save:0:""
+
+Session serialization, load-save: small ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_load_save:42:""
+
+Session serialization, load-save: large ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_load_save:1023:""
+
+Session serialization, load-save: no ticket, cert
+depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_load_save:0:"data_files/server5.crt"
+
+Session serialization, load-save: small ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_load_save:42:"data_files/server5.crt"
+
+Session serialization, load-save: large ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_load_save:1023:"data_files/server5.crt"
+
+Session serialization, save buffer size: no ticket, no cert
+ssl_serialize_session_save_buf_size:0:""
+
+Session serialization, save buffer size: small ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_save_buf_size:42:""
+
+Session serialization, save buffer size: large ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_save_buf_size:1023:""
+
+Session serialization, save buffer size: no ticket, cert
+depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_save_buf_size:0:"data_files/server5.crt"
+
+Session serialization, save buffer size: small ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_save_buf_size:42:"data_files/server5.crt"
+
+Session serialization, save buffer size: large ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_save_buf_size:1023:"data_files/server5.crt"
+
+Session serialization, load buffer size: no ticket, no cert
+ssl_serialize_session_load_buf_size:0:""
+
+Session serialization, load buffer size: small ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_load_buf_size:42:""
+
+Session serialization, load buffer size: large ticket, no cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C
+ssl_serialize_session_load_buf_size:1023:""
+
+Session serialization, load buffer size: no ticket, cert
+depends_on:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_load_buf_size:0:"data_files/server5.crt"
+
+Session serialization, load buffer size: small ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_load_buf_size:42:"data_files/server5.crt"
+
+Session serialization, load buffer size: large ticket, cert
+depends_on:MBEDTLS_SSL_SESSION_TICKETS:MBEDTLS_SSL_CLI_C:MBEDTLS_X509_USE_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_FS_IO
+ssl_serialize_session_load_buf_size:1023:"data_files/server5.crt"
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 104a52f..2fa716b 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -267,6 +267,93 @@
return( ret );
}
+/*
+ * Populate a session structure for serialization tests.
+ * Choose dummy values, mostly non-0 to distinguish from the init default.
+ */
+static int ssl_populate_session( mbedtls_ssl_session *session,
+ int ticket_len,
+ const char *crt_file )
+{
+#if defined(MBEDTLS_HAVE_TIME)
+ session->start = mbedtls_time( NULL ) - 42;
+#endif
+ session->ciphersuite = 0xabcd;
+ session->compression = 1;
+ session->id_len = sizeof( session->id );
+ memset( session->id, 66, session->id_len );
+ memset( session->master, 17, sizeof( session->master ) );
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_FS_IO)
+ if( strlen( crt_file ) != 0 )
+ {
+ mbedtls_x509_crt tmp_crt;
+ int ret;
+
+ mbedtls_x509_crt_init( &tmp_crt );
+ ret = mbedtls_x509_crt_parse_file( &tmp_crt, crt_file );
+ if( ret != 0 )
+ return( ret );
+
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ /* Move temporary CRT. */
+ session->peer_cert = mbedtls_calloc( 1, sizeof( *session->peer_cert ) );
+ if( session->peer_cert == NULL )
+ return( -1 );
+ *session->peer_cert = tmp_crt;
+ memset( &tmp_crt, 0, sizeof( tmp_crt ) );
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ /* Calculate digest of temporary CRT. */
+ session->peer_cert_digest =
+ mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN );
+ if( session->peer_cert_digest == NULL )
+ return( -1 );
+ ret = mbedtls_md( mbedtls_md_info_from_type(
+ MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
+ tmp_crt.raw.p, tmp_crt.raw.len,
+ session->peer_cert_digest );
+ if( ret != 0 )
+ return( ret );
+ session->peer_cert_digest_type =
+ MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE;
+ session->peer_cert_digest_len =
+ MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
+ mbedtls_x509_crt_free( &tmp_crt );
+ }
+#else /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_FS_IO */
+ (void) crt_file;
+#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_FS_IO */
+ session->verify_result = 0xdeadbeef;
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+ if( ticket_len != 0 )
+ {
+ session->ticket = mbedtls_calloc( 1, ticket_len );
+ if( session->ticket == NULL )
+ return( -1 );
+ memset( session->ticket, 33, ticket_len );
+ }
+ session->ticket_len = ticket_len;
+ session->ticket_lifetime = 86401;
+#else
+ (void) ticket_len;
+#endif
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ session->mfl_code = 1;
+#endif
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+ session->trunc_hmac = 1;
+#endif
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ session->encrypt_then_mac = 1;
+#endif
+
+ return( 0 );
+}
+
/* END_HEADER */
/* BEGIN_DEPENDENCIES
@@ -605,3 +692,295 @@
mbedtls_free( output );
}
/* END_CASE */
+
+/* BEGIN_CASE */
+void ssl_serialize_session_save_load( int ticket_len, char *crt_file )
+{
+ mbedtls_ssl_session original, restored;
+ unsigned char *buf = NULL;
+ size_t len;
+
+ /*
+ * Test that a save-load pair is the identity
+ */
+
+ mbedtls_ssl_session_init( &original );
+ mbedtls_ssl_session_init( &restored );
+
+ /* Prepare a dummy session to work on */
+ TEST_ASSERT( ssl_populate_session( &original, ticket_len, crt_file ) == 0 );
+
+ /* Serialize it */
+ TEST_ASSERT( mbedtls_ssl_session_save( &original, NULL, 0, &len )
+ == MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+ TEST_ASSERT( ( buf = mbedtls_calloc( 1, len ) ) != NULL );
+ TEST_ASSERT( mbedtls_ssl_session_save( &original, buf, len, &len )
+ == 0 );
+
+ /* Restore session from serialized data */
+ TEST_ASSERT( mbedtls_ssl_session_load( &restored, buf, len) == 0 );
+
+ /*
+ * Make sure both session structures are identical
+ */
+#if defined(MBEDTLS_HAVE_TIME)
+ TEST_ASSERT( original.start == restored.start );
+#endif
+ TEST_ASSERT( original.ciphersuite == restored.ciphersuite );
+ TEST_ASSERT( original.compression == restored.compression );
+ TEST_ASSERT( original.id_len == restored.id_len );
+ TEST_ASSERT( memcmp( original.id,
+ restored.id, sizeof( original.id ) ) == 0 );
+ TEST_ASSERT( memcmp( original.master,
+ restored.master, sizeof( original.master ) ) == 0 );
+
+#if defined(MBEDTLS_X509_CRT_PARSE_C)
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+ TEST_ASSERT( ( original.peer_cert == NULL ) ==
+ ( restored.peer_cert == NULL ) );
+ if( original.peer_cert != NULL )
+ {
+ TEST_ASSERT( original.peer_cert->raw.len ==
+ restored.peer_cert->raw.len );
+ TEST_ASSERT( memcmp( original.peer_cert->raw.p,
+ restored.peer_cert->raw.p,
+ original.peer_cert->raw.len ) == 0 );
+ }
+#else /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+ TEST_ASSERT( original.peer_cert_digest_type ==
+ restored.peer_cert_digest_type );
+ TEST_ASSERT( original.peer_cert_digest_len ==
+ restored.peer_cert_digest_len );
+ TEST_ASSERT( ( original.peer_cert_digest == NULL ) ==
+ ( restored.peer_cert_digest == NULL ) );
+ if( original.peer_cert_digest != NULL )
+ {
+ TEST_ASSERT( memcmp( original.peer_cert_digest,
+ restored.peer_cert_digest,
+ original.peer_cert_digest_len ) == 0 );
+ }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
+ TEST_ASSERT( original.verify_result == restored.verify_result );
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
+ TEST_ASSERT( original.ticket_len == restored.ticket_len );
+ if( original.ticket_len != 0 )
+ {
+ TEST_ASSERT( original.ticket != NULL );
+ TEST_ASSERT( restored.ticket != NULL );
+ TEST_ASSERT( memcmp( original.ticket,
+ restored.ticket, original.ticket_len ) == 0 );
+ }
+ TEST_ASSERT( original.ticket_lifetime == restored.ticket_lifetime );
+#endif
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ TEST_ASSERT( original.mfl_code == restored.mfl_code );
+#endif
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+ TEST_ASSERT( original.trunc_hmac == restored.trunc_hmac );
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+ TEST_ASSERT( original.encrypt_then_mac == restored.encrypt_then_mac );
+#endif
+
+exit:
+ mbedtls_ssl_session_free( &original );
+ mbedtls_ssl_session_free( &restored );
+ mbedtls_free( buf );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ssl_serialize_session_load_save( int ticket_len, char *crt_file )
+{
+ mbedtls_ssl_session session;
+ unsigned char *buf1 = NULL, *buf2 = NULL;
+ size_t len0, len1, len2;
+
+ /*
+ * Test that a load-save pair is the identity
+ */
+
+ mbedtls_ssl_session_init( &session );
+
+ /* Prepare a dummy session to work on */
+ TEST_ASSERT( ssl_populate_session( &session, ticket_len, crt_file ) == 0 );
+
+ /* Get desired buffer size for serializing */
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, NULL, 0, &len0 )
+ == MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+ /* Allocate first buffer */
+ buf1 = mbedtls_calloc( 1, len0 );
+ TEST_ASSERT( buf1 != NULL );
+
+ /* Serialize to buffer and free live session */
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, buf1, len0, &len1 )
+ == 0 );
+ TEST_ASSERT( len0 == len1 );
+ mbedtls_ssl_session_free( &session );
+
+ /* Restore session from serialized data */
+ TEST_ASSERT( mbedtls_ssl_session_load( &session, buf1, len1 ) == 0 );
+
+ /* Allocate second buffer and serialize to it */
+ buf2 = mbedtls_calloc( 1, len0 );
+ TEST_ASSERT( buf2 != NULL );
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, buf2, len0, &len2 )
+ == 0 );
+
+ /* Make sure both serialized versions are identical */
+ TEST_ASSERT( len1 == len2 );
+ TEST_ASSERT( memcmp( buf1, buf2, len1 ) == 0 );
+
+exit:
+ mbedtls_ssl_session_free( &session );
+ mbedtls_free( buf1 );
+ mbedtls_free( buf2 );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ssl_serialize_session_save_buf_size( int ticket_len, char *crt_file )
+{
+ mbedtls_ssl_session session;
+ unsigned char *buf = NULL;
+ size_t good_len, bad_len, test_len;
+
+ /*
+ * Test that session_save() fails cleanly on small buffers
+ */
+
+ mbedtls_ssl_session_init( &session );
+
+ /* Prepare dummy session and get serialized size */
+ TEST_ASSERT( ssl_populate_session( &session, ticket_len, crt_file ) == 0 );
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, NULL, 0, &good_len )
+ == MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+ /* Try all possible bad lengths */
+ for( bad_len = 1; bad_len < good_len; bad_len++ )
+ {
+ /* Allocate exact size so that asan/valgrind can detect any overwrite */
+ mbedtls_free( buf );
+ TEST_ASSERT( ( buf = mbedtls_calloc( 1, bad_len ) ) != NULL );
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, buf, bad_len,
+ &test_len )
+ == MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+ TEST_ASSERT( test_len == good_len );
+ }
+
+exit:
+ mbedtls_ssl_session_free( &session );
+ mbedtls_free( buf );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ssl_serialize_session_load_buf_size( int ticket_len, char *crt_file )
+{
+ mbedtls_ssl_session session;
+ unsigned char *good_buf = NULL, *bad_buf = NULL;
+ size_t good_len, bad_len;
+
+ /*
+ * Test that session_load() fails cleanly on small buffers
+ */
+
+ mbedtls_ssl_session_init( &session );
+
+ /* Prepare serialized session data */
+ TEST_ASSERT( ssl_populate_session( &session, ticket_len, crt_file ) == 0 );
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, NULL, 0, &good_len )
+ == MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+ TEST_ASSERT( ( good_buf = mbedtls_calloc( 1, good_len ) ) != NULL );
+ TEST_ASSERT( mbedtls_ssl_session_save( &session, good_buf, good_len,
+ &good_len ) == 0 );
+ mbedtls_ssl_session_free( &session );
+
+ /* Try all possible bad lengths */
+ for( bad_len = 0; bad_len < good_len; bad_len++ )
+ {
+ /* Allocate exact size so that asan/valgrind can detect any overread */
+ mbedtls_free( bad_buf );
+ bad_buf = mbedtls_calloc( 1, bad_len ? bad_len : 1 );
+ TEST_ASSERT( bad_buf != NULL );
+ memcpy( bad_buf, good_buf, bad_len );
+
+ TEST_ASSERT( mbedtls_ssl_session_load( &session, bad_buf, bad_len )
+ == MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ }
+
+exit:
+ mbedtls_ssl_session_free( &session );
+ mbedtls_free( good_buf );
+ mbedtls_free( bad_buf );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void ssl_session_serialize_version_check( int corrupt_major,
+ int corrupt_minor,
+ int corrupt_patch,
+ int corrupt_config )
+{
+ unsigned char serialized_session[ 2048 ];
+ size_t serialized_session_len;
+ unsigned cur_byte;
+ mbedtls_ssl_session session;
+ uint8_t should_corrupt_byte[] = { corrupt_major == 1,
+ corrupt_minor == 1,
+ corrupt_patch == 1,
+ corrupt_config == 1,
+ corrupt_config == 1 };
+
+ mbedtls_ssl_session_init( &session );
+
+ /* Infer length of serialized session. */
+ TEST_ASSERT( mbedtls_ssl_session_save( &session,
+ serialized_session,
+ sizeof( serialized_session ),
+ &serialized_session_len ) == 0 );
+
+ mbedtls_ssl_session_free( &session );
+
+ /* Without any modification, we should be able to successfully
+ * de-serialize the session - double-check that. */
+ TEST_ASSERT( mbedtls_ssl_session_load( &session,
+ serialized_session,
+ serialized_session_len ) == 0 );
+ mbedtls_ssl_session_free( &session );
+
+ /* Go through the bytes in the serialized session header and
+ * corrupt them bit-by-bit. */
+ for( cur_byte = 0; cur_byte < sizeof( should_corrupt_byte ); cur_byte++ )
+ {
+ int cur_bit;
+ unsigned char * const byte = &serialized_session[ cur_byte ];
+
+ if( should_corrupt_byte[ cur_byte ] == 0 )
+ continue;
+
+ for( cur_bit = 0; cur_bit < CHAR_BIT; cur_bit++ )
+ {
+ unsigned char const corrupted_bit = 0x1u << cur_bit;
+ /* Modify a single bit in the serialized session. */
+ *byte ^= corrupted_bit;
+
+ /* Attempt to deserialize */
+ TEST_ASSERT( mbedtls_ssl_session_load( &session,
+ serialized_session,
+ serialized_session_len ) ==
+ MBEDTLS_ERR_SSL_VERSION_MISMATCH );
+
+ /* Undo the change */
+ *byte ^= corrupted_bit;
+ }
+ }
+
+}
+/* END_CASE */