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