[openssl] master update

Richard Levitte levitte at openssl.org
Wed Mar 6 10:18:19 UTC 2019


The branch master has been updated
       via  18e1e302452e6dea4500b6f981cee7e151294dea (commit)
       via  c699712fa329ce1ce1b4756a50a78ab2f47909e1 (commit)
       via  0b836c2168fee1689ab1ea3bb785e38b9f85ef0f (commit)
       via  3b9e1a3902068baa55ecd16b264891cbcc7549ab (commit)
       via  6e810f2dcab6d27a7158a23888c81882a3501b7f (commit)
       via  5f8a5f46e4e83735bb5ad384d8d7df771d2aa4b3 (commit)
       via  b9ce85f631cf376cd781fd3dfdc80e927d88ee77 (commit)
       via  a902e43d7d34dd3d2cb0a3fe0fe7ae23d9021b40 (commit)
       via  3a9b3d2d93017014032d1bbed3e4193bb423eaae (commit)
       via  f518e3e802d8dcad283be6cb4913dd7cfc6f11fd (commit)
       via  f272be676b5462db641897057a4feaa9e8f35c1d (commit)
       via  f4db05df0e0bc665b98e7cda33d4572071884d03 (commit)
       via  5c64173586386a7c73e6431166c96eb43ae0baa2 (commit)
       via  77359d22c97d1636eccf1fa583dc295228835144 (commit)
       via  49b26f54f4c182d6a860c91d01994bdf2bba20de (commit)
       via  16a9d3746ef7e03207cc3cd290356613556959a5 (commit)
       via  682b444f8a78b8902a3521cd6486bdecb766e5e5 (commit)
       via  2390c573aa598b715eb592c9b4da50a71453347a (commit)
      from  8ab53b193a8e95bb2998744bc184146eb1ddcc23 (commit)


- Log -----------------------------------------------------------------
commit 18e1e302452e6dea4500b6f981cee7e151294dea
Author: Richard Levitte <levitte at openssl.org>
Date:   Sun Feb 10 15:16:20 2019 +0100

    apps/openssl.c: avoid memory leaks
    
    The trace API doesn't know that the BIOs we give it, let alone those
    we attach to callbacks as 'void *data', need to be cleaned up.  This
    must be done in the application.
    
    To ensure this cleanup is done as late as possible, use atexit().
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit c699712fa329ce1ce1b4756a50a78ab2f47909e1
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Dec 14 17:18:00 2018 +0100

    Add a log about the tracing functionality
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 0b836c2168fee1689ab1ea3bb785e38b9f85ef0f
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Dec 14 17:17:22 2018 +0100

    Document the tracing functionality
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 3b9e1a3902068baa55ecd16b264891cbcc7549ab
Author: Richard Levitte <levitte at openssl.org>
Date:   Sat Feb 9 12:37:49 2019 +0100

    Make it possible to trace the trace functionality itself
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 6e810f2dcab6d27a7158a23888c81882a3501b7f
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 12:35:48 2018 +0100

    Adapt BN_CTX_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 5f8a5f46e4e83735bb5ad384d8d7df771d2aa4b3
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 12:04:26 2018 +0100

    Adapt OPENSSL_DEBUG_DECRYPT to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit b9ce85f631cf376cd781fd3dfdc80e927d88ee77
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 08:19:08 2018 +0100

    Adapt OPENSSL_POLICY_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit a902e43d7d34dd3d2cb0a3fe0fe7ae23d9021b40
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 08:07:25 2018 +0100

    Adapt OPENSSL_DEBUG_KEYGEN to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 3a9b3d2d93017014032d1bbed3e4193bb423eaae
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 01:53:13 2018 +0100

    Adapt OPENSSL_DEBUG_PKCS5V2 to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit f518e3e802d8dcad283be6cb4913dd7cfc6f11fd
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 01:42:46 2018 +0100

    Adapt ENGINE_REF_COUNT_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit f272be676b5462db641897057a4feaa9e8f35c1d
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 01:42:07 2018 +0100

    Adapt ENGINE_TABLE_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit f4db05df0e0bc665b98e7cda33d4572071884d03
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 01:37:10 2018 +0100

    Adapt ENGINE_CONF_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 5c64173586386a7c73e6431166c96eb43ae0baa2
Author: Richard Levitte <levitte at openssl.org>
Date:   Thu Dec 13 00:32:57 2018 +0100

    Adapt OPENSSL_INIT_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 77359d22c97d1636eccf1fa583dc295228835144
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Dec 12 23:57:48 2018 +0100

    Adapt CIPHER_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 49b26f54f4c182d6a860c91d01994bdf2bba20de
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Dec 12 00:04:44 2018 +0100

    Adapt SSL_DEBUG to the new generic trace API
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 16a9d3746ef7e03207cc3cd290356613556959a5
Author: Richard Levitte <levitte at openssl.org>
Date:   Wed Dec 12 21:31:36 2018 +0100

    Make it possible to disable the TRACE API
    
    This disabled the tracing functionality by making functions do
    nothing, and making convenience macros produce dead code.
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 682b444f8a78b8902a3521cd6486bdecb766e5e5
Author: Richard Levitte <levitte at openssl.org>
Date:   Fri Dec 14 15:48:53 2018 +0100

    apps/openssl.c: Adapt to enable tracing output
    
    Use the environment variables OPENSSL_TRACE to determine what's going
    to be enabled.  The value of this variables is a comma separated list
    of trace and debugging names, which correspond to the trace category
    macros defined in include/openssl/trace.h.
    
    For example, setting OPENSSL_DEBUG=TRACE,SSL will enable debugging output
    for the types OSSL_TRACE_CATEGORY_TRACE and OSSL_TRACE_CATEGORY_SSL.
    
    This also slightly changes the handling of the prefix method in
    apps/apps.c.  This is for the better, as the prefix method pointer was
    unneccessarily stored in two places.
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

commit 2390c573aa598b715eb592c9b4da50a71453347a
Author: Richard Levitte <levitte at openssl.org>
Date:   Tue Dec 11 23:58:29 2018 +0100

    Add generic trace API
    
    The idea is that the application shall be able to register output
    channels or callbacks to print tracing output as it sees fit.
    
    OpenSSL internals, on the other hand, want to print thoses texts using
    normal printing routines, such as BIO_printf() or BIO_dump() through
    well defined BIOs.
    
    When the application registers callbacks, the tracing functionality
    sets up an internal BIO that simply forwards received text to the
    appropriate application provided callback.
    
    Co-authored-by: Dr. Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
    
    Reviewed-by: Paul Dale <paul.dale at oracle.com>
    (Merged from https://github.com/openssl/openssl/pull/8198)

-----------------------------------------------------------------------

Summary of changes:
 CHANGES                                  |   9 +
 Configure                                |   1 +
 NEWS                                     |   2 +
 apps/apps.c                              |  14 +-
 apps/openssl.c                           | 115 ++++++-
 apps/s_client.c                          |   6 +-
 crypto/bn/bn_ctx.c                       |  72 ++---
 crypto/build.info                        |   1 +
 crypto/engine/eng_cnf.c                  |  19 +-
 crypto/engine/eng_int.h                  |  51 ++--
 crypto/engine/eng_table.c                |  57 ++--
 crypto/evp/p5_crpt2.c                    |  41 +--
 crypto/include/internal/cryptlib_int.h   |   2 +
 crypto/init.c                            | 198 +++++--------
 crypto/pkcs12/p12_decr.c                 |  23 +-
 crypto/pkcs12/p12_key.c                  |  48 +--
 crypto/trace.c                           | 495 +++++++++++++++++++++++++++++++
 crypto/x509v3/pcy_tree.c                 |  67 ++---
 doc/man1/openssl.pod                     |  68 +++++
 doc/man3/OSSL_trace_enabled.pod          | 183 ++++++++++++
 doc/man3/OSSL_trace_get_category_num.pod |  44 +++
 doc/man3/OSSL_trace_set_channel.pod      | 288 ++++++++++++++++++
 include/openssl/trace.h                  | 291 ++++++++++++++++++
 ssl/record/ssl3_record.c                 |  61 ++--
 ssl/s3_lib.c                             |  36 +--
 ssl/ssl_ciph.c                           |  45 +--
 ssl/ssl_init.c                           |  33 +--
 ssl/ssl_lib.c                            |   7 +-
 ssl/statem/statem_clnt.c                 |   7 +-
 ssl/statem/statem_lib.c                  |  14 +-
 ssl/statem/statem_srvr.c                 |  17 +-
 ssl/t1_enc.c                             | 114 +++----
 util/libcrypto.num                       |   9 +
 util/private.num                         |   1 +
 34 files changed, 1869 insertions(+), 570 deletions(-)
 create mode 100644 crypto/trace.c
 create mode 100644 doc/man3/OSSL_trace_enabled.pod
 create mode 100644 doc/man3/OSSL_trace_get_category_num.pod
 create mode 100644 doc/man3/OSSL_trace_set_channel.pod
 create mode 100644 include/openssl/trace.h

diff --git a/CHANGES b/CHANGES
index ff61ff4..d977c76 100644
--- a/CHANGES
+++ b/CHANGES
@@ -9,6 +9,15 @@
 
  Changes between 1.1.1 and 3.0.0 [xx XXX xxxx]
 
+  *) Added support for enabling instrumentation through trace output.
+     This is left to application control, by allowing it to register BIOs as
+     channels for a number of tracing and debugging categories.
+
+     The 'openssl' application has been expanded to enable any of the types
+     available via environment variables defined by the user, and serves as
+     one possible example on how to use this functionality.
+     [Richard Levitte & Matthias St. Pierre]
+
   *) Added build tests for C++.  These are generated files that only do one
      thing, to include one public OpenSSL head file each.  This tests that
      the public header files can be usefully included in a C++ application.
diff --git a/Configure b/Configure
index 707e8b9..b2410a2 100755
--- a/Configure
+++ b/Configure
@@ -417,6 +417,7 @@ my @disablables = (
     "tests",
     "threads",
     "tls",
+    "trace",
     "ts",
     "ubsan",
     "ui-console",
diff --git a/NEWS b/NEWS
index 7ac249e..c743dbc 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@
 
   Major changes between OpenSSL 1.1.1 and OpenSSL 3.0.0 [under development]
 
+      o Add support for enabling instrumentation through trace and debug
+        output.
       o Changed our version number scheme and set the next major release to
         3.0.0
       o Added EVP_MAC, an EVP layer MAC API, and a generic EVP_PKEY to EVP_MAC
diff --git a/apps/apps.c b/apps/apps.c
index 44a90a3..d095dee 100644
--- a/apps/apps.c
+++ b/apps/apps.c
@@ -2243,8 +2243,6 @@ BIO *dup_bio_in(int format)
                       BIO_NOCLOSE | (FMT_istext(format) ? BIO_FP_TEXT : 0));
 }
 
-static BIO_METHOD *prefix_method = NULL;
-
 BIO *dup_bio_out(int format)
 {
     BIO *b = BIO_new_fp(stdout,
@@ -2256,10 +2254,9 @@ BIO *dup_bio_out(int format)
         b = BIO_push(BIO_new(BIO_f_linebuffer()), b);
 #endif
 
-    if (FMT_istext(format) && (prefix = getenv("HARNESS_OSSL_PREFIX")) != NULL) {
-        if (prefix_method == NULL)
-            prefix_method = apps_bf_prefix();
-        b = BIO_push(BIO_new(prefix_method), b);
+    if (FMT_istext(format)
+        && (prefix = getenv("HARNESS_OSSL_PREFIX")) != NULL) {
+        b = BIO_push(BIO_new(apps_bf_prefix()), b);
         BIO_ctrl(b, PREFIX_CTRL_SET_PREFIX, 0, prefix);
     }
 
@@ -2277,8 +2274,13 @@ BIO *dup_bio_err(int format)
     return b;
 }
 
+/*
+ * Because the prefix method is created dynamically, we must also be able
+ * to destroy it.
+ */
 void destroy_prefix_method(void)
 {
+    BIO_METHOD *prefix_method = apps_bf_prefix();
     BIO_meth_free(prefix_method);
     prefix_method = NULL;
 }
diff --git a/apps/openssl.c b/apps/openssl.c
index 6b63b36..854f943 100644
--- a/apps/openssl.c
+++ b/apps/openssl.c
@@ -13,6 +13,7 @@
 #include <stdlib.h>
 #include <openssl/bio.h>
 #include <openssl/crypto.h>
+#include <openssl/trace.h>
 #include <openssl/lhash.h>
 #include <openssl/conf.h>
 #include <openssl/x509.h>
@@ -93,7 +94,6 @@ static int apps_startup(void)
 static void apps_shutdown(void)
 {
     destroy_ui_method();
-    destroy_prefix_method();
 }
 
 static char *make_config_name(void)
@@ -117,6 +117,110 @@ static char *make_config_name(void)
     return p;
 }
 
+typedef struct tracedata_st {
+    BIO *bio;
+    unsigned int ingroup:1;
+} tracedata;
+
+static size_t internal_trace_cb(const char *buf, size_t cnt,
+                                int category, int cmd, void *vdata)
+{
+    int ret;
+    tracedata *trace_data = vdata;
+    int set_prefix = 0;
+
+    switch (cmd) {
+    case OSSL_TRACE_CTRL_BEGIN:
+        trace_data->ingroup = 1;
+        set_prefix = 1;
+        break;
+    case OSSL_TRACE_CTRL_DURING:
+        if (!trace_data->ingroup)
+            set_prefix = 1;
+        break;
+    case OSSL_TRACE_CTRL_END:
+        trace_data->ingroup = 0;
+        break;
+    }
+
+    if (set_prefix) {
+        union {
+            CRYPTO_THREAD_ID tid;
+            unsigned long ltid;
+        } tid;
+        char buffer[256];
+
+        tid.ltid = 0;
+        tid.tid = CRYPTO_THREAD_get_current_id();
+
+        BIO_snprintf(buffer, sizeof(buffer), "TRACE[%lx]:%s: ", tid.ltid,
+                     OSSL_trace_get_category_name(category));
+        BIO_ctrl(trace_data->bio, PREFIX_CTRL_SET_PREFIX,
+                 strlen(buffer), buffer);
+    }
+    ret = BIO_write(trace_data->bio, buf, cnt);
+
+    return ret < 0 ? 0 : ret;
+}
+
+DEFINE_STACK_OF(tracedata)
+static STACK_OF(tracedata) *trace_data_stack;
+
+static void tracedata_free(tracedata *data)
+{
+    BIO_free_all(data->bio);
+    OPENSSL_free(data);
+}
+
+static STACK_OF(tracedata) *trace_data_stack;
+
+static void cleanup_trace(void)
+{
+    sk_tracedata_pop_free(trace_data_stack, tracedata_free);
+}
+
+static void setup_trace(const char *str)
+{
+    char *val;
+
+    trace_data_stack = sk_tracedata_new_null();
+    val = OPENSSL_strdup(str);
+
+    if (val != NULL) {
+        char *valp = val;
+        char *item;
+
+        for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) {
+            int category = OSSL_trace_get_category_num(item);
+
+            if (category >= 0) {
+                BIO *channel = BIO_push(BIO_new(apps_bf_prefix()),
+                                        dup_bio_err(FORMAT_TEXT));
+                tracedata *trace_data = OPENSSL_zalloc(sizeof(*trace_data));
+
+                if (trace_data == NULL
+                    || (trace_data->bio = channel) == NULL
+                    || OSSL_trace_set_callback(category, internal_trace_cb,
+                                               trace_data) == 0
+                    || sk_tracedata_push(trace_data_stack, trace_data) == 0) {
+                    OSSL_trace_set_callback(category, NULL, NULL);
+                    BIO_free_all(channel);
+                    fprintf(stderr,
+                            "warning: unable to setup trace callback for category '%s'.\n",
+                            item);
+                }
+            } else {
+                fprintf(stderr,
+                        "warning: unknown trace category: '%s'.\n",
+                        item);
+            }
+        }
+    }
+
+    OPENSSL_free(val);
+    atexit(cleanup_trace);
+}
+
 int main(int argc, char *argv[])
 {
     FUNCTION f, *fp;
@@ -145,6 +249,15 @@ int main(int argc, char *argv[])
     win32_utf8argv(&argc, &argv);
 #endif
 
+    /*
+     * We use the prefix method to get the trace output we want.  Since some
+     * trace outputs happen with OPENSSL_cleanup(), which is run automatically
+     * after exit(), we need to destroy the prefix method as late as possible.
+     */
+    atexit(destroy_prefix_method);
+
+    setup_trace(getenv("OPENSSL_TRACE"));
+
     p = getenv("OPENSSL_DEBUG_MEMORY");
     if (p != NULL && strcmp(p, "on") == 0)
         CRYPTO_set_mem_debug(1);
diff --git a/apps/s_client.c b/apps/s_client.c
index 687e755..7a41d83 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -38,6 +38,7 @@ typedef unsigned int u_int;
 #include <openssl/rand.h>
 #include <openssl/ocsp.h>
 #include <openssl/bn.h>
+#include <openssl/trace.h>
 #include <openssl/async.h>
 #ifndef OPENSSL_NO_SRP
 # include <openssl/srp.h>
@@ -1521,6 +1522,7 @@ int s_client_main(int argc, char **argv)
             break;
         }
     }
