From a3024eef7be4d1ed55976dc15536e41f4897e1d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 9 Jul 2019 12:54:17 +0200
Subject: [PATCH 01/27] Save Hello random bytes for later use

---
 include/mbedtls/ssl_internal.h | 6 ++++++
 library/ssl_tls.c              | 8 +++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 40391d581..fb9a1605e 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -728,6 +728,12 @@ struct mbedtls_ssl_transform
     z_stream ctx_deflate;               /*!<  compression context     */
     z_stream ctx_inflate;               /*!<  decompression context   */
 #endif
+
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    /* We need the Hello random bytes in order to re-derive keys from the
+     * Master Secret and other session info, see ssl_populate_transform() */
+    unsigned char randbytes[64]; /*!< ServerHello.random+ClientHello.random */
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 };
 
 static inline int mbedtls_ssl_transform_get_minor_ver( mbedtls_ssl_transform const *transform )
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 0b1ebddcf..39522197c 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -812,7 +812,9 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
     (void) ssl;
 #endif
 
-    /* Copy info about negotiated version and extensions */
+    /*
+     * Some data just needs copying into the structure
+     */
 #if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
     defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
     transform->encrypt_then_mac = encrypt_then_mac;
@@ -824,6 +826,10 @@ static int ssl_populate_transform( mbedtls_ssl_transform *transform,
     ((void) minor_ver);
 #endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
 
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    memcpy( transform->randbytes, randbytes, sizeof( transform->randbytes ) );
+#endif
+
     /*
      * Get various info structures
      */

From 569ed6ba56e821394f72caa2060a220abbbad693 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Wed, 10 Jul 2019 14:14:05 +0200
Subject: [PATCH 02/27] Implement usage checks in context_save()

Enforce restrictions indicated in the documentation.

This allows to make some simplifying assumptions (no need to worry about
saving IVs for CBC in TLS < 1.1, nor about saving handshake data) and
guarantees that all values marked as "forced" in the design document have the
intended values and can be skipped when serialising.

Some of the "forced" values are not checked because their value is a
consequence of other checks (for example, session_negotiated == NULL outside
handshakes). We do however check that session and transform are not NULL (even
if that's also a consequence of the initial handshake being over) as we're
going to dereference them and static analyzers may appreciate the info.
---
 include/mbedtls/ssl.h          |  3 ++-
 include/mbedtls/ssl_internal.h | 15 +++++++++++++++
 library/ssl_tls.c              | 29 +++++++++++++++++++++++++++--
 3 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 0f9ab0ecf..ccad3954d 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3932,13 +3932,14 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
  * \return         #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small.
  * \return         #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if a handshake is in
  *                 progress, or there is pending data for reading or sending,
- *                 or the connection does not use DTLS 1.2 with and AEAD
+ *                 or the connection does not use DTLS 1.2 with an AEAD
  *                 ciphersuite, or renegotiation is enabled.
  */
 int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
                               unsigned char *buf,
                               size_t buf_len,
                               size_t *olen );
+
 /**
  * \brief          Load serialized connection data to an SSL context.
  *
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index fb9a1605e..7cab1e2a0 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -746,6 +746,21 @@ static inline int mbedtls_ssl_transform_get_minor_ver( mbedtls_ssl_transform con
 #endif
 }
 
+/*
+ * Return 1 if the transform uses an AEAD cipher, 0 otherwise.
+ * Equivalently, return 0 if a separate MAC is used, 1 otherwise.
+ */
+static inline int mbedtls_ssl_transform_uses_aead(
+        const mbedtls_ssl_transform *transform )
+{
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+    return( transform->maclen == 0 && transform->taglen != 0 );
+#else
+    (void) transform;
+    return( 1 );
+#endif
+}
+
 /*
  * Internal representation of record frames
  *
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 39522197c..2ab14df0f 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10727,9 +10727,34 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
                               size_t buf_len,
                               size_t *olen )
 {
-    /* Unimplemented */
-    (void) ssl;
+    /*
+     * Enforce current usage restrictions
+     */
+    if( /* The initial handshake is over ... */
+        ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ||
+        ssl->handshake != NULL ||
+        /* ... and the various sub-structures are indeed ready. */
+        ssl->transform == NULL ||
+        ssl->session == NULL ||
+        /* There is no pending incoming or outgoing data ... */
+        mbedtls_ssl_check_pending( ssl ) != 0 ||
+        ssl->out_left != 0 ||
+        /* We're using DTLS 1.2 ... */
+        MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
+        ssl->major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 ||
+        ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ||
+        /* ... with an AEAD ciphersuite. */
+        mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 ||
+        /* Renegotation is disabled. */
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED
+#endif
+        )
+    {
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
 
+    /* Unimplemented */
     if( buf != NULL )
         memset( buf, 0, buf_len );
 

From b6163ef175588c88e36f89c55f9f362ab7aa0da1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Wed, 10 Jul 2019 14:58:45 +0200
Subject: [PATCH 03/27] Document internal serialisation format

This mainly follows the design document (saving all fields marked "saved" in
the main structure and the transform sub-structure) with two exceptions:

- things related to renegotiation are excluded here (there weren't quite in
  the design document as the possibility of allowing renegotiation was still
on the table, which is no longer is) - also, ssl.secure_renegotiation (which
is not guarded by MBEDTLS_SSL_RENEGOTIATION because it's used in initial
handshakes even with renegotiation disabled) is still excluded, as we don't
need it after the handshake.

- things related to Connection ID are added, as they weren't present at the
  time the design document was written.

The exact format of the header (value of the bitflag indicating compile-time
options, whether and how to merge it with the serialized session header) will
be determined later.
---
 library/ssl_tls.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 2ab14df0f..64c0c9490 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10721,6 +10721,41 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
 
 /*
  * 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[n];    // version-specific field determining
+ *                               // the format of the remaining
+ *                               // serialized data. (n TBD)
+ *  Note: When updating the format, remember to keep
+ *        these version+format bytes. (To be confirmed.)
+ *
+ *  // 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,

From 5e534baaecbf04e1f4a39d13bf55cba44343677d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Thu, 11 Jul 2019 09:56:30 +0200
Subject: [PATCH 04/27] Add usage checks in context_load()

---
 library/ssl_tls.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 64c0c9490..993ca92ac 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10805,8 +10805,36 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
                               const unsigned char *buf,
                               size_t len )
 {
+    /*
+     * The context should have been freshly setup or reset.
+     * Give the user an error in case of obvious misuse.
+     * (Checking session is useful because if won't be NULL if we're
+     * renegotiating, or if the user mistakenly loaded a session first.)
+     */
+    if( ssl->state != MBEDTLS_SSL_HELLO_REQUEST ||
+        ssl->session != NULL )
+    {
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    /*
+     * We can't check that the config matches the initial one, but we can at
+     * least check it matches the requirements for serializing.
+     */
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
+        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
+        )
+    {
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
     /* Unimplemented */
-    (void) ssl;
     (void) buf;
     (void) len;
 

From d0dd10469bb051366b068e5ae487d00ef98cb2c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Thu, 11 Jul 2019 10:58:10 +0200
Subject: [PATCH 05/27] Add (stub) header writing and checking

The number of meaning of the flags will be determined later, when handling the
relevant struct members. For now three bytes are reserved as an example, but
this number may change later.
---
 include/mbedtls/ssl.h |  2 ++
 library/ssl_tls.c     | 64 +++++++++++++++++++++++++++++++++++++------
 2 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index ccad3954d..2913b4f92 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3999,6 +3999,8 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
  *
  * \return         \c 0 if successful.
  * \return         #MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed.
+ * \return         #MBEDTLS_ERR_SSL_VERSION_MISMATCH if the serialized data
+ *                 comes from a different Mbed TLS version or build.
  * \return         #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if input data is invalid.
  */
 int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 993ca92ac..37a7c22ca 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10719,6 +10719,17 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
     mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) );
 }
 
