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 103 static ossl_inline unsigned int constant_time_msb(unsigned int a) 104 { 105 return 0 - (a >> (sizeof(a) * 8 - 1)); 106 } 107 108 109 static ossl_inline uint32_t constant_time_msb_32(uint32_t a) 110 { 111 return 0 - (a >> 31); 112 } 113 114 static ossl_inline uint64_t constant_time_msb_64(uint64_t a) 115 { 116 return 0 - (a >> 63); 117 } 118 119 static ossl_inline size_t constant_time_msb_s(size_t a) 120 { 121 return 0 - (a >> (sizeof(a) * 8 - 1)); 122 } 123 124 static ossl_inline unsigned int constant_time_lt(unsigned int a, 125 unsigned int b) 126 { 127 return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b))); 128 } 129 130 static ossl_inline size_t constant_time_lt_s(size_t a, size_t b) 131 { 132 return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b))); 133 } 134 135 static ossl_inline unsigned char constant_time_lt_8(unsigned int a, 136 unsigned int b) 137 { 138 return (unsigned char)constant_time_lt(a, b); 139 } 140 141 static ossl_inline uint32_t constant_time_lt_32(uint32_t a, uint32_t b) 142 { 143 return constant_time_msb_32(a ^ ((a ^ b) | ((a - b) ^ b))); 144 } 145 146 static ossl_inline uint64_t constant_time_lt_64(uint64_t a, uint64_t b) 147 { 148 return constant_time_msb_64(a ^ ((a ^ b) | ((a - b) ^ b))); 149 } 150 151 #ifdef BN_ULONG 152 static ossl_inline BN_ULONG value_barrier_bn(BN_ULONG a) 153 { 154 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 155 BN_ULONG r; 156 __asm__("" : "=r"(r) : "0"(a)); 157 #else 158 volatile BN_ULONG r = a; 159 #endif 160 return r; 161 } 162 163 static ossl_inline BN_ULONG constant_time_msb_bn(BN_ULONG a) 164 { 165 return 0 - (a >> (sizeof(a) * 8 - 1)); 166 } 167 168 static ossl_inline BN_ULONG constant_time_lt_bn(BN_ULONG a, BN_ULONG b) 169 { 170 return constant_time_msb_bn(a ^ ((a ^ b) | ((a - b) ^ b))); 171 } 172 173 static ossl_inline BN_ULONG constant_time_is_zero_bn(BN_ULONG a) 174 { 175 return constant_time_msb_bn(~a & (a - 1)); 176 } 177 178 static ossl_inline BN_ULONG constant_time_eq_bn(BN_ULONG a, 179 BN_ULONG b) 180 { 181 return constant_time_is_zero_bn(a ^ b); 182 } 183 184 static ossl_inline BN_ULONG constant_time_select_bn(BN_ULONG mask, 185 BN_ULONG a, 186 BN_ULONG b) 187 { 188 return (value_barrier_bn(mask) & a) | (value_barrier_bn(~mask) & b); 189 } 190 #endif 191 192 static ossl_inline unsigned int constant_time_ge(unsigned int a, 193 unsigned int b) 194 { 195 return ~constant_time_lt(a, b); 196 } 197 198 static ossl_inline size_t constant_time_ge_s(size_t a, size_t b) 199 { 200 return ~constant_time_lt_s(a, b); 201 } 202 203 static ossl_inline unsigned char constant_time_ge_8(unsigned int a, 204 unsigned int b) 205 { 206 return (unsigned char)constant_time_ge(a, b); 207 } 208 209 static ossl_inline unsigned char constant_time_ge_8_s(size_t a, size_t b) 210 { 211 return (unsigned char)constant_time_ge_s(a, b); 212 } 213 214 static ossl_inline unsigned int constant_time_is_zero(unsigned int a) 215 { 216 return constant_time_msb(~a & (a - 1)); 217 } 218 219 static ossl_inline size_t constant_time_is_zero_s(size_t a) 220 { 221 return constant_time_msb_s(~a & (a - 1)); 222 } 223 224 static ossl_inline unsigned char constant_time_is_zero_8(unsigned int a) 225 { 226 return (unsigned char)constant_time_is_zero(a); 227 } 228 229 static ossl_inline uint32_t constant_time_is_zero_32(uint32_t a) 230 { 231 return constant_time_msb_32(~a & (a - 1)); 232 } 233 234 static ossl_inline uint64_t constant_time_is_zero_64(uint64_t a) 235 { 236 return constant_time_msb_64(~a & (a - 1)); 237 } 238 239 static ossl_inline unsigned int constant_time_eq(unsigned int a, 240 unsigned int b) 241 { 242 return constant_time_is_zero(a ^ b); 243 } 244 245 static ossl_inline size_t constant_time_eq_s(size_t a, size_t b) 246 { 247 return constant_time_is_zero_s(a ^ b); 248 } 249 250 static ossl_inline unsigned char constant_time_eq_8(unsigned int a, 251 unsigned int b) 252 { 253 return (unsigned char)constant_time_eq(a, b); 254 } 255 256 static ossl_inline unsigned char constant_time_eq_8_s(size_t a, size_t b) 257 { 258 return (unsigned char)constant_time_eq_s(a, b); 259 } 260 261 static ossl_inline unsigned int constant_time_eq_int(int a, int b) 262 { 263 return constant_time_eq((unsigned)(a), (unsigned)(b)); 264 } 265 266 static ossl_inline unsigned char constant_time_eq_int_8(int a, int b) 267 { 268 return constant_time_eq_8((unsigned)(a), (unsigned)(b)); 269 } 270 271 /* 272 * Returns the value unmodified, but avoids optimizations. 273 * The barriers prevent the compiler from narrowing down the 274 * possible value range of the mask and ~mask in the select 275 * statements, which avoids the recognition of the select 276 * and turning it into a conditional load or branch. 277 */ 278 static ossl_inline unsigned int value_barrier(unsigned int a) 279 { 280 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 281 unsigned int r; 282 __asm__("" : "=r"(r) : "0"(a)); 283 #else 284 volatile unsigned int r = a; 285 #endif 286 return r; 287 } 288 289 /* Convenience method for uint32_t. */ 290 static ossl_inline uint32_t value_barrier_32(uint32_t a) 291 { 292 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 293 uint32_t r; 294 __asm__("" : "=r"(r) : "0"(a)); 295 #else 296 volatile uint32_t r = a; 297 #endif 298 return r; 299 } 300 301 /* Convenience method for uint64_t. */ 302 static ossl_inline uint64_t value_barrier_64(uint64_t a) 303 { 304 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 305 uint64_t r; 306 __asm__("" : "=r"(r) : "0"(a)); 307 #else 308 volatile uint64_t r = a; 309 #endif 310 return r; 311 } 312 313 /* Convenience method for size_t. */ 314 static ossl_inline size_t value_barrier_s(size_t a) 315 { 316 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 317 size_t r; 318 __asm__("" : "=r"(r) : "0"(a)); 319 #else 320 volatile size_t r = a; 321 #endif 322 return r; 323 } 324 325 /* Convenience method for unsigned char. */ 326 static ossl_inline unsigned char value_barrier_8(unsigned char a) 327 { 328 #if !defined(OPENSSL_NO_ASM) && defined(__GNUC__) 329 unsigned char r; 330 __asm__("" : "=r"(r) : "0"(a)); 331 #else 332 volatile unsigned char r = a; 333 #endif 334 return r; 335 } 336 337 static ossl_inline unsigned int constant_time_select(unsigned int mask, 338 unsigned int a, 339 unsigned int b) 340 { 341 return (value_barrier(mask) & a) | (value_barrier(~mask) & b); 342 } 343 344 static ossl_inline size_t constant_time_select_s(size_t mask, 345 size_t a, 346 size_t b) 347 { 348 return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b); 349 } 350 351 static ossl_inline unsigned char constant_time_select_8(unsigned char mask, 352 unsigned char a, 353 unsigned char b) 354 { 355 return (unsigned char)constant_time_select(mask, a, b); 356 } 357 358 static ossl_inline int constant_time_select_int(unsigned int mask, int a, 359 int b) 360 { 361 return (int)constant_time_select(mask, (unsigned)(a), (unsigned)(b)); 362 } 363 364 static ossl_inline int constant_time_select_int_s(size_t mask, int a, int b) 365 { 366 return (int)constant_time_select((unsigned)mask, (unsigned)(a), 367 (unsigned)(b)); 368 } 369 370 static ossl_inline uint32_t constant_time_select_32(uint32_t mask, uint32_t a, 371 uint32_t b) 372 { 373 return (value_barrier_32(mask) & a) | (value_barrier_32(~mask) & b); 374 } 375 376 static ossl_inline uint64_t constant_time_select_64(uint64_t mask, uint64_t a, 377 uint64_t b) 378 { 379 return (value_barrier_64(mask) & a) | (value_barrier_64(~mask) & b); 380 } 381 382 /* 383 * mask must be 0xFFFFFFFF or 0x00000000. 384 * 385 * if (mask) { 386 * uint32_t tmp = *a; 387 * 388 * *a = *b; 389 * *b = tmp; 390 * } 391 */ 392 static ossl_inline void constant_time_cond_swap_32(uint32_t mask, uint32_t *a, 393 uint32_t *b) 394 { 395 uint32_t xor = *a ^ *b; 396 397 xor &= value_barrier_32(mask); 398 *a ^= xor; 399 *b ^= xor; 400 } 401 402 /* 403 * mask must be 0xFFFFFFFF or 0x00000000. 404 * 405 * if (mask) { 406 * uint64_t tmp = *a; 407 * 408 * *a = *b; 409 * *b = tmp; 410 * } 411 */ 412 static ossl_inline void constant_time_cond_swap_64(uint64_t mask, uint64_t *a, 413 uint64_t *b) 414 { 415 uint64_t xor = *a ^ *b; 416 417 xor &= value_barrier_64(mask); 418 *a ^= xor; 419 *b ^= xor; 420 } 421 422 /* 423 * mask must be 0xFF or 0x00. 424 * "constant time" is per len. 425 * 426 * if (mask) { 427 * unsigned char tmp[len]; 428 * 429 * memcpy(tmp, a, len); 430 * memcpy(a, b); 431 * memcpy(b, tmp); 432 * } 433 */ 434 static ossl_inline void constant_time_cond_swap_buff(unsigned char mask, 435 unsigned char *a, 436 unsigned char *b, 437 size_t len) 438 { 439 size_t i; 440 unsigned char tmp; 441 442 for (i = 0; i < len; i++) { 443 tmp = a[i] ^ b[i]; 444 tmp &= value_barrier_8(mask); 445 a[i] ^= tmp; 446 b[i] ^= tmp; 447 } 448 } 449 450 /* 451 * table is a two dimensional array of bytes. Each row has rowsize elements. 452 * Copies row number idx into out. rowsize and numrows are not considered 453 * private. 454 */ 455 static ossl_inline void constant_time_lookup(void *out, 456 const void *table, 457 size_t rowsize, 458 size_t numrows, 459 size_t idx) 460 { 461 size_t i, j; 462 const unsigned char *tablec = (const unsigned char *)table; 463 unsigned char *outc = (unsigned char *)out; 464 unsigned char mask; 465 466 memset(out, 0, rowsize); 467 468 /* Note idx may underflow - but that is well defined */ 469 for (i = 0; i < numrows; i++, idx--) { 470 mask = (unsigned char)constant_time_is_zero_s(idx); 471 for (j = 0; j < rowsize; j++) 472 *(outc + j) |= constant_time_select_8(mask, *(tablec++), 0); 473 } 474 } 475 476 /* 477 * Expected usage pattern is to unconditionally set error and then 478 * wipe it if there was no actual error. |clear| is 1 or 0. 479 */ 480 void err_clear_last_constant_time(int clear); 481 482 #endif /* OSSL_INTERNAL_CONSTANT_TIME_H */ 483