+
     if (count4or6 >= 2) {
         BIO_printf(bio_err, "%s: Can't use both -4 and -6\n", prog);
         goto opthelp;
@@ -3321,8 +3323,7 @@ static void print_stuff(BIO *bio, SSL *s, int full)
         BIO_printf(bio_err, "Using Kernel TLS for sending\n");
 #endif
 
-#ifdef SSL_DEBUG
-    {
+    if (OSSL_TRACE_ENABLED(TLS)) {
         /* Print out local port of connection: useful for debugging */
         int sock;
         union BIO_sock_info_u info;
@@ -3335,7 +3336,6 @@ static void print_stuff(BIO *bio, SSL *s, int full)
         }
         BIO_ADDR_free(info.addr);
     }
-#endif
 
 #if !defined(OPENSSL_NO_NEXTPROTONEG)
     if (next_proto.status != -1) {
diff --git a/crypto/bn/bn_ctx.c b/crypto/bn/bn_ctx.c
index d6e7605..9e908bf 100644
--- a/crypto/bn/bn_ctx.c
+++ b/crypto/bn/bn_ctx.c
@@ -7,6 +7,7 @@
  * https://www.openssl.org/source/license.html
  */
 
+#include <openssl/trace.h>
 #include "internal/cryptlib.h"
 #include "bn_lcl.h"
 
@@ -87,48 +88,38 @@ struct bignum_ctx {
     int flags;
 };
 
-/* Enable this to find BN_CTX bugs */
-#ifdef BN_CTX_DEBUG
-static const char *ctxdbg_cur = NULL;
-static void ctxdbg(BN_CTX *ctx)
+/* Debugging functionality */
+static void ctxdbg(BIO *channel, const char *text, BN_CTX *ctx)
 {
     unsigned int bnidx = 0, fpidx = 0;
     BN_POOL_ITEM *item = ctx->pool.head;
     BN_STACK *stack = &ctx->stack;
-    fprintf(stderr, "(%16p): ", ctx);
+
+    BIO_printf(channel, "%s\n", text);
+    BIO_printf(channel, "  (%16p): ", (void*)ctx);
     while (bnidx < ctx->used) {
-        fprintf(stderr, "%03x ", item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
+        BIO_printf(channel, "%03x ",
+                   item->vals[bnidx++ % BN_CTX_POOL_SIZE].dmax);
         if (!(bnidx % BN_CTX_POOL_SIZE))
             item = item->next;
     }
-    fprintf(stderr, "\n");
+    BIO_printf(channel, "\n");
     bnidx = 0;
-    fprintf(stderr, "          : ");
+    BIO_printf(channel, "   %16s : ", "");
     while (fpidx < stack->depth) {
         while (bnidx++ < stack->indexes[fpidx])
-            fprintf(stderr, "    ");
-        fprintf(stderr, "^^^ ");
+            BIO_printf(channel, "    ");
+        BIO_printf(channel, "^^^ ");
         bnidx++;
         fpidx++;
     }
-    fprintf(stderr, "\n");
+    BIO_printf(channel, "\n");
 }
 
-# define CTXDBG_ENTRY(str, ctx)  do { \
-                                ctxdbg_cur = (str); \
-                                fprintf(stderr,"Starting %s\n", ctxdbg_cur); \
-                                ctxdbg(ctx); \
-                                } while(0)
-# define CTXDBG_EXIT(ctx)        do { \
-                                fprintf(stderr,"Ending %s\n", ctxdbg_cur); \
-                                ctxdbg(ctx); \
-                                } while(0)
-# define CTXDBG_RET(ctx,ret)
-#else
-# define CTXDBG_ENTRY(str, ctx)
-# define CTXDBG_EXIT(ctx)
-# define CTXDBG_RET(ctx,ret)
-#endif
+#define CTXDBG(str, ctx)            \
+    OSSL_TRACE_BEGIN(BN_CTX) {      \
+        ctxdbg(trc_out, str, ctx);  \
+    } OSSL_TRACE_END(BN_CTX)
 
 
 BN_CTX *BN_CTX_new(void)
@@ -158,21 +149,20 @@ void BN_CTX_free(BN_CTX *ctx)
 {
     if (ctx == NULL)
         return;
-#ifdef BN_CTX_DEBUG
-    {
+    OSSL_TRACE_BEGIN(BN_CTX) {
         BN_POOL_ITEM *pool = ctx->pool.head;
-        fprintf(stderr, "BN_CTX_free, stack-size=%d, pool-bignums=%d\n",
-                ctx->stack.size, ctx->pool.size);
-        fprintf(stderr, "dmaxs: ");
+        BIO_printf(trc_out,
+                   "BN_CTX_free(): stack-size=%d, pool-bignums=%d\n",
+                   ctx->stack.size, ctx->pool.size);
+        BIO_printf(trc_out, "  dmaxs: ");
         while (pool) {
             unsigned loop = 0;
             while (loop < BN_CTX_POOL_SIZE)
-                fprintf(stderr, "%02x ", pool->vals[loop++].dmax);
+                BIO_printf(trc_out, "%02x ", pool->vals[loop++].dmax);
             pool = pool->next;
         }
-        fprintf(stderr, "\n");
-    }
-#endif
+        BIO_printf(trc_out, "\n");
+    } OSSL_TRACE_END(BN_CTX);
     BN_STACK_finish(&ctx->stack);
     BN_POOL_finish(&ctx->pool);
     OPENSSL_free(ctx);
@@ -180,7 +170,7 @@ void BN_CTX_free(BN_CTX *ctx)
 
 void BN_CTX_start(BN_CTX *ctx)
 {
-    CTXDBG_ENTRY("BN_CTX_start", ctx);
+    CTXDBG("ENTER BN_CTX_start()", ctx);
     /* If we're already overflowing ... */
     if (ctx->err_stack || ctx->too_many)
         ctx->err_stack++;
@@ -189,12 +179,12 @@ void BN_CTX_start(BN_CTX *ctx)
         BNerr(BN_F_BN_CTX_START, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
         ctx->err_stack++;
     }
-    CTXDBG_EXIT(ctx);
+    CTXDBG("LEAVE BN_CTX_start()", ctx);
 }
 
 void BN_CTX_end(BN_CTX *ctx)
 {
-    CTXDBG_ENTRY("BN_CTX_end", ctx);
+    CTXDBG("ENTER BN_CTX_end()", ctx);
     if (ctx->err_stack)
         ctx->err_stack--;
     else {
@@ -206,14 +196,14 @@ void BN_CTX_end(BN_CTX *ctx)
         /* Unjam "too_many" in case "get" had failed */
         ctx->too_many = 0;
     }
-    CTXDBG_EXIT(ctx);
+    CTXDBG("LEAVE BN_CTX_end()", ctx);
 }
 
 BIGNUM *BN_CTX_get(BN_CTX *ctx)
 {
     BIGNUM *ret;
 
-    CTXDBG_ENTRY("BN_CTX_get", ctx);
+    CTXDBG("ENTER BN_CTX_get()", ctx);
     if (ctx->err_stack || ctx->too_many)
         return NULL;
     if ((ret = BN_POOL_get(&ctx->pool, ctx->flags)) == NULL) {
@@ -230,7 +220,7 @@ BIGNUM *BN_CTX_get(BN_CTX *ctx)
     /* clear BN_FLG_CONSTTIME if leaked from previous frames */
     ret->flags &= (~BN_FLG_CONSTTIME);
     ctx->used++;
-    CTXDBG_RET(ctx, ret);
+    CTXDBG("LEAVE BN_CTX_get()", ctx);
     return ret;
 }
 
diff --git a/crypto/build.info b/crypto/build.info
index 94ed06e..e3e9cee 100644
--- a/crypto/build.info
+++ b/crypto/build.info
@@ -13,6 +13,7 @@ SOURCE[../libcrypto]=\
         ebcdic.c uid.c o_time.c o_str.c o_dir.c o_fopen.c ctype.c \
         threads_pthread.c threads_win.c threads_none.c getenv.c \
         o_init.c o_fips.c mem_sec.c init.c context.c sparse_array.c \
+        trace.c \
         {- $target{cpuid_asm_src} -} {- $target{uplink_aux_src} -}
 
 DEPEND[cversion.o]=buildinf.h
diff --git a/crypto/engine/eng_cnf.c b/crypto/engine/eng_cnf.c
index bece327..c87a8a1 100644
--- a/crypto/engine/eng_cnf.c
+++ b/crypto/engine/eng_cnf.c
@@ -9,8 +9,7 @@
 
 #include "eng_int.h"
 #include <openssl/conf.h>
-
-/* #define ENGINE_CONF_DEBUG */
+#include <openssl/trace.h>
 
 /* ENGINE config module */
 
@@ -50,9 +49,7 @@ static int int_engine_configure(const char *name, const char *value, const CONF
     int soft = 0;
 
     name = skip_dot(name);
-#ifdef ENGINE_CONF_DEBUG
-    fprintf(stderr, "Configuring engine %s\n", name);
-#endif
+    OSSL_TRACE1(ENGINE_CONF, "Configuring engine %s\n", name);
     /* Value is a section containing ENGINE commands */
     ecmds = NCONF_get_section(cnf, value);
 
@@ -66,10 +63,8 @@ static int int_engine_configure(const char *name, const char *value, const CONF
         ecmd = sk_CONF_VALUE_value(ecmds, i);
         ctrlname = skip_dot(ecmd->name);
         ctrlvalue = ecmd->value;
-#ifdef ENGINE_CONF_DEBUG
-        fprintf(stderr, "ENGINE conf: doing ctrl(%s,%s)\n", ctrlname,
-                ctrlvalue);
-#endif
+        OSSL_TRACE2(ENGINE_CONF, "ENGINE conf: doing ctrl(%s,%s)\n",
+                    ctrlname, ctrlvalue);
 
         /* First handle some special pseudo ctrls */
 
@@ -153,10 +148,8 @@ static int int_engine_module_init(CONF_IMODULE *md, const CONF *cnf)
     STACK_OF(CONF_VALUE) *elist;
     CONF_VALUE *cval;
     int i;
-#ifdef ENGINE_CONF_DEBUG
-    fprintf(stderr, "Called engine module: name %s, value %s\n",
-            CONF_imodule_get_name(md), CONF_imodule_get_value(md));
-#endif
+    OSSL_TRACE2(ENGINE_CONF, "Called engine module: name %s, value %s\n",
+                CONF_imodule_get_name(md), CONF_imodule_get_value(md));
     /* Value is a section containing ENGINEs to configure */
     elist = NCONF_get_section(cnf, CONF_imodule_get_value(md));
 
diff --git a/crypto/engine/eng_int.h b/crypto/engine/eng_int.h
index 2a32411..d456175 100644
--- a/crypto/engine/eng_int.h
+++ b/crypto/engine/eng_int.h
@@ -11,6 +11,7 @@
 #ifndef HEADER_ENGINE_INT_H
 # define HEADER_ENGINE_INT_H
 
+# include <openssl/trace.h>
 # include "internal/cryptlib.h"
 # include "internal/engine.h"
 # include "internal/thread_once.h"
@@ -19,27 +20,20 @@
 extern CRYPTO_RWLOCK *global_engine_lock;
 
 /*
- * If we compile with this symbol defined, then both reference counts in the
- * ENGINE structure will be monitored with a line of output on stderr for
- * each change. This prints the engine's pointer address (truncated to
- * unsigned int), "struct" or "funct" to indicate the reference type, the
- * before and after reference count, and the file:line-number pair. The
- * "engine_ref_debug" statements must come *after* the change.
+ * This prints the engine's pointer address (truncated to unsigned int),
+ * "struct" or "funct" to indicate the reference type, the before and after
+ * reference count, and the file:line-number pair. The "engine_ref_debug"
+ * statements must come *after* the change.
  */
-# ifdef ENGINE_REF_COUNT_DEBUG
-
-#  define engine_ref_debug(e, isfunct, diff) \
-        fprintf(stderr, "engine: %08x %s from %d to %d (%s:%d)\n", \
-                (unsigned int)(e), (isfunct ? "funct" : "struct"), \
-                ((isfunct) ? ((e)->funct_ref - (diff)) : ((e)->struct_ref - (diff))), \
-                ((isfunct) ? (e)->funct_ref : (e)->struct_ref), \
-                (OPENSSL_FILE), (OPENSSL_LINE))
-
-# else
-
-#  define engine_ref_debug(e, isfunct, diff)
-
-# endif
+# define engine_ref_debug(e, isfunct, diff)                             \
+    OSSL_TRACE6(ENGINE_REF_COUNT,                                       \
+               "engine: %p %s from %d to %d (%s:%d)\n",               \
+               (void *)(e), (isfunct ? "funct" : "struct"),             \
+               ((isfunct)                                               \
+                ? ((e)->funct_ref - (diff))                             \
+                : ((e)->struct_ref - (diff))),                          \
+               ((isfunct) ? (e)->funct_ref : (e)->struct_ref),          \
+               (OPENSSL_FILE), (OPENSSL_LINE))
 
 /*
  * Any code that will need cleanup operations should use these functions to
@@ -59,14 +53,6 @@ void engine_cleanup_add_last(ENGINE_CLEANUP_CB *cb);
 DEFINE_STACK_OF(ENGINE)
 
 /*
- * If this symbol is defined then engine_table_select(), the function that is
- * used by RSA, DSA (etc) code to select registered ENGINEs, cache defaults
- * and functional references (etc), will display debugging summaries to
- * stderr.
- */
-/* #define ENGINE_TABLE_DEBUG */
-
-/*
  * This represents an implementation table. Dependent code should instantiate
  * it as a (ENGINE_TABLE *) pointer value set initially to NULL.
  */
@@ -76,13 +62,10 @@ int engine_table_register(ENGINE_TABLE **table, ENGINE_CLEANUP_CB *cleanup,
                           int setdefault);
 void engine_table_unregister(ENGINE_TABLE **table, ENGINE *e);
 void engine_table_cleanup(ENGINE_TABLE **table);
-# ifndef ENGINE_TABLE_DEBUG
-ENGINE *engine_table_select(ENGINE_TABLE **table, int nid);
-# else
-ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
+ENGINE *engine_table_select_int(ENGINE_TABLE **table, int nid, const char *f,
                                 int l);
-#  define engine_table_select(t,n) engine_table_select_tmp(t,n,OPENSSL_FILE,OPENSSL_LINE)
-# endif
+# define engine_table_select(t,n)                               \
+    engine_table_select_int(t,n,OPENSSL_FILE,OPENSSL_LINE)
 typedef void (engine_table_doall_cb) (int nid, STACK_OF(ENGINE) *sk,
                                       ENGINE *def, void *arg);
 void engine_table_doall(ENGINE_TABLE *table, engine_table_doall_cb *cb,
diff --git a/crypto/engine/eng_table.c b/crypto/engine/eng_table.c
index b0e3ebb..c3afa58 100644
--- a/crypto/engine/eng_table.c
+++ b/crypto/engine/eng_table.c
@@ -10,6 +10,7 @@
 #include "internal/cryptlib.h"
 #include <openssl/evp.h>
 #include <openssl/lhash.h>
+#include <openssl/trace.h>
 #include "eng_int.h"
 
 /* The type of the items in the table */
@@ -189,29 +190,24 @@ void engine_table_cleanup(ENGINE_TABLE **table)
 }
 
 /* return a functional reference for a given 'nid' */
-#ifndef ENGINE_TABLE_DEBUG
-ENGINE *engine_table_select(ENGINE_TABLE **table, int nid)
-#else
-ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
+ENGINE *engine_table_select_int(ENGINE_TABLE **table, int nid, const char *f,
                                 int l)
-#endif
 {
     ENGINE *ret = NULL;
     ENGINE_PILE tmplate, *fnd = NULL;
     int initres, loop = 0;
 
     if (!(*table)) {
-#ifdef ENGINE_TABLE_DEBUG
-        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, nothing "
-                "registered!\n", f, l, nid);
-#endif
+        OSSL_TRACE3(ENGINE_TABLE,
+                   "%s:%d, nid=%d, nothing registered!\n",
+                   f, l, nid);
         return NULL;
     }
     ERR_set_mark();
     CRYPTO_THREAD_write_lock(global_engine_lock);
     /*
      * Check again inside the lock otherwise we could race against cleanup
-     * operations. But don't worry about a fprintf(stderr).
+     * operations. But don't worry about a debug printout
      */
     if (!int_table_check(table, 0))
         goto end;
@@ -220,10 +216,9 @@ ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
     if (!fnd)
         goto end;
     if (fnd->funct && engine_unlocked_init(fnd->funct)) {
-#ifdef ENGINE_TABLE_DEBUG
-        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
-                "ENGINE '%s' cached\n", f, l, nid, fnd->funct->id);
-#endif
+        OSSL_TRACE4(ENGINE_TABLE,
+                   "%s:%d, nid=%d, using ENGINE '%s' cached\n",
+                   f, l, nid, fnd->funct->id);
         ret = fnd->funct;
         goto end;
     }
@@ -234,10 +229,10 @@ ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
  trynext:
     ret = sk_ENGINE_value(fnd->sk, loop++);
     if (!ret) {
-#ifdef ENGINE_TABLE_DEBUG
-        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, no "
-                "registered implementations would initialise\n", f, l, nid);
-#endif
+        OSSL_TRACE3(ENGINE_TABLE,
+                    "%s:%d, nid=%d, "
+                    "no registered implementations would initialise\n",
+                    f, l, nid);
         goto end;
     }
     /* Try to initialise the ENGINE? */
@@ -252,15 +247,13 @@ ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
             if (fnd->funct)
                 engine_unlocked_finish(fnd->funct, 0);
             fnd->funct = ret;
-#ifdef ENGINE_TABLE_DEBUG
-            fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, "
-                    "setting default to '%s'\n", f, l, nid, ret->id);
-#endif
+            OSSL_TRACE4(ENGINE_TABLE,
+                        "%s:%d, nid=%d, setting default to '%s'\n",
+                        f, l, nid, ret->id);
         }
-#ifdef ENGINE_TABLE_DEBUG
-        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, using "
-                "newly initialised '%s'\n", f, l, nid, ret->id);
-#endif
+        OSSL_TRACE4(ENGINE_TABLE,
+                    "%s:%d, nid=%d, using newly initialised '%s'\n",
+                    f, l, nid, ret->id);
         goto end;
     }
     goto trynext;
