Merge pull request #5328 from gilles-peskine-arm/zeroize-tag-2.16

Backport 2.16: Zeroize expected MAC/tag intermediate variables
diff --git a/ChangeLog.d/mac-zeroize.txt b/ChangeLog.d/mac-zeroize.txt
new file mode 100644
index 0000000..a43e34f
--- /dev/null
+++ b/ChangeLog.d/mac-zeroize.txt
@@ -0,0 +1,6 @@
+Security
+   * Zeroize several intermediate variables used to calculate the expected
+     value when verifying a MAC or AEAD tag. This hardens the library in
+     case the value leaks through a memory disclosure vulnerability. For
+     example, a memory disclosure vulnerability could have allowed a
+     man-in-the-middle to inject fake ciphertext into a DTLS connection.
diff --git a/ChangeLog.d/ssl-mac-zeroize.txt b/ChangeLog.d/ssl-mac-zeroize.txt
deleted file mode 100644
index b49c7ac..0000000
--- a/ChangeLog.d/ssl-mac-zeroize.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Security
-   * Zeroize intermediate variables used to calculate the MAC in CBC cipher
-     suites. This hardens the library in case stack memory leaks through a
-     memory disclosure vulnerabilty, which could formerly have allowed a
-     man-in-the-middle to inject fake ciphertext into a DTLS connection.
diff --git a/library/cipher.c b/library/cipher.c
index 57da0b9..4ea0221 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -967,6 +967,12 @@
         return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
     }
 
+    /* Status to return on a non-authenticated algorithm. It would make sense
+     * to return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT or perhaps
+     * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, but at the time I write this our
+     * unit tests assume 0. */
+    ret = 0;
+
 #if defined(MBEDTLS_GCM_C)
     if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
     {
@@ -981,9 +987,10 @@
 
         /* Check the tag in "constant-time" */
         if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
-            return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
-
-        return( 0 );
+        {
+            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
+            goto exit;
+        }
     }
 #endif /* MBEDTLS_GCM_C */
 
@@ -1003,13 +1010,16 @@
 
         /* Check the tag in "constant-time" */
         if( mbedtls_constant_time_memcmp( tag, check_tag, tag_len ) != 0 )
-            return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
-
-        return( 0 );
+        {
+            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
+            goto exit;
+        }
     }
 #endif /* MBEDTLS_CHACHAPOLY_C */
 
-    return( 0 );
+exit:
+    mbedtls_platform_zeroize( check_tag, tag_len );
+    return( ret );
 }
 #endif /* MBEDTLS_GCM_C || MBEDTLS_CHACHAPOLY_C */
 
diff --git a/library/rsa.c b/library/rsa.c
index c8c23db..47d784c 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -2148,9 +2148,13 @@
     memcpy( sig, sig_try, ctx->len );
 
 cleanup:
+    mbedtls_platform_zeroize( sig_try, ctx->len );
+    mbedtls_platform_zeroize( verif, ctx->len );
     mbedtls_free( sig_try );
     mbedtls_free( verif );
 
+    if( ret != 0 )
+        memset( sig, '!', ctx->len );
     return( ret );
 }
 #endif /* MBEDTLS_PKCS1_V15 */
diff --git a/library/ssl_cookie.c b/library/ssl_cookie.c
index 04565e0..9e21368 100644
--- a/library/ssl_cookie.c
+++ b/library/ssl_cookie.c
@@ -250,15 +250,18 @@
 
 #if defined(MBEDTLS_THREADING_C)
     if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
-        return( MBEDTLS_ERR_SSL_INTERNAL_ERROR +
+        ret = ( MBEDTLS_ERR_SSL_INTERNAL_ERROR +
                 MBEDTLS_ERR_THREADING_MUTEX_ERROR );
 #endif
 
     if( ret != 0 )
-        return( ret );
+        goto exit;
 
     if( mbedtls_ssl_safer_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 )
-        return( -1 );
+    {
+        ret = -1;
+        goto exit;
+    }
 
 #if defined(MBEDTLS_HAVE_TIME)
     cur_time = (unsigned long) mbedtls_time( NULL );
@@ -272,8 +275,13 @@
                   ( (unsigned long) cookie[3]       );
 
     if( ctx->timeout != 0 && cur_time - cookie_time > ctx->timeout )
-        return( -1 );
+    {
+        ret = -1;
+        goto exit;
+    }
 
-    return( 0 );
+exit:
+    mbedtls_platform_zeroize( ref_hmac, sizeof( ref_hmac ) );
+    return( ret );
 }
 #endif /* MBEDTLS_SSL_COOKIE_C */
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 04275a4..ae8f34e 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -6811,22 +6811,6 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) );
 
-    ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 );
-
-    if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
-    {
-        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
-        return( ret );
-    }
-
-    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 );
-        return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
-    }
-
     /* There is currently no ciphersuite using another length with TLS 1.2 */
 #if defined(MBEDTLS_SSL_PROTO_SSL3)
     if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 )
@@ -6835,13 +6819,31 @@
 #endif
         hash_len = 12;
 
+    ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 );
+
+    if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
+    {
+        MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
+        goto exit;
+    }
+
+    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 );
+        ret = MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE;
+        goto exit;
+    }
+
     if( ssl->in_msg[0] != MBEDTLS_SSL_HS_FINISHED ||
         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 );
-        return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
+        ret = MBEDTLS_ERR_SSL_BAD_HS_FINISHED;
+        goto exit;
     }
 
     if( mbedtls_ssl_safer_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ),
@@ -6850,7 +6852,8 @@
         MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) );
         mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
                                         MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR );
-        return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED );
+        ret = MBEDTLS_ERR_SSL_BAD_HS_FINISHED;
+        goto exit;
     }
 
 #if defined(MBEDTLS_SSL_RENEGOTIATION)
@@ -6879,7 +6882,9 @@
 
     MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) );
 
-    return( 0 );
+exit:
+    mbedtls_platform_zeroize( buf, hash_len );
+    return( ret );
 }
 
 static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake )