Browse Source

Add wolfSSL_CTX_set_keylog_callback

TakayukiMatsuo 3 years ago
parent
commit
5df0f7820a
9 changed files with 996 additions and 279 deletions
  1. 2 1
      Makefile.am
  2. 239 0
      src/internal.c
  3. 31 2
      src/ssl.c
  4. 65 1
      src/tls13.c
  5. 633 271
      tests/api.c
  6. 9 0
      wolfssl/internal.h
  7. 4 4
      wolfssl/openssl/evp.h
  8. 4 0
      wolfssl/openssl/ssl.h
  9. 9 0
      wolfssl/ssl.h

+ 2 - 1
Makefile.am

@@ -125,7 +125,8 @@ CLEANFILES+= ecc-key.der \
              pkcs7signedEncryptedCompressedFirmwarePkgData_ECDSA_SHA256_noattr.der \
              pkcs7signedEncryptedCompressedFirmwarePkgData_RSA_SHA256.der \
              pkcs7signedEncryptedCompressedFirmwarePkgData_RSA_SHA256_noattr.der \
-             tests/test-log-dump-to-file.txt
+             tests/test-log-dump-to-file.txt \
+             MyKeyLog.txt
 
 exampledir = $(docdir)/example
 dist_example_DATA=

+ 239 - 0
src/internal.c

@@ -84,6 +84,9 @@
     #include <wolfssl/wolfcrypt/srp.h>
 #endif
 
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+    #include <wolfssl/wolfcrypt/coding.h>
+#endif
 #ifdef HAVE_LIBZ
     #include "zlib.h"
 #endif