+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,
+    0, /* placeholder */
+    0, /* placeholder */
+    0, /* placeholder */
+};
+
 /*
  * Serialize a full SSL context
  *
@@ -10727,9 +10738,9 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
  *
  *  // header
  *  opaque mbedtls_version[3];   // major, minor, patch
- *  opaque context_format[n];    // version-specific field determining
+ *  opaque context_format[5];    // version-specific field determining
  *                               // the format of the remaining
- *                               // serialized data. (n TBD)
+ *                               // serialized data.
  *  Note: When updating the format, remember to keep
  *        these version+format bytes. (To be confirmed.)
  *
@@ -10762,6 +10773,9 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
                               size_t buf_len,
                               size_t *olen )
 {
+    unsigned char *p = buf;
+    size_t used = 0;
+
     /*
      * Enforce current usage restrictions
      */
@@ -10789,11 +10803,25 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    /* Unimplemented */
-    if( buf != NULL )
-        memset( buf, 0, buf_len );
+    /*
+     * Version and format identifier
+     */
+    used += sizeof( ssl_serialized_context_header );
 
-    *olen = 0;
+    if( used <= buf_len )
+    {
+        memcpy( p, ssl_serialized_context_header,
+                sizeof( ssl_serialized_context_header ) );
+        p += sizeof( ssl_serialized_context_header );
+    }
+
+    /*
+     * Done
+     */
+    *olen = used;
+
+    if( used > buf_len )
+        return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
 
     return( 0 );
 }
@@ -10805,6 +10833,9 @@ int mbedtls_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;
+
     /*
      * The context should have been freshly setup or reset.
      * Give the user an error in case of obvious misuse.
@@ -10834,9 +10865,24 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
-    /* Unimplemented */
-    (void) buf;
-    (void) 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 );
+
+    /*
+     * Done - should have consumed entire buffer
+     */
+    if( p != end )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
     return( 0 );
 }

From f1f3e529a5a0113b022971f4e6048247a74a62c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Thu, 11 Jul 2019 12:50:53 +0200
Subject: [PATCH 06/27] Add session saving/loading

For now, the header (version+format bytes) is duplicated. This might be
optimized later.
---
 include/mbedtls/ssl.h | 11 +++++-
 library/ssl_tls.c     | 86 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 92 insertions(+), 5 deletions(-)

diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 2913b4f92..485d1cd92 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3926,7 +3926,11 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
  * \note           \p olen is updated to the correct value regardless of
  *                 whether \p buf_len was large enough. This makes it possible
  *                 to determine the necessary size by calling this function
- *                 with \p buf set to \c NULL and \p buf_len to \c 0.
+ *                 with \p buf set to \c NULL and \p buf_len to \c 0. However,
+ *                 the value of \p olen is only guaranteed to be correct when
+ *                 the function returns #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL or
+ *                 \c 0. If the return value is different, then the value of
+ *                 \p olen is undefined.
  *
  * \return         \c 0 if successful.
  * \return         #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small.
@@ -3991,6 +3995,11 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
  *                 newly-configured value with the value that was active when
  *                 the context was saved.
  *
+ * \note           When this function returns an error code, it calls
+ *                 mbedtls_ssl_free() on \p ssl. In this case, you need to
+ *                 prepare the context with the usual sequence starting with a
+ *                 call to mbedtls_ssl_init() if you want to use it again.
+ *
  * \param ssl      The SSL context structure to be populated. It must have
  *                 been prepared as described in the note above.
  * \param buf      The buffer holding the serialized connection data. It must
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 37a7c22ca..e6d27e7b3 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10775,6 +10775,8 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
 {
     unsigned char *p = buf;
     size_t used = 0;
+    size_t session_len;
+    int ret = 0;
 
     /*
      * Enforce current usage restrictions
@@ -10815,6 +10817,29 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         p += sizeof( ssl_serialized_context_header );
     }
 
+    /*
+     * Session (length + data)
+     */
+    ret = mbedtls_ssl_session_save( ssl->session, NULL, 0, &session_len );
+    if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
+        return( ret );
+
+    used += 4 + session_len;
+    if( used <= buf_len )
+    {
+        *p++ = (unsigned char)( ( session_len >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( session_len >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( session_len >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( session_len       ) & 0xFF );
+
+        ret = mbedtls_ssl_session_save( ssl->session,
+                                        p, session_len, &session_len );
+        if( ret != 0 )
+            return( ret );
+
+        p += session_len;
+    }
+
     /*
      * Done
      */
@@ -10823,18 +10848,25 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
     if( used > buf_len )
         return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
 
+    MBEDTLS_SSL_DEBUG_BUF( 4, "saved context", buf, used );
+
     return( 0 );
 }
 
 /*
- * Deserialize a full SSL context
+ * Unserialize context, see mbedtls_ssl_context_save() for format.
+ *
+ * This internal version is wrapped by a public function that cleans up in
+ * case of error.
  */
-int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
-                              const unsigned char *buf,
-                              size_t len )
+static int ssl_context_load( mbedtls_ssl_context *ssl,
+                             const unsigned char *buf,
+                             size_t len )
 {
     const unsigned char *p = buf;
     const unsigned char * const end = buf + len;
+    size_t session_len;
+    int ret;
 
     /*
      * The context should have been freshly setup or reset.
@@ -10865,6 +10897,8 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
 
+    MBEDTLS_SSL_DEBUG_BUF( 4, "context to load", buf, len );
+
     /*
      * Check version identifier
      */
@@ -10878,6 +10912,35 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
     }
     p += sizeof( ssl_serialized_context_header );
 
+    /*
+     * Session
+     */
+    if( (size_t)( end - p ) < 4 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session_len = ( (size_t) p[0] << 24 ) |
+                  ( (size_t) p[1] << 16 ) |
+                  ( (size_t) p[2] <<  8 ) |
+                  ( (size_t) p[3]       );
+    p += 4;
+
+    ssl->session = mbedtls_calloc( 1, sizeof( mbedtls_ssl_session ) );
+    if( ssl->session == NULL )
+        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+    mbedtls_ssl_session_init( ssl->session );
+
+    ssl->session_in = ssl->session;
+    ssl->session_out = ssl->session;
+
+    if( (size_t)( end - p ) < session_len )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ret = mbedtls_ssl_session_load( ssl->session, p, session_len );
+    if( ret != 0 )
+        return( ret );
+
+    p += session_len;
+
     /*
      * Done - should have consumed entire buffer
      */
@@ -10887,6 +10950,21 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
     return( 0 );
 }
 
+/*
+ * Unserialize context: public wrapper for error cleaning
+ */
+int mbedtls_ssl_context_load( mbedtls_ssl_context *context,
+                              const unsigned char *buf,
+                              size_t len )
+{
+    int ret = ssl_context_load( context, buf, len );
+
+    if( ret != 0 )
+        mbedtls_ssl_free( context );
+
+    return( ret );
+}
+
 /*
  * Free an SSL context
  */

From 3b23c7d2d21c1c3cf609af79c6c4f44b962db823 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Fri, 12 Jul 2019 10:41:55 +0200
Subject: [PATCH 07/27] Improve demo/testing code in client/server2

Previously it was missing reset in case 1, and in case 2 the code was never
executed as the option value was reset to 0.

Tighten checking of return values of save(NULL, 0) now that it works.

Also, improve the printed output as well as the comments.

I checked manually that everything now works and fail in the expected way:
save, reset-or-reinit and load all succeed, but the subsequent read or write
fails.
---
 programs/ssl/ssl_client2.c | 40 +++++++++++++++++++--------
 programs/ssl/ssl_server2.c | 55 ++++++++++++++++++++++++++++++++------
 2 files changed, 76 insertions(+), 19 deletions(-)

diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 87454b2fb..41cd4e4c0 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -2491,14 +2491,10 @@ send_request:
         size_t buf_len;
         unsigned char *context_buf = NULL;
 
-        opt.serialize = 0;
-        mbedtls_printf( " Serializing live connection..." );
+        mbedtls_printf( "  . Serializing live connection..." );
 
         ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
-
-        /* Allow stub implementation returning 0 for now */
-        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL &&
-            ret != 0 )
+        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
@@ -2517,14 +2513,32 @@ send_request:
         if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
                                               buf_len, &buf_len ) ) != 0 )
         {
-            mbedtls_printf( "failed\n  ! mbedtls_ssl_context_save returned "
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
 
             goto exit;
         }
 
+        mbedtls_printf( " ok\n" );
+
+        if( opt.serialize == 1 )
+        {
+            mbedtls_printf( "  . Reseting context..." );
+
+            if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned "
+                                "-0x%x\n\n", -ret );
+                goto exit;
+            }
+
+            mbedtls_printf( " ok\n" );
+        }
+
         if( opt.serialize == 2 )
         {
+            mbedtls_printf( "  . Freeing and reinitializing context..." );
+
             mbedtls_ssl_free( &ssl );
 
             mbedtls_ssl_init( &ssl );
@@ -2532,7 +2546,7 @@ send_request:
             if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
             {
                 mbedtls_printf( " failed\n  ! mbedtls_ssl_setup returned "
-                                " -0x%x\n\n", -ret );
+                                "-0x%x\n\n", -ret );
                 goto exit;
             }
 
