From 2688e7a0beb0f5e76a98749f25b978ddfb40ac7f Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.org>
Date: Wed, 19 Oct 2016 17:13:13 +0100
Subject: [PATCH] Provide some constant time functions for dealing with size_t
 values

Also implement the using of them

Reviewed-by: Rich Salz <rsalz@openssl.org>
---
 include/internal/constant_time_locl.h |   49 ++++++++++++++++++++++++++++++++++
 ssl/record/ssl3_record.c              |   38 +++++++++++++-------------
 ssl/s3_cbc.c                          |    8 ++---
 3 files changed, 73 insertions(+), 22 deletions(-)

--- a/include/internal/constant_time_locl.h
+++ b/include/internal/constant_time_locl.h
@@ -10,6 +10,7 @@
 #ifndef HEADER_CONSTANT_TIME_LOCL_H
 # define HEADER_CONSTANT_TIME_LOCL_H
 
+# include <stdlib.h>
 # include <openssl/e_os2.h>              /* For 'ossl_inline' */
 
 #ifdef __cplusplus
@@ -103,12 +104,22 @@ static ossl_inline uint64_t constant_tim
     return 0 - (a >> 63);
 }
 
+static ossl_inline size_t constant_time_msb_s(size_t a)
+{
+    return 0 - (a >> (sizeof(a) * 8 - 1));
+}
+
 static ossl_inline unsigned int constant_time_lt(unsigned int a,
                                                  unsigned int b)
 {
     return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
 }
 
+static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)
+{
+    return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));
+}
+
 static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
                                                     unsigned int b)
 {
@@ -126,17 +137,32 @@ static ossl_inline unsigned int constant
     return ~constant_time_lt(a, b);
 }
 
+static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)
+{
+    return ~constant_time_lt_s(a, b);
+}
+
 static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
                                                     unsigned int b)
 {
     return (unsigned char)(constant_time_ge(a, b));
 }
 
+static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)
+{
+    return (unsigned char)(constant_time_ge_s(a, b));
+}
+
 static ossl_inline unsigned int constant_time_is_zero(unsigned int a)
 {
     return constant_time_msb(~a & (a - 1));
 }
 
+static ossl_inline size_t constant_time_is_zero_s(size_t a)
+{
+    return constant_time_msb_s(~a & (a - 1));
+}
+
 static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)
 {
     return (unsigned char)(constant_time_is_zero(a));
@@ -148,12 +174,22 @@ static ossl_inline unsigned int constant
     return constant_time_is_zero(a ^ b);
 }
 
+static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)
+{
+    return constant_time_is_zero_s(a ^ b);
+}
+
 static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
                                                     unsigned int b)
 {
     return (unsigned char)(constant_time_eq(a, b));
 }
 
+static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)
+{
+    return (unsigned char)(constant_time_eq_s(a, b));
+}
+
 static ossl_inline unsigned int constant_time_eq_int(int a, int b)
 {
     return constant_time_eq((unsigned)(a), (unsigned)(b));
@@ -171,6 +207,13 @@ static ossl_inline unsigned int constant
     return (mask & a) | (~mask & b);
 }
 
+static ossl_inline size_t constant_time_select_s(size_t mask,
+                                                 size_t a,
+                                                 size_t b)
+{
+    return (mask & a) | (~mask & b);
+}
+
 static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
                                                         unsigned char a,
                                                         unsigned char b)
@@ -178,6 +221,12 @@ static ossl_inline unsigned char constan
     return (unsigned char)(constant_time_select(mask, a, b));
 }
 