@@ -224,6 +227,225 @@ static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz,
     int tsip_generatePremasterSecret();
     int tsip_generateEncryptPreMasterSecret(WOLFSSL *ssl, byte *out, word32 *outSz);
 #endif
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+
+    static int  SessionSecret_callback(WOLFSSL* ssl, void* secret,
+                                                  int* secretSz, void* ctx);
+    static int  SessionSecret_callback_Tls13(WOLFSSL* ssl, int id,
+                       const unsigned char* secret, int secretSz, void* ctx);
+
+    /*
+     * This function builds up string for key-logging then call user's
+     * key-log-callback to pass the string for TLS1.2 and older.
+     * The user's key-logging callback has been set via
+     * wolfSSL_CTX_set_keylog_callback function. The logging string format is:
+     * "CLIENT_RANDOM <hex-encoded client random> <hex-encoded master-secret>"
+     * parameter
+     *  - ssl: WOLFSSL object
+     *  - secret: pointer to the buffer holding master-secret
+     *  - secretSz: size of secret
+     *  - ctx: not used
+     * returns 0 on success, negative value on failure.
+     */
+    static int SessionSecret_callback(WOLFSSL* ssl, void* secret,
+                    int* secretSz, void* ctx)
+    {
+        wolfSSL_CTX_keylog_cb_func logCb = NULL;
+        int msSz;
+        int hasVal;
+        int i;
+        const char* label = "CLIENT_RANDOM";
+        int labelSz = sizeof("CLIENT_RANDOM");
+        int buffSz;
+        byte* log = NULL;
+        word32 outSz;
+        int idx;
+        int ret;
+        (void)ctx;
+
+        if (ssl == NULL || secret == NULL || *secretSz == 0)
+            return BAD_FUNC_ARG;
+        if (ssl->arrays == NULL)
+            return BAD_FUNC_ARG;
+
+        /* get the user-callback func from CTX*/
+        logCb = ssl->ctx->keyLogCb;
+        if (logCb == NULL)
+            return 0;
+
+        /* need to make sure the given master-secret has a meaningful value */
+        msSz   = *secretSz;
+        hasVal = 0;
+        for (i = 0; i < msSz; i++) {
+            if (*((byte*)secret) != 0) {
+                hasVal = 1;
+                break;
+            }
+        }
+        if (hasVal == 0)
+            return 0; /* master-secret looks invalid */
+
+        /* build up a hex-decoded keylog string
+           "CLIENT_RANDOM <hex-encoded client random> <hex-encoded master-secret>"
+           note that each keylog string does not have LF.
+        */
+        buffSz  = labelSz + (RAN_LEN * 2) + 1 + ((*secretSz) * 2) + 1;
+        log     = XMALLOC(buffSz, ssl->heap, DYNAMIC_TYPE_SECRET);
+
+        if (log == NULL)
+            return MEMORY_E;
+
+        XMEMSET(log, 0, buffSz);
+        XMEMCPY(log, label, labelSz -1);     /* put label w/o terminator */
+        XMEMSET(log + labelSz - 1, ' ', 1);               /* '\0' -> ' ' */
+        idx = labelSz;
+        outSz = buffSz - idx;
+        if ((ret = Base16_Encode(ssl->arrays->clientRandom, RAN_LEN,
+                                            log + idx, &outSz)) == 0) {
+            idx += (outSz - 1); /* reduce terminator byte */
+            outSz = buffSz - idx;
+
+            if (outSz > 1) {
+                XMEMSET(log + idx, ' ', 1);  /* add space*/
+                idx++;
+                outSz = buffSz - idx;
+
+                if ((ret = Base16_Encode((byte*)secret, *secretSz,
+                                             log + idx, &outSz)) == 0) {
+                    /* pass the log to the client callback*/
+                    logCb(ssl, (char*)log);
+                    ret = 0;
+                }
+            }
+            else
+                ret = MEMORY_E;
+        }
+        XFREE(log, ssl->heap, DYNAMIC_TYPE_SECRET);
+        return ret;
+    }
+#if defined(WOLFSSL_TLS13)
+    /*
+     * This function builds up string for key-logging then call user's
+     * key-log-callback to pass the string for TLS1.3.
+     * The user's key-logging callback has been set via
+     * wolfSSL_CTX_set_keylog_callback function. The logging string format is:
+     * "<Lable> <hex-encoded client random> <hex-encoded secret>"
+     *
+     * parameter
+     *  - ssl: WOLFSSL object
+     *  - id: type of secret for logging
+     *  - secret: pointer to the buffer holding secret
+     *  - secretSz: size of secret
+     *  - ctx: not used
+     * returns 0 on success, negative value on failure.
+     */
+    static int SessionSecret_callback_Tls13(WOLFSSL* ssl, int id,
+        const unsigned char* secret, int secretSz, void* ctx)
+    {
+        wolfSSL_CTX_keylog_cb_func logCb = NULL;
+        char  label[50];
+        int   labelSz = 0;
+        int   buffSz  = 0;
+        byte* log     = NULL;
+        word32 outSz;
+        int idx;
+        int ret;
+
+        (void)ctx;
+
+        if (ssl == NULL || secret == NULL || secretSz == 0)
+            return BAD_FUNC_ARG;
+        if (ssl->arrays == NULL)
+            return BAD_FUNC_ARG;
+
+        /* get the user-callback func from CTX*/
+        logCb = ssl->ctx->keyLogCb;
+        if (logCb == NULL)
+            return 0;
+
+        switch (id) {
+            case CLIENT_EARLY_TRAFFIC_SECRET:
+
+                labelSz = sizeof("CLIENT_EARLY_TRAFFIC_SECRET");
+                XSTRNCPY(label,"CLIENT_EARLY_TRAFFIC_SECRET", labelSz);
+                break;
+
+            case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
+
+                labelSz = sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET");
+                XSTRNCPY(label, "CLIENT_HANDSHAKE_TRAFFIC_SECRET", labelSz);
+                break;
+
+            case SERVER_HANDSHAKE_TRAFFIC_SECRET:
+
+                labelSz = sizeof("SERVER_HANDSHAKE_TRAFFIC_SECRET");
+                XSTRNCPY(label, "SERVER_HANDSHAKE_TRAFFIC_SECRET", labelSz);
+                break;
+
+            case CLIENT_TRAFFIC_SECRET:
+
+                labelSz = sizeof("CLIENT_TRAFFIC_SECRET_0");
+                XSTRNCPY(label, "CLIENT_TRAFFIC_SECRET_0", labelSz);
+                break;
+
+            case SERVER_TRAFFIC_SECRET:
+
+                labelSz = sizeof("SERVER_TRAFFIC_SECRET_0");
+                XSTRNCPY(label, "SERVER_TRAFFIC_SECRET_0", labelSz);
+                break;
+
+            case EARLY_EXPORTER_SECRET:
+
+                labelSz = sizeof("EARLY_EXPORTER_SECRET");
+                XSTRNCPY(label, "EARLY_EXPORTER_SECRET", labelSz);
+                break;
+
+            case EXPORTER_SECRET:
+
+                labelSz = sizeof("EXPORTER_SECRET");
+                XSTRNCPY(label, "EXPORTER_SECRET", labelSz);
+                break;
+
+            default:
+                return BAD_FUNC_ARG;
+        }
+        /* prepare a log string for passing user callback */
+        buffSz = labelSz + (RAN_LEN * 2) + 1 + secretSz * 2 + 1;
+        log    = XMALLOC(buffSz, ssl->heap, DYNAMIC_TYPE_SECRET);
+        if (log == NULL)
+            return MEMORY_E;
+
+        XMEMSET(log, 0, buffSz);
+        XMEMCPY(log, label, labelSz - 1);     /* put label w/o terminator */
+        XMEMSET(log + labelSz - 1, ' ', 1);               /* '\0' -> ' ' */
+
+        idx = labelSz;
+        outSz = buffSz - idx;
+        if ((ret = Base16_Encode(ssl->arrays->clientRandom, RAN_LEN,
+                                            log + idx, &outSz)) == 0) {
+            idx  += (outSz -1); /* reduce terminator byte */
+            outSz = buffSz - idx;
+
+            if (outSz >1) {
+                XMEMSET(log + idx, ' ', 1);        /* add space*/
+                idx++;
+                outSz = buffSz - idx;
+
+                if ((ret = Base16_Encode((byte*)secret, secretSz,
+                                log + idx, &outSz)) == 0) {
+                    logCb(ssl, (char*)log);
+                    ret = 0;
+                }
+            }
+            else
+                ret = MEMORY_E;
+        }
+        XFREE(log, ssl->heap, DYNAMIC_TYPE_SECRET);
+        return ret;
+    }
+#endif /* WOLFSSL_TLS13*/
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK*/
+
 int IsTLS(const WOLFSSL* ssl)
 {
     if (ssl->version.major == SSLv3_MAJOR && ssl->version.minor >=TLSv1_MINOR)
@@ -6135,6 +6357,14 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
     ssl->tls13SecretCtx = NULL;
 #endif
 #endif
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+    if (ctx->keyLogCb != NULL) {
+        ssl->keyLogCb = SessionSecret_callback;
+#if defined(WOLFSSL_TLS13)
+        ssl->tls13KeyLogCb = SessionSecret_callback_Tls13;
+#endif /*WOLFSSL_TLS13*/
+    }
+#endif /*OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
 
 #ifdef HAVE_SESSION_TICKET
     ssl->options.noTicketTls12 = ctx->noTicketTls12;
@@ -25389,6 +25619,15 @@ int SendClientKeyExchange(WOLFSSL* ssl)
                 }
                 ssl->options.clientState = CLIENT_KEYEXCHANGE_COMPLETE;
             }
+        #if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+            if (ssl->keyLogCb != NULL) {
+                int secretSz = SECRET_LEN;
+                ret = ssl->keyLogCb(ssl, ssl->arrays->masterSecret, &secretSz,
+                                                                        NULL);
+                if (ret != 0 || secretSz != SECRET_LEN)
+                    return SESSION_SECRET_CB_E;
+            }
+        #endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
             break;
         }
         default:

+ 31 - 2
src/ssl.c

@@ -43754,7 +43754,11 @@ int wolfSSL_CTX_use_PrivateKey(WOLFSSL_CTX *ctx, WOLFSSL_EVP_PKEY *pkey)
 
 #endif /* OPENSSL_EXTRA */
 
-#if defined(HAVE_EX_DATA) || defined(FORTRESS) || defined(WOLFSSL_WPAS_SMALL)
+#if defined(HAVE_EX_DATA) && \
+   (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \
+    defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) || \
+    defined(HAVE_LIGHTY)) || defined(HAVE_EX_DATA) || defined(FORTRESS) || \
+    defined(WOLFSSL_WPAS_SMALL)
 /**
  * get_ex_new_index is a helper function for the following
  * xx_get_ex_new_index functions:
@@ -49559,7 +49563,6 @@ int oid2nid(word32 oid, int grp)
     return -1;
 }
 
-
 /* when calling SetIndividualInternal, mpi should be cleared by caller if no
  * longer used. ie mp_free(mpi). This is to free data when fastmath is
  * disabled since a copy of mpi is made by this function and placed into bn.
@@ -51993,6 +51996,7 @@ void wolfSSL_BN_free(WOLFSSL_BIGNUM* bn)
         XFREE(bn, NULL, DYNAMIC_TYPE_BIGINT);
         /* bn = NULL, don't try to access or double free it */
     }
+
 }
 
 void wolfSSL_BN_clear_free(WOLFSSL_BIGNUM* bn)
@@ -53958,6 +53962,31 @@ int wolfSSL_CONF_cmd(WOLFSSL_CONF_CTX* cctx, const char* cmd, const char* value)
     return ret;
 }
 
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+/*
+ * This API accepts a user callback which puts key-log records into
+ * a KEY LOGFILE. The callback is stored into a CTX and propagated to
+ * each SSL object on its creation timing.
+ */
+void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx, wolfSSL_CTX_keylog_cb_func cb)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_set_keylog_callback");
+  /* stores the callback into WOLFSSL_CTX */
+    if (ctx != NULL) {
+        ctx->keyLogCb = cb;
+    }
+}
+wolfSSL_CTX_keylog_cb_func wolfSSL_CTX_get_keylog_callback(
+    const WOLFSSL_CTX* ctx)
+{
+    WOLFSSL_ENTER("wolfSSL_CTX_get_keylog_callback");
+    if (ctx != NULL)
+        return ctx->keyLogCb;
+    else
+        return NULL;
+}
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
+
 /**
  * Return DH p, q and g parameters
  * @param dh a pointer to WOLFSSL_DH

+ 65 - 1
src/tls13.c

@@ -531,6 +531,15 @@ static int DeriveEarlyTrafficSecret(WOLFSSL* ssl, byte* key)
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, CLIENT_EARLY_TRAFFIC_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -560,12 +569,21 @@ static int DeriveEarlyExporterSecret(WOLFSSL* ssl, byte* key)
                     ssl->specs.mac_algorithm, 1);
 #ifdef HAVE_SECRET_CALLBACK
     if (ret == 0 && ssl->tls13SecretCb != NULL) {
-        ret = ssl->tls13SecretCb(ssl, EARLY_EXPORTER_SECRET, key
+        ret = ssl->tls13SecretCb(ssl, EARLY_EXPORTER_SECRET, key,
                                  ssl->specs.hash_size, ssl->tls13SecretCtx);
         if (ret != 0) {
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, EARLY_EXPORTER_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -602,6 +620,15 @@ static int DeriveClientHandshakeSecret(WOLFSSL* ssl, byte* key)
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, CLIENT_HANDSHAKE_TRAFFIC_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -636,6 +663,15 @@ static int DeriveServerHandshakeSecret(WOLFSSL* ssl, byte* key)
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, SERVER_HANDSHAKE_TRAFFIC_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -670,6 +706,15 @@ static int DeriveClientTrafficSecret(WOLFSSL* ssl, byte* key)
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, CLIENT_TRAFFIC_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -704,6 +749,15 @@ static int DeriveServerTrafficSecret(WOLFSSL* ssl, byte* key)
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, SERVER_TRAFFIC_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -739,6 +793,15 @@ static int DeriveExporterSecret(WOLFSSL* ssl, byte* key)
             return TLS13_SECRET_CB_E;
         }
     }
+#ifdef OPENSSL_EXTRA
+    if (ret == 0 && ssl->tls13KeyLogCb != NULL) {
+        ret = ssl->tls13KeyLogCb(ssl, EXPORTER_SECRET, key,
+                                ssl->specs.hash_size, NULL);
+        if (ret != 0) {
+            return TLS13_SECRET_CB_E;
+        }
+    }
+#endif /* OPENSSL_EXTRA */
 #endif /* HAVE_SECRET_CALLBACK */
     return ret;
 }
@@ -3852,6 +3915,7 @@ static void RefineSuites(WOLFSSL* ssl, Suites* peerSuites)
 #endif
 }
 
+
 #ifndef NO_PSK
 /* Attempt to find the PSK (not session ticket) that matches.
  *

+ 633 - 271
tests/api.c

@@ -2638,6 +2638,276 @@ static void test_ED448(void)
  | EVP
  *----------------------------------------------------------------------------*/
 
+static void test_wolfSSL_EVP_PKEY_print_public(void)
+{
+#if defined(OPENSSL_EXTRA)
+
+    WOLFSSL_BIO* rbio = NULL;
+    WOLFSSL_BIO* wbio = NULL;
+    WOLFSSL_EVP_PKEY* pkey = NULL;
+    char line[256] = { 0 };
+    char line1[256] = { 0 };
+    int i;
+
+    printf(testingFmt, "EVP_PKEY_print_public()");
+    /* test error cases */
+    AssertIntEQ( EVP_PKEY_print_public(NULL,NULL,0,NULL),0L);
+
+    /*
+     *  test RSA public key print
+     *  in this test, pass '3' for indent
+     */
+#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_1024)
+
+    rbio = BIO_new_mem_buf( client_keypub_der_1024,
+                            sizeof_client_keypub_der_1024);
+    AssertNotNull(rbio);
+
+    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
+    AssertNotNull(pkey);
+
+    wbio = BIO_new(BIO_s_mem());
+    AssertNotNull(wbio);
+
+    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,3,NULL),1);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "   RSA Public-Key: (1024 bit)\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "   Modulus:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "       00:BC:73:0E:A8:49:F3:74:A2:A9:EF:18:A5:DA:55:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+
+    /* skip to the end of modulus element*/
+    for( i = 0; i < 8 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "   Exponent: 65537 (0x010001)\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+
+    /* should reach EOF */
+    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
+
+    EVP_PKEY_free(pkey);
+    pkey = NULL;
+    BIO_free(rbio);
+    BIO_free(wbio);
+    rbio = NULL;
+    wbio = NULL;
+
+#endif  /* !NO_RSA && USE_CERT_BUFFERS_1024*/
+
+    /*
+     *  test DSA public key print
+     */
+#if !defined(NO_DSA) && defined(USE_CERT_BUFFERS_2048)
+    rbio = BIO_new_mem_buf( dsa_pub_key_der_2048,
+                            sizeof_dsa_pub_key_der_2048);
+    AssertNotNull(rbio);
+
+    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
+    AssertNotNull(pkey);
+
+    wbio = BIO_new(BIO_s_mem());
+    AssertNotNull(wbio);
+
+    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,0,NULL),1);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "DSA Public-Key: (2048 bit)\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "pub:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1,
+        "    00:C2:35:2D:EC:83:83:6C:73:13:9E:52:7C:74:C8:\n"); 
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of pub element*/
+    for( i = 0; i < 17 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "P:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of P element*/
+    for( i = 0; i < 18 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "Q:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of Q element*/
+    for( i = 0; i < 3 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "G:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of G element*/
+    for( i = 0; i < 18 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+    /* should reach EOF */
+    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
+
+    EVP_PKEY_free(pkey);
+    pkey = NULL;
+    BIO_free(rbio);
+    BIO_free(wbio);
+    rbio = NULL;
+    wbio = NULL;
+
+#endif /* !NO_DSA && USE_CERT_BUFFERS_2048 */
+
+    /*
+     *  test ECC public key print
+     */
+#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
+
+    rbio = BIO_new_mem_buf( ecc_clikeypub_der_256,
+                            sizeof_ecc_clikeypub_der_256);
+    AssertNotNull(rbio);
+
+    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
+    AssertNotNull(pkey);
+
+    wbio = BIO_new(BIO_s_mem());
+    AssertNotNull(wbio);
+
+    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,0,NULL),1);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "Public-Key: (256 bit)\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "pub:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1,
+            "    04:55:BF:F4:0F:44:50:9A:3D:CE:9B:B7:F0:C5:4D:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of pub element*/
+    for( i = 0; i < 4 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "ASN1 OID: prime256v1\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "NIST CURVE: P-256\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+
+    /* should reach EOF */
+    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
+
+    EVP_PKEY_free(pkey);
+    pkey = NULL;
+    BIO_free(rbio);
+    BIO_free(wbio);
+    rbio = NULL;
+    wbio = NULL;
+
+#endif /* HAVE_ECC && USE_CERT_BUFFERS_256 */
+
+    /*
+     *  test DH public key print
+     */
+#if defined(WOLFSSL_DH_EXTRA) && defined(USE_CERT_BUFFERS_2048)
+
+    rbio = BIO_new_mem_buf( dh_pub_key_der_2048,
+                            sizeof_dh_pub_key_der_2048);
+    AssertNotNull(rbio);
+
+    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
+    AssertNotNull(pkey);
+
+    wbio = BIO_new(BIO_s_mem());
+    AssertNotNull(wbio);
+
+    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,0,NULL),1);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "DH Public-Key: (2048 bit)\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "public-key:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1,
+        "    34:41:BF:E9:F2:11:BF:05:DB:B2:72:A8:29:CC:BD:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of public-key element*/
+    for( i = 0; i < 17 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "prime:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1,
+        "    00:D3:B2:99:84:5C:0A:4C:E7:37:CC:FC:18:37:01:\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* skip to the end of prime element*/
+    for( i = 0; i < 17 ;i++) {
+        BIO_gets(wbio, line, sizeof(line));
+    }
+
+    BIO_gets(wbio, line, sizeof(line));
+    strcpy(line1, "generator: 2 (0x02)\n");
+    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
+
+    /* should reach EOF */
+    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
+
+    EVP_PKEY_free(pkey);
+    pkey = NULL;
+    BIO_free(rbio);
+    BIO_free(wbio);
+    rbio = NULL;
+    wbio = NULL;
+
+#endif /* WOLFSSL_DH_EXTRA && USE_CERT_BUFFERS_2048 */
+
+    /* to prevent "unused variable" warning */
+    (void)pkey;
+    (void)wbio;
+    (void)rbio;
+    (void)line;
+    (void)line1;
+    (void)i;
+    printf(resultFmt, passed);
+#endif /* OPENSSL_EXTRA */
+}
 /* Test functions for base64 encode/decode */
 static void test_wolfSSL_EVP_ENCODE_CTX_new(void)
 {
@@ -3140,276 +3410,6 @@ static void test_wolfSSL_EVP_DecodeFinal(void)
     printf(resultFmt, passed);
 #endif /* OPENSSL && WOLFSSL_BASE_DECODE */
 }
-static void test_wolfSSL_EVP_PKEY_print_public(void)
-{
-#if defined(OPENSSL_EXTRA)
-
-    WOLFSSL_BIO* rbio = NULL;
-    WOLFSSL_BIO* wbio = NULL;
-    WOLFSSL_EVP_PKEY* pkey = NULL;
-    char line[256] = { 0 };
-    char line1[256] = { 0 };
-    int i;
-
-    printf(testingFmt, "EVP_PKEY_print_public()");
-    /* test error cases */
-    AssertIntEQ( EVP_PKEY_print_public(NULL,NULL,0,NULL),0L);
-
-    /*
-     *  test RSA public key print
-     *  in this test, pass '3' for indent
-     */
-#if !defined(NO_RSA) && defined(USE_CERT_BUFFERS_1024)
-
-    rbio = BIO_new_mem_buf( client_keypub_der_1024,
-                            sizeof_client_keypub_der_1024);
-    AssertNotNull(rbio);
-
-    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
-    AssertNotNull(pkey);
-
-    wbio = BIO_new(BIO_s_mem());
-    AssertNotNull(wbio);
-
-    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,3,NULL),1);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "   RSA Public-Key: (1024 bit)\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "   Modulus:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "       00:BC:73:0E:A8:49:F3:74:A2:A9:EF:18:A5:DA:55:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-
-    /* skip to the end of modulus element*/
-    for( i = 0; i < 8 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "   Exponent: 65537 (0x010001)\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-
-    /* should reach EOF */
-    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
-
-    EVP_PKEY_free(pkey);
-    pkey = NULL;
-    BIO_free(rbio);
-    BIO_free(wbio);
-    rbio = NULL;
-    wbio = NULL;
-
-#endif  /* !NO_RSA && USE_CERT_BUFFERS_1024*/
-
-    /*
-     *  test DSA public key print
-     */
-#if !defined(NO_DSA) && defined(USE_CERT_BUFFERS_2048)
-    rbio = BIO_new_mem_buf( dsa_pub_key_der_2048,
-                            sizeof_dsa_pub_key_der_2048);
-    AssertNotNull(rbio);
-
-    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
-    AssertNotNull(pkey);
-
-    wbio = BIO_new(BIO_s_mem());
-    AssertNotNull(wbio);
-
-    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,0,NULL),1);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "DSA Public-Key: (2048 bit)\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "pub:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1,
-        "    00:C2:35:2D:EC:83:83:6C:73:13:9E:52:7C:74:C8:\n"); 
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of pub element*/
-    for( i = 0; i < 17 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "P:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of P element*/
-    for( i = 0; i < 18 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "Q:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of Q element*/
-    for( i = 0; i < 3 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "G:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of G element*/
-    for( i = 0; i < 18 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-    /* should reach EOF */
-    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
-
-    EVP_PKEY_free(pkey);
-    pkey = NULL;
-    BIO_free(rbio);
-    BIO_free(wbio);
-    rbio = NULL;
-    wbio = NULL;
-
-#endif /* !NO_DSA && USE_CERT_BUFFERS_2048 */
-
-    /*
-     *  test ECC public key print
-     */
-#if defined(HAVE_ECC) && defined(USE_CERT_BUFFERS_256)
-
-    rbio = BIO_new_mem_buf( ecc_clikeypub_der_256,
-                            sizeof_ecc_clikeypub_der_256);
-    AssertNotNull(rbio);
-
-    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
-    AssertNotNull(pkey);
-
-    wbio = BIO_new(BIO_s_mem());
-    AssertNotNull(wbio);
-
-    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,0,NULL),1);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "Public-Key: (256 bit)\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "pub:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1,
-            "    04:55:BF:F4:0F:44:50:9A:3D:CE:9B:B7:F0:C5:4D:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of pub element*/
-    for( i = 0; i < 4 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "ASN1 OID: prime256v1\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "NIST CURVE: P-256\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-
-    /* should reach EOF */
-    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
-
-    EVP_PKEY_free(pkey);
-    pkey = NULL;
-    BIO_free(rbio);
-    BIO_free(wbio);
-    rbio = NULL;
-    wbio = NULL;
-
-#endif /* HAVE_ECC && USE_CERT_BUFFERS_256 */
-
-    /*
-     *  test DH public key print
-     */
-#if defined(WOLFSSL_DH_EXTRA) && defined(USE_CERT_BUFFERS_2048)
-
-    rbio = BIO_new_mem_buf( dh_pub_key_der_2048,
-                            sizeof_dh_pub_key_der_2048);
-    AssertNotNull(rbio);
-
-    wolfSSL_d2i_PUBKEY_bio(rbio, &pkey);
-    AssertNotNull(pkey);
-
-    wbio = BIO_new(BIO_s_mem());
-    AssertNotNull(wbio);
-
-    AssertIntEQ(EVP_PKEY_print_public(wbio, pkey,0,NULL),1);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "DH Public-Key: (2048 bit)\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "public-key:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1,
-        "    34:41:BF:E9:F2:11:BF:05:DB:B2:72:A8:29:CC:BD:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of public-key element*/
-    for( i = 0; i < 17 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "prime:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1,
-        "    00:D3:B2:99:84:5C:0A:4C:E7:37:CC:FC:18:37:01:\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* skip to the end of prime element*/
-    for( i = 0; i < 17 ;i++) {
-        BIO_gets(wbio, line, sizeof(line));
-    }
-
-    BIO_gets(wbio, line, sizeof(line));
-    strcpy(line1, "generator: 2 (0x02)\n");
-    AssertIntEQ(XSTRNCMP( line, line1, XSTRLEN(line1)), 0);
-
-    /* should reach EOF */
-    AssertIntLE(BIO_gets(wbio, line, sizeof(line)) ,0);
-
-    EVP_PKEY_free(pkey);
-    pkey = NULL;
-    BIO_free(rbio);
-    BIO_free(wbio);
-    rbio = NULL;
-    wbio = NULL;
-
-#endif /* WOLFSSL_DH_EXTRA && USE_CERT_BUFFERS_2048 */
-
-    /* to prevent "unused variable" warning */
-    (void)pkey;
-    (void)wbio;
-    (void)rbio;
-    (void)line;
-    (void)line1;
-    (void)i;
-    printf(resultFmt, passed);
-#endif /* OPENSSL_EXTRA */
-}
 
 /* Test function for wolfSSL_EVP_get_cipherbynid.
  */
@@ -30361,6 +30361,364 @@ static void test_wolfSSL_CTX_add_client_CA(void)
     printf(resultFmt, passed);
 #endif /* OPENSSL_EXTRA  && !NO_RSA && !NO_CERTS && !NO_WOLFSSL_CLIENT */
 }
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+static THREAD_RETURN WOLFSSL_THREAD server_task(void* args)
+{
+    callback_functions* callbacks = ((func_args*)args)->callbacks;
+    WOLFSSL_CTX* ctx       = wolfSSL_CTX_new(callbacks->method());
+    WOLFSSL*  ssl   = NULL;
+    SOCKET_T  sfd   = 0;
+    SOCKET_T  cfd   = 0;
+    word16    port;
+    char      msg[] = "I hear you fa shizzle!";
+    int       len   = (int) XSTRLEN(msg);
+    char      input[1024];
+    int       idx;
+    int       ret, err = 0;
+
+#ifdef WOLFSSL_TIRTOS
+    fdOpenSession(Task_self());
+#endif
+    ((func_args*)args)->return_code = TEST_FAIL;
+    port = ((func_args*)args)->signal->port;
+
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_load_verify_locations(ctx, cliCertFile, 0));
+
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_use_certificate_file(ctx, svrCertFile,
+            WOLFSSL_FILETYPE_PEM));
+
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile,
+                 WOLFSSL_FILETYPE_PEM));
+
+    if (callbacks->ctx_ready)
+        callbacks->ctx_ready(ctx);
+
+    ssl = wolfSSL_new(ctx);
+    tcp_accept(&sfd, &cfd, (func_args*)args, port, 0, 0, 0, 0, 1, NULL, NULL);
+    CloseSocket(sfd);
+    AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_set_fd(ssl, cfd));
+
+    if (callbacks->ssl_ready)
+        callbacks->ssl_ready(ssl);
+
+    do {
+        err = 0; /* Reset error */
+        ret = wolfSSL_accept(ssl);
+        if (ret != WOLFSSL_SUCCESS) {
+            err = wolfSSL_get_error(ssl, 0);
+        }
+    } while (ret != WOLFSSL_SUCCESS && err == WC_PENDING_E);
+
+    if (ret != WOLFSSL_SUCCESS) {
+        char buff[WOLFSSL_MAX_ERROR_SZ];
+        printf("error = %d, %s\n", err, wolfSSL_ERR_error_string(err, buff));
+    }
+    else {
+        if (0 < (idx = wolfSSL_read(ssl, input, sizeof(input)-1))) {
+            input[idx] = 0;
+            printf("Client message: %s\n", input);
+        }
+
+        AssertIntEQ(len, wolfSSL_write(ssl, msg, len));
+#ifdef WOLFSSL_TIRTOS
+        Task_yield();
+#endif
+        ((func_args*)args)->return_code = TEST_SUCCESS;
+    }
+
+    if (callbacks->on_result)
+        callbacks->on_result(ssl);
+
+    wolfSSL_shutdown(ssl);
+    wolfSSL_free(ssl);
+    wolfSSL_CTX_free(ctx);
+    CloseSocket(cfd);
+
+#ifdef WOLFSSL_TIRTOS
+    fdCloseSession(Task_self());
+#endif
+#ifndef WOLFSSL_TIRTOS
+    return 0;
+#endif
+}
+
+static void keyLog_callback(const WOLFSSL* ssl, const char* line )
+{
+
+    AssertNotNull(ssl);
+    AssertNotNull(line);
+
+    XFILE fp;
+    const byte  lf = '\n';
+    fp = XFOPEN("./MyKeyLog.txt", "a");
+    XFWRITE( line, 1, strlen(line),fp);
+    XFWRITE( (void*)&lf,1,1,fp);
+    XFCLOSE(fp);
+
+}
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
+static void test_wolfSSL_CTX_set_keylog_callback(void)
+{
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+    SSL_CTX* ctx;
+
+    printf( testingFmt, "wolfSSL_CTX_set_keylog_callback()");
+    AssertNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
+    SSL_CTX_set_keylog_callback(ctx, keyLog_callback );
+    SSL_CTX_free(ctx);
+    SSL_CTX_set_keylog_callback(NULL, NULL);
+    printf(resultFmt, passed);
+
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
+}
+static void test_wolfSSL_CTX_get_keylog_callback(void)
+{
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+    SSL_CTX* ctx;
+
+    printf( testingFmt, "wolfSSL_CTX_get_keylog_callback()");
+    AssertNotNull(ctx = SSL_CTX_new(wolfSSLv23_client_method()));
+    AssertPtrEq(SSL_CTX_get_keylog_callback(ctx),NULL);
+    SSL_CTX_set_keylog_callback(ctx, keyLog_callback );
+    AssertPtrEq(SSL_CTX_get_keylog_callback(ctx),keyLog_callback);
+    SSL_CTX_set_keylog_callback(ctx, NULL );
+    AssertPtrEq(SSL_CTX_get_keylog_callback(ctx),NULL);
+    SSL_CTX_free(ctx);
+    printf(resultFmt, passed);
+
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
+}
+static void test_wolfSSL_Tls12_Key_Logging_test(void)
+{
+ #if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+ /* This test is intended for checking whether keylog callback is called
+  * in client during TLS handshake between the client and a server.
+  */
+
+    tcp_ready ready;
+    func_args client_args;
+    func_args server_args;
+    THREAD_TYPE serverThread;
+    callback_functions server_cbf;
+    callback_functions client_cbf;
+    SOCKET_T sockfd = 0;
+    WOLFSSL_CTX* ctx;
+    WOLFSSL*     ssl;
+    XFILE fp;
+    char msg[64] = "hello wolfssl!";
+    char reply[1024];
+    int  msgSz = (int)XSTRLEN(msg);
+
+    printf(testingFmt, "wolfSSL_Tls12_Key_Logging_test()");
+
+#ifdef WOLFSSL_TIRTOS
+    fdOpenSession(Task_self());
+#endif
+
+    InitTcpReady(&ready);
+    ready.port = 22222;
+
+    XMEMSET(&client_args, 0, sizeof(func_args));
+    XMEMSET(&server_args, 0, sizeof(func_args));
+    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
+    XMEMSET(&client_cbf, 0, sizeof(callback_functions));
+    server_cbf.method     = wolfTLSv1_2_server_method;
+
+    server_args.callbacks = &server_cbf;
+    server_args.signal    = &ready;
+
+    /* clean up keylog file */
+    fp = XFOPEN("./MyKeyLog.txt", "w");
+    XFCLOSE(fp);
+
+    /* start server task */
+    start_thread(server_task, &server_args, &serverThread);
+    wait_tcp_ready(&server_args);
+
+
+    /* run as a TLS1.2 client */
+    AssertNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method()));
+    AssertIntEQ(WOLFSSL_SUCCESS,
+            wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));
+
+    tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 0, 0, NULL);
+
+    /* set keylog callback */
+    wolfSSL_CTX_set_keylog_callback(ctx,keyLog_callback);
+
+    /* get connected the server task */
+    AssertNotNull(ssl = wolfSSL_new(ctx));
+    AssertIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
+
+
+    AssertIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
+
+    AssertIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz);
+    AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)), 0);
+    wolfSSL_shutdown(ssl);
+    wolfSSL_free(ssl);
+    wolfSSL_CTX_free(ctx);
+    CloseSocket(sockfd);
+    join_thread(serverThread);
+
+    FreeTcpReady(&ready);
+
+#ifdef WOLFSSL_TIRTOS
+    fdOpenSession(Task_self());
+#endif
+
+    /* check if the keylog file exists */
+
+    char  buff[300] = {0};
+    int  found = 0;
+
+    fp = XFOPEN("./MyKeyLog.txt", "r");
+
+    AssertNotNull(fp);
+
+    while(XFGETS( buff, (int)sizeof(buff),fp) != NULL ) {
+        if(0 == strncmp(buff,"CLIENT_RANDOM ",
+                    sizeof("CLIENT_RANDOM ")-1)) {
+            found = 1;
+            break;
+        }
+    }
+    XFCLOSE(fp);
+    /* a log starting with "CLIENT_RANDOM " should exit in the file */
+    AssertNotNull( found );
+    printf(resultFmt, passed);
+
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
+}
+static void test_wolfSSL_Tls13_Key_Logging_test(void)
+{
+ #if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+ /* This test is intended for checking whether keylog callback is called
+  * in client during TLS handshake between the client and a server.
+  */
+
+    tcp_ready ready;
+    func_args client_args;
+    func_args server_args;
+    THREAD_TYPE serverThread;
+    callback_functions server_cbf;
+    callback_functions client_cbf;
+    SOCKET_T sockfd = 0;
+    WOLFSSL_CTX* ctx;
+    WOLFSSL*     ssl;
+    XFILE fp;
+    char msg[64] = "hello wolfssl!";
+    char reply[1024];
+    int  msgSz = (int)XSTRLEN(msg);
+
+    printf(testingFmt, "wolfSSL_Tls13_Key_Logging_test()");
+
+#ifdef WOLFSSL_TIRTOS
+    fdOpenSession(Task_self());
+#endif
+
+    InitTcpReady(&ready);
+    ready.port = 22222;
+
+    XMEMSET(&client_args, 0, sizeof(func_args));
+    XMEMSET(&server_args, 0, sizeof(func_args));
+    XMEMSET(&server_cbf, 0, sizeof(callback_functions));
+    XMEMSET(&client_cbf, 0, sizeof(callback_functions));
+    server_cbf.method     = wolfTLSv1_3_server_method;  /* TLS1.3 */
+
+    server_args.callbacks = &server_cbf;
+    server_args.signal    = &ready;
+
+    /* clean up keylog file */
+    fp = XFOPEN("./MyKeyLog.txt", "w");
+    XFCLOSE(fp);
+
+    /* start server task */
+    start_thread(server_task, &server_args, &serverThread);
+    wait_tcp_ready(&server_args);
+
+
+    /* run as a TLS1.2 client */
+    AssertNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
+    AssertIntEQ(WOLFSSL_SUCCESS,
+            wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0));
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_use_certificate_file(ctx, cliCertFile, SSL_FILETYPE_PEM));
+    AssertIntEQ(WOLFSSL_SUCCESS,
+        wolfSSL_CTX_use_PrivateKey_file(ctx, cliKeyFile, SSL_FILETYPE_PEM));
+
+    tcp_connect(&sockfd, wolfSSLIP, server_args.signal->port, 0, 0, NULL);
+
+    /* set keylog callback */
+    wolfSSL_CTX_set_keylog_callback(ctx,keyLog_callback);
+
+    /* get connected the server task */
+    AssertNotNull(ssl = wolfSSL_new(ctx));
+    AssertIntEQ(wolfSSL_set_fd(ssl, sockfd), WOLFSSL_SUCCESS);
+    AssertIntEQ(wolfSSL_connect(ssl), WOLFSSL_SUCCESS);
+    AssertIntEQ(wolfSSL_write(ssl, msg, msgSz), msgSz);
+    AssertIntGT(wolfSSL_read(ssl, reply, sizeof(reply)), 0);
+    wolfSSL_free(ssl);
+    wolfSSL_CTX_free(ctx);
+
+    join_thread(serverThread);
+
+    FreeTcpReady(&ready);
+
+#ifdef WOLFSSL_TIRTOS
+    fdOpenSession(Task_self());
+#endif
+
+    /* check if the keylog file exists */
+
+    char  buff[300] = {0};
+    int  found[4]   = {0};
+
+    fp = XFOPEN("./MyKeyLog.txt", "r");
+
+    AssertNotNull(fp);
+
+    while(XFGETS( buff, (int)sizeof(buff),fp) != NULL ) {
+        if(0 == strncmp(buff,"CLIENT_HANDSHAKE_TRAFFIC_SECRET ",
+                    sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
+            found[0] = 1;
+            continue;
+        }
+        else if(0 == strncmp(buff,"SERVER_HANDSHAKE_TRAFFIC_SECRET ",
+                    sizeof("SERVER_HANDSHAKE_TRAFFIC_SECRET ")-1)) {
+            found[1] = 1;
+            continue;
+        }
+        else if(0 == strncmp(buff,"CLIENT_TRAFFIC_SECRET_0 ",
+                    sizeof("CLIENT_TRAFFIC_SECRET_0 ")-1)) {
+            found[2] = 1;
+            continue;
+        }
+        else if(0 == strncmp(buff,"SERVER_TRAFFIC_SECRET_0 ",
+                    sizeof("SERVER_TRAFFIC_SECRET_0 ")-1)) {
+            found[3] = 1;
+            continue;
+        }
+    }
+    XFCLOSE(fp);
+    int numfnd = 0;
+    for( uint i = 0; i < 4; i++) {
+        if( found[i] != 0)
+            numfnd++;
+    }
+    AssertIntEQ( numfnd,4 );
+
+    printf(resultFmt, passed);
+
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
+}
 
 static void test_wolfSSL_X509_NID(void)
 {
@@ -45173,6 +45531,7 @@ void ApiTest(void)
     test_wolfSSL_EVP_MD_hmac_signing();
     test_wolfSSL_EVP_MD_rsa_signing();
     test_wolfSSL_EVP_MD_ecc_signing();
+    test_wolfSSL_EVP_PKEY_print_public();
     test_wolfSSL_EVP_ENCODE_CTX_new();
     test_wolfSSL_EVP_ENCODE_CTX_free();
     test_wolfSSL_EVP_EncodeInit();
@@ -45181,7 +45540,6 @@ void ApiTest(void)
     test_wolfSSL_EVP_DecodeInit();
     test_wolfSSL_EVP_DecodeUpdate();
     test_wolfSSL_EVP_DecodeFinal();
-    test_wolfSSL_EVP_PKEY_print_public();
     test_wolfSSL_CTX_add_extra_chain_cert();
 #if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
     test_wolfSSL_ERR_peek_last_error_line();
@@ -45244,6 +45602,10 @@ void ApiTest(void)
     test_wolfSSL_CTX_add_client_CA();
     test_wolfSSL_CTX_set_srp_username();
     test_wolfSSL_CTX_set_srp_password();
+    test_wolfSSL_CTX_set_keylog_callback();
+    test_wolfSSL_CTX_get_keylog_callback();
+    test_wolfSSL_Tls12_Key_Logging_test();
+    test_wolfSSL_Tls13_Key_Logging_test();
     test_wolfSSL_CTX_set_ecdh_auto();
     test_wolfSSL_THREADID_hash();
     test_wolfSSL_RAND_set_rand_method();

+ 9 - 0
wolfssl/internal.h

@@ -3066,6 +3066,9 @@ struct WOLFSSL_CTX {
     Srp*  srp;  /* TLS Secure Remote Password Protocol*/
     byte* srp_password;
 #endif
+#if defined(OPENSSL_EXTRA) && defined(HAVE_SECRET_CALLBACK)
+    wolfSSL_CTX_keylog_cb_func keyLogCb;
+#endif /* OPENSSL_EXTRA && HAVE_SECRET_CALLBACK */
 #ifdef WOLFSSL_STATIC_EPHEMERAL
     StaticKeyExchangeInfo_t staticKE;
 #endif
@@ -4438,6 +4441,12 @@ struct WOLFSSL {
         Tls13SecretCb   tls13SecretCb;
         void*           tls13SecretCtx;
     #endif
+    #ifdef OPENSSL_EXTRA
+        SessionSecretCb keyLogCb;
+    #ifdef WOLFSSL_TLS13
+        Tls13SecretCb   tls13KeyLogCb;
+    #endif
+    #endif
 #endif /* HAVE_SECRET_CALLBACK */
 #ifdef WOLFSSL_JNI
         void* jObjectRef;     /* reference to WolfSSLSession in JNI wrapper */

+ 4 - 4
wolfssl/openssl/evp.h

@@ -377,6 +377,10 @@ struct WOLFSSL_EVP_PKEY_CTX {
     int nbits;
 };
 
+typedef
+struct WOLFSSL_ASN1_PCTX {
+    int dummy;
+} WOLFSSL_ASN1_PCTX;
 #if defined(WOLFSSL_BASE64_ENCODE) || defined(WOLFSSL_BASE64_DECODE)
 
 #define   BASE64_ENCODE_BLOCK_SIZE  48
@@ -409,10 +413,6 @@ WOLFSSL_API int  wolfSSL_EVP_DecodeUpdate(WOLFSSL_EVP_ENCODE_CTX* ctx,
 WOLFSSL_API int wolfSSL_EVP_DecodeFinal(WOLFSSL_EVP_ENCODE_CTX* ctx,
                 unsigned char*out, int *outl);
 #endif /* WOLFSSL_BASE64_DECODE */
-typedef
-struct WOLFSSL_ASN1_PCTX {
-    int dummy;
-} WOLFSSL_ASN1_PCTX;
 
 typedef int WOLFSSL_ENGINE  ;
 typedef WOLFSSL_ENGINE ENGINE;

+ 4 - 0
wolfssl/openssl/ssl.h

@@ -815,6 +815,10 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_
 #define SSL_CTX_set_info_callback       wolfSSL_CTX_set_info_callback
 #define SSL_CTX_set_alpn_protos         wolfSSL_CTX_set_alpn_protos
 
+#define SSL_CTX_keylog_cb_func          wolfSSL_CTX_keylog_cb_func
+#define SSL_CTX_set_keylog_callback     wolfSSL_CTX_set_keylog_callback
+#define SSL_CTX_get_keylog_callback     wolfSSL_CTX_get_keylog_callback
+
 #define SSL_alert_type_string           wolfSSL_alert_type_string
 #define SSL_alert_desc_string           wolfSSL_alert_desc_string
 #define SSL_state_string                wolfSSL_state_string

+ 9 - 0
wolfssl/ssl.h

@@ -4165,6 +4165,15 @@ WOLFSSL_API int wolfSSL_CTX_AsyncPoll(WOLFSSL_CTX* ctx, WOLF_EVENT** events, int
 typedef void (*SSL_Msg_Cb)(int write_p, int version, int content_type,
     const void *buf, size_t len, WOLFSSL *ssl, void *arg);
 
+#if defined(HAVE_SECRET_CALLBACK)
+typedef void (*wolfSSL_CTX_keylog_cb_func)
+            (const WOLFSSL* ssl, const char* line);
+WOLFSSL_API void wolfSSL_CTX_set_keylog_callback(WOLFSSL_CTX* ctx,
+    wolfSSL_CTX_keylog_cb_func cb);
+WOLFSSL_API wolfSSL_CTX_keylog_cb_func wolfSSL_CTX_get_keylog_callback(
+    const WOLFSSL_CTX* ctx);
+#endif /* HAVE_SECRET_CALLBACK */
+
 WOLFSSL_API int wolfSSL_CTX_set_msg_callback(WOLFSSL_CTX *ctx, SSL_Msg_Cb cb);
 WOLFSSL_API int wolfSSL_set_msg_callback(WOLFSSL *ssl, SSL_Msg_Cb cb);
 WOLFSSL_API int wolfSSL_CTX_set_msg_callback_arg(WOLFSSL_CTX *ctx, void* arg);