/src/openssl31/crypto/trace.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /*  | 
2  |  |  * Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.  | 
3  |  |  *  | 
4  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use  | 
5  |  |  * this file except in compliance with the License.  You can obtain a copy  | 
6  |  |  * in the file LICENSE in the source distribution or at  | 
7  |  |  * https://www.openssl.org/source/license.html  | 
8  |  |  */  | 
9  |  |  | 
10  |  | #include <stdio.h>  | 
11  |  | #include <string.h>  | 
12  |  |  | 
13  |  | #include "internal/thread_once.h"  | 
14  |  | #include <openssl/bio.h>  | 
15  |  | #include <openssl/crypto.h>  | 
16  |  | #include <openssl/trace.h>  | 
17  |  | #include "internal/bio.h"  | 
18  |  | #include "internal/nelem.h"  | 
19  |  | #include "internal/refcount.h"  | 
20  |  | #include "crypto/cryptlib.h"  | 
21  |  |  | 
22  |  | #ifndef OPENSSL_NO_TRACE  | 
23  |  |  | 
24  |  | static CRYPTO_RWLOCK *trace_lock = NULL;  | 
25  |  |  | 
26  |  | static const BIO  *current_channel = NULL;  | 
27  |  |  | 
28  |  | /*-  | 
29  |  |  * INTERNAL TRACE CHANNEL IMPLEMENTATION  | 
30  |  |  *  | 
31  |  |  * For our own flexibility, all trace categories are associated with a  | 
32  |  |  * BIO sink object, also called the trace channel. Instead of a BIO object,  | 
33  |  |  * the application can also provide a callback function, in which case an  | 
34  |  |  * internal trace channel is attached, which simply calls the registered  | 
35  |  |  * callback function.  | 
36  |  |  */  | 
37  |  | static int trace_write(BIO *b, const char *buf,  | 
38  |  |                                size_t num, size_t *written);  | 
39  |  | static int trace_puts(BIO *b, const char *str);  | 
40  |  | static long trace_ctrl(BIO *channel, int cmd, long argl, void *argp);  | 
41  |  | static int trace_free(BIO *b);  | 
42  |  |  | 
43  |  | static const BIO_METHOD trace_method = { | 
44  |  |     BIO_TYPE_SOURCE_SINK,  | 
45  |  |     "trace",  | 
46  |  |     trace_write,  | 
47  |  |     NULL,                        /* old write */  | 
48  |  |     NULL,                        /* read_ex */  | 
49  |  |     NULL,                        /* read */  | 
50  |  |     trace_puts,  | 
51  |  |     NULL,                        /* gets */  | 
52  |  |     trace_ctrl,                  /* ctrl */  | 
53  |  |     NULL,                        /* create */  | 
54  |  |     trace_free,                  /* free */  | 
55  |  |     NULL,                        /* callback_ctrl */  | 
56  |  | };  | 
57  |  |  | 
58  |  | struct trace_data_st { | 
59  |  |     OSSL_trace_cb callback;  | 
60  |  |     int category;  | 
61  |  |     void *data;  | 
62  |  | };  | 
63  |  |  | 
64  |  | static int trace_write(BIO *channel,  | 
65  |  |                        const char *buf, size_t num, size_t *written)  | 
66  |  | { | 
67  |  |     struct trace_data_st *ctx = BIO_get_data(channel);  | 
68  |  |     size_t cnt = ctx->callback(buf, num, ctx->category, OSSL_TRACE_CTRL_WRITE,  | 
69  |  |                                ctx->data);  | 
70  |  |  | 
71  |  |     *written = cnt;  | 
72  |  |     return cnt != 0;  | 
73  |  | }  | 
74  |  |  | 
75  |  | static int trace_puts(BIO *channel, const char *str)  | 
76  |  | { | 
77  |  |     size_t written;  | 
78  |  |  | 
79  |  |     if (trace_write(channel, str, strlen(str), &written))  | 
80  |  |         return (int)written;  | 
81  |  |  | 
82  |  |     return EOF;  | 
83  |  | }  | 
84  |  |  | 
85  |  | static long trace_ctrl(BIO *channel, int cmd, long argl, void *argp)  | 
86  |  | { | 
87  |  |     struct trace_data_st *ctx = BIO_get_data(channel);  | 
88  |  |  | 
89  |  |     switch (cmd) { | 
90  |  |     case OSSL_TRACE_CTRL_BEGIN:  | 
91  |  |     case OSSL_TRACE_CTRL_END:  | 
92  |  |         /* We know that the callback is likely to return 0 here */  | 
93  |  |         ctx->callback("", 0, ctx->category, cmd, ctx->data); | 
94  |  |         return 1;  | 
95  |  |     default:  | 
96  |  |         break;  | 
97  |  |     }  | 
98  |  |     return -2;                   /* Unsupported */  | 
99  |  | }  | 
100  |  |  | 
101  |  | static int trace_free(BIO *channel)  | 
102  |  | { | 
103  |  |     if (channel == NULL)  | 
104  |  |         return 0;  | 
105  |  |     OPENSSL_free(BIO_get_data(channel));  | 
106  |  |     return 1;  | 
107  |  | }  | 
108  |  | #endif  | 
109  |  |  | 
110  |  | /*-  | 
111  |  |  * TRACE  | 
112  |  |  */  | 
113  |  |  | 
114  |  | /* Helper struct and macro to get name string to number mapping */  | 
115  |  | struct trace_category_st { | 
116  |  |     const char * const name;  | 
117  |  |     const int num;  | 
118  |  | };  | 
119  |  | #define TRACE_CATEGORY_(name)       { #name, OSSL_TRACE_CATEGORY_##name } | 
120  |  |  | 
121  |  | static const struct trace_category_st  | 
122  |  |     trace_categories[OSSL_TRACE_CATEGORY_NUM] = { | 
123  |  |     TRACE_CATEGORY_(ALL),  | 
124  |  |     TRACE_CATEGORY_(TRACE),  | 
125  |  |     TRACE_CATEGORY_(INIT),  | 
126  |  |     TRACE_CATEGORY_(TLS),  | 
127  |  |     TRACE_CATEGORY_(TLS_CIPHER),  | 
128  |  |     TRACE_CATEGORY_(CONF),  | 
129  |  |     TRACE_CATEGORY_(ENGINE_TABLE),  | 
130  |  |     TRACE_CATEGORY_(ENGINE_REF_COUNT),  | 
131  |  |     TRACE_CATEGORY_(PKCS5V2),  | 
132  |  |     TRACE_CATEGORY_(PKCS12_KEYGEN),  | 
133  |  |     TRACE_CATEGORY_(PKCS12_DECRYPT),  | 
134  |  |     TRACE_CATEGORY_(X509V3_POLICY),  | 
135  |  |     TRACE_CATEGORY_(BN_CTX),  | 
136  |  |     TRACE_CATEGORY_(CMP),  | 
137  |  |     TRACE_CATEGORY_(STORE),  | 
138  |  |     TRACE_CATEGORY_(DECODER),  | 
139  |  |     TRACE_CATEGORY_(ENCODER),  | 
140  |  |     TRACE_CATEGORY_(REF_COUNT),  | 
141  |  |     TRACE_CATEGORY_(HTTP),  | 
142  |  | }; /* KEEP THIS LIST IN SYNC with #define OSSL_TRACE_CATEGORY_... in trace.h */  | 
143  |  |  | 
144  |  | const char *OSSL_trace_get_category_name(int num)  | 
145  | 0  | { | 
146  | 0  |     if (num < 0 || (size_t)num >= OSSL_NELEM(trace_categories))  | 
147  | 0  |         return NULL;  | 
148  |  |     /*  | 
149  |  |      * Partial check that OSSL_TRACE_CATEGORY_... macros  | 
150  |  |      * are synced with trace_categories array  | 
151  |  |      */  | 
152  | 0  |     if (!ossl_assert(trace_categories[num].name != NULL)  | 
153  | 0  |         || !ossl_assert(trace_categories[num].num == num))  | 
154  | 0  |         return NULL;  | 
155  | 0  |     return trace_categories[num].name;  | 
156  | 0  | }  | 
157  |  |  | 
158  |  | int OSSL_trace_get_category_num(const char *name)  | 
159  | 0  | { | 
160  | 0  |     size_t i;  | 
161  |  | 
  | 
162  | 0  |     if (name == NULL)  | 
163  | 0  |         return -1;  | 
164  |  |  | 
165  | 0  |     for (i = 0; i < OSSL_NELEM(trace_categories); i++)  | 
166  | 0  |         if (OPENSSL_strcasecmp(name, trace_categories[i].name) == 0)  | 
167  | 0  |             return trace_categories[i].num;  | 
168  |  |  | 
169  | 0  |     return -1; /* not found */  | 
170  | 0  | }  | 
171  |  |  | 
172  |  | #ifndef OPENSSL_NO_TRACE  | 
173  |  |  | 
174  |  | /* We use one trace channel for each trace category */  | 
175  |  | static struct { | 
176  |  |     enum { SIMPLE_CHANNEL, CALLBACK_CHANNEL } type; | 
177  |  |     BIO *bio;  | 
178  |  |     char *prefix;  | 
179  |  |     char *suffix;  | 
180  |  | } trace_channels[OSSL_TRACE_CATEGORY_NUM] = { | 
181  |  |     { 0, NULL, NULL, NULL }, | 
182  |  | };  | 
183  |  |  | 
184  |  | #endif  | 
185  |  |  | 
186  |  | #ifndef OPENSSL_NO_TRACE  | 
187  |  |  | 
188  |  | enum { | 
189  |  |     CHANNEL,  | 
190  |  |     PREFIX,  | 
191  |  |     SUFFIX  | 
192  |  | };  | 
193  |  |  | 
194  |  | static int trace_attach_cb(int category, int type, const void *data)  | 
195  |  | { | 
196  |  |     switch (type) { | 
197  |  |     case CHANNEL:  | 
198  |  |         OSSL_TRACE2(TRACE, "Attach channel %p to category '%s'\n",  | 
199  |  |                     data, trace_categories[category].name);  | 
200  |  |         break;  | 
201  |  |     case PREFIX:  | 
202  |  |         OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n",  | 
203  |  |                     (const char *)data, trace_categories[category].name);  | 
204  |  |         break;  | 
205  |  |     case SUFFIX:  | 
206  |  |         OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n",  | 
207  |  |                     (const char *)data, trace_categories[category].name);  | 
208  |  |         break;  | 
209  |  |     default:                     /* No clue */  | 
210  |  |         break;  | 
211  |  |     }  | 
212  |  |     return 1;  | 
213  |  | }  | 
214  |  |  | 
215  |  | static int trace_detach_cb(int category, int type, const void *data)  | 
216  |  | { | 
217  |  |     switch (type) { | 
218  |  |     case CHANNEL:  | 
219  |  |         OSSL_TRACE2(TRACE, "Detach channel %p from category '%s'\n",  | 
220  |  |                     data, trace_categories[category].name);  | 
221  |  |         break;  | 
222  |  |     case PREFIX:  | 
223  |  |         OSSL_TRACE2(TRACE, "Detach prefix \"%s\" from category '%s'\n",  | 
224  |  |                     (const char *)data, trace_categories[category].name);  | 
225  |  |         break;  | 
226  |  |     case SUFFIX:  | 
227  |  |         OSSL_TRACE2(TRACE, "Detach suffix \"%s\" from category '%s'\n",  | 
228  |  |                     (const char *)data, trace_categories[category].name);  | 
229  |  |         break;  | 
230  |  |     default:                     /* No clue */  | 
231  |  |         break;  | 
232  |  |     }  | 
233  |  |     return 1;  | 
234  |  | }  | 
235  |  |  | 
236  |  | static int do_ossl_trace_init(void);  | 
237  |  | static CRYPTO_ONCE trace_inited = CRYPTO_ONCE_STATIC_INIT;  | 
238  |  | DEFINE_RUN_ONCE_STATIC(ossl_trace_init)  | 
239  |  | { | 
240  |  |     return do_ossl_trace_init();  | 
241  |  | }  | 
242  |  |  | 
243  |  | static int set_trace_data(int category, int type, BIO **channel,  | 
244  |  |                           const char **prefix, const char **suffix,  | 
245  |  |                           int (*attach_cb)(int, int, const void *),  | 
246  |  |                           int (*detach_cb)(int, int, const void *))  | 
247  |  | { | 
248  |  |     BIO *curr_channel = NULL;  | 
249  |  |     char *curr_prefix = NULL;  | 
250  |  |     char *curr_suffix = NULL;  | 
251  |  |  | 
252  |  |     /* Ensure do_ossl_trace_init() is called once */  | 
253  |  |     if (!RUN_ONCE(&trace_inited, ossl_trace_init))  | 
254  |  |         return 0;  | 
255  |  |  | 
256  |  |     curr_channel = trace_channels[category].bio;  | 
257  |  |     curr_prefix = trace_channels[category].prefix;  | 
258  |  |     curr_suffix = trace_channels[category].suffix;  | 
259  |  |  | 
260  |  |     /* Make sure to run the detach callback first on all data */  | 
261  |  |     if (prefix != NULL && curr_prefix != NULL) { | 
262  |  |         detach_cb(category, PREFIX, curr_prefix);  | 
263  |  |     }  | 
264  |  |  | 
265  |  |     if (suffix != NULL && curr_suffix != NULL) { | 
266  |  |         detach_cb(category, SUFFIX, curr_suffix);  | 
267  |  |     }  | 
268  |  |  | 
269  |  |     if (channel != NULL && curr_channel != NULL) { | 
270  |  |         detach_cb(category, CHANNEL, curr_channel);  | 
271  |  |     }  | 
272  |  |  | 
273  |  |     /* After detach callbacks are done, clear data where appropriate */  | 
274  |  |     if (prefix != NULL && curr_prefix != NULL) { | 
275  |  |         OPENSSL_free(curr_prefix);  | 
276  |  |         trace_channels[category].prefix = NULL;  | 
277  |  |     }  | 
278  |  |  | 
279  |  |     if (suffix != NULL && curr_suffix != NULL) { | 
280  |  |         OPENSSL_free(curr_suffix);  | 
281  |  |         trace_channels[category].suffix = NULL;  | 
282  |  |     }  | 
283  |  |  | 
284  |  |     if (channel != NULL && curr_channel != NULL) { | 
285  |  |         BIO_free(curr_channel);  | 
286  |  |         trace_channels[category].type = 0;  | 
287  |  |         trace_channels[category].bio = NULL;  | 
288  |  |     }  | 
289  |  |  | 
290  |  |     /* Before running callbacks are done, set new data where appropriate */  | 
291  |  |     if (prefix != NULL && *prefix != NULL) { | 
292  |  |         if ((curr_prefix = OPENSSL_strdup(*prefix)) == NULL)  | 
293  |  |             return 0;  | 
294  |  |         trace_channels[category].prefix = curr_prefix;  | 
295  |  |     }  | 
296  |  |  | 
297  |  |     if (suffix != NULL && *suffix != NULL) { | 
298  |  |         if ((curr_suffix = OPENSSL_strdup(*suffix)) == NULL)  | 
299  |  |             return 0;  | 
300  |  |         trace_channels[category].suffix = curr_suffix;  | 
301  |  |     }  | 
302  |  |  | 
303  |  |     if (channel != NULL && *channel != NULL) { | 
304  |  |         trace_channels[category].type = type;  | 
305  |  |         trace_channels[category].bio = *channel;  | 
306  |  |         /*  | 
307  |  |          * This must not be done before setting prefix/suffix,  | 
308  |  |          * as those may fail, and then the caller is mislead to free *channel.  | 
309  |  |          */  | 
310  |  |     }  | 
311  |  |  | 
312  |  |     /* Finally, run the attach callback on the new data */  | 
313  |  |     if (channel != NULL && *channel != NULL) { | 
314  |  |         attach_cb(category, CHANNEL, *channel);  | 
315  |  |     }  | 
316  |  |  | 
317  |  |     if (prefix != NULL && *prefix != NULL) { | 
318  |  |         attach_cb(category, PREFIX, *prefix);  | 
319  |  |     }  | 
320  |  |  | 
321  |  |     if (suffix != NULL && *suffix != NULL) { | 
322  |  |         attach_cb(category, SUFFIX, *suffix);  | 
323  |  |     }  | 
324  |  |  | 
325  |  |     return 1;  | 
326  |  | }  | 
327  |  |  | 
328  |  | static int do_ossl_trace_init(void)  | 
329  |  | { | 
330  |  |     trace_lock = CRYPTO_THREAD_lock_new();  | 
331  |  |     return trace_lock != NULL;  | 
332  |  | }  | 
333  |  |  | 
334  |  | #endif  | 
335  |  |  | 
336  |  | void ossl_trace_cleanup(void)  | 
337  | 133  | { | 
338  |  | #ifndef OPENSSL_NO_TRACE  | 
339  |  |     int category;  | 
340  |  |     BIO *channel = NULL;  | 
341  |  |     const char *prefix = NULL;  | 
342  |  |     const char *suffix = NULL;  | 
343  |  |  | 
344  |  |     for (category = 0; category < OSSL_TRACE_CATEGORY_NUM; category++) { | 
345  |  |         /* We force the TRACE category to be treated last */  | 
346  |  |         if (category == OSSL_TRACE_CATEGORY_TRACE)  | 
347  |  |             continue;  | 
348  |  |         set_trace_data(category, 0, &channel, &prefix, &suffix,  | 
349  |  |                        trace_attach_cb, trace_detach_cb);  | 
350  |  |     }  | 
351  |  |     set_trace_data(OSSL_TRACE_CATEGORY_TRACE, 0, &channel,  | 
352  |  |                    &prefix, &suffix,  | 
353  |  |                    trace_attach_cb, trace_detach_cb);  | 
354  |  |     CRYPTO_THREAD_lock_free(trace_lock);  | 
355  |  | #endif  | 
356  | 133  | }  | 
357  |  |  | 
358  |  | int OSSL_trace_set_channel(int category, BIO *channel)  | 
359  | 133  | { | 
360  |  | #ifndef OPENSSL_NO_TRACE  | 
361  |  |     if (category >= 0 && category < OSSL_TRACE_CATEGORY_NUM)  | 
362  |  |         return set_trace_data(category, SIMPLE_CHANNEL, &channel, NULL, NULL,  | 
363  |  |                               trace_attach_cb, trace_detach_cb);  | 
364  |  | #endif  | 
365  | 133  |     return 0;  | 
366  | 133  | }  | 
367  |  |  | 
368  |  | #ifndef OPENSSL_NO_TRACE  | 
369  |  | static int trace_attach_w_callback_cb(int category, int type, const void *data)  | 
370  |  | { | 
371  |  |     switch (type) { | 
372  |  |     case CHANNEL:  | 
373  |  |         OSSL_TRACE2(TRACE,  | 
374  |  |                     "Attach channel %p to category '%s' (with callback)\n",  | 
375  |  |                     data, trace_categories[category].name);  | 
376  |  |         break;  | 
377  |  |     case PREFIX:  | 
378  |  |         OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n",  | 
379  |  |                     (const char *)data, trace_categories[category].name);  | 
380  |  |         break;  | 
381  |  |     case SUFFIX:  | 
382  |  |         OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n",  | 
383  |  |                     (const char *)data, trace_categories[category].name);  | 
384  |  |         break;  | 
385  |  |     default:                     /* No clue */  | 
386  |  |         break;  | 
387  |  |     }  | 
388  |  |     return 1;  | 
389  |  | }  | 
390  |  | #endif  | 
391  |  |  | 
392  |  | int OSSL_trace_set_callback(int category, OSSL_trace_cb callback, void *data)  | 
393  | 0  | { | 
394  |  | #ifndef OPENSSL_NO_TRACE  | 
395  |  |     BIO *channel = NULL;  | 
396  |  |     struct trace_data_st *trace_data = NULL;  | 
397  |  |  | 
398  |  |     if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM)  | 
399  |  |         return 0;  | 
400  |  |  | 
401  |  |     if (callback != NULL) { | 
402  |  |         if ((channel = BIO_new(&trace_method)) == NULL  | 
403  |  |             || (trace_data =  | 
404  |  |                 OPENSSL_zalloc(sizeof(struct trace_data_st))) == NULL)  | 
405  |  |             goto err;  | 
406  |  |  | 
407  |  |         trace_data->callback = callback;  | 
408  |  |         trace_data->category = category;  | 
409  |  |         trace_data->data = data;  | 
410  |  |  | 
411  |  |         BIO_set_data(channel, trace_data);  | 
412  |  |     }  | 
413  |  |  | 
414  |  |     if (!set_trace_data(category, CALLBACK_CHANNEL, &channel, NULL, NULL,  | 
415  |  |                         trace_attach_w_callback_cb, trace_detach_cb))  | 
416  |  |         goto err;  | 
417  |  |  | 
418  |  |     return 1;  | 
419  |  |  | 
420  |  |  err:  | 
421  |  |     BIO_free(channel);  | 
422  |  |     OPENSSL_free(trace_data);  | 
423  |  | #endif  | 
424  |  | 
  | 
425  | 0  |     return 0;  | 
426  | 0  | }  | 
427  |  |  | 
428  |  | int OSSL_trace_set_prefix(int category, const char *prefix)  | 
429  | 0  | { | 
430  |  | #ifndef OPENSSL_NO_TRACE  | 
431  |  |     if (category >= 0 && category < OSSL_TRACE_CATEGORY_NUM)  | 
432  |  |         return set_trace_data(category, 0, NULL, &prefix, NULL,  | 
433  |  |                               trace_attach_cb, trace_detach_cb);  | 
434  |  | #endif  | 
435  | 0  |     return 0;  | 
436  | 0  | }  | 
437  |  |  | 
438  |  | int OSSL_trace_set_suffix(int category, const char *suffix)  | 
439  | 0  | { | 
440  |  | #ifndef OPENSSL_NO_TRACE  | 
441  |  |     if (category >= 0 && category < OSSL_TRACE_CATEGORY_NUM)  | 
442  |  |         return set_trace_data(category, 0, NULL, NULL, &suffix,  | 
443  |  |                               trace_attach_cb, trace_detach_cb);  | 
444  |  | #endif  | 
445  | 0  |     return 0;  | 
446  | 0  | }  | 
447  |  |  | 
448  |  | #ifndef OPENSSL_NO_TRACE  | 
449  |  | static int ossl_trace_get_category(int category)  | 
450  |  | { | 
451  |  |     if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM)  | 
452  |  |         return -1;  | 
453  |  |     if (trace_channels[category].bio != NULL)  | 
454  |  |         return category;  | 
455  |  |     return OSSL_TRACE_CATEGORY_ALL;  | 
456  |  | }  | 
457  |  | #endif  | 
458  |  |  | 
459  |  | int OSSL_trace_enabled(int category)  | 
460  | 0  | { | 
461  | 0  |     int ret = 0;  | 
462  |  | #ifndef OPENSSL_NO_TRACE  | 
463  |  |     category = ossl_trace_get_category(category);  | 
464  |  |     if (category >= 0)  | 
465  |  |         ret = trace_channels[category].bio != NULL;  | 
466  |  | #endif  | 
467  | 0  |     return ret;  | 
468  | 0  | }  | 
469  |  |  | 
470  |  | BIO *OSSL_trace_begin(int category)  | 
471  | 0  | { | 
472  | 0  |     BIO *channel = NULL;  | 
473  |  | #ifndef OPENSSL_NO_TRACE  | 
474  |  |     char *prefix = NULL;  | 
475  |  |  | 
476  |  |     category = ossl_trace_get_category(category);  | 
477  |  |     if (category < 0 || !OSSL_trace_enabled(category))  | 
478  |  |         return NULL;  | 
479  |  |  | 
480  |  |     channel = trace_channels[category].bio;  | 
481  |  |     prefix = trace_channels[category].prefix;  | 
482  |  |  | 
483  |  |     if (channel != NULL) { | 
484  |  |         if (!CRYPTO_THREAD_write_lock(trace_lock))  | 
485  |  |             return NULL;  | 
486  |  |         current_channel = channel;  | 
487  |  |         switch (trace_channels[category].type) { | 
488  |  |         case SIMPLE_CHANNEL:  | 
489  |  |             if (prefix != NULL) { | 
490  |  |                 (void)BIO_puts(channel, prefix);  | 
491  |  |                 (void)BIO_puts(channel, "\n");  | 
492  |  |             }  | 
493  |  |             break;  | 
494  |  |         case CALLBACK_CHANNEL:  | 
495  |  |             (void)BIO_ctrl(channel, OSSL_TRACE_CTRL_BEGIN,  | 
496  |  |                            prefix == NULL ? 0 : strlen(prefix), prefix);  | 
497  |  |             break;  | 
498  |  |         }  | 
499  |  |     }  | 
500  |  | #endif  | 
501  | 0  |     return channel;  | 
502  | 0  | }  | 
503  |  |  | 
504  |  | void OSSL_trace_end(int category, BIO * channel)  | 
505  | 0  | { | 
506  |  | #ifndef OPENSSL_NO_TRACE  | 
507  |  |     char *suffix = NULL;  | 
508  |  |  | 
509  |  |     category = ossl_trace_get_category(category);  | 
510  |  |     if (category < 0)  | 
511  |  |         return;  | 
512  |  |     suffix = trace_channels[category].suffix;  | 
513  |  |     if (channel != NULL  | 
514  |  |         && ossl_assert(channel == current_channel)) { | 
515  |  |         (void)BIO_flush(channel);  | 
516  |  |         switch (trace_channels[category].type) { | 
517  |  |         case SIMPLE_CHANNEL:  | 
518  |  |             if (suffix != NULL) { | 
519  |  |                 (void)BIO_puts(channel, suffix);  | 
520  |  |                 (void)BIO_puts(channel, "\n");  | 
521  |  |             }  | 
522  |  |             break;  | 
523  |  |         case CALLBACK_CHANNEL:  | 
524  |  |             (void)BIO_ctrl(channel, OSSL_TRACE_CTRL_END,  | 
525  |  |                            suffix == NULL ? 0 : strlen(suffix), suffix);  | 
526  |  |             break;  | 
527  |  |         }  | 
528  |  |         current_channel = NULL;  | 
529  |  |         CRYPTO_THREAD_unlock(trace_lock);  | 
530  |  |     }  | 
531  |  | #endif  | 
532  | 0  | }  |