Merge pull request #632 from hanno-arm/baremetal_sh_debug-baremetal

[Baremetal] Add `--debug` option to `baremetal.sh`
diff --git a/configs/baremetal.h b/configs/baremetal.h
index aadbd09..9929d56 100644
--- a/configs/baremetal.h
+++ b/configs/baremetal.h
@@ -122,6 +122,8 @@
 #define MBEDTLS_X509_CHECK_KEY_USAGE
 #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE
 #define MBEDTLS_X509_REMOVE_INFO
+#define MBEDTLS_X509_CRT_REMOVE_TIME
+#define MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID
 #define MBEDTLS_X509_ON_DEMAND_PARSING
 #define MBEDTLS_X509_ALWAYS_FLUSH
 #define MBEDTLS_ASN1_PARSE_C
diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h
index 576349f..29e61db 100644
--- a/include/mbedtls/check_config.h
+++ b/include/mbedtls/check_config.h
@@ -793,6 +793,11 @@
 #error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites"
 #endif
 
+#if defined(MBEDTLS_X509_CRT_REMOVE_TIME) && \
+    defined(MBEDTLS_HAVE_TIME_DATE)
+#error "MBEDTLS_X509_CRT_REMOVE_TIME and MBEDTLS_HAVE_TIME_DATE cannot be defined simultaneously"
+#endif
+
 #if defined(MBEDTLS_HAVE_INT32) && defined(MBEDTLS_HAVE_INT64)
 #error "MBEDTLS_HAVE_INT32 and MBEDTLS_HAVE_INT64 cannot be defined simultaneously"
 #endif /* MBEDTLS_HAVE_INT32 && MBEDTLS_HAVE_INT64 */
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index fb0f26e..f8a99f2 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -1943,6 +1943,29 @@
 //#define MBEDTLS_X509_REMOVE_INFO
 
 /**
+ * \def MBEDTLS_X509_CRT_REMOVE_TIME
+ *
+ * Don't store time validity fields in X.509 certificate structures.
+ *
+ * Uncomment this to save some code and RAM on constrained systems which
+ * don't have time and where there's no use of the time validity fields
+ * in a certificate.
+ *
+ * Requires: !MBEDTLS_HAVE_TIME_DATE
+ */
+//#define MBEDTLS_X509_CRT_REMOVE_TIME
+
+/**
+ * \def MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID
+ *
+ * Don't store subject and issuer ID in X.509 certificate structures.
+ *
+ * Uncomment this to save some code and RAM on constrained systems which
+ * don't need to inspect issuer and subject ID fields in certificates.
+ */
+//#define MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID
+
+/**
  * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT
  *
  * Enable parsing and verification of X.509 certificates, CRLs and CSRS
@@ -3670,7 +3693,7 @@
  * If this is set, you must also define the following:
  * - MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
  *   This must resolve to the Mbed TLS group ID for the elliptic
- *   curve to use (e.g. MBEDTLS_ECP_DP_SECP256R1_ENABLED); see
+ *   curve to use (e.g. MBEDTLS_ECP_DP_SECP256R1); see
  *   ::mbedtls_ecp_group_id in mbedtls/ecp.h for a complete list
  *   of curve identifiers.
  * - MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID
@@ -3682,8 +3705,8 @@
  * runtime configuration API mbedtls_ssl_conf_curves().
  */
 //#define MBEDTLS_SSL_CONF_SINGLE_EC
-//#define MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID
-//#define MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID
+//#define MBEDTLS_SSL_CONF_SINGLE_EC_TLS_ID 23
+//#define MBEDTLS_SSL_CONF_SINGLE_EC_GRP_ID MBEDTLS_ECP_DP_SECP256R1
 
 /* Enable support a single signature hash algorithm
  * at compile-time, at the benefit of code-size.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index a41182c..9e5fb2d 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -366,6 +366,7 @@
 #define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME    112  /* 0x70 */
 #define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115  /* 0x73 */
 #define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */
+#define MBEDTLS_SSL_ALERT_MSG_NONE                 255  /* internal */
 
 #define MBEDTLS_SSL_HS_HELLO_REQUEST            0
 #define MBEDTLS_SSL_HS_CLIENT_HELLO             1
@@ -1234,6 +1235,9 @@
 {
     const mbedtls_ssl_config *conf; /*!< configuration information          */
 
+    unsigned char pending_fatal_alert_msg; /*!< Type of a fatal alert
+                                            *   pending to be delivered.    */
+
     /*
      * Miscellaneous
      */
@@ -3899,6 +3903,7 @@
  */
 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
@@ -3914,10 +3919,10 @@
  * \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
@@ -3932,19 +3937,26 @@
  * \note           \p olen is updated to the correct value regardless of
  *                 whether \p buf_len was large enough. This makes it possible
  *                 to determine the necessary size by calling this function
- *                 with \p buf set to \c NULL and \p buf_len to \c 0.
+ *                 with \p buf set to \c NULL and \p buf_len to \c 0. However,
+ *                 the value of \p olen is only guaranteed to be correct when
+ *                 the function returns #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL or
+ *                 \c 0. If the return value is different, then the value of
+ *                 \p olen is undefined.
  *
  * \return         \c 0 if successful.
  * \return         #MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL if \p buf is too small.
+ * \return         #MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed
+ *                 while reseting the context.
  * \return         #MBEDTLS_ERR_SSL_BAD_INPUT_DATA if a handshake is in
  *                 progress, or there is pending data for reading or sending,
- *                 or the connection does not use DTLS 1.2 with and AEAD
+ *                 or the connection does not use DTLS 1.2 with an AEAD
  *                 ciphersuite, or renegotiation is enabled.
  */
 int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
                               unsigned char *buf,
                               size_t buf_len,
                               size_t *olen );
+
 /**
  * \brief          Load serialized connection data to an SSL context.
  *
@@ -3978,15 +3990,12 @@
  *                 (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.
  *
@@ -3996,6 +4005,11 @@
  *                 newly-configured value with the value that was active when
  *                 the context was saved.
  *
+ * \note           When this function returns an error code, it calls
+ *                 mbedtls_ssl_free() on \p ssl. In this case, you need to
+ *                 prepare the context with the usual sequence starting with a
+ *                 call to mbedtls_ssl_init() if you want to use it again.
+ *
  * \param ssl      The SSL context structure to be populated. It must have
  *                 been prepared as described in the note above.
  * \param buf      The buffer holding the serialized connection data. It must
@@ -4004,11 +4018,14 @@
  *
  * \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
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index b8875ab..9b8e21f 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -728,6 +728,12 @@
     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 )
@@ -741,6 +747,21 @@
 }
 
 /*
+ * 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:
@@ -1222,6 +1243,17 @@
 #endif
 }
 
+static inline int mbedtls_ssl_conf_is_renegotiation_enabled(
+        const mbedtls_ssl_config *conf )
+{
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+    return( conf->disable_renegotiation ==
+            MBEDTLS_SSL_RENEGOTIATION_ENABLED );
+#else
+    (void) conf;
+    return( 0 );
+#endif
+}
 
 /*
  * Getter functions for fields in mbedtls_ssl_config which may
@@ -1724,4 +1756,28 @@
 
 #endif /* MBEDTLS_SSL_CONF_SINGLE_SIG_HASH */
 
+#if defined(__GNUC__) || defined(__arm__)
+#define MBEDTLS_ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define MBEDTLS_ALWAYS_INLINE
+#endif
+
+/* This internal function can be used to pend a fatal alert for
+ * later delivery.
+ *
+ * The check for pending alerts must be done by calling
+ * the function ssl_send_pending_fatal_alert() in ssl_tls.c.
+ * Currently, it happens only during the handshake loop and after
+ * calling ssl_get_next_record() in the record processing stack.
+ *
+ * This function must not be called multiple times without
+ * sending the pending fatal alerts in between.
+ */
+MBEDTLS_ALWAYS_INLINE static inline void mbedtls_ssl_pend_fatal_alert(
+    mbedtls_ssl_context *ssl,
+    unsigned char message )
+{
+    ssl->pending_fatal_alert_msg = message;
+}
+
 #endif /* ssl_internal.h */
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 5212e67..c8f488c 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -70,8 +70,10 @@
     uint32_t ext_types;                     /**< Bitfield indicating which extensions are present.
                                              *   See the values in x509.h.                                      */
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
     mbedtls_x509_time valid_from;           /**< The start time of certificate validity.                        */
     mbedtls_x509_time valid_to;             /**< The end time of certificate validity.                          */