@@ -2540,8 +2554,8 @@ send_request:
                 mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv,
                                      NULL );
             else
-                mbedtls_ssl_set_bio( &ssl, &server_fd,
-                            mbedtls_net_send, mbedtls_net_recv,
+                mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send,
+                            mbedtls_net_recv,
                             opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
 #if defined(MBEDTLS_TIMING_C)
@@ -2557,9 +2571,11 @@ send_request:
 #endif
             }
 #endif /* MBEDTLS_TIMING_C */
+
+            mbedtls_printf( " ok\n" );
         }
 
-        mbedtls_printf( " Deserializing connection..." );
+        mbedtls_printf( "  . Deserializing connection..." );
 
         if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
                                               buf_len ) ) != 0 )
@@ -2569,6 +2585,8 @@ send_request:
 
             goto exit;
         }
+
+        mbedtls_printf( " ok\n" );
     }
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 9cca9c4d7..dbabc7a34 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -3507,14 +3507,10 @@ data_exchange:
         size_t buf_len;
         unsigned char *context_buf = NULL;
 
-        opt.serialize = 0;
-        mbedtls_printf( " Serializing live connection..." );
+        mbedtls_printf( "  . Serializing live connection..." );
 
         ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
-
-        /* Allow stub implementation returning 0 for now */
-        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL &&
-            ret != 0 )
+        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
@@ -3533,14 +3529,47 @@ data_exchange:
         if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
                                               buf_len, &buf_len ) ) != 0 )
         {
-            mbedtls_printf( "failed\n  ! mbedtls_ssl_context_save returned "
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
 
             goto exit;
         }
 
+        mbedtls_printf( " ok\n" );
+
+        /*
+         * This simulates a workflow where you have a long-lived server
+         * instance, potentially with a pool of ssl_context objects, and you
+         * just want to re-use one while the connection is inactive: in that
+         * case you can just reset() it, and then it's ready to receive
+         * serialized data from another connection (or the same here).
+         */
+        if( opt.serialize == 1 )
+        {
+            mbedtls_printf( "  . Reseting context..." );
+
+            if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
+            {
+                mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned "
+                                "-0x%x\n\n", -ret );
+                goto exit;
+            }
+
+            mbedtls_printf( " ok\n" );
+        }
+
+        /*
+         * 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 );
@@ -3552,6 +3581,12 @@ data_exchange:
                 goto exit;
             }
 
+            /*
+             * This illustrates the minimum amount of things you need to set
+             * up, however you could set up much more if desired, for example
+             * if you want to share your set up code between the case of
+             * establishing a new connection and this case.
+             */
             if( opt.nbio == 2 )
                 mbedtls_ssl_set_bio( &ssl, &client_fd, my_send, my_recv,
                                      NULL );
@@ -3573,9 +3608,11 @@ data_exchange:
 #endif
             }
 #endif /* MBEDTLS_TIMING_C */
+
+            mbedtls_printf( " ok\n" );
         }
 
-        mbedtls_printf( " Deserializing connection..." );
+        mbedtls_printf( "  . Deserializing connection..." );
 
         if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
                                               buf_len ) ) != 0 )
@@ -3585,6 +3622,8 @@ data_exchange:
 
             goto exit;
         }
+
+        mbedtls_printf( " ok\n" );
     }
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 

From 8175816200ef60eb8209a38dfcf38b9da9d8401f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Fri, 12 Jul 2019 10:50:19 +0200
Subject: [PATCH 08/27] Fix English in comments

