From 278d54d95de9fa80b4ac9f6dd0f900841114ca8c Mon Sep 17 00:00:00 2001
From: Sean Parkinson <sean@wolfssl.com>
Date: Mon, 27 Aug 2018 10:16:40 +1000
Subject: [PATCH] Make RsaUnPad constant time when Block Type 2 message

(cherry picked from commit ab03f9291b040269ae21d33b9f01529ed8311728)
[cherry-pick changes]
Signed-off-by: Eneas U de Queiroz <cotequeiroz@gmail.com>

--- a/src/internal.c
+++ b/src/internal.c
@@ -24766,26 +24766,22 @@ static int DoSessionTicket(WOLFSSL* ssl,
                          * indistinguishable from correctly formatted RSA blocks
                          */
 
-                        ret = args->lastErr;
                         args->lastErr = 0; /* reset */
 
                         /* build PreMasterSecret */
                         ssl->arrays->preMasterSecret[0] = ssl->chVersion.major;
                         ssl->arrays->preMasterSecret[1] = ssl->chVersion.minor;
-                        if (ret == 0 && args->sigSz == SECRET_LEN &&
-                                                         args->output != NULL) {
+                        if (args->output != NULL) {
                             XMEMCPY(&ssl->arrays->preMasterSecret[VERSION_SZ],
-                                &args->output[VERSION_SZ],
-                                SECRET_LEN - VERSION_SZ);
+                                    &args->output[VERSION_SZ],
+                                    SECRET_LEN - VERSION_SZ);
                         }
-                        else {
-                            /* preMasterSecret has RNG and version set */
-                            /* return proper length and ignore error */
-                            /* error will be caught as decryption error */
-                            args->sigSz = SECRET_LEN;
-                            ret = 0;
-                        }
-
+                        /* preMasterSecret has RNG and version set
+                         * return proper length and ignore error
+                         * error will be caught as decryption error
+                         */
+                        args->sigSz = SECRET_LEN;
+                        ret = 0;
                         break;
                     } /* rsa_kea */
                 #endif /* !NO_RSA */
--- a/src/tls.c
+++ b/src/tls.c
@@ -1136,12 +1136,12 @@ static int Hmac_UpdateFinal_CT(Hmac* hma
             else if (k < maxLen)
                 b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ];
 
-            b = ctMaskSel(atEoc, b, 0x80);
+            b = ctMaskSel(atEoc, 0x80, b);
             b &= ~pastEoc;
             b &= ~isOutBlock | isEocBlock;
 
             if (j >= blockSz - 8) {
-                b = ctMaskSel(isOutBlock, b, lenBytes[j - (blockSz - 8)]);
+                b = ctMaskSel(isOutBlock, lenBytes[j - (blockSz - 8)], b);
             }
 
             hashBlock[j] = b;
--- a/wolfcrypt/src/integer.c
+++ b/wolfcrypt/src/integer.c
@@ -321,6 +321,17 @@ int mp_to_unsigned_bin (mp_int * a, unsi
   return res;
 }
 
+int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
+{
+    int i, len;
+
+    len = mp_unsigned_bin_size(a);
+
+    /* pad front w/ zeros to match length */
+    for (i = 0; i < c - len; i++)
+        b[i] = 0x00;
+    return mp_to_unsigned_bin(a, b + i);
+}
 
 /* creates "a" then copies b into it */
 int mp_init_copy (mp_int * a, mp_int * b)
--- a/wolfcrypt/src/misc.c
+++ b/wolfcrypt/src/misc.c
@@ -341,10 +341,22 @@ STATIC INLINE byte ctMaskEq(int a, int b
     return 0 - (a == b);
 }
 
