Skip to content

Commit 6df179e

Browse files
romanmichalvasko
authored andcommitted
session server tls UPDATE add tls keylog support
Resolves #517
1 parent acfb5cb commit 6df179e

File tree

6 files changed

+185
-1
lines changed

6 files changed

+185
-1
lines changed

src/session_mbedtls.c

Lines changed: 89 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>
@@ -1923,3 +1924,91 @@ nc_tls_get_cert_exp_time_wrap(void *cert)
19231924

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

src/session_openssl.c

Lines changed: 43 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>
@@ -1449,3 +1450,45 @@ nc_tls_get_cert_exp_time_wrap(void *cert)
14491450

14501451
return timegm(&t);
14511452
}
1453+
1454+
/**
1455+
* @brief Callback for writing a line in the keylog file.
1456+
*/
1457+
static void
1458+
nc_tls_keylog_write_line(const SSL *UNUSED(ssl), const char *line)
1459+
{
1460+
size_t linelen;
1461+
char buf[256];
1462+
1463+
if (!server_opts.tls_keylog_file || !line) {
1464+
return;
1465+
}
1466+
1467+
/* linelen should not exceed 196 bytes, so 256 should be enough */
1468+
linelen = strlen(line);
1469+
if (!linelen || (linelen > sizeof(buf) - 2)) {
1470+
return;
1471+
}
1472+
1473+
memcpy(buf, line, linelen);
1474+
if (line[linelen - 1] != '\n') {
1475+
buf[linelen++] = '\n';
1476+
}
1477+
buf[linelen] = '\0';
1478+
1479+
fputs(buf, server_opts.tls_keylog_file);
1480+
fflush(server_opts.tls_keylog_file);
1481+
}
1482+
1483+
void
1484+
nc_tls_keylog_session_wrap(void *session)
1485+
{
1486+
SSL_CTX *ctx;
1487+
1488+
ctx = SSL_get_SSL_CTX(session);
1489+
if (!ctx) {
1490+
return;
1491+
}
1492+
1493+
SSL_CTX_set_keylog_callback(ctx, nc_tls_keylog_write_line);
1494+
}

src/session_p.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,8 @@ struct nc_server_opts {
625625
} *intervals;
626626
int interval_count; /**< Number of intervals. */
627627
} cert_exp_notif;
628+
629+
FILE *tls_keylog_file; /**< File to log TLS secrets to. */
628630
#endif
629631
};
630632

@@ -685,6 +687,11 @@ struct nc_server_opts {
685687
*/
686688
#define NC_CLIENT_MONITORING_LOCK_TIMEOUT 500
687689

690+
/**
691+
* TLS key log file environment variable name.
692+
*/
693+
#define NC_TLS_KEYLOGFILE_ENV "SSLKEYLOGFILE"
694+
688695
/**
689696
* @brief Type of the session
690697
*/

src/session_server.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,29 @@ nc_server_init_cb_ctx(const struct ly_ctx *ctx)
795795
}
796796
}
797797

798+
#ifdef NC_ENABLED_SSH_TLS
799+
800+
/**
801+
* @brief Open the keylog file for writing TLS secrets.
802+
*/
803+
static void
804+
nc_server_keylog_file_open(void)
805+
{
806+
char *keylog_file_name;
807+
808+
keylog_file_name = getenv(NC_TLS_KEYLOGFILE_ENV);
809+
if (!keylog_file_name) {
810+
return;
811+
}
812+
813+
server_opts.tls_keylog_file = fopen(keylog_file_name, "a");
814+
if (!server_opts.tls_keylog_file) {
815+
WRN(NULL, "Failed to open keylog file \"%s\".", keylog_file_name);
816+
}
817+
}
818+
819+
#endif
820+
798821
API int
799822
nc_server_init(void)
800823
{
@@ -858,6 +881,9 @@ nc_server_init(void)
858881
ERR(NULL, "%s: failed to init certificate expiration notification thread condition(%s).", __func__, strerror(r));
859882
goto error;
860883
}
884+
885+
/* try to open the keylog file for writing TLS secrets */
886+
nc_server_keylog_file_open();
861887
#endif
862888

863889
return 0;
@@ -917,6 +943,11 @@ nc_server_destroy(void)
917943
nc_server_config_ts_truststore(NULL, NC_OP_DELETE);
918944
curl_global_cleanup();
919945
ssh_finalize();
946+
947+
/* close the TLS keylog file */
948+
if (server_opts.tls_keylog_file) {
949+
fclose(server_opts.tls_keylog_file);
950+
}
920951
#endif /* NC_ENABLED_SSH_TLS */
921952
}
922953

src/session_server_tls.c

Lines changed: 6 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
@@ -899,6 +899,11 @@ nc_accept_tls_session(struct nc_session *session, struct nc_server_tls_opts *opt
899899
goto fail;
900900
}
901901

902+
/* if keylog file is set, log the tls secrets there */
903+
if (server_opts.tls_keylog_file) {
904+
nc_tls_keylog_session_wrap(session->ti.tls.session);
905+
}
906+
902907
/* set session fd */
903908
nc_tls_set_fd_wrap(session->ti.tls.session, sock, &session->ti.tls.ctx);
904909

src/session_wrapper.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ struct nc_tls_verify_cb_data {
6969
void *chain; /**< Certificate chain used to verify the client cert. */
7070
};
7171

72+
extern struct nc_server_opts server_opts;
73+
7274
/**
7375
* @brief Creates a new TLS session from the given configuration.
7476
*
@@ -732,4 +734,11 @@ void nc_server_tls_set_cipher_suites_wrap(void *tls_cfg, void *cipher_suites);
732734
*/
733735
time_t nc_tls_get_cert_exp_time_wrap(void *cert);
734736

737+
/**
738+
* @brief Set the session to log TLS secrets for.
739+
*
740+
* @param[in] session Session to log secrets for.
741+
*/
742+
void nc_tls_keylog_session_wrap(void *session);
743+
735744
#endif

0 commit comments

Comments
 (0)