ssl_client.c: Adapt session id generation to the TLS 1.2 case

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
diff --git a/library/ssl_client.c b/library/ssl_client.c
index 2759de4..c251518 100644
--- a/library/ssl_client.c
+++ b/library/ssl_client.c
@@ -262,20 +262,22 @@
                            p, MBEDTLS_CLIENT_HELLO_RANDOM_LEN );
     p += MBEDTLS_CLIENT_HELLO_RANDOM_LEN;
 
-    /*
-     * Write legacy_session_id
+    /* TLS 1.2:
+     * ...
+     * SessionID session_id;
+     * ...
+     * with
+     * opaque SessionID<0..32>;
      *
-     * Versions of TLS before TLS 1.3 supported a "session resumption" feature
-     * which has been merged with pre-shared keys in this version. A client
-     * which has a cached session ID set by a pre-TLS 1.3 server SHOULD set
-     * this field to that value. In compatibility mode, this field MUST be
-     * non-empty, so a client not offering a pre-TLS 1.3 session MUST generate
-     * a new 32-byte value. This value need not be random but SHOULD be
-     * unpredictable to avoid implementations fixating on a specific value
-     * ( also known as ossification ). Otherwise, it MUST be set as a zero-length
-     * vector ( i.e., a zero-valued single byte length field ).
+     * TLS 1.3:
+     * ...
+     * opaque legacy_session_id<0..32>;
+     * ...
+     *
+     * The (legacy) session identifier bytes have been by
+     * ssl_prepare_client_hello() into the ssl->session_negotiate->id buffer
+     * and are copied here into the output buffer.
      */
-#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
     MBEDTLS_SSL_CHK_BUF_PTR( p, end, ssl->session_negotiate->id_len + 1 );
     *p++ = (unsigned char)ssl->session_negotiate->id_len;
     memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->id_len );
@@ -283,10 +285,6 @@
 
     MBEDTLS_SSL_DEBUG_BUF( 3, "session id", ssl->session_negotiate->id,
                               ssl->session_negotiate->id_len );
-#else
-    MBEDTLS_SSL_CHK_BUF_PTR( p, end, 1 );
-    *p++ = 0; /* session id length set to zero */
-#endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
 
     /* Write cipher_suites */
     ret = ssl_write_client_hello_cipher_suites( ssl, p, end, &output_len );
@@ -411,6 +409,7 @@
 static int ssl_prepare_client_hello( mbedtls_ssl_context *ssl )
 {
     int ret;
+    size_t session_id_len;
 
     if( ssl->conf->f_rng == NULL )
     {
@@ -459,24 +458,83 @@
         }
     }
 
-#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
     /*
-     * Create a session identifier for the purpose of middlebox compatibility
-     * only if one has not been created already.
+     * Prepare session identifier. But in the case of a TLS 1.2 session
+     * renegotiation or session resumption, the initial value of the session
+     * identifier length below is equal to zero.
      */
-    if( ssl->session_negotiate->id_len == 0 )
+    session_id_len = ssl->session_negotiate->id_len;
+
+#if defined(MBEDTLS_SSL_PROTO_TLS1_2)
+    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 )
     {
-        /* Creating a session id with 32 byte length */
-        if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng,
-                                      ssl->session_negotiate->id, 32 ) ) != 0 )
+        if( session_id_len < 16 || session_id_len > 32 ||
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+            ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ||
+#endif
+            ssl->handshake->resume == 0 )
         {
-            MBEDTLS_SSL_DEBUG_RET( 1, "creating session id failed", ret );
-            return( ret );
+            session_id_len = 0;
         }
-        ssl->session_negotiate->id_len = 32;
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+    /*
+     * RFC 5077 section 3.4: "When presenting a ticket, the client MAY
+     * generate and include a Session ID in the TLS ClientHello."
+     */
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+        if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE )
+#endif
+        {
+            if( ( ssl->session_negotiate->ticket != NULL ) &&
+                ( ssl->session_negotiate->ticket_len != 0 ) )
+            {
+                session_id_len = 32;
+            }
+        }
+#endif /* MBEDTLS_SSL_SESSION_TICKETS */
+    }
+#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */
+
+#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
+    if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_4 )
+    {
+        /*
+         * Create a legacy session identifier for the purpose of middlebox
+         * compatibility only if one has not been created already, which is
+         * the case if we are here for the TLS 1.3 second ClientHello.
+         *
+         * Versions of TLS before TLS 1.3 supported a "session resumption"
+         * feature which has been merged with pre-shared keys in TLS 1.3
+         * version. A client which has a cached session ID set by a pre-TLS 1.3
+         * server SHOULD set this field to that value. In compatibility mode,
+         * this field MUST be non-empty, so a client not offering a pre-TLS 1.3
+         * session MUST generate a new 32-byte value. This value need not be
+         * random but SHOULD be unpredictable to avoid implementations fixating
+         * on a specific value (also known as ossification). Otherwise, it MUST
+         * be set as a zero-length vector ( i.e., a zero-valued single byte
+         * length field ).
+         */
+        session_id_len = 32;
     }
 #endif /* MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE */
 
+    if( session_id_len != ssl->session_negotiate->id_len )
+    {
+        ssl->session_negotiate->id_len = session_id_len;
+        if( session_id_len > 0 )
+        {
+            ret = ssl->conf->f_rng( ssl->conf->p_rng,
+                                    ssl->session_negotiate->id,
+                                    session_id_len );
+            if( ret != 0 )
+            {
+                MBEDTLS_SSL_DEBUG_RET( 1, "creating session id failed", ret );
+                return( ret );
+            }
+        }
+    }
+
     return( 0 );
 }