@@ -271,14 +264,14 @@ ENGINE *engine_table_select_tmp(ENGINE_TABLE **table, int nid, const char *f,
      */
     if (fnd)
         fnd->uptodate = 1;
-#ifdef ENGINE_TABLE_DEBUG
     if (ret)
-        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
-                "ENGINE '%s'\n", f, l, nid, ret->id);
+        OSSL_TRACE4(ENGINE_TABLE,
+                   "%s:%d, nid=%d, caching ENGINE '%s'\n",
+                   f, l, nid, ret->id);
     else
-        fprintf(stderr, "engine_table_dbg: %s:%d, nid=%d, caching "
-                "'no matching ENGINE'\n", f, l, nid);
-#endif
+        OSSL_TRACE3(ENGINE_TABLE,
+                    "%s:%d, nid=%d, caching 'no matching ENGINE'\n",
+                    f, l, nid);
     CRYPTO_THREAD_unlock(global_engine_lock);
     /*
      * Whatever happened, any failed init()s are not failures in this
diff --git a/crypto/evp/p5_crpt2.c b/crypto/evp/p5_crpt2.c
index 4210e51..ac5b974 100644
--- a/crypto/evp/p5_crpt2.c
+++ b/crypto/evp/p5_crpt2.c
@@ -14,16 +14,10 @@
 #include <openssl/evp.h>
 #include <openssl/kdf.h>
 #include <openssl/hmac.h>
+#include <openssl/trace.h>
 #include "internal/evp_int.h"
 #include "evp_locl.h"
 
-/* set this to print out info about the keygen algorithm */
-/* #define OPENSSL_DEBUG_PKCS5V2 */
-
-#ifdef OPENSSL_DEBUG_PKCS5V2
-static void h__dump(const unsigned char *p, int len);
-#endif
-
 int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
                       const unsigned char *salt, int saltlen, int iter,
                       const EVP_MD *digest, int keylen, unsigned char *out)
@@ -55,15 +49,21 @@ int PKCS5_PBKDF2_HMAC(const char *pass, int passlen,
 
     EVP_KDF_CTX_free(kctx);
 
-# ifdef OPENSSL_DEBUG_PKCS5V2
-    fprintf(stderr, "Password:\n");
-    h__dump(pass, passlen);
-    fprintf(stderr, "Salt:\n");
-    h__dump(salt, saltlen);
-    fprintf(stderr, "Iteration count %d\n", iter);
-    fprintf(stderr, "Key:\n");
-    h__dump(out, keylen);
-# endif
+    OSSL_TRACE_BEGIN(PKCS5V2) {
+        BIO_printf(trc_out, "Password:\n");
+        BIO_hex_string(trc_out,
+                       0, passlen, pass, passlen);
+        BIO_printf(trc_out, "\n");
+        BIO_printf(trc_out, "Salt:\n");
+        BIO_hex_string(trc_out,
+                       0, saltlen, salt, saltlen);
+        BIO_printf(trc_out, "\n");
+        BIO_printf(trc_out, "Iteration count %d\n", iter);
+        BIO_printf(trc_out, "Key:\n");
+        BIO_hex_string(trc_out,
+                       0, keylen, out, keylen);
+        BIO_printf(trc_out, "\n");
+    } OSSL_TRACE_END(PKCS5V2);
     return rv;
 }
 
@@ -200,12 +200,3 @@ int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass,
     PBKDF2PARAM_free(kdf);
     return rv;
 }
-
-# ifdef OPENSSL_DEBUG_PKCS5V2
-static void h__dump(const unsigned char *p, int len)
-{
-    for (; len--; p++)
-        fprintf(stderr, "%02X ", *p);
-    fprintf(stderr, "\n");
-}
-# endif
diff --git a/crypto/include/internal/cryptlib_int.h b/crypto/include/internal/cryptlib_int.h
index 618dadb..422ef01 100644
--- a/crypto/include/internal/cryptlib_int.h
+++ b/crypto/include/internal/cryptlib_int.h
@@ -32,4 +32,6 @@ int ossl_init_thread_start(uint64_t opts);
 # define OPENSSL_INIT_THREAD_ERR_STATE       0x02
 # define OPENSSL_INIT_THREAD_RAND            0x04
 
+int ossl_trace_init(void);
+void ossl_trace_cleanup(void);
 void ossl_malloc_setup_failures(void);
diff --git a/crypto/init.c b/crypto/init.c
index ef9c043..12c9d62 100644
--- a/crypto/init.c
+++ b/crypto/init.c
@@ -27,6 +27,7 @@
 #include "internal/dso_conf.h"
 #include "internal/dso.h"
 #include "internal/store.h"
+#include <openssl/trace.h>
 
 static int stopped = 0;
 
@@ -90,9 +91,10 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base)
 {
     CRYPTO_THREAD_LOCAL key;
 
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_base: Setting up stop handlers\n");
-#endif
+    if (ossl_trace_init() == 0)
+        return 0;
+
+    OSSL_TRACE(INIT, "ossl_init_base: setting up stop handlers\n");
 #ifndef OPENSSL_NO_CRYPTO_MDEBUG
     ossl_malloc_setup_failures();
 #endif
@@ -107,9 +109,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_base)
     return 1;
 
 err:
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_base not ok!\n");
-#endif
+    OSSL_TRACE(INIT, "ossl_init_base failed!\n");
     CRYPTO_THREAD_lock_free(init_lock);
     init_lock = NULL;
 
@@ -158,9 +158,8 @@ DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_register_atexit,
 static CRYPTO_ONCE load_crypto_nodelete = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete)
 {
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_load_crypto_nodelete()\n");
-#endif
+    OSSL_TRACE(INIT, "ossl_init_load_crypto_nodelete()\n");
+
 #if !defined(OPENSSL_NO_DSO) \
     && !defined(OPENSSL_USE_NODELETE) \
     && !defined(OPENSSL_NO_PINSHARED)
@@ -174,10 +173,10 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete)
                                 | GET_MODULE_HANDLE_EX_FLAG_PIN,
                                 (void *)&base_inited, &handle);
 
-#  ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: obtained DSO reference? %s\n",
-                (ret == TRUE ? "No!" : "Yes."));
-#  endif
+        OSSL_TRACE1(INIT,
+                    "ossl_init_load_crypto_nodelete: "
+                    "obtained DSO reference? %s\n",
+                    (ret == TRUE ? "No!" : "Yes."));
         return (ret == TRUE) ? 1 : 0;
     }
 # else
@@ -193,15 +192,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete)
             return 0;
 
         dso = DSO_dsobyaddr(&base_inited, DSO_FLAG_NO_UNLOAD_ON_FREE);
-#  ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: obtained DSO reference? %s\n",
-                (dso == NULL ? "No!" : "Yes."));
         /*
          * In case of No!, it is uncertain our exit()-handlers can still be
          * called. After dlclose() the whole library might have been unloaded
          * already.
          */
-#  endif
+        OSSL_TRACE1(INIT, "obtained DSO reference? %s\n",
+                    (dso == NULL ? "No!" : "Yes."));
         DSO_free(dso);
         err_unshelve_state(err);
     }
@@ -221,10 +218,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings)
      * pulling in all the error strings during static linking
      */
 #if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_load_crypto_strings: "
-                    "err_load_crypto_strings_int()\n");
-# endif
+    OSSL_TRACE(INIT, "err_load_crypto_strings_int()\n");
     ret = err_load_crypto_strings_int();
     load_crypto_strings_inited = 1;
 #endif
@@ -246,10 +240,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers)
      * pulling in all the ciphers during static linking
      */
 #ifndef OPENSSL_NO_AUTOALGINIT
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_add_all_ciphers: "
-                    "openssl_add_all_ciphers_int()\n");
-# endif
+    OSSL_TRACE(INIT, "openssl_add_all_ciphers_int()\n");
     openssl_add_all_ciphers_int();
 #endif
     return 1;
@@ -270,10 +261,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests)
      * pulling in all the ciphers during static linking
      */
 #ifndef OPENSSL_NO_AUTOALGINIT
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_add_all_digests: "
-                    "openssl_add_all_digests()\n");
-# endif
+    OSSL_TRACE(INIT, "openssl_add_all_digests()\n");
     openssl_add_all_digests_int();
 #endif
     return 1;
@@ -294,10 +282,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_macs)
      * pulling in all the macs during static linking
      */
 #ifndef OPENSSL_NO_AUTOALGINIT
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_add_all_macs: "
-                    "openssl_add_all_macs_int()\n");
-# endif
+    OSSL_TRACE(INIT, "openssl_add_all_macs_int()\n");
     openssl_add_all_macs_int();
 #endif
     return 1;
@@ -320,10 +305,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_config)
 }
 DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_config, ossl_init_config)
 {
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr,
-            "OPENSSL_INIT: ossl_init_config: openssl_no_config_int()\n");
-#endif
+    OSSL_TRACE(INIT, "openssl_no_config_int()\n");
     openssl_no_config_int();
     config_inited = 1;
     return 1;
@@ -333,9 +315,7 @@ static CRYPTO_ONCE async = CRYPTO_ONCE_STATIC_INIT;
 static int async_inited = 0;
 DEFINE_RUN_ONCE_STATIC(ossl_init_async)
 {
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_async: async_init()\n");
-#endif
+    OSSL_TRACE(INIT, "async_init()\n");
     if (!async_init())
         return 0;
     async_inited = 1;
@@ -346,22 +326,15 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_async)
 static CRYPTO_ONCE engine_openssl = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_openssl)
 {
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_openssl: "
-                    "engine_load_openssl_int()\n");
-# endif
+    OSSL_TRACE(INIT, "engine_load_openssl_int()\n");
     engine_load_openssl_int();
     return 1;
 }
-
 # ifndef OPENSSL_NO_RDRAND
 static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_rdrand)
 {
-#  ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_rdrand: "
-                    "engine_load_rdrand_int()\n");
-#  endif
+    OSSL_TRACE(INIT, "engine_load_rdrand_int()\n");
     engine_load_rdrand_int();
     return 1;
 }
@@ -369,10 +342,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_rdrand)
 static CRYPTO_ONCE engine_dynamic = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_dynamic)
 {
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_dynamic: "
-                    "engine_load_dynamic_int()\n");
-# endif
+    OSSL_TRACE(INIT, "engine_load_dynamic_int()\n");
     engine_load_dynamic_int();
     return 1;
 }
@@ -381,10 +351,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_dynamic)
 static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
 {
-#   ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
-                    "engine_load_devcrypto_int()\n");
-#   endif
+    OSSL_TRACE(INIT, "engine_load_devcrypto_int()\n");
     engine_load_devcrypto_int();
     return 1;
 }
@@ -393,10 +360,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
 static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
 {
-#   ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_padlock: "
-                    "engine_load_padlock_int()\n");
-#   endif
+    OSSL_TRACE(INIT, "engine_load_padlock_int()\n");
     engine_load_padlock_int();
     return 1;
 }
@@ -405,10 +369,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
 static CRYPTO_ONCE engine_capi = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_capi)
 {
-#   ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_capi: "
-                    "engine_load_capi_int()\n");
-#   endif
+    OSSL_TRACE(INIT, "engine_load_capi_int()\n");
     engine_load_capi_int();
     return 1;
 }
@@ -417,10 +378,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_capi)
 static CRYPTO_ONCE engine_afalg = CRYPTO_ONCE_STATIC_INIT;
 DEFINE_RUN_ONCE_STATIC(ossl_init_engine_afalg)
 {
-#   ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_afalg: "
-                    "engine_load_afalg_int()\n");
-#   endif
+    OSSL_TRACE(INIT, "engine_load_afalg_int()\n");
     engine_load_afalg_int();
     return 1;
 }
@@ -447,26 +405,17 @@ static void ossl_init_thread_stop(struct thread_local_inits_st *locals)
         return;
 
     if (locals->async) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_stop: "
-                        "async_delete_thread_state()\n");
-#endif
+        OSSL_TRACE(INIT, "async_delete_thread_state()\n");
         async_delete_thread_state();
     }
 
     if (locals->err_state) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_stop: "
-                        "err_delete_thread_state()\n");
-#endif
+        OSSL_TRACE(INIT, "err_delete_thread_state()\n");
         err_delete_thread_state();
     }
 
     if (locals->rand) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_stop: "
-                        "drbg_delete_thread_state()\n");
-#endif
+        OSSL_TRACE(INIT, "drbg_delete_thread_state()\n");
         drbg_delete_thread_state();
     }
 
@@ -492,26 +441,23 @@ int ossl_init_thread_start(uint64_t opts)
         return 0;
 
     if (opts & OPENSSL_INIT_THREAD_ASYNC) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_start: "
-                        "marking thread for async\n");
-#endif
+        OSSL_TRACE(INIT,
+                   "ossl_init_thread_start: "
+                   "marking thread for async\n");
         locals->async = 1;
     }
 
     if (opts & OPENSSL_INIT_THREAD_ERR_STATE) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_start: "
-                        "marking thread for err_state\n");
-#endif
+        OSSL_TRACE(INIT,
+                   "ossl_init_thread_start: "
+                   "marking thread for err_state\n");
         locals->err_state = 1;
     }
 
     if (opts & OPENSSL_INIT_THREAD_RAND) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ossl_init_thread_start: "
-                        "marking thread for rand\n");
-#endif
+        OSSL_TRACE(INIT,
+                   "ossl_init_thread_start: "
+                   "marking thread for rand\n");
         locals->rand = 1;
     }
 
@@ -557,27 +503,18 @@ void OPENSSL_cleanup(void)
 
 #ifndef OPENSSL_NO_COMP
     if (zlib_inited) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                        "comp_zlib_cleanup_int()\n");
-#endif
+        OSSL_TRACE(INIT, "OPENSSL_cleanup: comp_zlib_cleanup_int()\n");
         comp_zlib_cleanup_int();
     }
 #endif
 
     if (async_inited) {
-# ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                        "async_deinit()\n");
-# endif
+        OSSL_TRACE(INIT, "OPENSSL_cleanup: async_deinit()\n");
         async_deinit();
     }
 
     if (load_crypto_strings_inited) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                        "err_free_strings_int()\n");
-#endif
+        OSSL_TRACE(INIT, "OPENSSL_cleanup: err_free_strings_int()\n");
         err_free_strings_int();
     }
 
@@ -585,28 +522,6 @@ void OPENSSL_cleanup(void)
     destructor_key.sane = -1;
     CRYPTO_THREAD_cleanup_local(&key);
 
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "rand_cleanup_int()\n");
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "conf_modules_free_int()\n");
-#ifndef OPENSSL_NO_ENGINE
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "engine_cleanup_int()\n");
-#endif
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "crypto_cleanup_all_ex_data_int()\n");
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "bio_sock_cleanup_int()\n");
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "bio_cleanup()\n");
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "evp_cleanup_int()\n");
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "obj_cleanup_int()\n");
-    fprintf(stderr, "OPENSSL_INIT: OPENSSL_cleanup: "
-                    "err_cleanup()\n");
-#endif
     /*
      * Note that cleanup order is important:
      * - rand_cleanup_int could call an ENGINE's RAND cleanup function so
@@ -618,21 +533,42 @@ void OPENSSL_cleanup(void)
      * - ENGINEs and additional EVP algorithms might use added OIDs names so
      * obj_cleanup_int() must be called last
      */
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: rand_cleanup_int()\n");
     rand_cleanup_int();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: rand_drbg_cleanup_int()\n");
     rand_drbg_cleanup_int();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: conf_modules_free_int()\n");
     conf_modules_free_int();
 #ifndef OPENSSL_NO_ENGINE
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: engine_cleanup_int()\n");
     engine_cleanup_int();
 #endif
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_store_cleanup_int()\n");
     ossl_store_cleanup_int();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: crypto_cleanup_all_ex_data_int()\n");
     crypto_cleanup_all_ex_data_int();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: bio_cleanup()\n");
     bio_cleanup();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: evp_cleanup_int()\n");
     evp_cleanup_int();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: obj_cleanup_int()\n");
     obj_cleanup_int();
+
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: err_int()\n");
     err_cleanup();
 
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: CRYPTO_secure_malloc_done()\n");
     CRYPTO_secure_malloc_done();
 
+    OSSL_TRACE(INIT, "OPENSSL_cleanup: ossl_trace_cleanup()\n");
+    ossl_trace_cleanup();
+
     base_inited = 0;
 }
 
@@ -835,12 +771,10 @@ int OPENSSL_atexit(void (*handler)(void))
 
             ERR_set_mark();
             dso = DSO_dsobyaddr(handlersym.sym, DSO_FLAG_NO_UNLOAD_ON_FREE);
-#  ifdef OPENSSL_INIT_DEBUG
-            fprintf(stderr,
-                    "OPENSSL_INIT: OPENSSL_atexit: obtained DSO reference? %s\n",
-                    (dso == NULL ? "No!" : "Yes."));
             /* See same code above in ossl_init_base() for an explanation. */
-#  endif
+            OSSL_TRACE1(INIT,
+                       "atexit: obtained DSO reference? %s\n",
+                       (dso == NULL ? "No!" : "Yes."));
             DSO_free(dso);
             ERR_pop_to_mark();
         }
diff --git a/crypto/pkcs12/p12_decr.c b/crypto/pkcs12/p12_decr.c
index 67a9305..b9d13d9 100644
--- a/crypto/pkcs12/p12_decr.c
+++ b/crypto/pkcs12/p12_decr.c
@@ -10,11 +10,7 @@
 #include <stdio.h>
 #include "internal/cryptlib.h"
 #include <openssl/pkcs12.h>
-
-/* Define this to dump decrypted output to files called DERnnn */
-/*
- * #define OPENSSL_DEBUG_DECRYPT
- */
+#include <openssl/trace.h>
 
 /*
  * Encrypt/Decrypt a buffer based on password and algor, result in a
@@ -95,18 +91,11 @@ void *PKCS12_item_decrypt_d2i(const X509_ALGOR *algor, const ASN1_ITEM *it,
         return NULL;
     }
     p = out;
-#ifdef OPENSSL_DEBUG_DECRYPT
-    {
-        FILE *op;
-
-        char fname[30];
-        static int fnm = 1;
-        sprintf(fname, "DER%d", fnm++);
-        op = fopen(fname, "wb");
-        fwrite(p, 1, outlen, op);
-        fclose(op);
-    }
-#endif
+    OSSL_TRACE_BEGIN(PKCS12_DECRYPT) {
+        BIO_printf(trc_out, "\n");
+        BIO_dump(trc_out, out, outlen);
+        BIO_printf(trc_out, "\n");
+    } OSSL_TRACE_END(PKCS12_DECRYPT);
     ret = ASN1_item_d2i(NULL, &p, outlen, it);
     if (zbuf)
         OPENSSL_cleanse(out, outlen);
diff --git a/crypto/pkcs12/p12_key.c b/crypto/pkcs12/p12_key.c
index 9e9fb17..3580754 100644
--- a/crypto/pkcs12/p12_key.c
+++ b/crypto/pkcs12/p12_key.c
@@ -11,16 +11,7 @@
 #include "internal/cryptlib.h"
 #include <openssl/pkcs12.h>
 #include <openssl/bn.h>
-
-/* Uncomment out this line to get debugging info about key generation */
-/*
- * #define OPENSSL_DEBUG_KEYGEN
- */
-#ifdef OPENSSL_DEBUG_KEYGEN
-# include <openssl/bio.h>
-extern BIO *bio_err;
-void h__dump(unsigned char *p, int len);
-#endif
+#include <openssl/trace.h>
 
 /* PKCS12 compatible key/IV generation */
 #ifndef min
@@ -82,23 +73,22 @@ int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
     int i, j, u, v;
     int ret = 0;
     EVP_MD_CTX *ctx = NULL;
-#ifdef  OPENSSL_DEBUG_KEYGEN
     unsigned char *tmpout = out;
     int tmpn = n;
-#endif
 
     ctx = EVP_MD_CTX_new();
     if (ctx == NULL)
         goto err;
 
-#ifdef  OPENSSL_DEBUG_KEYGEN
-    fprintf(stderr, "KEYGEN DEBUG\n");
-    fprintf(stderr, "ID %d, ITER %d\n", id, iter);
-    fprintf(stderr, "Password (length %d):\n", passlen);
-    h__dump(pass, passlen);
-    fprintf(stderr, "Salt (length %d):\n", saltlen);
-    h__dump(salt, saltlen);
-#endif
+    OSSL_TRACE_BEGIN(PKCS12_KEYGEN) {
+        BIO_printf(trc_out, "PKCS12_key_gen_uni(): ID %d, ITER %d\n", id, iter);
+        BIO_printf(trc_out, "Password (length %d):\n", passlen);
+        BIO_hex_string(trc_out, 0, passlen, pass, passlen);
+        BIO_printf(trc_out, "\n");
+        BIO_printf(trc_out, "Salt (length %d):\n", saltlen);
+        BIO_hex_string(trc_out, 0, saltlen, salt, saltlen);
+        BIO_printf(trc_out, "\n");
+    } OSSL_TRACE_END(PKCS12_KEYGEN);
     v = EVP_MD_block_size(md_type);
     u = EVP_MD_size(md_type);
     if (u < 0 || v <= 0)
@@ -136,10 +126,11 @@ int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
         }
         memcpy(out, Ai, min(n, u));
         if (u >= n) {
-#ifdef OPENSSL_DEBUG_KEYGEN
-            fprintf(stderr, "Output KEY (length %d)\n", tmpn);
-            h__dump(tmpout, tmpn);
-#endif
+            OSSL_TRACE_BEGIN(PKCS12_KEYGEN) {
+                BIO_printf(trc_out, "Output KEY (length %d)\n", tmpn);
+                BIO_hex_string(trc_out, 0, tmpn, tmpout, tmpn);
+                BIO_printf(trc_out, "\n");
+            } OSSL_TRACE_END(PKCS12_KEYGEN);
             ret = 1;
             goto end;
         }
@@ -172,12 +163,3 @@ int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt,
     EVP_MD_CTX_free(ctx);
     return ret;
 }
-
-#ifdef OPENSSL_DEBUG_KEYGEN
-void h__dump(unsigned char *p, int len)
-{
-    for (; len--; p++)
-        fprintf(stderr, "%02X", *p);
-    fprintf(stderr, "\n");
-}
-#endif
diff --git a/crypto/trace.c b/crypto/trace.c
new file mode 100644
index 0000000..8ead944
--- /dev/null
+++ b/crypto/trace.c
@@ -0,0 +1,495 @@
+/*
+ * Copyright 2019 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
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/trace.h>
+#include "internal/bio.h"
+#include "internal/nelem.h"
+#include "internal/cryptlib_int.h"
+
+#include "e_os.h"                /* strcasecmp for Windows */
+
+#ifndef OPENSSL_NO_TRACE
+
+static CRYPTO_RWLOCK *trace_lock = NULL;
+
+static const BIO  *current_channel = NULL;
+
+/*-
+ * INTERNAL TRACE CHANNEL IMPLEMENTATION
+ *
+ * For our own flexibility, all trace categories are associated with a
+ * BIO sink object, also called the trace channel. Instead of a BIO object,
+ * the application can also provide a callback function, in which case an
+ * internal trace channel is attached, which simply calls the registered
+ * callback function.
+ */
+static int trace_write(BIO *b, const char *buf,
+                               size_t num, size_t *written);
+static int trace_puts(BIO *b, const char *str);
+static long trace_ctrl(BIO *channel, int cmd, long argl, void *argp);
+static int trace_free(BIO *b);
+
+static const BIO_METHOD trace_method = {
+    BIO_TYPE_SOURCE_SINK,
+    "trace",
+    trace_write,
+    NULL,                        /* old write */
+    NULL,                        /* read_ex */
+    NULL,                        /* read */
+    trace_puts,
+    NULL,                        /* gets */
+    trace_ctrl,                  /* ctrl */
+    NULL,                        /* create */
+    trace_free,                  /* free */
+    NULL,                        /* callback_ctrl */
+};
+
+struct trace_data_st {
+    OSSL_trace_cb callback;
+    int category;
+    void *data;
+};
+
+static int trace_write(BIO *channel,
+                       const char *buf, size_t num, size_t *written)
+{
+    struct trace_data_st *ctx = BIO_get_data(channel);
+    size_t cnt = ctx->callback(buf, num, ctx->category, OSSL_TRACE_CTRL_DURING,
+                               ctx->data);
+
+    *written = cnt;
+    return cnt != 0;
+}
+
+static int trace_puts(BIO *channel, const char *str)
+{
+    size_t written;
+
+    if (trace_write(channel, str, strlen(str), &written))
+        return (int)written;
+
+    return EOF;
+}
+
+static long trace_ctrl(BIO *channel, int cmd, long argl, void *argp)
+{
+    struct trace_data_st *ctx = BIO_get_data(channel);
+
+    switch (cmd) {
+    case OSSL_TRACE_CTRL_BEGIN:
+    case OSSL_TRACE_CTRL_END:
+        /* We know that the callback is likely to return 0 here */
+        ctx->callback("", 0, ctx->category, cmd, ctx->data);
+        return 1;
+    default:
+        break;
+    }
+    return -2;                   /* Unsupported */
+}
+
+static int trace_free(BIO *channel)
+{
+    if (channel == NULL)
+        return 0;
+    OPENSSL_free(BIO_get_data(channel));
+    return 1;
+}
+#endif
+
+/*-
+ * TRACE
+ */
+
+/* Helper struct and macro to get name string to number mapping */
+struct trace_category_st {
+    const char * const name;
+    const int num;
+};
+#define TRACE_CATEGORY_(name)       { #name, OSSL_TRACE_CATEGORY_##name }
+
+static const struct trace_category_st trace_categories[] = {
+    TRACE_CATEGORY_(ANY),
+    TRACE_CATEGORY_(TRACE),
+    TRACE_CATEGORY_(INIT),
+    TRACE_CATEGORY_(TLS),
+    TRACE_CATEGORY_(TLS_CIPHER),
+    TRACE_CATEGORY_(ENGINE_CONF),
+    TRACE_CATEGORY_(ENGINE_TABLE),
+    TRACE_CATEGORY_(ENGINE_REF_COUNT),
+    TRACE_CATEGORY_(PKCS5V2),
+    TRACE_CATEGORY_(PKCS12_KEYGEN),
+    TRACE_CATEGORY_(PKCS12_DECRYPT),
+    TRACE_CATEGORY_(X509V3_POLICY),
+    TRACE_CATEGORY_(BN_CTX),
+};
+
+const char *OSSL_trace_get_category_name(int num)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(trace_categories); i++)
+        if (trace_categories[i].num == num)
+            return trace_categories[i].name;
+    return NULL; /* not found */
+}
+
+int OSSL_trace_get_category_num(const char *name)
+{
+    size_t i;
+
+    for (i = 0; i < OSSL_NELEM(trace_categories); i++)
+        if (strcasecmp(name, trace_categories[i].name) == 0)
+            return trace_categories[i].num;
+    return -1; /* not found */
+}
+
+#ifndef OPENSSL_NO_TRACE
+
+/* We use one trace channel for each trace category */
+static struct {
+    enum { t_channel, t_callback } type;
+    BIO *bio;
+    char *prefix;
+    char *suffix;
+} trace_channels[OSSL_TRACE_CATEGORY_NUM] = {
+    { 0, NULL, NULL, NULL },
+};
+
+#endif
+
+#ifndef OPENSSL_NO_TRACE
+static int trace_attach_cb(int category, int type, const void *data)
+{
+    switch (type) {
+    case 0:                      /* Channel */
+        OSSL_TRACE2(TRACE, "Attach channel %p to category '%s'\n",
+                    data, trace_categories[category].name);
+        break;
+    case 1:                      /* Prefix */
+        OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n",
+                    (const char *)data, trace_categories[category].name);
+        break;
+    case 2:                      /* Suffix */
+        OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n",
+                    (const char *)data, trace_categories[category].name);
+        break;
+    default:                     /* No clue */
+        break;
+    }
+    return 1;
+}
+
+static int trace_detach_cb(int category, int type, const void *data)
+{
+    switch (type) {
+    case 0:                      /* Channel */
+        OSSL_TRACE2(TRACE, "Detach channel %p from category '%s'\n",
+                    data, trace_categories[category].name);
+        break;
+    case 1:                      /* Prefix */
+        OSSL_TRACE2(TRACE, "Detach prefix \"%s\" from category '%s'\n",
+                    (const char *)data, trace_categories[category].name);
+        break;
+    case 2:                      /* Suffix */
+        OSSL_TRACE2(TRACE, "Detach suffix \"%s\" from category '%s'\n",
+                    (const char *)data, trace_categories[category].name);
+        break;
+    default:                     /* No clue */
+        break;
+    }
+    return 1;
+}
+
+static int set_trace_data(int category, BIO **channel,
+                          const char **prefix, const char **suffix,
+                          int (*attach_cb)(int, int, const void *),
+                          int (*detach_cb)(int, int, const void *))
+{
+    BIO *curr_channel = trace_channels[category].bio;
+    char *curr_prefix = trace_channels[category].prefix;
+    char *curr_suffix = trace_channels[category].suffix;
+
+    /* Make sure to run the detach callback first on all data */
+    if (prefix != NULL && curr_prefix != NULL) {
+        detach_cb(category, 1, curr_prefix);
+    }
+
+    if (suffix != NULL && curr_suffix != NULL) {
+        detach_cb(category, 2, curr_suffix);
+    }
+
+    if (channel != NULL && curr_channel != NULL) {
+        detach_cb(category, 0, curr_channel);
+    }
+
+    /* After detach callbacks are done, clear data where appropriate */
+    if (prefix != NULL && curr_prefix != NULL) {
+        OPENSSL_free(curr_prefix);
+        trace_channels[category].prefix = NULL;
+    }
+
+    if (suffix != NULL && curr_suffix != NULL) {
+        OPENSSL_free(curr_suffix);
+        trace_channels[category].suffix = NULL;
+    }
+
+    if (channel != NULL && curr_channel != NULL) {
+        BIO_free(curr_channel);
+        trace_channels[category].bio = NULL;
+    }
+
+    /* Before running callbacks are done, set new data where appropriate */
+    if (channel != NULL && *channel != NULL) {
+        trace_channels[category].bio = *channel;
+    }
+
+    if (prefix != NULL && *prefix != NULL) {
+        if ((curr_prefix = OPENSSL_strdup(*prefix)) == NULL)
+            return 0;
+        trace_channels[category].prefix = curr_prefix;
+    }
+
+    if (suffix != NULL && *suffix != NULL) {
+        if ((curr_suffix = OPENSSL_strdup(*suffix)) == NULL)
+            return 0;
+        trace_channels[category].suffix = curr_suffix;
+    }
+
+    /* Finally, run the attach callback on the new data */
+    if (channel != NULL && *channel != NULL) {
+        attach_cb(category, 0, *channel);
+    }
+
+    if (prefix != NULL && *prefix != NULL) {
+        attach_cb(category, 1, *prefix);
+    }
+
+    if (suffix != NULL && *suffix != NULL) {
+        attach_cb(category, 2, *suffix);
+    }
+
+    return 1;
+}
+#endif
+
+int ossl_trace_init(void)
+{
+#ifndef OPENSSL_NO_TRACE
+    trace_lock = CRYPTO_THREAD_lock_new();
+    if (trace_lock != NULL)
+        return 1;
+#endif
+
+    return 0;
+}
+
+void ossl_trace_cleanup(void)
+{
+#ifndef OPENSSL_NO_TRACE
+    int category;
+    BIO *channel = NULL;
+    const char *prefix = NULL;
+    const char *suffix = NULL;
+
+    for (category = 0; category < OSSL_TRACE_CATEGORY_NUM; category++) {
+        /* We force the TRACE category to be treated last */
+        if (category == OSSL_TRACE_CATEGORY_TRACE)
+            continue;
+        set_trace_data(category, &channel, &prefix, &suffix,
+                       trace_attach_cb, trace_detach_cb);
+    }
+    set_trace_data(OSSL_TRACE_CATEGORY_TRACE, &channel, &prefix, &suffix,
+                   trace_attach_cb, trace_detach_cb);
+    CRYPTO_THREAD_lock_free(trace_lock);
+#endif
+}
+
+int OSSL_trace_set_channel(int category, BIO *channel)
+{
+#ifndef OPENSSL_NO_TRACE
+    if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM
+        || !set_trace_data(category, &channel, NULL, NULL,
+                           trace_attach_cb, trace_detach_cb))
+        goto err;
+
+    trace_channels[category].type = t_channel;
+    return 1;
+
+ err:
+#endif
+
+    return 0;
+}
+
+#ifndef OPENSSL_NO_TRACE
+static int trace_attach_w_callback_cb(int category, int type, const void *data)
+{
+    switch (type) {
+    case 0:                      /* Channel */
+        OSSL_TRACE2(TRACE,
+                    "Attach channel %p to category '%s' (with callback)\n",
+                    data, trace_categories[category].name);
+        break;
+    case 1:                      /* Prefix */
+        OSSL_TRACE2(TRACE, "Attach prefix \"%s\" to category '%s'\n",
+                    (const char *)data, trace_categories[category].name);
+        break;
+    case 2:                      /* Suffix */
+        OSSL_TRACE2(TRACE, "Attach suffix \"%s\" to category '%s'\n",
+                    (const char *)data, trace_categories[category].name);
+        break;
+    default:                     /* No clue */
+        break;
+    }
+    return 1;
+}
+#endif
+
+int OSSL_trace_set_callback(int category, OSSL_trace_cb callback, void *data)
+{
+#ifndef OPENSSL_NO_TRACE
+    BIO *channel = NULL;
+    struct trace_data_st *trace_data = NULL;
+
+    if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM)
+        goto err;
+
+    if (callback != NULL) {
+        if ((channel = BIO_new(&trace_method)) == NULL
+            || (trace_data =
+                OPENSSL_zalloc(sizeof(struct trace_data_st))) == NULL)
+            goto err;
+
+        trace_data->callback = callback;
+        trace_data->category = category;
+        trace_data->data = data;
+
+        BIO_set_data(channel, trace_data);
+    }
+
+    if (!set_trace_data(category, &channel, NULL, NULL,
+                        trace_attach_w_callback_cb, trace_detach_cb))
+        goto err;
+
+    trace_channels[category].type = t_callback;
+    return 1;
+
+ err:
+    BIO_free(channel);
+    OPENSSL_free(trace_data);
+#endif
+
+    return 0;
+}
+
+int OSSL_trace_set_prefix(int category, const char *prefix)
+{
+#ifndef OPENSSL_NO_TRACE
+    if (category >= 0 || category < OSSL_TRACE_CATEGORY_NUM)
+        return set_trace_data(category, NULL, &prefix, NULL,
+                              trace_attach_cb, trace_detach_cb);
+#endif
+
+    return 0;
+}
+
+int OSSL_trace_set_suffix(int category, const char *suffix)
+{
+#ifndef OPENSSL_NO_TRACE
+    if (category >= 0 || category < OSSL_TRACE_CATEGORY_NUM)
+        return set_trace_data(category, NULL, NULL, &suffix,
+                              trace_attach_cb, trace_detach_cb);
+#endif
+
+    return 0;
+}
+
+#ifndef OPENSSL_NO_TRACE
+static int ossl_trace_get_category(int category)
+{
+    if (category < 0 || category >= OSSL_TRACE_CATEGORY_NUM)
+        return -1;
+    if (trace_channels[category].bio != NULL)
+        return category;
+    return OSSL_TRACE_CATEGORY_ANY;
+}
+#endif
+
+int OSSL_trace_enabled(int category)
+{
+    int ret = 0;
+#ifndef OPENSSL_NO_TRACE
+    category = ossl_trace_get_category(category);
+    ret = trace_channels[category].bio != NULL;
+#endif
+    return ret;
+}
+
+BIO *OSSL_trace_begin(int category)
+{
+    BIO *channel = NULL;
+#ifndef OPENSSL_NO_TRACE
+    char *prefix = NULL;
+
+    category = ossl_trace_get_category(category);
+    channel = trace_channels[category].bio;
+    prefix = trace_channels[category].prefix;
+
+    if (channel != NULL) {
+        CRYPTO_THREAD_write_lock(trace_lock);
+        current_channel = channel;
+        switch (trace_channels[category].type) {
+        case t_channel:
+            if (prefix != NULL) {
+                (void)BIO_puts(channel, prefix);
+                (void)BIO_puts(channel, "\n");
+            }
+            break;
+        case t_callback:
+            (void)BIO_ctrl(channel, OSSL_TRACE_CTRL_BEGIN,
+                           prefix == NULL ? 0 : strlen(prefix), prefix);
+            break;
+        }
+    }
+#endif
+    return channel;
+}
+
+void OSSL_trace_end(int category, BIO * channel)
+{
+#ifndef OPENSSL_NO_TRACE
+    char *suffix = NULL;
+
+    category = ossl_trace_get_category(category);
+    suffix = trace_channels[category].suffix;
+    if (channel != NULL
+        && ossl_assert(channel == current_channel)) {
+        (void)BIO_flush(channel);
+        switch (trace_channels[category].type) {
+        case t_channel:
+            if (suffix != NULL) {
+                (void)BIO_puts(channel, suffix);
+                (void)BIO_puts(channel, "\n");
+            }
+            break;
+        case t_callback:
+            (void)BIO_ctrl(channel, OSSL_TRACE_CTRL_END,
+                           suffix == NULL ? 0 : strlen(suffix), suffix);
+            break;
+        }
+        current_channel = NULL;
+        CRYPTO_THREAD_unlock(trace_lock);
+    }
+#endif
+}
diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c
index 860e4bf..0c5887c 100644
--- a/crypto/x509v3/pcy_tree.c
+++ b/crypto/x509v3/pcy_tree.c
@@ -8,76 +8,71 @@
  */
 
 #include "internal/cryptlib.h"
