Coverage Report

Created: 2025-11-16 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/crau/crau.h
Line
Count
Source
1
/* SPDX-License-Identifier: MIT OR Unlicense */
2
/* Copyright (C) 2022-2025 The crypto-auditing developers. */
3
4
/* This file declares a set of high-level functions to insert probe
5
 * points used for crypto-auditing into the application programs. See
6
 * <crau/macros.h> for the low-level interface.
7
 *
8
 * As this is a header-only library, one of C files that includes
9
 * this file should do:
10
 *
11
 * #define CRAU_IMPLEMENTATION
12
 * #include "crau/crau.h"
13
 *
14
 * to get the necessary functions are defined.
15
 *
16
 * The following configuration macros can also be set to override the
17
 * behavior of the implementation:
18
 *
19
 * * CRAU_CONTEXT_STACK_DEPTH: depth of the thread-local context stack
20
 *   (default: 3)
21
 *
22
 * * CRAU_RETURN_ADDRESS: return address of the current function
23
 *   (default: auto-detected)
24
 *
25
 * * CRAU_THREAD_LOCAL: thread-local modifier of the C language
26
 *   (default: auto-detected)
27
 *
28
 * * CRAU_MAYBE_UNUSED: an attribute to suppress warnings when a
29
 *   function argument is not used in the function body (default:
30
 *   auto-detected)
31
 *
32
 * Unless ENABLE_CRYPTO_AUDITING is defined, all functions turn to
33
 * no-op.
34
 */
35
36
#ifndef CRAU_CRAU_H
37
#define CRAU_CRAU_H
38
39
#include <stdarg.h>
40
#include <stddef.h>
41
#include <stdint.h>
42
43
/* A special context value used to represent a context which is
44
 * automatically assigned based on the current call frame.
45
 */
46
#ifndef CRAU_AUTO_CONTEXT
47
# ifdef __GNUC__
48
0
#  define CRAU_AUTO_CONTEXT (long)(intptr_t)(char *)__builtin_return_address(0)
49
# elif defined(__CC_ARM)
50
#  define CRAU_AUTO_CONTEXT (long)(intptr_t)(char *)__return_address()
51
# else
52
#  define CRAU_AUTO_CONTEXT CRAU_ORPHANED_CONTEXT
53
# endif
54
#endif /* CRAU_AUTO_CONTEXT */
55
56
/* A special context value used to represent a context which is not
57
 * associated with any parent nor children.
58
 */
59
0
#define CRAU_ORPHANED_CONTEXT ((long)-1)
60
61
#ifndef CRAU_CONTEXT_STACK_DEPTH
62
# define CRAU_CONTEXT_STACK_DEPTH 3
63
#endif /* CRAU_CONTEXT_STACK_DEPTH */
64
65
struct crau_context_stack_st {
66
  long stack[CRAU_CONTEXT_STACK_DEPTH];
67
  size_t top;
68
};
69
70
/* Types of crypto-auditing event data. CRAU_WORD means an integer in
71
 * a machine word, CRAU_STRING means a NUL-terminated
72
 * string. CRAU_BLOB means an explicitly sized binary blob.
73
 */
74
enum crau_data_type_t {
75
  CRAU_WORD,
76
  CRAU_STRING,
77
  CRAU_BLOB,
78
};
79
80
/* Push a context CONTEXT onto the given context stack STACK. If the depth of
81
 * the stack exceeds CRAU_CONTEXT_STACK_DEPTH, the older element will be
82
 * removed.
83
 *
84
 * This call shall be followed by a `crau_pop_context`.
85
 */
86
void crau_push_context(struct crau_context_stack_st *stack,
87
           long context);
88
89
/* Pop a context from the given context stack STACK. If the stack is empty, it
90
 * returns a CRAU_ORPHANED_CONTEXT.
91
 */
92
long crau_pop_context(struct crau_context_stack_st *stack);
93
94
/* Return the context currently active in the given context stack STACK. If
95
 * there is no active context, it returns a CRAU_ORPHANED_CONTEXT.
96
 */
97
long crau_current_context(struct crau_context_stack_st *stack);
98
99
/* Push a context CONTEXT onto the given context stack STACK,
100
 * optionally emitting events through varargs.
101
 *
102
 * If the depth of the stack exceeds CRAU_CONTEXT_STACK_DEPTH, the
103
 * older element will be removed.  This call shall be followed by a
104
 * `crau_pop_context`.
105
 */
106
void crau_push_context_with_data(struct crau_context_stack_st *stack,
107
         long context, ...);
108
109
void crau_push_context_with_datav(struct crau_context_stack_st *stack,
110
          long context, va_list ap);
111
112
/* Push a new context (inferred from the current call stack) onto the given
113
 * context stack STACK, optionally emitting events through varargs.
114
 *
115
 * Typical usage example is as follows:
116
 *
117
 * crau_new_context_with_data(
118
 *   stack,
119
 *   "name", CRAU_STRING, "pk::sign",
120
 *   "pk::algorithm", CRAU_STRING, "mldsa",
121
 *   "pk::bits", CRAU_WORD, 1952 * 8,
122
 *   NULL);
123
 *
124
 * If the depth of the stack exceeds CRAU_CONTEXT_STACK_DEPTH, the
125
 * older element will be removed.  This call shall be followed by a
126
 * `crau_pop_context`.
127
 */
128
#define crau_new_context_with_data(stack, ...)        \
129
  crau_push_context_with_data((stack), CRAU_AUTO_CONTEXT, __VA_ARGS__)
130
131
#define crau_new_context_with_datav(stack, ap)        \
132
  crau_push_context_with_datav((stack), CRAU_AUTO_CONTEXT, (ap))
