Skip to content

Instantly share code, notes, and snippets.

@ghoff
Created April 24, 2015 02:23
Show Gist options
  • Save ghoff/3b9ff5e78a4779b9bea6 to your computer and use it in GitHub Desktop.
Save ghoff/3b9ff5e78a4779b9bea6 to your computer and use it in GitHub Desktop.
sslkeylog patch
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