+#include <openssl/trace.h>
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
 #include "pcy_int.h"
 
-/*
- * Enable this to print out the complete policy tree at various point during
- * evaluation.
- */
-
-/*
- * #define OPENSSL_POLICY_DEBUG
- */
-
-#ifdef OPENSSL_POLICY_DEBUG
-
-static void expected_print(BIO *err, X509_POLICY_LEVEL *lev,
-                           X509_POLICY_NODE *node, int indent)
+static void expected_print(BIO *channel,
+                           X509_POLICY_LEVEL *lev, X509_POLICY_NODE *node,
+                           int indent)
 {
     if ((lev->flags & X509_V_FLAG_INHIBIT_MAP)
         || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK))
-        BIO_puts(err, "  Not Mapped\n");
+        BIO_puts(channel, "  Not Mapped\n");
     else {
         int i;
+
         STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set;
         ASN1_OBJECT *oid;
-        BIO_puts(err, "  Expected: ");
+        BIO_puts(channel, "  Expected: ");
         for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) {
             oid = sk_ASN1_OBJECT_value(pset, i);
             if (i)
-                BIO_puts(err, ", ");
-            i2a_ASN1_OBJECT(err, oid);
+                BIO_puts(channel, ", ");
+            i2a_ASN1_OBJECT(channel, oid);
         }
-        BIO_puts(err, "\n");
+        BIO_puts(channel, "\n");
     }
 }
 
-static void tree_print(char *str, X509_POLICY_TREE *tree,
+static void tree_print(BIO *channel,
+                       char *str, X509_POLICY_TREE *tree,
                        X509_POLICY_LEVEL *curr)
 {
-    BIO *err = BIO_new_fp(stderr, BIO_NOCLOSE);
     X509_POLICY_LEVEL *plev;
 
-    if (err == NULL)
-        return;
     if (!curr)
         curr = tree->levels + tree->nlevel;
     else
         curr++;
 
-    BIO_printf(err, "Level print after %s\n", str);
-    BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels);
+    BIO_printf(channel, "Level print after %s\n", str);
+    BIO_printf(channel, "Printing Up to Level %ld\n",
+               curr - tree->levels);
     for (plev = tree->levels; plev != curr; plev++) {
         int i;
 
-        BIO_printf(err, "Level %ld, flags = %x\n",
+        BIO_printf(channel, "Level %ld, flags = %x\n",
                    (long)(plev - tree->levels), plev->flags);
         for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) {
-            X509_POLICY_NODE *node = sk_X509_POLICY_NODE_value(plev->nodes, i);
+            X509_POLICY_NODE *node =
+                sk_X509_POLICY_NODE_value(plev->nodes, i);
 
-            X509_POLICY_NODE_print(err, node, 2);
-            expected_print(err, plev, node, 2);
-            BIO_printf(err, "  Flags: %x\n", node->data->flags);
+            X509_POLICY_NODE_print(channel, node, 2);
+            expected_print(channel, plev, node, 2);
+            BIO_printf(channel, "  Flags: %x\n", node->data->flags);
         }
         if (plev->anyPolicy)
-            X509_POLICY_NODE_print(err, plev->anyPolicy, 2);
+            X509_POLICY_NODE_print(channel, plev->anyPolicy, 2);
     }
-    BIO_free(err);
 }
