v / thirdparty / mbedtls / library / common.h
487 lines · 458 sloc · 18.26 KB · 3d9911f887ecec942f9ae2a5be02d064f233b729
Raw
1/**
2 * \file common.h
3 *
4 * \brief Utility macros for internal use in the library
5 */
6/*
7 * Copyright The Mbed TLS Contributors
8 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
9 */
10
11#ifndef MBEDTLS_LIBRARY_COMMON_H
12#define MBEDTLS_LIBRARY_COMMON_H
13
14#include "mbedtls/build_info.h"
15#include "alignment.h"
16
17#include <assert.h>
18#include <stddef.h>
19#include <stdint.h>
20#include <stddef.h>
21
22#if defined(__ARM_NEON)
23#include <arm_neon.h>
24#define MBEDTLS_HAVE_NEON_INTRINSICS
25#elif defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
26#include <arm64_neon.h>
27#define MBEDTLS_HAVE_NEON_INTRINSICS
28#endif
29
30/* Decide whether we're built for a Unix-like platform.
31 */
32#if defined(MBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE) //no-check-names
33/* We may be building on a Unix-like platform, but for test purposes,
34 * do not try to use Unix features. */
35#elif defined(_WIN32)
36/* If Windows platform interfaces are available, we use them, even if
37 * a Unix-like might also to be available. */
38/* defined(_WIN32) ==> we can include <windows.h> */
39#elif defined(unix) || defined(__unix) || defined(__unix__) || \
40 (defined(__APPLE__) && defined(__MACH__)) || \
41 defined(__HAIKU__) || \
42 defined(__midipix__) || \
43 /* Add other Unix-like platform indicators here ^^^^ */ 0
44/* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) ==> we can include <unistd.h> */
45#define MBEDTLS_PLATFORM_IS_UNIXLIKE
46#endif
47
48/** Helper to define a function as static except when building invasive tests.
49 *
50 * If a function is only used inside its own source file and should be
51 * declared `static` to allow the compiler to optimize for code size,
52 * but that function has unit tests, define it with
53 * ```
54 * MBEDTLS_STATIC_TESTABLE int mbedtls_foo(...) { ... }
55 * ```
56 * and declare it in a header in the `library/` directory with
57 * ```
58 * #if defined(MBEDTLS_TEST_HOOKS)
59 * int mbedtls_foo(...);
60 * #endif
61 * ```
62 */
63#if defined(MBEDTLS_TEST_HOOKS)
64#define MBEDTLS_STATIC_TESTABLE
65#else
66#define MBEDTLS_STATIC_TESTABLE static
67#endif
68
69#if defined(MBEDTLS_TEST_HOOKS)
70extern void (*mbedtls_test_hook_test_fail)(const char *test, int line, const char *file);
71#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST) \
72 do { \
73 if ((!(TEST)) && ((*mbedtls_test_hook_test_fail) != NULL)) \
74 { \
75 (*mbedtls_test_hook_test_fail)( #TEST, __LINE__, __FILE__); \
76 } \
77 } while (0)
78#else
79#define MBEDTLS_TEST_HOOK_TEST_ASSERT(TEST)
80#endif /* defined(MBEDTLS_TEST_HOOKS) */
81
82/** \def ARRAY_LENGTH
83 * Return the number of elements of a static or stack array.
84 *
85 * \param array A value of array (not pointer) type.
86 *
87 * \return The number of elements of the array.
88 */
89/* A correct implementation of ARRAY_LENGTH, but which silently gives
90 * a nonsensical result if called with a pointer rather than an array. */
91#define ARRAY_LENGTH_UNSAFE(array) \
92 (sizeof(array) / sizeof(*(array)))
93
94#if defined(__GNUC__)
95/* Test if arg and &(arg)[0] have the same type. This is true if arg is
96 * an array but not if it's a pointer. */
97#define IS_ARRAY_NOT_POINTER(arg) \
98 (!__builtin_types_compatible_p(__typeof__(arg), \
99 __typeof__(&(arg)[0])))
100/* A compile-time constant with the value 0. If `const_expr` is not a
101 * compile-time constant with a nonzero value, cause a compile-time error. */
102#define STATIC_ASSERT_EXPR(const_expr) \
103 (0 && sizeof(struct { unsigned int STATIC_ASSERT : 1 - 2 * !(const_expr); }))
104
105/* Return the scalar value `value` (possibly promoted). This is a compile-time
106 * constant if `value` is. `condition` must be a compile-time constant.
107 * If `condition` is false, arrange to cause a compile-time error. */
108#define STATIC_ASSERT_THEN_RETURN(condition, value) \
109 (STATIC_ASSERT_EXPR(condition) ? 0 : (value))
110
111#define ARRAY_LENGTH(array) \
112 (STATIC_ASSERT_THEN_RETURN(IS_ARRAY_NOT_POINTER(array), \
113 ARRAY_LENGTH_UNSAFE(array)))
114
115#else
116/* If we aren't sure the compiler supports our non-standard tricks,
117 * fall back to the unsafe implementation. */
118#define ARRAY_LENGTH(array) ARRAY_LENGTH_UNSAFE(array)
119#endif
120
121#if defined(__has_builtin)
122#define MBEDTLS_HAS_BUILTIN(x) __has_builtin(x)
123#else
124#define MBEDTLS_HAS_BUILTIN(x) 0
125#endif
126
127/** Allow library to access its structs' private members.
128 *
129 * Although structs defined in header files are publicly available,
130 * their members are private and should not be accessed by the user.
131 */
132#define MBEDTLS_ALLOW_PRIVATE_ACCESS
133
134/**
135 * \brief Securely zeroize a buffer then free it.
136 *
137 * Similar to making consecutive calls to
138 * \c mbedtls_platform_zeroize() and \c mbedtls_free(), but has
139 * code size savings, and potential for optimisation in the future.
140 *
141 * Guaranteed to be a no-op if \p buf is \c NULL and \p len is 0.
142 *
143 * \param buf Buffer to be zeroized then freed.
144 * \param len Length of the buffer in bytes
145 */
146void mbedtls_zeroize_and_free(void *buf, size_t len);
147
148/** Return an offset into a buffer.
149 *
150 * This is just the addition of an offset to a pointer, except that this
151 * function also accepts an offset of 0 into a buffer whose pointer is null.
152 * (`p + n` has undefined behavior when `p` is null, even when `n == 0`.
153 * A null pointer is a valid buffer pointer when the size is 0, for example
154 * as the result of `malloc(0)` on some platforms.)
155 *
156 * \param p Pointer to a buffer of at least n bytes.
157 * This may be \p NULL if \p n is zero.
158 * \param n An offset in bytes.
159 * \return Pointer to offset \p n in the buffer \p p.
160 * Note that this is only a valid pointer if the size of the
161 * buffer is at least \p n + 1.
162 */
163static inline unsigned char *mbedtls_buffer_offset(
164 unsigned char *p, size_t n)
165{
166 return p == NULL ? NULL : p + n;
167}
168
169/** Return an offset into a read-only buffer.
170 *
171 * Similar to mbedtls_buffer_offset(), but for const pointers.
172 *
173 * \param p Pointer to a buffer of at least n bytes.
174 * This may be \p NULL if \p n is zero.
175 * \param n An offset in bytes.
176 * \return Pointer to offset \p n in the buffer \p p.
177 * Note that this is only a valid pointer if the size of the
178 * buffer is at least \p n + 1.
179 */
180static inline const unsigned char *mbedtls_buffer_offset_const(
181 const unsigned char *p, size_t n)
182{
183 return p == NULL ? NULL : p + n;
184}
185
186/* Always inline mbedtls_xor() for similar reasons as mbedtls_xor_no_simd(). */
187#if defined(__IAR_SYSTEMS_ICC__)
188#pragma inline = forced
189#elif defined(__GNUC__)
190__attribute__((always_inline))
191#endif
192/**
193 * Perform a fast block XOR operation, such that
194 * r[i] = a[i] ^ b[i] where 0 <= i < n
195 *
196 * \param r Pointer to result (buffer of at least \p n bytes). \p r
197 * may be equal to either \p a or \p b, but behaviour when
198 * it overlaps in other ways is undefined.
199 * \param a Pointer to input (buffer of at least \p n bytes)
200 * \param b Pointer to input (buffer of at least \p n bytes)
201 * \param n Number of bytes to process.
202 *
203 * \note Depending on the situation, it may be faster to use either mbedtls_xor() or
204 * mbedtls_xor_no_simd() (these are functionally equivalent).
205 * If the result is used immediately after the xor operation in non-SIMD code (e.g, in
206 * AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
207 * registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
208 * the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
209 * For targets without SIMD support, they will behave the same.
210 */
211static inline void mbedtls_xor(unsigned char *r,
212 const unsigned char *a,
213 const unsigned char *b,
214 size_t n)
215{
216 size_t i = 0;
217#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
218#if defined(MBEDTLS_HAVE_NEON_INTRINSICS) && \
219 (!(defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_GCC_VERSION < 70300))
220 /* Old GCC versions generate a warning here, so disable the NEON path for these compilers */
221 for (; (i + 16) <= n; i += 16) {
222 uint8x16_t v1 = vld1q_u8(a + i);
223 uint8x16_t v2 = vld1q_u8(b + i);
224 uint8x16_t x = veorq_u8(v1, v2);
225 vst1q_u8(r + i, x);
226 }
227#if defined(__IAR_SYSTEMS_ICC__)
228 /* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
229 * where n is a constant multiple of 16.
230 * For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
231 * constant, and is a very small perf regression if n is not a compile-time constant. */
232 if (n % 16 == 0) {
233 return;
234 }
235#endif
236#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
237 if (__builtin_constant_p(n) && n % 16 == 0) {
238 return;
239 }
240#endif
241#elif defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
242 /* This codepath probably only makes sense on architectures with 64-bit registers */
243 for (; (i + 8) <= n; i += 8) {
244 uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
245 mbedtls_put_unaligned_uint64(r + i, x);
246 }
247#if defined(__IAR_SYSTEMS_ICC__)
248 if (n % 8 == 0) {
249 return;
250 }
251#endif
252#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
253 if (__builtin_constant_p(n) && n % 8 == 0) {
254 return;
255 }
256#endif
257#else
258 for (; (i + 4) <= n; i += 4) {
259 uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
260 mbedtls_put_unaligned_uint32(r + i, x);
261 }
262#if defined(__IAR_SYSTEMS_ICC__)
263 if (n % 4 == 0) {
264 return;
265 }
266#endif
267#if defined(MBEDTLS_COMPILER_IS_GCC) && MBEDTLS_HAS_BUILTIN(__builtin_constant_p)
268 if (__builtin_constant_p(n) && n % 4 == 0) {
269 return;
270 }
271#endif
272#endif
273#endif
274 for (; i < n; i++) {
275 r[i] = a[i] ^ b[i];
276 }
277}
278
279/* Always inline mbedtls_xor_no_simd() as we see significant perf regressions when it does not get
280 * inlined (e.g., observed about 3x perf difference in gcm_mult_largetable with gcc 7 - 12) */
281#if defined(__IAR_SYSTEMS_ICC__)
282#pragma inline = forced
283#elif defined(__GNUC__)
284__attribute__((always_inline))
285#endif
286/**
287 * Perform a fast block XOR operation, such that
288 * r[i] = a[i] ^ b[i] where 0 <= i < n
289 *
290 * In some situations, this can perform better than mbedtls_xor() (e.g., it's about 5%
291 * better in AES-CBC).
292 *
293 * \param r Pointer to result (buffer of at least \p n bytes). \p r
294 * may be equal to either \p a or \p b, but behaviour when
295 * it overlaps in other ways is undefined.
296 * \param a Pointer to input (buffer of at least \p n bytes)
297 * \param b Pointer to input (buffer of at least \p n bytes)
298 * \param n Number of bytes to process.
299 *
300 * \note Depending on the situation, it may be faster to use either mbedtls_xor() or
301 * mbedtls_xor_no_simd() (these are functionally equivalent).
302 * If the result is used immediately after the xor operation in non-SIMD code (e.g, in
303 * AES-CBC), there may be additional latency to transfer the data from SIMD to scalar
304 * registers, and in this case, mbedtls_xor_no_simd() may be faster. In other cases where
305 * the result is not used immediately (e.g., in AES-CTR), mbedtls_xor() may be faster.
306 * For targets without SIMD support, they will behave the same.
307 */
308static inline void mbedtls_xor_no_simd(unsigned char *r,
309 const unsigned char *a,
310 const unsigned char *b,
311 size_t n)
312{
313 size_t i = 0;
314#if defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)
315#if defined(MBEDTLS_ARCH_IS_X64) || defined(MBEDTLS_ARCH_IS_ARM64)
316 /* This codepath probably only makes sense on architectures with 64-bit registers */
317 for (; (i + 8) <= n; i += 8) {
318 uint64_t x = mbedtls_get_unaligned_uint64(a + i) ^ mbedtls_get_unaligned_uint64(b + i);
319 mbedtls_put_unaligned_uint64(r + i, x);
320 }
321#if defined(__IAR_SYSTEMS_ICC__)
322 /* This if statement helps some compilers (e.g., IAR) optimise out the byte-by-byte tail case
323 * where n is a constant multiple of 8.
324 * For other compilers (e.g. recent gcc and clang) it makes no difference if n is a compile-time
325 * constant, and is a very small perf regression if n is not a compile-time constant. */
326 if (n % 8 == 0) {
327 return;
328 }
329#endif
330#else
331 for (; (i + 4) <= n; i += 4) {
332 uint32_t x = mbedtls_get_unaligned_uint32(a + i) ^ mbedtls_get_unaligned_uint32(b + i);
333 mbedtls_put_unaligned_uint32(r + i, x);
334 }
335#if defined(__IAR_SYSTEMS_ICC__)
336 if (n % 4 == 0) {
337 return;
338 }
339#endif
340#endif
341#endif
342 for (; i < n; i++) {
343 r[i] = a[i] ^ b[i];
344 }
345}
346
347/* Fix MSVC C99 compatible issue
348 * MSVC support __func__ from visual studio 2015( 1900 )
349 * Use MSVC predefine macro to avoid name check fail.
350 */
351#if (defined(_MSC_VER) && (_MSC_VER <= 1900))
352#define /*no-check-names*/ __func__ __FUNCTION__
353#endif
354
355/* Define `asm` for compilers which don't define it. */
356/* *INDENT-OFF* */
357#ifndef asm
358#if defined(__IAR_SYSTEMS_ICC__)
359#define asm __asm
360#else
361#define asm __asm__
362#endif
363#endif
364/* *INDENT-ON* */
365
366/*
367 * Define the constraint used for read-only pointer operands to aarch64 asm.
368 *
369 * This is normally the usual "r", but for aarch64_32 (aka ILP32,
370 * as found in watchos), "p" is required to avoid warnings from clang.
371 *
372 * Note that clang does not recognise '+p' or '=p', and armclang
373 * does not recognise 'p' at all. Therefore, to update a pointer from
374 * aarch64 assembly, it is necessary to use something like:
375 *
376 * uintptr_t uptr = (uintptr_t) ptr;
377 * asm( "ldr x4, [%x0], #8" ... : "+r" (uptr) : : )
378 * ptr = (void*) uptr;
379 *
380 * Note that the "x" in "%x0" is neccessary; writing "%0" will cause warnings.
381 */
382#if defined(__aarch64__) && defined(MBEDTLS_HAVE_ASM)
383#if UINTPTR_MAX == 0xfffffffful
384/* ILP32: Specify the pointer operand slightly differently, as per #7787. */
385#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "p"
386#elif UINTPTR_MAX == 0xfffffffffffffffful
387/* Normal case (64-bit pointers): use "r" as the constraint for pointer operands to asm */
388#define MBEDTLS_ASM_AARCH64_PTR_CONSTRAINT "r"
389#else
390#error "Unrecognised pointer size for aarch64"
391#endif
392#endif
393
394/* Always provide a static assert macro, so it can be used unconditionally.
395 * It does nothing on systems where we don't know how to define a static assert.
396 */
397/* Can't use the C11-style `defined(static_assert)` on FreeBSD, since it
398 * defines static_assert even with -std=c99, but then complains about it.
399 */
400#if defined(static_assert) && !defined(__FreeBSD__)
401#define MBEDTLS_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
402#else
403/* Make sure `MBEDTLS_STATIC_ASSERT(expr, msg);` is valid both inside and
404 * outside a function. We choose a struct declaration, which can be repeated
405 * any number of times and does not need a matching definition. */
406#define MBEDTLS_STATIC_ASSERT(expr, msg) \
407 struct ISO_C_does_not_allow_extra_semicolon_outside_of_a_function
408#endif
409
410/* Define compiler branch hints */
411#if MBEDTLS_HAS_BUILTIN(__builtin_expect)
412#define MBEDTLS_LIKELY(x) __builtin_expect(!!(x), 1)
413#define MBEDTLS_UNLIKELY(x) __builtin_expect(!!(x), 0)
414#else
415#define MBEDTLS_LIKELY(x) x
416#define MBEDTLS_UNLIKELY(x) x
417#endif
418
419/* MBEDTLS_ASSUME may be used to provide additional information to the compiler
420 * which can result in smaller code-size. */
421#if MBEDTLS_HAS_BUILTIN(__builtin_assume)
422/* clang provides __builtin_assume */
423#define MBEDTLS_ASSUME(x) __builtin_assume(x)
424#elif MBEDTLS_HAS_BUILTIN(__builtin_unreachable)
425/* gcc and IAR can use __builtin_unreachable */
426#define MBEDTLS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while (0)
427#elif defined(_MSC_VER)
428/* Supported by MSVC since VS 2005 */
429#define MBEDTLS_ASSUME(x) __assume(x)
430#else
431#define MBEDTLS_ASSUME(x) do { } while (0)
432#endif
433
434/* For gcc -Os, override with -O2 for a given function.
435 *
436 * This will not affect behaviour for other optimisation settings, e.g. -O0.
437 */
438#if defined(MBEDTLS_COMPILER_IS_GCC) && defined(__OPTIMIZE_SIZE__)
439#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE __attribute__((optimize("-O2")))
440#else
441#define MBEDTLS_OPTIMIZE_FOR_PERFORMANCE
442#endif
443
444/* Suppress compiler warnings for unused functions and variables. */
445#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__has_attribute)
446# if __has_attribute(unused)
447# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
448# endif
449#endif
450#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__GNUC__)
451# define MBEDTLS_MAYBE_UNUSED __attribute__((unused))
452#endif
453#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(__IAR_SYSTEMS_ICC__) && defined(__VER__)
454/* IAR does support __attribute__((unused)), but only if the -e flag (extended language support)
455 * is given; the pragma always works.
456 * Unfortunately the pragma affects the rest of the file where it is used, but this is harmless.
457 * Check for version 5.2 or later - this pragma may be supported by earlier versions, but I wasn't
458 * able to find documentation).
459 */
460# if (__VER__ >= 5020000)
461# define MBEDTLS_MAYBE_UNUSED _Pragma("diag_suppress=Pe177")
462# endif
463#endif
464#if !defined(MBEDTLS_MAYBE_UNUSED) && defined(_MSC_VER)
465# define MBEDTLS_MAYBE_UNUSED __pragma(warning(suppress:4189))
466#endif
467#if !defined(MBEDTLS_MAYBE_UNUSED)
468# define MBEDTLS_MAYBE_UNUSED
469#endif
470
471/* GCC >= 15 has a warning 'unterminated-string-initialization' which complains if you initialize
472 * a string into an array without space for a terminating NULL character. In some places in the
473 * codebase this behaviour is intended, so we add the macro MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
474 * to suppress the warning in these places.
475 */
476#if defined(__has_attribute)
477#if __has_attribute(nonstring)
478#define MBEDTLS_HAS_ATTRIBUTE_NONSTRING
479#endif /* __has_attribute(nonstring) */
480#endif /* __has_attribute */
481#if defined(MBEDTLS_HAS_ATTRIBUTE_NONSTRING)
482#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING __attribute__((nonstring))
483#else
484#define MBEDTLS_ATTRIBUTE_UNTERMINATED_STRING
485#endif /* MBEDTLS_HAS_ATTRIBUTE_NONSTRING */
486
487#endif /* MBEDTLS_LIBRARY_COMMON_H */
488