Created
April 24, 2015 02:23
-
-
Save ghoff/3b9ff5e78a4779b9bea6 to your computer and use it in GitHub Desktop.
sslkeylog patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apps/s_client.c | 10 +++++ | |
ssl/s3_both.c | 7 ++++ | |
ssl/s3_clnt.c | 6 +++ | |
ssl/ssl.h | 13 +++++++ | |
ssl/ssl_lib.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
ssl/ssl_locl.h | 19 ++++++++++ | |
6 files changed, 171 insertions(+) | |
diff --git a/apps/s_client.c b/apps/s_client.c | |
index 8fa2b73..2b5abed 100644 | |
--- a/apps/s_client.c | |
+++ b/apps/s_client.c | |
@@ -740,6 +740,8 @@ int MAIN(int argc, char **argv) | |
int crl_download = 0; | |
STACK_OF(X509_CRL) *crls = NULL; | |
+ char *sslkeylogfile = NULL; | |
+ | |
meth = SSLv23_client_method(); | |
apps_startup(); | |
@@ -1255,6 +1257,14 @@ int MAIN(int argc, char **argv) | |
goto end; | |
} | |
+ sslkeylogfile = getenv("SSLKEYLOGFILE"); | |
+ if (sslkeylogfile) { | |
+ BIO *keylog_bio = BIO_new_file(sslkeylogfile, "a"); | |
+ if (keylog_bio) { | |
+ SSL_CTX_set_keylog_bio(ctx, keylog_bio); | |
+ } | |
+ } | |
+ | |
if (vpm) | |
SSL_CTX_set1_param(ctx, vpm); | |
diff --git a/ssl/s3_both.c b/ssl/s3_both.c | |
index c92fd72..564a88f 100644 | |
--- a/ssl/s3_both.c | |
+++ b/ssl/s3_both.c | |
@@ -174,6 +174,13 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) | |
memcpy(p, s->s3->tmp.finish_md, i); | |
l = i; | |
+ /* Log the master secret, if logging is enabled. */ | |
+ if (!ssl_ctx_log_master_secret(s->ctx, s->s3->client_random, | |
+ SSL3_RANDOM_SIZE, s->session->master_key, | |
+ s->session->master_key_length)) { | |
+ return 0; | |
+ } | |
+ | |
/* | |
* Copy the finished so we can use it for renegotiation checks | |
*/ | |
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c | |
index 91053d5..37dc78b 100644 | |
--- a/ssl/s3_clnt.c | |
+++ b/ssl/s3_clnt.c | |
@@ -2389,6 +2389,12 @@ int ssl3_send_client_key_exchange(SSL *s) | |
goto err; | |
} | |
+ /* Log the premaster secret, if logging is enabled. */ | |
+ if (!ssl_ctx_log_rsa_client_key_exchange(s->ctx, p, n, tmp_buf, | |
+ sizeof tmp_buf)) { | |
+ goto err; | |
+ } | |
+ | |
/* Fix buf for TLS and beyond */ | |
if (s->version > SSL3_VERSION) { | |
s2n(n, q); | |
diff --git a/ssl/ssl.h b/ssl/ssl.h | |
index a6d845d..364b577 100644 | |
--- a/ssl/ssl.h | |
+++ b/ssl/ssl.h | |
@@ -842,6 +842,14 @@ void SSL_set_msg_callback(SSL *ssl, | |
# define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) | |
# define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg)) | |
+/* SSL_CTX_set_keylog_bio sets configures all SSL objects attached to |ctx| to | |
+ * log session material to |keylog_bio|. This is intended for debugging use with | |
+ * tools like Wireshark. |ctx| takes ownership of |keylog_bio|. | |
+ * | |
+ * The format is described in | |
+ * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. */ | |
+OPENSSL_EXPORT void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio); | |
+ | |
# ifndef OPENSSL_NO_SRP | |
# ifndef OPENSSL_NO_SSL_INTERN | |
@@ -1181,6 +1189,10 @@ struct ssl_ctx_st { | |
unsigned char *tlsext_ellipticcurvelist; | |
# endif /* OPENSSL_NO_EC */ | |
# endif | |
+ /* If not NULL, session key material will be logged to this BIO for | |
+ * debugging purposes. The format matches NSS's and is readable by | |
+ * Wireshark. */ | |
+ BIO *keylog_bio; | |
}; | |
# endif | |
@@ -2817,6 +2829,7 @@ void ERR_load_SSL_strings(void); | |
# define SSL_F_SSL_VERIFY_CERT_CHAIN 207 | |
# define SSL_F_SSL_WRITE 208 | |
# define SSL_F_TLS12_CHECK_PEER_SIGALG 333 | |
+# define SSL_F_ssl_ctx_log_rsa_client_key_exchange 285 | |
# define SSL_F_TLS1_CERT_VERIFY_MAC 286 | |
# define SSL_F_TLS1_CHANGE_CIPHER_STATE 209 | |
# define SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT 274 | |
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c | |
index e9ad2bc..3f156e7 100644 | |
--- a/ssl/ssl_lib.c | |
+++ b/ssl/ssl_lib.c | |
@@ -2169,6 +2169,9 @@ void SSL_CTX_free(SSL_CTX *a) | |
if (a->alpn_client_proto_list != NULL) | |
OPENSSL_free(a->alpn_client_proto_list); | |
#endif | |
+ if (a->keylog_bio) { | |
+ BIO_free(a->keylog_bio); | |
+ } | |
OPENSSL_free(a); | |
} | |
@@ -3486,6 +3489,119 @@ void SSL_set_msg_callback(SSL *ssl, | |
SSL_callback_ctrl(ssl, SSL_CTRL_SET_MSG_CALLBACK, (void (*)(void))cb); | |
} | |
+void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio) { | |
+ if (ctx->keylog_bio != NULL) { | |
+ BIO_free(ctx->keylog_bio); | |
+ } | |
+ ctx->keylog_bio = keylog_bio; | |
+} | |
+ | |
+void data_add_hex(uint8_t *data, const uint8_t *in, size_t in_len) { | |
+ static const char hextable[] = "0123456789abcdef"; | |
+ size_t i; | |
+ | |
+ for (i = 0; i < in_len; i++) { | |
+ *(data++) = (uint8_t)hextable[in[i] >> 4]; | |
+ *(data++) = (uint8_t)hextable[in[i] & 0xf]; | |
+ } | |
+} | |
+ | |
+int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx, | |
+ const uint8_t *encrypted_premaster, | |
+ size_t encrypted_premaster_len, | |
+ const uint8_t *premaster, | |
+ size_t premaster_len) { | |
+ BIO *bio = ctx->keylog_bio; | |
+ uint8_t *out, *p; | |
+ size_t out_len; | |
+ int ret; | |
+ | |
+ if (bio == NULL) { | |
+ return 1; | |
+ } | |
+ | |
+ if (encrypted_premaster_len < 8) { | |
+/* OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_rsa_client_key_exchange, | |
+ ERR_R_INTERNAL_ERROR);*/ | |
+ return 0; | |
+ } | |
+ | |
+ out_len = 4 + 16 + 1 + premaster_len * 2 + 1; | |
+ if (!(out = (uint8_t *)OPENSSL_malloc(out_len))) { | |
+ return 0; | |
+ } | |
+ p = out; | |
+ memcpy(p, "RSA ", 4); p += 4; | |
+ data_add_hex(p, encrypted_premaster, 8); p += 16; | |
+ memcpy(p, " ", 1); p += 1; | |
+ data_add_hex(p, premaster, premaster_len); p += (premaster_len*2); | |
+ memcpy(p, "\n", 1); | |
+ | |
+ /* | |
+ !CBB_add_bytes(&cbb, (const uint8_t *)"RSA ", 4) || | |
+ * Only the first 8 bytes of the encrypted premaster secret are | |
+ * logged. * | |
+ !cbb_add_hex(&cbb, encrypted_premaster, 8) || | |
+ !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || | |
+ !cbb_add_hex(&cbb, premaster, premaster_len) || | |
+ !CBB_add_bytes(&cbb, (const uint8_t *)"\n", 1) || | |
+ !CBB_finish(&cbb, &out, &out_len)) { | |
+ */ | |
+ | |
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | |
+ ret = BIO_write(bio, out, out_len) >= 0 && BIO_flush(bio); | |
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); | |
+ | |
+ OPENSSL_free(out); | |
+ return ret; | |
+} | |
+ | |
+int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random, | |
+ size_t client_random_len, const uint8_t *master, | |
+ size_t master_len) { | |
+ BIO *bio = ctx->keylog_bio; | |
+ uint8_t *out, *p; | |
+ size_t out_len; | |
+ int ret; | |
+ | |
+ if (bio == NULL) { | |
+ return 1; | |
+ } | |
+ | |
+ if (client_random_len != 32) { | |
+ //OPENSSL_PUT_ERROR(SSL, ssl_ctx_log_master_secret, ERR_R_INTERNAL_ERROR); | |
+ return 0; | |
+ } | |
+ | |
+ out_len = 14 + 64 + 1 + master_len * 2 + 1; | |
+ if (!(out = (uint8_t *)OPENSSL_malloc(out_len))) { | |
+ return 0; | |
+ } | |
+ | |
+ p = out; | |
+ memcpy(p, "CLIENT_RANDOM ", 14); p += 14; | |
+ data_add_hex(p, client_random, 32); p += 64; | |
+ memcpy(p, " ", 1); p++; | |
+ data_add_hex(p, master, master_len); p += (master_len*2); | |
+ memcpy(p, "\n", 1); | |
+ | |
+ /* | |
+ !CBB_add_bytes(&cbb, (const uint8_t *)"CLIENT_RANDOM ", 14) || | |
+ !cbb_add_hex(&cbb, client_random, 32) || | |
+ !CBB_add_bytes(&cbb, (const uint8_t *)" ", 1) || | |
+ !cbb_add_hex(&cbb, master, master_len) || | |
+ !CBB_add_bytes(&cbb, (const uint8_t *)"\n", 1) || | |
+ !CBB_finish(&cbb, &out, &out_len)) | |
+ */ | |
+ | |
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | |
+ ret = BIO_write(bio, out, out_len) >= 0 && BIO_flush(bio); | |
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); | |
+ | |
+ OPENSSL_free(out); | |
+ return ret; | |
+} | |
+ | |
/* | |
* Allocates new EVP_MD_CTX and sets pointer to it into given pointer | |
* vairable, freeing EVP_MD_CTX previously stored in that variable, if any. | |
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h | |
index 79b85b9..d2bb3c8 100644 | |
--- a/ssl/ssl_locl.h | |
+++ b/ssl/ssl_locl.h | |
@@ -165,6 +165,8 @@ | |
# include <openssl/ssl.h> | |
# include <openssl/symhacks.h> | |
+# include <stdint.h> | |
+ | |
# ifdef OPENSSL_BUILD_SHLIBSSL | |
# undef OPENSSL_EXTERN | |
# define OPENSSL_EXTERN OPENSSL_EXPORT | |
@@ -1400,6 +1402,23 @@ int tls1_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain, | |
int idx); | |
void tls1_set_cert_validity(SSL *s); | |
+/* ssl_ctx_log_rsa_client_key_exchange logs |premaster| to |ctx|, if logging is | |
+ * enabled. It returns one on success and zero on failure. The entry is | |
+ * identified by the first 8 bytes of |encrypted_premaster|. */ | |
+int ssl_ctx_log_rsa_client_key_exchange(SSL_CTX *ctx, | |
+ const uint8_t *encrypted_premaster, | |
+ size_t encrypted_premaster_len, | |
+ const uint8_t *premaster, | |
+ size_t premaster_len); | |
+ | |
+/* ssl_ctx_log_master_secret logs |master| to |ctx|, if logging is enabled. It | |
+ * returns one on success and zero on failure. The entry is identified by | |
+ * |client_random|. */ | |
+int ssl_ctx_log_master_secret(SSL_CTX *ctx, const uint8_t *client_random, | |
+ size_t client_random_len, const uint8_t *master, | |
+ size_t master_len); | |
+ | |
+ | |
# endif | |
EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md); | |
void ssl_clear_hash_ctx(EVP_MD_CTX **hash); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment