Coverage Report

Created: 2025-10-12 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/liboqs/src/common/common.c
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0 AND MIT
2
3
#if !defined(OQS_USE_OPENSSL) && !defined(_WIN32) && !defined(OQS_HAVE_EXPLICIT_BZERO) && !defined(OQS_HAVE_EXPLICIT_MEMSET)
4
// Request memset_s
5
#define __STDC_WANT_LIB_EXT1__ 1
6
#endif
7
8
#include <oqs/common.h>
9
10
#include <errno.h>
11
#include <stdint.h>
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <stddef.h>
15
#include <string.h>
16
#include <stddef.h>
17
18
#if defined(OQS_DIST_BUILD) && defined(OQS_USE_PTHREADS)
19
#include <pthread.h>
20
#endif
21
22
#if !defined(OQS_HAVE_POSIX_MEMALIGN) || defined(__MINGW32__) || defined(__MINGW64__) || defined(_MSC_VER)
23
#include <malloc.h>
24
#endif
25
26
#if defined(_WIN32)
27
#include <windows.h>
28
#endif
29
30
#if defined(OQS_USE_OPENSSL)
31
#include "ossl_helpers.h"
32
#endif
33
34
/* Identifying the CPU is expensive so we cache the results in cpu_ext_data */
35
#if defined(OQS_DIST_BUILD)
36
static unsigned int cpu_ext_data[OQS_CPU_EXT_COUNT] = {0};
37
#if defined(OQS_USE_PTHREADS)
38
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
39
#endif
40
#endif
41
42
#if defined(OQS_DIST_X86_64_BUILD)
43
/* set_available_cpu_extensions_x86_64() has been written using:
44
 * https://github.com/google/cpu_features/blob/339bfd32be1285877ff517cba8b82ce72e946afd/src/cpuinfo_x86.c
45
 */
