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 24static CRYPTO_RWLOCK *trace_lock = NULL; 25 26static 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 */ 37static int trace_write(BIO *b, const char *buf, 38 size_t num, size_t *written); 39static int trace_puts(BIO *b, const char *str); 40static long trace_ctrl(BIO *channel, int cmd, long argl, void *argp); 41static int trace_free(BIO *b); 42 43static 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 58struct trace_data_st { 59 OSSL_trace_cb callback; 60 int category; 61 void *data; 62}; 63 64static 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 75static 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 85static 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 101static 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 */ 115struct trace_category_st { 116 const char * const name; 117 const int num; 118}; 119#define TRACE_CATEGORY_(name) { #name, OSSL_TRACE_CATEGORY_##name } 120 121static 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}; 142 143const char *OSSL_trace_get_category_name(int num) 144{ 145 if (num < 0 || (size_t)num >= OSSL_NELEM(trace_categories)) 146 return NULL; 147 /* 148 * Partial check that OSSL_TRACE_CATEGORY_... macros 149 * are synced with trace_categories array 150 */ 151 if (!ossl_assert(trace_categories[num].name != NULL) 152 || !ossl_assert(trace_categories[num].num == num)) 153 return NULL; 154 return trace_categories[num].name; 155} 156 157int OSSL_trace_get_category_num(const char *name) 158{ 159 size_t i; 160 161 if (name == NULL) 162 return -1; 163 164 for (i = 0; i < OSSL_NELEM(trace_categories); i++) 165 if (OPENSSL_strcasecmp(name, trace_categories[i].name) == 0) 166 return trace_categories[i].num; 167 168 return -1; /* not found */ 169} 170 171#ifndef OPENSSL_NO_TRACE 172 173/* We use one trace channel for each trace category */ 174static struct { 175 enum { SIMPLE_CHANNEL, CALLBACK_CHANNEL } type; 176 BIO *bio; 177 char *prefix; 178 char *suffix; 179} trace_channels[OSSL_TRACE_CATEGORY_NUM] = { 180 { 0, NULL, NULL, NULL }, 181}; 182 183#endif 184 185#ifndef OPENSSL_NO_TRACE 186 187enum { 188 CHANNEL, 189 PREFIX, 190 SUFFIX 191}; 192 193static int trace_attach_cb(int category, int type, const void *data) 194{ 195 switch (type) { 196 case CHANNEL: 197 OSSL_TRACE2(TRACE, "Attach channel %p to category '%s'\n", 198 data, trace_categories[category].name); 199 break; 200 case PREFIX: 201 OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n", 202 (const char *)data, trace_categories[category].name); 203 break; 204 case SUFFIX: 205 OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n", 206 (const char *)data, trace_categories[category].name); 207 break; 208 default: /* No clue */ 209 break; 210 } 211 return 1; 212} 213 214static int trace_detach_cb(int category, int type, const void *data) 215{ 216 switch (type) { 217 case CHANNEL: 218 OSSL_TRACE2(TRACE, "Detach channel %p from category '%s'\n", 219 data, trace_categories[category].name); 220 break; 221 case PREFIX: 222 OSSL_TRACE2(TRACE, "Detach prefix \"%s\" from category '%s'\n", 223 (const char *)data, trace_categories[category].name); 224 break; 225 case SUFFIX: 226 OSSL_TRACE2(TRACE, "Detach suffix \"%s\" from category '%s'\n", 227 (const char *)data, trace_categories[category].name); 228 break; 229 default: /* No clue */ 230 break; 231 } 232 return 1; 233} 234 235static int do_ossl_trace_init(void); 236static CRYPTO_ONCE trace_inited = CRYPTO_ONCE_STATIC_INIT; 237DEFINE_RUN_ONCE_STATIC(ossl_trace_init) 238{ 239 return do_ossl_trace_init(); 240} 241 242static int set_trace_data(int category, int type, BIO **channel, 243 const char **prefix, const char **suffix, 244 int (*attach_cb)(int, int, const void *), 245 int (*detach_cb)(int, int, const void *)) 246{ 247 BIO *curr_channel = NULL; 248 char *curr_prefix = NULL; 249 char *curr_suffix = NULL; 250 251 /* Ensure do_ossl_trace_init() is called once */ 252 if (!RUN_ONCE(&trace_inited, ossl_trace_init)) 253 return 0; 254 255 curr_channel = trace_channels[category].bio; 256 curr_prefix = trace_channels[category].prefix; 257 curr_suffix = trace_channels[category].suffix; 258 259 /* Make sure to run the detach callback first on all data */ 260 if (prefix != NULL && curr_prefix != NULL) { 261 detach_cb(category, PREFIX, curr_prefix); 262 } 263 264 if (suffix != NULL && curr_suffix != NULL) { 265 detach_cb(category, SUFFIX, curr_suffix); 266 } 267 268 if (channel != NULL && curr_channel != NULL) { 269 detach_cb(category, CHANNEL, curr_channel); 270 } 271 272 /* After detach callbacks are done, clear data where appropriate */ 273 if (prefix != NULL && curr_prefix != NULL) { 274 OPENSSL_free(curr_prefix); 275 trace_channels[category].prefix = NULL; 276 } 277 278 if (suffix != NULL && curr_suffix != NULL) { 279 OPENSSL_free(curr_suffix); 280 trace_channels[category].suffix = NULL; 281 } 282 283 if (channel != NULL && curr_channel != NULL) { 284 BIO_free(curr_channel); 285 trace_channels[category].type = 0; 286 trace_channels[category].bio = NULL; 287 } 288 289 /* Before running callbacks are done, set new data where appropriate */ 290 if (prefix != NULL && *prefix != NULL) { 291 if ((curr_prefix = OPENSSL_strdup(*prefix)) == NULL) 292 return 0; 293 trace_channels[category].prefix = curr_prefix; 294 } 295 296 if (suffix != NULL && *suffix != NULL) { 297 if ((curr_suffix = OPENSSL_strdup(*suffix)) == NULL) 298 return 0; 299 trace_channels[category].suffix = curr_suffix; 300 } 301 302 if (channel != NULL && *channel != NULL) { 303 trace_channels[category].type = type; 304 trace_channels[category].bio = *channel; 305 /* 306 * This must not be done before setting prefix/suffix, 307 * as those may fail, and then the caller is mislead to free *channel. 308 */ 309 } 310 311 /* Finally, run the attach callback on the new data */ 312 if (channel != NULL && *channel != NULL) { 313 attach_cb(category, CHANNEL, *channel); 314 } 315 316 if (prefix != NULL && *prefix != NULL) { 317 attach_cb(category, PREFIX, *prefix); 318 } 319 320 if (suffix != NULL && *suffix != NULL) { 321 attach_cb(category, SUFFIX, *suffix); 322 } 323 324 return 1; 325} 326 327static int do_ossl_trace_init(void) 328{ 329 trace_lock = CRYPTO_THREAD_lock_new(); 330 return trace_lock != NULL; 331} 332 333#endif 334 335void ossl_trace_cleanup(void) 336{ 337#ifndef OPENSSL_NO_TRACE 338 int category; 339 BIO *channel = NULL; 340 const char *prefix = NULL; 341 const char *suffix = NULL; 342 343 for (category = 0; category < OSSL_TRACE_CATEGORY_NUM; category++) { 344 /* We force the TRACE category to be treated last */ 345 if (category == OSSL_TRACE_CATEGORY_TRACE) 346 continue; 347 set_trace_data(category, 0, &channel, &prefix, &suffix, 348 trace_attach_cb, trace_detach_cb); 349 } 350 set_trace_data(OSSL_TRACE_CATEGORY_TRACE, 0, &channel, 351 &prefix, &suffix, 352 trace_attach_cb, trace_detach_cb); 353 CRYPTO_THREAD_lock_free(trace_lock); 354#endif 355} 356 357int OSSL_trace_set_channel(int category, BIO *channel) 358{ 359#ifndef OPENSSL_NO_TRACE 360 if (category >= 0 && category < OSSL_TRACE_CATEGORY_NUM) 361 return set_trace_data(category, SIMPLE_CHANNEL, &channel, NULL, NULL, 362 trace_attach_cb, trace_detach_cb); 363#endif 364 return 0; 365} 366 367#ifndef OPENSSL_NO_TRACE 368static int trace_attach_w_callback_cb(int category, int type, const void *data) 369{ 370 switch (type) { 371 case CHANNEL: 372 OSSL_TRACE2(TRACE, 373 "Attach channel %p to category '%s' (with callback)\n", 374 data, trace_categories[category].name); 375 break; 376 case PREFIX: 377 OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n", 378 (const char *)data, trace_categories[category].name); 379 break; 380 case SUFFIX: 381 OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n", 382 (const char *)data, trace_categories[category].name); 383 break; 384 default: /* No clue */ 385 break; 386 } 387 return 1; 388} 389#endif 390 391int OSSL_trace_set_callback(int category, OSSL_trace_cb callback, void *data) 392{ 393#ifndef OPENSSL_NO_TRACE 394 BIO *channel = NULL; 395 struct trace_data_st *trace_data = NULL; 396 397 if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM) 398 return 0; 399 400 if (callback != NULL) { 401 if ((channel = BIO_new(&trace_method)) == NULL 402 || (trace_data = 403 OPENSSL_zalloc(sizeof(struct trace_data_st))) == NULL) 404 goto err; 405 406 trace_data->callback = callback; 407 trace_data->category = category; 408 trace_data->data = data; 409 410 BIO_set_data(channel, trace_data); 411 } 412 413 if (!set_trace_data(category, CALLBACK_CHANNEL, &channel, NULL, NULL, 414 trace_attach_w_callback_cb, trace_detach_cb)) 415 goto err; 416 417 return 1; 418 419 err: 420 BIO_free(channel); 421 OPENSSL_free(trace_data); 422#endif 423 424 return 0; 425} 426 427int OSSL_trace_set_prefix(int category, const char *prefix) 428{ 429#ifndef OPENSSL_NO_TRACE 430 if (category >= 0 && category < OSSL_TRACE_CATEGORY_NUM) 431 return set_trace_data(category, 0, NULL, &prefix, NULL, 432 trace_attach_cb, trace_detach_cb); 433#endif 434 return 0; 435} 436 437int OSSL_trace_set_suffix(int category, const char *suffix) 438{ 439#ifndef OPENSSL_NO_TRACE 440 if (category >= 0 && category < OSSL_TRACE_CATEGORY_NUM) 441 return set_trace_data(category, 0, NULL, NULL, &suffix, 442 trace_attach_cb, trace_detach_cb); 443#endif 444 return 0; 445} 446 447#ifndef OPENSSL_NO_TRACE 448static int ossl_trace_get_category(int category) 449{ 450 if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM) 451 return -1; 452 if (trace_channels[category].bio != NULL) 453 return category; 454 return OSSL_TRACE_CATEGORY_ALL; 455} 456#endif 457 458int OSSL_trace_enabled(int category) 459{ 460 int ret = 0; 461#ifndef OPENSSL_NO_TRACE 462 category = ossl_trace_get_category(category); 463 if (category >= 0) 464 ret = trace_channels[category].bio != NULL; 465#endif 466 return ret; 467} 468 469BIO *OSSL_trace_begin(int category) 470{ 471 BIO *channel = NULL; 472#ifndef OPENSSL_NO_TRACE 473 char *prefix = NULL; 474 475 category = ossl_trace_get_category(category); 476 if (category < 0) 477 return NULL; 478 479 channel = trace_channels[category].bio; 480 prefix = trace_channels[category].prefix; 481 482 if (channel != NULL) { 483 if (!CRYPTO_THREAD_write_lock(trace_lock)) 484 return NULL; 485 current_channel = channel; 486 switch (trace_channels[category].type) { 487 case SIMPLE_CHANNEL: 488 if (prefix != NULL) { 489 (void)BIO_puts(channel, prefix); 490 (void)BIO_puts(channel, "\n"); 491 } 492 break; 493 case CALLBACK_CHANNEL: 494 (void)BIO_ctrl(channel, OSSL_TRACE_CTRL_BEGIN, 495 prefix == NULL ? 0 : strlen(prefix), prefix); 496 break; 497 } 498 } 499#endif 500 return channel; 501} 502 503void OSSL_trace_end(int category, BIO * channel) 504{ 505#ifndef OPENSSL_NO_TRACE 506 char *suffix = NULL; 507 508 category = ossl_trace_get_category(category); 509 if (category < 0) 510 return; 511 suffix = trace_channels[category].suffix; 512 if (channel != NULL 513 && ossl_assert(channel == current_channel)) { 514 (void)BIO_flush(channel); 515 switch (trace_channels[category].type) { 516 case SIMPLE_CHANNEL: 517 if (suffix != NULL) { 518 (void)BIO_puts(channel, suffix); 519 (void)BIO_puts(channel, "\n"); 520 } 521 break; 522 case CALLBACK_CHANNEL: 523 (void)BIO_ctrl(channel, OSSL_TRACE_CTRL_END, 524 suffix == NULL ? 0 : strlen(suffix), suffix); 525 break; 526 } 527 current_channel = NULL; 528 CRYPTO_THREAD_unlock(trace_lock); 529 } 530#endif 531} 532