---
 library/ssl_tls.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index e6d27e7b3..8e5e5afa1 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -9565,7 +9565,7 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
 }
 
 /*
- * Unserialize session, see mbedtls_ssl_session_save() for format.
+ * 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.
@@ -9805,7 +9805,7 @@ static int ssl_session_load( mbedtls_ssl_session *session,
 }
 
 /*
- * Unserialize session: public wrapper for error cleaning
+ * Deserialize session: public wrapper for error cleaning
  */
 int mbedtls_ssl_session_load( mbedtls_ssl_session *session,
                               const unsigned char *buf,
@@ -10854,7 +10854,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
 }
 
 /*
- * Unserialize context, see mbedtls_ssl_context_save() for format.
+ * 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.
@@ -10951,7 +10951,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
 }
 
 /*
- * Unserialize context: public wrapper for error cleaning
+ * Deserialize context: public wrapper for error cleaning
  */
 int mbedtls_ssl_context_load( mbedtls_ssl_context *context,
                               const unsigned char *buf,

From 322f3c73771ebc26cad8e28e766adeecec676671 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 15 Jul 2019 09:04:11 +0200
Subject: [PATCH 09/27] Add transform (de)serialization

---
 library/ssl_tls.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 106 insertions(+)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 8e5e5afa1..bbaf7b6f3 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10840,6 +10840,31 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         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 */
+
     /*
      * Done
      */
@@ -10853,6 +10878,23 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
     return( 0 );
 }
 