+#endif /* !MBEDTLS_X509_CRT_REMOVE_TIME */
 
     mbedtls_x509_buf_raw raw;               /**< The raw certificate data in DER.                               */
     mbedtls_x509_buf_raw tbs;               /**< The part of the CRT that is [T]o [B]e [S]igned.                */
@@ -80,10 +82,12 @@
 
     mbedtls_x509_buf_raw pubkey_raw;        /**< The raw public key data (DER).                                 */
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
     mbedtls_x509_buf_raw issuer_id;         /**< Optional X.509 v2/v3 issuer unique identifier.                 */
-    mbedtls_x509_buf_raw issuer_raw;        /**< The raw issuer data (DER). Used for quick comparison.          */
-
     mbedtls_x509_buf_raw subject_id;        /**< Optional X.509 v2/v3 subject unique identifier.                */
+#endif /* !MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
+
+    mbedtls_x509_buf_raw issuer_raw;        /**< The raw issuer data (DER). Used for quick comparison.          */
     mbedtls_x509_buf_raw subject_raw;       /**< The raw subject data (DER). Used for quick comparison.         */
 
     mbedtls_x509_buf_raw sig;               /**< Signature: hash of the tbs part signed with the private key.   */
@@ -123,14 +127,18 @@
     mbedtls_x509_name issuer;           /**< The parsed issuer data (named information object). */
     mbedtls_x509_name subject;          /**< The parsed subject data (named information object). */
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
     mbedtls_x509_time valid_from;       /**< Start time of certificate validity. */
     mbedtls_x509_time valid_to;         /**< End time of certificate validity. */
+#endif /* !MBEDTLS_X509_CRT_REMOVE_TIME */
 
     mbedtls_x509_buf pk_raw;
     mbedtls_pk_context pk;              /**< Container for the public key context. */
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
     mbedtls_x509_buf issuer_id;         /**< Optional X.509 v2/v3 issuer unique identifier. */
     mbedtls_x509_buf subject_id;        /**< Optional X.509 v2/v3 subject unique identifier. */
+#endif /* !MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
     mbedtls_x509_buf v3_ext;            /**< Optional X.509 v3 extensions.  */
     mbedtls_x509_sequence subject_alt_names;    /**< Optional list of Subject Alternative Names (Only dNSName supported). */
 
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 3d42155..003aa10 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1185,8 +1185,8 @@
                           ssl->peer_verify_data, ssl->verify_data_len ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
     }
@@ -1196,8 +1196,8 @@
         if( len != 1 || buf[0] != 0x00 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
 
@@ -1221,8 +1221,8 @@
         buf[0] != ssl->conf->mfl_code )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching max fragment length extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1239,8 +1239,8 @@
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching truncated HMAC extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1265,16 +1265,16 @@
         ssl->negotiate_cid == MBEDTLS_SSL_CID_DISABLED )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension unexpected" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     if( len == 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1284,16 +1284,16 @@
     if( peer_cid_len > MBEDTLS_SSL_CID_OUT_LEN_MAX )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     if( len != peer_cid_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "CID extension invalid" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1318,8 +1318,8 @@
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching encrypt-then-MAC extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1342,8 +1342,8 @@
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching extended master secret extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1361,8 +1361,8 @@
         len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching session ticket extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1386,8 +1386,8 @@
     if( len == 0 || (size_t)( buf[0] + 1 ) != len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
     list_size = buf[0];
@@ -1413,8 +1413,8 @@
     }
 
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "no point format in common" ) );
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
     return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
 }
 #endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C ||
@@ -1444,8 +1444,8 @@
                                                 buf, len ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( ret );
     }
 
@@ -1464,8 +1464,8 @@
     if( ssl->conf->alpn_list == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching ALPN extension" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1482,24 +1482,24 @@
     /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */
     if( len < 4 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     list_len = ( buf[0] << 8 ) | buf[1];
     if( list_len != len - 2 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
     name_len = buf[2];
     if( name_len != list_len - 1 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1515,8 +1515,8 @@
     }
 
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "ALPN extension: no matching protocol" ) );
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
     return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
 }
 #endif /* MBEDTLS_SSL_ALPN */
@@ -1554,8 +1554,8 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server version" ) );
 
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
 
         return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
     }
@@ -1567,8 +1567,8 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1,
             ( "cookie length does not match incoming message size" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1651,8 +1651,8 @@
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -1679,8 +1679,8 @@
         buf[0] != MBEDTLS_SSL_HS_SERVER_HELLO )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1718,8 +1718,8 @@
                          mbedtls_ssl_conf_get_max_major_ver( ssl->conf ),
                          mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) ) );
 
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                      MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                 MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
 
             return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
         }
@@ -1748,8 +1748,8 @@
     if( n > 32 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1762,8 +1762,8 @@
             ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 40 + n + ext_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
     }
@@ -1774,8 +1774,8 @@
     else
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -1798,8 +1798,8 @@
 #endif/* MBEDTLS_ZLIB_SUPPORT */
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
     }
 
@@ -1813,8 +1813,8 @@
     if( server_suite_info == MBEDTLS_SSL_CIPHERSUITE_INVALID_HANDLE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
     }
     mbedtls_ssl_optimize_checksum( ssl, server_suite_info );
@@ -1853,8 +1853,8 @@
         if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
             return( ret );
         }
     }
@@ -1903,8 +1903,8 @@
     /* If we reach this code-path, the server's chosen ciphersuite
      * wasn't among those advertised by us. */
     MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
     return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
 
 server_picked_valid_suite:
@@ -1928,8 +1928,8 @@
       )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
     ssl->session_negotiate->compression = comp;
@@ -1949,8 +1949,8 @@
         if( ext_size + 4 > ext_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
         }
 
@@ -2161,8 +2161,8 @@
 
     if( handshake_failure == 1 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO );
     }
 
@@ -2608,8 +2608,8 @@
         if( ( ret = ssl_get_ecdh_params_from_cert( ssl ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( ret );
         }
 
@@ -2639,8 +2639,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -2663,8 +2663,8 @@
 
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key exchange message must "
                                     "not be skipped" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
 
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
@@ -2692,8 +2692,8 @@
         if( ssl_parse_server_psk_hint( ssl, &p, end ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     } /* FALLTROUGH */
@@ -2721,8 +2721,8 @@
         if( ssl_parse_server_dh_params( ssl, &p, end ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
@@ -2742,8 +2742,8 @@
         if( ssl_parse_server_ecdh_params( ssl, &p, end ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
@@ -2760,8 +2760,8 @@
         if( ret != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                   MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
     }
@@ -2795,16 +2795,16 @@
                                                &md_alg, &pk_alg ) != 0 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                    MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
                 return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
             }
 
             if( pk_alg != mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ) )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                     MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
                 return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
             }
         }
@@ -2834,8 +2834,8 @@
         if( p > end - 2 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
         sig_len = ( p[0] << 8 ) | p[1];
@@ -2844,8 +2844,8 @@
         if( p != end - sig_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE );
         }
 
@@ -2912,8 +2912,8 @@
         if( !mbedtls_pk_can_do( peer_pk, pk_alg ) )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
 #if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
             mbedtls_x509_crt_pk_release( ssl->session_negotiate->peer_cert );
 #endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
@@ -2931,8 +2931,10 @@
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
             if( ret != MBEDTLS_ERR_ECP_IN_PROGRESS )
 #endif
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+            {
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                     MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
+            }
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret );
 #if defined(MBEDTLS_SSL__ECP_RESTARTABLE)
             if( ret == MBEDTLS_ERR_ECP_IN_PROGRESS )
@@ -3009,8 +3011,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                              MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -3057,8 +3059,8 @@
     if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
     cert_type_len = buf[mbedtls_ssl_hs_hdr_len( ssl )];
@@ -3077,8 +3079,8 @@
     if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
 
@@ -3108,8 +3110,8 @@
         if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n + sig_alg_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
         }
 
@@ -3134,8 +3136,8 @@
     if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST );
     }
 
@@ -3168,8 +3170,8 @@
         ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO_DONE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE );
     }
 
@@ -3709,8 +3711,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                         MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -3728,8 +3730,8 @@
         ssl->in_hslen < 6 + mbedtls_ssl_hs_hdr_len( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
     }
 
@@ -3743,8 +3745,8 @@
     if( ticket_len + 6 + mbedtls_ssl_hs_hdr_len( ssl ) != ssl->in_hslen )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET );
     }
 
