]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
add SSLKEYLOGFILE capability
authorAlan T. DeKok <aland@freeradius.org>
Mon, 29 Nov 2021 13:39:32 +0000 (08:39 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 29 Nov 2021 13:39:32 +0000 (08:39 -0500)
and add "keylog_file" to the TLS configuration, so that we can
distinguish SSL keys for EAP versus incoming / outgoing RadSec

src/lib/tls/conf-h
src/lib/tls/conf.c
src/lib/tls/ctx.c
src/lib/tls/session.c
src/lib/tls/session.h

index f52a32b6540e1cab8f2e4daf5ef62d54dbcdf55b..43d1073bf5c9c6cd8c1c6bb25a75a8bc44cf50fe 100644 (file)
@@ -170,6 +170,8 @@ struct fr_tls_conf_s {
        char const              *psk_query;
 #endif
 
+       char const              *keylog_file;           //!< for SSLKEYLOGFILE functionality.
+
        fr_tls_cache_conf_t     cache;                  //!< Session cache configuration.
        fr_tls_verify_conf_t    verify;
 };
index 65f8643d32118045690c72de861b2a1c12493d16..2fda62cc90b7d9487a437557353b23d6cb69fd39 100644 (file)
@@ -170,6 +170,8 @@ CONF_PARSER fr_tls_server_config[] = {
        { FR_CONF_OFFSET("psk_hexphrase", FR_TYPE_STRING | FR_TYPE_SECRET, fr_tls_conf_t, psk_password) },
        { FR_CONF_OFFSET("psk_query", FR_TYPE_STRING, fr_tls_conf_t, psk_query) },
 #endif
+       { FR_CONF_OFFSET("keylog_file", FR_TYPE_STRING, fr_tls_conf_t, keylog_file) },
+
        { FR_CONF_OFFSET("dh_file", FR_TYPE_FILE_INPUT, fr_tls_conf_t, dh_file) },
        { FR_CONF_OFFSET("fragment_size", FR_TYPE_UINT32, fr_tls_conf_t, fragment_size), .dflt = "1024" },
        { FR_CONF_OFFSET("padding", FR_TYPE_UINT32, fr_tls_conf_t, padding_block_size), },
@@ -208,6 +210,8 @@ CONF_PARSER fr_tls_client_config[] = {
        { FR_CONF_DEPRECATED("private_key_password", FR_TYPE_STRING | FR_TYPE_SECRET, fr_tls_conf_t, NULL) },
        { FR_CONF_DEPRECATED("private_key_file", FR_TYPE_FILE_INPUT, fr_tls_conf_t, NULL) },
 
+       { FR_CONF_OFFSET("keylog_file", FR_TYPE_STRING, fr_tls_conf_t, keylog_file) },
+
        { FR_CONF_OFFSET("verify_depth", FR_TYPE_UINT32, fr_tls_conf_t, verify_depth), .dflt = "0" },
        { FR_CONF_OFFSET("ca_path", FR_TYPE_FILE_INPUT, fr_tls_conf_t, ca_path) },
 
index e433ab60e6a47587ebe21292d9d677016241a185..6a8a1688442645432a6a4b66f20d13c1693df848 100644 (file)
@@ -1028,6 +1028,15 @@ post_ca:
         */
        if (fr_tls_cache_ctx_init(ctx, &conf->cache) < 0) goto error;
 
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+       /*
+        *      Set the keylog file if the admin requested it.
+        */
+       if ((getenv("SSLKEYLOGFILE") != NULL) || (conf->keylog_file && *conf->keylog_file)) {
+               SSL_CTX_set_keylog_callback(ctx, fr_tls_session_keylog_cb);
+       }
+#endif
+
        return ctx;
 }
 #endif
index 0776c3240aba03bf0a4561f56ad580f25c9d3f79..9fe64a5c7db6fa08e076add90506181ed4a8a4a8 100644 (file)
@@ -42,6 +42,7 @@
 
 #include <openssl/ssl.h>
 #include <ctype.h>
+#include <fcntl.h>
 
 #include "attrs.h"
 #include "base.h"
@@ -841,6 +842,82 @@ void fr_tls_session_msg_cb(int write_p, int msg_version, int content_type,
 #endif
 }
 
+#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER)
+/*
+ *  By setting the environment variable SSLKEYLOGFILE to a filename keying
+ *  material will be exported that you may use with Wireshark to decode any
+ *  TLS flows. Please see the following for more details:
+ *
+ *     https://gitlab.com/wireshark/wireshark/-/wikis/TLS#tls-decryption
+ *
+ *  An example logging session is (you should delete the file on each run):
+ *
+ *     rm -f /tmp/sslkey.log; env SSLKEYLOGFILE=/tmp/sslkey.log freeradius -X | tee /tmp/debug
+ *
+ *  Note that we rely on the OS to check file permissions.  If the
+ *  caller can run radiusd, then they can only write to files which
+ *  they own.  If radiusd is running as root, then only root can
+ *  change the environment variables for radiusd.
+ *
+ *  Note also that we don't try anything fancy, like xlat expansions.
+ *  Those could block, and the OpenSSL API doesn't support async key
+ *  log callbacks.  Instead,
+ */
+void fr_tls_session_keylog_cb(const SSL *ssl, const char *line)
+{
+       int fd;
+       size_t len;
+       const char *filename;
+       char buffer[64 + 2*SSL3_RANDOM_SIZE + 2*SSL_MAX_MASTER_KEY_LENGTH];
+
+       /*
+        *      Just a double-check.
+        */
+       filename = getenv("SSLKEYLOGFILE");
+       if (!filename) {
+               fr_tls_conf_t *conf;
+
+               conf = (fr_tls_conf_t *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_CONF);
+               if (!conf || !conf->keylog_file || !*conf->keylog_file) return;
+
+               filename = conf->keylog_file;
+       }
+
+       /*
+        *      We write all of the data at once.  This is *generally*
+        *      atomic on most systems.
+        */
+       len = strlen(line);
+       if ((len + 1) > sizeof(buffer)) {
+               DEBUG("SSLKEYLOGFILE buffer not large enough, max %lu, required %lu", sizeof(buffer), len + 1);
+               return;
+       }
+
+       /*
+        *      Add a \n, which means that in order to write() the
+        *      buffer AND the trailing \n, we have to place both
+        *      strings into the same buffer.
+        */
+       memcpy(buffer, line, len);
+       buffer[len] = '\n';
+
+       fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+       if (fd < 0) {
+               DEBUG("Failed to open file %s: %s", filename, strerror(errno));
+               return;
+       }
+
+       /*
+        *      This should work in most situations.
+        */
+       if (write(fd, buffer, len + 1) < 0) {
+               DEBUG("Failed to write to file %s: %s", filename, strerror(errno));
+       }
+
+       close(fd);
+}
+#endif
+
 /** Decrypt application data
  *
  * @note Handshake must have completed before this function may be called.
index 176d0dbd38d5bf1602eec52f5de38630b8a57204..396a0943dde7cd5a34e417f6c66eadafacf355e6 100644 (file)
@@ -284,6 +284,8 @@ void                fr_tls_session_info_cb(SSL const *s, int where, int ret);
 void           fr_tls_session_msg_cb(int write_p, int msg_version, int content_type,
                                      void const *buf, size_t len, SSL *ssl, void *arg);
 
+void           fr_tls_session_keylog_cb(const SSL *ssl, const char *line);
+
 int            fr_tls_session_pairs_from_x509_cert(fr_pair_list_t *pair_list, TALLOC_CTX *ctx,
                                                    request_t *request, X509 *cert) CC_HINT(nonnull);