OSSL_TRACE_ENABLED(3SSL)

<h1>πŸ¦‹ OSSL_TRACE_ENABLED πŸ¦‹</h1>

okay bestie, you found the OSSL_TRACE_ENABLED(3SSL) page β€” yes, that's the manual page name, it's giving "the whole OpenSSL Tracing API in one chaotic group chat". Settle in, hydrate, and let's get into it. πŸ’–

✨ NAME ✨

OSSL_trace_enabled, OSSL_trace_begin, OSSL_trace_end, OSSL_TRACE_BEGIN, OSSL_TRACE_END, OSSL_TRACE_CANCEL, OSSL_TRACE, OSSL_TRACE1, OSSL_TRACE2, OSSL_TRACE3, OSSL_TRACE4, OSSL_TRACE5, OSSL_TRACE6, OSSL_TRACE7, OSSL_TRACE8, OSSL_TRACE9, OSSL_TRACEV, OSSL_TRACE_STRING, OSSL_TRACE_STRING_MAX, OSSL_trace_string, OSSL_TRACE_ENABLED β€” the OpenSSL Tracing API. That's the whole squad, no one left behind. 🫢


🌈 SYNOPSIS 🌈

#include <openssl/trace.h>

int OSSL_trace_enabled(int category);

BIO *OSSL_trace_begin(int category);
void OSSL_trace_end(int category, BIO *channel);

/* trace group macros */
OSSL_TRACE_BEGIN(category) {
    ...
    if (some_error) {
        /* Leave trace group prematurely in case of an error */
        OSSL_TRACE_CANCEL(category);
        goto err;
    }
    ...
} OSSL_TRACE_END(category);

/* one-shot trace macros */
OSSL_TRACE(category, text)
OSSL_TRACE1(category, format, arg1)
OSSL_TRACE2(category, format, arg1, arg2)
...
OSSL_TRACE9(category, format, arg1, ..., arg9)
OSSL_TRACE_STRING(category, text, full, data, len)

#define OSSL_TRACE_STRING_MAX 80
int OSSL_trace_string(BIO *out, int text, int full,
                      const unsigned char *data, size_t size);

/* check whether a trace category is enabled */
if (OSSL_TRACE_ENABLED(category)) {
    ...
}

look at all those macros. it's a whole buffet. πŸ“


πŸ’œ DESCRIPTION πŸ’œ

So who is this page for? Mainly the girlies who provide OpenSSL functionality β€” either inside OpenSSL itself, or in a provider, or something provider-adjacent. If that's you, hi, this is your moment. πŸ‘‘

