diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 4ad49f19f..876457c4f 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -8779,11 +8779,23 @@ const mbedtls_ssl_session *mbedtls_ssl_get_session_pointer( const mbedtls_ssl_co
  * Serialize a session in the following format:
  * (in the presentation language of TLS, RFC 8446 section 3)
  *
- *  opaque session_struct[n];       // n = sizeof(mbedtls_ssl_session)
- *  opaque peer_cert<0..2^24-1>;    // 0 means no peer cert
- *  opaque ticket<0..2^24-1>;       // 0 means no ticket
+ *  uint64 start_time;
+ *  uint8 ciphersuite[2];           // defined by the standard
+ *  uint8 compression;              // 0 or 1
+ *  uint8 session_id_len;           // at most 32
+ *  opaque session_id[32];
+ *  opaque master[48];              // fixed length in the standard
+ *  uint32 verify_result;
+ *  opaque peer_cert<0..2^24-1>;    // length 0 means no peer cert
+ *  opaque ticket<0..2^24-1>;       // length 0 means no ticket
+ *  uint32 ticket_lifetime;
+ *  uint8 mfl_code;                 // up to 255 according to standard
+ *  uint8 trunc_hmac;               // 0 or 1
+ *  uint8 encrypt_then_mac;         // 0 or 1
  *
- * Only the peer's certificate is saved, not the whole chain.
+ * The order is the same as in the definition of the structure, except
+ * verify_result is put before peer_cert so that all mandatory fields come
+ * together in one block.
  */
 int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
                               unsigned char *buf,
@@ -8792,23 +8804,66 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
 {
     unsigned char *p = buf;
     size_t used = 0;
+#if defined(MBEDTLS_HAVE_TIME)
+    uint64_t start;
+#endif
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
     size_t cert_len;
-#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#endif
 
     /*
-     * Shallow copy of the session structure
+     * Time
      */
-    used += sizeof( mbedtls_ssl_session );
+#if defined(MBEDTLS_HAVE_TIME)
+    used += 8;
 
     if( used <= buf_len )
     {
-        memcpy( p, session, sizeof( mbedtls_ssl_session ) );
-        p += sizeof( mbedtls_ssl_session );
+        start = (uint64_t) session->start;
+
+        *p++ = (unsigned char)( ( start >> 56 ) & 0xFF );
+        *p++ = (unsigned char)( ( start >> 48 ) & 0xFF );
+        *p++ = (unsigned char)( ( start >> 40 ) & 0xFF );
+        *p++ = (unsigned char)( ( start >> 32 ) & 0xFF );
+        *p++ = (unsigned char)( ( start >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( start >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( start >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( start       ) & 0xFF );
+    }
+#endif /* MBEDTLS_HAVE_TIME */
+
+    /*
+     * Basic mandatory fields
+     */
+    used += 2   /* ciphersuite */
+          + 1   /* compression */
+          + 1   /* id_len */
+          + sizeof( session->id )
+          + sizeof( session->master )
+          + 4;  /* verify_result */
+
+    if( used <= buf_len )
+    {
+        *p++ = (unsigned char)( ( session->ciphersuite >> 8 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->ciphersuite      ) & 0xFF );
+
+        *p++ = (unsigned char)( session->compression & 0xFF );
+
+        *p++ = (unsigned char)( session->id_len & 0xFF );
+        memcpy( p, session->id, 32 );
+        p += 32;
+
+        memcpy( p, session->master, 48 );
+        p += 48;
+
+        *p++ = (unsigned char)( ( session->verify_result >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->verify_result >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->verify_result >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->verify_result       ) & 0xFF );
     }
 
     /*
-     * Copy of the peer's end-entity certificate
+     * Peer's end-entity certificate
      */
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
     if( session->peer_cert == NULL )
@@ -8833,10 +8888,10 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     /*
-     * Copy of the session ticket if any
+     * Session ticket if any, plus associated data
      */
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
-    used += 3 + session->ticket_len;
+    used += 3 + session->ticket_len + 4; /* len + ticket + lifetime */
 
     if( used <= buf_len )
     {
@@ -8849,9 +8904,38 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
             memcpy( p, session->ticket, session->ticket_len );
             p += session->ticket_len;
         }
+
+        *p++ = (unsigned char)( ( session->ticket_lifetime >> 24 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->ticket_lifetime >> 16 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->ticket_lifetime >>  8 ) & 0xFF );
+        *p++ = (unsigned char)( ( session->ticket_lifetime       ) & 0xFF );
     }
 #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
 
+    /*
+     * Misc extension-related info
+     */
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+    used += 1;
+
+    if( used <= buf_len )
+        *p++ = session->mfl_code;
+#endif
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+    used += 1;
+
+    if( used <= buf_len )
+        *p++ = (unsigned char)( ( session->trunc_hmac ) & 0xFF );
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    used += 1;
+
+    if( used <= buf_len )
+        *p++ = (unsigned char)( ( session->encrypt_then_mac ) & 0xFF );
+#endif
+
     /* Done */
     *olen = used;
 
@@ -8862,7 +8946,7 @@ int mbedtls_ssl_session_save( const mbedtls_ssl_session *session,
 }
 
 /*
- * Unserialize session, see mbedtls_ssl_session_save().
+ * Unserialize session, see mbedtls_ssl_session_save() for format.
  *
  * This internal version is wrapped by a public function that cleans up in
  * case of error.
@@ -8873,18 +8957,56 @@ static int ssl_session_load( mbedtls_ssl_session *session,
 {
     const unsigned char *p = buf;
     const unsigned char * const end = buf + len;
+#if defined(MBEDTLS_HAVE_TIME)
+    uint64_t start;
+#endif
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
     size_t cert_len;
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     /*
-     * Shallow session structure
+     * Time
      */
-    if( sizeof( mbedtls_ssl_session ) > (size_t)( end - p ) )
+#if defined(MBEDTLS_HAVE_TIME)
+    if( 8 > (size_t)( end - p ) )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
 
-    memcpy( session, p, sizeof( mbedtls_ssl_session ) );
-    p += sizeof( mbedtls_ssl_session );
+    start = ( (uint64_t) p[0] << 56 ) |
+            ( (uint64_t) p[1] << 48 ) |
+            ( (uint64_t) p[2] << 40 ) |
+            ( (uint64_t) p[3] << 32 ) |
+            ( (uint64_t) p[4] << 24 ) |
+            ( (uint64_t) p[5] << 16 ) |
+            ( (uint64_t) p[6] <<  8 ) |
+            ( (uint64_t) p[7]       );
+    p += 8;
+
+    session->start = (time_t) start;
+#endif /* MBEDTLS_HAVE_TIME */
+
+    /*
+     * Basic mandatory fields
+     */
+    if( 2 + 1 + 1 + 32 + 48 + 4 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session->ciphersuite = ( p[0] << 8 ) | p[1];
+    p += 2;
+
+    session->compression = *p++;
+
+    session->id_len = *p++;
+    memcpy( session->id, p, 32 );
+    p += 32;
+
+    memcpy( session->master, p, 48 );
+    p += 48;
+
+    session->verify_result = ( (uint32_t) p[0] << 24 ) |
+                             ( (uint32_t) p[1] << 16 ) |
+                             ( (uint32_t) p[2] <<  8 ) |
+                             ( (uint32_t) p[3]       );
+    p += 4;
 
     /* Immediately clear invalid pointer values that have been read, in case
      * we exit early before we replaced them with valid ones. */
@@ -8937,7 +9059,7 @@ static int ssl_session_load( mbedtls_ssl_session *session,
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     /*
-     * Session ticket
+     * Session ticket and associated data
      */
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
     if( 3 > (size_t)( end - p ) )
@@ -8958,8 +9080,41 @@ static int ssl_session_load( mbedtls_ssl_session *session,
         memcpy( session->ticket, p, session->ticket_len );
         p += session->ticket_len;
     }
+
+    if( 4 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session->ticket_lifetime = ( (uint32_t) p[0] << 24 ) |
+                               ( (uint32_t) p[1] << 16 ) |
+                               ( (uint32_t) p[2] <<  8 ) |
+                               ( (uint32_t) p[3]       );
+    p += 4;
 #endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */
 
+    /*
+     * Misc extension-related info
+     */
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+    if( 1 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session->mfl_code = *p++;
+#endif
+
+#if defined(MBEDTLS_SSL_TRUNCATED_HMAC)
+    if( 1 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session->trunc_hmac = *p++;
+#endif
+
+#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
+    if( 1 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session->encrypt_then_mac = *p++;
+#endif
+
     /* Done, should have consumed entire buffer */
     if( p != end )
         return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 72e7c3e88..95d733683 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -702,7 +702,7 @@ component_test_small_ssl_dtls_max_buffering () {
 
 component_test_small_mbedtls_ssl_dtls_max_buffering () {
     msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
-    scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
+    scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 190
     CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
     make
 
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index d6683b41e..da89642e3 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -7711,11 +7711,11 @@ run_test    "DTLS reordering: Buffer encrypted Finished message" \
 #   without fragmentation or be reassembled within the bounds of
 #   MBEDTLS_SSL_DTLS_MAX_BUFFERING. Achieve this by testing with a PSK-based
 #   handshake, omitting CRTs.
-requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 240
-requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 280
+requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 190
+requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 230
 run_test    "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket" \
             -p "$P_PXY delay_srv=NewSessionTicket delay_srv=NewSessionTicket delay_ccs=1" \
-            "$P_SRV mtu=190 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \
+            "$P_SRV mtu=140 response_size=90 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \
             "$P_CLI dgram_packing=0 dtls=1 debug_level=2 force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8 psk=abc123 psk_identity=foo" \
             0 \
             -s "Buffer record from epoch 1" \
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index b13f882c3..1b5501848 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -724,7 +724,7 @@ exit:
 }
 /* END_CASE */
 
-/* BEGIN_CASE depends_on:MBEDTLS_SEE_FUTURE_PR */
+/* BEGIN_CASE */
 void ssl_serialize_session_load_save( int ticket_len, char *crt_file )
 {
     mbedtls_ssl_session session;