+/*
+ * Helper to get TLS 1.2 PRF from ciphersuite
+ * (Duplicates bits of logic from ssl_set_handshake_prfs().)
+ */
+typedef int (*tls_prf_fn)( const unsigned char *secret, size_t slen,
+                           const char *label,
+                           const unsigned char *random, size_t rlen,
+                           unsigned char *dstbuf, size_t dlen );
+static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id )
+{
+    mbedtls_ssl_ciphersuite_handle_t const info =
+        mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
+    const mbedtls_md_type_t hash = mbedtls_ssl_suite_get_mac( info );
+
+    return hash == MBEDTLS_MD_SHA384 ? tls_prf_sha384 : tls_prf_sha256;
+}
+
 /*
  * Deserialize context, see mbedtls_ssl_context_save() for format.
  *
@@ -10941,6 +10983,70 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
 
     p += session_len;
 
+    /*
+     * Transform
+     */
+
+    /* Allocate and initialize structure */
+    ssl->transform = mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) );
+    if( ssl->transform == NULL )
+        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+    mbedtls_ssl_transform_init( ssl->transform );
+
+    ssl->transform_in = ssl->transform;
+    ssl->transform_out = ssl->transform;
+
+    /* Read random bytes and populate structure */
+    if( (size_t)( end - p ) < sizeof( ssl->transform->randbytes ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ret = ssl_populate_transform( ssl->transform,
+                  mbedtls_ssl_session_get_ciphersuite( ssl->session ),
+                  ssl->session->master,
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+                  ssl->session->encrypt_then_mac,
+#endif
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+                  ssl->session->trunc_hmac,
+#endif
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+                  ssl->session->compression,
+#endif
+                  ssl_tls12prf_from_cs(
+                      mbedtls_ssl_session_get_ciphersuite( ssl->session) ),
+                  p, /* currently pointing to randbytes */
+                  MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */
+                  mbedtls_ssl_conf_get_endpoint( ssl->conf ),
+                  ssl );
+    if( ret != 0 )
+        return( ret );
+
+    p += sizeof( ssl->transform->randbytes );
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    /* Read connection IDs and store them */
+    if( (size_t)( end - p ) < 1 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->transform->in_cid_len = *p++;
+
+    if( (size_t)( end - p ) < ssl->transform->in_cid_len + 1 )
+        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 */
+
     /*
      * Done - should have consumed entire buffer
      */

From c981229b04cdb149af95147fa54d5c747281e78d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 15 Jul 2019 10:31:11 +0200
Subject: [PATCH 10/27] Fix memory leak in client/server2

context_buf was never free()d. Moreover, since we want to free it on error
paths as well, and even properly zeroize it in order to demonstrate good
memory hygiene, we need to make it and its length main()-scoped.
---
 programs/ssl/ssl_client2.c | 15 ++++++++++++++-
 programs/ssl/ssl_server2.c | 16 +++++++++++++++-
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 41cd4e4c0..55277b12d 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -805,6 +805,10 @@ int main( int argc, char *argv[] )
 #endif
     char *p, *q;
     const int *list;
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    unsigned char *context_buf = NULL;
+    size_t context_buf_len;
+#endif
 
     /*
      * Make sure memory references are valid.
@@ -2489,7 +2493,6 @@ send_request:
     if( opt.serialize != 0 )
     {
         size_t buf_len;
-        unsigned char *context_buf = NULL;
 
         mbedtls_printf( "  . Serializing live connection..." );
 
@@ -2509,6 +2512,7 @@ send_request:
 
             goto exit;
         }
+        context_buf_len = buf_len;
 
         if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
                                               buf_len, &buf_len ) ) != 0 )
@@ -2586,6 +2590,10 @@ send_request:
             goto exit;
         }
 
+        mbedtls_free( context_buf );
+        context_buf = NULL;
+        context_buf_len = 0;
+
         mbedtls_printf( " ok\n" );
     }
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
@@ -2725,6 +2733,11 @@ exit:
     if( session_data != NULL )
         mbedtls_platform_zeroize( session_data, session_data_len );
     mbedtls_free( session_data );
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    if( context_buf != NULL )
+        mbedtls_platform_zeroize( context_buf, context_buf_len );
+    mbedtls_free( context_buf );
+#endif
 
 #if defined(_WIN32)
     mbedtls_printf( "  + Press Enter to exit this program.\n" );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index dbabc7a34..bf209e8b1 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1442,6 +1442,10 @@ int main( int argc, char *argv[] )
     size_t cid_len = 0;
     size_t cid_renego_len = 0;
 #endif
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    unsigned char *context_buf = NULL;
+    size_t context_buf_len;
+#endif
 
     int i;
     char *p, *q;
@@ -3505,7 +3509,6 @@ data_exchange:
     if( opt.serialize != 0 )
     {
         size_t buf_len;
-        unsigned char *context_buf = NULL;
 
         mbedtls_printf( "  . Serializing live connection..." );
 
@@ -3525,6 +3528,7 @@ data_exchange:
 
             goto exit;
         }
+        context_buf_len = buf_len;
 
         if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
                                               buf_len, &buf_len ) ) != 0 )
@@ -3623,6 +3627,10 @@ data_exchange:
             goto exit;
         }
 
+        mbedtls_free( context_buf );
+        context_buf = NULL;
+        context_buf_len = 0;
+
         mbedtls_printf( " ok\n" );
     }
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
@@ -3715,6 +3723,12 @@ exit:
 
     mbedtls_free( buf );
 
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+    if( context_buf != NULL )
+        mbedtls_platform_zeroize( context_buf, context_buf_len );
+    mbedtls_free( context_buf );
+#endif
+
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
 #if defined(MBEDTLS_MEMORY_DEBUG)
     mbedtls_memory_buffer_alloc_status();

From 16d1485a3d49acee63bec873a825601cb4ca4cd9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 15 Jul 2019 11:23:03 +0200
Subject: [PATCH 11/27] Add saved fields from top-level structure

---
 library/ssl_tls.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index bbaf7b6f3..4fec9885e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10865,6 +10865,88 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
     }
 #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
+                               ? 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
      */
@@ -11047,6 +11129,98 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
     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 */
+
     /*
      * Done - should have consumed entire buffer
      */

From 138079d7d6d7613de540ec08927b36669a6b34d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 15 Jul 2019 11:53:51 +0200
Subject: [PATCH 12/27] Add setting of forced fields when deserializing

---
 library/ssl_tls.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 4fec9885e..e2f177940 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -11221,6 +11221,31 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
     }
 #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
      */

From 86dfa0cfc954c2dcbcd1ac4e4cf23961cb690f8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 15 Jul 2019 12:23:22 +0200
Subject: [PATCH 13/27] Change requirements for setting timer callback

The code wants timer callbacks to be set (checked in fetch_input()), and can't
easily check whether we're using nbio, so it seems easier to require the
callbacks to be always set rather than only with nbio as was previously done.
---
 include/mbedtls/ssl.h      | 15 ++++++---------
 programs/ssl/ssl_client2.c | 11 ++++-------
 programs/ssl/ssl_server2.c | 11 ++++-------
 3 files changed, 14 insertions(+), 23 deletions(-)

diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 485d1cd92..56b567708 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3977,15 +3977,12 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
  *                 (unless they were already set before calling
  *                 mbedtls_ssl_session_reset() and the values are suitable for
  *                 the present connection). Specifically, you want to call
- *                 at least mbedtls_ssl_set_bio(). If you're using a read
- *                 timeout (that is, you called
- *                 mbedtls_ssl_conf_read_timeout() with a non-zero timeout)
- *                 and non-blocking I/O, you also need to set timer callbacks
- *                 by calling mbedtls_ssl_set_timer_cb(). All other SSL setter
- *                 functions are not necessary to call, either because they're
- *                 only used in handshakes, or because the setting is already
- *                 saved. You might choose to call them anyway, for example in
- *                 order to share code between the cases of establishing a new
+ *                 at least mbedtls_ssl_set_bio() and
+ *                 mbedtls_ssl_set_timer_cb(). All other SSL setter functions
+ *                 are not necessary to call, either because they're only used
+ *                 in handshakes, or because the setting is already saved. You
+ *                 might choose to call them anyway, for example in order to
+ *                 share code between the cases of establishing a new
  *                 connection and the case of loading an already-established
  *                 connection.
  *
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 55277b12d..77bab8d54 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -2563,17 +2563,14 @@ send_request:
                             opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
 #if defined(MBEDTLS_TIMING_C)
-            if( opt.nbio != 0 && opt.read_timeout != 0 )
-            {
 #if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
     !defined(MBEDTLS_SSL_CONF_GET_TIMER)
-                mbedtls_ssl_set_timer_cb( &ssl, &timer,
-                                          mbedtls_timing_set_delay,
-                                          mbedtls_timing_get_delay );
+            mbedtls_ssl_set_timer_cb( &ssl, &timer,
+                                      mbedtls_timing_set_delay,
+                                      mbedtls_timing_get_delay );
 #else
-                mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+            mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
 #endif
-            }
 #endif /* MBEDTLS_TIMING_C */
 
             mbedtls_printf( " ok\n" );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index bf209e8b1..b2c140fd1 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -3600,17 +3600,14 @@ data_exchange:
                             opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
 #if defined(MBEDTLS_TIMING_C)
-            if( opt.nbio != 0 && opt.read_timeout != 0 )
-            {
 #if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
     !defined(MBEDTLS_SSL_CONF_GET_TIMER)
-                mbedtls_ssl_set_timer_cb( &ssl, &timer,
-                                          mbedtls_timing_set_delay,
-                                          mbedtls_timing_get_delay );
+            mbedtls_ssl_set_timer_cb( &ssl, &timer,
+                                      mbedtls_timing_set_delay,
+                                      mbedtls_timing_get_delay );
 #else
-                mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+            mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
 #endif
-            }
 #endif /* MBEDTLS_TIMING_C */
 
             mbedtls_printf( " ok\n" );

From 0d83271a45ef7b45aac707867a87be080596258a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 14:13:43 +0200
Subject: [PATCH 14/27] Enable serialisation tests in ssl-opt.sh

They currently pass in a default build.
---
 tests/ssl-opt.sh | 42 ++++++++++++++++++------------------------
 1 file changed, 18 insertions(+), 24 deletions(-)

diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index acbf4143e..c170df22c 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1322,56 +1322,50 @@ run_test    "Truncated HMAC, DTLS: client enabled, server enabled" \
 
 # Tests for Context serialization
 
-skip_next_test
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
-run_test    "(STUB) Context serialization, client serializes" \
-            "$P_SRV serialize=0 exchanges=2" \
-            "$P_CLI serialize=1 exchanges=2" \
+run_test    "Context serialization, client serializes" \
+            "$P_SRV dtls=1 serialize=0 exchanges=2" \
+            "$P_CLI dtls=1 serialize=1 exchanges=2" \
             0 \
             -c "Deserializing connection..." \
             -S "Deserializing connection..."
 
-skip_next_test
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
-run_test    "(STUB) Context serialization, server serializes" \
-            "$P_SRV serialize=1 exchanges=2" \
-            "$P_CLI serialize=0 exchanges=2" \
+run_test    "Context serialization, server serializes" \
+            "$P_SRV dtls=1 serialize=1 exchanges=2" \
+            "$P_CLI dtls=1 serialize=0 exchanges=2" \
             0 \
             -C "Deserializing connection..." \
             -s "Deserializing connection..."
 
-skip_next_test
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
-run_test    "(STUB) Context serialization, both serialize" \
-            "$P_SRV serialize=1 exchanges=2" \
-            "$P_CLI serialize=1 exchanges=2" \
+run_test    "Context serialization, both serialize" \
+            "$P_SRV dtls=1 serialize=1 exchanges=2" \
+            "$P_CLI dtls=1 serialize=1 exchanges=2" \
             0 \
             -c "Deserializing connection..." \
             -s "Deserializing connection..."
 
-skip_next_test
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
-run_test    "(STUB) Context serialization, re-init, client serializes" \
-            "$P_SRV serialize=0 exchanges=2" \
-            "$P_CLI serialize=2 exchanges=2" \
+run_test    "Context serialization, re-init, client serializes" \
+            "$P_SRV dtls=1 serialize=0 exchanges=2" \
+            "$P_CLI dtls=1 serialize=2 exchanges=2" \
             0 \
             -c "Deserializing connection..." \
             -S "Deserializing connection..."
 
-skip_next_test
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
-run_test    "(STUB) Context serialization, re-init, server serializes" \
-            "$P_SRV serialize=2 exchanges=2" \
-            "$P_CLI serialize=0 exchanges=2" \
+run_test    "Context serialization, re-init, server serializes" \
+            "$P_SRV dtls=1 serialize=2 exchanges=2" \
+            "$P_CLI dtls=1 serialize=0 exchanges=2" \
             0 \
             -C "Deserializing connection..." \
             -s "Deserializing connection..."
 
-skip_next_test
 requires_config_enabled MBEDTLS_SSL_CONTEXT_SERIALIZATION
-run_test    "(STUB) Context serialization, re-init, both serialize" \
-            "$P_SRV serialize=2 exchanges=2" \
-            "$P_CLI serialize=2 exchanges=2" \
+run_test    "Context serialization, re-init, both serialize" \
+            "$P_SRV dtls=1 serialize=2 exchanges=2" \
+            "$P_CLI dtls=1 serialize=2 exchanges=2" \
             0 \
             -c "Deserializing connection..." \
             -s "Deserializing connection..."

From ff22200fab6ad7fc3ffde46a3ab9837aaa90f6d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 14:43:30 +0200
Subject: [PATCH 15/27] Re-use buffer allocated by handshake_init()

This fixes a memory leak as well (found by running ssl-opt.sh in an Asan
build).
---
 library/ssl_tls.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index e2f177940..b80fc34d3 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -11048,13 +11048,12 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
                   ( (size_t) p[3]       );
     p += 4;
 
-    ssl->session = mbedtls_calloc( 1, sizeof( mbedtls_ssl_session ) );
-    if( ssl->session == NULL )
-        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-    mbedtls_ssl_session_init( ssl->session );
-
+    /* 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 );
@@ -11069,14 +11068,12 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
      * Transform
      */
 
-    /* Allocate and initialize structure */
-    ssl->transform = mbedtls_calloc( 1, sizeof( mbedtls_ssl_transform ) );
-    if( ssl->transform == NULL )
-        return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
-    mbedtls_ssl_transform_init( ssl->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 ) )

From bc847caa333cd830ac3b1215688ab216210a6e10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 14:51:09 +0200
Subject: [PATCH 16/27] Actually reset the context on save as advertised

Also fix some wording in the documentation while at it.
---
 include/mbedtls/ssl.h      |  6 ++++--
 library/ssl_tls.c          |  2 +-
 programs/ssl/ssl_client2.c | 12 ++----------
 programs/ssl/ssl_server2.c | 12 ++----------
 4 files changed, 9 insertions(+), 23 deletions(-)

diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 56b567708..1bbae3f6c 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3908,10 +3908,10 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
  * \note           When this function succeeds, it calls
  *                 mbedtls_ssl_session_reset() on \p ssl which as a result is
  *                 no longer associated with the connection that has been
- *                 serialized. This avoids creating copies of the session
+ *                 serialized. This avoids creating copies of the connection
  *                 state. You're then free to either re-use the context
  *                 structure for a different connection, or call
- *                 mbedtls_ssl_session_free() on it. See the documentation of
+ *                 mbedtls_ssl_free() on it. See the documentation of
  *                 mbedtls_ssl_session_reset() for more details.
  *
  * \param ssl      The SSL context to save. On success, it is no longer
@@ -3934,6 +3934,8 @@ void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
  *
  * \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
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index b80fc34d3..d96038a5e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10957,7 +10957,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
 
     MBEDTLS_SSL_DEBUG_BUF( 4, "saved context", buf, used );
 
-    return( 0 );
+    return( ssl_session_reset_int( ssl, 0 ) );
 }
 
 /*
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 77bab8d54..81480b097 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -2527,16 +2527,8 @@ send_request:
 
         if( opt.serialize == 1 )
         {
-            mbedtls_printf( "  . Reseting context..." );
-
-            if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
-            {
-                mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned "
-                                "-0x%x\n\n", -ret );
-                goto exit;
-            }
-
-            mbedtls_printf( " ok\n" );
+            /* nothing to do here, done by context_save() already */
+            mbedtls_printf( "  . Context has been reset... ok" );
         }
 
         if( opt.serialize == 2 )
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index b2c140fd1..996d7f629 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -3550,16 +3550,8 @@ data_exchange:
          */
         if( opt.serialize == 1 )
         {
-            mbedtls_printf( "  . Reseting context..." );
-
-            if( ( ret = mbedtls_ssl_session_reset( &ssl ) ) != 0 )
-            {
-                mbedtls_printf( " failed\n  ! mbedtls_ssl_session_reset returned "
-                                "-0x%x\n\n", -ret );
-                goto exit;
-            }
-
-            mbedtls_printf( " ok\n" );
+            /* nothing to do here, done by context_save() already */
+            mbedtls_printf( "  . Context has been reset... ok" );
         }
 
         /*

From 2f3fa62a0afb760737fc6d65e41bbdb9647c148f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 15:02:54 +0200
Subject: [PATCH 17/27] Fix compiler warning: comparing signed to unsigned

Since the type of cid_len is unsigned but shorter than int, it gets
"promoted" to int (which is also the type of the result), unless we make the
other operand an unsigned int which then forces the expression to unsigned int
as well.
---
 library/ssl_tls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index d96038a5e..35d67f01c 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -11111,7 +11111,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
 
     ssl->transform->in_cid_len = *p++;
 
-    if( (size_t)( end - p ) < ssl->transform->in_cid_len + 1 )
+    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 );

From 73a4636ca4eb5aef5e2576fa134ed8515befd79a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 15:16:19 +0200
Subject: [PATCH 18/27] Adapt to hardcoded single version

---
 library/ssl_tls.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 35d67f01c..5fcb8feff 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10792,8 +10792,8 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         ssl->out_left != 0 ||
         /* We're using DTLS 1.2 ... */
         MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