@@ -3779,8 +3781,8 @@
     if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
         return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
     }
 
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index cb88be6..573f327 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -94,16 +94,16 @@
     if( len < 2 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
     if( servername_list_size + 2 != len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -114,8 +114,8 @@
         if( hostname_len + 3 > servername_list_size )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
@@ -126,7 +126,7 @@
             if( ret != 0 )
             {
                 MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                mbedtls_ssl_pend_fatal_alert( ssl,
                         MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
@@ -140,8 +140,8 @@
     if( servername_list_size != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -163,8 +163,8 @@
                           ssl->verify_data_len ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
     }
@@ -174,8 +174,8 @@
         if( len != 1 || buf[0] != 0x0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
@@ -214,8 +214,8 @@
 
     if ( len < 2 ) {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
@@ -223,8 +223,8 @@
         sig_alg_list_size % 2 != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -287,8 +287,8 @@
 
     if ( len < 2 ) {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                       MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     list_size = ( ( buf[0] << 8 ) | ( buf[1] ) );
@@ -296,8 +296,8 @@
         list_size % 2 != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -336,8 +336,8 @@
     if( len == 0 || (size_t)( buf[0] + 1 ) != len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
     list_size = buf[0];
@@ -384,8 +384,8 @@
                                                 buf, len ) ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( ret );
     }
 
@@ -404,8 +404,8 @@
     if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -426,8 +426,8 @@
     if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -443,8 +443,8 @@
     if( len < 1 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -454,8 +454,8 @@
     if( len != peer_cid_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -471,8 +471,8 @@
     if( peer_cid_len > MBEDTLS_SSL_CID_OUT_LEN_MAX )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -495,8 +495,8 @@
     if( len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -517,7 +517,7 @@
     if( len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+        mbedtls_ssl_pend_fatal_alert( ssl,
                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
@@ -542,8 +542,8 @@
     if( len != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -650,16 +650,16 @@
     /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */
     if( len < 4 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
     list_len = ( buf[0] << 8 ) | buf[1];
     if( list_len != len - 2 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -675,16 +675,16 @@
         /* Current identifier must fit in list */
         if( cur_len > (size_t)( end - theirs ) )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
         /* Empty strings MUST NOT be included */
         if( cur_len == 0 )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
     }
@@ -709,8 +709,8 @@
     }
 
     /* If we get there, no match was found */
-    mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                            MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL );
+    mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL );
     return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
 }
 #endif /* MBEDTLS_SSL_ALPN */
@@ -1056,8 +1056,8 @@
     if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
@@ -1112,8 +1112,8 @@
                             mbedtls_ssl_conf_get_min_major_ver( ssl->conf ),
                             mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) ) );
 
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                     MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
         return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
     }
 
@@ -1210,8 +1210,8 @@
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV "
                                     "during renegotiation" ) );
 
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                             MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
@@ -1234,8 +1234,8 @@
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) );
 
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                         MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
 
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
@@ -1323,8 +1323,8 @@
           MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1652,8 +1652,8 @@
                             major_ver, minor_ver,
                             mbedtls_ssl_conf_get_min_major_ver( ssl->conf ),
                             mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
             return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION );
         }
 
@@ -1689,8 +1689,8 @@
         sess_len + 34 + 2 > msg_len ) /* 2 for cipherlist length field */
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1714,8 +1714,8 @@
         if( cookie_offset + 1 + cookie_len + 2 > msg_len )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION );
             return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
         }
 
@@ -1774,8 +1774,8 @@
         ( ciph_len % 2 ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1794,8 +1794,8 @@
         comp_len + comp_offset + 1 > msg_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -1835,8 +1835,8 @@
             if( msg_len < ext_offset + 2 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
 
@@ -1847,8 +1847,8 @@
                 msg_len != ext_offset + 2 + ext_len )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
         }
@@ -1864,8 +1864,8 @@
             unsigned int ext_size;
             if ( ext_len < 4 ) {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                               MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
             ext_id   = ( ( ext[0] <<  8 ) | ( ext[1] ) );
@@ -1874,8 +1874,8 @@
             if( ext_size + 4 > ext_len )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
             switch( ext_id )
@@ -2033,8 +2033,8 @@
             if( ext_len > 0 && ext_len < 4 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                         MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
         }
@@ -2055,8 +2055,8 @@
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) );
 
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                              MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK );
 
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
@@ -2099,8 +2099,8 @@
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV "
                                             "during renegotiation" ) );
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                    MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
             }
 #endif
@@ -2169,8 +2169,8 @@
 
     if( handshake_failure == 1 )
     {
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                            MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
     }
 
@@ -2229,15 +2229,15 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, "
                             "but none of them usable" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                          MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE );
     }
     else
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                           MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE );
         return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN );
     }
 
@@ -4024,8 +4024,8 @@
     if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY )
     {
         MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", *p, n );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                 MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY );
         return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY );
     }
 
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index fc7ece7..3e78e5d 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -75,6 +75,17 @@
 #endif
 }
 
+static void ssl_send_pending_fatal_alert( mbedtls_ssl_context *ssl )
+{
+    if( ssl->pending_fatal_alert_msg == MBEDTLS_SSL_ALERT_MSG_NONE )
+        return;
+
+    mbedtls_ssl_send_alert_message( ssl,
+                                    MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                                    ssl->pending_fatal_alert_msg );
+    ssl->pending_fatal_alert_msg = MBEDTLS_SSL_ALERT_MSG_NONE;
+}
+
 /*
  * Start a timer.
  * Passing millisecs = 0 cancels a running timer.
@@ -812,7 +823,9 @@
     (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 +837,10 @@
     ((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
      */
@@ -4708,8 +4725,8 @@
          * Section 4.1.2.7, that is, send alert only with TLS */
         if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
         {
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                    MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         }
 #endif /* MBEDTLS_SSL_PROTO_TLS */
 
@@ -5105,6 +5122,7 @@
                     if( ret != 0 )
                     {
                         MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_get_next_record" ), ret );
+                        ssl_send_pending_fatal_alert( ssl );
                         return( ret );
                     }
                 }
@@ -5833,8 +5851,7 @@
 #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
                     if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
                     {
-                        mbedtls_ssl_send_alert_message( ssl,
-                                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                        mbedtls_ssl_pend_fatal_alert( ssl,
                                 MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC );
                     }
 #endif
@@ -5870,8 +5887,7 @@
 #if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES)
             if( ret == MBEDTLS_ERR_SSL_INVALID_MAC )
             {
-                mbedtls_ssl_send_alert_message( ssl,
-                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
+                mbedtls_ssl_pend_fatal_alert( ssl,
                         MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC );
             }
 #endif
@@ -6033,8 +6049,8 @@
 }
 
 int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl,
-                            unsigned char level,
-                            unsigned char message )
+                                    unsigned char level,
+                                    unsigned char message )
 {
     int ret;
 
@@ -6308,8 +6324,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                            MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -6317,8 +6333,8 @@
         ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
@@ -6333,8 +6349,8 @@
         ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
     }
 
@@ -6347,9 +6363,8 @@
         /* Check that there's room for the next CRT's length fields. */
         if ( i + 3 > ssl->in_hslen ) {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl,
-                              MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                              MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
         /* In theory, the CRT can be up to 2**24 Bytes, but we don't support
@@ -6357,9 +6372,8 @@
         if( ssl->in_msg[i] != 0 )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl,
-                            MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                            MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
@@ -6371,9 +6385,8 @@
         if( n < 128 || i + n > ssl->in_hslen )
         {
             MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) );
-            mbedtls_ssl_send_alert_message( ssl,
-                                 MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                 MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                          MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
             return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
         }
 
@@ -6394,9 +6407,8 @@
                                               n ) != 0 )
             {
                 MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) );
-                mbedtls_ssl_send_alert_message( ssl,
-                                                MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                                MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
+                mbedtls_ssl_pend_fatal_alert( ssl,
+                                       MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED );
                 return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE );
             }
 
@@ -6432,7 +6444,7 @@
             default:
                 alert = MBEDTLS_SSL_ALERT_MSG_BAD_CERT;
             crt_parse_der_failed:
-                mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, alert );
+                mbedtls_ssl_pend_fatal_alert( ssl,  alert );
                 MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret );
                 return( ret );
         }
@@ -6666,8 +6678,7 @@
             alert = MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA;
         else
             alert = MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN;
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        alert );
+        mbedtls_ssl_pend_fatal_alert( ssl, alert );
     }
 
 #if defined(MBEDTLS_DEBUG_C)
@@ -6699,9 +6710,8 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
                                     sizeof( MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN ) ) );
-        mbedtls_ssl_send_alert_message( ssl,
-                                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
         return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
     }
@@ -6804,9 +6814,8 @@
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed",
                                     sizeof( mbedtls_x509_crt ) ) );
-        mbedtls_ssl_send_alert_message( ssl,
-                                        MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
         ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
         goto exit;
@@ -6937,8 +6946,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                             MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -6985,8 +6994,8 @@
         if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_INBOUND ) ) != 0 )
         {
             MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret );
-            mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                            MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+            mbedtls_ssl_pend_fatal_alert( ssl,
+                                  MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
             return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED );
         }
     }
@@ -7579,8 +7588,8 @@
     if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                               MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE );
         return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
     }
 
@@ -7596,8 +7605,8 @@
         ssl->in_hslen  != mbedtls_ssl_hs_hdr_len( ssl ) + hash_len )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
     }
 
@@ -7605,8 +7614,8 @@
                       buf, hash_len ) != 0 )
     {
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
         return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
     }
 
@@ -7983,6 +7992,8 @@
     if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
         goto error;
 
+    ssl->pending_fatal_alert_msg = MBEDTLS_SSL_ALERT_MSG_NONE;
+
     return( 0 );
 
 error:
@@ -9370,10 +9381,11 @@
  * 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;
@@ -9386,17 +9398,20 @@
 #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 );
+        }
     }
 
     /*
@@ -9562,12 +9577,24 @@
 }
 
 /*
- * Unserialize session, see mbedtls_ssl_session_save() for format.
+ * Public wrapper for ssl_session_save()
+ */
+int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
+                              unsigned char *buf,
+                              size_t buf_len,
+                              size_t *olen )
+{
+    return( ssl_session_save( session, 0, buf, buf_len, olen ) );
+}
+
+/*
+ * Deserialize session, see mbedtls_ssl_session_save() for format.
  *
  * This internal version is wrapped by a public function that cleans up in
- * case of error.
+ * case of error, and has an extra option omit_header.
  */
 static int ssl_session_load( mbedtls_ssl_session *session,
+                             unsigned char omit_header,
                              const unsigned char *buf,
                              size_t len )
 {
@@ -9583,19 +9610,22 @@
 #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
@@ -9802,13 +9832,13 @@
 }
 
 /*
- * Unserialize session: public wrapper for error cleaning
+ * Deserialize session: public wrapper for error cleaning
  */
 int mbedtls_ssl_session_load( mbedtls_ssl_session *session,
                               const unsigned char *buf,
                               size_t len )
 {
-    int ret = ssl_session_load( session, buf, len );
+    int ret = ssl_session_load( session, 0, buf, len );
 
     if( ret != 0 )
         mbedtls_ssl_session_free( session );
@@ -9835,6 +9865,7 @@
         ret = mbedtls_ssl_handshake_server_step( ssl );
 #endif
 
+    ssl_send_pending_fatal_alert( ssl );
     return( ret );
 }
 
@@ -10008,7 +10039,7 @@
 
     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 );
     }
