From cbb2a179f9bb73d8e15436f608a3f2bd6ab5790a Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 19:08:11 +0000 Subject: [PATCH 01/13] naive implementation with -X, no help, validation, logging --- main.c | 9 ++++++++- opts.h | 1 + pxyconn.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index 617047f..b0cbccb 100644 --- a/main.c +++ b/main.c @@ -275,7 +275,7 @@ main(int argc, char *argv[]) } while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z OPT_i - "k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:F:dDVh")) != -1) { + "k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:F:dDVhX:")) != -1) { switch (ch) { case 'c': if (opts->cacrt) @@ -519,6 +519,13 @@ main(int argc, char *argv[]) opts->contentlog_isdir = 0; opts->contentlog_isspec = 1; break; + case 'X': + if (opts->certgendir) + free(opts->certgendir); + opts->certgendir = strdup(optarg); + if (!opts->certgendir) + oom_die(argv0); + break; #ifdef HAVE_LOCAL_PROCINFO case 'i': opts->lprocinfo = 1; diff --git a/opts.h b/opts.h index abbf5e8..6098b83 100644 --- a/opts.h +++ b/opts.h @@ -100,6 +100,7 @@ typedef struct opts { char *ecdhcurve; #endif /* !OPENSSL_NO_ECDH */ proxyspec_t *spec; + char *certgendir; } opts_t; opts_t *opts_new(void) MALLOC; diff --git a/pxyconn.c b/pxyconn.c index 3cefc66..8c643d5 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -702,6 +702,40 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain, SSL_CTX_add_extra_chain_cert(sslctx, c); } + if (ctx->opts->certgendir) { + unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; + char origfprstr[SSL_X509_FPRSZ*2], newfprstr[SSL_X509_FPRSZ*2]; + ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); + ssl_x509_fingerprint_sha1(crt, newfpr); + sprintf(origfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], + origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], + origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], + origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); + sprintf(newfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], + newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], + newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], + newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); + char *keyfn = malloc(strlen(ctx->opts->certgendir)+1+SSL_X509_FPRSZ*4+1+4); + char *crtfn = malloc(strlen(ctx->opts->certgendir)+1+SSL_X509_FPRSZ*4+1+4); + sprintf(keyfn, "%s/%s-%s.key", ctx->opts->certgendir, origfprstr, newfprstr); + sprintf(crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, origfprstr, newfprstr); + FILE *keyfd, *crtfd; + keyfd = fopen(keyfn, "w"); + crtfd = fopen(crtfn, "w"); + if (keyfd) { + PEM_write_PrivateKey(keyfd, key, NULL, 0, 0, NULL, NULL); + fclose(keyfd); + } + if (crtfd) { + PEM_write_X509(crtfd, crt); + fclose(crtfd); + } + } + #ifdef DEBUG_SESSION_CACHE if (OPTS_DEBUG(ctx->opts)) { int mode = SSL_CTX_get_session_cache_mode(sslctx); From 61d5186864e3c4bab2e5ace4f97f122d2dacc8c2 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 19:40:07 +0000 Subject: [PATCH 02/13] added exclusivity with -K, man page and -h --- main.c | 6 ++++++ sslsplit.1 | 9 ++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/main.c b/main.c index b0cbccb..e8aa164 100644 --- a/main.c +++ b/main.c @@ -112,6 +112,7 @@ main_usage(void) " -k pemfile use CA key (and cert) from pemfile to sign forged certs\n" " -C pemfile use CA chain from pemfile (intermediate and root CA certs)\n" " -K pemfile use key from pemfile for leaf certs (default: generate)\n" +" -X gendir write generated key/cert pairs to gendir\n" " -t certdir use cert+chain+key PEM files from certdir to target all sites\n" " matching the common names (non-matching: generate if CA)\n" " -O deny all OCSP requests on all proxyspecs\n" @@ -561,6 +562,11 @@ main(int argc, char *argv[]) argv0); exit(EXIT_FAILURE); } + if (opts->certgendir && opts->key)) { + fprintf(stderr, "%s: -K and -X are mutually exclusive.\n", + argv0); + exit(EXIT_FAILURE); + } if (!opts->spec) { fprintf(stderr, "%s: no proxyspec specified.\n", argv0); exit(EXIT_FAILURE); diff --git a/sslsplit.1 b/sslsplit.1 index e888b4d..278a58b 100644 --- a/sslsplit.1 +++ b/sslsplit.1 @@ -30,15 +30,15 @@ sslsplit \-\- transparent and scalable SSL/TLS interception .SH SYNOPSIS .na .B sslsplit -[\fB-kCKOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP +[\fB-kCKXOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fIproxyspecs\fP [...] .br .B sslsplit -[\fB-kCKOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP +[\fB-kCKXOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP \fIproxyspecs\fP [...] .br .B sslsplit -[\fB-OPZdDgGsrReumjplLSFi\fP] \fB-t\fP \fIdir\fP +[\fB-OPZXdDgGsrReumjplLSFi\fP] \fB-t\fP \fIdir\fP \fIproxyspecs\fP [...] .br .B sslsplit -E @@ -185,6 +185,9 @@ no matching certificate in the provided certificate directory. Use private key from \fIpemfile\fP for certificates forged on-the-fly. If \fB-K\fP is not given, SSLsplit will generate a random 1024-bit RSA key. .TP +.B \-X \fIgendir\fP +Write generated keys and certificates to individual files in \fIgendir\fP. +.TP .B \-l \fIlogfile\fP Log connections to \fIlogfile\fP in a single line per connection format, including addresses and ports and some HTTP and SSL information, if available. From 73042d4daa1f13b51312281dc230aea2676c4a1d Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 19:47:10 +0000 Subject: [PATCH 03/13] fix mutual exclusivity, sprintf->asprintf --- main.c | 2 +- pxyconn.c | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/main.c b/main.c index e8aa164..799f487 100644 --- a/main.c +++ b/main.c @@ -562,7 +562,7 @@ main(int argc, char *argv[]) argv0); exit(EXIT_FAILURE); } - if (opts->certgendir && opts->key)) { + if (opts->certgendir && opts->key) { fprintf(stderr, "%s: -K and -X are mutually exclusive.\n", argv0); exit(EXIT_FAILURE); diff --git a/pxyconn.c b/pxyconn.c index 8c643d5..0180b94 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -704,25 +704,24 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain, if (ctx->opts->certgendir) { unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; - char origfprstr[SSL_X509_FPRSZ*2], newfprstr[SSL_X509_FPRSZ*2]; ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); ssl_x509_fingerprint_sha1(crt, newfpr); - sprintf(origfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + char *origfprstr, *newfprstr; + asprintf(&origfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - sprintf(newfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + asprintf(&newfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); - char *keyfn = malloc(strlen(ctx->opts->certgendir)+1+SSL_X509_FPRSZ*4+1+4); - char *crtfn = malloc(strlen(ctx->opts->certgendir)+1+SSL_X509_FPRSZ*4+1+4); - sprintf(keyfn, "%s/%s-%s.key", ctx->opts->certgendir, origfprstr, newfprstr); - sprintf(crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, origfprstr, newfprstr); + char *keyfn, *crtfn; + asprintf(&keyfn, "%s/%s-%s.key", ctx->opts->certgendir, origfprstr, newfprstr); + asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, origfprstr, newfprstr); FILE *keyfd, *crtfd; keyfd = fopen(keyfn, "w"); crtfd = fopen(crtfn, "w"); From 13dce0aa351dcb3f5717631d4c41dfbf647541c0 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 20:02:25 +0000 Subject: [PATCH 04/13] moved write to pxy_srccert_create, -X to -w, opts_free use --- main.c | 8 +++---- opts.c | 3 +++ pxyconn.c | 66 +++++++++++++++++++++++++++--------------------------- sslsplit.1 | 8 +++---- 4 files changed, 44 insertions(+), 41 deletions(-) diff --git a/main.c b/main.c index 799f487..d6d28ba 100644 --- a/main.c +++ b/main.c @@ -112,7 +112,7 @@ main_usage(void) " -k pemfile use CA key (and cert) from pemfile to sign forged certs\n" " -C pemfile use CA chain from pemfile (intermediate and root CA certs)\n" " -K pemfile use key from pemfile for leaf certs (default: generate)\n" -" -X gendir write generated key/cert pairs to gendir\n" +" -w gendir write generated key/cert pairs to gendir\n" " -t certdir use cert+chain+key PEM files from certdir to target all sites\n" " matching the common names (non-matching: generate if CA)\n" " -O deny all OCSP requests on all proxyspecs\n" @@ -276,7 +276,7 @@ main(int argc, char *argv[]) } while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z OPT_i - "k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:F:dDVhX:")) != -1) { + "k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:F:dDVhw:")) != -1) { switch (ch) { case 'c': if (opts->cacrt) @@ -520,7 +520,7 @@ main(int argc, char *argv[]) opts->contentlog_isdir = 0; opts->contentlog_isspec = 1; break; - case 'X': + case 'w': if (opts->certgendir) free(opts->certgendir); opts->certgendir = strdup(optarg); @@ -563,7 +563,7 @@ main(int argc, char *argv[]) exit(EXIT_FAILURE); } if (opts->certgendir && opts->key) { - fprintf(stderr, "%s: -K and -X are mutually exclusive.\n", + fprintf(stderr, "%s: -K and -w are mutually exclusive.\n", argv0); exit(EXIT_FAILURE); } diff --git a/opts.c b/opts.c index 0189af8..e21cc54 100644 --- a/opts.c +++ b/opts.c @@ -105,6 +105,9 @@ opts_free(opts_t *opts) if (opts->contentlog) { free(opts->contentlog); } + if (opts->certgendir) { + free(opts->certgendir); + } memset(opts, 0, sizeof(opts_t)); free(opts); } diff --git a/pxyconn.c b/pxyconn.c index 0180b94..6b4eae7 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -702,39 +702,6 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain, SSL_CTX_add_extra_chain_cert(sslctx, c); } - if (ctx->opts->certgendir) { - unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; - ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); - ssl_x509_fingerprint_sha1(crt, newfpr); - char *origfprstr, *newfprstr; - asprintf(&origfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], - origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], - origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], - origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - asprintf(&newfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], - newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], - newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], - newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); - char *keyfn, *crtfn; - asprintf(&keyfn, "%s/%s-%s.key", ctx->opts->certgendir, origfprstr, newfprstr); - asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, origfprstr, newfprstr); - FILE *keyfd, *crtfd; - keyfd = fopen(keyfn, "w"); - crtfd = fopen(crtfn, "w"); - if (keyfd) { - PEM_write_PrivateKey(keyfd, key, NULL, 0, 0, NULL, NULL); - fclose(keyfd); - } - if (crtfd) { - PEM_write_X509(crtfd, crt); - fclose(crtfd); - } - } - #ifdef DEBUG_SESSION_CACHE if (OPTS_DEBUG(ctx->opts)) { int mode = SSL_CTX_get_session_cache_mode(sslctx); @@ -831,6 +798,39 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) cert_set_chain(cert, ctx->opts->chain); } + if (ctx->opts->certgendir) { + unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; + ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); + ssl_x509_fingerprint_sha1(cert->crt, newfpr); + char *origfprstr, *newfprstr; + asprintf(&origfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], + origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], + origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], + origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); + asprintf(&newfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], + newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], + newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], + newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); + char *keyfn, *crtfn; + asprintf(&keyfn, "%s/%s-%s.key", ctx->opts->certgendir, origfprstr, newfprstr); + asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, origfprstr, newfprstr); + FILE *keyfd, *crtfd; + keyfd = fopen(keyfn, "w"); + crtfd = fopen(crtfn, "w"); + if (keyfd) { + PEM_write_PrivateKey(keyfd, cert->key, NULL, 0, 0, NULL, NULL); + fclose(keyfd); + } + if (crtfd) { + PEM_write_X509(crtfd, cert->crt); + fclose(crtfd); + } + } + return cert; } diff --git a/sslsplit.1 b/sslsplit.1 index 278a58b..a67ed38 100644 --- a/sslsplit.1 +++ b/sslsplit.1 @@ -30,15 +30,15 @@ sslsplit \-\- transparent and scalable SSL/TLS interception .SH SYNOPSIS .na .B sslsplit -[\fB-kCKXOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP +[\fB-kCKwOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fIproxyspecs\fP [...] .br .B sslsplit -[\fB-kCKXOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP +[\fB-kCKwOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP \fIproxyspecs\fP [...] .br .B sslsplit -[\fB-OPZXdDgGsrReumjplLSFi\fP] \fB-t\fP \fIdir\fP +[\fB-OPZwdDgGsrReumjplLSFi\fP] \fB-t\fP \fIdir\fP \fIproxyspecs\fP [...] .br .B sslsplit -E @@ -185,7 +185,7 @@ no matching certificate in the provided certificate directory. Use private key from \fIpemfile\fP for certificates forged on-the-fly. If \fB-K\fP is not given, SSLsplit will generate a random 1024-bit RSA key. .TP -.B \-X \fIgendir\fP +.B \-w \fIgendir\fP Write generated keys and certificates to individual files in \fIgendir\fP. .TP .B \-l \fIlogfile\fP From a7e2d99b39fd6e597345caf6a41baad9f948a4c7 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 21:13:04 +0000 Subject: [PATCH 05/13] added logging of fingerprints, uppercased names --- pxyconn.c | 60 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/pxyconn.c b/pxyconn.c index 6b4eae7..5d1a85f 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -357,6 +357,23 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) } #endif /* HAVE_LOCAL_PROCINFO */ + unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; + ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); + ssl_x509_fingerprint_sha1(SSL_get_certificate(ctx->src.ssl), newfpr); + char *origfprstr, *newfprstr; + asprintf(&origfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], + origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], + origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], + origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); + asprintf(&newfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], + newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], + newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], + newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); + if (!ctx->spec->ssl || ctx->passthrough) { rv = asprintf(&msg, "%s %s %s" #ifdef HAVE_LOCAL_PROCINFO @@ -377,7 +394,7 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "\n", + "%s%s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->sni), @@ -389,7 +406,9 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO , lpi #endif /* HAVE_LOCAL_PROCINFO */ - ); + , + ctx->opts->certgendir ? origfprstr : "", + ctx->opts->certgendir ? newfprstr : ""); } if ((rv < 0) || !msg) { ctx->enomem = 1; @@ -446,12 +465,29 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) } #endif /* HAVE_LOCAL_PROCINFO */ + unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; + ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); + ssl_x509_fingerprint_sha1(SSL_get_certificate(ctx->src.ssl), newfpr); + char *origfprstr, *newfprstr; + asprintf(&origfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], + origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], + origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], + origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); + asprintf(&newfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], + newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], + newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], + newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); + if (!ctx->spec->ssl) { rv = asprintf(&msg, "http %s %s %s %s %s %s %s" #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s\n", + "%s%s%s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->http_host), @@ -462,7 +498,9 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO lpi, #endif /* HAVE_LOCAL_PROCINFO */ - ctx->ocsp_denied ? " ocsp:denied" : ""); + ctx->ocsp_denied ? " ocsp:denied" : "", + ctx->opts->certgendir ? origfprstr : "", + ctx->opts->certgendir ? newfprstr : ""); } else { rv = asprintf(&msg, "https %s %s %s %s %s %s %s " "sni:%s names:%s " @@ -470,7 +508,7 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s\n", + "%s%s%s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->http_host), @@ -487,7 +525,9 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO lpi, #endif /* HAVE_LOCAL_PROCINFO */ - ctx->ocsp_denied ? " ocsp:denied" : ""); + ctx->ocsp_denied ? " ocsp:denied" : "", + ctx->opts->certgendir ? origfprstr : "", + ctx->opts->certgendir ? newfprstr : ""); } if ((rv < 0 ) || !msg) { ctx->enomem = 1; @@ -803,14 +843,14 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); ssl_x509_fingerprint_sha1(cert->crt, newfpr); char *origfprstr, *newfprstr; - asprintf(&origfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + asprintf(&origfprstr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - asprintf(&newfprstr,"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + asprintf(&newfprstr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], From 4f310a877a4aa5c4c21e8367ada86848d6a5b9f0 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 21:43:05 +0000 Subject: [PATCH 06/13] implemented -W to write original certs --- main.c | 12 +++++++++++- opts.h | 1 + pxyconn.c | 9 +++++++++ sslsplit.1 | 3 +++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index d6d28ba..037d7fd 100644 --- a/main.c +++ b/main.c @@ -113,6 +113,7 @@ main_usage(void) " -C pemfile use CA chain from pemfile (intermediate and root CA certs)\n" " -K pemfile use key from pemfile for leaf certs (default: generate)\n" " -w gendir write generated key/cert pairs to gendir\n" +" -W gendir same as -w but also write the original cert\n" " -t certdir use cert+chain+key PEM files from certdir to target all sites\n" " matching the common names (non-matching: generate if CA)\n" " -O deny all OCSP requests on all proxyspecs\n" @@ -276,7 +277,7 @@ main(int argc, char *argv[]) } while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z OPT_i - "k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:F:dDVhw:")) != -1) { + "k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:F:dDVhW:w:")) != -1) { switch (ch) { case 'c': if (opts->cacrt) @@ -520,7 +521,16 @@ main(int argc, char *argv[]) opts->contentlog_isdir = 0; opts->contentlog_isspec = 1; break; + case 'W': + opts->writeorig = 1; + if (opts->certgendir) + free(opts->certgendir); + opts->certgendir = strdup(optarg); + if (!opts->certgendir) + oom_die(argv0); + break; case 'w': + opts->writeorig = 0; if (opts->certgendir) free(opts->certgendir); opts->certgendir = strdup(optarg); diff --git a/opts.h b/opts.h index 6098b83..cfcd415 100644 --- a/opts.h +++ b/opts.h @@ -101,6 +101,7 @@ typedef struct opts { #endif /* !OPENSSL_NO_ECDH */ proxyspec_t *spec; char *certgendir; + unsigned int writeorig: 1; } opts_t; opts_t *opts_new(void) MALLOC; diff --git a/pxyconn.c b/pxyconn.c index 5d1a85f..2819332 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -869,6 +869,15 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) PEM_write_X509(crtfd, cert->crt); fclose(crtfd); } + if (ctx->opts->writeorig) { + char *origfn; + asprintf(&origfn, "%s/%s.crt", ctx->opts->certgendir, origfprstr); + FILE *origfd = fopen(origfn, "w"); + if (origfd) { + PEM_write_X509(origfd, ctx->origcrt); + fclose(origfd); + } + } } return cert; diff --git a/sslsplit.1 b/sslsplit.1 index a67ed38..fc73cce 100644 --- a/sslsplit.1 +++ b/sslsplit.1 @@ -188,6 +188,9 @@ If \fB-K\fP is not given, SSLsplit will generate a random 1024-bit RSA key. .B \-w \fIgendir\fP Write generated keys and certificates to individual files in \fIgendir\fP. .TP +.B \-W \fIgendir\fP +Same as -w, but also write original certificates +.TP .B \-l \fIlogfile\fP Log connections to \fIlogfile\fP in a single line per connection format, including addresses and ports and some HTTP and SSL information, if available. From 5d7c52cde14540264f6b7df9429539ab3a27db74 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 21:43:49 +0000 Subject: [PATCH 07/13] fix manpage --- sslsplit.1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sslsplit.1 b/sslsplit.1 index fc73cce..e698952 100644 --- a/sslsplit.1 +++ b/sslsplit.1 @@ -30,15 +30,15 @@ sslsplit \-\- transparent and scalable SSL/TLS interception .SH SYNOPSIS .na .B sslsplit -[\fB-kCKwOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP +[\fB-kCKwWOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fIproxyspecs\fP [...] .br .B sslsplit -[\fB-kCKwOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP +[\fB-kCKwWOPZdDgGsrReumjplLSFi\fP] \fB-c\fP \fIpem\fP \fB-t\fP \fIdir\fP \fIproxyspecs\fP [...] .br .B sslsplit -[\fB-OPZwdDgGsrReumjplLSFi\fP] \fB-t\fP \fIdir\fP +[\fB-OPZwWdDgGsrReumjplLSFi\fP] \fB-t\fP \fIdir\fP \fIproxyspecs\fP [...] .br .B sslsplit -E From 1736564b3212cffd3b12d7bca4cd78ba20ad1666 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Tue, 9 Dec 2014 23:26:00 +0000 Subject: [PATCH 08/13] error handling --- pxyconn.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pxyconn.c b/pxyconn.c index 2819332..e498696 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -864,10 +864,16 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) if (keyfd) { PEM_write_PrivateKey(keyfd, cert->key, NULL, 0, 0, NULL, NULL); fclose(keyfd); + } else { + log_err_printf("Failed to open '%s' for writing: %s\n", + keyfn, strerror(errno)); } if (crtfd) { PEM_write_X509(crtfd, cert->crt); fclose(crtfd); + } else { + log_err_printf("Failed to open '%s' for writing: %s\n", + keyfn, strerror(errno)); } if (ctx->opts->writeorig) { char *origfn; @@ -876,6 +882,9 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) if (origfd) { PEM_write_X509(origfd, ctx->origcrt); fclose(origfd); + } else { + log_err_printf("Failed to open '%s' for writing: %s\n", + keyfn, strerror(errno)); } } } From a83cd68605fbafd9848c3eadf6f002f87f40da26 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Thu, 11 Dec 2014 13:57:50 +0000 Subject: [PATCH 09/13] stored fpr as char* in ctx --- pxyconn.c | 92 ++++++++++++++++++------------------------------------- 1 file changed, 30 insertions(+), 62 deletions(-) diff --git a/pxyconn.c b/pxyconn.c index e498696..ae2f0b9 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -167,6 +167,8 @@ typedef struct pxy_conn_ctx { socklen_t addrlen; int af; X509 *origcrt; + char *origfpr[SSL_X509_FPRSZ*2+1]; + char *newfpr[SSL_X509_FPRSZ*2+1]; /* references to event base and configuration */ struct event_base *evbase; @@ -357,23 +359,6 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) } #endif /* HAVE_LOCAL_PROCINFO */ - unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; - ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); - ssl_x509_fingerprint_sha1(SSL_get_certificate(ctx->src.ssl), newfpr); - char *origfprstr, *newfprstr; - asprintf(&origfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], - origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], - origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], - origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - asprintf(&newfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], - newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], - newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], - newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); - if (!ctx->spec->ssl || ctx->passthrough) { rv = asprintf(&msg, "%s %s %s" #ifdef HAVE_LOCAL_PROCINFO @@ -394,7 +379,7 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s%s\n", + " %s %s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->sni), @@ -407,8 +392,8 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) , lpi #endif /* HAVE_LOCAL_PROCINFO */ , - ctx->opts->certgendir ? origfprstr : "", - ctx->opts->certgendir ? newfprstr : ""); + *ctx->origfpr, + *ctx->newfpr); } if ((rv < 0) || !msg) { ctx->enomem = 1; @@ -465,29 +450,12 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) } #endif /* HAVE_LOCAL_PROCINFO */ - unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; - ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); - ssl_x509_fingerprint_sha1(SSL_get_certificate(ctx->src.ssl), newfpr); - char *origfprstr, *newfprstr; - asprintf(&origfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], - origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], - origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], - origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - asprintf(&newfprstr," %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], - newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], - newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], - newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); - if (!ctx->spec->ssl) { rv = asprintf(&msg, "http %s %s %s %s %s %s %s" #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s%s%s\n", + "%s %s %s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->http_host), @@ -499,8 +467,8 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) lpi, #endif /* HAVE_LOCAL_PROCINFO */ ctx->ocsp_denied ? " ocsp:denied" : "", - ctx->opts->certgendir ? origfprstr : "", - ctx->opts->certgendir ? newfprstr : ""); + *ctx->origfpr, + *ctx->newfpr); } else { rv = asprintf(&msg, "https %s %s %s %s %s %s %s " "sni:%s names:%s " @@ -508,7 +476,7 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s%s%s\n", + "%s %s %s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->http_host), @@ -526,8 +494,8 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) lpi, #endif /* HAVE_LOCAL_PROCINFO */ ctx->ocsp_denied ? " ocsp:denied" : "", - ctx->opts->certgendir ? origfprstr : "", - ctx->opts->certgendir ? newfprstr : ""); + *ctx->origfpr, + *ctx->newfpr); } if ((rv < 0 ) || !msg) { ctx->enomem = 1; @@ -838,26 +806,26 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) cert_set_chain(cert, ctx->opts->chain); } + unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; + ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); + ssl_x509_fingerprint_sha1(cert->crt, newfpr); + asprintf(ctx->origfpr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], + origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], + origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], + origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); + asprintf(ctx->newfpr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], + newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], + newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], + newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); + if (ctx->opts->certgendir) { - unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; - ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); - ssl_x509_fingerprint_sha1(cert->crt, newfpr); - char *origfprstr, *newfprstr; - asprintf(&origfprstr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], - origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], - origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], - origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - asprintf(&newfprstr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], - newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], - newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], - newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); char *keyfn, *crtfn; - asprintf(&keyfn, "%s/%s-%s.key", ctx->opts->certgendir, origfprstr, newfprstr); - asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, origfprstr, newfprstr); + asprintf(&keyfn, "%s/%s-%s.key", ctx->opts->certgendir, *ctx->origfpr, *ctx->newfpr); + asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, *ctx->origfpr, *ctx->newfpr); FILE *keyfd, *crtfd; keyfd = fopen(keyfn, "w"); crtfd = fopen(crtfn, "w"); @@ -877,7 +845,7 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) } if (ctx->opts->writeorig) { char *origfn; - asprintf(&origfn, "%s/%s.crt", ctx->opts->certgendir, origfprstr); + asprintf(&origfn, "%s/%s.crt", ctx->opts->certgendir, *ctx->origfpr); FILE *origfd = fopen(origfn, "w"); if (origfd) { PEM_write_X509(origfd, ctx->origcrt); From 3aff928dafcfabb180d353dfa225b122601299b0 Mon Sep 17 00:00:00 2001 From: PsychoMario Date: Fri, 12 Dec 2014 17:28:06 +0000 Subject: [PATCH 10/13] moved key output to main.c, caught some bugs --- main.c | 24 ++++++++++++++++++++++++ pxyconn.c | 17 ++++------------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/main.c b/main.c index e8b9217..cf2a043 100644 --- a/main.c +++ b/main.c @@ -770,6 +770,30 @@ main(int argc, char *argv[]) } } + if (opts->certgendir) { + unsigned char *keyfpr = malloc(SSL_KEY_IDSZ); + if(ssl_key_identifier_sha1(opts->key, keyfpr)) { + fprintf(stderr, "%s: error generating RSA fingerprint\n", argv0); + exit(EXIT_FAILURE); + } + char *keyfn; + asprintf(&keyfn, "%s/%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X.key", + opts->certgendir, + keyfpr[0], keyfpr[1], keyfpr[2], keyfpr[3], keyfpr[4], + keyfpr[5], keyfpr[6], keyfpr[7], keyfpr[8], keyfpr[9], + keyfpr[10], keyfpr[11], keyfpr[12], keyfpr[13], keyfpr[14], + keyfpr[15], keyfpr[16], keyfpr[17], keyfpr[18], keyfpr[19]); + FILE *keyfd = fopen(keyfn,"w"); + if (!keyfd) { + log_err_printf("Failed to open '%s' for writing: %s\n", + keyfn, strerror(errno)); + } else { + PEM_write_PrivateKey(keyfd, opts->key, NULL, 0, 0, NULL, NULL); + fclose(keyfd); + } + } + /* usage checks after defaults */ if (opts->dropgroup && !opts->dropuser) { fprintf(stderr, "%s: -m depends on -u.\n", argv0); diff --git a/pxyconn.c b/pxyconn.c index ae2f0b9..91e5c7f 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -823,25 +823,16 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); if (ctx->opts->certgendir) { - char *keyfn, *crtfn; - asprintf(&keyfn, "%s/%s-%s.key", ctx->opts->certgendir, *ctx->origfpr, *ctx->newfpr); + char *crtfn; asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, *ctx->origfpr, *ctx->newfpr); - FILE *keyfd, *crtfd; - keyfd = fopen(keyfn, "w"); + FILE *crtfd; crtfd = fopen(crtfn, "w"); - if (keyfd) { - PEM_write_PrivateKey(keyfd, cert->key, NULL, 0, 0, NULL, NULL); - fclose(keyfd); - } else { - log_err_printf("Failed to open '%s' for writing: %s\n", - keyfn, strerror(errno)); - } if (crtfd) { PEM_write_X509(crtfd, cert->crt); fclose(crtfd); } else { log_err_printf("Failed to open '%s' for writing: %s\n", - keyfn, strerror(errno)); + crtfn, strerror(errno)); } if (ctx->opts->writeorig) { char *origfn; @@ -852,7 +843,7 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) fclose(origfd); } else { log_err_printf("Failed to open '%s' for writing: %s\n", - keyfn, strerror(errno)); + origfn, strerror(errno)); } } } From 7f378251e8d314f7bf78cccf8ef144f1feff7a4b Mon Sep 17 00:00:00 2001 From: Daniel Roethlisberger Date: Fri, 12 Dec 2014 23:22:11 +0100 Subject: [PATCH 11/13] Update documentation --- AUTHORS.md | 1 + NEWS.md | 5 +++++ sslsplit.1 | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/AUTHORS.md b/AUTHORS.md index 1307485..d0185ee 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -9,6 +9,7 @@ patches or pull requests, in chronological order of their first contribution: - Steve Wills ([swills](https://github.com/swills)) - Landon Fuller ([landonf](https://github.com/landonf)) - Wayne Jensen ([wjjensen](https://github.com/wjjensen)) +- Rory McNamara ([psychomario](https://github.com/psychomario)) Many more individuals have contributed by reporting bugs or feature requests. See [issue tracker on Github][1], `NEWS.md` and `git log` for details. diff --git a/NEWS.md b/NEWS.md index 3909b48..1a65fc2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,4 +1,9 @@ +### SSLsplit feature/genstore + +- Add options -w and -W to write generated leaf key, original and forged + certificates to disk (issue #67 by @psychomario). + ### SSLsplit develop - Add signal SIGUSR1 to re-open long-living -l/-L log files (issue #52). diff --git a/sslsplit.1 b/sslsplit.1 index c17a63d..649bc47 100644 --- a/sslsplit.1 +++ b/sslsplit.1 @@ -662,7 +662,7 @@ SSLsplit was written by Daniel Roethlisberger . The following individuals have contributed to the codebase, in chronological order of their first contribution: -Steve Wills, Landon Fuller and Wayne Jensen. +Steve Wills, Landon Fuller, Wayne Jensen and Rory McNamara. .SH BUGS Use Github for submission of bug reports or patches: .LP From 11f6742bfff122f48bc4cf323e085574c5382d8b Mon Sep 17 00:00:00 2001 From: Daniel Roethlisberger Date: Fri, 12 Dec 2014 23:50:55 +0100 Subject: [PATCH 12/13] Add convenience functions for printing SHA1 values --- ssl.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ ssl.h | 4 ++++ 2 files changed, 58 insertions(+) diff --git a/ssl.c b/ssl.c index a669010..4fbca06 100644 --- a/ssl.c +++ b/ssl.c @@ -421,6 +421,30 @@ ssl_fini(void) CRYPTO_cleanup_all_ex_data(); } +/* + * Format SHA1 hash into newly allocated string, with or without colons. + */ +char * +ssl_sha1_to_str(unsigned char *sha1, int colons) +{ + char *str; + int rv; + + rv = asprintf(&str, colons ? + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X" + "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X" : + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + sha1[ 0], sha1[ 1], sha1[ 2], sha1[ 3], + sha1[ 4], sha1[ 5], sha1[ 6], sha1[ 7], + sha1[ 8], sha1[ 9], sha1[10], sha1[11], + sha1[12], sha1[13], sha1[14], sha1[15], + sha1[16], sha1[17], sha1[18], sha1[19]); + if (rv == -1) + return NULL; + return str; +} + /* * Format SSL state into newly allocated string. * Returns pointer to string that must be freed by caller, or NULL on error. @@ -1058,6 +1082,21 @@ errout: return -1; } +/* + * Returns the result of ssl_key_identifier_sha1() as hex characters with or + * without colons in a newly allocated string. + */ +char * +ssl_key_identifier(EVP_PKEY *key, int colons) +{ + unsigned char id[SSL_KEY_IDSZ]; + + if (ssl_key_identifier_sha1(key, id) == -1) + return NULL; + + return ssl_sha1_to_str(id, colons); +} + /* * Returns the one-line representation of the subject DN in a newly allocated * string which must be freed by the caller. @@ -1107,6 +1146,21 @@ ssl_x509_fingerprint_sha1(X509 *crt, unsigned char *fpr) return X509_digest(crt, EVP_sha1(), fpr, &sz) ? 0 : -1; } +/* + * Returns the result of ssl_x509_fingerprint_sha1() as hex characters with or + * without colons in a newly allocated string. + */ +char * +ssl_x509_fingerprint(X509 *crt, int colons) +{ + unsigned char fpr[SSL_X509_FPRSZ]; + + if (ssl_x509_fingerprint_sha1(crt, fpr) == -1) + return NULL; + + return ssl_sha1_to_str(fpr, colons); +} + #ifndef OPENSSL_NO_DH /* * Increment the reference count of DH parameters in a thread-safe diff --git a/ssl.h b/ssl.h index 8913fea..6af426f 100644 --- a/ssl.h +++ b/ssl.h @@ -113,6 +113,8 @@ int ssl_init(void) WUNRES; void ssl_reinit(void); void ssl_fini(void); +char * ssl_sha1_to_str(unsigned char *, int) NONNULL(1) MALLOC; + char * ssl_ssl_state_to_str(SSL *) NONNULL(1) MALLOC; #ifndef OPENSSL_NO_DH @@ -130,6 +132,7 @@ EVP_PKEY * ssl_key_genrsa(const int) MALLOC; void ssl_key_refcount_inc(EVP_PKEY *) NONNULL(1); #define SSL_KEY_IDSZ 20 int ssl_key_identifier_sha1(EVP_PKEY *, unsigned char *) NONNULL(1,2); +char * ssl_key_identifier(EVP_PKEY *, int) NONNULL(1) MALLOC; #ifndef OPENSSL_NO_TLSEXT int ssl_x509_v3ext_add(X509V3_CTX *, X509 *, char *, char *) NONNULL(1,2,3,4); @@ -143,6 +146,7 @@ char * ssl_x509_subject(X509 *) NONNULL(1) MALLOC; char * ssl_x509_subject_cn(X509 *, size_t *) NONNULL(1,2) MALLOC; #define SSL_X509_FPRSZ 20 int ssl_x509_fingerprint_sha1(X509 *, unsigned char *) NONNULL(1,2); +char * ssl_x509_fingerprint(X509 *, int) NONNULL(1) MALLOC; char ** ssl_x509_names(X509 *) NONNULL(1) MALLOC; int ssl_x509_names_match(X509 *, const char *) NONNULL(1,2); char * ssl_x509_names_to_str(X509 *) NONNULL(1) MALLOC; From 6ec6c56ded8ed10e23882bff0eb49b9f365da93f Mon Sep 17 00:00:00 2001 From: Daniel Roethlisberger Date: Sat, 13 Dec 2014 02:36:45 +0100 Subject: [PATCH 13/13] Refactored -w/-W and improved docs --- main.c | 59 +++++++++-------- opts.h | 4 +- pxyconn.c | 188 +++++++++++++++++++++++++++++++++-------------------- sslsplit.1 | 19 ++++-- 4 files changed, 165 insertions(+), 105 deletions(-) diff --git a/main.c b/main.c index cf2a043..b4db01f 100644 --- a/main.c +++ b/main.c @@ -115,10 +115,10 @@ main_usage(void) " -k pemfile use CA key (and cert) from pemfile to sign forged certs\n" " -C pemfile use CA chain from pemfile (intermediate and root CA certs)\n" " -K pemfile use key from pemfile for leaf certs (default: generate)\n" -" -w gendir write generated key/cert pairs to gendir\n" -" -W gendir same as -w but also write the original cert\n" " -t certdir use cert+chain+key PEM files from certdir to target all sites\n" " matching the common names (non-matching: generate if CA)\n" +" -w gendir write leaf key and only generated certificates to gendir\n" +" -W gendir write leaf key and all certificates to gendir\n" " -O deny all OCSP requests on all proxyspecs\n" " -P passthrough SSL connections if they cannot be split because of\n" " client cert auth or no matching cert and no CA (default: drop)\n" @@ -618,7 +618,7 @@ main(int argc, char *argv[]) free(rhs); break; case 'W': - opts->writeorig = 1; + opts->certgen_writeall = 1; if (opts->certgendir) free(opts->certgendir); opts->certgendir = strdup(optarg); @@ -626,7 +626,7 @@ main(int argc, char *argv[]) oom_die(argv0); break; case 'w': - opts->writeorig = 0; + opts->certgen_writeall = 0; if (opts->certgendir) free(opts->certgendir); opts->certgendir = strdup(optarg); @@ -669,11 +669,6 @@ main(int argc, char *argv[]) argv0); exit(EXIT_FAILURE); } - if (opts->certgendir && opts->key) { - fprintf(stderr, "%s: -K and -w are mutually exclusive.\n", - argv0); - exit(EXIT_FAILURE); - } if (!opts->spec) { fprintf(stderr, "%s: no proxyspec specified.\n", argv0); exit(EXIT_FAILURE); @@ -771,27 +766,37 @@ main(int argc, char *argv[]) } if (opts->certgendir) { - unsigned char *keyfpr = malloc(SSL_KEY_IDSZ); - if(ssl_key_identifier_sha1(opts->key, keyfpr)) { - fprintf(stderr, "%s: error generating RSA fingerprint\n", argv0); + char *keyid, *keyfn; + int prv; + FILE *keyf; + + keyid = ssl_key_identifier(opts->key, 0); + if (!keyid) { + fprintf(stderr, "%s: error generating key id\n", argv0); exit(EXIT_FAILURE); } - char *keyfn; - asprintf(&keyfn, "%s/%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X.key", - opts->certgendir, - keyfpr[0], keyfpr[1], keyfpr[2], keyfpr[3], keyfpr[4], - keyfpr[5], keyfpr[6], keyfpr[7], keyfpr[8], keyfpr[9], - keyfpr[10], keyfpr[11], keyfpr[12], keyfpr[13], keyfpr[14], - keyfpr[15], keyfpr[16], keyfpr[17], keyfpr[18], keyfpr[19]); - FILE *keyfd = fopen(keyfn,"w"); - if (!keyfd) { - log_err_printf("Failed to open '%s' for writing: %s\n", - keyfn, strerror(errno)); - } else { - PEM_write_PrivateKey(keyfd, opts->key, NULL, 0, 0, NULL, NULL); - fclose(keyfd); + + prv = asprintf(&keyfn, "%s/%s.key", opts->certgendir, keyid); + if (prv == -1) { + fprintf(stderr, "%s: %s (%i)\n", argv0, + strerror(errno), errno); + exit(EXIT_FAILURE); + } + + if (!(keyf = fopen(keyfn, "w"))) { + fprintf(stderr, "%s: Failed to open '%s' for writing: " + "%s (%i)\n", argv0, keyfn, + strerror(errno), errno); + exit(EXIT_FAILURE); + } + if (!PEM_write_PrivateKey(keyf, opts->key, NULL, 0, 0, + NULL, NULL)) { + fprintf(stderr, "%s: Failed to write key to '%s': " + "%s (%i)\n", argv0, keyfn, + strerror(errno), errno); + exit(EXIT_FAILURE); } + fclose(keyf); } /* usage checks after defaults */ diff --git a/opts.h b/opts.h index 0279376..af6e215 100644 --- a/opts.h +++ b/opts.h @@ -80,7 +80,9 @@ typedef struct opts { #ifdef HAVE_LOCAL_PROCINFO unsigned int lprocinfo : 1; #endif /* HAVE_LOCAL_PROCINFO */ + unsigned int certgen_writeall: 1; char *ciphers; + char *certgendir; char *tgcrtdir; char *dropuser; char *dropgroup; @@ -101,8 +103,6 @@ typedef struct opts { char *ecdhcurve; #endif /* !OPENSSL_NO_ECDH */ proxyspec_t *spec; - char *certgendir; - unsigned int writeorig: 1; } opts_t; opts_t *opts_new(void) MALLOC; diff --git a/pxyconn.c b/pxyconn.c index 91e5c7f..c49ed73 100644 --- a/pxyconn.c +++ b/pxyconn.c @@ -40,6 +40,7 @@ #include "attrib.h" #include "proc.h" +#include #include #include #include @@ -120,6 +121,7 @@ typedef struct pxy_conn_ctx { /* status flags */ unsigned int immutable_cert : 1; /* 1 if the cert cannot be changed */ + unsigned int generated_cert : 1; /* 1 if we generated a new cert */ unsigned int connected : 1; /* 0 until both ends are connected */ unsigned int seen_req_header : 1; /* 0 until request header complete */ unsigned int seen_resp_header : 1; /* 0 until response hdr complete */ @@ -147,8 +149,10 @@ typedef struct pxy_conn_ctx { char *http_status_text; char *http_content_length; - /* log strings from SSL context */ + /* log strings related to SSL */ char *ssl_names; + char *origcrtfpr; + char *usedcrtfpr; #ifdef HAVE_LOCAL_PROCINFO /* local process information */ @@ -167,8 +171,6 @@ typedef struct pxy_conn_ctx { socklen_t addrlen; int af; X509 *origcrt; - char *origfpr[SSL_X509_FPRSZ*2+1]; - char *newfpr[SSL_X509_FPRSZ*2+1]; /* references to event base and configuration */ struct event_base *evbase; @@ -211,9 +213,7 @@ pxy_conn_ctx_new(proxyspec_t *spec, opts_t *opts, return ctx; } -static void -pxy_conn_ctx_free(pxy_conn_ctx_t *ctx) NONNULL(1); -static void +static void NONNULL(1) pxy_conn_ctx_free(pxy_conn_ctx_t *ctx) { #ifdef DEBUG_PROXY @@ -253,6 +253,12 @@ pxy_conn_ctx_free(pxy_conn_ctx_t *ctx) if (ctx->ssl_names) { free(ctx->ssl_names); } + if (ctx->origcrtfpr) { + free(ctx->origcrtfpr); + } + if (ctx->usedcrtfpr) { + free(ctx->usedcrtfpr); + } #ifdef HAVE_LOCAL_PROCINFO if (ctx->lproc.exec_path) { free(ctx->lproc.exec_path); @@ -314,17 +320,11 @@ pxy_debug_crt(X509 *crt) free(names); } - unsigned char fpr[SSL_X509_FPRSZ]; - if (ssl_x509_fingerprint_sha1(crt, fpr) == -1) { + char *fpr; + if (!(fpr = ssl_x509_fingerprint(crt, 1))) { log_err_printf("Warning: Error generating X509 fingerprint\n"); } else { - log_dbg_printf("Fingerprint: " "%02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - fpr[0], fpr[1], fpr[2], fpr[3], fpr[4], - fpr[5], fpr[6], fpr[7], fpr[8], fpr[9], - fpr[10], fpr[11], fpr[12], fpr[13], fpr[14], - fpr[15], fpr[16], fpr[17], fpr[18], fpr[19]); + log_dbg_printf("Fingerprint: %s\n", fpr); } #ifdef DEBUG_CERTIFICATE @@ -375,11 +375,12 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) } else { rv = asprintf(&msg, "ssl %s %s " "sni:%s names:%s " - "sproto:%s:%s dproto:%s:%s" + "sproto:%s:%s dproto:%s:%s " + "origcrt:%s usedcrt:%s" #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - " %s %s\n", + "\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->sni), @@ -387,13 +388,13 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx) SSL_get_version(ctx->src.ssl), SSL_get_cipher(ctx->src.ssl), SSL_get_version(ctx->dst.ssl), - SSL_get_cipher(ctx->dst.ssl) + SSL_get_cipher(ctx->dst.ssl), + STRORDASH(ctx->origcrtfpr), + STRORDASH(ctx->usedcrtfpr) #ifdef HAVE_LOCAL_PROCINFO , lpi #endif /* HAVE_LOCAL_PROCINFO */ - , - *ctx->origfpr, - *ctx->newfpr); + ); } if ((rv < 0) || !msg) { ctx->enomem = 1; @@ -455,7 +456,7 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s %s %s\n", + "%s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->http_host), @@ -466,17 +467,16 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) #ifdef HAVE_LOCAL_PROCINFO lpi, #endif /* HAVE_LOCAL_PROCINFO */ - ctx->ocsp_denied ? " ocsp:denied" : "", - *ctx->origfpr, - *ctx->newfpr); + ctx->ocsp_denied ? " ocsp:denied" : ""); } else { rv = asprintf(&msg, "https %s %s %s %s %s %s %s " "sni:%s names:%s " - "sproto:%s:%s dproto:%s:%s" + "sproto:%s:%s dproto:%s:%s " + "origcrt:%s usedcrt:%s" #ifdef HAVE_LOCAL_PROCINFO " %s" #endif /* HAVE_LOCAL_PROCINFO */ - "%s %s %s\n", + "%s\n", STRORDASH(ctx->src_str), STRORDASH(ctx->dst_str), STRORDASH(ctx->http_host), @@ -490,12 +490,12 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx) SSL_get_cipher(ctx->src.ssl), SSL_get_version(ctx->dst.ssl), SSL_get_cipher(ctx->dst.ssl), + STRORDASH(ctx->origcrtfpr), + STRORDASH(ctx->usedcrtfpr), #ifdef HAVE_LOCAL_PROCINFO lpi, #endif /* HAVE_LOCAL_PROCINFO */ - ctx->ocsp_denied ? " ocsp:denied" : "", - *ctx->origfpr, - *ctx->newfpr); + ctx->ocsp_denied ? " ocsp:denied" : ""); } if ((rv < 0 ) || !msg) { ctx->enomem = 1; @@ -732,6 +732,66 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain, return sslctx; } +static int +pxy_srccert_write_to_gendir(pxy_conn_ctx_t *ctx, X509 *crt, int is_orig) +{ + char *fn; + int rv; + struct stat sb; + FILE *f; + + if (!ctx->origcrtfpr) + return -1; + if (is_orig) { + rv = asprintf(&fn, "%s/%s.crt", ctx->opts->certgendir, + ctx->origcrtfpr); + } else { + if (!ctx->usedcrtfpr) + return -1; + rv = asprintf(&fn, "%s/%s-%s.crt", ctx->opts->certgendir, + ctx->origcrtfpr, ctx->usedcrtfpr); + } + if (rv == -1) { + ctx->enomem = 1; + return -1; + } + if (stat(fn, &sb) == 0) { + free(fn); + return 0; + } + if (!(f = fopen(fn, "w"))) { + log_err_printf("Failed to open '%s' for writing: %s (%i)\n", + fn, strerror(errno), errno); + free(fn); + return -1; + } + if (!PEM_write_X509(f, crt)) { + log_err_printf("Failed to write certificate to '%s'\n", fn); + fclose(f); + free(fn); + return -1; + } + fclose(f); + free(fn); + return 0; +} + +static void +pxy_srccert_write(pxy_conn_ctx_t *ctx) +{ + if (ctx->opts->certgen_writeall || ctx->generated_cert) { + if (pxy_srccert_write_to_gendir(ctx, + SSL_get_certificate(ctx->src.ssl), 0) == -1) { + log_err_printf("Failed to write used certificate\n"); + } + } + if (ctx->opts->certgen_writeall) { + if (pxy_srccert_write_to_gendir(ctx, ctx->origcrt, 1) == -1) { + log_err_printf("Failed to write orig certificate\n"); + } + } +} + static cert_t * pxy_srccert_create(pxy_conn_ctx_t *ctx) { @@ -804,48 +864,19 @@ pxy_srccert_create(pxy_conn_ctx_t *ctx) } cert_set_key(cert, ctx->opts->key); cert_set_chain(cert, ctx->opts->chain); + ctx->generated_cert = 1; } - unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; - ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); - ssl_x509_fingerprint_sha1(cert->crt, newfpr); - asprintf(ctx->origfpr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], - origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], - origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], - origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); - asprintf(ctx->newfpr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - newfpr[0], newfpr[1], newfpr[2], newfpr[3], newfpr[4], - newfpr[5], newfpr[6], newfpr[7], newfpr[8], newfpr[9], - newfpr[10], newfpr[11], newfpr[12], newfpr[13], newfpr[14], - newfpr[15], newfpr[16], newfpr[17], newfpr[18], newfpr[19]); - - if (ctx->opts->certgendir) { - char *crtfn; - asprintf(&crtfn, "%s/%s-%s.crt", ctx->opts->certgendir, *ctx->origfpr, *ctx->newfpr); - FILE *crtfd; - crtfd = fopen(crtfn, "w"); - if (crtfd) { - PEM_write_X509(crtfd, cert->crt); - fclose(crtfd); - } else { - log_err_printf("Failed to open '%s' for writing: %s\n", - crtfn, strerror(errno)); - } - if (ctx->opts->writeorig) { - char *origfn; - asprintf(&origfn, "%s/%s.crt", ctx->opts->certgendir, *ctx->origfpr); - FILE *origfd = fopen(origfn, "w"); - if (origfd) { - PEM_write_X509(origfd, ctx->origcrt); - fclose(origfd); - } else { - log_err_printf("Failed to open '%s' for writing: %s\n", - origfn, strerror(errno)); - } - } + if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) && ctx->origcrt) { + ctx->origcrtfpr = ssl_x509_fingerprint(ctx->origcrt, 0); + if (!ctx->origcrtfpr) + ctx->enomem = 1; + } + if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) && + cert && cert->crt) { + ctx->usedcrtfpr = ssl_x509_fingerprint(cert->crt, 0); + if (!ctx->usedcrtfpr) + ctx->enomem = 1; } return cert; @@ -969,6 +1000,7 @@ pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg) return SSL_TLSEXT_ERR_NOACK; } cachemgr_fkcrt_set(ctx->origcrt, newcrt); + ctx->generated_cert = 1; if (OPTS_DEBUG(ctx->opts)) { log_dbg_printf("===> Updated forged server " "certificate:\n"); @@ -983,6 +1015,16 @@ pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg) ctx->enomem = 1; } } + if (WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) { + if (ctx->usedcrtfpr) { + free(ctx->usedcrtfpr); + } + ctx->usedcrtfpr = ssl_x509_fingerprint(newcrt, 0); + if (!ctx->usedcrtfpr) { + ctx->enomem = 1; + } + } + newsslctx = pxy_srcsslctx_create(ctx, newcrt, ctx->opts->chain, ctx->opts->key); if (!newsslctx) { @@ -1810,6 +1852,12 @@ connected: pxy_log_connect_nonhttp(ctx); } + /* write SSL certificates to gendir */ + if (this->ssl && (bev == ctx->src.bev) && + ctx->opts->certgendir) { + pxy_srccert_write(ctx); + } + if (OPTS_DEBUG(ctx->opts)) { if (this->ssl) { /* for SSL, we get two connect events */ diff --git a/sslsplit.1 b/sslsplit.1 index 649bc47..172d857 100644 --- a/sslsplit.1 +++ b/sslsplit.1 @@ -181,12 +181,6 @@ no matching certificate in the provided certificate directory. Use private key from \fIpemfile\fP for certificates forged on-the-fly. If \fB-K\fP is not given, SSLsplit will generate a random 1024-bit RSA key. .TP -.B \-w \fIgendir\fP -Write generated keys and certificates to individual files in \fIgendir\fP. -.TP -.B \-W \fIgendir\fP -Same as -w, but also write original certificates -.TP .B \-l \fIlogfile\fP Log connections to \fIlogfile\fP in a single line per connection format, including addresses and ports and some HTTP and SSL information, if available. @@ -297,6 +291,19 @@ Mac OS X. .B \-V Display version and compiled features information and exit. .TP +.B \-w \fIgendir\fP +Write generated keys and certificates to individual files in \fIgendir\fP. +For keys, the key identifier is used as filename, which consists of the SHA-1 +hash of the ASN.1 bit string of the public key, as referenced by the +subjectKeyIdentifier extension in certificates. +For certificates, the SHA-1 fingerprints of the original and the used (forged) +certificate are combined to form the filename. +Note that only newly generated certificates are written to disk. +.TP +.B \-W \fIgendir\fP +Same as \fB-w\fP, but also write original certificates and certificates not +newly generated, such as those loaded from \fB-t\fP. +.TP .B \-Z Disable SSL/TLS compression on all connections. This is useful if your limiting factor is CPU, not network bandwidth.