Browse Source

add OSSL_TRACE_STRING(), OSSL_TRACE_STRING_MAX, and OSSL_trace_string()

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/18704)
Dr. David von Oheimb 1 year ago
parent
commit
0243e82147
5 changed files with 104 additions and 16 deletions
  1. 25 0
      crypto/trace.c
  2. 27 1
      doc/man3/OSSL_trace_enabled.pod
  3. 8 0
      include/openssl/trace.h
  4. 43 15
      test/trace_api_test.c
  5. 1 0
      util/libcrypto.num

+ 25 - 0
crypto/trace.c

@@ -18,6 +18,7 @@
 #include "internal/nelem.h"
 #include "internal/refcount.h"
 #include "crypto/cryptlib.h"
+#include "crypto/ctype.h"
 
 #ifndef OPENSSL_NO_TRACE
 
@@ -530,3 +531,27 @@ void OSSL_trace_end(int category, BIO * channel)
     }
 #endif
 }
+
+int OSSL_trace_string(BIO *out, int text, int full,
+                      const unsigned char *data, size_t size)
+{
+    unsigned char buf[OSSL_TRACE_STRING_MAX + 1];
+    int len, i;
+
+    if (!full && size > OSSL_TRACE_STRING_MAX) {
+        BIO_printf(out, "[len %zu limited to %d]: ",
+                   size, OSSL_TRACE_STRING_MAX);
+        len = OSSL_TRACE_STRING_MAX;
+    } else {
+        len = (int)size;
+    }
+    if (!text) { /* mask control characters while preserving newlines */
+        for (i = 0; i < len; i++, data++)
+            buf[i] = (char)*data != '\n' && ossl_iscntrl((int)*data)
+                ? ' ' : *data;
+        if (len == 0 || data[-1] != '\n')
+            buf[len++] = '\n';
+        data = buf;
+    }
+    return BIO_printf(out, "%.*s", len, data);
+}

+ 27 - 1
doc/man3/OSSL_trace_enabled.pod

@@ -7,6 +7,7 @@ OSSL_TRACE_BEGIN, OSSL_TRACE_END, OSSL_TRACE_CANCEL,
 OSSL_TRACE, OSSL_TRACE1, OSSL_TRACE2, OSSL_TRACE3, OSSL_TRACE4,
 OSSL_TRACE5, OSSL_TRACE6, OSSL_TRACE7, OSSL_TRACE8, OSSL_TRACE9,
 OSSL_TRACEV,
+OSSL_TRACE_STRING, OSSL_TRACE_STRING_MAX, OSSL_trace_string,
 OSSL_TRACE_ENABLED
 - OpenSSL Tracing API
 
@@ -38,6 +39,11 @@ OSSL_TRACE_ENABLED
  OSSL_TRACE2(category, format, arg1, arg2)
  ...
  OSSL_TRACE9(category, format, arg1, ..., arg9)
