blob: 16d7a1fc411bc3948b39c792b5fab99f84381c7f [file] [log] [blame]
gabor-mezei-armd1125342021-07-12 16:31:22 +02001/**
2 * Constant-time functions
3 *
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
Gilles Peskine449bd832023-01-11 14:50:10 +010020/*
Gabor Mezei642eeb22021-11-03 16:13:32 +010021 * The following functions are implemented without using comparison operators, as those
Gabor Mezeieab90bc2021-10-18 16:09:41 +020022 * might be translated to branches by some compilers on some platforms.
23 */
24
gabor-mezei-armd1125342021-07-12 16:31:22 +020025#include "common.h"
Gabor Mezei22c9a6f2021-10-20 12:09:35 +020026#include "constant_time_internal.h"
Gabor Mezei765862c2021-10-19 12:22:25 +020027#include "mbedtls/constant_time.h"
gabor-mezei-arm1349ffd2021-09-27 14:28:31 +020028#include "mbedtls/error.h"
gabor-mezei-arm5b3a32d2021-09-29 10:50:31 +020029#include "mbedtls/platform_util.h"
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +020030
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +020031#if defined(MBEDTLS_BIGNUM_C)
32#include "mbedtls/bignum.h"
Gabor Mezei87638a92022-09-15 20:02:36 +020033#include "bignum_core.h"
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +020034#endif
35
gabor-mezei-arm1349ffd2021-09-27 14:28:31 +020036#if defined(MBEDTLS_SSL_TLS_C)
37#include "ssl_misc.h"
38#endif
39
gabor-mezei-arm5b3a32d2021-09-29 10:50:31 +020040#if defined(MBEDTLS_RSA_C)
41#include "mbedtls/rsa.h"
42#endif
43
Gabor Mezei28d61152021-11-15 16:13:01 +010044#if defined(MBEDTLS_BASE64_C)
45#include "constant_time_invasive.h"
46#endif
47
gabor-mezei-armfdb71182021-09-27 16:11:12 +020048#include <string.h>
Andrzej Kurek8a045ce2022-12-23 11:00:06 -050049#if defined(MBEDTLS_USE_PSA_CRYPTO)
50#define PSA_TO_MBEDTLS_ERR(status) PSA_TO_MBEDTLS_ERR_LIST(status, \
51 psa_to_ssl_errors, \
52 psa_generic_status_to_mbedtls)
53#endif
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +020054
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000055/*
Dave Rodgman051225d2022-12-30 21:25:35 +000056 * Define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS where assembly is present to
57 * perform fast unaligned access to volatile data.
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000058 *
59 * This is needed because mbedtls_get_unaligned_uintXX etc don't support volatile
60 * memory accesses.
61 *
Dave Rodgman051225d2022-12-30 21:25:35 +000062 * Some of these definitions could be moved into alignment.h but for now they are
63 * only used here.
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000064 */
Dave Rodgman051225d2022-12-30 21:25:35 +000065#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS) && defined(MBEDTLS_HAVE_ASM)
66#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__) || defined(__aarch64__)
67#define MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS
68#endif
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000069#endif
70
Dave Rodgman051225d2022-12-30 21:25:35 +000071#if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS)
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000072static inline uint32_t mbedtls_get_unaligned_volatile_uint32(volatile const unsigned char *p)
73{
74 /* This is UB, even where it's safe:
75 * return *((volatile uint32_t*)p);
76 * so instead the same thing is expressed in assembly below.
77 */
78 uint32_t r;
79#if defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
Dave Rodgman4610d4b2023-01-30 09:26:48 +000080 asm volatile ("ldr %0, [%1]" : "=r" (r) : "r" (p) :);
Dave Rodgman051225d2022-12-30 21:25:35 +000081#elif defined(__aarch64__)
Dave Rodgman4610d4b2023-01-30 09:26:48 +000082 asm volatile ("ldr %w0, [%1]" : "=r" (r) : "r" (p) :);
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000083#endif
Dave Rodgman051225d2022-12-30 21:25:35 +000084 return r;
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000085}
Dave Rodgman051225d2022-12-30 21:25:35 +000086#endif /* MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS */
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000087
Gilles Peskine449bd832023-01-11 14:50:10 +010088int mbedtls_ct_memcmp(const void *a,
89 const void *b,
90 size_t n)
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +020091{
Dave Rodgman36dfc5a2022-12-22 15:04:43 +000092 size_t i = 0;
Dave Rodgman7658b632023-01-11 17:39:33 +000093 /*
94 * `A` and `B` are cast to volatile to ensure that the compiler
95 * generates code that always fully reads both buffers.
96 * Otherwise it could generate a test to exit early if `diff` has all
97 * bits set early in the loop.
98 */
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +020099 volatile const unsigned char *A = (volatile const unsigned char *) a;
100 volatile const unsigned char *B = (volatile const unsigned char *) b;
Dave Rodgman7658b632023-01-11 17:39:33 +0000101 uint32_t diff = 0;
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +0200102
Dave Rodgman051225d2022-12-30 21:25:35 +0000103#if defined(MBEDTLS_EFFICIENT_UNALIGNED_VOLATILE_ACCESS)
Dave Rodgman36dfc5a2022-12-22 15:04:43 +0000104 for (; (i + 4) <= n; i += 4) {
105 uint32_t x = mbedtls_get_unaligned_volatile_uint32(A + i);
106 uint32_t y = mbedtls_get_unaligned_volatile_uint32(B + i);
107 diff |= x ^ y;
108 }
109#endif
110
111 for (; i < n; i++) {
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +0200112 /* Read volatile data in order before computing diff.
113 * This avoids IAR compiler warning:
114 * 'the order of volatile accesses is undefined ..' */
115 unsigned char x = A[i], y = B[i];
116 diff |= x ^ y;
117 }
118
Gilles Peskine449bd832023-01-11 14:50:10 +0100119 return (int) diff;
gabor-mezei-armdb9a38c2021-09-27 11:28:54 +0200120}
121
Gilles Peskine449bd832023-01-11 14:50:10 +0100122unsigned mbedtls_ct_uint_mask(unsigned value)
gabor-mezei-arm340948e2021-09-27 11:40:03 +0200123{
124 /* MSVC has a warning about unary minus on unsigned, but this is
125 * well-defined and precisely what we want to do here */
126#if defined(_MSC_VER)
127#pragma warning( push )
128#pragma warning( disable : 4146 )
129#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100130 return -((value | -value) >> (sizeof(value) * 8 - 1));
gabor-mezei-arm340948e2021-09-27 11:40:03 +0200131#if defined(_MSC_VER)
132#pragma warning( pop )
133#endif
134}
gabor-mezei-arm3733bf82021-09-27 11:49:42 +0200135
Przemek Stekiel89ad6232022-09-27 13:36:12 +0200136#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
Gabor Mezei6a426c92021-10-20 11:17:43 +0200137
Gilles Peskine449bd832023-01-11 14:50:10 +0100138size_t mbedtls_ct_size_mask(size_t value)
gabor-mezei-arm3733bf82021-09-27 11:49:42 +0200139{
140 /* MSVC has a warning about unary minus on unsigned integer types,
141 * but this is well-defined and precisely what we want to do here. */
142#if defined(_MSC_VER)
143#pragma warning( push )
144#pragma warning( disable : 4146 )
145#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100146 return -((value | -value) >> (sizeof(value) * 8 - 1));
gabor-mezei-arm3733bf82021-09-27 11:49:42 +0200147#if defined(_MSC_VER)
148#pragma warning( pop )
149#endif
150}
gabor-mezei-armc76227d2021-09-27 11:53:54 +0200151
Przemek Stekiel89ad6232022-09-27 13:36:12 +0200152#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
Gabor Mezei6a426c92021-10-20 11:17:43 +0200153
gabor-mezei-arm9cb55692021-08-11 15:07:02 +0200154#if defined(MBEDTLS_BIGNUM_C)
155
Gilles Peskine449bd832023-01-11 14:50:10 +0100156mbedtls_mpi_uint mbedtls_ct_mpi_uint_mask(mbedtls_mpi_uint value)
gabor-mezei-arm9cb55692021-08-11 15:07:02 +0200157{
158 /* MSVC has a warning about unary minus on unsigned, but this is
159 * well-defined and precisely what we want to do here */
160#if defined(_MSC_VER)
161#pragma warning( push )
162#pragma warning( disable : 4146 )
163#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100164 return -((value | -value) >> (sizeof(value) * 8 - 1));
gabor-mezei-arm9cb55692021-08-11 15:07:02 +0200165#if defined(_MSC_VER)
166#pragma warning( pop )
167#endif
168}
169
170#endif /* MBEDTLS_BIGNUM_C */
171
Gabor Mezeie2123792021-10-18 17:05:06 +0200172#if defined(MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC)
173
Gabor Mezei1e642612021-10-18 16:05:50 +0200174/** Constant-flow mask generation for "less than" comparison:
175 * - if \p x < \p y, return all-bits 1, that is (size_t) -1
176 * - otherwise, return all bits 0, that is 0
177 *
178 * This function can be used to write constant-time code by replacing branches
179 * with bit operations using masks.
180 *
181 * \param x The first value to analyze.
182 * \param y The second value to analyze.
183 *
184 * \return All-bits-one if \p x is less than \p y, otherwise zero.
185 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100186static size_t mbedtls_ct_size_mask_lt(size_t x,
187 size_t y)
gabor-mezei-armc76227d2021-09-27 11:53:54 +0200188{
189 /* This has the most significant bit set if and only if x < y */
190 const size_t sub = x - y;
191
192 /* sub1 = (x < y) ? 1 : 0 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100193 const size_t sub1 = sub >> (sizeof(sub) * 8 - 1);
gabor-mezei-armc76227d2021-09-27 11:53:54 +0200194
195 /* mask = (x < y) ? 0xff... : 0x00... */
Gilles Peskine449bd832023-01-11 14:50:10 +0100196 const size_t mask = mbedtls_ct_size_mask(sub1);
gabor-mezei-armc76227d2021-09-27 11:53:54 +0200197
Gilles Peskine449bd832023-01-11 14:50:10 +0100198 return mask;
gabor-mezei-armc76227d2021-09-27 11:53:54 +0200199}
gabor-mezei-arm16fc57b2021-09-27 11:58:31 +0200200
Gilles Peskine449bd832023-01-11 14:50:10 +0100201size_t mbedtls_ct_size_mask_ge(size_t x,
202 size_t y)
gabor-mezei-arm16fc57b2021-09-27 11:58:31 +0200203{
Gilles Peskine449bd832023-01-11 14:50:10 +0100204 return ~mbedtls_ct_size_mask_lt(x, y);
gabor-mezei-arm16fc57b2021-09-27 11:58:31 +0200205}
gabor-mezei-arm8d1d5fd2021-09-27 12:15:19 +0200206
Gabor Mezeie2123792021-10-18 17:05:06 +0200207#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
208
Gabor Mezei28d61152021-11-15 16:13:01 +0100209#if defined(MBEDTLS_BASE64_C)
210
211/* Return 0xff if low <= c <= high, 0 otherwise.
212 *
213 * Constant flow with respect to c.
214 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100215unsigned char mbedtls_ct_uchar_mask_of_range(unsigned char low,
216 unsigned char high,
217 unsigned char c)
Gabor Mezei28d61152021-11-15 16:13:01 +0100218{
219 /* low_mask is: 0 if low <= c, 0x...ff if low > c */
Gilles Peskine449bd832023-01-11 14:50:10 +0100220 unsigned low_mask = ((unsigned) c - low) >> 8;
Gabor Mezei28d61152021-11-15 16:13:01 +0100221 /* high_mask is: 0 if c <= high, 0x...ff if c > high */
Gilles Peskine449bd832023-01-11 14:50:10 +0100222 unsigned high_mask = ((unsigned) high - c) >> 8;
223 return ~(low_mask | high_mask) & 0xff;
Gabor Mezei28d61152021-11-15 16:13:01 +0100224}
225
226#endif /* MBEDTLS_BASE64_C */
227
Gilles Peskine449bd832023-01-11 14:50:10 +0100228unsigned mbedtls_ct_size_bool_eq(size_t x,
229 size_t y)
gabor-mezei-arm8d1d5fd2021-09-27 12:15:19 +0200230{
231 /* diff = 0 if x == y, non-zero otherwise */
232 const size_t diff = x ^ y;
233
234 /* MSVC has a warning about unary minus on unsigned integer types,
235 * but this is well-defined and precisely what we want to do here. */
236#if defined(_MSC_VER)
237#pragma warning( push )
238#pragma warning( disable : 4146 )
239#endif
240
241 /* diff_msb's most significant bit is equal to x != y */
Gilles Peskine449bd832023-01-11 14:50:10 +0100242 const size_t diff_msb = (diff | (size_t) -diff);
gabor-mezei-arm8d1d5fd2021-09-27 12:15:19 +0200243
244#if defined(_MSC_VER)
245#pragma warning( pop )
246#endif
247
248 /* diff1 = (x != y) ? 1 : 0 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100249 const unsigned diff1 = diff_msb >> (sizeof(diff_msb) * 8 - 1);
gabor-mezei-arm8d1d5fd2021-09-27 12:15:19 +0200250
Gilles Peskine449bd832023-01-11 14:50:10 +0100251 return 1 ^ diff1;
gabor-mezei-arm8d1d5fd2021-09-27 12:15:19 +0200252}
gabor-mezei-arm5a854422021-09-27 12:25:07 +0200253
Gabor Mezeie2123792021-10-18 17:05:06 +0200254#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
255
Dave Rodgman0afe0012023-05-09 11:09:52 +0100256unsigned mbedtls_ct_size_gt(size_t x, size_t y)
gabor-mezei-arm5a854422021-09-27 12:25:07 +0200257{
gabor-mezei-arm87ac5be2021-08-10 20:36:09 +0200258 /* Return the sign bit (1 for negative) of (y - x). */
Gilles Peskine449bd832023-01-11 14:50:10 +0100259 return (y - x) >> (sizeof(size_t) * 8 - 1);
gabor-mezei-arm5a854422021-09-27 12:25:07 +0200260}
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200261
Gabor Mezeie2123792021-10-18 17:05:06 +0200262#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
263
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200264#if defined(MBEDTLS_BIGNUM_C)
265
Gilles Peskine449bd832023-01-11 14:50:10 +0100266unsigned mbedtls_ct_mpi_uint_lt(const mbedtls_mpi_uint x,
267 const mbedtls_mpi_uint y)
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200268{
269 mbedtls_mpi_uint ret;
270 mbedtls_mpi_uint cond;
271
272 /*
273 * Check if the most significant bits (MSB) of the operands are different.
274 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100275 cond = (x ^ y);
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200276 /*
277 * If the MSB are the same then the difference x-y will be negative (and
278 * have its MSB set to 1 during conversion to unsigned) if and only if x<y.
279 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100280 ret = (x - y) & ~cond;
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200281 /*
282 * If the MSB are different, then the operand with the MSB of 1 is the
283 * bigger. (That is if y has MSB of 1, then x<y is true and it is false if
284 * the MSB of y is 0.)
285 */
286 ret |= y & cond;
287
288
Gilles Peskine449bd832023-01-11 14:50:10 +0100289 ret = ret >> (sizeof(mbedtls_mpi_uint) * 8 - 1);
gabor-mezei-arm3f90fd52021-09-27 12:55:33 +0200290
291 return (unsigned) ret;
292}
293
294#endif /* MBEDTLS_BIGNUM_C */
gabor-mezei-armb2dbf2c2021-09-27 12:59:30 +0200295
Gilles Peskine449bd832023-01-11 14:50:10 +0100296unsigned mbedtls_ct_uint_if(unsigned condition,
297 unsigned if1,
298 unsigned if0)
gabor-mezei-armb2dbf2c2021-09-27 12:59:30 +0200299{
Gilles Peskine449bd832023-01-11 14:50:10 +0100300 unsigned mask = mbedtls_ct_uint_mask(condition);
301 return (mask & if1) | (~mask & if0);
gabor-mezei-armb2dbf2c2021-09-27 12:59:30 +0200302}
gabor-mezei-armd3230d52021-09-27 13:03:57 +0200303
Gabor Mezeie2123792021-10-18 17:05:06 +0200304#if defined(MBEDTLS_BIGNUM_C)
gabor-mezei-arm65cefdb2021-09-27 15:47:00 +0200305
Gilles Peskine449bd832023-01-11 14:50:10 +0100306void mbedtls_ct_mpi_uint_cond_assign(size_t n,
307 mbedtls_mpi_uint *dest,
308 const mbedtls_mpi_uint *src,
309 unsigned char condition)
gabor-mezei-armbe8d98b2021-09-27 13:17:15 +0200310{
311 size_t i;
312
313 /* MSVC has a warning about unary minus on unsigned integer types,
314 * but this is well-defined and precisely what we want to do here. */
315#if defined(_MSC_VER)
316#pragma warning( push )
317#pragma warning( disable : 4146 )
318#endif
319
gabor-mezei-arm87ac5be2021-08-10 20:36:09 +0200320 /* all-bits 1 if condition is 1, all-bits 0 if condition is 0 */
321 const mbedtls_mpi_uint mask = -condition;
gabor-mezei-armbe8d98b2021-09-27 13:17:15 +0200322
323#if defined(_MSC_VER)
324#pragma warning( pop )
325#endif
326
Gilles Peskine449bd832023-01-11 14:50:10 +0100327 for (i = 0; i < n; i++) {
328 dest[i] = (src[i] & mask) | (dest[i] & ~mask);
329 }
gabor-mezei-armbe8d98b2021-09-27 13:17:15 +0200330}
331
332#endif /* MBEDTLS_BIGNUM_C */
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200333
Gabor Mezeie2123792021-10-18 17:05:06 +0200334#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
335
Dave Rodgman0afe0012023-05-09 11:09:52 +0100336void mbedtls_ct_mem_move_to_left(void *start,
Dave Rodgman19e8cd02023-05-09 11:10:21 +0100337 size_t total,
338 size_t offset)
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200339{
340 volatile unsigned char *buf = start;
341 size_t i, n;
Gilles Peskine449bd832023-01-11 14:50:10 +0100342 if (total == 0) {
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200343 return;
Gilles Peskine449bd832023-01-11 14:50:10 +0100344 }
345 for (i = 0; i < total; i++) {
346 unsigned no_op = mbedtls_ct_size_gt(total - offset, i);
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200347 /* The first `total - offset` passes are a no-op. The last
348 * `offset` passes shift the data one byte to the left and
349 * zero out the last byte. */
Gilles Peskine449bd832023-01-11 14:50:10 +0100350 for (n = 0; n < total - 1; n++) {
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200351 unsigned char current = buf[n];
352 unsigned char next = buf[n+1];
Gilles Peskine449bd832023-01-11 14:50:10 +0100353 buf[n] = mbedtls_ct_uint_if(no_op, current, next);
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200354 }
Gilles Peskine449bd832023-01-11 14:50:10 +0100355 buf[total-1] = mbedtls_ct_uint_if(no_op, buf[total-1], 0);
gabor-mezei-arm394aeaa2021-09-27 13:31:06 +0200356 }
357}
gabor-mezei-armdee0fd32021-09-27 13:34:25 +0200358
Gabor Mezeie2123792021-10-18 17:05:06 +0200359#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
360
Przemek Stekiel89ad6232022-09-27 13:36:12 +0200361#if defined(MBEDTLS_SSL_SOME_SUITES_USE_MAC)
Gabor Mezeie2123792021-10-18 17:05:06 +0200362
Gilles Peskine449bd832023-01-11 14:50:10 +0100363void mbedtls_ct_memcpy_if_eq(unsigned char *dest,
364 const unsigned char *src,
365 size_t len,
366 size_t c1,
367 size_t c2)
gabor-mezei-armdee0fd32021-09-27 13:34:25 +0200368{
369 /* mask = c1 == c2 ? 0xff : 0x00 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100370 const size_t equal = mbedtls_ct_size_bool_eq(c1, c2);
gabor-mezei-armdee0fd32021-09-27 13:34:25 +0200371
gabor-mezei-arm87ac5be2021-08-10 20:36:09 +0200372 /* dest[i] = c1 == c2 ? src[i] : dest[i] */
Dave Rodgman36dfc5a2022-12-22 15:04:43 +0000373 size_t i = 0;
374#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
375 const uint32_t mask32 = (uint32_t) mbedtls_ct_size_mask(equal);
376 const unsigned char mask = (unsigned char) mask32 & 0xff;
377
378 for (; (i + 4) <= len; i += 4) {
379 uint32_t a = mbedtls_get_unaligned_uint32(src + i) & mask32;
380 uint32_t b = mbedtls_get_unaligned_uint32(dest + i) & ~mask32;
381 mbedtls_put_unaligned_uint32(dest + i, a | b);
382 }
383#else
384 const unsigned char mask = (unsigned char) mbedtls_ct_size_mask(equal);
385#endif /* MBEDTLS_EFFICIENT_UNALIGNED_ACCESS */
386 for (; i < len; i++) {
Gilles Peskine449bd832023-01-11 14:50:10 +0100387 dest[i] = (src[i] & mask) | (dest[i] & ~mask);
388 }
gabor-mezei-armdee0fd32021-09-27 13:34:25 +0200389}
gabor-mezei-arm0e7f71e2021-09-27 13:57:45 +0200390
Gilles Peskine449bd832023-01-11 14:50:10 +0100391void mbedtls_ct_memcpy_offset(unsigned char *dest,
392 const unsigned char *src,
393 size_t offset,
394 size_t offset_min,
395 size_t offset_max,
396 size_t len)
gabor-mezei-arm0e7f71e2021-09-27 13:57:45 +0200397{
Gabor Mezei63bbba52021-10-18 16:17:57 +0200398 size_t offsetval;
gabor-mezei-arm0e7f71e2021-09-27 13:57:45 +0200399
Gilles Peskine449bd832023-01-11 14:50:10 +0100400 for (offsetval = offset_min; offsetval <= offset_max; offsetval++) {
401 mbedtls_ct_memcpy_if_eq(dest, src + offsetval, len,
402 offsetval, offset);
gabor-mezei-arm0e7f71e2021-09-27 13:57:45 +0200403 }
404}
gabor-mezei-arm1349ffd2021-09-27 14:28:31 +0200405
Przemek Stekiel89ad6232022-09-27 13:36:12 +0200406#endif /* MBEDTLS_SSL_SOME_SUITES_USE_MAC */
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200407
408#if defined(MBEDTLS_BIGNUM_C)
409
Gilles Peskine449bd832023-01-11 14:50:10 +0100410#define MPI_VALIDATE_RET(cond) \
411 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_MPI_BAD_INPUT_DATA)
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200412
413/*
414 * Conditionally assign X = Y, without leaking information
415 * about whether the assignment was made or not.
416 * (Leaking information about the respective sizes of X and Y is ok however.)
417 */
Tautvydas Žilys40fc7da2022-01-31 13:34:01 -0800418#if defined(_MSC_VER) && defined(_M_ARM64) && (_MSC_FULL_VER < 193131103)
Tautvydas Žilys60165d72022-01-26 15:33:27 -0800419/*
Tautvydas Žilys40fc7da2022-01-31 13:34:01 -0800420 * MSVC miscompiles this function if it's inlined prior to Visual Studio 2022 version 17.1. See:
Tautvydas Žilys60165d72022-01-26 15:33:27 -0800421 * https://developercommunity.visualstudio.com/t/c-compiler-miscompiles-part-of-mbedtls-library-on/1646989
422 */
423__declspec(noinline)
424#endif
Gilles Peskine449bd832023-01-11 14:50:10 +0100425int mbedtls_mpi_safe_cond_assign(mbedtls_mpi *X,
426 const mbedtls_mpi *Y,
427 unsigned char assign)
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200428{
429 int ret = 0;
Gilles Peskine449bd832023-01-11 14:50:10 +0100430 MPI_VALIDATE_RET(X != NULL);
431 MPI_VALIDATE_RET(Y != NULL);
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200432
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200433 /* all-bits 1 if assign is 1, all-bits 0 if assign is 0 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100434 mbedtls_mpi_uint limb_mask = mbedtls_ct_mpi_uint_mask(assign);
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200435
Gilles Peskine449bd832023-01-11 14:50:10 +0100436 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200437
Tom Cosgrovee22413c2023-05-03 09:44:01 +0100438 X->s = (int) mbedtls_ct_uint_if(assign, Y->s, X->s);
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200439
Gilles Peskine449bd832023-01-11 14:50:10 +0100440 mbedtls_mpi_core_cond_assign(X->p, Y->p, Y->n, assign);
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200441
Gilles Peskine449bd832023-01-11 14:50:10 +0100442 for (size_t i = Y->n; i < X->n; i++) {
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200443 X->p[i] &= ~limb_mask;
Gilles Peskine449bd832023-01-11 14:50:10 +0100444 }
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200445
446cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +0100447 return ret;
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200448}
449
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200450/*
451 * Conditionally swap X and Y, without leaking information
452 * about whether the swap was made or not.
Shaun Case8b0ecbc2021-12-20 21:14:10 -0800453 * Here it is not ok to simply swap the pointers, which would lead to
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200454 * different memory access patterns when X and Y are used afterwards.
455 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100456int mbedtls_mpi_safe_cond_swap(mbedtls_mpi *X,
457 mbedtls_mpi *Y,
458 unsigned char swap)
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200459{
Gabor Mezeid7edb1d2022-10-10 14:32:09 +0200460 int ret = 0;
461 int s;
Gilles Peskine449bd832023-01-11 14:50:10 +0100462 MPI_VALIDATE_RET(X != NULL);
463 MPI_VALIDATE_RET(Y != NULL);
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200464
Gilles Peskine449bd832023-01-11 14:50:10 +0100465 if (X == Y) {
466 return 0;
467 }
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200468
Gilles Peskine449bd832023-01-11 14:50:10 +0100469 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(X, Y->n));
470 MBEDTLS_MPI_CHK(mbedtls_mpi_grow(Y, X->n));
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200471
472 s = X->s;
Tom Cosgrovee22413c2023-05-03 09:44:01 +0100473 X->s = (int) mbedtls_ct_uint_if(swap, Y->s, X->s);
474 Y->s = (int) mbedtls_ct_uint_if(swap, s, Y->s);
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200475
Gilles Peskine449bd832023-01-11 14:50:10 +0100476 mbedtls_mpi_core_cond_swap(X->p, Y->p, X->n, swap);
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200477
478cleanup:
Gilles Peskine449bd832023-01-11 14:50:10 +0100479 return ret;
gabor-mezei-arm5c976212021-09-27 15:37:50 +0200480}
481
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200482/*
Janos Follath23bdeca2022-07-22 18:24:06 +0100483 * Compare unsigned values in constant time
484 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100485unsigned mbedtls_mpi_core_lt_ct(const mbedtls_mpi_uint *A,
486 const mbedtls_mpi_uint *B,
487 size_t limbs)
Janos Follath23bdeca2022-07-22 18:24:06 +0100488{
Janos Follath23bdeca2022-07-22 18:24:06 +0100489 unsigned ret, cond, done;
490
Janos Follath63184682022-08-11 17:42:59 +0100491 /* The value of any of these variables is either 0 or 1 for the rest of
492 * their scope. */
Janos Follath23bdeca2022-07-22 18:24:06 +0100493 ret = cond = done = 0;
494
Gilles Peskine449bd832023-01-11 14:50:10 +0100495 for (size_t i = limbs; i > 0; i--) {
Janos Follath23bdeca2022-07-22 18:24:06 +0100496 /*
Janos Follathb7a88ec2022-08-19 12:24:40 +0100497 * If B[i - 1] < A[i - 1] then A < B is false and the result must
Janos Follath23bdeca2022-07-22 18:24:06 +0100498 * remain 0.
499 *
500 * Again even if we can make a decision, we just mark the result and
501 * the fact that we are done and continue looping.
502 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100503 cond = mbedtls_ct_mpi_uint_lt(B[i - 1], A[i - 1]);
Janos Follath23bdeca2022-07-22 18:24:06 +0100504 done |= cond;
505
506 /*
Janos Follathb7a88ec2022-08-19 12:24:40 +0100507 * If A[i - 1] < B[i - 1] then A < B is true.
Janos Follath23bdeca2022-07-22 18:24:06 +0100508 *
509 * Again even if we can make a decision, we just mark the result and
510 * the fact that we are done and continue looping.
511 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100512 cond = mbedtls_ct_mpi_uint_lt(A[i - 1], B[i - 1]);
513 ret |= cond & (1 - done);
Janos Follath23bdeca2022-07-22 18:24:06 +0100514 done |= cond;
515 }
516
517 /*
Janos Follathb7a88ec2022-08-19 12:24:40 +0100518 * If all the limbs were equal, then the numbers are equal, A < B is false
Janos Follath23bdeca2022-07-22 18:24:06 +0100519 * and leaving the result 0 is correct.
520 */
521
Gilles Peskine449bd832023-01-11 14:50:10 +0100522 return ret;
Janos Follath23bdeca2022-07-22 18:24:06 +0100523}
524
525/*
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200526 * Compare signed values in constant time
527 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100528int mbedtls_mpi_lt_mpi_ct(const mbedtls_mpi *X,
529 const mbedtls_mpi *Y,
530 unsigned *ret)
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200531{
532 size_t i;
533 /* The value of any of these variables is either 0 or 1 at all times. */
534 unsigned cond, done, X_is_negative, Y_is_negative;
535
Gilles Peskine449bd832023-01-11 14:50:10 +0100536 MPI_VALIDATE_RET(X != NULL);
537 MPI_VALIDATE_RET(Y != NULL);
538 MPI_VALIDATE_RET(ret != NULL);
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200539
Gilles Peskine449bd832023-01-11 14:50:10 +0100540 if (X->n != Y->n) {
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200541 return MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
Gilles Peskine449bd832023-01-11 14:50:10 +0100542 }
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200543
544 /*
545 * Set sign_N to 1 if N >= 0, 0 if N < 0.
546 * We know that N->s == 1 if N >= 0 and N->s == -1 if N < 0.
547 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100548 X_is_negative = (X->s & 2) >> 1;
549 Y_is_negative = (Y->s & 2) >> 1;
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200550
551 /*
552 * If the signs are different, then the positive operand is the bigger.
553 * That is if X is negative (X_is_negative == 1), then X < Y is true and it
554 * is false if X is positive (X_is_negative == 0).
555 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100556 cond = (X_is_negative ^ Y_is_negative);
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200557 *ret = cond & X_is_negative;
558
559 /*
560 * This is a constant-time function. We might have the result, but we still
561 * need to go through the loop. Record if we have the result already.
562 */
563 done = cond;
564
Gilles Peskine449bd832023-01-11 14:50:10 +0100565 for (i = X->n; i > 0; i--) {
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200566 /*
567 * If Y->p[i - 1] < X->p[i - 1] then X < Y is true if and only if both
568 * X and Y are negative.
569 *
570 * Again even if we can make a decision, we just mark the result and
571 * the fact that we are done and continue looping.
572 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100573 cond = mbedtls_ct_mpi_uint_lt(Y->p[i - 1], X->p[i - 1]);
574 *ret |= cond & (1 - done) & X_is_negative;
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200575 done |= cond;
576
577 /*
578 * If X->p[i - 1] < Y->p[i - 1] then X < Y is true if and only if both
579 * X and Y are positive.
580 *
581 * Again even if we can make a decision, we just mark the result and
582 * the fact that we are done and continue looping.
583 */
Gilles Peskine449bd832023-01-11 14:50:10 +0100584 cond = mbedtls_ct_mpi_uint_lt(X->p[i - 1], Y->p[i - 1]);
585 *ret |= cond & (1 - done) & (1 - X_is_negative);
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200586 done |= cond;
587 }
588
Gilles Peskine449bd832023-01-11 14:50:10 +0100589 return 0;
gabor-mezei-armc29a3da2021-09-27 15:41:30 +0200590}
591
gabor-mezei-arm40a49252021-09-27 15:33:35 +0200592#endif /* MBEDTLS_BIGNUM_C */