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;
};
{ 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), },
{ 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) },
*/
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
#include <openssl/ssl.h>
#include <ctype.h>
+#include <fcntl.h>
#include "attrs.h"
#include "base.h"
#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.
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);