Skip to content

Commit ea1fc0a

Browse files
author
roman
committed
session server tls UPDATE add tls keylog support
1 parent acfb5cb commit ea1fc0a

File tree

6 files changed

+258
-1
lines changed

6 files changed

+258
-1
lines changed

src/session_mbedtls.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <ctype.h>
2323
#include <errno.h>
2424
#include <poll.h>
25+
#include <pthread.h>
2526
#include <stdint.h>
2627
#include <stdio.h>
2728
#include <stdlib.h>
@@ -50,6 +51,8 @@
5051
#include <mbedtls/x509_crl.h>
5152
#include <mbedtls/x509_crt.h>
5253

54+
extern struct nc_server_opts server_opts;
55+
5356
/**
5457
* @brief Converts mbedTLS error codes to a string.
5558
*
@@ -220,6 +223,9 @@ nc_tls_session_destroy_wrap(void *tls_session)
220223
{
221224
mbedtls_ssl_free(tls_session);
222225
free(tls_session);
226+
227+
/* close keylog file if needed */
228+
nc_tls_keylog_close();
223229
}
224230

225231
void *
@@ -1923,3 +1929,98 @@ nc_tls_get_cert_exp_time_wrap(void *cert)
19231929

19241930
return timegm(&t);
19251931
}
1932+
1933+
/**
1934+
* @brief Convert the MbedTLS key export type to a label for the keylog file.
1935+
*
1936+
* @param[in] type MbedTLS key export type.
1937+
* @return Label for the keylog file or NULL if the type is not supported.
1938+
*/
1939+
static const char *
1940+
nc_tls_keylog_type2label(mbedtls_ssl_key_export_type type)
1941+
{
1942+
switch (type) {
1943+
case MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET:
1944+
return "CLIENT_RANDOM";
1945+
#ifdef MBEDTLS_SSL_PROTO_TLS1_3
1946+
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_HANDSHAKE_TRAFFIC_SECRET:
1947+
return "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
1948+
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_HANDSHAKE_TRAFFIC_SECRET:
1949+
return "SERVER_HANDSHAKE_TRAFFIC_SECRET";
1950+
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_CLIENT_APPLICATION_TRAFFIC_SECRET:
1951+
return "CLIENT_TRAFFIC_SECRET_0";
1952+
case MBEDTLS_SSL_KEY_EXPORT_TLS1_3_SERVER_APPLICATION_TRAFFIC_SECRET:
1953+
return "SERVER_TRAFFIC_SECRET_0";
1954+
#endif
1955+
default:
1956+
return NULL;
1957+
}
1958+
}
1959+
1960+
/**
1961+
* @brief Callback for writing a line in the keylog file.
1962+
*/
1963+
static void
1964+
nc_tls_keylog_write_line(void *UNUSED(p_expkey), mbedtls_ssl_key_export_type type, const unsigned char *secret,
1965+
size_t secret_len, const unsigned char client_random[32],
1966+
const unsigned char UNUSED(server_random[32]), mbedtls_tls_prf_types UNUSED(tls_prf_type))
1967+
{
1968+
size_t linelen, len = 0, i, client_random_len;
1969+
char buf[256];
1970+
const char *label;
1971+
1972+
/* LOCK */
1973+
pthread_mutex_lock(&server_opts.keylog_data.lock);
1974+
1975+
if (!server_opts.keylog_data.f) {
1976+
goto cleanup;
1977+
}
1978+
1979+
label = nc_tls_keylog_type2label(type);
1980+
if (!label) {
1981+
/* type not supported */
1982+
goto cleanup;
1983+
}
1984+
1985+
/* <Label> <space> 0x<ClientRandom> <space> 0x<Secret> */
1986+
linelen = strlen(label) + 1 + 2 * 32 + 1 + 2 * secret_len + 1;
1987+
if (linelen > sizeof(buf)) {
1988+
/* sanity check, should not happen since the max len should be 196 bytes */
1989+
goto cleanup;
1990+
}
1991+
1992+
/* write the label */
1993+
len += sprintf(buf + len, "%s ", label);
1994+
1995+
/* write the client random */
1996+
client_random_len = 32;
1997+
for (i = 0; i < client_random_len; i++) {
1998+
len += sprintf(buf + len, "%02x", client_random[i]);
1999+
}
2000+
len += sprintf(buf + len, " ");
2001+
2002+
/* write the secret */
2003+
for (i = 0; i < secret_len; i++) {
2004+
len += sprintf(buf + len, "%02x", secret[i]);
2005+
}
2006+
2007+
len += sprintf(buf + len, "\n");
2008+
buf[len] = '\0';
2009+
2010+
if (len != linelen) {
2011+
goto cleanup;
2012+
}
2013+
2014+
fputs(buf, server_opts.keylog_data.f);
2015+
fflush(server_opts.keylog_data.f);
2016+
2017+
cleanup:
2018+
/* UNLOCK */
2019+
pthread_mutex_unlock(&server_opts.keylog_data.lock);
2020+
}
2021+
2022+
void
2023+
nc_tls_keylog_session_wrap(void *session)
2024+
{
2025+
mbedtls_ssl_set_export_keys_cb(session, nc_tls_keylog_write_line, NULL);
2026+
}

