| gabor-mezei-arm | d112534 | 2021-07-12 16:31:22 +0200 | [diff] [blame] | 1 | /** | 
|  | 2 | *  Constant-time functions | 
|  | 3 | * | 
|  | 4 | *  Copyright The Mbed TLS Contributors | 
| Dave Rodgman | 16799db | 2023-11-02 19:47:20 +0000 | [diff] [blame] | 5 | *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | 
| gabor-mezei-arm | d112534 | 2021-07-12 16:31:22 +0200 | [diff] [blame] | 6 | */ | 
|  | 7 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 8 | /* | 
| Gabor Mezei | 642eeb2 | 2021-11-03 16:13:32 +0100 | [diff] [blame] | 9 | * The following functions are implemented without using comparison operators, as those | 
| Gabor Mezei | eab90bc | 2021-10-18 16:09:41 +0200 | [diff] [blame] | 10 | * might be translated to branches by some compilers on some platforms. | 
|  | 11 | */ | 
|  | 12 |  | 
| Dave Rodgman | 4f26770 | 2023-09-11 19:05:51 +0100 | [diff] [blame] | 13 | #include <stdint.h> | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 14 | #include <limits.h> | 
|  | 15 |  | 
| gabor-mezei-arm | d112534 | 2021-07-12 16:31:22 +0200 | [diff] [blame] | 16 | #include "common.h" | 
| Gabor Mezei | 22c9a6f | 2021-10-20 12:09:35 +0200 | [diff] [blame] | 17 | #include "constant_time_internal.h" | 
| Gabor Mezei | 765862c | 2021-10-19 12:22:25 +0200 | [diff] [blame] | 18 | #include "mbedtls/constant_time.h" | 
| gabor-mezei-arm | 1349ffd | 2021-09-27 14:28:31 +0200 | [diff] [blame] | 19 | #include "mbedtls/error.h" | 
| gabor-mezei-arm | 5b3a32d | 2021-09-29 10:50:31 +0200 | [diff] [blame] | 20 | #include "mbedtls/platform_util.h" | 
| gabor-mezei-arm | db9a38c | 2021-09-27 11:28:54 +0200 | [diff] [blame] | 21 |  | 
| gabor-mezei-arm | fdb7118 | 2021-09-27 16:11:12 +0200 | [diff] [blame] | 22 | #include <string.h> | 
| Andrzej Kurek | 1c7a998 | 2023-05-30 09:21:20 -0400 | [diff] [blame] | 23 |  | 
| Dave Rodgman | 58c80f4 | 2023-06-12 18:19:46 +0100 | [diff] [blame] | 24 | #if !defined(MBEDTLS_CT_ASM) | 
|  | 25 | /* | 
| Dave Rodgman | 1ab0b48 | 2023-06-12 18:22:18 +0100 | [diff] [blame] | 26 | * Define an object with the value zero, such that the compiler cannot prove that it | 
|  | 27 | * has the value zero (because it is volatile, it "may be modified in ways unknown to | 
|  | 28 | * the implementation"). | 
|  | 29 | */ | 
| Dave Rodgman | 58c80f4 | 2023-06-12 18:19:46 +0100 | [diff] [blame] | 30 | volatile mbedtls_ct_uint_t mbedtls_ct_zero = 0; | 
|  | 31 | #endif | 
|  | 32 |  | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 33 | /* | 
| Dave Rodgman | 051225d | 2022-12-30 21:25:35 +0000 | [diff] [blame] | 34 | * Define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS where assembly is present to | 
|  | 35 | * perform fast unaligned access to volatile data. | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 36 | * | 
|  | 37 | * This is needed because mbedtls_get_unaligned_uintXX etc don't support volatile | 
|  | 38 | * memory accesses. | 
|  | 39 | * | 
| Dave Rodgman | 051225d | 2022-12-30 21:25:35 +0000 | [diff] [blame] | 40 | * Some of these definitions could be moved into alignment.h but for now they are | 
|  | 41 | * only used here. | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 42 | */ | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 43 | #if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && \ | 
| Dave Rodgman | 9fbb0cf | 2023-06-28 18:52:02 +0100 | [diff] [blame] | 44 | ((defined(MBEDTLS_CT_ARM_ASM) && (UINTPTR_MAX == 0xfffffffful)) || \ | 
|  | 45 | defined(MBEDTLS_CT_AARCH64_ASM)) | 
| Dave Rodgman | 63e89b4 | 2023-06-21 11:55:17 +0100 | [diff] [blame] | 46 | /* We check pointer sizes to avoid issues with them not matching register size requirements */ | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 47 | #define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS | 
|  | 48 |  | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 49 | static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsigned char *p) | 
|  | 50 | { | 
|  | 51 | /* This is UB, even where it's safe: | 
|  | 52 | *    return *((volatile uint32_t*)p); | 
|  | 53 | * so instead the same thing is expressed in assembly below. | 
|  | 54 | */ | 
|  | 55 | uint32_t r; | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 56 | #if defined(MBEDTLS_CT_ARM_ASM) | 
| Antonio de Angelis | f1adc2a | 2023-08-16 12:31:54 +0100 | [diff] [blame] | 57 | asm volatile ("ldr %0, [%1]" : "=r" (r) : "r" (p) :); | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 58 | #elif defined(MBEDTLS_CT_AARCH64_ASM) | 
| Dave Rodgman | 5b5dd01 | 2023-06-21 16:36:47 +0100 | [diff] [blame] | 59 | asm volatile ("ldr %w0, [%1]" : "=r" (r) : MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT(p) :); | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 60 | #else | 
| Antonio de Angelis | 1ee4d12 | 2023-08-16 12:26:37 +0100 | [diff] [blame] | 61 | #error "No assembly defined for mbedtls_get_unaligned_volatile_uint32" | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 62 | #endif | 
| Dave Rodgman | 051225d | 2022-12-30 21:25:35 +0000 | [diff] [blame] | 63 | return r; | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 64 | } | 
| Dave Rodgman | 40a41d0 | 2023-05-17 11:59:56 +0100 | [diff] [blame] | 65 | #endif /* defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && | 
|  | 66 | (defined(MBEDTLS_CT_ARM_ASM) || defined(MBEDTLS_CT_AARCH64_ASM)) */ | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 67 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 68 | int mbedtls_ct_memcmp(const void *a, | 
|  | 69 | const void *b, | 
|  | 70 | size_t n) | 
| gabor-mezei-arm | db9a38c | 2021-09-27 11:28:54 +0200 | [diff] [blame] | 71 | { | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 72 | size_t i = 0; | 
| Dave Rodgman | 7658b63 | 2023-01-11 17:39:33 +0000 | [diff] [blame] | 73 | /* | 
|  | 74 | * `A` and `B` are cast to volatile to ensure that the compiler | 
|  | 75 | * generates code that always fully reads both buffers. | 
|  | 76 | * Otherwise it could generate a test to exit early if `diff` has all | 
|  | 77 | * bits set early in the loop. | 
|  | 78 | */ | 
| gabor-mezei-arm | db9a38c | 2021-09-27 11:28:54 +0200 | [diff] [blame] | 79 | volatile const unsigned char *A = (volatile const unsigned char *) a; | 
|  | 80 | volatile const unsigned char *B = (volatile const unsigned char *) b; | 
| Dave Rodgman | 7658b63 | 2023-01-11 17:39:33 +0000 | [diff] [blame] | 81 | uint32_t diff = 0; | 
| gabor-mezei-arm | db9a38c | 2021-09-27 11:28:54 +0200 | [diff] [blame] | 82 |  | 
| Dave Rodgman | 051225d | 2022-12-30 21:25:35 +0000 | [diff] [blame] | 83 | #if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS) | 
| Dave Rodgman | 36dfc5a | 2022-12-22 15:04:43 +0000 | [diff] [blame] | 84 | for (; (i + 4) <= n; i += 4) { | 
|  | 85 | uint32_t x = mbedtls_get_unaligned_volatile_uint32(A + i); | 
|  | 86 | uint32_t y = mbedtls_get_unaligned_volatile_uint32(B + i); | 
|  | 87 | diff |= x ^ y; | 
|  | 88 | } | 
|  | 89 | #endif | 
|  | 90 |  | 
|  | 91 | for (; i < n; i++) { | 
| gabor-mezei-arm | db9a38c | 2021-09-27 11:28:54 +0200 | [diff] [blame] | 92 | /* Read volatile data in order before computing diff. | 
|  | 93 | * This avoids IAR compiler warning: | 
|  | 94 | * 'the order of volatile accesses is undefined ..' */ | 
|  | 95 | unsigned char x = A[i], y = B[i]; | 
|  | 96 | diff |= x ^ y; | 
|  | 97 | } | 
|  | 98 |  | 
| Dave Rodgman | 98926d5 | 2023-09-12 09:29:33 +0100 | [diff] [blame] | 99 |  | 
| Dave Rodgman | 50b0a35 | 2023-09-12 09:30:44 +0100 | [diff] [blame] | 100 | #if (INT_MAX < INT32_MAX) | 
| Dave Rodgman | 98926d5 | 2023-09-12 09:29:33 +0100 | [diff] [blame] | 101 | /* We don't support int smaller than 32-bits, but if someone tried to build | 
|  | 102 | * with this configuration, there is a risk that, for differing data, the | 
|  | 103 | * only bits set in diff are in the top 16-bits, and would be lost by a | 
|  | 104 | * simple cast from uint32 to int. | 
|  | 105 | * This would have significant security implications, so protect against it. */ | 
|  | 106 | #error "mbedtls_ct_memcmp() requires minimum 32-bit ints" | 
| Dave Rodgman | 4f26770 | 2023-09-11 19:05:51 +0100 | [diff] [blame] | 107 | #else | 
| Dave Rodgman | bd58944 | 2023-09-12 12:38:53 +0100 | [diff] [blame] | 108 | /* The bit-twiddling ensures that when we cast uint32_t to int, we are casting | 
|  | 109 | * a value that is in the range 0..INT_MAX - a value larger than this would | 
|  | 110 | * result in implementation defined behaviour. | 
|  | 111 | * | 
|  | 112 | * This ensures that the value returned by the function is non-zero iff | 
|  | 113 | * diff is non-zero. | 
|  | 114 | */ | 
|  | 115 | return (int) ((diff & 0xffff) | (diff >> 16)); | 
| Dave Rodgman | 4f26770 | 2023-09-11 19:05:51 +0100 | [diff] [blame] | 116 | #endif | 
| gabor-mezei-arm | db9a38c | 2021-09-27 11:28:54 +0200 | [diff] [blame] | 117 | } | 
|  | 118 |  | 
| Dave Rodgman | 9c14007 | 2023-09-18 18:20:27 +0100 | [diff] [blame] | 119 | #if defined(MBEDTLS_NIST_KW_C) | 
|  | 120 |  | 
|  | 121 | int mbedtls_ct_memcmp_partial(const void *a, | 
|  | 122 | const void *b, | 
|  | 123 | size_t n, | 
|  | 124 | size_t skip_head, | 
|  | 125 | size_t skip_tail) | 
|  | 126 | { | 
|  | 127 | unsigned int diff = 0; | 
|  | 128 |  | 
|  | 129 | volatile const unsigned char *A = (volatile const unsigned char *) a; | 
|  | 130 | volatile const unsigned char *B = (volatile const unsigned char *) b; | 
|  | 131 |  | 
|  | 132 | size_t valid_end = n - skip_tail; | 
|  | 133 |  | 
|  | 134 | for (size_t i = 0; i < n; i++) { | 
|  | 135 | unsigned char x = A[i], y = B[i]; | 
| Dave Rodgman | c2630fa | 2023-09-19 14:13:41 +0100 | [diff] [blame] | 136 | unsigned int d = x ^ y; | 
| Dave Rodgman | 9c14007 | 2023-09-18 18:20:27 +0100 | [diff] [blame] | 137 | mbedtls_ct_condition_t valid = mbedtls_ct_bool_and(mbedtls_ct_uint_ge(i, skip_head), | 
|  | 138 | mbedtls_ct_uint_lt(i, valid_end)); | 
|  | 139 | diff |= mbedtls_ct_uint_if_else_0(valid, d); | 
|  | 140 | } | 
|  | 141 |  | 
| Dave Rodgman | c2630fa | 2023-09-19 14:13:41 +0100 | [diff] [blame] | 142 | /* Since we go byte-by-byte, the only bits set will be in the bottom 8 bits, so the | 
|  | 143 | * cast from uint to int is safe. */ | 
|  | 144 | return (int) diff; | 
| Dave Rodgman | 9c14007 | 2023-09-18 18:20:27 +0100 | [diff] [blame] | 145 | } | 
|  | 146 |  | 
|  | 147 | #endif | 
|  | 148 |  | 
| Gabor Mezei | e212379 | 2021-10-18 17:05:06 +0200 | [diff] [blame] | 149 | #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) | 
|  | 150 |  | 
| Dave Rodgman | 15c142b | 2023-05-17 12:20:11 +0100 | [diff] [blame] | 151 | void mbedtls_ct_memmove_left(void *start, size_t total, size_t offset) | 
| gabor-mezei-arm | 394aeaa | 2021-09-27 13:31:06 +0200 | [diff] [blame] | 152 | { | 
| Dave Rodgman | 1714a9b | 2023-07-31 12:37:01 +0100 | [diff] [blame] | 153 | volatile unsigned char *buf = start; | 
| Dave Rodgman | 15c142b | 2023-05-17 12:20:11 +0100 | [diff] [blame] | 154 | for (size_t i = 0; i < total; i++) { | 
| Dave Rodgman | b7825ce | 2023-08-10 11:58:18 +0100 | [diff] [blame] | 155 | mbedtls_ct_condition_t no_op = mbedtls_ct_uint_gt(total - offset, i); | 
| Dave Rodgman | 1714a9b | 2023-07-31 12:37:01 +0100 | [diff] [blame] | 156 | /* The first `total - offset` passes are a no-op. The last | 
|  | 157 | * `offset` passes shift the data one byte to the left and | 
|  | 158 | * zero out the last byte. */ | 
|  | 159 | for (size_t n = 0; n < total - 1; n++) { | 
|  | 160 | unsigned char current = buf[n]; | 
|  | 161 | unsigned char next    = buf[n+1]; | 
|  | 162 | buf[n] = mbedtls_ct_uint_if(no_op, current, next); | 
|  | 163 | } | 
| Dave Rodgman | 98ddc01 | 2023-08-10 12:11:31 +0100 | [diff] [blame] | 164 | buf[total-1] = mbedtls_ct_uint_if_else_0(no_op, buf[total-1]); | 
| gabor-mezei-arm | 394aeaa | 2021-09-27 13:31:06 +0200 | [diff] [blame] | 165 | } | 
|  | 166 | } | 
| gabor-mezei-arm | dee0fd3 | 2021-09-27 13:34:25 +0200 | [diff] [blame] | 167 |  | 
| Gabor Mezei | e212379 | 2021-10-18 17:05:06 +0200 | [diff] [blame] | 168 | #endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */ | 
|  | 169 |  | 
| Dave Rodgman | 7fe6e6f | 2023-05-17 12:34:56 +0100 | [diff] [blame] | 170 | void mbedtls_ct_memcpy_if(mbedtls_ct_condition_t condition, | 
|  | 171 | unsigned char *dest, | 
|  | 172 | const unsigned char *src1, | 
|  | 173 | const unsigned char *src2, | 
|  | 174 | size_t len) | 
|  | 175 | { | 
| Dave Rodgman | 42391b4 | 2023-05-19 10:33:21 +0100 | [diff] [blame] | 176 | #if defined(MBEDTLS_CT_SIZE_64) | 
|  | 177 | const uint64_t mask     = (uint64_t) condition; | 
|  | 178 | const uint64_t not_mask = (uint64_t) ~mbedtls_ct_compiler_opaque(condition); | 
|  | 179 | #else | 
| Dave Rodgman | 7fe6e6f | 2023-05-17 12:34:56 +0100 | [diff] [blame] | 180 | const uint32_t mask     = (uint32_t) condition; | 
|  | 181 | const uint32_t not_mask = (uint32_t) ~mbedtls_ct_compiler_opaque(condition); | 
| Dave Rodgman | 42391b4 | 2023-05-19 10:33:21 +0100 | [diff] [blame] | 182 | #endif | 
| Dave Rodgman | 7fe6e6f | 2023-05-17 12:34:56 +0100 | [diff] [blame] | 183 |  | 
| Dave Rodgman | 07f8537 | 2023-07-31 12:27:49 +0100 | [diff] [blame] | 184 | /* If src2 is NULL, setup src2 so that we read from the destination address. | 
|  | 185 | * | 
|  | 186 | * This means that if src2 == NULL && condition is false, the result will be a | 
|  | 187 | * no-op because we read from dest and write the same data back into dest. | 
|  | 188 | */ | 
| Dave Rodgman | 7fe6e6f | 2023-05-17 12:34:56 +0100 | [diff] [blame] | 189 | if (src2 == NULL) { | 
|  | 190 | src2 = dest; | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | /* dest[i] = c1 == c2 ? src[i] : dest[i] */ | 
|  | 194 | size_t i = 0; | 
|  | 195 | #if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) | 
| Dave Rodgman | 42391b4 | 2023-05-19 10:33:21 +0100 | [diff] [blame] | 196 | #if defined(MBEDTLS_CT_SIZE_64) | 
|  | 197 | for (; (i + 8) <= len; i += 8) { | 
|  | 198 | uint64_t a = mbedtls_get_unaligned_uint64(src1 + i) & mask; | 
|  | 199 | uint64_t b = mbedtls_get_unaligned_uint64(src2 + i) & not_mask; | 
|  | 200 | mbedtls_put_unaligned_uint64(dest + i, a | b); | 
|  | 201 | } | 
|  | 202 | #else | 
| Dave Rodgman | 7fe6e6f | 2023-05-17 12:34:56 +0100 | [diff] [blame] | 203 | for (; (i + 4) <= len; i += 4) { | 
|  | 204 | uint32_t a = mbedtls_get_unaligned_uint32(src1 + i) & mask; | 
|  | 205 | uint32_t b = mbedtls_get_unaligned_uint32(src2 + i) & not_mask; | 
|  | 206 | mbedtls_put_unaligned_uint32(dest + i, a | b); | 
|  | 207 | } | 
| Dave Rodgman | 42391b4 | 2023-05-19 10:33:21 +0100 | [diff] [blame] | 208 | #endif /* defined(MBEDTLS_CT_SIZE_64) */ | 
| Dave Rodgman | 7fe6e6f | 2023-05-17 12:34:56 +0100 | [diff] [blame] | 209 | #endif /* MBEDTLS_EFFICIENT_UNALIGNED_ACCESS */ | 
|  | 210 | for (; i < len; i++) { | 
|  | 211 | dest[i] = (src1[i] & mask) | (src2[i] & not_mask); | 
|  | 212 | } | 
|  | 213 | } | 
|  | 214 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 215 | void mbedtls_ct_memcpy_offset(unsigned char *dest, | 
|  | 216 | const unsigned char *src, | 
|  | 217 | size_t offset, | 
|  | 218 | size_t offset_min, | 
|  | 219 | size_t offset_max, | 
|  | 220 | size_t len) | 
| gabor-mezei-arm | 0e7f71e | 2021-09-27 13:57:45 +0200 | [diff] [blame] | 221 | { | 
| Gabor Mezei | 63bbba5 | 2021-10-18 16:17:57 +0200 | [diff] [blame] | 222 | size_t offsetval; | 
| gabor-mezei-arm | 0e7f71e | 2021-09-27 13:57:45 +0200 | [diff] [blame] | 223 |  | 
| Gilles Peskine | 449bd83 | 2023-01-11 14:50:10 +0100 | [diff] [blame] | 224 | for (offsetval = offset_min; offsetval <= offset_max; offsetval++) { | 
| Dave Rodgman | b7825ce | 2023-08-10 11:58:18 +0100 | [diff] [blame] | 225 | mbedtls_ct_memcpy_if(mbedtls_ct_uint_eq(offsetval, offset), dest, src + offsetval, NULL, | 
| Dave Rodgman | 585f7f7 | 2023-05-17 17:45:33 +0100 | [diff] [blame] | 226 | len); | 
| gabor-mezei-arm | 0e7f71e | 2021-09-27 13:57:45 +0200 | [diff] [blame] | 227 | } | 
|  | 228 | } | 
| gabor-mezei-arm | 1349ffd | 2021-09-27 14:28:31 +0200 | [diff] [blame] | 229 |  | 
| Dave Rodgman | debf867 | 2023-05-17 12:12:44 +0100 | [diff] [blame] | 230 | #if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) | 
|  | 231 |  | 
|  | 232 | void mbedtls_ct_zeroize_if(mbedtls_ct_condition_t condition, void *buf, size_t len) | 
|  | 233 | { | 
|  | 234 | uint32_t mask = (uint32_t) ~condition; | 
|  | 235 | uint8_t *p = (uint8_t *) buf; | 
|  | 236 | size_t i = 0; | 
|  | 237 | #if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) | 
|  | 238 | for (; (i + 4) <= len; i += 4) { | 
|  | 239 | mbedtls_put_unaligned_uint32((void *) (p + i), | 
|  | 240 | mbedtls_get_unaligned_uint32((void *) (p + i)) & mask); | 
|  | 241 | } | 
|  | 242 | #endif | 
|  | 243 | for (; i < len; i++) { | 
|  | 244 | p[i] = p[i] & mask; | 
|  | 245 | } | 
|  | 246 | } | 
|  | 247 |  | 
|  | 248 | #endif /* defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT) */ |