/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 */ |