Refactored -w/-W and improved docs

pull/13/head
Daniel Roethlisberger 10 years ago
parent 11f6742bff
commit 6ec6c56ded

@ -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 */

@ -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;

@ -40,6 +40,7 @@
#include "attrib.h"
#include "proc.h"
#include <sys/stat.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <stdio.h>
@ -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 */

@ -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.

Loading…
Cancel
Save