[openssl-commits] [openssl] master update

Richard Levitte levitte at openssl.org
Mon Jan 23 16:09:10 UTC 2017


The branch master has been updated
       via  2f5f49d146a0baef81c7562be29a6a71f894f336 (commit)
       via  6acdd3e531e52173a0c76490c0aae3ecebe04a89 (commit)
       via  2faa1b48fd6864f6bb8f992fd638378202fdd416 (commit)
      from  ea24bb0ac5afee1cb7807752a674cb8a858545db (commit)


- Log -----------------------------------------------------------------
commit 2f5f49d146a0baef81c7562be29a6a71f894f336
Author: Cory Benfield <lukasaoz at gmail.com>
Date:   Fri Jan 20 16:22:49 2017 +0000

    Add documentation for the key logging callbacks
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/1646)

commit 6acdd3e531e52173a0c76490c0aae3ecebe04a89
Author: Cory Benfield <lukasaoz at gmail.com>
Date:   Fri Jan 20 16:22:39 2017 +0000

    Add tests for the key logging callbacks.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/1646)

commit 2faa1b48fd6864f6bb8f992fd638378202fdd416
Author: Cory Benfield <lukasaoz at gmail.com>
Date:   Fri Jan 20 16:22:30 2017 +0000

    Add support for key logging callbacks.
    
    Reviewed-by: Rich Salz <rsalz at openssl.org>
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/1646)

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

Summary of changes:
 doc/man3/SSL_CTX_set_keylog_callback.pod |  48 +++++
 include/openssl/ssl.h                    |  22 ++
 ssl/ssl_err.c                            |   6 +-
 ssl/ssl_lib.c                            | 111 ++++++++++
 ssl/ssl_locl.h                           |  26 +++
 ssl/statem/statem_clnt.c                 |   6 +-
 ssl/statem/statem_lib.c                  |   6 +
 test/sslapitest.c                        | 342 +++++++++++++++++++++++++++++++
 util/libssl.num                          |   2 +
 9 files changed, 567 insertions(+), 2 deletions(-)
 create mode 100644 doc/man3/SSL_CTX_set_keylog_callback.pod

diff --git a/doc/man3/SSL_CTX_set_keylog_callback.pod b/doc/man3/SSL_CTX_set_keylog_callback.pod
new file mode 100644
index 0000000..abe45ae
--- /dev/null
+++ b/doc/man3/SSL_CTX_set_keylog_callback.pod
@@ -0,0 +1,48 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_keylog_callback, SSL_CTX_get_keylog_callback,
+SSL_CTX_keylog_cb_func - logging TLS key material
+
+=head1 SYNOPSIS
+
+ #include <openssl/ssl.h>
+
+ typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
+
+ void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb);
+ SSL_CTX_keylog_cb_func SSL_CTX_get_keylog_callback(const SSL_CTX *ctx);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_keylog_callback() sets the TLS key logging callback. This callback
+is called whenever TLS key material is generated or received, in order to allow
+applications to store this keying material for debugging purposes.
+
+SSL_CTX_get_keylog_callback() retrieves the previously set TLS key logging
+callback. If no callback has been set, this will return NULL. When there is no
+key logging callback, or if SSL_CTX_set_keylog_callback is called with NULL as
+the value of cb, no logging of key material will be done.
+
+The key logging callback is called with two items: the B<ssl> object associated
+with the connection, and B<line>, a string containing the key material in the
+format used by NSS for its B<SSLKEYLOGFILE> debugging output. To recreate that
+file, the key logging callback should log B<line>, followed by a newline.
+B<line> will always be a NULL-terminated string.
+
+
+=head1 SEE ALSO
+
+L<ssl(3)>
+
+=head1 COPYRIGHT
+
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (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/ssl.h b/include/openssl/ssl.h
index 2f6d59a..86ffcb9 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -775,6 +775,25 @@ __owur int SSL_extension_supported(unsigned int ext_type);
 # define SSL_MAC_FLAG_READ_MAC_STREAM 1
 # define SSL_MAC_FLAG_WRITE_MAC_STREAM 2
 
+/*
+ * A callback for logging out TLS key material. This callback should log out
+ * |line| followed by a newline.
+ */
+typedef void (*SSL_CTX_keylog_cb_func)(const SSL *ssl, const char *line);
+
+/*
+ * SSL_CTX_set_keylog_callback configures a callback to log key material. This
+ * is intended for debugging use with tools like Wireshark. The cb function
+ * should log line followed by a newline.
+ */
+void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb);
+
+/*
+ * SSL_CTX_get_keylog_callback returns the callback configured by
+ * SSL_CTX_set_keylog_callback.
+ */
+SSL_CTX_keylog_cb_func SSL_CTX_get_keylog_callback(const SSL_CTX *ctx);
+
 #ifdef __cplusplus
 }
 #endif
