Allow dumping SSL session keys on TRACE_SESSION_KEY

This dumps SSL session keys to a log file specified by the
SSLKEYLOGFILE environment variable.

This permits decrypting SSL trafic in wireshark with a tcpdump
capture for example.
cf.
https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format
https://security.stackexchange.com/questions/35639/decrypting-tls-in-wireshark-when-using-dhe-rsa-ciphersuites/42350#42350
https://wiki.wireshark.org/SSL#Using_the_.28Pre.29-Master-Secret
https://jimshaver.net/2015/02/11/decrypting-tls-browser-traffic-with-wireshark-the-easy-way/

Looks like we miss the required function from SSL...
SSL_SESSION_print_keylog is only in 1.1.0.
Also added dumping of client_random as it's required by wireshark.
This commit is contained in:
François Revol 2017-05-03 22:21:18 +02:00
parent 84c62f1d46
commit e62e979e60
1 changed files with 114 additions and 0 deletions

View File

@ -11,6 +11,7 @@
#ifdef OPENSSL_ENABLED
# include <openssl/ssl.h>
# include <openssl/ssl3.h> // for TRACE_SESSION_KEY only
# include <openssl/err.h>
#endif
@ -32,9 +33,94 @@
# define TRACE(x...) ;
#endif
//#define TRACE_SESSION_KEY
#ifdef OPENSSL_ENABLED
#ifdef TRACE_SESSION_KEY
#if OPENSSL_VERSION_NUMBER < 0x10100000L
/*
* print session id and master key in NSS keylog format (RSA
* Session-ID:<session id> Master-Key:<master key>)
*/
int SSL_SESSION_print_keylog(BIO *bp, const SSL_SESSION *x)
{
size_t i;
if (x == NULL)
goto err;
if (x->session_id_length == 0 || x->master_key_length == 0)
goto err;
/*
* the RSA prefix is required by the format's definition although there's
* nothing RSA-specific in the output, therefore, we don't have to check if
* the cipher suite is based on RSA
*/
if (BIO_puts(bp, "RSA ") <= 0)
goto err;
if (BIO_puts(bp, "Session-ID:") <= 0)
goto err;
for (i = 0; i < x->session_id_length; i++) {
if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0)
goto err;
}
if (BIO_puts(bp, " Master-Key:") <= 0)
goto err;
for (i = 0; i < (size_t)x->master_key_length; i++) {
if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
goto err;
}
if (BIO_puts(bp, "\n") <= 0)
goto err;
return (1);
err:
return (0);
}
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
/*
* print client random id and master key in NSS keylog format
* as session ID is not enough.
*/
int SSL_SESSION_print_client_random(BIO *bp, const SSL *ssl)
{
const SSL_SESSION *x = SSL_get_session(ssl);
size_t i;
if (x == NULL)
goto err;
if (x->session_id_length == 0 || x->master_key_length == 0)
goto err;
/*
* the RSA prefix is required by the format's definition although there's
* nothing RSA-specific in the output, therefore, we don't have to check if
* the cipher suite is based on RSA
*/
if (BIO_puts(bp, "CLIENT_RANDOM ") <= 0)
goto err;
for (i = 0; i < sizeof(ssl->s3->client_random); i++) {
if (BIO_printf(bp, "%02X", ssl->s3->client_random[i]) <= 0)
goto err;
}
if (BIO_puts(bp, " ") <= 0)
goto err;
for (i = 0; i < (size_t)x->master_key_length; i++) {
if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
goto err;
}
if (BIO_puts(bp, "\n") <= 0)
goto err;
return (1);
err:
return (0);
}
#endif /* TRACE_SESSION_KEY */
class BSecureSocket::Private {
public:
@ -59,6 +145,11 @@ private:
static SSL_CTX* sContext;
// FIXME When do we SSL_CTX_free it?
static pthread_once_t sInitOnce;
#ifdef TRACE_SESSION_KEY
public:
static BIO* sKeyLogBIO;
#endif
};
@ -66,6 +157,9 @@ private:
/* static */ int BSecureSocket::Private::sDataIndex;
/* static */ pthread_once_t BSecureSocket::Private::sInitOnce
= PTHREAD_ONCE_INIT;
#ifdef TRACE_SESSION_KEY
/* static */ BIO* BSecureSocket::Private::sKeyLogBIO = NULL;
#endif
BSecureSocket::Private::Private()
@ -286,6 +380,17 @@ BSecureSocket::Private::_CreateContext()
// Get an unique index number for storing application data in SSL
// structs. We will store a pointer to the BSecureSocket class there.
sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
#ifdef TRACE_SESSION_KEY
FILE *keylog = NULL;
const char *logpath = getenv("SSLKEYLOGFILE");
if (logpath)
keylog = fopen(logpath, "w+");
if (keylog) {
fprintf(keylog, "# Key Log File generated by Haiku Network Kit\n");
sKeyLogBIO = BIO_new_fp(keylog, BIO_NOCLOSE);
}
#endif
}
@ -477,6 +582,7 @@ BSecureSocket::_SetupCommon(const char* host)
SSL_set_tlsext_host_name(fPrivate->fSSL, host);
}
return B_OK;
}
@ -495,6 +601,14 @@ BSecureSocket::_SetupConnect(const char* host)
return fPrivate->ErrorCode(returnValue);
}
#ifdef TRACE_SESSION_KEY
fprintf(stderr, "SSL SESSION INFO:\n");
//SSL_SESSION_print_fp(stderr, SSL_get_session(fPrivate->fSSL));
SSL_SESSION_print_keylog(fPrivate->sKeyLogBIO, SSL_get_session(fPrivate->fSSL));
SSL_SESSION_print_client_random(fPrivate->sKeyLogBIO, fPrivate->fSSL);
fprintf(stderr, "\n");
#endif
return B_OK;
}