133
134
/* Emit events through varargs, under the currently active context in the given
135
 * context stack STACK. Unlike `crau_new_context_with_data`, this does not push
136
 * a new context.
137
 */
138
void crau_data(struct crau_context_stack_st *stack, ...);
139
140
void crau_datav(struct crau_context_stack_st *stack, va_list ap);
141
142
#ifdef CRAU_IMPLEMENTATION
143
144
#include "macros.h"
145
146
/* Avoid name clash with crau_data_type_t */
147
#undef CRAU_WORD
148
#undef CRAU_STRING
149
#undef CRAU_BLOB
150
151
# ifdef ENABLE_CRYPTO_AUDITING
152
153
static inline void push_context(struct crau_context_stack_st *stack,
154
        long context)
155
{
156
  stack->stack[stack->top++ % CRAU_CONTEXT_STACK_DEPTH] = context;
157
}
158
159
void crau_push_context(struct crau_context_stack_st *stack,
160
           long context)
161
{
162
  CRAU_NEW_CONTEXT(context, crau_current_context(stack));
163
  push_context(stack, context);
164
}
165
166
long crau_pop_context(struct crau_context_stack_st *stack)
167
{
168
  return stack->top == 0 ? CRAU_ORPHANED_CONTEXT :
169
    stack->stack[--stack->top];
170
}
171
172
long crau_current_context(struct crau_context_stack_st *stack)
173
{
174
  return stack->top == 0 ? CRAU_ORPHANED_CONTEXT :
175
    stack->stack[stack->top - 1];
176
}
177
178
static inline unsigned long
179
crau_accumulate_datav(struct crypto_auditing_data data[CRAU_MAX_DATA_ELEMS],
180
          va_list ap)
181
{
182
  unsigned long count = 0;
183
  char *key_ptr;
184
185
  for (key_ptr = va_arg(ap, char *);
186
       key_ptr != NULL && count < CRAU_MAX_DATA_ELEMS;
187
       key_ptr = va_arg(ap, char *), count++) {
188
    data[count].key_ptr = key_ptr;
189
190
    switch (va_arg(ap, enum crau_data_type_t)) {
191
    case CRAU_WORD:
192
      data[count].value_ptr = (void *)va_arg(ap, intptr_t);
193
      data[count].value_size = (unsigned long)-2;
194
      break;
195
    case CRAU_STRING:
196
      data[count].value_ptr = (void *)va_arg(ap, char *);
197
      data[count].value_size = (unsigned long)-1;
198
      break;
199
    case CRAU_BLOB:
200
      data[count].value_ptr = va_arg(ap, void *);
201
      data[count].value_size = va_arg(ap, unsigned long);
202
      break;
203
    }
204
  }
205
206
  return count;
207
}
208
209
void crau_push_context_with_datav(struct crau_context_stack_st *stack,
210
          long context, va_list ap)
211
{
212
  struct crypto_auditing_data data[CRAU_MAX_DATA_ELEMS];
213
  unsigned long count;
214
215
  count = crau_accumulate_datav(data, ap);
216
217
  CRAU_NEW_CONTEXT_WITH_DATA(context, crau_current_context(stack), data,
218
           count);
219
  push_context(stack, context);
220
}
221
222
void crau_push_context_with_data(struct crau_context_stack_st *stack,
223
         long context, ...)
224
{
225
  va_list ap;
226
227
  va_start(ap, context);
228
  crau_push_context_with_datav(stack, context, ap);
229
  va_end(ap);
230
}
231
232
void crau_datav(struct crau_context_stack_st *stack, va_list ap)
233
{
234
  struct crypto_auditing_data data[CRAU_MAX_DATA_ELEMS];
235
  size_t count;
236
237
  count = crau_accumulate_datav(data, ap);
238
239
  CRAU_DATA(crau_current_context(stack), data, count);
240
}
241
242
void crau_data(struct crau_context_stack_st *stack, ...)
243
{
244
  va_list ap;
245
246
  va_start(ap, stack);
247
  crau_datav(stack, ap);
248
  va_end(ap);
249
}
250
251
# else
252
253
#  ifndef CRAU_MAYBE_UNUSED
254
#   if defined(__has_c_attribute) && \
255
    __has_c_attribute (__maybe_unused__)
256
#    define CRAU_MAYBE_UNUSED [[__maybe_unused__]]
257
#   elif defined(__GNUC__)
258
#    define CRAU_MAYBE_UNUSED __attribute__((__unused__))
259
#   endif
260
#  endif /* CRAU_MAYBE_UNUSED */
261
262
void crau_push_context(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED,
263
           long context CRAU_MAYBE_UNUSED)
264
0
{
265
0
}
266
267
long
268
crau_pop_context(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED)
269
0
{
270
0
  return CRAU_ORPHANED_CONTEXT;
271
0
}
272
273
long
274
crau_current_context(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED)
275
0
{
276
0
  return CRAU_ORPHANED_CONTEXT;
277
0
}
278
279
void crau_push_context_with_datav(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED,
280
          long context CRAU_MAYBE_UNUSED,
281
          va_list ap CRAU_MAYBE_UNUSED)
282
0
{
283
0
}
284
285
void crau_push_context_with_data(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED,
286
         long context CRAU_MAYBE_UNUSED, ...)
287
0
{
288
0
}
289
290
void crau_datav(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED,
291
    va_list ap CRAU_MAYBE_UNUSED)
292
0
{
293
0
}
294
295
void crau_data(struct crau_context_stack_st *stack CRAU_MAYBE_UNUSED, ...)
296
0
{
297
0
}
298
299
# endif /* ENABLE_CRYPTO_AUDITING */
300
301
#endif /* CRAU_IMPLEMENTATION */
302
303
#endif /* CRAU_CRAU_H */