If the tracing facility is enabled (peep "Configure Tracing" down below, it's got its own lil section), these functions are how you generate free-text tracing output.

Tracing output is split into types, and the application turns each one on individually. Those tracing types are described in excruciating beautiful detail over in "Trace types" in OSSL_trace_set_callback(3). One thing though: the fallback type OSSL_TRACE_CATEGORY_ALL should NOT be used with the functions on this page. just don't. πŸ’€

Tracing for a specific category is enabled at run-time if a so-called trace channel is attached to it. And a trace channel is literally just a BIO object that the application can write its trace output to. simple as that, no cap.

The application has two different ways to register a trace channel:

The callback one gets wrapped internally by a dedicated BIO object, so from the tracing code's perspective both channel types are effectively indistinguishable. We call them a simple trace channel and a callback trace channel, respectively. ✨

Now, to actually produce trace output you gotta:

  1. get a pointer to the trace channel (the BIO object) using OSSL_trace_begin(),
  2. write to it with whatever BIO output routines you like, and
  3. release the channel with OSSL_trace_end().

The OSSL_trace_begin() / OSSL_trace_end() calls wrapped around the trace output create a group, and that group acts as a critical section (guarded by a mutex) so that the trace output of different threads doesn't get all mixed up. multithreading girlies, we stay safe. πŸ”’

The tracing code normally does not call OSSL_trace_{begin,end}() directly β€” it reaches for a set of convenience macros instead. That's the "Macros" section, keep scrolling. 😌

🌸 Functions 🌸

  • OSSL_trace_enabled() β€” checks if tracing for the given category is enabled, i.e. whether the tracing facility has been statically enabled (see "Configure Tracing" below) and a trace channel has been registered with OSSL_trace_set_channel(3) or OSSL_trace_set_callback(3).
  • OSSL_trace_begin() β€” starts a tracing section and hands you the channel for the given category in the form of a BIO. This BIO is output only, btw. And the pointer it returns is NULL if the category is invalid or not enabled. πŸ™ˆ
  • OSSL_trace_end() β€” ends a tracing section. that's it, that's the job.
  • OSSL_trace_string() β€” outputs data of length size as a string on BIO out. If text is 0, the function masks any included control characters apart from newlines, and makes sure that for nonempty input the output ends with a newline. Unless full is nonzero, the length gets limited (with a suitable warning) to OSSL_TRACE_STRING_MAX characters, which currently is 80.
🚨 okay this part is serious: using OSSL_trace_begin() and OSSL_trace_end() to wrap tracing sections is mandatory. Trying to produce tracing output outside of such sections has undefined results. undefined behaviour is not cute, bestie. don't do it.

πŸŽ€ Macros πŸŽ€

There are a bunch of convenience macros defined so that tracing stays easy and consistent. obsessed, honestly.

OSSL_TRACE_BEGIN() and OSSL_TRACE_END() reserve the BIO "trc_out" and are used like this to wrap a trace section:

OSSL_TRACE_BEGIN(TLS) {

    BIO_printf(trc_out, ... );

} OSSL_TRACE_END(TLS);

This will normally expand to:

do {
    BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
    if (trc_out != NULL) {
        ...
        BIO_printf(trc_out, ...);
    }
    OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
} while (0);

OSSL_TRACE_CANCEL() must be used before returning from, or jumping out of, a trace section:

OSSL_TRACE_BEGIN(TLS) {

    if (some_error) {
        OSSL_TRACE_CANCEL(TLS);
        goto err;
    }
    BIO_printf(trc_out, ... );

} OSSL_TRACE_END(TLS);

This will normally expand to:

do {
    BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
    if (trc_out != NULL) {
        if (some_error) {
            OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
            goto err;
        }
        BIO_printf(trc_out, ... );
    }
    OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
} while (0);

OSSL_TRACE() and OSSL_TRACE1(), OSSL_TRACE2(), … OSSL_TRACE9() are the so-called one-shot macros:

  • The macro call OSSL_TRACE(category, text) produces literal text trace output.
  • The macro call OSSL_TRACEn(category, format, arg1, ..., argn) produces printf-style trace output with n format field arguments (n=1,...,9). It expands to:
OSSL_TRACE_BEGIN(category) {
    BIO_printf(trc_out, format, arg1, ..., argN);
} OSSL_TRACE_END(category)

Internally, all the one-shot macros are implemented using a generic OSSL_TRACEV() macro, because C90 does not support variadic macros. That helper macro has a rather weird synopsis and should not be used directly. like, it's the backstage crew, let it cook in peace. πŸ’…

The macro call OSSL_TRACE_STRING(category, text, full, data, len) outputs data of length size as a string if tracing for the given category is enabled. It expands to:

OSSL_TRACE_BEGIN(category) {
    OSSL_trace_string(trc_out, text, full, data, len);
} OSSL_TRACE_END(category)

And the OSSL_TRACE_ENABLED() macro lets you conditionally execute code only if a specific trace category is enabled. In some situations that's simpler than entering a trace section with OSSL_TRACE_BEGIN() / OSSL_TRACE_END(). For example, the code

if (OSSL_TRACE_ENABLED(TLS)) {
    ...
}

expands to

if (OSSL_trace_enabled(OSSL_TRACE_CATEGORY_TLS) {
    ...
}

⭐ NOTES ⭐

You do not need to guard trace output function calls like OSSL_TRACE(category, ...) with OSSL_TRACE_ENABLED(category). it's already handled. chill. 🧘

But β€” if producing the trace output requires carrying out auxiliary calculations, that auxiliary code should go inside a conditional block that only runs when the trace category is enabled.

The most natural way to do that is to put the code inside the trace section itself, because it already introduces exactly such a conditional block:

OSSL_TRACE_BEGIN(TLS) {
    int var = do_some_auxiliary_calculation();

    BIO_printf(trc_out, "var = %d\n", var);

} OSSL_TRACE_END(TLS);

In some cases it's more advantageous to use a simple conditional group instead of a trace section. That's the case when calculations and tracing happen in different locations of the code, or when the calculations are so time-consuming that putting them inside a (critical) trace section would create too much contention:

if (OSSL_TRACE_ENABLED(TLS)) {
    int var = do_some_auxiliary_calculation();

    OSSL_TRACE1("var = %d\n", var);
}

Note however that premature optimization of tracing code is in general futile, and it's better to keep the tracing code as simple as possible. Because most often the limiting factor for the application's speed is the time it takes to print the trace output, not to calculate it. fr fr. 🫠

🧚 Configure Tracing 🧚

By default, the OpenSSL library is built with tracing disabled. So to use any of this functionality, you've gotta configure and build OpenSSL with the 'enable-trace' option. periodt.

When the library is built with tracing disabled:

  • The macro OPENSSL_NO_TRACE is defined in <openssl/opensslconf.h>.
  • All functions are still present, but OSSL_trace_enabled() will always report the categories as disabled, and all other functions will do nothing. (they're on stage but the mic is off. 😭)
  • The convenience macros are defined to produce dead code. For example, take this example from the "Macros" section above:
OSSL_TRACE_BEGIN(TLS) {

    if (condition) {
        OSSL_TRACE_CANCEL(TLS);
        goto err;
    }
    BIO_printf(trc_out, ... );

} OSSL_TRACE_END(TLS);

When the tracing API isn't operational, that will expand to:

do {
    BIO *trc_out = NULL;
    if (0) {
        if (condition) {
            ((void)0);
            goto err;
        }
        BIO_printf(trc_out, ... );
    }
} while (0);

πŸ’– RETURN VALUES πŸ’–

  • OSSL_trace_enabled() returns 1 if tracing for the given type is operational and enabled, otherwise 0.
  • OSSL_trace_begin() returns a BIO pointer if the given type is enabled, otherwise NULL.
  • OSSL_trace_string() returns the number of characters emitted, or -1 on error.

πŸ‘‘ SEE ALSO πŸ‘‘

OSSL_trace_set_channel(3), OSSL_trace_set_callback(3)


πŸ•°οΈ HISTORY πŸ•°οΈ

  • The OpenSSL Tracing functions were added in OpenSSL 3.0.
  • OSSL_TRACE_STRING(), OSSL_TRACE_STRING_MAX, and OSSL_trace_string were added in OpenSSL 3.2.

Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.

Licensed under the Apache License 2.0 (the "License"). You may not use this file except in compliance with the License. You can obtain a copy in the file LICENSE in the source distribution or at <https://www.openssl.org/source/license.html>.


that's the whole page bestie, you ate it. πŸ’…βœ¨ this was OpenSSL 4.0.3, dated 2026-09-29 β€” mwah, go trace something iconic. πŸ¦‹πŸ’–

πŸ“¦ where this page comes from