Add peer CRT digest to session tickets

This commit changes the format of session tickets to include
the digest of the peer's CRT if MBEDTLS_SSL_KEEP_PEER_CERTIFICATE
is disabled.

This commit does not yet remove the peer CRT itself.
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index c682166..5e39579 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -9023,6 +9023,12 @@
 #define SSL_SERIALIZED_SESSION_CONFIG_TICKET 0
 #endif /* MBEDTLS_SSL_SESSION_TICKETS */
 
+#if defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+#define SSL_SERIALIZED_SESSION_CONFIG_KEEP_CRT 1
+#else
+#define SSL_SERIALIZED_SESSION_CONFIG_KEEP_CRT 0
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
 #define SSL_SERIALIZED_SESSION_CONFIG_TIME_BIT          0
 #define SSL_SERIALIZED_SESSION_CONFIG_CRT_BIT           1
 #define SSL_SERIALIZED_SESSION_CONFIG_CLIENT_TICKET_BIT 2
@@ -9030,6 +9036,7 @@
 #define SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC_BIT    4
 #define SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT           5
 #define SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT        6
+#define SSL_SERIALIZED_SESSION_CONFIG_KEEP_CRT_BIT      7
 
 #define SSL_SERIALIZED_SESSION_CONFIG_BITFLAG                           \
     ( (uint16_t) (                                                      \
@@ -9039,7 +9046,8 @@
         ( SSL_SERIALIZED_SESSION_CONFIG_MFL           << SSL_SERIALIZED_SESSION_CONFIG_MFL_BIT           ) | \
         ( SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC    << SSL_SERIALIZED_SESSION_CONFIG_TRUNC_HMAC_BIT    ) | \
         ( SSL_SERIALIZED_SESSION_CONFIG_ETM           << SSL_SERIALIZED_SESSION_CONFIG_ETM_BIT           ) | \
-        ( SSL_SERIALIZED_SESSION_CONFIG_TICKET        << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT        ) ) )
+        ( SSL_SERIALIZED_SESSION_CONFIG_TICKET        << SSL_SERIALIZED_SESSION_CONFIG_TICKET_BIT        ) | \
+        ( SSL_SERIALIZED_SESSION_CONFIG_KEEP_CRT      << SSL_SERIALIZED_SESSION_CONFIG_KEEP_CRT_BIT      ) ) )
 
 static unsigned char ssl_serialized_session_header[] = {
     MBEDTLS_VERSION_MAJOR,
@@ -9073,6 +9081,8 @@
  *  opaque master[48];           // fixed length in the standard
  *  uint32 verify_result;
  *  opaque peer_cert<0..2^24-1>; // length 0 means no peer cert
+ *  uint8_t peer_cert_digest_type;
+ *  opaque peer_cert_digest<0..2^8-1>;
  *  opaque ticket<0..2^24-1>;    // length 0 means no ticket
  *  uint32 ticket_lifetime;
  *  uint8 mfl_code;              // up to 255 according to standard
@@ -9184,6 +9194,31 @@
             p += cert_len;
         }
     }
+
+    /* Digest of peer certificate */
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    if( session->peer_cert_digest != NULL )
+    {
+        used += 1 /* type */ + 1 /* length */ + session->peer_cert_digest_len;
+        if( used <= buf_len )
+        {
+            *p++ = (unsigned char) session->peer_cert_digest_type;
+            *p++ = (unsigned char) session->peer_cert_digest_len;
+            memcpy( p, session->peer_cert_digest,
+                    session->peer_cert_digest_len );
+            p += session->peer_cert_digest_len;
+        }
+    }
+    else
+    {
+        used += 2;
+        if( used <= buf_len )
+        {
+            *p++ = (unsigned char) MBEDTLS_MD_NONE;
+            *p++ = 0;
+        }
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     /*
@@ -9325,6 +9360,9 @@
      * we exit early before we replaced them with valid ones. */
 #if defined(MBEDTLS_X509_CRT_PARSE_C)
     session->peer_cert = NULL;
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    session->peer_cert_digest = NULL;
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)
     session->ticket = NULL;