-        ssl->major_ver != MBEDTLS_SSL_MAJOR_VERSION_3 ||
-        ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ||
+        mbedtls_ssl_get_major_ver( ssl ) != MBEDTLS_SSL_MAJOR_VERSION_3 ||
+        mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 ||
         /* ... with an AEAD ciphersuite. */
         mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 ||
         /* Renegotation is disabled. */
@@ -11009,10 +11009,14 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
      * least check it matches the requirements for serializing.
      */
     if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
-        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 ||
+        mbedtls_ssl_conf_get_max_major_ver( ssl->conf ) <
+            MBEDTLS_SSL_MAJOR_VERSION_3 ||
+        mbedtls_ssl_conf_get_min_major_ver( ssl->conf ) >
+            MBEDTLS_SSL_MAJOR_VERSION_3 ||
+        mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) <
+            MBEDTLS_SSL_MINOR_VERSION_3 ||
+        mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) >
+            MBEDTLS_SSL_MINOR_VERSION_3 ||
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
         ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED
 #endif

From 4c1d06e429f4bd4cacf3c1aeef039716dc41d954 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 16:13:17 +0200
Subject: [PATCH 19/27] Provide serialisation API only if it's enabled

---
 include/mbedtls/ssl.h | 2 ++
 library/ssl_tls.c     | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 1bbae3f6c..33a6aa1e5 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -3893,6 +3893,7 @@ int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl );
  */
 void mbedtls_ssl_free( mbedtls_ssl_context *ssl );
 
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
 /**
  * \brief          Save an active connection as serialized data in a buffer.
  *                 This allows the freeing or re-using of the SSL context
@@ -4014,6 +4015,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
 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
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 5fcb8feff..016e0e373 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10719,6 +10719,7 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *session )
     mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) );
 }
 
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
 static unsigned char ssl_serialized_context_header[] = {
     MBEDTLS_VERSION_MAJOR,
     MBEDTLS_VERSION_MINOR,
@@ -11270,6 +11271,7 @@ int mbedtls_ssl_context_load( mbedtls_ssl_context *context,
 
     return( ret );
 }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 
 /*
  * Free an SSL context

From a7cd4830ee5607d5d2beba3193094c377f9e3194 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 16:31:16 +0200
Subject: [PATCH 20/27] Implement config-checking header to context s11n

Modelled after the config-checking header from session s11n.

The list of relevant config flags was established by manually checking the
fields serialized in the format, and which config.h flags they depend on.
This probably deserves double-checking by reviewers.
---
 library/ssl_tls.c | 48 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 5 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 016e0e373..8c4041063 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10720,15 +10720,53 @@ void mbedtls_ssl_session_free( mbedtls_ssl_session *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,
-    0, /* placeholder */
-    0, /* placeholder */
-    0, /* placeholder */
+    ( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >> 16 ) & 0xFF,
+    ( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >>  8 ) & 0xFF,
+    ( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >>  0 ) & 0xFF,
 };
 
 /*
@@ -10742,8 +10780,8 @@ static unsigned char ssl_serialized_context_header[] = {
  *  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. (To be confirmed.)
+ *  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()

From 7ce9446e4c327dad8e9ec8a5bd47141706f2376f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 16:52:45 +0200
Subject: [PATCH 21/27] Avoid duplication of session format header

---
 library/ssl_tls.c | 84 ++++++++++++++++++++++++++++++-----------------
 1 file changed, 53 insertions(+), 31 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 8c4041063..6efde6010 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -9373,10 +9373,11 @@ static unsigned char ssl_serialized_session_header[] = {
  * verify_result is put before peer_cert so that all mandatory fields come
  * together in one block.
  */
