Merge pull request #1082 from daverodgman/padding-ct-changelog-2.28

Backport 2.28: Add Changelog for CT fixes
diff --git a/library/ccm.c b/library/ccm.c
index 2d2695e..79a04a2 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -33,6 +33,7 @@
 #include "mbedtls/ccm.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
+#include "mbedtls/constant_time.h"
 
 #include <string.h>
 
@@ -362,7 +363,6 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char check_tag[16];
-    unsigned char i;
     int diff;
 
     CCM_VALIDATE_RET(ctx != NULL);
@@ -379,9 +379,7 @@
     }
 
     /* Check tag in "constant-time" */
-    for (diff = 0, i = 0; i < tag_len; i++) {
-        diff |= tag[i] ^ check_tag[i];
-    }
+    diff = mbedtls_ct_memcmp(tag, check_tag, tag_len);
 
     if (diff != 0) {
         mbedtls_platform_zeroize(output, length);
diff --git a/library/chachapoly.c b/library/chachapoly.c
index ceb4292..547ffb2 100644
--- a/library/chachapoly.c
+++ b/library/chachapoly.c
@@ -25,6 +25,7 @@
 #include "mbedtls/chachapoly.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
+#include "mbedtls/constant_time.h"
 
 #include <string.h>
 
@@ -337,7 +338,6 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char check_tag[16];
-    size_t i;
     int diff;
     CHACHAPOLY_VALIDATE_RET(ctx   != NULL);
     CHACHAPOLY_VALIDATE_RET(nonce != NULL);
@@ -353,9 +353,7 @@
     }
 
     /* Check tag in "constant-time" */
-    for (diff = 0, i = 0; i < sizeof(check_tag); i++) {
-        diff |= tag[i] ^ check_tag[i];
-    }
+    diff = mbedtls_ct_memcmp(tag, check_tag, sizeof(check_tag));
 
     if (diff != 0) {
         mbedtls_platform_zeroize(output, length);
diff --git a/library/cipher.c b/library/cipher.c
index 4b715d4..09ca686 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -30,6 +30,7 @@
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
 #include "mbedtls/constant_time.h"
+#include "constant_time_internal.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -748,17 +749,17 @@
     *data_len = input_len - padding_len;
 
     /* Avoid logical || since it results in a branch */
-    bad |= padding_len > input_len;
-    bad |= padding_len == 0;
+    bad |= ~mbedtls_ct_size_mask_ge(input_len, padding_len);
+    bad |= mbedtls_ct_size_bool_eq(padding_len, 0);
 
     /* The number of bytes checked must be independent of padding_len,
      * so pick input_len, which is usually 8 or 16 (one block) */
     pad_idx = input_len - padding_len;
     for (i = 0; i < input_len; i++) {
-        bad |= (input[i] ^ padding_len) * (i >= pad_idx);
+        size_t mask = mbedtls_ct_size_mask_ge(i, pad_idx);
+        bad |= (input[i] ^ padding_len) & mask;
     }
-
-    return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0);
+    return -(int) mbedtls_ct_uint_if(bad, -MBEDTLS_ERR_CIPHER_INVALID_PADDING, 0);
 }
 #endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
 
@@ -781,24 +782,29 @@
 static int get_one_and_zeros_padding(unsigned char *input, size_t input_len,
                                      size_t *data_len)
 {
-    size_t i;
-    unsigned char done = 0, prev_done, bad;
+    unsigned int bad = 1;
 
     if (NULL == input || NULL == data_len) {
         return MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
     }
 
-    bad = 0x80;
     *data_len = 0;
-    for (i = input_len; i > 0; i--) {
-        prev_done = done;
-        done |= (input[i - 1] != 0);
-        *data_len |= (i - 1) * (done != prev_done);
-        bad ^= input[i - 1] * (done != prev_done);
+    size_t in_padding = ~0;
+
+    for (ptrdiff_t i = (ptrdiff_t) (input_len) - 1; i >= 0; i--) {
+        size_t is_nonzero = mbedtls_ct_uint_mask(input[i]);
+
+        size_t hit_first_nonzero = is_nonzero & in_padding;
+
+        *data_len = (*data_len & ~hit_first_nonzero) | ((size_t) i & hit_first_nonzero);
+
+        bad = mbedtls_ct_uint_if((unsigned int) hit_first_nonzero,
+                                 !mbedtls_ct_size_bool_eq(input[i], 0x80), bad);
+
+        in_padding = in_padding & ~is_nonzero;
     }
 
-    return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0);
-
+    return -(int) mbedtls_ct_uint_if(bad, -MBEDTLS_ERR_CIPHER_INVALID_PADDING, 0);
 }
 #endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
 
@@ -832,16 +838,17 @@
     *data_len = input_len - padding_len;
 
     /* Avoid logical || since it results in a branch */
-    bad |= padding_len > input_len;
-    bad |= padding_len == 0;
+    bad |= mbedtls_ct_size_mask_ge(padding_len, input_len + 1);
+    bad |= mbedtls_ct_size_bool_eq(padding_len, 0);
 
     /* The number of bytes checked must be independent of padding_len */
     pad_idx = input_len - padding_len;
     for (i = 0; i < input_len - 1; i++) {
-        bad |= input[i] * (i >= pad_idx);
+        size_t mask = mbedtls_ct_size_mask_ge(i, pad_idx);
+        bad |= input[i] & mask;
     }
 
-    return MBEDTLS_ERR_CIPHER_INVALID_PADDING * (bad != 0);
+    return -(int) mbedtls_ct_uint_if(bad, -MBEDTLS_ERR_CIPHER_INVALID_PADDING, 0);
 }
 #endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
 
@@ -872,8 +879,9 @@
     *data_len = 0;
     for (i = input_len; i > 0; i--) {
         prev_done = done;
-        done |= (input[i-1] != 0);
-        *data_len |= i * (done != prev_done);
+        done |= !mbedtls_ct_size_bool_eq(input[i-1], 0);
+        size_t mask = mbedtls_ct_size_mask(done ^ prev_done);
+        *data_len |= i & mask;
     }
 
     return 0;
diff --git a/library/constant_time.c b/library/constant_time.c
index c0f53bb..2307ed5 100644
--- a/library/constant_time.c
+++ b/library/constant_time.c
@@ -80,7 +80,8 @@
 #endif
 }
 
-#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || \
+    defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC)
 
 size_t mbedtls_ct_size_mask(size_t value)
 {
@@ -96,7 +97,8 @@
 #endif
 }
 
-#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
+#endif /* defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) ||
+          defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC) */
 
 #if defined(MBEDTLS_BIGNUM_C)
 
@@ -116,7 +118,8 @@
 
 #endif /* MBEDTLS_BIGNUM_C */
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) || \
+    defined(MBEDTLS_CIPHER_MODE_CBC)
 
 /** Constant-flow mask generation for "less than" comparison:
  * - if \p x < \p y, return all-bits 1, that is (size_t) -1
@@ -151,7 +154,8 @@
     return ~mbedtls_ct_size_mask_lt(x, y);
 }
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) ||
+          defined(MBEDTLS_CIPHER_MODE_CBC) */
 
 #if defined(MBEDTLS_BASE64_C)
 
diff --git a/library/constant_time_internal.h b/library/constant_time_internal.h
index 402cf14..0ba8a7a 100644
--- a/library/constant_time_internal.h
+++ b/library/constant_time_internal.h
@@ -45,7 +45,8 @@
  */
 unsigned mbedtls_ct_uint_mask(unsigned value);
 
-#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC)
+#if defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || \
+    defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC)
 
 /** Turn a value into a mask:
  * - if \p value == 0, return the all-bits 0 mask, aka 0
@@ -60,7 +61,8 @@
  */
 size_t mbedtls_ct_size_mask(size_t value);
 
-#endif /* MBEDTLS_SSL_SOME_MODES_USE_MAC */
+#endif /* defined(MBEDTLS_SSL_SOME_MODES_USE_MAC) || defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) ||
+          defined(MBEDTLS_NIST_KW_C) || defined(MBEDTLS_CIPHER_MODE_CBC) */
 
 #if defined(MBEDTLS_BIGNUM_C)
 
@@ -79,7 +81,8 @@
 
 #endif /* MBEDTLS_BIGNUM_C */
 
-#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
+#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) || \
+    defined(MBEDTLS_CIPHER_MODE_CBC)
 
 /** Constant-flow mask generation for "greater or equal" comparison:
  * - if \p x >= \p y, return all-bits 1, that is (size_t) -1
@@ -97,7 +100,8 @@
 size_t mbedtls_ct_size_mask_ge(size_t x,
                                size_t y);
 
-#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
+#endif /* defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC) || defined(MBEDTLS_NIST_KW_C) ||
+          defined(MBEDTLS_CIPHER_MODE_CBC) */
 
 /** Constant-flow boolean "equal" comparison:
  * return x == y
diff --git a/library/gcm.c b/library/gcm.c
index 0c958c7..71e7b2e 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -35,6 +35,7 @@
 #include "mbedtls/platform.h"
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
+#include "mbedtls/constant_time.h"
 
 #include <string.h>
 
@@ -478,7 +479,6 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char check_tag[16];
-    size_t i;
     int diff;
 
     GCM_VALIDATE_RET(ctx != NULL);
@@ -495,9 +495,7 @@
     }
 
     /* Check tag in "constant-time" */
-    for (diff = 0, i = 0; i < tag_len; i++) {
-        diff |= tag[i] ^ check_tag[i];
-    }
+    diff = mbedtls_ct_memcmp(tag, check_tag, tag_len);
 
     if (diff != 0) {
         mbedtls_platform_zeroize(output, length);
diff --git a/library/nist_kw.c b/library/nist_kw.c
index 5817bf4..4ff5e41 100644
--- a/library/nist_kw.c
+++ b/library/nist_kw.c
@@ -35,6 +35,7 @@
 #include "mbedtls/platform_util.h"
 #include "mbedtls/error.h"
 #include "mbedtls/constant_time.h"
+#include "constant_time_internal.h"
 
 #include <stdint.h>
 #include <string.h>
@@ -335,7 +336,7 @@
     int ret = 0;
     size_t i, olen;
     unsigned char A[KW_SEMIBLOCK_LENGTH];
-    unsigned char diff, bad_padding = 0;
+    unsigned char diff;
 
     *out_len = 0;
     if (out_size < in_len - KW_SEMIBLOCK_LENGTH) {
@@ -420,18 +421,13 @@
          * larger than 8, because of the type wrap around.
          */
         padlen = in_len - KW_SEMIBLOCK_LENGTH - Plen;
-        if (padlen > 7) {
-            padlen &= 7;
-            ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
-        }
+        ret = -(int) mbedtls_ct_uint_if(padlen & ~7, -MBEDTLS_ERR_CIPHER_AUTH_FAILED, -ret);
+        padlen &= 7;
 
         /* Check padding in "constant-time" */
         for (diff = 0, i = 0; i < KW_SEMIBLOCK_LENGTH; i++) {
-            if (i >= KW_SEMIBLOCK_LENGTH - padlen) {
-                diff |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
-            } else {
-                bad_padding |= output[*out_len - KW_SEMIBLOCK_LENGTH + i];
-            }
+            size_t mask = mbedtls_ct_size_mask_ge(i, KW_SEMIBLOCK_LENGTH - padlen);
+            diff |= (unsigned char) (mask & output[*out_len - KW_SEMIBLOCK_LENGTH + i]);
         }
 
         if (diff != 0) {
@@ -454,7 +450,6 @@
         *out_len = 0;
     }
 
-    mbedtls_platform_zeroize(&bad_padding, sizeof(bad_padding));
     mbedtls_platform_zeroize(&diff, sizeof(diff));
     mbedtls_platform_zeroize(A, sizeof(A));
 
diff --git a/library/rsa.c b/library/rsa.c
index f44b2c3..01d0eb0 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -1351,7 +1351,8 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t ilen, i, pad_len;
-    unsigned char *p, bad, pad_done;
+    unsigned char *p, pad_done;
+    int bad;
     unsigned char buf[MBEDTLS_MPI_MAX_SIZE];
     unsigned char lhash[MBEDTLS_MD_MAX_SIZE];
     unsigned int hlen;
@@ -1439,9 +1440,8 @@
     p += hlen; /* Skip seed */
 
     /* Check lHash */
-    for (i = 0; i < hlen; i++) {
-        bad |= lhash[i] ^ *p++;
-    }
+    bad |= mbedtls_ct_memcmp(lhash, p, hlen);
+    p += hlen;
 
     /* Get zero-padding len, but always read till end of buffer
      * (minus one, for the 01 byte) */