+ OSSL_TRACE_STRING(category, text, full, data, len)
+
+ #define OSSL_TRACE_STRING_MAX 80
+ int OSSL_trace_string(BIO *out, int text, int full,
+                       const unsigned char *data, size_t size);
 
  /* check whether a trace category is enabled */
  if (OSSL_TRACE_ENABLED(category)) {
@@ -102,6 +108,12 @@ is I<mandatory>.
 The result of trying to produce tracing output outside of such
 sections is undefined.
 
+OSSL_trace_string() outputs I<data> of length I<size> as a string on BIO I<out>.
+If I<text> is 0, the function masks any included control characters apart from
+newlines and makes sure for nonempty input that the output ends with a newline.
+Unless I<full> is nonzero, the length is limited (with a suitable warning)
+to B<OSSL_TRACE_STRING_MAX> characters, which currently is 80.
+
 =head2 Macros
 
 There are a number of convenience macros defined, to make tracing
@@ -165,13 +177,22 @@ printf-style trace output with n format field arguments (n=1,...,9).
 It expands to:
 
  OSSL_TRACE_BEGIN(category) {
-     BIO_printf(trc_out, format, arg1, ..., argN)
+     BIO_printf(trc_out, format, arg1, ..., argN);
  } OSSL_TRACE_END(category)
 
 Internally, all one-shot macros are implemented using a generic OSSL_TRACEV()
 macro, since C90 does not support variadic macros. This helper macro has a rather
 weird synopsis and should not be used directly.
 
+The macro call C<OSSL_TRACE_STRING(category, text, full, data, len)>
+outputs I<data> of length I<size> as a string
+if tracing for the given I<category> is enabled.
+It expands to:
+
+ OSSL_TRACE_BEGIN(category) {
+     OSSL_trace_string(trc_out, text, full, data, len);
+ } OSSL_TRACE_END(category)
+
 The OSSL_TRACE_ENABLED() macro can be used to conditionally execute some code
 only if a specific trace category is enabled.
 In some situations this is simpler than entering a trace section using
@@ -279,6 +300,8 @@ operational and enabled, otherwise 0.
 OSSL_trace_begin() returns a B<BIO> pointer if the given I<type> is enabled,
 otherwise NULL.
 
+OSSL_trace_string() returns the number of characters emitted, or -1 on error.
+
 =head1 SEE ALSO
 
 L<OSSL_trace_set_channel(3)>, L<OSSL_trace_set_callback(3)>
@@ -287,6 +310,9 @@ L<OSSL_trace_set_channel(3)>, L<OSSL_trace_set_callback(3)>
 
 The OpenSSL Tracing API was added in OpenSSL 3.0.
 
+OSSL_TRACE_STRING(), OSSL_TRACE_STRING_MAX, and OSSL_trace_string
+were added in OpenSSL 3.2.
+
 =head1 COPYRIGHT
 
 Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.

+ 8 - 0
include/openssl/trace.h

@@ -305,6 +305,14 @@ void OSSL_trace_end(int category, BIO *channel);
 # define OSSL_TRACE9(category, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
     OSSL_TRACEV(category, (trc_out, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9))
 
+#define OSSL_TRACE_STRING_MAX 80
+int OSSL_trace_string(BIO *out, int text, int full,
+                      const unsigned char *data, size_t size);
+#define OSSL_TRACE_STRING(category, text, full, data, len) \
+    OSSL_TRACE_BEGIN(category) { \
+        OSSL_trace_string(trc_out, text, full, data, len);  \
+    } OSSL_TRACE_END(category)
+
 # ifdef  __cplusplus
 }
 # endif

+ 43 - 15
test/trace_api_test.c

@@ -65,18 +65,45 @@ static int test_trace_categories(void)
 }
 
 #ifndef OPENSSL_NO_TRACE