@@ -9369,6 +9407,30 @@
 
         p += cert_len;
     }
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    /* Deserialize CRT digest from the end of the ticket. */
+    if( 2 > (size_t)( end - p ) )
+        return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+    session->peer_cert_digest_type = (mbedtls_md_type_t) *p++;
+    session->peer_cert_digest_len  = (size_t) *p++;
+
+    if( session->peer_cert_digest_len != 0 )
+    {
+        if( session->peer_cert_digest_len > (size_t)( end - p ) )
+            return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+
+        session->peer_cert_digest =
+            mbedtls_calloc( 1, session->peer_cert_digest_len );
+        if( session->peer_cert_digest == NULL )
+            return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+
+        memcpy( session->peer_cert_digest, p,
+                session->peer_cert_digest_len );
+        p += session->peer_cert_digest_len;
+    }
+#endif /* MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 
     /*
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index 65f5852..77a6afb 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -1,6 +1,7 @@
 /* BEGIN_HEADER */
 #include <mbedtls/ssl.h>
 #include <mbedtls/ssl_internal.h>
+#include <mbedtls/md.h>
 
 /*
  * Helper function setting up inverse record transformations
@@ -286,15 +287,40 @@
 #if defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_FS_IO)
     if( strlen( crt_file ) != 0 )
     {
+        mbedtls_x509_crt tmp_crt;
         int ret;
 
+        mbedtls_x509_crt_init( &tmp_crt );
+        ret = mbedtls_x509_crt_parse_file( &tmp_crt, crt_file );
+        if( ret != 0 )
+            return( ret );
+
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+        /* Calculate digest of temporary CRT. */
+        session->peer_cert_digest =
+            mbedtls_calloc( 1, MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN );
+        if( session->peer_cert_digest == NULL )
+            return( -1 );
+        ret = mbedtls_md( mbedtls_md_info_from_type(
+                              MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE ),
+                          tmp_crt.raw.p, tmp_crt.raw.len,
+                          session->peer_cert_digest );
+        if( ret != 0 )
+            return( ret );
+        session->peer_cert_digest_type =
+            MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_TYPE;
+        session->peer_cert_digest_len =
+            MBEDTLS_SSL_PEER_CERT_DIGEST_DFL_LEN;
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+
+        /* Move temporary CRT. */
         session->peer_cert = mbedtls_calloc( 1, sizeof( *session->peer_cert ) );
         if( session->peer_cert == NULL )
             return( -1 );
+        *session->peer_cert = tmp_crt;
+        memset( &tmp_crt, 0, sizeof( tmp_crt ) );
 
-        ret = mbedtls_x509_crt_parse_file( session->peer_cert, crt_file );
-        if( ret != 0 )
-            return( ret );
+        mbedtls_x509_crt_free( &tmp_crt );
     }
 #else
     (void) crt_file;
@@ -690,7 +716,21 @@
                              restored.peer_cert->raw.p,
                              original.peer_cert->raw.len ) == 0 );
     }
-#endif
+#if !defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
+    TEST_ASSERT( original.peer_cert_digest_type ==
+                 restored.peer_cert_digest_type );
+    TEST_ASSERT( original.peer_cert_digest_len ==
+                 restored.peer_cert_digest_len );
+    TEST_ASSERT( ( original.peer_cert_digest == NULL ) ==
+                 ( restored.peer_cert_digest == NULL ) );
+    if( original.peer_cert_digest != NULL )
+    {
+        TEST_ASSERT( memcmp( original.peer_cert_digest,
+                             restored.peer_cert_digest,
+                             original.peer_cert_digest_len ) == 0 );
+    }
+#endif /* !MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
     TEST_ASSERT( original.verify_result == restored.verify_result );
 
 #if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C)