src/session_openssl.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <ctype.h>
2323
#include <poll.h>
24+
#include <pthread.h>
2425
#include <stdint.h>
2526
#include <stdio.h>
2627
#include <stdlib.h>
@@ -43,6 +44,8 @@
4344
#include <openssl/x509.h>
4445
#include <openssl/x509v3.h>
4546

47+
extern struct nc_server_opts server_opts;
48+
4649
void *
4750
nc_tls_session_new_wrap(void *tls_cfg)
4851
{
@@ -61,6 +64,9 @@ void
6164
nc_tls_session_destroy_wrap(void *tls_session)
6265
{
6366
SSL_free(tls_session);
67+
68+
/* close keylog file if needed */
69+
nc_tls_keylog_close();
6470
}
6571

6672
void *
@@ -1449,3 +1455,52 @@ nc_tls_get_cert_exp_time_wrap(void *cert)
14491455

14501456
return timegm(&t);
14511457
}
1458+
1459+
/**
1460+
* @brief Callback for writing a line in the keylog file.
1461+
*/
1462+
static void
1463+
nc_tls_keylog_write_line(const SSL *UNUSED(ssl), const char *line)
1464+
{
1465+
size_t linelen;
1466+
char buf[256];
1467+
1468+
/* LOCK */
1469+
pthread_mutex_lock(&server_opts.keylog_data.lock);
1470+
1471+
if (!server_opts.keylog_data.f || !line) {
1472+
goto cleanup;
1473+
}
1474+
1475+
/* linelen should not exceed 196 bytes, so 256 should be enough */
1476+
linelen = strlen(line);
1477+
if (!linelen || (linelen > sizeof(buf) - 2)) {
1478+
goto cleanup;
1479+
}
1480+
1481+
memcpy(buf, line, linelen);
1482+
if (line[linelen - 1] != '\n') {
1483+
buf[linelen++] = '\n';
1484+
}
1485+
buf[linelen] = '\0';
1486+
1487+
fputs(buf, server_opts.keylog_data.f);
1488+
fflush(server_opts.keylog_data.f);
1489+
1490+
cleanup:
1491+
/* UNLOCK */
1492+
pthread_mutex_unlock(&server_opts.keylog_data.lock);
1493+
}
1494+
1495+
void
1496+
nc_tls_keylog_session_wrap(void *session)
1497+
{
1498+
SSL_CTX *ctx;
1499+
1500+
ctx = SSL_get_SSL_CTX(session);
1501+
if (!ctx) {
1502+
return;
1503+
}
1504+
1505+
SSL_CTX_set_keylog_callback(ctx, nc_tls_keylog_write_line);
1506+
}

src/session_p.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,15 @@ struct nc_server_opts {
625625
} *intervals;
626626
int interval_count; /**< Number of intervals. */
627627
} cert_exp_notif;
628+
629+
/**
630+
* @brief Data for TLS key logger.
631+
*/
632+
struct {
633+
FILE *f; /**< File to log keys to. */
634+
uint32_t session_count; /**< Number of sessions using the key logger. */
635+
pthread_mutex_t lock; /**< Lock for the key logger data. */
636+
} keylog_data;
628637
#endif
629638
};
630639

src/session_server.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,11 @@ nc_server_init(void)
858858
ERR(NULL, "%s: failed to init certificate expiration notification thread condition(%s).", __func__, strerror(r));
859859
goto error;
860860
}
861+
862+
if ((r = pthread_mutex_init(&server_opts.keylog_data.lock, NULL))) {
863+
ERR(NULL, "%s: failed to init keylog data lock(%s).", __func__, strerror(r));
864+
goto error;
865+
}
861866
#endif
862867

863868
return 0;
@@ -917,6 +922,8 @@ nc_server_destroy(void)
917922
nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
918923
curl_global_cleanup();
919924
ssh_finalize();
925+
926+
pthread_mutex_destroy(&server_opts.keylog_data.lock);
920927
#endif /* NC_ENABLED_SSH_TLS */
921928
}
922929

src/session_server_tls.c

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#define _GNU_SOURCE
1818

19+
#include <errno.h>
1920
#include <poll.h>
2021
#include <stdint.h>
2122
#include <stdio.h>
@@ -32,7 +33,6 @@
3233
#include "session_p.h"
3334
#include "session_wrapper.h"
3435

35-
struct nc_server_tls_opts tls_ch_opts;
3636
extern struct nc_server_opts server_opts;
3737

3838
static int
@@ -790,6 +790,70 @@ nc_server_tls_get_num_certs(struct nc_cert_grouping *certs_grp)
790790
return count;
791791
}
792792

793+
static int
794+
nc_tls_keylog_open(void)
795+
{
796+
int ret = 0;
797+
char *keylog_file_name;
798+
799+
/* LOCK */
800+
pthread_mutex_lock(&server_opts.keylog_data.lock);
801+
802+
/* check if the file is already open and if not, open it */
803+
if (!server_opts.keylog_data.f) {
804+
keylog_file_name = getenv(SSLKEYLOGFILE_ENV);
805+
if (!keylog_file_name) {
806+
ret = 1;
807+
goto cleanup;
808+
}
809+
810+
server_opts.keylog_data.f = fopen(keylog_file_name, "a");
811+
if (!server_opts.keylog_data.f) {
812+
WRN(NULL, "Failed to open keylog file \"%s\".", keylog_file_name);
813+
ret = 1;
814+
goto cleanup;
815+
}
816+
817+
if (setvbuf(server_opts.keylog_data.f, NULL, _IOLBF, 4096)) {
818+
fclose(server_opts.keylog_data.f);
819+
server_opts.keylog_data.f = NULL;
820+
ERR(NULL, "Failed to setvbuf() on keylog file \"%s\" (%s).", keylog_file_name, strerror(errno));
821+
ret = 1;
822+
goto cleanup;
823+
}
824+
}
825+
826+
/* increase the session count */
827+
server_opts.keylog_data.session_count++;
828+
829+
cleanup:
830+
/* UNLOCK */
831+
pthread_mutex_unlock(&server_opts.keylog_data.lock);
832+
return ret;
833+
}
834+
835+
void
836+
nc_tls_keylog_close(void)
837+
{
838+
/* LOCK */
839+
pthread_mutex_lock(&server_opts.keylog_data.lock);
840+
841+
if (!server_opts.keylog_data.f) {
842+
goto cleanup;
843+
}
844+
845+
/* decrease the session count */
846+
server_opts.keylog_data.session_count--;
847+
if (!server_opts.keylog_data.session_count) {
848+
fclose(server_opts.keylog_data.f);
849+
server_opts.keylog_data.f = NULL;
850+
}
851+
852+
cleanup:
853+
/* UNLOCK */
854+
pthread_mutex_unlock(&server_opts.keylog_data.lock);
855+
}
856+
793857
int
794858
nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opts, int sock, int timeout)
795859
{
@@ -899,6 +963,10 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt
899963
goto fail;
900964
}
901965

966+
if (!nc_tls_keylog_open()) {
967+
nc_tls_keylog_session_wrap(session->ti.tls.session);
968+
}
969+
902970
/* set session fd */
903971
nc_tls_set_fd_wrap(session->ti.tls.session, sock, &session->ti.tls.ctx);
904972

src/session_wrapper.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ struct nc_tls_ctx {
6060

6161
#endif
6262

63+
/**
64+
* TLS key log file environment variable name.
65+
*/
66+
#define SSLKEYLOGFILE_ENV "SSLKEYLOGFILE"
67+
6368
/**
6469
* @brief Server side TLS verify callback data.
6570
*/
@@ -732,4 +737,16 @@ void nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites);
732737
*/
733738
time_t nc_tls_get_cert_exp_time_wrap(void *cert);
734739

740+
/**
741+
* @brief Set the session to log TLS secrets for.
742+
*
743+
* @param[in] session Session to log secrets for.
744+
*/
745+
void nc_tls_keylog_session_wrap(void *session);
746+
747+
/**
748+
* @brief Decrease the logging session reference counter and close the keylog file if it reaches 0.
749+
*/
750+
void nc_tls_keylog_close(void);
751+
735752
#endif

0 commit comments

Comments
 (0)