-int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
-                              unsigned char *buf,
-                              size_t buf_len,
-                              size_t *olen )
+static int ssl_session_save( const mbedtls_ssl_session *session,
+                             unsigned char omit_header,
+                             unsigned char *buf,
+                             size_t buf_len,
+                             size_t *olen )
 {
     unsigned char *p = buf;
     size_t used = 0;
@@ -9389,17 +9390,20 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
 #endif
 #endif
 
-    /*
-     * Add version identifier
-     */
-
-    used += sizeof( ssl_serialized_session_header );
-
-    if( used <= buf_len )
+    if( !omit_header )
     {
-        memcpy( p, ssl_serialized_session_header,
-                sizeof( ssl_serialized_session_header ) );
-        p += sizeof( ssl_serialized_session_header );
+        /*
+         * Add version identifier
+         */
+
+        used += sizeof( ssl_serialized_session_header );
+
+        if( used <= buf_len )
+        {
+            memcpy( p, ssl_serialized_session_header,
+                    sizeof( ssl_serialized_session_header ) );
+            p += sizeof( ssl_serialized_session_header );
+        }
     }
 
     /*
@@ -9564,13 +9568,25 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
     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.
+ * 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 )
 {
@@ -9586,19 +9602,22 @@ static int ssl_session_load( mbedtls_ssl_session *session,
 #endif
 #endif
 
-    /*
-     * Check version identifier
-     */
-
-    if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) )
-        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-
-    if( memcmp( p, ssl_serialized_session_header,
-                sizeof( ssl_serialized_session_header ) ) != 0 )
+    if( !omit_header )
     {
-        return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
+        /*
+         * Check version identifier
+         */
+
+        if( (size_t)( end - p ) < sizeof( ssl_serialized_session_header ) )
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+        if( memcmp( p, ssl_serialized_session_header,
+                    sizeof( ssl_serialized_session_header ) ) != 0 )
+        {
+            return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
+        }
+        p += sizeof( ssl_serialized_session_header );
     }
-    p += sizeof( ssl_serialized_session_header );
 
     /*
      * Time
@@ -9811,7 +9830,7 @@ int mbedtls_ssl_session_load( mbedtls_ssl_session *session,
                               const unsigned char *buf,
                               size_t len )
 {
-    int ret = ssl_session_load( session, buf, len );
+    int ret = ssl_session_load( session, 0, buf, len );
 
     if( ret != 0 )
         mbedtls_ssl_session_free( session );
@@ -10859,7 +10878,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
     /*
      * Session (length + data)
      */
-    ret = mbedtls_ssl_session_save( ssl->session, NULL, 0, &session_len );
+    ret = ssl_session_save( ssl->session, 1, NULL, 0, &session_len );
     if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
         return( ret );
 
@@ -10871,8 +10890,8 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         *p++ = (unsigned char)( ( session_len >>  8 ) & 0xFF );
         *p++ = (unsigned char)( ( session_len       ) & 0xFF );
 
-        ret = mbedtls_ssl_session_save( ssl->session,
-                                        p, session_len, &session_len );
+        ret = ssl_session_save( ssl->session, 1,
+                                p, session_len, &session_len );
         if( ret != 0 )
             return( ret );
 
@@ -11101,9 +11120,12 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
     if( (size_t)( end - p ) < session_len )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
-    ret = mbedtls_ssl_session_load( ssl->session, p, session_len );
+    ret = ssl_session_load( ssl->session, 1, p, session_len );
     if( ret != 0 )
+    {
+        mbedtls_ssl_session_free( ssl->session );
         return( ret );
+    }
 
     p += session_len;
 

From 2cc9223a3bdbe62b2491d975fbaf5b4b2ff2fae4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Tue, 23 Jul 2019 17:11:24 +0200
Subject: [PATCH 22/27] Fix compile error in reduced configurations

Found by running scripts/baremetal.h --rom --gcc --check after adding
MBEDTLS_SSL_CONTEXT_SERIALIZATION to baremetal.h
---
 library/ssl_tls.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 6efde6010..dcfd52aca 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10856,9 +10856,9 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 ||
         /* Renegotation is disabled. */
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
-        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED
+        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
 #endif
-        )
+        0 )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
@@ -11032,7 +11032,13 @@ static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id )
         mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
     const mbedtls_md_type_t hash = mbedtls_ssl_suite_get_mac( info );
 
-    return hash == MBEDTLS_MD_SHA384 ? tls_prf_sha384 : tls_prf_sha256;
+#if defined(MBEDTLS_SHA512_C)
+    if( hash == MBEDTLS_MD_SHA384 )
+        return( tls_prf_sha384 );
+#else
+    (void) hash;
+#endif
+    return( tls_prf_sha256 );
 }
 
 /*
@@ -11076,9 +11082,9 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
         mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) >
             MBEDTLS_SSL_MINOR_VERSION_3 ||
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
-        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED
+        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
 #endif
-        )
+        0 )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
@@ -11291,8 +11297,12 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
      */
     ssl->state = MBEDTLS_SSL_HANDSHAKE_OVER;
 
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
     ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
     ssl->minor_ver = MBEDTLS_SSL_MINOR_VERSION_3;
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
     ssl->in_epoch = 1;

From 7af73754739c28300c2f456524f9e86e4ac1f386 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Wed, 24 Jul 2019 00:58:27 +0200
Subject: [PATCH 23/27] Fix MSVC warning

