Refactored -w/-W and improved docs

This commit is contained in:
Daniel Roethlisberger 2014-12-13 02:36:45 +01:00
parent 11f6742bff
commit 6ec6c56ded
4 changed files with 165 additions and 105 deletions

59
main.c
View File

@ -115,10 +115,10 @@ main_usage(void)
" -k pemfile use CA key (and cert) from pemfile to sign forged certs\n" " -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" " -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" " -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" " -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" " 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" " -O deny all OCSP requests on all proxyspecs\n"
" -P passthrough SSL connections if they cannot be split because of\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" " client cert auth or no matching cert and no CA (default: drop)\n"
@ -618,7 +618,7 @@ main(int argc, char *argv[])
free(rhs); free(rhs);
break; break;
case 'W': case 'W':
opts->writeorig = 1; opts->certgen_writeall = 1;
if (opts->certgendir) if (opts->certgendir)
free(opts->certgendir); free(opts->certgendir);
opts->certgendir = strdup(optarg); opts->certgendir = strdup(optarg);
@ -626,7 +626,7 @@ main(int argc, char *argv[])
oom_die(argv0); oom_die(argv0);
break; break;
case 'w': case 'w':
opts->writeorig = 0; opts->certgen_writeall = 0;
if (opts->certgendir) if (opts->certgendir)
free(opts->certgendir); free(opts->certgendir);
opts->certgendir = strdup(optarg); opts->certgendir = strdup(optarg);
@ -669,11 +669,6 @@ main(int argc, char *argv[])
argv0); argv0);
exit(EXIT_FAILURE); 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) { if (!opts->spec) {
fprintf(stderr, "%s: no proxyspec specified.\n", argv0); fprintf(stderr, "%s: no proxyspec specified.\n", argv0);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -771,27 +766,37 @@ main(int argc, char *argv[])
} }
if (opts->certgendir) { if (opts->certgendir) {
unsigned char *keyfpr = malloc(SSL_KEY_IDSZ); char *keyid, *keyfn;
if(ssl_key_identifier_sha1(opts->key, keyfpr)) { int prv;
fprintf(stderr, "%s: error generating RSA fingerprint\n", argv0); FILE *keyf;
keyid = ssl_key_identifier(opts->key, 0);
if (!keyid) {
fprintf(stderr, "%s: error generating key id\n", argv0);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
char *keyfn;
asprintf(&keyfn, "%s/%02X%02X%02X%02X%02X%02X%02X%02X%02X" prv = asprintf(&keyfn, "%s/%s.key", opts->certgendir, keyid);
"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X.key", if (prv == -1) {
opts->certgendir, fprintf(stderr, "%s: %s (%i)\n", argv0,
keyfpr[0], keyfpr[1], keyfpr[2], keyfpr[3], keyfpr[4], strerror(errno), errno);
keyfpr[5], keyfpr[6], keyfpr[7], keyfpr[8], keyfpr[9], exit(EXIT_FAILURE);
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);
} }
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 */ /* usage checks after defaults */

4
opts.h
View File

@ -80,7 +80,9 @@ typedef struct opts {
#ifdef HAVE_LOCAL_PROCINFO #ifdef HAVE_LOCAL_PROCINFO
unsigned int lprocinfo : 1; unsigned int lprocinfo : 1;
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
unsigned int certgen_writeall: 1;
char *ciphers; char *ciphers;
char *certgendir;
char *tgcrtdir; char *tgcrtdir;
char *dropuser; char *dropuser;
char *dropgroup; char *dropgroup;
@ -101,8 +103,6 @@ typedef struct opts {
char *ecdhcurve; char *ecdhcurve;
#endif /* !OPENSSL_NO_ECDH */ #endif /* !OPENSSL_NO_ECDH */
proxyspec_t *spec; proxyspec_t *spec;
char *certgendir;
unsigned int writeorig: 1;
} opts_t; } opts_t;
opts_t *opts_new(void) MALLOC; opts_t *opts_new(void) MALLOC;

188
pxyconn.c
View File

@ -40,6 +40,7 @@
#include "attrib.h" #include "attrib.h"
#include "proc.h" #include "proc.h"
#include <sys/stat.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -120,6 +121,7 @@ typedef struct pxy_conn_ctx {
/* status flags */ /* status flags */
unsigned int immutable_cert : 1; /* 1 if the cert cannot be changed */ 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 connected : 1; /* 0 until both ends are connected */
unsigned int seen_req_header : 1; /* 0 until request header complete */ unsigned int seen_req_header : 1; /* 0 until request header complete */
unsigned int seen_resp_header : 1; /* 0 until response hdr 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_status_text;
char *http_content_length; char *http_content_length;
/* log strings from SSL context */ /* log strings related to SSL */
char *ssl_names; char *ssl_names;
char *origcrtfpr;
char *usedcrtfpr;
#ifdef HAVE_LOCAL_PROCINFO #ifdef HAVE_LOCAL_PROCINFO
/* local process information */ /* local process information */
@ -167,8 +171,6 @@ typedef struct pxy_conn_ctx {
socklen_t addrlen; socklen_t addrlen;
int af; int af;
X509 *origcrt; X509 *origcrt;
char *origfpr[SSL_X509_FPRSZ*2+1];
char *newfpr[SSL_X509_FPRSZ*2+1];
/* references to event base and configuration */ /* references to event base and configuration */
struct event_base *evbase; struct event_base *evbase;
@ -211,9 +213,7 @@ pxy_conn_ctx_new(proxyspec_t *spec, opts_t *opts,
return ctx; return ctx;
} }
static void static void NONNULL(1)
pxy_conn_ctx_free(pxy_conn_ctx_t *ctx) NONNULL(1);
static void
pxy_conn_ctx_free(pxy_conn_ctx_t *ctx) pxy_conn_ctx_free(pxy_conn_ctx_t *ctx)
{ {
#ifdef DEBUG_PROXY #ifdef DEBUG_PROXY
@ -253,6 +253,12 @@ pxy_conn_ctx_free(pxy_conn_ctx_t *ctx)
if (ctx->ssl_names) { if (ctx->ssl_names) {
free(ctx->ssl_names); free(ctx->ssl_names);
} }
if (ctx->origcrtfpr) {
free(ctx->origcrtfpr);
}
if (ctx->usedcrtfpr) {
free(ctx->usedcrtfpr);
}
#ifdef HAVE_LOCAL_PROCINFO #ifdef HAVE_LOCAL_PROCINFO
if (ctx->lproc.exec_path) { if (ctx->lproc.exec_path) {
free(ctx->lproc.exec_path); free(ctx->lproc.exec_path);
@ -314,17 +320,11 @@ pxy_debug_crt(X509 *crt)
free(names); free(names);
} }
unsigned char fpr[SSL_X509_FPRSZ]; char *fpr;
if (ssl_x509_fingerprint_sha1(crt, fpr) == -1) { if (!(fpr = ssl_x509_fingerprint(crt, 1))) {
log_err_printf("Warning: Error generating X509 fingerprint\n"); log_err_printf("Warning: Error generating X509 fingerprint\n");
} else { } else {
log_dbg_printf("Fingerprint: " "%02x:%02x:%02x:%02x:" log_dbg_printf("Fingerprint: %s\n", fpr);
"%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]);
} }
#ifdef DEBUG_CERTIFICATE #ifdef DEBUG_CERTIFICATE
@ -375,11 +375,12 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx)
} else { } else {
rv = asprintf(&msg, "ssl %s %s " rv = asprintf(&msg, "ssl %s %s "
"sni:%s names:%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 #ifdef HAVE_LOCAL_PROCINFO
" %s" " %s"
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
" %s %s\n", "\n",
STRORDASH(ctx->src_str), STRORDASH(ctx->src_str),
STRORDASH(ctx->dst_str), STRORDASH(ctx->dst_str),
STRORDASH(ctx->sni), STRORDASH(ctx->sni),
@ -387,13 +388,13 @@ pxy_log_connect_nonhttp(pxy_conn_ctx_t *ctx)
SSL_get_version(ctx->src.ssl), SSL_get_version(ctx->src.ssl),
SSL_get_cipher(ctx->src.ssl), SSL_get_cipher(ctx->src.ssl),
SSL_get_version(ctx->dst.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 #ifdef HAVE_LOCAL_PROCINFO
, lpi , lpi
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
, );
*ctx->origfpr,
*ctx->newfpr);
} }
if ((rv < 0) || !msg) { if ((rv < 0) || !msg) {
ctx->enomem = 1; ctx->enomem = 1;
@ -455,7 +456,7 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx)
#ifdef HAVE_LOCAL_PROCINFO #ifdef HAVE_LOCAL_PROCINFO
" %s" " %s"
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
"%s %s %s\n", "%s\n",
STRORDASH(ctx->src_str), STRORDASH(ctx->src_str),
STRORDASH(ctx->dst_str), STRORDASH(ctx->dst_str),
STRORDASH(ctx->http_host), STRORDASH(ctx->http_host),
@ -466,17 +467,16 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx)
#ifdef HAVE_LOCAL_PROCINFO #ifdef HAVE_LOCAL_PROCINFO
lpi, lpi,
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
ctx->ocsp_denied ? " ocsp:denied" : "", ctx->ocsp_denied ? " ocsp:denied" : "");
*ctx->origfpr,
*ctx->newfpr);
} else { } else {
rv = asprintf(&msg, "https %s %s %s %s %s %s %s " rv = asprintf(&msg, "https %s %s %s %s %s %s %s "
"sni:%s names:%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 #ifdef HAVE_LOCAL_PROCINFO
" %s" " %s"
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
"%s %s %s\n", "%s\n",
STRORDASH(ctx->src_str), STRORDASH(ctx->src_str),
STRORDASH(ctx->dst_str), STRORDASH(ctx->dst_str),
STRORDASH(ctx->http_host), 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_cipher(ctx->src.ssl),
SSL_get_version(ctx->dst.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 #ifdef HAVE_LOCAL_PROCINFO
lpi, lpi,
#endif /* HAVE_LOCAL_PROCINFO */ #endif /* HAVE_LOCAL_PROCINFO */
ctx->ocsp_denied ? " ocsp:denied" : "", ctx->ocsp_denied ? " ocsp:denied" : "");
*ctx->origfpr,
*ctx->newfpr);
} }
if ((rv < 0 ) || !msg) { if ((rv < 0 ) || !msg) {
ctx->enomem = 1; ctx->enomem = 1;
@ -732,6 +732,66 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain,
return sslctx; 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 * static cert_t *
pxy_srccert_create(pxy_conn_ctx_t *ctx) 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_key(cert, ctx->opts->key);
cert_set_chain(cert, ctx->opts->chain); cert_set_chain(cert, ctx->opts->chain);
ctx->generated_cert = 1;
} }
unsigned char origfpr[SSL_X509_FPRSZ], newfpr[SSL_X509_FPRSZ]; if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) && ctx->origcrt) {
ssl_x509_fingerprint_sha1(ctx->origcrt, origfpr); ctx->origcrtfpr = ssl_x509_fingerprint(ctx->origcrt, 0);
ssl_x509_fingerprint_sha1(cert->crt, newfpr); if (!ctx->origcrtfpr)
asprintf(ctx->origfpr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" ctx->enomem = 1;
"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", }
origfpr[0], origfpr[1], origfpr[2], origfpr[3], origfpr[4], if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) &&
origfpr[5], origfpr[6], origfpr[7], origfpr[8], origfpr[9], cert && cert->crt) {
origfpr[10], origfpr[11], origfpr[12], origfpr[13], origfpr[14], ctx->usedcrtfpr = ssl_x509_fingerprint(cert->crt, 0);
origfpr[15], origfpr[16], origfpr[17], origfpr[18], origfpr[19]); if (!ctx->usedcrtfpr)
asprintf(ctx->newfpr,"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X" ctx->enomem = 1;
"%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));
}
}
} }
return cert; return cert;
@ -969,6 +1000,7 @@ pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg)
return SSL_TLSEXT_ERR_NOACK; return SSL_TLSEXT_ERR_NOACK;
} }
cachemgr_fkcrt_set(ctx->origcrt, newcrt); cachemgr_fkcrt_set(ctx->origcrt, newcrt);
ctx->generated_cert = 1;
if (OPTS_DEBUG(ctx->opts)) { if (OPTS_DEBUG(ctx->opts)) {
log_dbg_printf("===> Updated forged server " log_dbg_printf("===> Updated forged server "
"certificate:\n"); "certificate:\n");
@ -983,6 +1015,16 @@ pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg)
ctx->enomem = 1; 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, newsslctx = pxy_srcsslctx_create(ctx, newcrt, ctx->opts->chain,
ctx->opts->key); ctx->opts->key);
if (!newsslctx) { if (!newsslctx) {
@ -1810,6 +1852,12 @@ connected:
pxy_log_connect_nonhttp(ctx); 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 (OPTS_DEBUG(ctx->opts)) {
if (this->ssl) { if (this->ssl) {
/* for SSL, we get two connect events */ /* for SSL, we get two connect events */

View File

@ -181,12 +181,6 @@ no matching certificate in the provided certificate directory.
Use private key from \fIpemfile\fP for certificates forged on-the-fly. 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. If \fB-K\fP is not given, SSLsplit will generate a random 1024-bit RSA key.
.TP .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 .B \-l \fIlogfile\fP
Log connections to \fIlogfile\fP in a single line per connection format, Log connections to \fIlogfile\fP in a single line per connection format,
including addresses and ports and some HTTP and SSL information, if available. including addresses and ports and some HTTP and SSL information, if available.
@ -297,6 +291,19 @@ Mac OS X.
.B \-V .B \-V
Display version and compiled features information and exit. Display version and compiled features information and exit.
.TP .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 .B \-Z
Disable SSL/TLS compression on all connections. This is useful if your Disable SSL/TLS compression on all connections. This is useful if your
limiting factor is CPU, not network bandwidth. limiting factor is CPU, not network bandwidth.