-#endif
+
+#define TREE_PRINT(str, tree, curr) \
+    OSSL_TRACE_BEGIN(X509V3_POLICY) { \
+        tree_print(trc_out, "before tree_prune()", tree, curr); \
+    } OSSL_TRACE_END(X509V3_POLICY)
 
 /*-
  * Return value: <= 0 on error, or positive bit mask:
@@ -588,9 +583,7 @@ static int tree_evaluate(X509_POLICY_TREE *tree)
         if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
             && !tree_link_any(curr, cache, tree))
             return X509_PCY_TREE_INTERNAL;
-#ifdef OPENSSL_POLICY_DEBUG
-        tree_print("before tree_prune()", tree, curr);
-#endif
+        TREE_PRINT("before tree_prune()", tree, curr);
         ret = tree_prune(tree, curr);
         if (ret != X509_PCY_TREE_VALID)
             return ret;
@@ -665,9 +658,7 @@ int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
     }
 
     ret = tree_evaluate(tree);
-#ifdef OPENSSL_POLICY_DEBUG
-    tree_print("tree_evaluate()", tree, NULL);
-#endif
+    TREE_PRINT("tree_evaluate()", tree, NULL);
     if (ret <= 0)
         goto error;
 
diff --git a/doc/man1/openssl.pod b/doc/man1/openssl.pod
index a2002d4..ca4f78c 100644
--- a/doc/man1/openssl.pod
+++ b/doc/man1/openssl.pod
@@ -531,6 +531,74 @@ Read the password from standard input.
 
 =back
 
+=head1 ENVIRONMENT
+
+=over 4
+
+=item B<OPENSSL_TRACE=>I<name,...>
+
+Enable tracing output of OpenSSL library, by name.
+This output will only make sense if you know OpenSSL internals well.
+Also, it might not give you any output at all, depending on how
+OpenSSL was built.
+
+The value is a comma separated list of names, with the following
+available:
+
+=over 4
+
+=item B<TRACE>
+
+The tracing functionality.
+
+=item B<TLS>
+
+General SSL/TLS.
+
+=item B<TLS_CIPHER>
+
+SSL/TLS cipher.
+
+=item B<ENGINE_CONF>
+
+ENGINE configuration.
+
+=item B<ENGINE_TABLE>
+
+The function that is used by RSA, DSA (etc) code to select registered
+ENGINEs, cache defaults and functional references (etc), will generate
+debugging summaries.
+
+=item B<ENGINE_REF_COUNT>
+
+Reference counts in the ENGINE structure will be monitored with a line
+of generated for each change.
+
+=item B<PKCS5V2>
+
+PKCS#5 v2 keygen.
+
+=item B<PKCS12_KEYGEN>
+
+PKCS#12 key generation.
+
+=item B<PKCS12_DECRYPT>
+
+PKCS#12 decryption.
+
+=item B<X509V3_POLICY>
+
+Generates the complete policy tree at various point during X.509 v3
+policy evaluation.
+
+=item B<BN_CTX>
+
+BIGNUM context.
+
+=back
+
+=back
+
 =head1 SEE ALSO
 
 L<asn1parse(1)>, L<ca(1)>, L<ciphers(1)>, L<cms(1)>, L<config(5)>,
diff --git a/doc/man3/OSSL_trace_enabled.pod b/doc/man3/OSSL_trace_enabled.pod
new file mode 100644
index 0000000..ecb88ab
--- /dev/null
+++ b/doc/man3/OSSL_trace_enabled.pod
@@ -0,0 +1,183 @@
+=pod
+
+=head1 NAME
+
+OSSL_trace_enabled, OSSL_trace_begin, OSSL_trace_end
+- OpenSSL Tracing API
+
+=head1 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);
+
+=head1 DESCRIPTION
+
+The functions described here are mainly interesting for those who provide
+OpenSSL functionality, either in OpenSSL itself or in engine modules
+or similar.
+
+If operational (see L</NOTES> below), these functions are used to
+generate free text tracing output.
+
+The tracing output is divided into types which are enabled
+individually by the application.
+The tracing types are described in detail in
+L<OSSL_trace_set_callback(3)/Trace types>.
+The fallback type C<OSSL_TRACE_CATEGORY_ANY> should I<not> be used
+with the functions described here.
+
+=head2 Functions
+
+OSSL_trace_enabled() can be used to check if tracing for the given
+C<category> is enabled.
+
+OSSL_trace_begin() is used to starts a tracing section, and get the
+channel for the given C<category> in form of a BIO.
+This BIO can only be used for output.
+
+OSSL_trace_end() is used to end a tracing section.
+
+Using OSSL_trace_begin() and OSSL_trace_end() to wrap tracing sections
+is I<mandatory>.
+The result of trying to produce tracing output outside of such
+sections is undefined.
+
+=head2 Convenience Macros
+
+There are a number of convenience macros defined, to make tracing
+easy and consistent.
+
+C<OSSL_TRACE_BEGIN(category)> and C<OSSL_TRACE_END(category)> reserve
+the B<BIO> C<trc_out> and are used as follows to wrap a trace section:
+
+ OSSL_TRACE_BEGIN(TLS) {
+
+     BIO_fprintf(trc_out, ... );
+
+ } OSSL_TRACE_END(TLS);
+
+This will normally expands to:
+
+ do {
+     BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
+     if (trc_out != NULL) {
+         ...
+         BIO_fprintf(trc_out, ...);
+     }
+     OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
+ } while (0);
+
+C<OSSL_TRACE_CANCEL(category)> must be used before returning from or
+jumping out of a trace section:
+
+ OSSL_TRACE_BEGIN(TLS) {
+
+     if (condition) {
+         OSSL_TRACE_CANCEL(TLS);
+         goto err;
+     }
+     BIO_fprintf(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 (condition) {
+             OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
+             goto err;
+         }
+         BIO_fprintf(trc_out, ... );
+     }
+     OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
+ } while (0);
+
+=head1 NOTES
+
+It is advisable to always check that a trace type is enabled with
+OSSL_trace_enabled() before generating any output, for example:
+
+    if (OSSL_trace_enabled(OSSL_TRACE_CATEGORY_TLS)) {
+        BIO *trace = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
+        BIO_printf(trace, "FOO %d\n", somevalue);
+        BIO_dump(trace, somememory, somememory_l);
+        OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trace);
+    }
+
+=head2 Tracing disabled
+
+The OpenSSL library may be built with tracing disabled, which makes
+everything documented here inoperational.
+
+When the library is built with tracing disabled:
+
+=over 4
+
+=item *
+
+The macro C<OPENSSL_NO_TRACE> is defined in C<openssl/opensslconf.h>.
+
+=item *
+
+all functions are still present, bu OSSL_trace_enabled() will always
+report the categories as disabled, and all other functions will do
+nothing.
+
+=item *
+
+the convenience macros are defined to produce dead code.
+For example, take this example from L</Convenience Macros> above:
+
+ OSSL_TRACE_BEGIN(TLS) {
+
+     if (condition) {
+         OSSL_TRACE_CANCEL(TLS);
+         goto err;
+     }
+     BIO_fprintf(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_fprintf(trc_out, ... );
+     }
+ } while (0);
+
+=back
+
+=head1 RETURN VALUES
+
+OSSL_trace_enabled() returns 1 if tracing for the given B<type> is
+operational and enabled, otherwise 0.
+
+OSSL_trace_begin() returns a C<BIO *> if the given B<type> is enabled,
+otherwise C<NULL>.
+
+=head1 HISTORY
+
+The OpenSSL Tracing API was added ino OpenSSL 3.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/OSSL_trace_get_category_num.pod b/doc/man3/OSSL_trace_get_category_num.pod
new file mode 100644
index 0000000..886d0f1
--- /dev/null
+++ b/doc/man3/OSSL_trace_get_category_num.pod
@@ -0,0 +1,44 @@
+=pod
+
+=head1 NAME
+
+OSSL_trace_get_category_num, OSSL_trace_get_category_name
+- OpenSSL tracing information functions
+
+=head1 SYNOPSIS
+
+ #include <openssl/trace.h>
+
+ int OSSL_trace_get_category_num(const char *name);
+ const char *OSSL_trace_get_category_name(int num);
+
+=head1 DESCRIPTION
+
+OSSL_trace_get_category_num() gives the category number corresponding
+to the given C<name>.
+
+OSSL_trace_get_category_name() gives the category name corresponding
+to the given C<num>.
+
+=head1 RETURN VALUES
+
+OSSL_trace_get_category_num() returns the category number if the given
+C<name> is a recognised category name, otherwise -1.
+
+OSSL_trace_get_category_name() returns the category name if the given
+C<num> is a recognised category number, otherwise NULL.
+
+=head1 HISTORY
+
+The OpenSSL Tracing API was added ino OpenSSL 3.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/doc/man3/OSSL_trace_set_channel.pod b/doc/man3/OSSL_trace_set_channel.pod
new file mode 100644
index 0000000..6981dbc
--- /dev/null
+++ b/doc/man3/OSSL_trace_set_channel.pod
@@ -0,0 +1,288 @@
+=pod
+
+=head1 NAME
+
+OSSL_trace_set_channel, OSSL_trace_set_prefix, OSSL_trace_set_suffix,
+OSSL_trace_set_callback, OSSL_trace_cb - Enabling trace output
+
+=head1 SYNOPSIS
+
+ #include <openssl/trace.h>
+
+ typedef size_t (*OSSL_trace_cb)(const char *buf, size_t cnt,
+                                 int category, int cmd, void *data);
+
+ void OSSL_trace_set_channel(int category, BIO *bio);
+ void OSSL_trace_set_prefix(int category, const char *prefix);
+ void OSSL_trace_set_suffix(int category, const char *suffix);
+ void OSSL_trace_set_callback(int category, OSSL_trace_cb cb, void  *data);
+
+=head1 DESCRIPTION
+
+If available (see L</NOTES> below), the application can request
+internal trace output.
+This output comes in form of free text for humans to read.
+
+The trace output is divided into categories which can be
+enabled individually.
+They are enabled by giving them a channel in form of a BIO, or a
+tracer callback, which is responsible for performing the actual
+output.
+
+=head2 Functions
+
+OSSL_trace_set_channel() is used to enable the given trace C<category>
+by giving it the B<BIO> C<bio>.
+
+OSSL_trace_set_prefix() and OSSL_trace_set_suffix() can be used to add
+an extra line for each channel, to be output before and after group of
+tracing output.
+What constitues an output group is decided by the code that produces
+the output.
+The lines given here are considered immutable; for more dynamic
+tracing prefixes, consider setting a callback with
+OSSL_trace_set_callback() instead.
+
+OSSL_trace_set_callback() is used to enable the given trace
+C<category> by giving it the tracer callback C<cb> with the associated
+data C<data>, which will simply be passed through to C<cb> whenever
+it's called.
+This should be used when it's desirable to do form the trace output to
+something suitable for application needs where a prefix and suffix
+line aren't enough.
+
+OSSL_trace_set_channel() and OSSL_trace_set_callback() are mutually
+exclusive, calling one of them will clear whatever was set by the
+previous call.
+
+Calling OSSL_trace_set_channel() with C<NULL> for C<channel> or
+OSSL_trace_set_callback() with C<NULL> for C<cb> disables tracing for
+the given C<category>
+
+=head2 Trace callback
+
+The tracer callback must return a C<size_t>, which must be zero on
+error and otherwise return the number of bytes that were output.
+It receives a text buffer C<buf> with C<cnt> bytes of text, as well as
+the C<category>, a control number C<cmd>, and the C<data> that was
+passed to OSSL_trace_set_callback().
+
+The possible control numbers are:
+
+=over 4
+
+=item C<OSSL_TRACE_CTRL_BEGIN>
+
+The callback is called from OSSL_trace_begin(), which gives the
+callback the possibility to output a dynamic starting line, or set a
+prefix that should be output at the beginning of each line, or
+something other.
+
+=item C<OSSL_TRACE_CTRL_DURING>
+
+The callback is called from any regular BIO output routine.
+
+=item C<OSSL_TRACE_CTRL_END>
+
+The callback is called from OSSL_trace_end(), which gives the callback
+the possibility to output a dynamic ending line, or reset the line
+prefix that was set with OSSL_TRACE_CTRL_BEGIN, or something other.
+
+=back
+
+=head2 Trace categories
+
+The trace categories are simple numbers available through macros.
+
+=over 4
+
+=item C<OSSL_TRACE_CATEGORY_TRACE>
+
+Traces the OpenSSL trace API itself.
+
+More precisely, this will generate trace output any time a new
+trace hook is set.
+
+=item C<OSSL_TRACE_CATEGORY_INIT>
+
+Traces OpenSSL library initialization and cleanup.
+
+This needs special care, as OpenSSL will do automatic cleanup after
+exit from C<main()>, and any tracing output done during this cleanup
+will be lost if the tracing channel or callback were cleaned away
+prematurely.
+A suggestion is to make such cleanup part of a function that's
+registered very early with L<atexit(3)>.
+
+=item C<OSSL_TRACE_CATEGORY_TLS>
+
+Traces the TLS/SSL protocoll.
+
+=item C<OSSL_TRACE_CATEGORY_TLS_CIPHER>
+
+Traces the ciphers used by the TLS/SSL protocoll.
+
+=item C<OSSL_TRACE_CATEGORY_ENGINE_CONF>
+
+Traces the ENGINE configuration.
+
+=item C<OSSL_TRACE_CATEGORY_ENGINE_TABLE>
+
+Traces the ENGINE algorithm table selection.
+
+More precisely, engine_table_select(), the function that is used by
+RSA, DSA (etc) code to select registered ENGINEs, cache defaults and
+functional references (etc), will generate trace summaries.
+
+=item C<OSSL_TRACE_CATEGORY_ENGINE_REF_COUNT>
+
+Tracds the ENGINE reference counting.
+
+More precisely, both reference counts in the ENGINE structure will be
+monitored with a line of trace output generated for each change.
+
+=item C<OSSL_TRACE_CATEGORY_PKCS5V2>
+
+Traces PKCS#5 v2 key generation.
+
+=item C<OSSL_TRACE_CATEGORY_PKCS12_KEYGEN>
+
+Traces PKCS#12 key generation.
+
+=item C<OSSL_TRACE_CATEGORY_PKCS12_DECRYPT>
+
+Traces PKCS#12 decryption.
+
+=item C<OSSL_TRACE_CATEGORY_X509V3_POLICY>
+
+Traces X509v3 policy processing.
+
+More precisely, this generates the complete policy tree at various
+point during evaluation.
+
+=item C<OSSL_TRACE_CATEGORY_BN_CTX>
+
+Traces BIGNUM context operations.
+
+=back
+
+There is also C<OSSL_TRACE_CATEGORY_ANY>, which works as a fallback
+and can be used to get I<all> trace output.
+
+=head1 RETURN VALUES
+
+OSSL_trace_set_channel(), OSSL_trace_set_prefix(),
+OSSL_trace_set_suffix(), and OSSL_trace_set_callback() return 1 on
+success, or 0 on failure.
+
+=head1 EXAMPLES
+
+In all examples below, we assume that the trace producing code is
+this:
+
+ int foo = 42;
+ const char bar[] = { 0,  1,  2,  3,  4,  5,  6,  7,
+                      8,  9, 10, 11, 12, 13, 14, 15 };
+
+ OSSL_TRACE_BEGIN(TLS) {
+     BIO_puts(trc_out, "foo: ");
+     BIO_printf(trc_out, "%d\n", foo);
+     BIO_dump(trc_out, bar, sizeof(bar));
+ } OSSL_TRACE_END(TLS);
+
+=head1 Simple example
+
+An example with just a channel and constant prefix / suffix.
+
+ int main(int argc, char *argv[])
+ {
+     BIO *err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+     OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_SSL, err);
+     OSSL_trace_set_prefix(OSSL_TRACE_CATEGORY_SSL, "BEGIN TRACE[TLS]");
+     OSSL_trace_set_suffix(OSSL_TRACE_CATEGORY_SSL, "END TRACE[TLS]");
+
+     /* ... work ... */
+ }
+
+When the trace producing code above is performed, this will be output
+on standard error:
+
+ BEGIN TRACE[TLS]
+ foo: 42
+ 0000 - 00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f   ................
+ END TRACE[TLS]
+
+=head2 Advanced example
+
+This example uses the callback, and depends on pthreads functionality.
+
+ static size_t cb(const char *buf, size_t cnt,
+                 int category, int cmd, void *vdata)
+ {
+     BIO *bio = vdata;
+     const char *label = NULL;
+
+     switch (cmd) {
+     case OSSL_TRACE_CTRL_BEGIN:
+         label = "BEGIN";
+         break;
+     case OSSL_TRACE_CTRL_END:
+         label = "END";
+         break;
+     }
+
+     if (label != NULL) {
+         union {
+             pthread_t tid;
+             unsigned long ltid;
+         } tid;
+
+         tid.tid = pthread_self();
+         BIO_printf(bio, "%s TRACE[%s]:%lx\n",
+                    label, OSSL_trace_get_category_name(category), tid.ltid);
+     }
+     return (size_t)BIO_puts(bio, buf);
+ }
+
+ int main(int argc, char *argv[])
+ {
+     BIO *err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+     OSSL_trace_set_callback(OSSL_TRACE_CATEGORY_SSL, cb, err);
+
+     /* ... work ... */
+ }
+
+The output is almost the same as for the simple example above.
+
+ BEGIN TRACE[TLS]:7f9eb0193b80
+ foo: 42
+ 0000 - 00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f   ................
+ END TRACE[TLS]:7f9eb0193b80
+
+=head1 NOTES
+
+=head2 Tracing disabled
+
+The OpenSSL library may be built with tracing disabled, which makes
+everything documented here inoperational.
+
+When the library is built with tracing disabled, the macro
+C<OPENSSL_NO_TRACE> is defined in C<openssl/opensslconf.h> and all
+functions described here are inoperational, i.e. will do nothing.
+
+=head1 HISTORY
+
+OSSL_trace_set_channel(), OSSL_trace_set_prefix(),
+OSSL_trace_set_suffix(), and OSSL_trace_set_callback() were all added
+in OpenSSL 3.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 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
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/openssl/trace.h b/include/openssl/trace.h
new file mode 100644
index 0000000..da0ba0b
--- /dev/null
+++ b/include/openssl/trace.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2019 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
+ */
+
+#ifndef OSSL_TRACE_H
+# define OSSL_TRACE_H
+
+# include <stdarg.h>
+
+# include <openssl/bio.h>
+
+# ifdef  __cplusplus
+extern "C" {
+# endif
+
+/*
+ * TRACE CATEGORIES
+ */
+
+/*
+ * The trace messages of the OpenSSL libraries are organized into different
+ * categories. For every trace category, the application can register a separate
+ * tracer callback. When a callback is registered, a so called trace channel is
+ * created for this category. This channel consists essentially of an internal
+ * BIO which sends all trace output it receives to the registered application
+ * callback.
+ *
+ * The ANY category is used as a fallback category.
+ */
+# define OSSL_TRACE_CATEGORY_ANY                 0 /* The fallback */
+# define OSSL_TRACE_CATEGORY_TRACE               1
+# define OSSL_TRACE_CATEGORY_INIT                2
+# define OSSL_TRACE_CATEGORY_TLS                 3
+# define OSSL_TRACE_CATEGORY_TLS_CIPHER          4
+# define OSSL_TRACE_CATEGORY_ENGINE_CONF         5
+# define OSSL_TRACE_CATEGORY_ENGINE_TABLE        6
+# define OSSL_TRACE_CATEGORY_ENGINE_REF_COUNT    7
+# define OSSL_TRACE_CATEGORY_PKCS5V2             8
+# define OSSL_TRACE_CATEGORY_PKCS12_KEYGEN       9
+# define OSSL_TRACE_CATEGORY_PKCS12_DECRYPT     10
+# define OSSL_TRACE_CATEGORY_X509V3_POLICY      11
+# define OSSL_TRACE_CATEGORY_BN_CTX             12
+# define OSSL_TRACE_CATEGORY_NUM                13
+
+/* Returns the trace category number for the given |name| */
+int OSSL_trace_get_category_num(const char *name);
+
+/* Returns the trace category name for the given |num| */
+const char *OSSL_trace_get_category_name(int num);
+
+/*
+ * TRACE CONSUMERS
+ */
+
+/*
+ * Enables tracing for the given |category| by providing a BIO sink
+ * as |channel|. If a null pointer is passed as |channel|, an existing
+ * trace channel is removed and tracing for the category is disabled.
+ *
+ * Returns 1 on success and 0 on failure
+ */
+int OSSL_trace_set_channel(int category, BIO* channel);
+
+/*
+ * Attach a prefix and a suffix to the given |category|, to be printed at the
+ * beginning and at the end of each trace output group, i.e. when
+ * OSSL_trace_begin() and OSSL_trace_end() are called.
+ * If a null pointer is passed as argument, the existing prefix or suffix is
+ * removed.
+ *
+ * They return 1 on success and 0 on failure
+ */
+int OSSL_trace_set_prefix(int category, const char *prefix);
+int OSSL_trace_set_suffix(int category, const char *suffix);
+
+/*
+ * OSSL_trace_cb is the type tracing callback provided by the application.
+ * It MUST return the number of bytes written, or 0 on error (in other words,
+ * it can never write zero bytes).
+ *
+ * The |buffer| will always contain text, which may consist of several lines.
+ * The |data| argument points to whatever data was provided by the application
+ * when registering the tracer function.
+ *
+ * The |category| number is given, as well as a |cmd| number, described below.
+ */
+typedef size_t (*OSSL_trace_cb)(const char *buffer, size_t count,
+                                int category, int cmd, void *data);
+/*
+ * Possible |cmd| numbers.
+ */
+# define OSSL_TRACE_CTRL_BEGIN  0
+# define OSSL_TRACE_CTRL_DURING 1
+# define OSSL_TRACE_CTRL_END    2
+
+/*
+ * Enables tracing for the given |category| by creating an internal
+ * trace channel which sends the output to the given |callback|.
+ * If a null pointer is passed as callback, an existing trace channel
+ * is removed and tracing for the category is disabled.
+ *
+ * NOTE: OSSL_trace_set_channel() and OSSL_trace_set_callback() are mutually
+ *       exclusive.
+ *
+ * Returns 1 on success and 0 on failure
+ */
+int OSSL_trace_set_callback(int category, OSSL_trace_cb callback, void *data);
+
+/*
+ * TRACE PRODUCERS
+ */
+
+/*
+ * Returns 1 if tracing for the specified category is enabled, otherwise 0
+ */
+int OSSL_trace_enabled(int category);
+
+/*
+ * Wrap a group of tracing output calls.  OSSL_trace_begin() locks tracing and
+ * returns the trace channel associated with the given category, or NULL if no
+ * channel is associated with the category.  OSSL_trace_end() unlocks tracing.
+ *
+ * Usage:
+ *
+ *    BIO *out;
+ *    if ((out = OSSL_trace_begin(category)) != NULL) {
+ *        ...
+ *        BIO_fprintf(out, ...);
+ *        ...
+ *        OSSL_trace_end(category, out);
+ *    }
+ *
+ * See also the convenience macros OSSL_TRACE_BEGIN and OSSL_TRACE_END below.
+ */
+BIO *OSSL_trace_begin(int category);
+void OSSL_trace_end(int category, BIO *channel);
+
+/*
+ * OSSL_TRACE* Convenience Macros
+ */
+
+/*
+ * When the tracing feature is disabled, these macros are defined to
+ * produce dead code, which a good compiler should eliminate.
+ */
+
+/*
+ * OSSL_TRACE_BEGIN, OSSL_TRACE_END - Define a Trace Group
+ *
+ * These two macros can be used to create a block which is executed only
+ * if the corresponding trace category is enabled. Inside this block, a
+ * local variable named |trc_out| is defined, which points to the channel
+ * associated with the given trace category.
+ *
+ * Usage: (using 'TLS' as an example category)
+ *
+ *     OSSL_TRACE_BEGIN(TLS) {
+ *
+ *         BIO_fprintf(trc_out, ... );
+ *
+ *     } OSSL_TRACE_END(TLS);
+ *
+ *
+ * This expands to the following code
+ *
+ *     do {
+ *         BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_TLS);
+ *         if (trc_out != NULL) {
+ *             ...
+ *             BIO_fprintf(trc_out, ...);
+ *         }
+ *         OSSL_trace_end(OSSL_TRACE_CATEGORY_TLS, trc_out);
+ *     } while (0);
+ *
+ * The use of the inner '{...}' group and the trailing ';' is enforced
+ * by the definition of the macros in order to make the code look as much
+ * like C code as possible.
+ *
+ * Before returning from inside the trace block, it is necessary to
+ * call OSSL_TRACE_CANCEL(category).
+ */
+
+# ifndef OPENSSL_NO_TRACE
+
+#  define OSSL_TRACE_BEGIN(category) \
+    do { \
+        BIO *trc_out = OSSL_trace_begin(OSSL_TRACE_CATEGORY_##category); \
+ \
+        if (trc_out != NULL)
+
+#  define OSSL_TRACE_END(category) \
+        OSSL_trace_end(OSSL_TRACE_CATEGORY_##category, trc_out); \
+    } while (0)
+
+#  define OSSL_TRACE_CANCEL(category) \
+        OSSL_trace_end(OSSL_TRACE_CATEGORY_##category, trc_out) \
+
+# else
+
+#  define OSSL_TRACE_BEGIN(category)           \
+    do {                                        \
+        BIO *trc_out = NULL;                    \
+        if (0)
+
+#  define OSSL_TRACE_END(category)             \
+    } while(0)
+
+#  define OSSL_TRACE_CANCEL(category)          \
+    ((void)0)
+
+# endif
+
+/*
+ * OSSL_TRACE_ENABLED() - Check whether tracing is enabled for |category|
+ *
+ * Usage:
+ *
+ *     if (OSSL_TRACE_ENABLED(TLS)) {
+ *         ...
+ *     }
+ */
+# ifndef OPENSSL_NO_TRACE
+
+#  define OSSL_TRACE_ENABLED(category) \
+    OSSL_trace_enabled(OSSL_TRACE_CATEGORY_##category)
+
+# else
+
+#  define OSSL_TRACE_ENABLED(category) (0)
+
+# endif
+
+/*
+ * OSSL_TRACE*() - OneShot Trace Macros
+ *
+ * These macros are intended to produce a simple printf-style trace output.
+ * Unfortunately, C90 macros don't support variable arguments, so the
+ * "vararg" OSSL_TRACEV() macro has a rather weird usage pattern:
+ *
+ *    OSSL_TRACEV(category, (trc_out, "format string", ...args...));
+ *
+ * Where 'channel' is the literal symbol of this name, not a variable.
+ * For that reason, it is currently not intended to be used directly,
+ * but only as helper macro for the other oneshot trace macros
+ * OSSL_TRACE(), OSSL_TRACE1(), OSSL_TRACE2(), ...
+ *
+ * Usage:
+ *
+ *    OSSL_TRACE(INIT, "Hello world!\n");
+ *    OSSL_TRACE1(TLS, "The answer is %d\n", 42);
+ *    OSSL_TRACE2(TLS, "The ultimate question to answer %d is '%s'\n",
+ *                42, "What do you get when you multiply six by nine?");
+ */
+
+# define OSSL_TRACEV(category, args) \
+    OSSL_TRACE_BEGIN(category) \
+        BIO_printf args; \
+    OSSL_TRACE_END(category)
+
+# define OSSL_TRACE(category, text) \
+    OSSL_TRACEV(category, (trc_out, "%s", text))
+
+# define OSSL_TRACE1(category, format, arg1) \
+    OSSL_TRACEV(category, (trc_out, format, arg1))
+# define OSSL_TRACE2(category, format, arg1, arg2) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2))
+# define OSSL_TRACE3(category, format, arg1, arg2, arg3) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3))
+# define OSSL_TRACE4(category, format, arg1, arg2, arg3, arg4) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4))
+# define OSSL_TRACE5(category, format, arg1, arg2, arg3, arg4, arg5) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4, arg5))
+# define OSSL_TRACE6(category, format, arg1, arg2, arg3, arg4, arg5, arg6) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4, arg5, arg6))
+# define OSSL_TRACE7(category, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7))
+# define OSSL_TRACE8(category, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8))
+# define OSSL_TRACE9(category, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
+    OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
+
+# ifdef  __cplusplus
+}
+# endif
+
+#endif
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 3f5f796..e1231d2 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -9,6 +9,7 @@
 
 #include "../ssl_locl.h"
 #include "internal/constant_time_locl.h"
+#include <openssl/trace.h>
 #include <openssl/rand.h>
 #include "record_locl.h"
 #include "internal/cryptlib.h"
@@ -563,15 +564,10 @@ int ssl3_get_record(SSL *s)
                  SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
         return -1;
     }
-#ifdef SSL_DEBUG
-    printf("dec %lu\n", (unsigned long)rr[0].length);
-    {
-        size_t z;
-        for (z = 0; z < rr[0].length; z++)
-            printf("%02X%c", rr[0].data[z], ((z + 1) % 16) ? ' ' : '\n');
-    }
-    printf("\n");
-#endif
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "dec %lu\n", (unsigned long)rr[0].length);
+        BIO_dump_indent(trc_out, rr[0].data, rr[0].length, 4);
+    } OSSL_TRACE_END(TLS);
 
     /* r->length is now the compressed data plus mac */
     if ((sess != NULL) &&
@@ -1361,22 +1357,12 @@ int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int sending)
 
     EVP_MD_CTX_free(hmac);
 
-#ifdef SSL_DEBUG
-    fprintf(stderr, "seq=");
-    {
-        int z;
-        for (z = 0; z < 8; z++)
-            fprintf(stderr, "%02X ", seq[z]);
-        fprintf(stderr, "\n");
-    }
-    fprintf(stderr, "rec=");
-    {
-        size_t z;
-        for (z = 0; z < rec->length; z++)
-            fprintf(stderr, "%02X ", rec->data[z]);
-        fprintf(stderr, "\n");
-    }
-#endif
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "seq:\n");
+        BIO_dump_indent(trc_out, seq, 8, 4);
+        BIO_printf(trc_out, "rec:\n");
+        BIO_dump_indent(trc_out, rec->data, rec->length, 4);
+    } OSSL_TRACE_END(TLS);
 
     if (!SSL_IS_DTLS(ssl)) {
         for (i = 7; i >= 0; i--) {
@@ -1385,14 +1371,10 @@ int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int sending)
                 break;
         }
     }