@@ -2079,6 +2098,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_FINAL_EMS                                  486
 # define SSL_F_FINAL_RENEGOTIATE                          483
 # define SSL_F_FINAL_SIG_ALGS                             497
+# define SSL_F_NSS_KEYLOG_INT                             500
 # define SSL_F_OPENSSL_INIT_SSL                           342
 # define SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION       436
 # define SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE       430
@@ -2170,6 +2190,8 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_GET_SIGN_PKEY                          183
 # define SSL_F_SSL_INIT_WBIO_BUFFER                       184
 # define SSL_F_SSL_LOAD_CLIENT_CA_FILE                    185
+# define SSL_F_SSL_LOG_MASTER_SECRET                      498
+# define SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE            499
 # define SSL_F_SSL_MODULE_INIT                            392
 # define SSL_F_SSL_NEW                                    186
 # define SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT      300
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index 79cbf2e..d380c86 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -53,6 +53,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_FINAL_EMS), "final_ems"},
     {ERR_FUNC(SSL_F_FINAL_RENEGOTIATE), "final_renegotiate"},
     {ERR_FUNC(SSL_F_FINAL_SIG_ALGS), "final_sig_algs"},
+    {ERR_FUNC(SSL_F_NSS_KEYLOG_INT), "nss_keylog_int"},
     {ERR_FUNC(SSL_F_OPENSSL_INIT_SSL), "OPENSSL_init_ssl"},
     {ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION),
      "ossl_statem_client13_read_transition"},
@@ -177,6 +178,9 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_SSL_GET_SIGN_PKEY), "ssl_get_sign_pkey"},
     {ERR_FUNC(SSL_F_SSL_INIT_WBIO_BUFFER), "ssl_init_wbio_buffer"},
     {ERR_FUNC(SSL_F_SSL_LOAD_CLIENT_CA_FILE), "SSL_load_client_CA_file"},
+    {ERR_FUNC(SSL_F_SSL_LOG_MASTER_SECRET), "ssl_log_master_secret"},
+    {ERR_FUNC(SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE),
+     "ssl_log_rsa_client_key_exchange"},
     {ERR_FUNC(SSL_F_SSL_MODULE_INIT), "ssl_module_init"},
     {ERR_FUNC(SSL_F_SSL_NEW), "SSL_new"},
     {ERR_FUNC(SSL_F_SSL_PARSE_CLIENTHELLO_RENEGOTIATE_EXT),
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 21ea284..fe17f3d 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -4344,3 +4344,114 @@ const CTLOG_STORE *SSL_CTX_get0_ctlog_store(const SSL_CTX *ctx)
 }
 
 #endif
+
+void SSL_CTX_set_keylog_callback(SSL_CTX *ctx, SSL_CTX_keylog_cb_func cb)
+{
+    ctx->keylog_callback = cb;
+}
+
+SSL_CTX_keylog_cb_func SSL_CTX_get_keylog_callback(const SSL_CTX *ctx)
+{
+    return ctx->keylog_callback;
+}
+
+static int nss_keylog_int(const char *prefix,
+                          SSL *ssl,
+                          const uint8_t *parameter_1,
+                          size_t parameter_1_len,
+                          const uint8_t *parameter_2,
+                          size_t parameter_2_len)
+{
+    char *out = NULL;
+    char *cursor = NULL;
+    size_t out_len = 0;
+    size_t i;
+    size_t prefix_len;
+
+    if (ssl->ctx->keylog_callback == NULL) return 1;
+
+    /*
+     * Our output buffer will contain the following strings, rendered with
+     * space characters in between, terminated by a NULL character: first the
+     * prefix, then the first parameter, then the second parameter. The
+     * meaning of each parameter depends on the specific key material being
+     * logged. Note that the first and second parameters are encoded in
+     * hexadecimal, so we need a buffer that is twice their lengths.
+     */
+    prefix_len = strlen(prefix);
+    out_len = prefix_len + (2*parameter_1_len) + (2*parameter_2_len) + 3;
+    if ((out = cursor = OPENSSL_malloc(out_len)) == NULL) {
+        SSLerr(SSL_F_NSS_KEYLOG_INT, ERR_R_MALLOC_FAILURE);
+        return 0;
+    }
+
+    strcpy(cursor, prefix);
+    cursor += prefix_len;
+    *cursor++ = ' ';
+
+    for (i = 0; i < parameter_1_len; i++) {
+        sprintf(cursor, "%02x", parameter_1[i]);
+        cursor += 2;
+    }
+    *cursor++ = ' ';
+
+    for (i = 0; i < parameter_2_len; i++) {
+        sprintf(cursor, "%02x", parameter_2[i]);
+        cursor += 2;
+    }
+    *cursor = '\0';
+
+    ssl->ctx->keylog_callback(ssl, (const char *)out);
+    OPENSSL_free(out);
+    return 1;
+
+}
+
+int ssl_log_rsa_client_key_exchange(SSL *ssl,
+                                    const uint8_t *encrypted_premaster,
+                                    size_t encrypted_premaster_len,
+                                    const uint8_t *premaster,
+                                    size_t premaster_len)
+{
+    if (encrypted_premaster_len < 8) {
+        SSLerr(SSL_F_SSL_LOG_RSA_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return nss_keylog_int("RSA",
+                          ssl,
+                          encrypted_premaster,
+                          encrypted_premaster_len,
+                          premaster,
+                          premaster_len);
+}
+
+int ssl_log_master_secret(SSL *ssl,
+                          const uint8_t *client_random,
+                          size_t client_random_len,
+                          const uint8_t *master,
+                          size_t master_len)
+{
+    /*
+     * TLSv1.3 changes the derivation of the master secret compared to earlier
+     * TLS versions, meaning that logging it out is less useful. Instead we
+     * want to log out other secrets: specifically, the handshake and
+     * application traffic secrets. For this reason, if this function is called
+     * for TLSv1.3 we don't bother logging, and just return success
+     * immediately.
+     */
+    if (SSL_IS_TLS13(ssl)) return 1;
+
+    if (client_random_len != 32) {
+        SSLerr(SSL_F_SSL_LOG_MASTER_SECRET, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return nss_keylog_int("CLIENT_RANDOM",
+                          ssl,
+                          client_random,
+                          client_random_len,
+                          master,
+                          master_len);
+}
+
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 10ae54c..27bfd9e 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -875,6 +875,12 @@ struct ssl_ctx_st {
     int (*not_resumable_session_cb) (SSL *ssl, int is_forward_secure);
 
     CRYPTO_RWLOCK *lock;
+
+    /*
+     * Callback for logging key material for use with debugging tools like
+     * Wireshark. The callback should log `line` followed by a newline.
+     */
+    SSL_CTX_keylog_cb_func keylog_callback;
 };
 
 struct ssl_st {
@@ -2194,6 +2200,26 @@ __owur const EVP_MD *ssl_md(int idx);
 __owur const EVP_MD *ssl_handshake_md(SSL *s);
 __owur const EVP_MD *ssl_prf_md(SSL *s);
 
+/*
+ * ssl_log_rsa_client_key_exchange logs |premaster| to the SSL_CTX associated
+ * with |ssl|, if logging is enabled. It returns one on success and zero on
+ * failure. The entry is identified by the first 8 bytes of
+ * |encrypted_premaster|.
+ */
+__owur int ssl_log_rsa_client_key_exchange(SSL *ssl,
+                                           const uint8_t *encrypted_premaster,
+                                           size_t encrypted_premaster_len,
+                                           const uint8_t *premaster,
+                                           size_t premaster_len);
+
+/* ssl_log_master_secret logs |master| to the SSL_CTX associated with |ssl|, if
+ * logging is enabled. It returns one on success and zero on failure. The entry
+ * is identified by |client_random|.
+ */
+__owur int ssl_log_master_secret(SSL *ssl, const uint8_t *client_random,
+                                 size_t client_random_len,
+                                 const uint8_t *master, size_t master_len);
+
 /* s3_cbc.c */
 __owur char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx);
 __owur int ssl3_cbc_digest_record(const EVP_MD_CTX *ctx,
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 5eec0d1..80ae480 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -2258,7 +2258,7 @@ int tls_process_cert_status_body(SSL *s, PACKET *pkt, int *al)
 
     return 1;
 }
-    
+
 
 MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
 {
@@ -2522,6 +2522,10 @@ static int tls_construct_cke_rsa(SSL *s, WPACKET *pkt, int *al)
     s->s3->tmp.pms = pms;
     s->s3->tmp.pmslen = pmslen;
 
+    /* Log the premaster secret, if logging is enabled. */
+    if (!ssl_log_rsa_client_key_exchange(s, encdata, enclen, pms, pmslen))
+        goto err;
+
     return 1;
  err:
     OPENSSL_clear_free(pms, pmslen);
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 03efdec..905a2cc 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -427,6 +427,12 @@ int tls_construct_finished(SSL *s, WPACKET *pkt)
         goto err;
     }
 
+    /* Log the master secret, if logging is enabled. */
+    if (!ssl_log_master_secret(s, s->s3->client_random, SSL3_RANDOM_SIZE,
+                               s->session->master_key,
+                               s->session->master_key_length))
+        return 0;
+
     /*
      * Copy the finished so we can use it for renegotiation checks
      */
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 4a84f4d..ac065b2 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -23,6 +23,13 @@
 static char *cert = NULL;
 static char *privkey = NULL;
 
+#define LOG_BUFFER_SIZE 1024
+static char server_log_buffer[LOG_BUFFER_SIZE + 1] = {0};
+static int server_log_buffer_index = 0;
+static char client_log_buffer[LOG_BUFFER_SIZE + 1] = {0};
+static int client_log_buffer_index = 0;
+static int error_writing_log = 0;
+
 #ifndef OPENSSL_NO_OCSP
 static const unsigned char orespder[] = "Dummy OCSP Response";
 static int ocsp_server_called = 0;
@@ -34,6 +41,337 @@ static X509 *ocspcert = NULL;
 
 #define NUM_EXTRA_CERTS 40
 
+static void client_keylog_callback(const SSL *ssl, const char *line) {
+    int line_length = strlen(line);
+
+    /* If the log doesn't fit, error out. */
+    if ((client_log_buffer_index + line_length) > LOG_BUFFER_SIZE) {
+        printf("No room in client log\n");
+        error_writing_log = 1;
+        return;
+    }
+
+    strcat(client_log_buffer, line);
+    client_log_buffer_index += line_length;
+    client_log_buffer[client_log_buffer_index] = '\n';
+    client_log_buffer_index += 1;
+
+    return;
+}
+
+static void server_keylog_callback(const SSL *ssl, const char *line) {
+    int line_length = strlen(line);
+
+    /* If the log doesn't fit, error out. */
+    if ((server_log_buffer_index + line_length) > LOG_BUFFER_SIZE) {
+        printf("No room in server log\n");
+        error_writing_log = 1;
+        return;
+    }
+
+    strcat(server_log_buffer, line);
+    server_log_buffer_index += line_length;
+    server_log_buffer[server_log_buffer_index] = '\n';
+    server_log_buffer_index += 1;
+
+    return;
+}
+
+static int compare_hex_encoded_buffer(const char *hex_encoded,
+                                      size_t hex_length,
+                                      const uint8_t *raw,
+                                      size_t raw_length) {
+    size_t i;
+    size_t j;
+
+    /* One byte too big, just to be safe. */
+    char hexed[3] = {0};
+
+    if ((raw_length * 2) != hex_length) {
+        printf("Inconsistent hex encoded lengths.\n");
+        return 1;
+    }
+
+    for (i = j = 0; (i < raw_length) && ((j + 1) < hex_length); i++) {
+        sprintf(hexed, "%02x", raw[i]);
+        if ((hexed[0] != hex_encoded[j]) || (hexed[1] != hex_encoded[j + 1])) {
+            printf("Hex output does not match.\n");
+            return 1;
+        }
+        j += 2;
+    }
+
+    return 0;
+}
+
+static int test_keylog_output(char *buffer, const SSL *ssl,
+                              const SSL_SESSION *session) {
+    int saw_client_random = 0;
+    char *token = NULL;
+    unsigned char actual_client_random[SSL3_RANDOM_SIZE] = {0};
+    size_t client_random_size = SSL3_RANDOM_SIZE;
+    unsigned char actual_master_key[SSL_MAX_MASTER_KEY_LENGTH] = {0};
+    size_t master_key_size = SSL_MAX_MASTER_KEY_LENGTH;
+
+    token = strtok(buffer, " \n");
+    while (token) {
+        if (strcmp(token, "RSA") == 0) {
+            /* Premaster secret. Tokens should be: 16 ASCII bytes of
+             * hex-encoded encrypted secret, then the hex-encoded pre-master
+             * secret.
+             */
+            token = strtok(NULL, " \n");
+            if (!token) {
+                printf("Unexpectedly short premaster secret log.\n");
+                return -1;
+            }
+            if (strlen(token) != 16) {
+                printf("Bad value for encrypted secret: %s\n", token);
+                return -1;
+            }
+            token = strtok(NULL, " \n");
+            if (!token) {
+                printf("Unexpectedly short premaster secret log.\n");
+                return -1;
+            }
+            /* TODO: Can I check this sensibly? */
+        } else if (strcmp(token, "CLIENT_RANDOM") == 0) {
+            /* Master secret. Tokens should be: 64 ASCII bytes of hex-encoded
+             * client random, then the hex-encoded master secret.
+             */
+            client_random_size = SSL_get_client_random(ssl,
+                                                       actual_client_random,
+                                                       SSL3_RANDOM_SIZE);
+            if (client_random_size != SSL3_RANDOM_SIZE) {
+                printf("Unexpected short client random.\n");
+                return -1;
+            }
+
+            token = strtok(NULL, " \n");
+            if (!token) {
+                printf("Unexpected short master secret log.\n");
+                return -1;
+            }
+            if (strlen(token) != 64) {
+                printf("Bad value for client random: %s\n", token);
+                return -1;
+            }
+            if (compare_hex_encoded_buffer(token, 64, actual_client_random,
+                                           client_random_size)) {
+                printf("Bad value for client random: %s\n", token);
+                return -1;
+            }
+
+            token = strtok(NULL, " \n");
+            if (!token) {
+                printf("Unexpectedly short master secret log.\n");
+                return -1;
+            }
+
+            master_key_size = SSL_SESSION_get_master_key(session,
+                                                         actual_master_key,
+                                                         master_key_size);
+            if (!master_key_size) {
+                printf("Error getting master key to compare.\n");
+                return -1;
+            }
+            if (compare_hex_encoded_buffer(token, strlen(token),
+                                           actual_master_key,
+                                           master_key_size)) {
+                printf("Bad value for master key: %s\n", token);
+                return -1;
+            }
+
+            saw_client_random = 1;
+        } else {
+            printf("Unexpected token in buffer: %s\n", token);
+            return -1;
+        }
+
+        token = strtok(NULL, " \n");
+    }
+
+    return saw_client_random;
+}
+
+static int test_keylog(void) {
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    int testresult = 0;
+
+    /* Clean up logging space */
+    memset(client_log_buffer, 0, LOG_BUFFER_SIZE + 1);
+    memset(server_log_buffer, 0, LOG_BUFFER_SIZE + 1);
+    client_log_buffer_index = 0;
+    server_log_buffer_index = 0;
+    error_writing_log = 0;
+
+    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
+                             &cctx, cert, privkey)) {
+        printf("Unable to create SSL_CTX pair\n");
+        return 0;
+    }
+
+    /* We cannot log the master secret for TLSv1.3, so we should forbid it. */
+    SSL_CTX_set_options(cctx, SSL_OP_NO_TLSv1_3);
+    SSL_CTX_set_options(sctx, SSL_OP_NO_TLSv1_3);
+
+    if (SSL_CTX_get_keylog_callback(cctx)) {
+        printf("Unexpected initial value for client "
+               "SSL_CTX_get_keylog_callback()\n");
+        goto end;
+    }
+    if (SSL_CTX_get_keylog_callback(sctx)) {
+        printf("Unexpected initial value for server "
+               "SSL_CTX_get_keylog_callback()\n");
+        goto end;
+    }
+
+    SSL_CTX_set_keylog_callback(cctx, client_keylog_callback);
+    SSL_CTX_set_keylog_callback(sctx, server_keylog_callback);
+
+    if (SSL_CTX_get_keylog_callback(cctx) != client_keylog_callback) {
+        printf("Unexpected set value for client "
+               "SSL_CTX_get_keylog_callback()\n");
+    }
+
+    if (SSL_CTX_get_keylog_callback(sctx) != server_keylog_callback) {
+        printf("Unexpected set value for server "
+               "SSL_CTX_get_keylog_callback()\n");
+    }
+
+    /* Now do a handshake and check that the logs have been written to. */
+    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    if (!create_ssl_connection(serverssl, clientssl)) {
+        printf("Unable to create SSL connection\n");
+        goto end;
+    }
+
+    if (error_writing_log) {
+        printf("Error encountered while logging\n");
+        goto end;
+    }
+
+    if ((client_log_buffer_index == 0) || (server_log_buffer_index == 0)) {
+        printf("No logs written\n");
+        goto end;
+    }
+
+    /* Now we want to test that our output data was vaguely sensible. We
+     * do that by using strtok and confirming that we have more or less the
+     * data we expect.
+     */
+    if (test_keylog_output(client_log_buffer, clientssl,
+                           SSL_get_session(clientssl)) != 1) {
+        printf("Error encountered in client log buffer\n");
+        goto end;
+    }
+    if (test_keylog_output(server_log_buffer, serverssl,
+                           SSL_get_session(serverssl)) != 1) {
+        printf("Error encountered in server log buffer\n");
+        goto end;
+    }
+
+    testresult = 1;
+
+end:
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+
+#ifndef OPENSSL_NO_TLS1_3
+static int test_keylog_no_master_key(void) {
+    SSL_CTX *cctx = NULL, *sctx = NULL;
+    SSL *clientssl = NULL, *serverssl = NULL;
+    int testresult = 0;
+
+    /* Clean up logging space */
+    memset(client_log_buffer, 0, LOG_BUFFER_SIZE + 1);
+    memset(server_log_buffer, 0, LOG_BUFFER_SIZE + 1);
+    client_log_buffer_index = 0;
+    server_log_buffer_index = 0;
+    error_writing_log = 0;
+
+    if (!create_ssl_ctx_pair(TLS_server_method(), TLS_client_method(), &sctx,
+                             &cctx, cert, privkey)) {
+        printf("Unable to create SSL_CTX pair\n");
+        return 0;
+    }
+
+    if (SSL_CTX_get_keylog_callback(cctx)) {
+        printf("Unexpected initial value for client "
+               "SSL_CTX_get_keylog_callback()\n");
+        goto end;
+    }
+    if (SSL_CTX_get_keylog_callback(sctx)) {
+        printf("Unexpected initial value for server "
+               "SSL_CTX_get_keylog_callback()\n");
+        goto end;
+    }
+
+    SSL_CTX_set_keylog_callback(cctx, client_keylog_callback);
+    SSL_CTX_set_keylog_callback(sctx, server_keylog_callback);
+
+    if (SSL_CTX_get_keylog_callback(cctx) != client_keylog_callback) {
+        printf("Unexpected set value for client "
+               "SSL_CTX_get_keylog_callback()\n");
+    }
+
+    if (SSL_CTX_get_keylog_callback(sctx) != server_keylog_callback) {
+        printf("Unexpected set value for server "
+               "SSL_CTX_get_keylog_callback()\n");
+    }
+
+    /* Now do a handshake and check that the logs have been written to. */
+    if (!create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, NULL)) {
+        printf("Unable to create SSL objects\n");
+        goto end;
+    }
+
+    if (!create_ssl_connection(serverssl, clientssl)) {
+        printf("Unable to create SSL connection\n");
+        goto end;
+    }
+
+    if (error_writing_log) {
+        printf("Error encountered while logging\n");
+        goto end;
+    }
+
+    /* Now we want to test that our output data was vaguely sensible. For this
+     * test, we expect no CLIENT_RANDOM entry.
+     */
+    if (test_keylog_output(client_log_buffer, clientssl,
+                           SSL_get_session(clientssl)) != 0) {
+        printf("Error encountered in client log buffer\n");
+        goto end;
+    }
+    if (test_keylog_output(server_log_buffer, serverssl,
+                           SSL_get_session(serverssl)) != 0) {
+        printf("Error encountered in server log buffer\n");
+        goto end;
+    }
+
+    testresult = 1;
+
+end:
+    SSL_free(serverssl);
+    SSL_free(clientssl);
+    SSL_CTX_free(sctx);
+    SSL_CTX_free(cctx);
+
+    return testresult;
+}
+#endif
+
 static int execute_test_large_message(const SSL_METHOD *smeth,
                                       const SSL_METHOD *cmeth, int read_ahead)
 {
@@ -1044,6 +1382,10 @@ int test_main(int argc, char *argv[])
     ADD_TEST(test_ssl_bio_change_rbio);
     ADD_TEST(test_ssl_bio_change_wbio);
     ADD_ALL_TESTS(test_set_sigalgs, OSSL_NELEM(testsigalgs) * 2);
+    ADD_TEST(test_keylog);
+#ifndef OPENSSL_NO_TLS1_3
+    ADD_TEST(test_keylog_no_master_key);
+#endif
 
     testresult = run_tests(argv[0]);
 
diff --git a/util/libssl.num b/util/libssl.num
index 730cff1..94def68 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -410,3 +410,5 @@ SSL_peek_ex                             410	1_1_1	EXIST::FUNCTION:
 SSL_write_ex                            411	1_1_1	EXIST::FUNCTION:
 SSL_COMP_get_id                         412	1_1_0d	EXIST::FUNCTION:
 SSL_COMP_get0_name                      413	1_1_0d	EXIST::FUNCTION:
+SSL_CTX_set_keylog_callback             414	1_1_1	EXIST::FUNCTION:
+SSL_CTX_get_keylog_callback             415	1_1_1	EXIST::FUNCTION:


More information about the openssl-commits mailing list