-/* Constant time - select b when mask is set and a otherwise. */
+/* Constant time - mask set when a != b. */
+STATIC INLINE byte ctMaskNotEq(int a, int b)
+{
+    return 0 - (a != b);
+}
+
+/* Constant time - select a when mask is set and b otherwise. */
 STATIC INLINE byte ctMaskSel(byte m, byte a, byte b)
 {
-    return (a & ~m) | (b & m);
+    return (b & ~m) | (a & m);
+}
+
+/* Constant time - select integer a when mask is set and integer b otherwise. */
+STATIC INLINE int ctMaskSelInt(byte m, int a, int b)
+{
+    return (b & (~(int)(char)m)) | (a & ((int)(char)m));
 }
 
 /* Constant time - bit set when a <= b. */
--- a/wolfcrypt/src/rsa.c
+++ b/wolfcrypt/src/rsa.c
@@ -989,10 +989,8 @@ static int RsaUnPad_OAEP(byte *pkcsBlock
     ret += pkcsBlock[idx++] ^ 0x01; /* separator value is 0x01 */
     ret += pkcsBlock[0]     ^ 0x00; /* Y, the first value, should be 0 */
 
-    if (ret != 0) {
-        WOLFSSL_MSG("RsaUnPad_OAEP: Padding Error");
-        return BAD_PADDING_E;
-    }
+    /* Return 0 data length on error. */
+    idx = ctMaskSelInt(ctMaskEq(ret, 0), idx, pkcsBlockLen);
 
     /* adjust pointer to correct location in array and return size of M */
     *output = (byte*)(pkcsBlock + idx);
@@ -1078,48 +1076,60 @@ static int RsaUnPad_PSS(byte *pkcsBlock,
 /* UnPad plaintext, set start to *output, return length of plaintext,
  * < 0 on error */
 static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
-                                               byte **output, byte padValue)
+                    byte **output, byte padValue)
 {
-    word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0;
-    word32 invalid = 0;
-    word32 i = 1;
-    word32 outputLen;
+    int    ret;
+    word32 i;
+    byte   invalid = 0;
 
     if (output == NULL || pkcsBlockLen == 0) {
         return BAD_FUNC_ARG;
     }
 
-    if (pkcsBlock[0] != 0x0) { /* skip past zero */
-        invalid = 1;
-    }
-    pkcsBlock++; pkcsBlockLen--;
+    if (padValue == RSA_BLOCK_TYPE_1) {
+        /* First byte must be 0x00 and Second byte, block type, 0x01 */
+        if (pkcsBlock[0] != 0 || pkcsBlock[1] != RSA_BLOCK_TYPE_1) {
+            WOLFSSL_MSG("RsaUnPad error, invalid formatting");
+            return RSA_PAD_E;
+        }
 
-    /* Require block type padValue */
-    invalid = (pkcsBlock[0] != padValue) || invalid;
+        /* check the padding until we find the separator */
+        for (i = 2; i < pkcsBlockLen && pkcsBlock[i++] == 0xFF; ) { }
 
-    /* verify the padding until we find the separator */
-    if (padValue == RSA_BLOCK_TYPE_1) {
-        while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
-    }
-    else {
-        while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
-    }
+        /* Minimum of 11 bytes of pre-message data and must have separator. */
+        if (i < RSA_MIN_PAD_SZ || pkcsBlock[i-1] != 0) {
+            WOLFSSL_MSG("RsaUnPad error, bad formatting");
+            return RSA_PAD_E;
+        }
 
-    if (!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
-        WOLFSSL_MSG("RsaUnPad error, bad formatting");
-        return RSA_PAD_E;
+        *output = (byte *)(pkcsBlock + i);
+        ret = pkcsBlockLen - i;
     }
+    else {
+        word32 j;
+        byte   pastSep = 0;
 
-    outputLen = pkcsBlockLen - i;
-    invalid = (outputLen > maxOutputLen) || invalid;
+        /* Decrypted with private key - unpad must be constant time. */
+        for (i = 0, j = 2; j < pkcsBlockLen; j++) {
+           /* Update i if not passed the separator and at separator. */
+           i |= (~pastSep) & ctMaskEq(pkcsBlock[j], 0x00) & (j + 1);
+           pastSep |= ctMaskEq(pkcsBlock[j], 0x00);
+        }
+
+        /* Minimum of 11 bytes of pre-message data - including leading 0x00. */
+        invalid |= ctMaskLT(i, RSA_MIN_PAD_SZ);
+        /* Must have seen separator. */
+        invalid |= ~pastSep;
+        /* First byte must be 0x00. */
+        invalid |= ctMaskNotEq(pkcsBlock[0], 0x00);
+        /* Check against expected block type: padValue */
+        invalid |= ctMaskNotEq(pkcsBlock[1], padValue);
 
-    if (invalid) {
-        WOLFSSL_MSG("RsaUnPad error, invalid formatting");
-        return RSA_PAD_E;
+        *output = (byte *)(pkcsBlock + i);
+        ret = ((int)~invalid) & (pkcsBlockLen - i);
     }
 
-    *output = (byte *)(pkcsBlock + i);
-    return outputLen;
+    return ret;
 }
 
 /* helper function to direct unpadding
@@ -1249,7 +1259,7 @@ static int wc_RsaFunctionSync(const byte
     mp_int rnd, rndi;
 #endif
     int    ret = 0;
-    word32 keyLen, len;
+    word32 keyLen;
 #endif
 
 #ifdef WOLFSSL_HAVE_SP_RSA
@@ -1308,6 +1318,7 @@ static int wc_RsaFunctionSync(const byte
     }
 #endif
 
+#ifndef TEST_UNPAD_CONSTANT_TIME
     if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
         ERROR_OUT(MP_READ_E);
 
@@ -1418,21 +1429,18 @@ static int wc_RsaFunctionSync(const byte
         ERROR_OUT(RSA_BUFFER_E);
     }
 
-    len = mp_unsigned_bin_size(&tmp);
-
-    /* pad front w/ zeros to match key length */
-    while (len < keyLen) {
-        *out++ = 0x00;
-        len++;
-    }
-
     *outLen = keyLen;
-
-    /* convert */
-    if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
+    if (mp_to_unsigned_bin_len(&tmp, out, keyLen) != MP_OKAY)
         ERROR_OUT(MP_TO_E);
 
 done:
+#else
+    (void)type;
+    (void)key;
+    (void)keyLen;
+    XMEMCPY(out, in, inLen);
+    *outLen = inLen;
+#endif
     mp_clear(&tmp);
 #ifdef WC_RSA_BLINDING
     if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
@@ -1633,6 +1641,7 @@ int wc_RsaFunction(const byte* in, word3
     }
 #endif
 
+#ifndef TEST_UNPAD_CONSTANT_TIME
 #ifndef NO_RSA_BOUNDS_CHECK
     if (type == RSA_PRIVATE_DECRYPT &&
         key->state == RSA_STATE_DECRYPT_EXPTMOD) {
@@ -1667,6 +1676,7 @@ int wc_RsaFunction(const byte* in, word3
             return ret;
     }
 #endif /* NO_RSA_BOUNDS_CHECK */
+#endif
 
 #if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
     if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
@@ -1880,7 +1890,8 @@ static int RsaPrivateDecryptEx(byte* in,
 
         /* if not doing this inline then allocate a buffer for it */
         if (outPtr == NULL) {
-            key->data = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_WOLF_BIGINT);
+            key->data = (byte*)XMALLOC(inLen, key->heap,
+                                                      DYNAMIC_TYPE_WOLF_BIGINT);
             key->dataIsAlloc = 1;
             if (key->data == NULL) {
                 ret = MEMORY_E;
@@ -1909,20 +1920,29 @@ static int RsaPrivateDecryptEx(byte* in,
         ret = wc_RsaUnPad_ex(key->data, key->dataLen, &pad, pad_value, pad_type,
                              hash, mgf, label, labelSz, saltLen,
                              mp_count_bits(&key->n), key->heap);
-        if (ret > 0 && ret <= (int)outLen && pad != NULL) {
+        if (rsa_type == RSA_PUBLIC_DECRYPT && ret > (int)outLen)
+            ret = RSA_BUFFER_E;
+        else if (ret >= 0 && pad != NULL) {
+            char c;
+
             /* only copy output if not inline */
             if (outPtr == NULL) {
-                XMEMCPY(out, pad, ret);
+                word32 i, j;
+                int start = (int)((size_t)pad - (size_t)key->data);
+
+                for (i = 0, j = 0; j < key->dataLen; j++) {
+                    out[i] = key->data[j];
+                    c  = ctMaskGTE(j, start);
+                    c &= ctMaskLT(i, outLen);
+                    /* 0 - no add, -1 add */
+                    i += -c;
+                }
             }
-            else {
+            else
                 *outPtr = pad;
-            }
-        }
-        else if (ret >= 0) {
-            ret = RSA_BUFFER_E;
-        }
-        if (ret < 0) {
-            break;
+
+            ret = ctMaskSelInt(ctMaskLTE(ret, outLen), ret, RSA_BUFFER_E);
+            ret = ctMaskSelInt(ctMaskNotEq(ret, 0), ret, RSA_BUFFER_E);
         }
 
         key->state = RSA_STATE_DECRYPT_RES;
@@ -1934,12 +1954,14 @@ static int RsaPrivateDecryptEx(byte* in,
             defined(HAVE_CAVIUM)
         if (key->asyncDev.marker == WOLFSSL_ASYNC_MARKER_RSA &&
                                                    pad_type != WC_RSA_PSS_PAD) {
-            /* convert result */
-            byte* dataLen = (byte*)&key->dataLen;
-            ret = (dataLen[0] << 8) | (dataLen[1]);
+            if (ret > 0) {
+                /* convert result */
+                byte* dataLen = (byte*)&key->dataLen;
+                ret = (dataLen[0] << 8) | (dataLen[1]);
 
-            if (outPtr)
-                *outPtr = in;
+                if (outPtr)
+                    *outPtr = in;
+            }
         }
     #endif
         break;
--- a/wolfcrypt/src/sp_int.c
+++ b/wolfcrypt/src/sp_int.c
@@ -286,7 +286,8 @@ int sp_leading_bit(sp_int* a)
  * The array must be large enough for encoded number - use mp_unsigned_bin_size
  * to calculate the number of bytes required.
  *
- * a  SP integer.
+ * a    SP integer.
+ * out  Array to put encoding into.
  * returns MP_OKAY always.
  */
 int sp_to_unsigned_bin(sp_int* a, byte* out)
@@ -305,6 +306,31 @@ int sp_to_unsigned_bin(sp_int* a, byte*
     return MP_OKAY;
 }
 
+/* Convert the big number to an array of bytes in big-endian format.
+ * The array must be large enough for encoded number - use mp_unsigned_bin_size
+ * to calculate the number of bytes required.
+ * Front-pads the output array with zeros make number the size of the array.
+ *
+ * a      SP integer.
+ * out    Array to put encoding into.
+ * outSz  Size of the array.
+ * returns MP_OKAY always.
+ */
+int sp_to_unsigned_bin_len(sp_int* a, byte* out, int outSz)
+{
+    int i, j, b;
+
+    j = outSz - 1;
+    for (i=0; j>=0; i++) {
+        for (b = 0; b < SP_WORD_SIZE; b += 8) {
+            out[j--] = a->dp[i] >> b;
+            if (j < 0)
+                break;
+        }
+    }
+
+    return MP_OKAY;
+}
 /* Ensure the data in the big number is zeroed.
  *
  * a  SP integer.
--- a/wolfcrypt/src/tfm.c
+++ b/wolfcrypt/src/tfm.c
@@ -1964,6 +1964,48 @@ void fp_to_unsigned_bin(fp_int *a, unsig
   fp_reverse (b, x);
 }
 
+int fp_to_unsigned_bin_len(fp_int *a, unsigned char *b, int c)
+{
+#if DIGIT_BIT == 64 || DIGIT_BIT == 32
+  int i, j, x;
+
+  for (x=c-1,j=0,i=0; x >= 0; x--) {
+     b[x] = (unsigned char)(a->dp[i] >> j);
+     j += 8;
+     i += j == DIGIT_BIT;
+     j &= DIGIT_BIT - 1;
+  }
+
+  return FP_OKAY;
+#else
+  int     x;
+#ifndef WOLFSSL_SMALL_STACK
+   fp_int t[1];
+#else
+   fp_int *t;
+#endif
+
+#ifdef WOLFSSL_SMALL_STACK
+   t = (fp_int*)XMALLOC(sizeof(fp_int), NULL, DYNAMIC_TYPE_TMP_BUFFER);
+   if (t == NULL)
+       return FP_MEM;
+#endif
+
+  fp_init_copy(t, a);
+
+  for (x = 0; x < c; x++) {
+      b[x] = (unsigned char) (t->dp[0] & 255);
+      fp_div_2d (t, 8, t, NULL);
+  }
+  fp_reverse (b, x);
+
+#ifdef WOLFSSL_SMALL_STACK
+  XFREE(t, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+#endif
+  return FP_OKAY;
+#endif
+}
+
 int fp_unsigned_bin_size(fp_int *a)
 {
   int     size = fp_count_bits (a);
@@ -2435,6 +2477,10 @@ int mp_to_unsigned_bin (mp_int * a, unsi
   return MP_OKAY;
 }
 
+int mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c)
+{
+  return fp_to_unsigned_bin_len(a, b, c);
+}
 /* reads a unsigned char array, assumes the msb is stored first [big endian] */
 int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
 {
--- a/wolfssl/wolfcrypt/integer.h
+++ b/wolfssl/wolfcrypt/integer.h
@@ -277,6 +277,7 @@ MP_API int  mp_unsigned_bin_size(mp_int
 MP_API int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
 MP_API int  mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b);
 MP_API int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+MP_API int  mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c);
 MP_API int  mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
 /* end functions needed by Rsa */
 
--- a/wolfssl/wolfcrypt/misc.h
+++ b/wolfssl/wolfcrypt/misc.h
@@ -97,7 +97,9 @@ WOLFSSL_LOCAL byte ctMaskGTE(int a, int
 WOLFSSL_LOCAL byte ctMaskLT(int a, int b);
 WOLFSSL_LOCAL byte ctMaskLTE(int a, int b);
 WOLFSSL_LOCAL byte ctMaskEq(int a, int b);
+WOLFSSL_LOCAL byte ctMaskNotEq(int a, int b);
 WOLFSSL_LOCAL byte ctMaskSel(byte m, byte a, byte b);
+WOLFSSL_LOCAL int  ctMaskSelInt(byte m, int a, int b);
 WOLFSSL_LOCAL byte ctSetLTE(int a, int b);
 
 #endif /* NO_INLINE */
--- a/wolfssl/wolfcrypt/sp_int.h
+++ b/wolfssl/wolfcrypt/sp_int.h
@@ -119,7 +119,8 @@ MP_API int sp_read_radix(sp_int* a, cons
 MP_API int sp_cmp(sp_int* a, sp_int* b);
 MP_API int sp_count_bits(sp_int* a);
 MP_API int sp_leading_bit(sp_int* a);
-MP_API int sp_to_unsigned_bin(sp_int* a, byte* in);
+MP_API int sp_to_unsigned_bin(sp_int* a, byte* out);
+MP_API int sp_to_unsigned_bin_len(sp_int* a, byte* out, int outSz);
 MP_API void sp_forcezero(sp_int* a);
 MP_API int sp_copy(sp_int* a, sp_int* b);
 MP_API int sp_set(sp_int* a, sp_int_digit d);
@@ -156,30 +157,31 @@ typedef sp_digit mp_digit;
 
 #define mp_free(a)
 
-#define mp_init                 sp_init
-#define mp_init_multi           sp_init_multi
-#define mp_clear                sp_clear
-#define mp_read_unsigned_bin    sp_read_unsigned_bin
-#define mp_unsigned_bin_size    sp_unsigned_bin_size
-#define mp_read_radix           sp_read_radix
-#define mp_cmp                  sp_cmp
-#define mp_count_bits           sp_count_bits
-#define mp_leading_bit          sp_leading_bit
-#define mp_to_unsigned_bin      sp_to_unsigned_bin
-#define mp_forcezero            sp_forcezero
-#define mp_copy                 sp_copy
-#define mp_set                  sp_set
-#define mp_iszero               sp_iszero
-#define mp_clamp                sp_clamp
-#define mp_grow                 sp_grow
-#define mp_sub_d                sp_sub_d
-#define mp_cmp_d                sp_cmp_d
-#define mp_mod                  sp_mod
-#define mp_zero                 sp_zero
-#define mp_add_d                sp_add_d
-#define mp_lshd                 sp_lshd
-#define mp_add                  sp_add
-#define mp_isodd                sp_isodd
+#define mp_init                     sp_init
+#define mp_init_multi               sp_init_multi
+#define mp_clear                    sp_clear
+#define mp_read_unsigned_bin        sp_read_unsigned_bin
+#define mp_unsigned_bin_size        sp_unsigned_bin_size
+#define mp_read_radix               sp_read_radix
+#define mp_cmp                      sp_cmp
+#define mp_count_bits               sp_count_bits
+#define mp_leading_bit              sp_leading_bit
+#define mp_to_unsigned_bin          sp_to_unsigned_bin
+#define mp_to_unsigned_bin_len      sp_to_unsigned_bin_len
+#define mp_forcezero                sp_forcezero
+#define mp_copy                     sp_copy
+#define mp_set                      sp_set
+#define mp_iszero                   sp_iszero
+#define mp_clamp                    sp_clamp
+#define mp_grow                     sp_grow
+#define mp_sub_d                    sp_sub_d
+#define mp_cmp_d                    sp_cmp_d
+#define mp_mod                      sp_mod
+#define mp_zero                     sp_zero
+#define mp_add_d                    sp_add_d
+#define mp_lshd                     sp_lshd
+#define mp_add                      sp_add
+#define mp_isodd                    sp_isodd
 
 #define MP_INT_DEFINED
 
--- a/wolfssl/wolfcrypt/tfm.h
+++ b/wolfssl/wolfcrypt/tfm.h
@@ -563,6 +563,7 @@ int fp_leading_bit(fp_int *a);
 int fp_unsigned_bin_size(fp_int *a);
 void fp_read_unsigned_bin(fp_int *a, const unsigned char *b, int c);
 void fp_to_unsigned_bin(fp_int *a, unsigned char *b);
+int fp_to_unsigned_bin_len(fp_int *a, unsigned char *b, int c);
 int fp_to_unsigned_bin_at_pos(int x, fp_int *t, unsigned char *b);
 
 /*int fp_signed_bin_size(fp_int *a);*/
@@ -686,6 +687,7 @@ MP_API int  mp_unsigned_bin_size(mp_int
 MP_API int  mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
 MP_API int  mp_to_unsigned_bin_at_pos(int x, mp_int *t, unsigned char *b);
 MP_API int  mp_to_unsigned_bin (mp_int * a, unsigned char *b);
+MP_API int  mp_to_unsigned_bin_len(mp_int * a, unsigned char *b, int c);
 
 MP_API int  mp_sub_d(fp_int *a, fp_digit b, fp_int *c);
 MP_API int  mp_copy(fp_int* a, fp_int* b);