We know the length of the ALPN string is always less than 255, so the cast to
uint8_t is safe.
---
 library/ssl_tls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index dcfd52aca..9a48b294e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10988,7 +10988,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
 #if defined(MBEDTLS_SSL_ALPN)
     {
         const uint8_t alpn_len = ssl->alpn_chosen
-                               ? strlen( ssl->alpn_chosen )
+                               ? (uint8_t) strlen( ssl->alpn_chosen )
                                : 0;
 
         used += 1 + alpn_len;

From 14e2a8ac06b34a136e46f2c267c85540d50f7d5a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Fri, 26 Jul 2019 16:31:53 +0200
Subject: [PATCH 24/27] Fix a typo in a comment

---
 library/ssl_tls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 9a48b294e..bded6c3ec 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -11059,7 +11059,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
     /*
      * The context should have been freshly setup or reset.
      * Give the user an error in case of obvious misuse.
-     * (Checking session is useful because if won't be NULL if we're
+     * (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 ||

From b3bb31bd90b1b34495db012ad30dab41dd4ccbb3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Fri, 26 Jul 2019 16:37:45 +0200
Subject: [PATCH 25/27] Introduce getter function for disable_renego

---
 include/mbedtls/ssl_internal.h | 10 ++++++++++
 library/ssl_tls.c              | 12 ++++--------
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 7cab1e2a0..5786f657e 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -1243,6 +1243,16 @@ static inline int mbedtls_ssl_get_renego_status(
 #endif
 }
 
+static inline int mbedtls_ssl_conf_get_disable_renego(
+        const mbedtls_ssl_config *conf )
+{
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+    return( conf->disable_renegotiation );
+#else
+    (void) conf;
+    return( MBEDTLS_SSL_RENEGOTIATION_DISABLED );
+#endif
+}
 
 /*
  * Getter functions for fields in mbedtls_ssl_config which may
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index bded6c3ec..42ccb780b 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10855,10 +10855,8 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         /* ... with an AEAD ciphersuite. */
         mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 ||
         /* Renegotation is disabled. */
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
-#endif
-        0 )
+        mbedtls_ssl_conf_get_disable_renego( ssl->conf )
+            != MBEDTLS_SSL_RENEGOTIATION_DISABLED )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
@@ -11081,10 +11079,8 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
             MBEDTLS_SSL_MINOR_VERSION_3 ||
         mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) >
             MBEDTLS_SSL_MINOR_VERSION_3 ||
-#if defined(MBEDTLS_SSL_RENEGOTIATION)
-        ssl->conf->disable_renegotiation != MBEDTLS_SSL_RENEGOTIATION_DISABLED ||
-#endif
-        0 )
+        mbedtls_ssl_conf_get_disable_renego( ssl->conf )
+            != MBEDTLS_SSL_RENEGOTIATION_DISABLED )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }

From 18332c5c6cdd654e92a11a8d2dc20349c0cf3e71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 29 Jul 2019 12:17:52 +0200
Subject: [PATCH 26/27] Improve getter for renegotiation enabled

---
 include/mbedtls/ssl_internal.h | 7 ++++---
 library/ssl_tls.c              | 8 +++-----
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index 5786f657e..0991926b3 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -1243,14 +1243,15 @@ static inline int mbedtls_ssl_get_renego_status(
 #endif
 }
 
-static inline int mbedtls_ssl_conf_get_disable_renego(
+static inline int mbedtls_ssl_conf_is_renegotiation_enabled(
         const mbedtls_ssl_config *conf )
 {
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
-    return( conf->disable_renegotiation );
+    return( conf->disable_renegotiation ==
+            MBEDTLS_SSL_RENEGOTIATION_ENABLED );
 #else
     (void) conf;
-    return( MBEDTLS_SSL_RENEGOTIATION_DISABLED );
+    return( 0 );
 #endif
 }
 
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 42ccb780b..d43912ddc 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10030,7 +10030,7 @@ static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl )
 
     if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ||
         ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ||
-        ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED )
+        ! mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
     {
         return( 0 );
     }
@@ -10855,8 +10855,7 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
         /* ... with an AEAD ciphersuite. */
         mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 ||
         /* Renegotation is disabled. */
-        mbedtls_ssl_conf_get_disable_renego( ssl->conf )
-            != MBEDTLS_SSL_RENEGOTIATION_DISABLED )
+        mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
@@ -11079,8 +11078,7 @@ static int ssl_context_load( mbedtls_ssl_context *ssl,
             MBEDTLS_SSL_MINOR_VERSION_3 ||
         mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) >
             MBEDTLS_SSL_MINOR_VERSION_3 ||
-        mbedtls_ssl_conf_get_disable_renego( ssl->conf )
-            != MBEDTLS_SSL_RENEGOTIATION_DISABLED )
+        mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
     {
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }

From 69a3e417d8e758256b3a0e3f2d492190c8fccbfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?=
 <manuel.pegourie-gonnard@arm.com>
Date: Mon, 29 Jul 2019 12:28:52 +0200
Subject: [PATCH 27/27] Improve reability and debugability of large if

Breaking into a series of statements makes things easier when stepping through
the code in a debugger.

Previous comments we stating the opposite or what the code tested for (what we
want vs what we're erroring out on) which was confusing.

Also expand a bit on the reasons for these restrictions.
---
 library/ssl_tls.c | 52 +++++++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 20 deletions(-)

diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index d43912ddc..99622784b 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -10837,28 +10837,40 @@ int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
     int ret = 0;
 
     /*
-     * Enforce current usage restrictions
+     * 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.
      */
-    if( /* The initial handshake is over ... */
-        ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ||
-        ssl->handshake != NULL ||
-        /* ... and the various sub-structures are indeed ready. */
-        ssl->transform == NULL ||
-        ssl->session == NULL ||
-        /* There is no pending incoming or outgoing data ... */
-        mbedtls_ssl_check_pending( ssl ) != 0 ||
-        ssl->out_left != 0 ||
-        /* We're using DTLS 1.2 ... */
-        MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
-        mbedtls_ssl_get_major_ver( ssl ) != MBEDTLS_SSL_MAJOR_VERSION_3 ||
-        mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 ||
-        /* ... with an AEAD ciphersuite. */
-        mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 ||
-        /* Renegotation is disabled. */
-        mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
-    {
+    /* The initial handshake must be over */
+    if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    if( ssl->handshake != NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Double-check that sub-structures are indeed ready */
+    if( ssl->transform == NULL || ssl->session == NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* There must be no pending incoming or outgoing data */
+    if( mbedtls_ssl_check_pending( ssl ) != 0 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    if( ssl->out_left != 0 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Protocol must be DLTS, not TLS */
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Version must be 1.2 */
+    if( mbedtls_ssl_get_major_ver( ssl ) != MBEDTLS_SSL_MAJOR_VERSION_3 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* We must be using an AEAD ciphersuite */
+    if( mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Renegotiation must not be enabled */
+    if( mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
-    }
 
     /*
      * Version and format identifier