Home | History | Annotate | Line # | Download | only in internal
      1 /*
      2  * Copyright 2014-2025 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #ifndef OSSL_INTERNAL_CONSTANT_TIME_H
     11 #define OSSL_INTERNAL_CONSTANT_TIME_H
     12 #pragma once
     13 
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <openssl/e_os2.h> /* For 'ossl_inline' */
     17 
     18 /*-
     19  * The boolean methods return a bitmask of all ones (0xff...f) for true
     20  * and 0 for false. This is useful for choosing a value based on the result
     21  * of a conditional in constant time. For example,
     22  *      if (a < b) {
     23  *        c = a;
     24  *      } else {
     25  *        c = b;
     26  *      }
     27  * can be written as
     28  *      unsigned int lt = constant_time_lt(a, b);
     29  *      c = constant_time_select(lt, a, b);
     30  */
     31 
     32 /* Returns the given value with the MSB copied to all the other bits. */
     33 static ossl_inline unsigned int constant_time_msb(unsigned int a);
     34 /* Convenience method for uint32_t. */
     35 static ossl_inline uint32_t constant_time_msb_32(uint32_t a);
     36 /* Convenience method for uint64_t. */
     37 static ossl_inline uint64_t constant_time_msb_64(uint64_t a);
     38 
     39 /* Returns 0xff..f if a < b and 0 otherwise. */
     40 static ossl_inline unsigned int constant_time_lt(unsigned int a,
     41     unsigned int b);
     42 /* Convenience method for getting an 8-bit mask. */
     43 static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
     44     unsigned int b);
     45 /* Convenience method for uint32_t. */
     46 static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b);
     47 
     48 /* Convenience method for uint64_t. */
     49 static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b);
     50 
     51 /* Returns 0xff..f if a >= b and 0 otherwise. */
     52 static ossl_inline unsigned int constant_time_ge(unsigned int a,
     53     unsigned int b);
     54 /* Convenience method for getting an 8-bit mask. */
     55 static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
     56     unsigned int b);
     57 
     58 /* Returns 0xff..f if a == 0 and 0 otherwise. */
     59 static ossl_inline unsigned int constant_time_is_zero(unsigned int a);
     60 /* Convenience method for getting an 8-bit mask. */
     61 static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a);
     62 /* Convenience method for getting a 32-bit mask. */
     63 static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a);
     64 
     65 /* Returns 0xff..f if a == b and 0 otherwise. */
     66 static ossl_inline unsigned int constant_time_eq(unsigned int a,
     67     unsigned int b);
     68 /* Convenience method for getting an 8-bit mask. */
     69 static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
     70     unsigned int b);
     71 /* Signed integers. */
     72 static ossl_inline unsigned int constant_time_eq_int(int a, int b);
     73 /* Convenience method for getting an 8-bit mask. */
     74 static ossl_inline unsigned char constant_time_eq_int_8(int a, int b);
     75 
     76 /*-
     77  * Returns (mask & a) | (~mask & b).
     78  *
     79  * When |mask| is all 1s or all 0s (as returned by the methods above),
     80  * the select methods return either |a| (if |mask| is nonzero) or |b|
     81  * (if |mask| is zero).
     82  */
     83 static ossl_inline unsigned int constant_time_select(unsigned int mask,
     84     unsigned int a,
     85     unsigned int b);
     86 /* Convenience method for unsigned chars. */
     87 static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
     88     unsigned char a,
     89     unsigned char b);
     90 
     91 /* Convenience method for uint32_t. */
     92 static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
     93     uint32_t b);
     94 
     95 /* Convenience method for uint64_t. */
     96 static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
     97     uint64_t b);
     98 /* Convenience method for signed integers. */
     99 static ossl_inline int constant_time_select_int(unsigned int mask, int a,
    100     int b);
    101 
    102 static ossl_inline unsigned int constant_time_msb(unsigned int a)
    103 {
    104     return 0 - (a >> (sizeof(a) * 8 - 1));
    105 }
    106 
    107 static ossl_inline uint32_t constant_time_msb_32(uint32_t a)
    108 {
    109     return 0 - (a >> 31);
    110 }
    111 
    112 static ossl_inline uint64_t constant_time_msb_64(uint64_t a)
    113 {
    114     return 0 - (a >> 63);
    115 }
    116 
    117 static ossl_inline size_t constant_time_msb_s(size_t a)
    118 {
    119     return 0 - (a >> (sizeof(a) * 8 - 1));
    120 }
    121 
    122 static ossl_inline unsigned int constant_time_lt(unsigned int a,
    123     unsigned int b)
    124 {
    125     return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
    126 }
    127 
    128 static ossl_inline size_t constant_time_lt_s(size_t a, size_t b)
    129 {
    130     return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));
    131 }
    132 
    133 static ossl_inline unsigned char constant_time_lt_8(unsigned int a,
    134     unsigned int b)
    135 {
    136     return (unsigned char)constant_time_lt(a, b);
    137 }
    138 
    139 static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b)
    140 {
    141     return constant_time_msb_32(a ^ ((a ^ b) | ((a - b) ^ b)));
    142 }
    143 
    144 static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b)
    145 {
    146     return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b)));
    147 }
    148 
    149 #ifdef BN_ULONG
    150 static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a)
    151 {
    152 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
    153     BN_ULONG r;
    154     __asm__("" : "=r"(r) : "0"(a));
    155 #else
    156     volatile BN_ULONG r = a;
    157 #endif
    158     return r;
    159 }
    160 
    161 static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a)
    162 {
    163     return 0 - (a >> (sizeof(a) * 8 - 1));
    164 }
    165 
    166 static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b)
    167 {
    168     return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b)));
    169 }
    170 
    171 static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a)
    172 {
    173     return constant_time_msb_bn(~a & (a - 1));
    174 }
    175 
    176 static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a,
    177     BN_ULONG b)
    178 {
    179     return constant_time_is_zero_bn(a ^ b);
    180 }
    181 
    182 static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask,
    183     BN_ULONG a,
    184     BN_ULONG b)
    185 {
    186     return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b);
    187 }
    188 #endif
    189 
    190 static ossl_inline unsigned int constant_time_ge(unsigned int a,
    191     unsigned int b)
    192 {
    193     return ~constant_time_lt(a, b);
    194 }
    195 
    196 static ossl_inline size_t constant_time_ge_s(size_t a, size_t b)
    197 {
    198     return ~constant_time_lt_s(a, b);
    199 }
    200 
    201 static ossl_inline unsigned char constant_time_ge_8(unsigned int a,
    202     unsigned int b)
    203 {
    204     return (unsigned char)constant_time_ge(a, b);
    205 }
    206 
    207 static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b)
    208 {
    209     return (unsigned char)constant_time_ge_s(a, b);
    210 }
    211 
    212 static ossl_inline unsigned int constant_time_is_zero(unsigned int a)
    213 {
    214     return constant_time_msb(~a & (a - 1));
    215 }
    216 
    217 static ossl_inline size_t constant_time_is_zero_s(size_t a)
    218 {
    219     return constant_time_msb_s(~a & (a - 1));
    220 }
    221 
    222 static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a)
    223 {
    224     return (unsigned char)constant_time_is_zero(a);
    225 }
    226 
    227 static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a)
    228 {
    229     return constant_time_msb_32(~a & (a - 1));
    230 }
    231 
    232 static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a)
    233 {
    234     return constant_time_msb_64(~a & (a - 1));
    235 }
    236 
    237 static ossl_inline unsigned int constant_time_eq(unsigned int a,
    238     unsigned int b)
    239 {
    240     return constant_time_is_zero(a ^ b);
    241 }
    242 
    243 static ossl_inline size_t constant_time_eq_s(size_t a, size_t b)
    244 {
    245     return constant_time_is_zero_s(a ^ b);
    246 }
    247 
    248 static ossl_inline unsigned char constant_time_eq_8(unsigned int a,
    249     unsigned int b)
    250 {
    251     return (unsigned char)constant_time_eq(a, b);
    252 }
    253 
    254 static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b)
    255 {
    256     return (unsigned char)constant_time_eq_s(a, b);
    257 }
    258 
    259 static ossl_inline unsigned int constant_time_eq_int(int a, int b)
    260 {
    261     return constant_time_eq((unsigned)(a), (unsigned)(b));
    262 }
    263 
    264 static ossl_inline unsigned char constant_time_eq_int_8(int a, int b)
    265 {
    266     return constant_time_eq_8((unsigned)(a), (unsigned)(b));
    267 }
    268 
    269 /*
    270  * Returns the value unmodified, but avoids optimizations.
    271  * The barriers prevent the compiler from narrowing down the
    272  * possible value range of the mask and ~mask in the select
    273  * statements, which avoids the recognition of the select
    274  * and turning it into a conditional load or branch.
    275  */
    276 static ossl_inline unsigned int value_barrier(unsigned int a)
    277 {
    278 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
    279     unsigned int r;
    280     __asm__("" : "=r"(r) : "0"(a));
    281 #else
    282     volatile unsigned int r = a;
    283 #endif
    284     return r;
    285 }
    286 
    287 /* Convenience method for uint32_t. */
    288 static ossl_inline uint32_t value_barrier_32(uint32_t a)
    289 {
    290 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
    291     uint32_t r;
    292     __asm__("" : "=r"(r) : "0"(a));
    293 #else
    294     volatile uint32_t r = a;
    295 #endif
    296     return r;
    297 }
    298 
    299 /* Convenience method for uint64_t. */
    300 static ossl_inline uint64_t value_barrier_64(uint64_t a)
    301 {
    302 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
    303     uint64_t r;
    304     __asm__("" : "=r"(r) : "0"(a));
    305 #else
    306     volatile uint64_t r = a;
    307 #endif
    308     return r;
    309 }
    310 
    311 /* Convenience method for size_t. */
    312 static ossl_inline size_t value_barrier_s(size_t a)
    313 {
    314 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
    315     size_t r;
    316     __asm__("" : "=r"(r) : "0"(a));
    317 #else
    318     volatile size_t r = a;
    319 #endif
    320     return r;
    321 }
    322 
    323 /* Convenience method for unsigned char. */
    324 static ossl_inline unsigned char value_barrier_8(unsigned char a)
    325 {
    326 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__)
    327     unsigned char r;
    328     __asm__("" : "=r"(r) : "0"(a));
    329 #else
    330     volatile unsigned char r = a;
    331 #endif
    332     return r;
    333 }
    334 
    335 static ossl_inline unsigned int constant_time_select(unsigned int mask,
    336     unsigned int a,
    337     unsigned int b)
    338 {
    339     return (value_barrier(mask) & a) | (value_barrier(~mask) & b);
    340 }
    341 
    342 static ossl_inline size_t constant_time_select_s(size_t mask,
    343     size_t a,
    344     size_t b)
    345 {
    346     return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);
    347 }
    348 
    349 static ossl_inline unsigned char constant_time_select_8(unsigned char mask,
    350     unsigned char a,
    351     unsigned char b)
    352 {
    353     return (unsigned char)constant_time_select(mask, a, b);
    354 }
    355 
    356 static ossl_inline int constant_time_select_int(unsigned int mask, int a,
    357     int b)
    358 {
    359     return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b));
    360 }
    361 
    362 static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b)
    363 {
    364     return (int)constant_time_select((unsigned)mask, (unsigned)(a),
    365         (unsigned)(b));
    366 }
    367 
    368 static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a,
    369     uint32_t b)
    370 {
    371     return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b);
    372 }
    373 
    374 static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a,
    375     uint64_t b)
    376 {
    377     return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b);
    378 }
    379 
    380 /*
    381  * mask must be 0xFFFFFFFF or 0x00000000.
    382  *
    383  * if (mask) {
    384  *     uint32_t tmp = *a;
    385  *
    386  *     *a = *b;
    387  *     *b = tmp;
    388  * }
    389  */
    390 static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a,
    391     uint32_t *b)
    392 {
    393     uint32_t xor = *a ^ *b;
    394 
    395     xor&= value_barrier_32(mask);
    396     *a ^= xor;
    397     *b ^= xor;
    398 }
    399 
    400 /*
    401  * mask must be 0xFFFFFFFF or 0x00000000.
    402  *
    403  * if (mask) {
    404  *     uint64_t tmp = *a;
    405  *
    406  *     *a = *b;
    407  *     *b = tmp;
    408  * }
    409  */
    410 static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a,
    411     uint64_t *b)
    412 {
    413     uint64_t xor = *a ^ *b;
    414 
    415     xor&= value_barrier_64(mask);
    416     *a ^= xor;
    417     *b ^= xor;
    418 }
    419 
    420 /*
    421  * mask must be 0xFF or 0x00.
    422  * "constant time" is per len.
    423  *
    424  * if (mask) {
    425  *     unsigned char tmp[len];
    426  *
    427  *     memcpy(tmp, a, len);
    428  *     memcpy(a, b);
    429  *     memcpy(b, tmp);
    430  * }
    431  */
    432 static ossl_inline void constant_time_cond_swap_buff(unsigned char mask,
    433     unsigned char *a,
    434     unsigned char *b,
    435     size_t len)
    436 {
    437     size_t i;
    438     unsigned char tmp;
    439 
    440     for (i = 0; i < len; i++) {
    441         tmp = a[i] ^ b[i];
    442         tmp &= value_barrier_8(mask);
    443         a[i] ^= tmp;
    444         b[i] ^= tmp;
    445     }
    446 }
    447 
    448 /*
    449  * table is a two dimensional array of bytes. Each row has rowsize elements.
    450  * Copies row number idx into out. rowsize and numrows are not considered
    451  * private.
    452  */
    453 static ossl_inline void constant_time_lookup(void *out,
    454     const void *table,
    455     size_t rowsize,
    456     size_t numrows,
    457     size_t idx)
    458 {
    459     size_t i, j;
    460     const unsigned char *tablec = (const unsigned char *)table;
    461     unsigned char *outc = (unsigned char *)out;
    462     unsigned char mask;
    463 
    464     memset(out, 0, rowsize);
    465 
    466     /* Note idx may underflow - but that is well defined */
    467     for (i = 0; i < numrows; i++, idx--) {
    468         mask = (unsigned char)constant_time_is_zero_s(idx);
    469         for (j = 0; j < rowsize; j++)
    470             *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0);
    471     }
    472 }
    473 
    474 /*
    475  * Expected usage pattern is to unconditionally set error and then
    476  * wipe it if there was no actual error. |clear| is 1 or 0.
    477  */
    478 void err_clear_last_constant_time(int clear);
    479 
    480 #endif /* OSSL_INTERNAL_CONSTANT_TIME_H */
    481