apps: Add support for writing a keylog file
The server and client demos (s_client and s_server) are extended with a -keylogfile option. This is similar as setting the SSLKEYLOGFILE environment variable for NSS and creates a keylog file which is suitable for Wireshark. Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2343)
This commit is contained in:
parent
a19a6c8179
commit
4bf73e9f86
6 changed files with 78 additions and 0 deletions
|
@ -99,4 +99,5 @@ int ssl_load_stores(SSL_CTX *ctx, const char *vfyCApath,
|
||||||
const char *chCAfile, STACK_OF(X509_CRL) *crls,
|
const char *chCAfile, STACK_OF(X509_CRL) *crls,
|
||||||
int crl_download);
|
int crl_download);
|
||||||
void ssl_ctx_security_debug(SSL_CTX *ctx, int verbose);
|
void ssl_ctx_security_debug(SSL_CTX *ctx, int verbose);
|
||||||
|
int set_keylog_file(SSL_CTX *ctx, const char *keylog_file);
|
||||||
#endif
|
#endif
|
||||||
|
|
48
apps/s_cb.c
48
apps/s_cb.c
|
@ -32,6 +32,7 @@ VERIFY_CB_ARGS verify_args = { 0, 0, X509_V_OK, 0 };
|
||||||
static unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
|
static unsigned char cookie_secret[COOKIE_SECRET_LENGTH];
|
||||||
static int cookie_initialized = 0;
|
static int cookie_initialized = 0;
|
||||||
#endif
|
#endif
|
||||||
|
static BIO *bio_keylog = NULL;
|
||||||
|
|
||||||
static const char *lookup(int val, const STRINT_PAIR* list, const char* def)
|
static const char *lookup(int val, const STRINT_PAIR* list, const char* def)
|
||||||
{
|
{
|
||||||
|
@ -1355,3 +1356,50 @@ void ssl_ctx_security_debug(SSL_CTX *ctx, int verbose)
|
||||||
SSL_CTX_set_security_callback(ctx, security_callback_debug);
|
SSL_CTX_set_security_callback(ctx, security_callback_debug);
|
||||||
SSL_CTX_set0_security_ex_data(ctx, &sdb);
|
SSL_CTX_set0_security_ex_data(ctx, &sdb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void keylog_callback(const SSL *ssl, const char *line)
|
||||||
|
{
|
||||||
|
if (bio_keylog == NULL) {
|
||||||
|
BIO_printf(bio_err, "Keylog callback is invoked without valid file!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There might be concurrent writers to the keylog file, so we must ensure
|
||||||
|
* that the given line is written at once.
|
||||||
|
*/
|
||||||
|
BIO_printf(bio_keylog, "%s\n", line);
|
||||||
|
(void)BIO_flush(bio_keylog);
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_keylog_file(SSL_CTX *ctx, const char *keylog_file)
|
||||||
|
{
|
||||||
|
/* Close any open files */
|
||||||
|
BIO_free_all(bio_keylog);
|
||||||
|
bio_keylog = NULL;
|
||||||
|
|
||||||
|
if (ctx == NULL || keylog_file == NULL) {
|
||||||
|
/* Keylogging is disabled, OK. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append rather than write in order to allow concurrent modification.
|
||||||
|
* Furthermore, this preserves existing keylog files which is useful when
|
||||||
|
* the tool is run multiple times.
|
||||||
|
*/
|
||||||
|
bio_keylog = BIO_new_file(keylog_file, "a");
|
||||||
|
if (bio_keylog == NULL) {
|
||||||
|
BIO_printf(bio_err, "Error writing keylog file %s\n", keylog_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a header for seekable, empty files (this excludes pipes). */
|
||||||
|
if (BIO_tell(bio_keylog) == 0) {
|
||||||
|
BIO_puts(bio_keylog,
|
||||||
|
"# SSL/TLS secrets log file, generated by OpenSSL\n");
|
||||||
|
(void)BIO_flush(bio_keylog);
|
||||||
|
}
|
||||||
|
SSL_CTX_set_keylog_callback(ctx, keylog_callback);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -549,6 +549,7 @@ typedef enum OPTION_choice {
|
||||||
OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME,
|
OPT_SERVERINFO, OPT_STARTTLS, OPT_SERVERNAME,
|
||||||
OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST,
|
OPT_USE_SRTP, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SMTPHOST,
|
||||||
OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF,
|
OPT_ASYNC, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF,
|
||||||
|
OPT_KEYLOG_FILE,
|
||||||
OPT_V_ENUM,
|
OPT_V_ENUM,
|
||||||
OPT_X_ENUM,
|
OPT_X_ENUM,
|
||||||
OPT_S_ENUM,
|
OPT_S_ENUM,
|
||||||
|
@ -731,6 +732,7 @@ const OPTIONS s_client_options[] = {
|
||||||
{"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"},
|
{"noct", OPT_NOCT, '-', "Do not request or parse SCTs (default)"},
|
||||||
{"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"},
|
{"ctlogfile", OPT_CTLOG_FILE, '<', "CT log list CONF file"},
|
||||||
#endif
|
#endif
|
||||||
|
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
|
||||||
{NULL, OPT_EOF, 0x00, NULL}
|
{NULL, OPT_EOF, 0x00, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -890,6 +892,7 @@ int s_client_main(int argc, char **argv)
|
||||||
int c_status_req = 0;
|
int c_status_req = 0;
|
||||||
#endif
|
#endif
|
||||||
BIO *bio_c_msg = NULL;
|
BIO *bio_c_msg = NULL;
|
||||||
|
const char *keylog_file = NULL;
|
||||||
|
|
||||||
FD_ZERO(&readfds);
|
FD_ZERO(&readfds);
|
||||||
FD_ZERO(&writefds);
|
FD_ZERO(&writefds);
|
||||||
|
@ -1358,6 +1361,9 @@ int s_client_main(int argc, char **argv)
|
||||||
case OPT_READ_BUF:
|
case OPT_READ_BUF:
|
||||||
read_buf_len = atoi(opt_arg());
|
read_buf_len = atoi(opt_arg());
|
||||||
break;
|
break;
|
||||||
|
case OPT_KEYLOG_FILE:
|
||||||
|
keylog_file = opt_arg();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count4or6 >= 2) {
|
if (count4or6 >= 2) {
|
||||||
|
@ -1706,6 +1712,9 @@ int s_client_main(int argc, char **argv)
|
||||||
SSL_CTX_sess_set_new_cb(ctx, new_session_cb);
|
SSL_CTX_sess_set_new_cb(ctx, new_session_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (set_keylog_file(ctx, keylog_file))
|
||||||
|
goto end;
|
||||||
|
|
||||||
con = SSL_new(ctx);
|
con = SSL_new(ctx);
|
||||||
if (sess_in) {
|
if (sess_in) {
|
||||||
SSL_SESSION *sess;
|
SSL_SESSION *sess;
|
||||||
|
@ -2574,6 +2583,7 @@ int s_client_main(int argc, char **argv)
|
||||||
OPENSSL_free(next_proto.data);
|
OPENSSL_free(next_proto.data);
|
||||||
#endif
|
#endif
|
||||||
SSL_CTX_free(ctx);
|
SSL_CTX_free(ctx);
|
||||||
|
set_keylog_file(NULL, NULL);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
sk_X509_CRL_pop_free(crls, X509_CRL_free);
|
sk_X509_CRL_pop_free(crls, X509_CRL_free);
|
||||||
EVP_PKEY_free(key);
|
EVP_PKEY_free(key);
|
||||||
|
|
|
@ -719,6 +719,7 @@ typedef enum OPTION_choice {
|
||||||
OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
|
OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
|
||||||
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
|
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
|
||||||
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
|
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
|
||||||
|
OPT_KEYLOG_FILE,
|
||||||
OPT_S_ENUM,
|
OPT_S_ENUM,
|
||||||
OPT_V_ENUM,
|
OPT_V_ENUM,
|
||||||
OPT_X_ENUM
|
OPT_X_ENUM
|
||||||
|
@ -913,6 +914,7 @@ const OPTIONS s_server_options[] = {
|
||||||
#ifndef OPENSSL_NO_ENGINE
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
|
{"engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device"},
|
||||||
#endif
|
#endif
|
||||||
|
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
|
||||||
{NULL, OPT_EOF, 0, NULL}
|
{NULL, OPT_EOF, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -988,6 +990,7 @@ int s_server_main(int argc, char *argv[])
|
||||||
int no_resume_ephemeral = 0;
|
int no_resume_ephemeral = 0;
|
||||||
unsigned int split_send_fragment = 0, max_pipelines = 0;
|
unsigned int split_send_fragment = 0, max_pipelines = 0;
|
||||||
const char *s_serverinfo_file = NULL;
|
const char *s_serverinfo_file = NULL;
|
||||||
|
const char *keylog_file = NULL;
|
||||||
|
|
||||||
/* Init of few remaining global variables */
|
/* Init of few remaining global variables */
|
||||||
local_argc = argc;
|
local_argc = argc;
|
||||||
|
@ -1489,6 +1492,9 @@ int s_server_main(int argc, char *argv[])
|
||||||
case OPT_READ_BUF:
|
case OPT_READ_BUF:
|
||||||
read_buf_len = atoi(opt_arg());
|
read_buf_len = atoi(opt_arg());
|
||||||
break;
|
break;
|
||||||
|
case OPT_KEYLOG_FILE:
|
||||||
|
keylog_file = opt_arg();
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1977,6 +1983,8 @@ int s_server_main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (set_keylog_file(ctx, keylog_file))
|
||||||
|
goto end;
|
||||||
|
|
||||||
BIO_printf(bio_s_out, "ACCEPT\n");
|
BIO_printf(bio_s_out, "ACCEPT\n");
|
||||||
(void)BIO_flush(bio_s_out);
|
(void)BIO_flush(bio_s_out);
|
||||||
|
@ -1997,6 +2005,7 @@ int s_server_main(int argc, char *argv[])
|
||||||
ret = 0;
|
ret = 0;
|
||||||
end:
|
end:
|
||||||
SSL_CTX_free(ctx);
|
SSL_CTX_free(ctx);
|
||||||
|
set_keylog_file(NULL, NULL);
|
||||||
X509_free(s_cert);
|
X509_free(s_cert);
|
||||||
sk_X509_CRL_pop_free(crls, X509_CRL_free);
|
sk_X509_CRL_pop_free(crls, X509_CRL_free);
|
||||||
X509_free(s_dcert);
|
X509_free(s_dcert);
|
||||||
|
|
|
@ -520,6 +520,11 @@ for SCTs.
|
||||||
A file containing a list of known Certificate Transparency logs. See
|
A file containing a list of known Certificate Transparency logs. See
|
||||||
L<SSL_CTX_set_ctlog_list_file(3)> for the expected file format.
|
L<SSL_CTX_set_ctlog_list_file(3)> for the expected file format.
|
||||||
|
|
||||||
|
=item B<-keylogfile path>
|
||||||
|
|
||||||
|
Appends TLS secrets to the specified keylog file such that external programs
|
||||||
|
(like Wireshark) can decrypt TLS connections.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 CONNECTED COMMANDS
|
=head1 CONNECTED COMMANDS
|
||||||
|
|
|
@ -557,6 +557,11 @@ cause the client to disconnect due to a protocol violation.
|
||||||
|
|
||||||
print out some session cache status information.
|
print out some session cache status information.
|
||||||
|
|
||||||
|
=item B<-keylogfile path>
|
||||||
|
|
||||||
|
Appends TLS secrets to the specified keylog file such that external programs
|
||||||
|
(like Wireshark) can decrypt TLS connections.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 NOTES
|
=head1 NOTES
|
||||||
|
|
Loading…
Reference in a new issue