+static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)
+{
+    return (int)(constant_time_select((unsigned)mask, (unsigned)(a),
+                                      (unsigned)(b)));
+}
+
 static ossl_inline int constant_time_select_int(unsigned int mask, int a,
                                                 int b)
 {
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -1096,7 +1096,8 @@ int tls1_mac(SSL *ssl, SSL3_RECORD *rec,
 int ssl3_cbc_remove_padding(SSL3_RECORD *rec,
                             unsigned block_size, unsigned mac_size)
 {
-    unsigned padding_length, good;
+    unsigned padding_length;
+    size_t good;
     const unsigned overhead = 1 /* padding length byte */  + mac_size;
 
     /*
@@ -1106,11 +1107,11 @@ int ssl3_cbc_remove_padding(SSL3_RECORD
         return 0;
 
     padding_length = rec->data[rec->length - 1];
-    good = constant_time_ge(rec->length, padding_length + overhead);
+    good = constant_time_ge_s(rec->length, padding_length + overhead);
     /* SSLv3 requires that the padding is minimal. */
-    good &= constant_time_ge(block_size, padding_length + 1);
+    good &= constant_time_ge_s(block_size, padding_length + 1);
     rec->length -= good & (padding_length + 1);
-    return constant_time_select_int(good, 1, -1);
+    return constant_time_select_int_s(good, 1, -1);
 }
 
 /*-
@@ -1130,7 +1131,8 @@ int tls1_cbc_remove_padding(const SSL *s
                             SSL3_RECORD *rec,
                             unsigned block_size, unsigned mac_size)
 {
-    unsigned padding_length, good, to_check, i;
+    unsigned padding_length, to_check, i;
+    size_t good;
     const unsigned overhead = 1 /* padding length byte */  + mac_size;
     /* Check if version requires explicit IV */
     if (SSL_USE_EXPLICIT_IV(s)) {
@@ -1157,7 +1159,7 @@ int tls1_cbc_remove_padding(const SSL *s
         return 1;
     }
 
-    good = constant_time_ge(rec->length, overhead + padding_length);
+    good = constant_time_ge_s(rec->length, overhead + padding_length);
     /*
      * The padding consists of a length byte at the end of the record and
      * then that many bytes of padding, all with the same value as the length
@@ -1172,7 +1174,7 @@ int tls1_cbc_remove_padding(const SSL *s
         to_check = rec->length;
 
     for (i = 0; i < to_check; i++) {
-        unsigned char mask = constant_time_ge_8(padding_length, i);
+        unsigned char mask = constant_time_ge_8_s(padding_length, i);
         unsigned char b = rec->data[rec->length - 1 - i];
         /*
          * The final |padding_length+1| bytes should all have the value
@@ -1185,10 +1187,10 @@ int tls1_cbc_remove_padding(const SSL *s
      * If any of the final |padding_length+1| bytes had the wrong value, one
      * or more of the lower eight bits of |good| will be cleared.
      */
-    good = constant_time_eq(0xff, good & 0xff);
+    good = constant_time_eq_s(0xff, good & 0xff);
     rec->length -= good & (padding_length + 1);
 
-    return constant_time_select_int(good, 1, -1);
+    return constant_time_select_int_s(good, 1, -1);
 }
 
 /*-
@@ -1232,8 +1234,8 @@ void ssl3_cbc_copy_mac(unsigned char *ou
      * MAC's position can only vary by 255 bytes.
      */
     unsigned scan_start = 0;
-    unsigned i, j;
-    unsigned rotate_offset;
+    size_t i, j;
+    size_t rotate_offset;
 
     OPENSSL_assert(rec->orig_len >= md_size);
     OPENSSL_assert(md_size <= EVP_MAX_MD_SIZE);
@@ -1250,15 +1252,15 @@ void ssl3_cbc_copy_mac(unsigned char *ou
     rotate_offset = 0;
     memset(rotated_mac, 0, md_size);
     for (i = scan_start, j = 0; i < rec->orig_len; i++) {
-        unsigned mac_started = constant_time_eq(i, mac_start);
-        unsigned mac_ended = constant_time_lt(i, mac_end);
+        unsigned mac_started = constant_time_eq_s(i, mac_start);
+        unsigned mac_ended = constant_time_lt_s(i, mac_end);
         unsigned char b = rec->data[i];
 
         in_mac |= mac_started;
         in_mac &= mac_ended;
         rotate_offset |= j & mac_started;
         rotated_mac[j++] |= b & in_mac;
-        j &= constant_time_lt(j, md_size);
+        j &= constant_time_lt_s(j, md_size);
     }
 
     /* Now rotate the MAC */
@@ -1268,17 +1270,17 @@ void ssl3_cbc_copy_mac(unsigned char *ou
         /* in case cache-line is 32 bytes, touch second line */
         ((volatile unsigned char *)rotated_mac)[rotate_offset ^ 32];
         out[j++] = rotated_mac[rotate_offset++];
-        rotate_offset &= constant_time_lt(rotate_offset, md_size);
+        rotate_offset &= constant_time_lt_s(rotate_offset, md_size);
     }
 #else
     memset(out, 0, md_size);
     rotate_offset = md_size - rotate_offset;
-    rotate_offset &= constant_time_lt(rotate_offset, md_size);
+    rotate_offset &= constant_time_lt_s(rotate_offset, md_size);
     for (i = 0; i < md_size; i++) {
         for (j = 0; j < md_size; j++)
-            out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset);
+            out[j] |= rotated_mac[i] & constant_time_eq_8_s(j, rotate_offset);
         rotate_offset++;
-        rotate_offset &= constant_time_lt(rotate_offset, md_size);
+        rotate_offset &= constant_time_lt_s(rotate_offset, md_size);
     }
 #endif
 }
--- a/ssl/s3_cbc.c
+++ b/ssl/s3_cbc.c
@@ -399,8 +399,8 @@ int ssl3_cbc_digest_record(const EVP_MD_
     for (i = num_starting_blocks; i <= num_starting_blocks + variance_blocks;
          i++) {
         unsigned char block[MAX_HASH_BLOCK_SIZE];
-        unsigned char is_block_a = constant_time_eq_8(i, index_a);
-        unsigned char is_block_b = constant_time_eq_8(i, index_b);
+        unsigned char is_block_a = constant_time_eq_8_s(i, index_a);
+        unsigned char is_block_b = constant_time_eq_8_s(i, index_b);
         for (j = 0; j < md_block_size; j++) {
             unsigned char b = 0, is_past_c, is_past_cp1;
             if (k < header_length)
@@ -409,8 +409,8 @@ int ssl3_cbc_digest_record(const EVP_MD_
                 b = data[k - header_length];
             k++;
 
-            is_past_c = is_block_a & constant_time_ge_8(j, c);
-            is_past_cp1 = is_block_a & constant_time_ge_8(j, c + 1);
+            is_past_c = is_block_a & constant_time_ge_8_s(j, c);
+            is_past_cp1 = is_block_a & constant_time_ge_8_s(j, c + 1);
             /*
              * If this is the block containing the end of the application
              * data, and we are at the offset for the 0x80 value, then