46
#include "x86_64_helpers.h"
47
0
static void set_available_cpu_extensions(void) {
48
  /* mark that this function has been called */
49
0
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
50
51
0
  cpuid_out leaf_1;
52
0
  cpuid(&leaf_1, 1);
53
0
  if (leaf_1.eax == 0) {
54
0
    return;
55
0
  }
56
57
0
  cpuid_out leaf_7;
58
0
  cpuid(&leaf_7, 7);
59
60
0
  const unsigned int has_xsave = is_bit_set(leaf_1.ecx, 26);
61
0
  const unsigned int has_osxsave = is_bit_set(leaf_1.ecx, 27);
62
0
  const uint32_t xcr0_eax = (has_xsave && has_osxsave) ? xgetbv_eax(0) : 0;
63
64
0
  cpu_ext_data[OQS_CPU_EXT_AES] = is_bit_set(leaf_1.ecx, 25);
65
0
  if (has_mask(xcr0_eax, MASK_XMM | MASK_YMM)) {
66
0
    cpu_ext_data[OQS_CPU_EXT_AVX] = is_bit_set(leaf_1.ecx, 28);
67
0
    cpu_ext_data[OQS_CPU_EXT_AVX2] = is_bit_set(leaf_7.ebx, 5);
68
0
  }
69
0
  cpu_ext_data[OQS_CPU_EXT_PCLMULQDQ] = is_bit_set(leaf_1.ecx, 1);
70
0
  cpu_ext_data[OQS_CPU_EXT_POPCNT] = is_bit_set(leaf_1.ecx, 23);
71
0
  cpu_ext_data[OQS_CPU_EXT_BMI1] = is_bit_set(leaf_7.ebx, 3);
72
0
  cpu_ext_data[OQS_CPU_EXT_BMI2] = is_bit_set(leaf_7.ebx, 8);
73
0
  cpu_ext_data[OQS_CPU_EXT_ADX] = is_bit_set(leaf_7.ebx, 19);
74
75
0
  if (has_mask(xcr0_eax, MASK_XMM)) {
76
0
    cpu_ext_data[OQS_CPU_EXT_SSE] = is_bit_set(leaf_1.edx, 25);
77
0
    cpu_ext_data[OQS_CPU_EXT_SSE2] = is_bit_set(leaf_1.edx, 26);
78
0
    cpu_ext_data[OQS_CPU_EXT_SSE3] = is_bit_set(leaf_1.ecx, 0);
79
0
  }
80
81
0
  if (has_mask(xcr0_eax, MASK_XMM | MASK_YMM | MASK_MASKREG | MASK_ZMM0_15 | MASK_ZMM16_31)) {
82
0
    unsigned int avx512f = is_bit_set(leaf_7.ebx, 16);
83
0
    unsigned int avx512bw = is_bit_set(leaf_7.ebx, 30);
84
0
    unsigned int avx512dq = is_bit_set(leaf_7.ebx, 17);
85
0
    if (avx512f && avx512bw && avx512dq) {
86
0
      cpu_ext_data[OQS_CPU_EXT_AVX512] = 1;
87
0
    }
88
0
    cpu_ext_data[OQS_CPU_EXT_VPCLMULQDQ] = is_bit_set(leaf_7.ecx, 10);
89
0
  }
90
0
}
91
#elif defined(OQS_DIST_X86_BUILD)
92
static void set_available_cpu_extensions(void) {
93
  /* mark that this function has been called */
94
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
95
}
96
#elif defined(OQS_DIST_ARM64_V8_BUILD)
97
#if defined(__APPLE__)
98
#include <sys/sysctl.h>
99
static unsigned int macos_feature_detection(const char *feature_name) {
100
  int p;
101
  size_t p_len = sizeof(p);
102
  int res = sysctlbyname(feature_name, &p, &p_len, NULL, 0);
103
  if (res != 0) {
104
    return 0;
105
  } else {
106
    return (p != 0) ? 1 : 0;
107
  }
108
}
109
static void set_available_cpu_extensions(void) {
110
  cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
111
  cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
112
  cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = macos_feature_detection("hw.optional.armv8_2_sha3");
113
  cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = macos_feature_detection("hw.optional.neon");
114
  /* mark that this function has been called */
115
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
116
}
117
#elif defined(__FreeBSD__) || defined(__FreeBSD)
118
#include <sys/auxv.h>
119
#include <machine/elf.h>
120
121
static void set_available_cpu_extensions(void) {
122
  /* mark that this function has been called */
123
  u_long hwcaps = 0;
124
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
125
  if (elf_aux_info(AT_HWCAP, &hwcaps, sizeof(u_long))) {
126
    fprintf(stderr, "Error getting HWCAP for ARM on FreeBSD\n");
127
    return;
128
  }
129
  if (hwcaps & HWCAP_AES) {
130
    cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
131
  }
132
  if (hwcaps & HWCAP_ASIMD) {
133
    cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
134
  }
135
  if (hwcaps & HWCAP_SHA2) {
136
    cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
137
  }
138
#ifdef HWCAP_SHA3
139
  if (hwcaps & HWCAP_SHA3) {
140
    cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = 1;
141
  }
142
#endif
143
}
144
#elif defined(_WIN32)
145
static void set_available_cpu_extensions(void) {
146
  /* mark that this function has been called */
147
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
148
  BOOL crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
149
  if (crypto) {
150
    cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
151
    cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
152
  }
153
  BOOL neon = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
154
  if (neon) {
155
    cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
156
  }
157
}
158
#else
159
#include <sys/auxv.h>
160
#include <asm/hwcap.h>
161
static void set_available_cpu_extensions(void) {
162
  /* mark that this function has been called */
163
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
164
  unsigned long int hwcaps = getauxval(AT_HWCAP);
165
  if (hwcaps & HWCAP_AES) {
166
    cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
167
  }
168
  if (hwcaps & HWCAP_SHA2) {
169
    cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
170
  }
171
#ifdef HWCAP_SHA3
172
  if (hwcaps & HWCAP_SHA3) {
173
    cpu_ext_data[OQS_CPU_EXT_ARM_SHA3] = 1;
174
  }
175
#endif
176
  if (hwcaps & HWCAP_ASIMD) {
177
    cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
178
  }
179
}
180
#endif
181
#elif defined(OQS_DIST_ARM32v7_BUILD)
182
#include <sys/auxv.h>
183
#include <asm/hwcap.h>
184
static void set_available_cpu_extensions(void) {
185
  /* mark that this function has been called */
186
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
187
  unsigned long int hwcaps = getauxval(AT_HWCAP);
188
  unsigned long int hwcaps2 = getauxval(AT_HWCAP2);
189
  if (hwcaps2 & HWCAP2_AES) {
190
    cpu_ext_data[OQS_CPU_EXT_ARM_AES] = 1;
191
  }
192
  if (hwcaps2 & HWCAP2_SHA2) {
193
    cpu_ext_data[OQS_CPU_EXT_ARM_SHA2] = 1;
194
  }
195
  if (hwcaps & HWCAP_NEON) {
196
    cpu_ext_data[OQS_CPU_EXT_ARM_NEON] = 1;
197
  }
198
}
199
#elif defined(OQS_DIST_PPC64LE_BUILD)
200
static void set_available_cpu_extensions(void) {
201
  /* mark that this function has been called */
202
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
203
}
204
#elif defined(OQS_DIST_S390X_BUILD)
205
static void set_available_cpu_extensions(void) {
206
  /* mark that this function has been called */
207
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
208
}
209
#elif defined(OQS_DIST_LOONGARCH64_BUILD)
210
static void set_available_cpu_extensions(void) {
211
  /* mark that this function has been called */
212
  cpu_ext_data[OQS_CPU_EXT_INIT] = 1;
213
}
214
#elif defined(OQS_DIST_BUILD)
215
static void set_available_cpu_extensions(void) {
216
}
217
#endif
218
219
0
OQS_API int OQS_CPU_has_extension(OQS_CPU_EXT ext) {
220
0
#if defined(OQS_DIST_BUILD)
221
0
#if defined(OQS_USE_PTHREADS)
222
0
  pthread_once(&once_control, &set_available_cpu_extensions);
223
#else
224
  if (0 == cpu_ext_data[OQS_CPU_EXT_INIT]) {
225
    set_available_cpu_extensions();
226
  }
227
#endif
228
0
  if (0 < ext && ext < OQS_CPU_EXT_COUNT) {
229
0
    return (int)cpu_ext_data[ext];
230
0
  }
231
#else
232
  (void)ext;
233
#endif
234
0
  return 0;
235
0
}
236
237
0
OQS_API void OQS_init(void) {
238
0
#if defined(OQS_DIST_BUILD)
239
0
  OQS_CPU_has_extension(OQS_CPU_EXT_INIT);
240
0
#endif
241
0
}
242
243
0
OQS_API void OQS_thread_stop(void) {
244
0
#if defined(OQS_USE_OPENSSL)
245
0
  oqs_thread_stop();
246
0
#endif
247
0
}
248
249
0
OQS_API const char *OQS_version(void) {
250
0
  return OQS_VERSION_TEXT;
251
0
}
252
253
0
OQS_API void OQS_destroy(void) {
254
0
#if defined(OQS_USE_OPENSSL)
255
0
  oqs_ossl_destroy();
256
0
#endif
257
0
}
258
259
0
OQS_API int OQS_MEM_secure_bcmp(const void *a, const void *b, size_t len) {
260
  /* Assume CHAR_BIT = 8 */
261
0
  uint8_t r = 0;
262
263
0
  for (size_t i = 0; i < len; i++) {
264
0
    r |= ((const uint8_t *)a)[i] ^ ((const uint8_t *)b)[i];
265
0
  }
266
267
  // We have 0 <= r < 256, and unsigned int is at least 16 bits.
268
0
  return 1 & ((-(unsigned int)r) >> 8);
269
0
}
270
271
0
OQS_API void OQS_MEM_cleanse(void *ptr, size_t len) {
272
0
  if (ptr == NULL) {
273
0
    return;
274
0
  }
275
0
#if defined(OQS_USE_OPENSSL)
276
0
  OSSL_FUNC(OPENSSL_cleanse)(ptr, len);
277
#elif defined(_WIN32)
278
  SecureZeroMemory(ptr, len);
279
#elif defined(OQS_HAVE_EXPLICIT_BZERO)
280
  explicit_bzero(ptr, len);
281
#elif defined(OQS_HAVE_EXPLICIT_MEMSET)
282
  explicit_memset(ptr, 0, len);
283
#elif defined(__STDC_LIB_EXT1__) || defined(OQS_HAVE_MEMSET_S)
284
  if (0U < len && memset_s(ptr, (rsize_t)len, 0, (rsize_t)len) != 0) {
285
    abort();
286
  }
287
#else
288
  typedef void *(*memset_t)(void *, int, size_t);
289
  static volatile memset_t memset_func = memset;
290
  memset_func(ptr, 0, len);
291
#endif
292
0
}
293
294
0
OQS_API void OQS_MEM_secure_free(void *ptr, size_t len) {
295
0
  if (ptr != NULL) {
296
0
    OQS_MEM_cleanse(ptr, len);
297
0
    OQS_MEM_insecure_free(ptr);
298
0
  }
299
0
}
300
301
0
OQS_API void OQS_MEM_insecure_free(void *ptr) {
302
0
#if defined(OQS_USE_OPENSSL) && defined(OPENSSL_VERSION_NUMBER)
303
0
  OSSL_FUNC(CRYPTO_free)(ptr, OPENSSL_FILE, OPENSSL_LINE);
304
#else
305
  free(ptr); // IGNORE memory-check
306
#endif
307
0
}
308
309
0
void *OQS_MEM_aligned_alloc(size_t alignment, size_t size) {
310
0
#if defined(OQS_USE_OPENSSL)
311
  // Use OpenSSL's memory allocation functions
312
0
  if (!size) {
313
0
    return NULL;
314
0
  }
315
0
  const size_t offset = alignment - 1 + sizeof(uint8_t);
316
0
  uint8_t *buffer = OSSL_FUNC(CRYPTO_malloc)(size + offset, OPENSSL_FILE, OPENSSL_LINE);
317
0
  if (!buffer) {
318
0
    return NULL;
319
0
  }
320
0
  uint8_t *ptr = (uint8_t *)(((uintptr_t)(buffer) + offset) & ~(alignment - 1));
321
0
  ptrdiff_t diff = ptr - buffer;
322
0
  if (diff > UINT8_MAX) {
323
    // Free and return NULL if alignment is too large
324
0
    OSSL_FUNC(CRYPTO_free)(buffer, OPENSSL_FILE, OPENSSL_LINE);
325
0
    errno = EINVAL;
326
0
    return NULL;
327
0
  }
328
  // Store the difference so that the free function can use it
329
0
  ptr[-1] = (uint8_t)diff;
330
0
  return ptr;
331
#elif defined(OQS_HAVE_ALIGNED_ALLOC) // glibc and other implementations providing aligned_alloc
332
  return aligned_alloc(alignment, size);
333
#else
334
  // Check alignment (power of 2, and >= sizeof(void*)) and size (multiple of alignment)
335
  if (alignment & (alignment - 1) || size & (alignment - 1) || alignment < sizeof(void *)) {
336
    errno = EINVAL;
337
    return NULL;
338
  }
339
340
#if defined(OQS_HAVE_POSIX_MEMALIGN)
341
  void *ptr = NULL;
342
  const int err = posix_memalign(&ptr, alignment, size);
343
  if (err) {
344
    errno = err;
345
    ptr = NULL;
346
  }
347
  return ptr;
348
#elif defined(OQS_HAVE_MEMALIGN)
349
  return memalign(alignment, size);
350
#elif defined(__MINGW32__) || defined(__MINGW64__)
351
  return __mingw_aligned_malloc(size, alignment);
352
#elif defined(_MSC_VER)
353
  return _aligned_malloc(size, alignment);
354
#else
355
  if (!size) {
356
    return NULL;
357
  }
358
  // Overallocate to be able to align the pointer (alignment -1) and to store
359
  // the difference between the pointer returned to the user (ptr) and the
360
  // pointer returned by malloc (buffer). The difference is caped to 255 and
361
  // can be made larger if necessary, but this should be enough for all users
362
  // in liboqs.
363
  //
364
  // buffer      ptr
365
  // ↓           ↓
366
  // ...........|...................
367
  //            |
368
  //       diff = ptr - buffer
369
  const size_t offset = alignment - 1 + sizeof(uint8_t);
370
  uint8_t *buffer = malloc(size + offset); // IGNORE memory-check
371
  if (!buffer) {
372
    return NULL;
373
  }
374
375
  // Align the pointer returned to the user.
376
  uint8_t *ptr = (uint8_t *)(((uintptr_t)(buffer) + offset) & ~(alignment - 1));
377
  ptrdiff_t diff = ptr - buffer;
378
  if (diff > UINT8_MAX) {
379
    // This should never happen in our code, but just to be safe
380
    free(buffer); // IGNORE memory-check
381
    errno = EINVAL;
382
    return NULL;
383
  }
384
  // Store the difference one byte ahead the returned poitner so that free
385
  // can reconstruct buffer.
386
  ptr[-1] = diff;
387
  return ptr;
388
#endif
389
#endif
390
0
}
391
392
0
void OQS_MEM_aligned_free(void *ptr) {
393
0
  if (ptr == NULL) {
394
0
    return;
395
0
  }
396
0
#if defined(OQS_USE_OPENSSL)
397
  // Use OpenSSL's free function
398
0
  uint8_t *u8ptr = ptr;
399
0
  OSSL_FUNC(CRYPTO_free)(u8ptr - u8ptr[-1], OPENSSL_FILE, OPENSSL_LINE);
400
#elif defined(OQS_HAVE_ALIGNED_ALLOC) || defined(OQS_HAVE_POSIX_MEMALIGN) || defined(OQS_HAVE_MEMALIGN)
401
  free(ptr); // IGNORE memory-check
402
#elif defined(__MINGW32__) || defined(__MINGW64__)
403
  __mingw_aligned_free(ptr);
404
#elif defined(_MSC_VER)
405
  _aligned_free(ptr);
406
#else
407
  // Reconstruct the pointer returned from malloc using the difference
408
  // stored one byte ahead of ptr.
409
  uint8_t *u8ptr = ptr;
410
  free(u8ptr - u8ptr[-1]); // IGNORE memory-check
411
#endif
412
0
}
413
414
0
void OQS_MEM_aligned_secure_free(void *ptr, size_t len) {
415
0
  OQS_MEM_cleanse(ptr, len);
416
0
  OQS_MEM_aligned_free(ptr);
417
0
}
418
419
0
OQS_API void *OQS_MEM_malloc(size_t size) {
420
0
#if defined(OQS_USE_OPENSSL)
421
0
  return OSSL_FUNC(CRYPTO_malloc)(size, OPENSSL_FILE, OPENSSL_LINE);
422
#else
423
  return malloc(size); // IGNORE memory-check
424
#endif
425
0
}
426
427
0
OQS_API void *OQS_MEM_calloc(size_t num_elements, size_t element_size) {
428
0
#if defined(OQS_USE_OPENSSL)
429
0
  return OSSL_FUNC(CRYPTO_zalloc)(num_elements * element_size,
430
0
                                  OPENSSL_FILE, OPENSSL_LINE);
431
#else
432
  return calloc(num_elements, element_size); // IGNORE memory-check
433
#endif
434
0
}
435
436
0
OQS_API char *OQS_MEM_strdup(const char *str) {
437
0
#if defined(OQS_USE_OPENSSL)
438
0
  return OSSL_FUNC(CRYPTO_strdup)(str, OPENSSL_FILE, OPENSSL_LINE);
439
#else
440
  return strdup(str); // IGNORE memory-check
441
#endif
442
0
}