-#ifdef SSL_DEBUG
-    {
-        unsigned int z;
-        for (z = 0; z < md_size; z++)
-            fprintf(stderr, "%02X ", md[z]);
-        fprintf(stderr, "\n");
-    }
-#endif
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "md:\n");
+        BIO_dump_indent(trc_out, md, md_size, 4);
+    } OSSL_TRACE_END(TLS);
     return 1;
 }
 
@@ -1683,15 +1665,10 @@ int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap)
         RECORD_LAYER_reset_packet_length(&s->rlayer);
         return 0;
     }
-#ifdef SSL_DEBUG
-    printf("dec %ld\n", rr->length);
-    {
-        size_t z;
-        for (z = 0; z < rr->length; z++)
-            printf("%02X%c", rr->data[z], ((z + 1) % 16) ? ' ' : '\n');
-    }
-    printf("\n");
-#endif
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "dec %ld\n", rr->length);
+        BIO_dump_indent(trc_out, rr->data, rr->length, 4);
+    } OSSL_TRACE_END(TLS);
 
     /* r->length is now the compressed data plus mac */
     if ((sess != NULL) && !SSL_READ_ETM(s) &&
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index a5b3dbb..a3639fd 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -16,6 +16,7 @@
 #include <openssl/md5.h>
 #include <openssl/dh.h>
 #include <openssl/rand.h>
+#include <openssl/trace.h>
 #include "internal/cryptlib.h"
 
 #define TLS13_NUM_CIPHERS       OSSL_NELEM(tls13_ciphers)
@@ -4153,20 +4154,20 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
      * pay with the price of sk_SSL_CIPHER_dup().
      */
 
-#ifdef CIPHER_DEBUG
-    fprintf(stderr, "Server has %d from %p:\n", sk_SSL_CIPHER_num(srvr),
-            (void *)srvr);
-    for (i = 0; i < sk_SSL_CIPHER_num(srvr); ++i) {
-        c = sk_SSL_CIPHER_value(srvr, i);
-        fprintf(stderr, "%p:%s\n", (void *)c, c->name);
-    }
-    fprintf(stderr, "Client sent %d from %p:\n", sk_SSL_CIPHER_num(clnt),
-            (void *)clnt);
-    for (i = 0; i < sk_SSL_CIPHER_num(clnt); ++i) {
-        c = sk_SSL_CIPHER_value(clnt, i);
-        fprintf(stderr, "%p:%s\n", (void *)c, c->name);
-    }
-#endif
+    OSSL_TRACE_BEGIN(TLS_CIPHER) {
+        BIO_printf(trc_out, "Server has %d from %p:\n",
+                   sk_SSL_CIPHER_num(srvr), (void *)srvr);
+        for (i = 0; i < sk_SSL_CIPHER_num(srvr); ++i) {
+            c = sk_SSL_CIPHER_value(srvr, i);
+            BIO_printf(trc_out, "%p:%s\n", (void *)c, c->name);
+        }
+        BIO_printf(trc_out, "Client sent %d from %p:\n",
+                   sk_SSL_CIPHER_num(clnt), (void *)clnt);
+        for (i = 0; i < sk_SSL_CIPHER_num(clnt); ++i) {
+            c = sk_SSL_CIPHER_value(clnt, i);
+            BIO_printf(trc_out, "%p:%s\n", (void *)c, c->name);
+        }
+    } OSSL_TRACE_END(TLS_CIPHER);
 
     /* SUITE-B takes precedence over server preference and ChaCha priortiy */
     if (tls1_suiteb(s)) {
@@ -4280,10 +4281,9 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
 #endif                          /* OPENSSL_NO_PSK */
 
             ok = (alg_k & mask_k) && (alg_a & mask_a);
-#ifdef CIPHER_DEBUG
-            fprintf(stderr, "%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n", ok, alg_k,
-                    alg_a, mask_k, mask_a, (void *)c, c->name);
-#endif
+            OSSL_TRACE7(TLS_CIPHER,
+                        "%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n",
+                        ok, alg_k, alg_a, mask_k, mask_a, (void *)c, c->name);
 
 #ifndef OPENSSL_NO_EC
             /*
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index 461a9de..5aa04db 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -16,6 +16,7 @@
 #include <openssl/engine.h>
 #include <openssl/crypto.h>
 #include <openssl/conf.h>
+#include <openssl/trace.h>
 #include "internal/nelem.h"
 #include "ssl_locl.h"
 #include "internal/thread_once.h"
@@ -781,12 +782,12 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey,
     const SSL_CIPHER *cp;
     int reverse = 0;
 
-#ifdef CIPHER_DEBUG
-    fprintf(stderr,
-            "Applying rule %d with %08x/%08x/%08x/%08x/%08x %08x (%d)\n",
-            rule, alg_mkey, alg_auth, alg_enc, alg_mac, min_tls,
-            algo_strength, strength_bits);
-#endif
+    OSSL_TRACE_BEGIN(TLS_CIPHER){
+        BIO_printf(trc_out,
+                   "Applying rule %d with %08x/%08x/%08x/%08x/%08x %08x (%d)\n",
+                   rule, alg_mkey, alg_auth, alg_enc, alg_mac, min_tls,
+                   algo_strength, strength_bits);
+    }
 
     if (rule == CIPHER_DEL || rule == CIPHER_BUMP)
         reverse = 1;            /* needed to maintain sorting between currently
@@ -825,13 +826,14 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey,
             if (strength_bits != cp->strength_bits)
                 continue;
         } else {
-#ifdef CIPHER_DEBUG
-            fprintf(stderr,
-                    "\nName: %s:\nAlgo = %08x/%08x/%08x/%08x/%08x Algo_strength = %08x\n",
-                    cp->name, cp->algorithm_mkey, cp->algorithm_auth,
-                    cp->algorithm_enc, cp->algorithm_mac, cp->min_tls,
-                    cp->algo_strength);
-#endif
+            if (trc_out != NULL) {
+                BIO_printf(trc_out,
+                           "\nName: %s:"
+                           "\nAlgo = %08x/%08x/%08x/%08x/%08x Algo_strength = %08x\n",
+                           cp->name, cp->algorithm_mkey, cp->algorithm_auth,
+                           cp->algorithm_enc, cp->algorithm_mac, cp->min_tls,
+                           cp->algo_strength);
+            }
             if (cipher_id != 0 && (cipher_id != cp->id))
                 continue;
             if (alg_mkey && !(alg_mkey & cp->algorithm_mkey))
@@ -852,9 +854,8 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey,
                 continue;
         }
 
-#ifdef CIPHER_DEBUG
-        fprintf(stderr, "Action = %d\n", rule);
-#endif
+        if (trc_out != NULL)
+            BIO_printf(trc_out, "Action = %d\n", rule);
 
         /* add the cipher if it has not been added yet. */
         if (rule == CIPHER_ADD) {
@@ -904,6 +905,8 @@ static void ssl_cipher_apply_rule(uint32_t cipher_id, uint32_t alg_mkey,
 
     *head_p = head;
     *tail_p = tail;
+
+    OSSL_TRACE_END(TLS_CIPHER);
 }
 
 static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
@@ -1605,6 +1608,9 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
         }
     }
 
+    OSSL_TRACE_BEGIN(TLS_CIPHER) {
+        BIO_printf(trc_out, "cipher selection:\n");
+    }
     /*
      * The cipher selection for the list is done. The ciphers are added
      * to the resulting precedence to the STACK_OF(SSL_CIPHER).
@@ -1614,14 +1620,15 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
             if (!sk_SSL_CIPHER_push(cipherstack, curr->cipher)) {
                 OPENSSL_free(co_list);
                 sk_SSL_CIPHER_free(cipherstack);
+                OSSL_TRACE_CANCEL(TLS_CIPHER);
                 return NULL;
             }
-#ifdef CIPHER_DEBUG
-            fprintf(stderr, "<%s>\n", curr->cipher->name);
-#endif
+            if (trc_out != NULL)
+                BIO_printf(trc_out, "<%s>\n", curr->cipher->name);
         }
     }
     OPENSSL_free(co_list);      /* Not needed any longer */
+    OSSL_TRACE_END(TLS_CIPHER);
 
     if (!update_cipher_list_by_id(cipher_list_by_id, cipherstack)) {
         sk_SSL_CIPHER_free(cipherstack);
diff --git a/ssl/ssl_init.c b/ssl/ssl_init.c
index e766ee1..0451d19 100644
--- a/ssl/ssl_init.c
+++ b/ssl/ssl_init.c
@@ -12,6 +12,7 @@
 #include "internal/err.h"
 #include <openssl/crypto.h>
 #include <openssl/evp.h>
+#include <openssl/trace.h>
 #include "ssl_locl.h"
 #include "internal/thread_once.h"
 
@@ -23,10 +24,7 @@ static CRYPTO_ONCE ssl_base = CRYPTO_ONCE_STATIC_INIT;
 static int ssl_base_inited = 0;
 DEFINE_RUN_ONCE_STATIC(ossl_init_ssl_base)
 {
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_ssl_base: "
-            "Adding SSL ciphers and digests\n");
-#endif
+    OSSL_TRACE(INIT, "ossl_init_ssl_base: adding SSL ciphers and digests\n");
 #ifndef OPENSSL_NO_DES
     EVP_add_cipher(EVP_des_cbc());
     EVP_add_cipher(EVP_des_ede3_cbc());
@@ -88,10 +86,8 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_ssl_base)
     EVP_add_digest(EVP_sha384());
     EVP_add_digest(EVP_sha512());
 #ifndef OPENSSL_NO_COMP
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_ssl_base: "
-            "SSL_COMP_get_compression_methods()\n");
-# endif
+    OSSL_TRACE(INIT, "ossl_init_ssl_base: "
+               "SSL_COMP_get_compression_methods()\n");
     /*
      * This will initialise the built-in compression algorithms. The value
      * returned is a STACK_OF(SSL_COMP), but that can be discarded safely
@@ -102,10 +98,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_ssl_base)
     if (!ssl_load_ciphers())
         return 0;
 
-#ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_ssl_base: "
-            "SSL_add_ssl_module()\n");
-#endif
+    OSSL_TRACE(INIT,"ossl_init_ssl_base: SSL_add_ssl_module()\n");
     /*
      * We ignore an error return here. Not much we can do - but not that bad
      * either. We can still safely continue.
@@ -124,10 +117,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_ssl_strings)
      * pulling in all the error strings during static linking
      */
 #if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
-# ifdef OPENSSL_INIT_DEBUG
-    fprintf(stderr, "OPENSSL_INIT: ossl_init_load_ssl_strings: "
-            "ERR_load_SSL_strings()\n");
-# endif
+    OSSL_TRACE(INIT, "ossl_init_load_ssl_strings: ERR_load_SSL_strings()\n");
     ERR_load_SSL_strings();
     ssl_strings_inited = 1;
 #endif
@@ -150,19 +140,14 @@ static void ssl_library_stop(void)
 
     if (ssl_base_inited) {
 #ifndef OPENSSL_NO_COMP
-# ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ssl_library_stop: "
-                "ssl_comp_free_compression_methods_int()\n");
-# endif
+        OSSL_TRACE(INIT, "ssl_library_stop: "
+                   "ssl_comp_free_compression_methods_int()\n");
         ssl_comp_free_compression_methods_int();
 #endif
     }
 
     if (ssl_strings_inited) {
-#ifdef OPENSSL_INIT_DEBUG
-        fprintf(stderr, "OPENSSL_INIT: ssl_library_stop: "
-                "err_free_strings_int()\n");
-#endif
+        OSSL_TRACE(INIT, "ssl_library_stop: err_free_strings_int()\n");
         /*
          * If both crypto and ssl error strings are inited we will end up
          * calling err_free_strings_int() twice - but that's ok. The second
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 322a438..f63e16b 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -20,6 +20,7 @@
 #include <openssl/engine.h>
 #include <openssl/async.h>
 #include <openssl/ct.h>
+#include <openssl/trace.h>
 #include "internal/cryptlib.h"
 #include "internal/refcount.h"
 #include "internal/ktls.h"
@@ -3329,10 +3330,8 @@ void ssl_set_masks(SSL *s)
     mask_k = 0;
     mask_a = 0;
 
-#ifdef CIPHER_DEBUG
-    fprintf(stderr, "dht=%d re=%d rs=%d ds=%d\n",
-            dh_tmp, rsa_enc, rsa_sign, dsa_sign);
-#endif
+    OSSL_TRACE4(TLS_CIPHER, "dh_tmp=%d rsa_enc=%d rsa_sign=%d dsa_sign=%d\n",
+               dh_tmp, rsa_enc, rsa_sign, dsa_sign);
 
 #ifndef OPENSSL_NO_GOST
     if (ssl_has_cert(s, SSL_PKEY_GOST12_512)) {
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 2a9b737..356dc89 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -22,6 +22,7 @@
 #include <openssl/dh.h>
 #include <openssl/bn.h>
 #include <openssl/engine.h>
+#include <openssl/trace.h>
 #include <internal/cryptlib.h>
 
 static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s, PACKET *pkt);
@@ -2347,11 +2348,9 @@ MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
                      ERR_R_INTERNAL_ERROR);
             goto err;
         }
-#ifdef SSL_DEBUG
         if (SSL_USE_SIGALGS(s))
-            fprintf(stderr, "USING TLSv1.2 HASH %s\n",
-                    md == NULL ? "n/a" : EVP_MD_name(md));
-#endif
+            OSSL_TRACE1(TLS, "USING TLSv1.2 HASH %s\n",
+                        md == NULL ? "n/a" : EVP_MD_name(md));
 
         if (!PACKET_get_length_prefixed_2(pkt, &signature)
             || PACKET_remaining(pkt) != 0) {
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index a18c5cc..10cf635 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -18,6 +18,7 @@
 #include <openssl/objects.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
+#include <openssl/trace.h>
 
 /*
  * Map error codes to TLS/SSL alart types.
@@ -394,11 +395,9 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
         goto err;
     }
 
-#ifdef SSL_DEBUG
     if (SSL_USE_SIGALGS(s))
-        fprintf(stderr, "USING TLSv1.2 HASH %s\n",
-                md == NULL ? "n/a" : EVP_MD_name(md));
-#endif
+        OSSL_TRACE1(TLS, "USING TLSv1.2 HASH %s\n",
+                    md == NULL ? "n/a" : EVP_MD_name(md));
 
     /* Check for broken implementations of GOST ciphersuites */
     /*
@@ -439,10 +438,9 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
         goto err;
     }
 
-#ifdef SSL_DEBUG
-    fprintf(stderr, "Using client verify alg %s\n",
-            md == NULL ? "n/a" : EVP_MD_name(md));
-#endif
+    OSSL_TRACE1(TLS, "Using client verify alg %s\n",
+                md == NULL ? "n/a" : EVP_MD_name(md));
+
     if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, pkey) <= 0) {
         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CERT_VERIFY,
                  ERR_R_EVP_LIB);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index bf1819d..e482e2d 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -23,6 +23,7 @@
 #include <openssl/dh.h>
 #include <openssl/bn.h>
 #include <openssl/md5.h>
+#include <openssl/trace.h>
 
 #define TICKET_NONCE_SIZE       8
 
@@ -1835,15 +1836,15 @@ static int tls_early_post_process_client_hello(SSL *s)
         j = 0;
         id = s->session->cipher->id;
 
-#ifdef CIPHER_DEBUG
-        fprintf(stderr, "client sent %d ciphers\n", sk_SSL_CIPHER_num(ciphers));
-#endif
+        OSSL_TRACE_BEGIN(TLS_CIPHER) {
+            BIO_printf(trc_out, "client sent %d ciphers\n",
+                       sk_SSL_CIPHER_num(ciphers));
+        }
         for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
             c = sk_SSL_CIPHER_value(ciphers, i);
-#ifdef CIPHER_DEBUG
-            fprintf(stderr, "client [%2d of %2d]:%s\n",
-                    i, sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
-#endif
+            if (trc_out != NULL)
+                BIO_printf(trc_out, "client [%2d of %2d]:%s\n", i,
+                           sk_SSL_CIPHER_num(ciphers), SSL_CIPHER_get_name(c));
             if (c->id == id) {
                 j = 1;
                 break;
@@ -1857,8 +1858,10 @@ static int tls_early_post_process_client_hello(SSL *s)
             SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
                      SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO,
                      SSL_R_REQUIRED_CIPHER_MISSING);
+            OSSL_TRACE_CANCEL(TLS_CIPHER);
             goto err;
         }
+        OSSL_TRACE_END(TLS_CIPHER);
     }
 
     for (loop = 0; loop < clienthello->compressions_len; loop++) {
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 9b58bd8..fe4ba93 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -18,6 +18,7 @@
 #include <openssl/kdf.h>
 #include <openssl/rand.h>
 #include <openssl/obj_mac.h>
+#include <openssl/trace.h>
 
 /* seed1 through seed5 are concatenated */
 static int tls1_PRF(SSL *s,
@@ -276,14 +277,11 @@ int tls1_change_cipher_state(SSL *s, int which)
         }
         EVP_PKEY_free(mac_key);
     }
-#ifdef SSL_DEBUG
-    printf("which = %04X\nmac key=", which);
-    {
-        size_t z;
-        for (z = 0; z < i; z++)
-            printf("%02X%c", ms[z], ((z + 1) % 16) ? ' ' : '\n');
-    }
-#endif
+
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "which = %04X, mac key:\n", which);
+        BIO_dump_indent(trc_out, ms, i, 4);
+    } OSSL_TRACE_END(TLS);
 
     if (EVP_CIPHER_mode(c) == EVP_CIPH_GCM_MODE) {
         if (!EVP_CipherInit_ex(dd, c, NULL, key, NULL, (which & SSL3_CC_WRITE))
@@ -388,21 +386,12 @@ int tls1_change_cipher_state(SSL *s, int which)
 #endif                          /* OPENSSL_NO_KTLS */
     s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
 
-#ifdef SSL_DEBUG
-    printf("which = %04X\nkey=", which);
-    {
-        int z;
-        for (z = 0; z < EVP_CIPHER_key_length(c); z++)
-            printf("%02X%c", key[z], ((z + 1) % 16) ? ' ' : '\n');
-    }
-    printf("\niv=");
-    {
-        size_t z;
-        for (z = 0; z < k; z++)
-            printf("%02X%c", iv[z], ((z + 1) % 16) ? ' ' : '\n');
-    }
-    printf("\n");
-#endif
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "which = %04X, key:\n", which);
+        BIO_dump_indent(trc_out, key, EVP_CIPHER_key_length(c), 4);
+        BIO_printf(trc_out, "iv:\n");
+        BIO_dump_indent(trc_out, iv, k, 4);
+    } OSSL_TRACE_END(TLS);
 
     return 1;
  err:
@@ -447,41 +436,26 @@ int tls1_setup_key_block(SSL *s)
     s->s3->tmp.key_block_length = num;
     s->s3->tmp.key_block = p;
 
-#ifdef SSL_DEBUG
-    printf("client random\n");
-    {
-        int z;
-        for (z = 0; z < SSL3_RANDOM_SIZE; z++)
-            printf("%02X%c", s->s3->client_random[z],
-                   ((z + 1) % 16) ? ' ' : '\n');
-    }
-    printf("server random\n");
-    {
-        int z;
-        for (z = 0; z < SSL3_RANDOM_SIZE; z++)
-            printf("%02X%c", s->s3->server_random[z],
-                   ((z + 1) % 16) ? ' ' : '\n');
-    }
-    printf("master key\n");
-    {
-        size_t z;
-        for (z = 0; z < s->session->master_key_length; z++)
-            printf("%02X%c", s->session->master_key[z],
-                   ((z + 1) % 16) ? ' ' : '\n');
-    }
-#endif
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "client random\n");
+        BIO_dump_indent(trc_out, s->s3->client_random, SSL3_RANDOM_SIZE, 4);
+        BIO_printf(trc_out, "server random\n");
+        BIO_dump_indent(trc_out, s->s3->server_random, SSL3_RANDOM_SIZE, 4);
+        BIO_printf(trc_out, "master key\n");
+        BIO_dump_indent(trc_out,
+                        s->session->master_key,
+                        s->session->master_key_length, 4);
+    } OSSL_TRACE_END(TLS);
+
     if (!tls1_generate_key_block(s, p, num)) {
         /* SSLfatal() already called */
         goto err;
     }
-#ifdef SSL_DEBUG
-    printf("\nkey block\n");
-    {
-        size_t z;
-        for (z = 0; z < num; z++)
-            printf("%02X%c", p[z], ((z + 1) % 16) ? ' ' : '\n');
-    }
-#endif
+
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "key block\n");
+        BIO_dump_indent(trc_out, p, num, 4);
+    } OSSL_TRACE_END(TLS);
 
     if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)
         && s->method->version <= TLS1_VERSION) {
@@ -549,10 +523,10 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
             /* SSLfatal() already called */
             return 0;
         }
-#ifdef SSL_DEBUG
-        fprintf(stderr, "Handshake hashes:\n");
-        BIO_dump_fp(stderr, (char *)hash, hashlen);
-#endif
+        OSSL_TRACE_BEGIN(TLS) {
+            BIO_printf(trc_out, "Handshake hashes:\n");
+            BIO_dump(trc_out, (char *)hash, hashlen);
+        } OSSL_TRACE_END(TLS);
         if (!tls1_PRF(s,
                       TLS_MD_EXTENDED_MASTER_SECRET_CONST,
                       TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
@@ -578,17 +552,19 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
             return 0;
         }
     }
-#ifdef SSL_DEBUG
-    fprintf(stderr, "Premaster Secret:\n");
-    BIO_dump_fp(stderr, (char *)p, len);
-    fprintf(stderr, "Client Random:\n");
-    BIO_dump_fp(stderr, (char *)s->s3->client_random, SSL3_RANDOM_SIZE);
-    fprintf(stderr, "Server Random:\n");
-    BIO_dump_fp(stderr, (char *)s->s3->server_random, SSL3_RANDOM_SIZE);
-    fprintf(stderr, "Master Secret:\n");
-    BIO_dump_fp(stderr, (char *)s->session->master_key,
-                SSL3_MASTER_SECRET_SIZE);
-#endif
+
+    OSSL_TRACE_BEGIN(TLS) {
+        BIO_printf(trc_out, "Premaster Secret:\n");
+        BIO_dump_indent(trc_out, p, len, 4);
+        BIO_printf(trc_out, "Client Random:\n");
+        BIO_dump_indent(trc_out, s->s3->client_random, SSL3_RANDOM_SIZE, 4);
+        BIO_printf(trc_out, "Server Random:\n");
+        BIO_dump_indent(trc_out, s->s3->server_random, SSL3_RANDOM_SIZE, 4);
+        BIO_printf(trc_out, "Master Secret:\n");
+        BIO_dump_indent(trc_out,
+                        s->session->master_key,
+                        SSL3_MASTER_SECRET_SIZE, 4);
+    } OSSL_TRACE_END(TLS);
 
     *secret_size = SSL3_MASTER_SECRET_SIZE;
     return 1;
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 9957cf8..cb0cb22 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4646,3 +4646,12 @@ OPENSSL_CTX_free                        4601	3_0_0	EXIST::FUNCTION:
 OPENSSL_LH_flush                        4602	3_0_0	EXIST::FUNCTION:
 BN_native2bn                            4603	3_0_0	EXIST::FUNCTION:
 BN_bn2nativepad                         4604	3_0_0	EXIST::FUNCTION:
+OSSL_trace_get_category_num             4605	3_0_0	EXIST::FUNCTION:
+OSSL_trace_get_category_name            4606	3_0_0	EXIST::FUNCTION:
+OSSL_trace_set_channel                  4607	3_0_0	EXIST::FUNCTION:
+OSSL_trace_set_prefix                   4608	3_0_0	EXIST::FUNCTION:
+OSSL_trace_set_suffix                   4609	3_0_0	EXIST::FUNCTION:
+OSSL_trace_set_callback                 4610	3_0_0	EXIST::FUNCTION:
+OSSL_trace_enabled                      4611	3_0_0	EXIST::FUNCTION:
+OSSL_trace_begin                        4612	3_0_0	EXIST::FUNCTION:
+OSSL_trace_end                          4613	3_0_0	EXIST::FUNCTION:
diff --git a/util/private.num b/util/private.num
index d8aba4d..ad1865f 100644
--- a/util/private.num
+++ b/util/private.num
@@ -47,6 +47,7 @@ OSSL_STORE_error_fn                     datatype
 OSSL_STORE_load_fn                      datatype
 OSSL_STORE_open_fn                      datatype
 OSSL_STORE_post_process_info_fn         datatype
+OSSL_trace_cb                           datatype
 PROFESSION_INFO                         datatype
 PROFESSION_INFOS                        datatype
 RAND_DRBG_cleanup_entropy_fn            datatype


More information about the openssl-commits mailing list