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 }; 142 143 const 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 157 int 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 */ 174 static 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 187 enum { 188 CHANNEL, 189 PREFIX, 190 SUFFIX 191 }; 192 193 static 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 214 static 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 235 static int do_ossl_trace_init(void); 236 static CRYPTO_ONCE trace_inited = CRYPTO_ONCE_STATIC_INIT; 237 DEFINE_RUN_ONCE_STATIC(ossl_trace_init) 238 { 239 return do_ossl_trace_init(); 240 } 241 242 static 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 327 static int do_ossl_trace_init(void) 328 { 329 trace_lock = CRYPTO_THREAD_lock_new(); 330 return trace_lock != NULL; 331 } 332 333 #endif 334 335 void 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 357 int 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 368 static 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 391 int 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 427 int 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 437 int 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 448 static 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 458 int 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 469 BIO *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 503 void 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