@@ -10234,12 +10265,11 @@
     defined(MBEDTLS_SSL_PROTO_TLS1_2)
                 if( mbedtls_ssl_get_minor_ver( ssl ) >= MBEDTLS_SSL_MINOR_VERSION_1 )
                 {
-                    if( ( ret = mbedtls_ssl_send_alert_message( ssl,
-                                    MBEDTLS_SSL_ALERT_LEVEL_WARNING,
-                                    MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 )
-                    {
+                    ret = mbedtls_ssl_send_alert_message( ssl,
+                                             MBEDTLS_SSL_ALERT_LEVEL_WARNING,
+                                             MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION );
+                    if( ret != 0 )
                         return( ret );
-                    }
                 }
                 else
 #endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 ||
@@ -10716,39 +10746,616 @@
     mbedtls_platform_zeroize( session, sizeof( mbedtls_ssl_session ) );
 }
 
+#if defined(MBEDTLS_SSL_CONTEXT_SERIALIZATION)
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID 1u
+#else
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID 0u
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT 1u
+#else
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT 0u
+#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY 1u
+#else
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY 0u
+#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
+
+#if defined(MBEDTLS_SSL_ALPN)
+#define SSL_SERIALIZED_CONTEXT_CONFIG_ALPN 1u
+#else
+#define SSL_SERIALIZED_CONTEXT_CONFIG_ALPN 0u
+#endif /* MBEDTLS_SSL_ALPN */
+
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT    0
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT     1
+#define SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT      2
+#define SSL_SERIALIZED_CONTEXT_CONFIG_ALPN_BIT                  3
+
+#define SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG   \
+    ( (uint32_t) (                              \
+        ( SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID     << SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_CONNECTION_ID_BIT     ) | \
+        ( SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT      << SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_BADMAC_LIMIT_BIT      ) | \
+        ( SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY       << SSL_SERIALIZED_CONTEXT_CONFIG_DTLS_ANTI_REPLAY_BIT       ) | \
+        ( SSL_SERIALIZED_CONTEXT_CONFIG_ALPN                   << SSL_SERIALIZED_CONTEXT_CONFIG_ALPN_BIT                   ) | \
+        0u ) )
+
+static unsigned char ssl_serialized_context_header[] = {
+    MBEDTLS_VERSION_MAJOR,
+    MBEDTLS_VERSION_MINOR,
+    MBEDTLS_VERSION_PATCH,
+    ( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG >> 8 ) & 0xFF,
+    ( SSL_SERIALIZED_SESSION_CONFIG_BITFLAG >> 0 ) & 0xFF,
+    ( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >> 16 ) & 0xFF,
+    ( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >>  8 ) & 0xFF,
+    ( SSL_SERIALIZED_CONTEXT_CONFIG_BITFLAG >>  0 ) & 0xFF,
+};
+
 /*
  * Serialize a full SSL context
+ *
+ * The format of the serialized data is:
+ * (in the presentation language of TLS, RFC 8446 section 3)
+ *
+ *  // header
+ *  opaque mbedtls_version[3];   // major, minor, patch
+ *  opaque context_format[5];    // version-specific field determining
+ *                               // the format of the remaining
+ *                               // serialized data.
+ *  Note: When updating the format, remember to keep these
+ *        version+format bytes. (We may make their size part of the API.)
+ *
+ *  // session sub-structure
+ *  opaque session<1..2^32-1>;  // see mbedtls_ssl_session_save()
+ *  // transform sub-structure
+ *  uint8 random[64];           // ServerHello.random+ClientHello.random
+ *  uint8 in_cid<0..2^8-1>      // Connection ID: expected incoming value
+ *  uint8 out_cid<0..2^8-1>     // Connection ID: outgoing value to use
+ *  // fields from ssl_context
+ *  uint32 badmac_seen;         // DTLS: number of records with failing MAC
+ *  uint64 in_window_top;       // DTLS: last validated record seq_num
+ *  uint64 in_window;           // DTLS: bitmask for replay protection
+ *  uint8 disable_datagram_packing; // DTLS: only one record per datagram
+ *  uint64 cur_out_ctr;         // Record layer: outgoing sequence number
+ *  uint16 mtu;                 // DTLS: path mtu (max outgoing fragment size)
+ *  uint8 alpn_chosen<0..2^8-1> // ALPN: negotiated application protocol
+ *
+ * Note that many fields of the ssl_context or sub-structures are not
+ * serialized, as they fall in one of the following categories:
+ *
+ *  1. forced value (eg in_left must be 0)
+ *  2. pointer to dynamically-allocated memory (eg session, transform)
+ *  3. value can be re-derived from other data (eg session keys from MS)
+ *  4. value was temporary (eg content of input buffer)
+ *  5. value will be provided by the user again (eg I/O callbacks and context)
  */
 int mbedtls_ssl_context_save( mbedtls_ssl_context *ssl,
                               unsigned char *buf,
                               size_t buf_len,
                               size_t *olen )
 {
-    /* Unimplemented */
-    (void) ssl;
+    unsigned char *p = buf;
+    size_t used = 0;
+    size_t session_len;
+    int ret = 0;
 
-    if( buf != NULL )
-        memset( buf, 0, buf_len );
+    /*
+     * Enforce usage restrictions, see "return BAD_INPUT_DATA" in
+     * this function's documentation.
+     *
+     * These are due to assumptions/limitations in the implementation. Some of
+     * them are likely to stay (no handshake in progress) some might go away
+     * (only DTLS) but are currently used to simplify the implementation.
+     */
+    /* The initial handshake must be over */
+    if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    if( ssl->handshake != NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Double-check that sub-structures are indeed ready */
+    if( ssl->transform == NULL || ssl->session == NULL )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* There must be no pending incoming or outgoing data */
+    if( mbedtls_ssl_check_pending( ssl ) != 0 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    if( ssl->out_left != 0 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Protocol must be DLTS, not TLS */
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Version must be 1.2 */
+    if( mbedtls_ssl_get_major_ver( ssl ) != MBEDTLS_SSL_MAJOR_VERSION_3 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    if( mbedtls_ssl_get_minor_ver( ssl ) != MBEDTLS_SSL_MINOR_VERSION_3 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* We must be using an AEAD ciphersuite */
+    if( mbedtls_ssl_transform_uses_aead( ssl->transform ) != 1 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    /* Renegotiation must not be enabled */
+    if( mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
-    *olen = 0;
+    /*
+     * Version and format identifier
+     */
+    used += sizeof( ssl_serialized_context_header );
+
+    if( used <= buf_len )
+    {
+        memcpy( p, ssl_serialized_context_header,
+                sizeof( ssl_serialized_context_header ) );
+        p += sizeof( ssl_serialized_context_header );
+    }
+
+    /*
+     * Session (length + data)
+     */
+    ret = ssl_session_save( ssl->session, 1, NULL, 0, &session_len );
+    if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
+        return( ret );
+
+    used += 4 + session_len;
+    if( used <= buf_len )
+    {
+        *p++ = (unsigned char)( ( session_len >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( session_len >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( session_len >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( session_len       ) & 0xFF );
+
+        ret = ssl_session_save( ssl->session, 1,
+                                p, session_len, &session_len );
+        if( ret != 0 )
+            return( ret );
+
+        p += session_len;
+    }
+
+    /*
+     * Transform
+     */
+    used += sizeof( ssl->transform->randbytes );
+    if( used <= buf_len )
+    {
+        memcpy( p, ssl->transform->randbytes,
+           sizeof( ssl->transform->randbytes ) );
+        p += sizeof( ssl->transform->randbytes );
+    }
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    used += 2 + ssl->transform->in_cid_len + ssl->transform->out_cid_len;
+    if( used <= buf_len )
+    {
+        *p++ = ssl->transform->in_cid_len;
+        memcpy( p, ssl->transform->in_cid, ssl->transform->in_cid_len );
+        p += ssl->transform->in_cid_len;
+
+        *p++ = ssl->transform->out_cid_len;
+        memcpy( p, ssl->transform->out_cid, ssl->transform->out_cid_len );
+        p += ssl->transform->out_cid_len;
+    }
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+    /*
+     * Saved fields from top-level ssl_context structure
+     */
+#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
+    used += 4;
+    if( used <= buf_len )
+    {
+        *p++ = (unsigned char)( ( ssl->badmac_seen >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->badmac_seen >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->badmac_seen >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->badmac_seen       ) & 0xFF );
+    }
+#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+    used += 16;
+    if( used <= buf_len )
+    {
+        *p++ = (unsigned char)( ( ssl->in_window_top >> 56 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top >> 48 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top >> 40 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top >> 32 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window_top       ) & 0xFF );
+
+        *p++ = (unsigned char)( ( ssl->in_window >> 56 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window >> 48 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window >> 40 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window >> 32 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->in_window       ) & 0xFF );
+    }
+#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    used += 1;
+    if( used <= buf_len )
+    {
+        *p++ = ssl->disable_datagram_packing;
+    }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+    used += 8;
+    if( used <= buf_len )
+    {
+        memcpy( p, ssl->cur_out_ctr, 8 );
+        p += 8;
+    }
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    used += 2;
+    if( used <= buf_len )
+    {
+        *p++ = (unsigned char)( ( ssl->mtu >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( ssl->mtu       ) & 0xFF );
+    }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+#if defined(MBEDTLS_SSL_ALPN)
+    {
+        const uint8_t alpn_len = ssl->alpn_chosen
+                               ? (uint8_t) strlen( ssl->alpn_chosen )
+                               : 0;
+
+        used += 1 + alpn_len;
+        if( used <= buf_len )
+        {
+            *p++ = alpn_len;
+
+            if( ssl->alpn_chosen != NULL )
+            {
+                memcpy( p, ssl->alpn_chosen, alpn_len );
+                p += alpn_len;
+            }
+        }
+    }
+#endif /* MBEDTLS_SSL_ALPN */
+
+    /*
+     * Done
+     */
+    *olen = used;
+
+    if( used > buf_len )
+        return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+
+    MBEDTLS_SSL_DEBUG_BUF( 4, "saved context", buf, used );
+
+    return( ssl_session_reset_int( ssl, 0 ) );
+}
+
+/*
+ * Helper to get TLS 1.2 PRF from ciphersuite
+ * (Duplicates bits of logic from ssl_set_handshake_prfs().)
+ */
+typedef int (*tls_prf_fn)( const unsigned char *secret, size_t slen,
+                           const char *label,
+                           const unsigned char *random, size_t rlen,
+                           unsigned char *dstbuf, size_t dlen );
+static tls_prf_fn ssl_tls12prf_from_cs( int ciphersuite_id )
+{
+    mbedtls_ssl_ciphersuite_handle_t const info =
+        mbedtls_ssl_ciphersuite_from_id( ciphersuite_id );
+    const mbedtls_md_type_t hash = mbedtls_ssl_suite_get_mac( info );
+
+#if defined(MBEDTLS_SHA512_C)
+    if( hash == MBEDTLS_MD_SHA384 )
+        return( tls_prf_sha384 );
+#else
+    (void) hash;
+#endif
+    return( tls_prf_sha256 );
+}
+
+/*
+ * Deserialize context, see mbedtls_ssl_context_save() for format.
+ *
+ * This internal version is wrapped by a public function that cleans up in
+ * case of error.
+ */
+static int ssl_context_load( mbedtls_ssl_context *ssl,
+                             const unsigned char *buf,
+                             size_t len )
+{
+    const unsigned char *p = buf;
+    const unsigned char * const end = buf + len;
+    size_t session_len;
+    int ret;
+
+    /*
+     * The context should have been freshly setup or reset.
+     * Give the user an error in case of obvious misuse.
+     * (Checking session is useful because it won't be NULL if we're
+     * renegotiating, or if the user mistakenly loaded a session first.)
+     */
+    if( ssl->state != MBEDTLS_SSL_HELLO_REQUEST ||
+        ssl->session != NULL )
+    {
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    /*
+     * We can't check that the config matches the initial one, but we can at
+     * least check it matches the requirements for serializing.
+     */
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) ||
+        mbedtls_ssl_conf_get_max_major_ver( ssl->conf ) <
+            MBEDTLS_SSL_MAJOR_VERSION_3 ||
+        mbedtls_ssl_conf_get_min_major_ver( ssl->conf ) >
+            MBEDTLS_SSL_MAJOR_VERSION_3 ||
+        mbedtls_ssl_conf_get_max_minor_ver( ssl->conf ) <
+            MBEDTLS_SSL_MINOR_VERSION_3 ||
+        mbedtls_ssl_conf_get_min_minor_ver( ssl->conf ) >
+            MBEDTLS_SSL_MINOR_VERSION_3 ||
+        mbedtls_ssl_conf_is_renegotiation_enabled( ssl->conf ) )
+    {
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+    }
+
+    MBEDTLS_SSL_DEBUG_BUF( 4, "context to load", buf, len );
+
+    /*
+     * Check version identifier
+     */
+    if( (size_t)( end - p ) < sizeof( ssl_serialized_context_header ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    if( memcmp( p, ssl_serialized_context_header,
+                sizeof( ssl_serialized_context_header ) ) != 0 )
+    {
+        return( MBEDTLS_ERR_SSL_VERSION_MISMATCH );
+    }
+    p += sizeof( ssl_serialized_context_header );
+
+    /*
+     * Session
+     */
+    if( (size_t)( end - p ) < 4 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session_len = ( (size_t) p[0] << 24 ) |
+                  ( (size_t) p[1] << 16 ) |
+                  ( (size_t) p[2] <<  8 ) |
+                  ( (size_t) p[3]       );
+    p += 4;
+
+    /* This has been allocated by ssl_handshake_init(), called by
+     * by either ssl_session_reset_int() or mbedtls_ssl_setup(). */
+    ssl->session = ssl->session_negotiate;
+    ssl->session_in = ssl->session;
+    ssl->session_out = ssl->session;
+    ssl->session_negotiate = NULL;
+
+    if( (size_t)( end - p ) < session_len )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ret = ssl_session_load( ssl->session, 1, p, session_len );
+    if( ret != 0 )
+    {
+        mbedtls_ssl_session_free( ssl->session );
+        return( ret );
+    }
+
+    p += session_len;
+
+    /*
+     * Transform
+     */
+
+    /* This has been allocated by ssl_handshake_init(), called by
+     * by either ssl_session_reset_int() or mbedtls_ssl_setup(). */
+    ssl->transform = ssl->transform_negotiate;
+    ssl->transform_in = ssl->transform;
+    ssl->transform_out = ssl->transform;
+    ssl->transform_negotiate = NULL;
+
+    /* Read random bytes and populate structure */
+    if( (size_t)( end - p ) < sizeof( ssl->transform->randbytes ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ret = ssl_populate_transform( ssl->transform,
+                  mbedtls_ssl_session_get_ciphersuite( ssl->session ),
+                  ssl->session->master,
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+                  ssl->session->encrypt_then_mac,
+#endif
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+                  ssl->session->trunc_hmac,
+#endif
+#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
+#if defined(MBEDTLS_ZLIB_SUPPORT)
+                  ssl->session->compression,
+#endif
+                  ssl_tls12prf_from_cs(
+                      mbedtls_ssl_session_get_ciphersuite( ssl->session) ),
+                  p, /* currently pointing to randbytes */
+                  MBEDTLS_SSL_MINOR_VERSION_3, /* (D)TLS 1.2 is forced */
+                  mbedtls_ssl_conf_get_endpoint( ssl->conf ),
+                  ssl );
+    if( ret != 0 )
+        return( ret );
+
+    p += sizeof( ssl->transform->randbytes );
+
+#if defined(MBEDTLS_SSL_DTLS_CONNECTION_ID)
+    /* Read connection IDs and store them */
+    if( (size_t)( end - p ) < 1 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->transform->in_cid_len = *p++;
+
+    if( (size_t)( end - p ) < ssl->transform->in_cid_len + 1u )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    memcpy( ssl->transform->in_cid, p, ssl->transform->in_cid_len );
+    p += ssl->transform->in_cid_len;
+
+    ssl->transform->out_cid_len = *p++;
+
+    if( (size_t)( end - p ) < ssl->transform->out_cid_len )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    memcpy( ssl->transform->out_cid, p, ssl->transform->out_cid_len );
+    p += ssl->transform->out_cid_len;
+#endif /* MBEDTLS_SSL_DTLS_CONNECTION_ID */
+
+    /*
+     * Saved fields from top-level ssl_context structure
+     */
+#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
+    if( (size_t)( end - p ) < 4 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->badmac_seen = ( (uint32_t) p[0] << 24 ) |
+                       ( (uint32_t) p[1] << 16 ) |
+                       ( (uint32_t) p[2] <<  8 ) |
+                       ( (uint32_t) p[3]       );
+    p += 4;
+#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
+
+#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
+    if( (size_t)( end - p ) < 16 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->in_window_top = ( (uint64_t) p[0] << 56 ) |
+                         ( (uint64_t) p[1] << 48 ) |
+                         ( (uint64_t) p[2] << 40 ) |
+                         ( (uint64_t) p[3] << 32 ) |
+                         ( (uint64_t) p[4] << 24 ) |
+                         ( (uint64_t) p[5] << 16 ) |
+                         ( (uint64_t) p[6] <<  8 ) |
+                         ( (uint64_t) p[7]       );
+    p += 8;
+
+    ssl->in_window = ( (uint64_t) p[0] << 56 ) |
+                     ( (uint64_t) p[1] << 48 ) |
+                     ( (uint64_t) p[2] << 40 ) |
+                     ( (uint64_t) p[3] << 32 ) |
+                     ( (uint64_t) p[4] << 24 ) |
+                     ( (uint64_t) p[5] << 16 ) |
+                     ( (uint64_t) p[6] <<  8 ) |
+                     ( (uint64_t) p[7]       );
+    p += 8;
+#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( (size_t)( end - p ) < 1 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->disable_datagram_packing = *p++;
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+    if( (size_t)( end - p ) < 8 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    memcpy( ssl->cur_out_ctr, p, 8 );
+    p += 8;
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( (size_t)( end - p ) < 2 )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    ssl->mtu = ( p[0] << 8 ) | p[1];
+    p += 2;
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+#if defined(MBEDTLS_SSL_ALPN)
+    {
+        uint8_t alpn_len;
+        const char **cur;
+
+        if( (size_t)( end - p ) < 1 )
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+        alpn_len = *p++;
+
+        if( alpn_len != 0 && ssl->conf->alpn_list != NULL )
+        {
+            /* alpn_chosen should point to an item in the configured list */
+            for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ )
+            {
+                if( strlen( *cur ) == alpn_len &&
+                    memcmp( p, cur, alpn_len ) == 0 )
+                {
+                    ssl->alpn_chosen = *cur;
+                    break;
+                }
+            }
+        }
+
+        /* can only happen on conf mismatch */
+        if( alpn_len != 0 && ssl->alpn_chosen == NULL )
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+        p += alpn_len;
+    }
+#endif /* MBEDTLS_SSL_ALPN */
+
+    /*
+     * Forced fields from top-level ssl_context structure
+     *
+     * Most of them already set to the correct value by mbedtls_ssl_init() and
+     * mbedtls_ssl_reset(), so we only need to set the remaining ones.
+     */
+    ssl->state = MBEDTLS_SSL_HANDSHAKE_OVER;
+
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MAJOR_VER)
+    ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3;
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MAJOR_VER */
+#if !defined(MBEDTLS_SSL_CONF_FIXED_MINOR_VER)
+    ssl->minor_ver = MBEDTLS_SSL_MINOR_VERSION_3;
+#endif /* !MBEDTLS_SSL_CONF_FIXED_MINOR_VER */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    ssl->in_epoch = 1;
+#endif
+
+    /* mbedtls_ssl_reset() leaves the handshake sub-structure allocated,
+     * which we don't want - otherwise we'd end up freeing the wrong transform
+     * by calling ssl_handshake_wrapup_free_hs_transform() inappropriately. */
+    if( ssl->handshake != NULL )
+    {
+        mbedtls_ssl_handshake_free( ssl );
+        mbedtls_free( ssl->handshake );
+        ssl->handshake = NULL;
+    }
+
+    /*
+     * Done - should have consumed entire buffer
+     */
+    if( p != end )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
     return( 0 );
 }
 
 /*
- * Deserialize a full SSL context
+ * Deserialize context: public wrapper for error cleaning
  */
-int mbedtls_ssl_context_load( mbedtls_ssl_context *ssl,
+int mbedtls_ssl_context_load( mbedtls_ssl_context *context,
                               const unsigned char *buf,
                               size_t len )
 {
-    /* Unimplemented */
-    (void) ssl;
-    (void) buf;
-    (void) len;
+    int ret = ssl_context_load( context, buf, len );
 
-    return( 0 );
+    if( ret != 0 )
+        mbedtls_ssl_free( context );
+
+    return( ret );
 }
+#endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 
 /*
  * Free an SSL context
@@ -11520,8 +12127,8 @@
     mbedtls_sha1_free( &mbedtls_sha1 );
 
     if( ret != 0 )
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
     return( ret );
 
@@ -11580,8 +12187,8 @@
     mbedtls_md_free( &ctx );
 
     if( ret != 0 )
-        mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
-                                        MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
+        mbedtls_ssl_pend_fatal_alert( ssl,
+                                      MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR );
 
     return( ret );
 }
diff --git a/library/version_features.c b/library/version_features.c
index 3753864..51ce780 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -564,6 +564,12 @@
 #if defined(MBEDTLS_X509_REMOVE_INFO)
     "MBEDTLS_X509_REMOVE_INFO",
 #endif /* MBEDTLS_X509_REMOVE_INFO */
+#if defined(MBEDTLS_X509_CRT_REMOVE_TIME)
+    "MBEDTLS_X509_CRT_REMOVE_TIME",
+#endif /* MBEDTLS_X509_CRT_REMOVE_TIME */
+#if defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
+    "MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID",
+#endif /* MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
 #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
     "MBEDTLS_X509_RSASSA_PSS_SUPPORT",
 #endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 24ef0e6..4e5ff43 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -223,16 +223,22 @@
     frame->version = crt->version;
     frame->sig_md = crt->sig_md;
     frame->sig_pk = crt->sig_pk;
+
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
     frame->valid_from = crt->valid_from;
     frame->valid_to = crt->valid_to;
+#endif /* !MBEDTLS_X509_CRT_REMOVE_TIME */
+
     x509_buf_to_buf_raw( &frame->raw, &crt->raw );
     x509_buf_to_buf_raw( &frame->tbs, &crt->tbs );
     x509_buf_to_buf_raw( &frame->serial, &crt->serial );
     x509_buf_to_buf_raw( &frame->pubkey_raw, &crt->pk_raw );
     x509_buf_to_buf_raw( &frame->issuer_raw, &crt->issuer_raw );
     x509_buf_to_buf_raw( &frame->subject_raw, &crt->subject_raw );
+#if !defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
     x509_buf_to_buf_raw( &frame->subject_id, &crt->subject_id );
     x509_buf_to_buf_raw( &frame->issuer_id, &crt->issuer_id );
+#endif /* !MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
     x509_buf_to_buf_raw( &frame->sig, &crt->sig );
     x509_buf_to_buf_raw( &frame->v3_ext, &crt->v3_ext );
 
@@ -694,6 +700,7 @@
     return( 0 );
 }
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
 /*
  *  Validity ::= SEQUENCE {
  *       notBefore      Time,
@@ -725,7 +732,28 @@
 
     return( 0 );
 }
+#else /* !MBEDTLS_X509_CRT_REMOVE_TIME */
+static int x509_skip_dates( unsigned char **p,
+                           const unsigned char *end )
+{
+    int ret;
+    size_t len;
 
+    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+            MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+        return( MBEDTLS_ERR_X509_INVALID_DATE + ret );
+
+    end = *p + len;
+
+    if( *p != end )
+        return( MBEDTLS_ERR_X509_INVALID_DATE +
+                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+#endif /* MBEDTLS_X509_CRT_REMOVE_TIME */
+
+#if !defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
 /*
  * X.509 v2/v3 unique identifier (not parsed)
  */
@@ -752,6 +780,30 @@
 
     return( 0 );
 }
+#else /* !MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
+static int x509_skip_uid( unsigned char **p,
+                          const unsigned char *end,
+                          int n )
+{
+    int ret;
+    size_t len;
+
+    if( *p == end )
+        return( 0 );
+
+    if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+            MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 )
+    {
+        if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG )
+            return( 0 );
+
+        return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret );
+    }
+
+    *p += len;
+    return( 0 );
+}
+#endif /* MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
 
 static int x509_get_basic_constraints( unsigned char **p,
                                        const unsigned char *end,
@@ -1293,9 +1345,15 @@
     /*
      * Validity ::= SEQUENCE { ...
      */
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
     ret = x509_get_dates( &p, end, &frame->valid_from, &frame->valid_to );
     if( ret != 0 )
         return( ret );
+#else /* !MBEDTLS_X509_CRT_REMOVE_TIME */
+    ret = x509_skip_dates( &p, end );
+    if( ret != 0 )
+        return( ret );
+#endif /* MBEDTLS_X509_CRT_REMOVE_TIME */
 
     /*
      * subject              Name
@@ -1334,6 +1392,7 @@
 
     if( frame->version != 1 )
     {
+#if !defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
         /*
          *  issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
          *                       -- If present, version shall be v2 or v3
@@ -1349,6 +1408,14 @@
         ret = x509_get_uid( &p, end, &frame->subject_id, 2 /* implicit tag */ );
         if( ret != 0 )
             return( ret );
+#else /* !MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
+        ret = x509_skip_uid( &p, end, 1 /* implicit tag */ );
+        if( ret != 0 )
+            return( ret );
+        ret = x509_skip_uid( &p, end, 2 /* implicit tag */ );
+        if( ret != 0 )
+            return( ret );
+#endif /* MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
     }
 
     /*
@@ -1531,13 +1598,19 @@
     x509_buf_raw_to_buf( &crt->serial, &frame->serial );
     x509_buf_raw_to_buf( &crt->issuer_raw, &frame->issuer_raw );
     x509_buf_raw_to_buf( &crt->subject_raw, &frame->subject_raw );
+#if !defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
     x509_buf_raw_to_buf( &crt->issuer_id, &frame->issuer_id );
     x509_buf_raw_to_buf( &crt->subject_id, &frame->subject_id );
+#endif /* !MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
     x509_buf_raw_to_buf( &crt->pk_raw, &frame->pubkey_raw );
     x509_buf_raw_to_buf( &crt->sig, &frame->sig );
     x509_buf_raw_to_buf( &crt->v3_ext, &frame->v3_ext );
+
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
     crt->valid_from = frame->valid_from;
     crt->valid_to = frame->valid_to;
+#endif /* !MBEDTLS_X509_CRT_REMOVE_TIME */
+
     crt->version      = frame->version;
     crt->ca_istrue    = frame->ca_istrue;
     crt->max_pathlen  = frame->max_pathlen;
@@ -2270,6 +2343,7 @@
     ret = mbedtls_x509_dn_gets( p, n, subject );
     MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
     ret = mbedtls_snprintf( p, n, "\n%sissued  on        : " \
                    "%04d-%02d-%02d %02d:%02d:%02d", prefix,
                    frame.valid_from.year, frame.valid_from.mon,
@@ -2283,6 +2357,7 @@
                    frame.valid_to.day,  frame.valid_to.hour,
                    frame.valid_to.min,  frame.valid_to.sec );
     MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
+#endif /* MBEDTLS_X509_CRT_REMOVE_TIME */
 
     ret = mbedtls_snprintf( p, n, "\n%ssigned using      : ", prefix );
     MBEDTLS_X509_SAFE_SNPRINTF_WITH_CLEANUP;
@@ -2897,11 +2972,13 @@
             if( ret != 0 )
                 return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
             if( !mbedtls_x509_time_is_past( &parent->valid_to ) &&
                 !mbedtls_x509_time_is_future( &parent->valid_from ) )
             {
                 parent_valid = 1;
             }
+#endif /* !MBEDTLS_X509_CRT_REMOVE_TIME */
 
             /* basic parenting skills (name, CA bit, key usage) */
             if( x509_crt_check_parent( child_sig, parent, top ) == 0 )
@@ -3198,11 +3275,13 @@
                 if( ret != 0 )
                     return( MBEDTLS_ERR_X509_FATAL_ERROR );
 
+#if !defined(MBEDTLS_X509_CRT_REMOVE_TIME)
                 /* Check time-validity (all certificates) */
                 if( mbedtls_x509_time_is_past( &child->valid_to ) )
                     *flags |= MBEDTLS_X509_BADCERT_EXPIRED;
                 if( mbedtls_x509_time_is_future( &child->valid_from ) )
                     *flags |= MBEDTLS_X509_BADCERT_FUTURE;
+#endif /* !MBEDTLS_X509_CRT_REMOVE_TIME */
 
                 /* Stop here for trusted roots (but not for trusted EE certs) */
                 if( child_is_trusted )
diff --git a/programs/ssl/query_config.c b/programs/ssl/query_config.c
index 6766314..0f7251d 100644
--- a/programs/ssl/query_config.c
+++ b/programs/ssl/query_config.c
@@ -1546,6 +1546,22 @@
     }
 #endif /* MBEDTLS_X509_REMOVE_INFO */
 
+#if defined(MBEDTLS_X509_CRT_REMOVE_TIME)
+    if( strcmp( "MBEDTLS_X509_CRT_REMOVE_TIME", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CRT_REMOVE_TIME );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CRT_REMOVE_TIME */
+
+#if defined(MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID)
+    if( strcmp( "MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID", config ) == 0 )
+    {
+        MACRO_EXPANSION_TO_STR( MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID );
+        return( 0 );
+    }
+#endif /* MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID */
+
 #if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT)
     if( strcmp( "MBEDTLS_X509_RSASSA_PSS_SUPPORT", config ) == 0 )
     {
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index bb84207..f0de381 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -807,6 +807,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
 
     /*
      * Make sure memory references are valid.
@@ -2493,16 +2497,11 @@
     if( opt.serialize != 0 )
     {
         size_t buf_len;
-        unsigned char *context_buf = NULL;
 
-        opt.serialize = 0;
-        mbedtls_printf( " Serializing live connection..." );
+        mbedtls_printf( "  . Serializing live connection..." );
 
         ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
-
-        /* Allow stub implementation returning 0 for now */
-        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL &&
-            ret != 0 )
+        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
@@ -2517,18 +2516,29 @@
 
             goto exit;
         }
+        context_buf_len = buf_len;
 
         if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
                                               buf_len, &buf_len ) ) != 0 )
         {
-            mbedtls_printf( "failed\n  ! mbedtls_ssl_context_save returned "
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
 
             goto exit;
         }
 
+        mbedtls_printf( " ok\n" );
+
+        if( opt.serialize == 1 )
+        {
+            /* nothing to do here, done by context_save() already */
+            mbedtls_printf( "  . Context has been reset... ok" );
+        }
+
         if( opt.serialize == 2 )
         {
+            mbedtls_printf( "  . Freeing and reinitializing context..." );
+
             mbedtls_ssl_free( &ssl );
 
             mbedtls_ssl_init( &ssl );
@@ -2536,7 +2546,7 @@
             if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
             {
                 mbedtls_printf( " failed\n  ! mbedtls_ssl_setup returned "
-                                " -0x%x\n\n", -ret );
+                                "-0x%x\n\n", -ret );
                 goto exit;
             }
 
@@ -2544,26 +2554,25 @@
                 mbedtls_ssl_set_bio( &ssl, &server_fd, my_send, my_recv,
                                      NULL );
             else
-                mbedtls_ssl_set_bio( &ssl, &server_fd,
-                            mbedtls_net_send, mbedtls_net_recv,
+                mbedtls_ssl_set_bio( &ssl, &server_fd, mbedtls_net_send,
+                            mbedtls_net_recv,
                             opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
 #if defined(MBEDTLS_TIMING_C)
-            if( opt.nbio != 0 && opt.read_timeout != 0 )
-            {
 #if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
     !defined(MBEDTLS_SSL_CONF_GET_TIMER)
-                mbedtls_ssl_set_timer_cb( &ssl, &timer,
-                                          mbedtls_timing_set_delay,
-                                          mbedtls_timing_get_delay );
+            mbedtls_ssl_set_timer_cb( &ssl, &timer,
+                                      mbedtls_timing_set_delay,
+                                      mbedtls_timing_get_delay );
 #else
-                mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+            mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
 #endif
-            }
 #endif /* MBEDTLS_TIMING_C */
+
+            mbedtls_printf( " ok\n" );
         }
 
-        mbedtls_printf( " Deserializing connection..." );
+        mbedtls_printf( "  . Deserializing connection..." );
 
         if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
                                               buf_len ) ) != 0 )
@@ -2573,6 +2582,12 @@
 
             goto exit;
         }
+
+        mbedtls_free( context_buf );
+        context_buf = NULL;
+        context_buf_len = 0;
+
+        mbedtls_printf( " ok\n" );
     }
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 
@@ -2711,6 +2726,11 @@
     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 42b9773..747523b 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -1443,6 +1443,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;
@@ -3508,16 +3512,11 @@
     if( opt.serialize != 0 )
     {
         size_t buf_len;
-        unsigned char *context_buf = NULL;
 
-        opt.serialize = 0;
-        mbedtls_printf( " Serializing live connection..." );
+        mbedtls_printf( "  . Serializing live connection..." );
 
         ret = mbedtls_ssl_context_save( &ssl, NULL, 0, &buf_len );
-
-        /* Allow stub implementation returning 0 for now */
-        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL &&
-            ret != 0 )
+        if( ret != MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL )
         {
             mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
@@ -3532,18 +3531,44 @@
 
             goto exit;
         }
+        context_buf_len = buf_len;
 
         if( ( ret = mbedtls_ssl_context_save( &ssl, context_buf,
                                               buf_len, &buf_len ) ) != 0 )
         {
-            mbedtls_printf( "failed\n  ! mbedtls_ssl_context_save returned "
+            mbedtls_printf( " failed\n  ! mbedtls_ssl_context_save returned "
                             "-0x%x\n\n", -ret );
 
             goto exit;
         }
 
+        mbedtls_printf( " ok\n" );
+
+        /*
+         * This simulates a workflow where you have a long-lived server
+         * instance, potentially with a pool of ssl_context objects, and you
+         * just want to re-use one while the connection is inactive: in that
+         * case you can just reset() it, and then it's ready to receive
+         * serialized data from another connection (or the same here).
+         */
+        if( opt.serialize == 1 )
+        {
+            /* nothing to do here, done by context_save() already */
+            mbedtls_printf( "  . Context has been reset... ok" );
+        }
+
+        /*
+         * This simulates a workflow where you have one server instance per
+         * connection, and want to release it entire when the connection is
+         * inactive, and spawn it again when needed again - this would happen
+         * between ssl_free() and ssl_init() below, together with any other
+         * teardown/startup code needed - for example, preparing the
+         * ssl_config again (see section 3 "setup stuff" in this file).
+         */
         if( opt.serialize == 2 )
         {
+            mbedtls_printf( "  . Freeing and reinitializing context..." );
+
             mbedtls_ssl_free( &ssl );
 
             mbedtls_ssl_init( &ssl );
@@ -3555,6 +3580,12 @@
                 goto exit;
             }
 
+            /*
+             * This illustrates the minimum amount of things you need to set
+             * up, however you could set up much more if desired, for example
+             * if you want to share your set up code between the case of
+             * establishing a new connection and this case.
+             */
             if( opt.nbio == 2 )
                 mbedtls_ssl_set_bio( &ssl, &client_fd, my_send, my_recv,
                                      NULL );
@@ -3564,21 +3595,20 @@
                             opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
 #if defined(MBEDTLS_TIMING_C)
-            if( opt.nbio != 0 && opt.read_timeout != 0 )
-            {
 #if !defined(MBEDTLS_SSL_CONF_SET_TIMER) && \
     !defined(MBEDTLS_SSL_CONF_GET_TIMER)
-                mbedtls_ssl_set_timer_cb( &ssl, &timer,
-                                          mbedtls_timing_set_delay,
-                                          mbedtls_timing_get_delay );
+            mbedtls_ssl_set_timer_cb( &ssl, &timer,
+                                      mbedtls_timing_set_delay,
+                                      mbedtls_timing_get_delay );
 #else
-                mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
+            mbedtls_ssl_set_timer_cb_ctx( &ssl, &timer );
 #endif
-            }
 #endif /* MBEDTLS_TIMING_C */
+
+            mbedtls_printf( " ok\n" );
         }
 
-        mbedtls_printf( " Deserializing connection..." );
+        mbedtls_printf( "  . Deserializing connection..." );
 
         if( ( ret = mbedtls_ssl_context_load( &ssl, context_buf,
                                               buf_len ) ) != 0 )
@@ -3588,6 +3618,12 @@
 
             goto exit;
         }
+
+        mbedtls_free( context_buf );
+        context_buf = NULL;
+        context_buf_len = 0;
+
+        mbedtls_printf( " ok\n" );
     }
 #endif /* MBEDTLS_SSL_CONTEXT_SERIALIZATION */
 
@@ -3679,6 +3715,12 @@
 
     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/scripts/config.pl b/scripts/config.pl
index 1c7c736..e4648de 100755
--- a/scripts/config.pl
+++ b/scripts/config.pl
@@ -39,6 +39,8 @@
 #   MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
 #       - this could be enabled if the respective tests were adapted
 #   MBEDTLS_X509_REMOVE_INFO
+#   MBEDTLS_X509_CRT_REMOVE_TIME
+#   MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID
 #   MBEDTLS_ZLIB_SUPPORT
 #   MBEDTLS_PKCS11_C
 #   and any symbol beginning _ALT
@@ -102,6 +104,8 @@
 MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
 MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
 MBEDTLS_X509_REMOVE_INFO
+MBEDTLS_X509_CRT_REMOVE_TIME
+MBEDTLS_X509_CRT_REMOVE_SUBJECT_ISSUER_ID
 MBEDTLS_ZLIB_SUPPORT
 MBEDTLS_PKCS11_C
 MBEDTLS_NO_UDBL_DIVISION
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 56db054..1ea58df 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -1322,56 +1322,50 @@
 
 # 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..."