-static void put_trace_output(void)
+
+# define OSSL_START "xyz-"
+# define OSSL_HELLO "Hello World\n"
+/* OSSL_STR80 must have length OSSL_TRACE_STRING_MAX */
+# define OSSL_STR80 "1234567890123456789012345678901234567890123456789012345678901234567890123456789\n"
+# define OSSL_STR81 (OSSL_STR80"x")
+# define OSSL_CTRL "A\xfe\nB"
+# define OSSL_MASKED "A \nB"
+# define OSSL_BYE "Good Bye Universe\n"
+# define OSSL_END "-abc"
+
+# define trace_string(text, full, str) \
+    OSSL_trace_string(trc_out, text, full, (unsigned char *)(str), strlen(str))
+
+static int put_trace_output(void)
 {
+    int res = 1;
+
     OSSL_TRACE_BEGIN(HTTP) {
-        BIO_printf(trc_out, "Hello World\n");
-        BIO_printf(trc_out, "Good Bye Universe\n");
+        res = TEST_int_eq(BIO_printf(trc_out, OSSL_HELLO), strlen(OSSL_HELLO))
+            + TEST_int_eq(trace_string(0, 0, OSSL_STR80), strlen(OSSL_STR80))
+            + TEST_int_eq(trace_string(0, 0, OSSL_STR81), strlen(OSSL_STR80))
+            + TEST_int_eq(trace_string(1, 1, OSSL_CTRL), strlen(OSSL_CTRL))
+            + TEST_int_eq(trace_string(0, 1, OSSL_MASKED), strlen(OSSL_MASKED)
+                          + 1) /* newline added */
+            + TEST_int_eq(BIO_printf(trc_out, OSSL_BYE), strlen(OSSL_BYE))
+            == 6;
+        /* not using '&&' but '+' to catch potentially multiple test failures */
     } OSSL_TRACE_END(HTTP);
+    return res;
 }
 
 static int test_trace_channel(void)
 {
-    static const char expected[] = "xyz-\nHello World\nGood Bye Universe\n-abc\n";
-    static const char expected_len = sizeof(expected) - 1;
+    static const char expected[] =
+        OSSL_START"\n" OSSL_HELLO
+        OSSL_STR80 "[len 81 limited to 80]: "OSSL_STR80
+        OSSL_CTRL OSSL_MASKED"\n" OSSL_BYE OSSL_END"\n";
+    static const size_t expected_len = sizeof(expected) - 1;
     BIO *bio = NULL;
     char *p_buf = NULL;
     long len = 0;
@@ -86,28 +113,29 @@ static int test_trace_channel(void)
     if (!TEST_ptr(bio))
         goto end;
 
-    if (!TEST_int_eq(OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_HTTP, bio), 1))
+    if (!TEST_int_eq(OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_HTTP, bio), 1)) {
+        BIO_free(bio);
         goto end;
+    }
 
     if (!TEST_true(OSSL_trace_enabled(OSSL_TRACE_CATEGORY_HTTP)))
         goto end;
 
-    if (!TEST_int_eq(OSSL_trace_set_prefix(OSSL_TRACE_CATEGORY_HTTP, "xyz-"), 1))
+    if (!TEST_int_eq(OSSL_trace_set_prefix(OSSL_TRACE_CATEGORY_HTTP,
+                                           OSSL_START), 1))
         goto end;
-    if (!TEST_int_eq(OSSL_trace_set_suffix(OSSL_TRACE_CATEGORY_HTTP, "-abc"), 1))
+    if (!TEST_int_eq(OSSL_trace_set_suffix(OSSL_TRACE_CATEGORY_HTTP,
+                                           OSSL_END), 1))
         goto end;
 
-    put_trace_output();
+    ret = put_trace_output();
     len = BIO_get_mem_data(bio, &p_buf);
     if (!TEST_strn2_eq(p_buf, len, expected, expected_len))
-        goto end;
-    if (!TEST_int_eq(OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_HTTP, NULL), 1))
-        goto end;
-    bio = NULL;
+        ret = 0;
+    ret = TEST_int_eq(OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_HTTP, NULL), 1)
+        && ret;
 
-    ret = 1;
  end:
-    BIO_free(bio);
     return ret;
 }
 

+ 1 - 0
util/libcrypto.num

@@ -5433,6 +5433,7 @@ RAND_set0_private                       ?	3_1_0	EXIST::FUNCTION:
 BN_are_coprime                          ?	3_1_0	EXIST::FUNCTION:
 X509_PUBKEY_set0_public_key             ?	3_2_0	EXIST::FUNCTION:
 OSSL_STACK_OF_X509_free                 ?	3_2_0	EXIST::FUNCTION:
+OSSL_trace_string                       ?	3_2_0	EXIST::FUNCTION:
 EVP_MD_CTX_dup                          ?	3_2_0	EXIST::FUNCTION:
 EVP_CIPHER_CTX_dup                      ?	3_2_0	EXIST::FUNCTION:
 BN_signed_bin2bn                        ?	3_2_0	EXIST::FUNCTION: