From 942273e9cba5aa7a73899b8ee7017201c97f2776 Mon Sep 17 00:00:00 2001 From: David Fort Date: Tue, 16 Aug 2022 10:40:32 +0200 Subject: [PATCH] tls: add an option to dump tls secrets for wireshark decoding (#8120) This new option /tls-secret-file: allows to dump TLS secrets in a file with the SSLKEYLOGFILE format. So this way you can setup the TLS dissector of wireshark (Pre-Master-Secret log filename) and see the traffic in clear in wireshark. It also add some more PFS ciphers to remove for netmon captures. --- client/common/cmdline.c | 10 ++++- client/common/cmdline.h | 2 + include/freerdp/settings.h | 4 +- libfreerdp/common/settings_getters.c | 9 +++++ libfreerdp/common/settings_str.c | 1 + .../core/test/settings_property_lists.h | 1 + libfreerdp/crypto/tls.c | 39 +++++++++++++++++++ 7 files changed, 64 insertions(+), 2 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 814d95677..4487215de 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -2867,7 +2867,7 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (strcmp(arg->Value, "netmon") == 0) { - ciphers = "ALL:!ECDH"; + ciphers = "ALL:!ECDH:!ADH:!DHE"; } else if (strcmp(arg->Value, "ma") == 0) { @@ -2890,6 +2890,14 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->TlsSecLevel = (UINT32)val; } + CommandLineSwitchCase(arg, "tls-secrets-file") + { + if (!arg->Value) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + + if (!freerdp_settings_set_string(settings, FreeRDP_TlsSecretsFile, arg->Value)) + return COMMAND_LINE_ERROR_MEMORY; + } CommandLineSwitchCase(arg, "enforce-tlsv1_2") { if (!(freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, TLS1_2_VERSION) && diff --git a/client/common/cmdline.h b/client/common/cmdline.h index 075725c82..d4ab90ed1 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -369,6 +369,8 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = { "Allowed TLS ciphers" }, { "tls-seclevel", COMMAND_LINE_VALUE_REQUIRED, "", "1", NULL, -1, NULL, "TLS security level - defaults to 1" }, + { "tls-secrets-file", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, + "File were TLS secrets will be stored in the SSLKEYLOGFILE format" }, { "enforce-tlsv1_2", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Force use of TLS1.2 for connection. Some servers have a buggy TLS version negotiation and " "might fail without this" }, diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 8852c18d6..528968946 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -639,6 +639,7 @@ typedef struct #define FreeRDP_SspiModule (1106) #define FreeRDP_TLSMinVersion (1107) #define FreeRDP_TLSMaxVersion (1108) +#define FreeRDP_TlsSecretsFile (1109) #define FreeRDP_MstscCookieMode (1152) #define FreeRDP_CookieMaxLength (1153) #define FreeRDP_PreconnectionId (1154) @@ -1126,7 +1127,8 @@ struct rdp_settings ALIGN64 char* SspiModule; /* 1106 */ ALIGN64 UINT16 TLSMinVersion; /* 1107 */ ALIGN64 UINT16 TLSMaxVersion; /* 1108 */ - UINT64 padding1152[1152 - 1109]; /* 1109 */ + ALIGN64 char* TlsSecretsFile; /* 1109 */ + UINT64 padding1152[1152 - 1110]; /* 1110 */ /* Connection Cookie */ ALIGN64 BOOL MstscCookieMode; /* 1152 */ diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index 838f2bb79..8c4ebb7d1 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -2594,6 +2594,9 @@ const char* freerdp_settings_get_string(const rdpSettings* settings, size_t id) case FreeRDP_TargetNetAddress: return settings->TargetNetAddress; + case FreeRDP_TlsSecretsFile: + return settings->TlsSecretsFile; + case FreeRDP_TransportDumpFile: return settings->TransportDumpFile; @@ -2855,6 +2858,9 @@ char* freerdp_settings_get_string_writable(rdpSettings* settings, size_t id) case FreeRDP_TargetNetAddress: return settings->TargetNetAddress; + case FreeRDP_TlsSecretsFile: + return settings->TlsSecretsFile; + case FreeRDP_TransportDumpFile: return settings->TransportDumpFile; @@ -3126,6 +3132,9 @@ BOOL freerdp_settings_set_string_(rdpSettings* settings, size_t id, const char* case FreeRDP_TargetNetAddress: return update_string(&settings->TargetNetAddress, cnv.cc, len, cleanup); + case FreeRDP_TlsSecretsFile: + return update_string(&settings->TlsSecretsFile, cnv.cc, len, cleanup); + case FreeRDP_TransportDumpFile: return update_string(&settings->TransportDumpFile, cnv.cc, len, cleanup); diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index 138a936f2..39e39f0a3 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -391,6 +391,7 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_SmartcardPrivateKey, 7, "FreeRDP_SmartcardPrivateKey" }, { FreeRDP_SspiModule, 7, "FreeRDP_SspiModule" }, { FreeRDP_TargetNetAddress, 7, "FreeRDP_TargetNetAddress" }, + { FreeRDP_TlsSecretsFile, 7, "FreeRDP_TlsSecretsFile" }, { FreeRDP_TransportDumpFile, 7, "FreeRDP_TransportDumpFile" }, { FreeRDP_Username, 7, "FreeRDP_Username" }, { FreeRDP_WindowTitle, 7, "FreeRDP_WindowTitle" }, diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index 704723605..e7644770e 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -400,6 +400,7 @@ static const size_t string_list_indices[] = { FreeRDP_SmartcardPrivateKey, FreeRDP_SspiModule, FreeRDP_TargetNetAddress, + FreeRDP_TlsSecretsFile, FreeRDP_TransportDumpFile, FreeRDP_Username, FreeRDP_WindowTitle, diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 20570d792..f9feb04fd 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -646,6 +646,33 @@ out_free: return NULL; } +static INIT_ONCE secrets_file_idx_once = INIT_ONCE_STATIC_INIT; +static int secrets_file_idx = -1; + +static BOOL CALLBACK secrets_file_init_cb(PINIT_ONCE once, PVOID param, PVOID* context) +{ + secrets_file_idx = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); + + return (secrets_file_idx != -1); +} + +static void SSLCTX_keylog_cb(const SSL* ssl, const char* line) +{ + char* dfile; + + if (secrets_file_idx == -1) + return; + + dfile = SSL_get_ex_data(ssl, secrets_file_idx); + if (dfile) + { + FILE* f = fopen(dfile, "a+"); + fwrite(line, strlen(line), 1, f); + fwrite("\n", 1, 1, f); + fclose(f); + } +} + #if OPENSSL_VERSION_NUMBER >= 0x010000000L static BOOL tls_prepare(rdpTls* tls, BIO* underlying, const SSL_METHOD* method, int options, BOOL clientMode) @@ -656,6 +683,7 @@ static BOOL tls_prepare(rdpTls* tls, BIO* underlying, SSL_METHOD* method, int op { rdpSettings* settings = tls->settings; tls->ctx = SSL_CTX_new(method); + tls->underlying = underlying; if (!tls->ctx) @@ -702,6 +730,17 @@ static BOOL tls_prepare(rdpTls* tls, BIO* underlying, SSL_METHOD* method, int op return FALSE; } + if (settings->TlsSecretsFile) + { + InitOnceExecuteOnce(&secrets_file_idx_once, secrets_file_init_cb, NULL, NULL); + + if (secrets_file_idx != -1) + { + SSL_set_ex_data(tls->ssl, secrets_file_idx, settings->TlsSecretsFile); + SSL_CTX_set_keylog_callback(tls->ctx, SSLCTX_keylog_cb); + } + } + BIO_push(tls->bio, underlying); return TRUE; }