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