Skip to content

Commit

Permalink
Allow more control over used SSL/TLS versions
Browse files Browse the repository at this point in the history
Add -r to force a specific SSL/TLS protocol version.
Add -R to disable one or several SSL/TLS protocol versions.
Replace WANT_SSLV2_CLIENT and WANT_SSLV2_SERVER to WITH_SSLV2.

Issue:		droe#30
Reported by:	@Apollo2342
  • Loading branch information
droe committed Nov 5, 2014
1 parent 53e3d59 commit 6b0e47d
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 29 deletions.
10 changes: 6 additions & 4 deletions GNUmakefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
### OpenSSL tweaking

# Define to enable SSLv2 in the server (src) or client (dst) code.
# Default since 0.4.9 is to disable SSLv2 entirely.
#FEATURES+= -DWANT_SSLV2_SERVER
#FEATURES+= -DWANT_SSLV2_CLIENT
# Define to enable support for SSLv2.
# Default since 0.4.9 is to disable SSLv2 entirely, since there are servers
# that are not compatible with SSLv2 Client Hello messages. If you build in
# SSLv2 support, you can disable it at runtime using -R ssl2 to get the same
# result as not building in SSLv2 support at all.
#FEATURES+= -DWITH_SSLV2

# Define to make SSLsplit set a session id context in server mode.
#FEATURES+= -DUSE_SSL_SESSION_ID_CONTEXT
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

### SSLsplit master

- Add option -r to force a specific SSL/TLS protocol version (issue #30).
- Add option -R to disable specific SSL/TLS protocol versions (issue #30).
- Replaced WANT_SSLV2_CLIENT and WANT_SSLV2_SERVER build knobs with a single
WITH_SSLV2 build knob.
- Minor bugfixes and improvements.


Expand Down
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ IPv4 and IPv6. For SSL and HTTPS connections, SSLsplit generates and signs
forged X509v3 certificates on-the-fly, based on the original server certificate
subject DN and subjectAltName extension. SSLsplit fully supports Server Name
Indication (SNI) and is able to work with RSA, DSA and ECDSA keys and DHE and
ECDHE cipher suites. SSLsplit can also use existing certificates of which the
private key is available, instead of generating forged ones. SSLsplit supports
NULL-prefix CN certificates and can deny OCSP requests in a generic way. For
HTTP and HTTPS connections, SSLsplit removes response headers for HPKP in order
to prevent public key pinning, for HSTS to allow the user to accept untrusted
ECDHE cipher suites. Depending on the version of OpenSSL, SSLsplit supports
SSL 3.0, TLS 1.0, TLS 1.1 and TLS 1.2, and optionally SSL 2.0 as well.
SSLsplit can also use existing certificates of which the private key is
available, instead of generating forged ones. SSLsplit supports NULL-prefix CN
certificates and can deny OCSP requests in a generic way. For HTTP and HTTPS
connections, SSLsplit removes response headers for HPKP in order to prevent
public key pinning, for HSTS to allow the user to accept untrusted
certificates, and Alternate Protocols to prevent switching to QUIC/SPDY.

See the manual page sslsplit(1) for details on using SSLsplit and setting up
Expand Down
14 changes: 13 additions & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ main_usage(void)
#else /* !SSL_OP_NO_COMPRESSION */
#define OPT_Z
#endif /* !SSL_OP_NO_COMPRESSION */
" -r proto only support one of " SSL_PROTO_SUPPORT_S "(default: all)\n"
" -R proto disable one of " SSL_PROTO_SUPPORT_S "(default: none)\n"
" -s ciphers use the given OpenSSL cipher suite spec (default: ALL:-aNULL)\n"
" -e engine specify default NAT engine to use (default: %s)\n"
" -E list available NAT engines and exit\n"
Expand Down Expand Up @@ -247,7 +249,7 @@ main(int argc, char *argv[])
}

while ((ch = getopt(argc, argv, OPT_g OPT_G OPT_Z
"k:c:C:K:t:OPs:e:Eu:m:j:p:l:L:S:dDVh")) != -1) {
"k:c:C:K:t:OPs:r:R:e:Eu:m:j:p:l:L:S:dDVh")) != -1) {
switch (ch) {
case 'c':
if (opts->cacrt)
Expand Down Expand Up @@ -413,6 +415,12 @@ main(int argc, char *argv[])
if (!opts->ciphers)
oom_die(argv0);
break;
case 'r':
opts_proto_force(opts, optarg, argv0);
break;
case 'R':
opts_proto_disable(opts, optarg, argv0);
break;
case 'e':
free(natengine);
natengine = strdup(optarg);
Expand Down Expand Up @@ -592,6 +600,10 @@ main(int argc, char *argv[])
/* debugging */
if (OPTS_DEBUG(opts)) {
main_version();
log_dbg_printf("proto: \n");

XXX

log_dbg_printf("proxyspecs:\n");
for (proxyspec_t *spec = opts->spec; spec; spec = spec->next) {
char *lbuf, *cbuf = NULL;
Expand Down
85 changes: 85 additions & 0 deletions opts.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ opts_new(void)

opts->sslcomp = 1;
opts->chain = sk_X509_new_null();
opts->sslmethod = SSLv23_method;

return opts;
}
Expand Down Expand Up @@ -124,6 +125,90 @@ opts_has_ssl_spec(opts_t *opts)
return 0;
}

/*
* Parse SSL proto string in optarg and look up the corresponding SSL method.
* Calls exit() on failure.
*/
void
opts_proto_force(opts_t *opts, const char *optarg, const char *argv0)
{
if (opts->sslmethod != SSLv23_method) {
fprintf(stderr, "%s: cannot use -r multiple times\n", argv0);
exit(EXIT_FAILURE);
}

#if defined(SSL_OP_NO_SSLv2) && defined(WITH_SSLV2)
if (!strcmp(optarg, "ssl2")) {
opts->sslmethod = SSLv2_method;
} else
#endif /* SSL_OP_NO_SSLv2 && WITH_SSLV2 */
#ifdef SSL_OP_NO_SSLv3
if (!strcmp(optarg, "ssl3")) {
opts->sslmethod = SSLv3_method;
} else
#endif /* SSL_OP_NO_SSLv3 */
#ifdef SSL_OP_NO_TLSv1
if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) {
opts->sslmethod = TLSv1_method;
} else
#endif /* SSL_OP_NO_TLSv1 */
#ifdef SSL_OP_NO_TLSv1_1
if (!strcmp(optarg, "tls11")) {
opts->sslmethod = TLSv1_1_method;
} else
#endif /* SSL_OP_NO_TLSv1_1 */
#ifdef SSL_OP_NO_TLSv1_2
if (!strcmp(optarg, "tls12")) {
opts->sslmethod = TLSv1_2_method;
} else
#endif /* SSL_OP_NO_TLSv1_2 */
{
fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n",
argv0, optarg);
exit(EXIT_FAILURE);
}
}

/*
* Parse SSL proto string in optarg and set the corresponding no_foo bit.
* Calls exit() on failure.
*/
void
opts_proto_disable(opts_t *opts, const char *optarg, const char *argv0)
{
#if defined(SSL_OP_NO_SSLv2) && defined(WITH_SSLV2)
if (!strcmp(optarg, "ssl2")) {
opts->no_ssl2 = 1;
} else
#endif /* SSL_OP_NO_SSLv2 && WITH_SSLV2 */
#ifdef SSL_OP_NO_SSLv3
if (!strcmp(optarg, "ssl3")) {
opts->no_ssl3 = 1;
} else
#endif /* SSL_OP_NO_SSLv3 */
#ifdef SSL_OP_NO_TLSv1
if (!strcmp(optarg, "tls10") || !strcmp(optarg, "tls1")) {
opts->no_tls10 = 1;
} else
#endif /* SSL_OP_NO_TLSv1 */
#ifdef SSL_OP_NO_TLSv1_1
if (!strcmp(optarg, "tls11")) {
opts->no_tls11 = 1;
} else
#endif /* SSL_OP_NO_TLSv1_1 */
#ifdef SSL_OP_NO_TLSv1_2
if (!strcmp(optarg, "tls12")) {
opts->no_tls12 = 1;
} else
#endif /* SSL_OP_NO_TLSv1_2 */
{
fprintf(stderr, "%s: Unsupported SSL/TLS protocol '%s'\n",
argv0, optarg);
exit(EXIT_FAILURE);
}
}


/*
* Parse proxyspecs using a simple state machine.
* Returns NULL if parsing failed.
Expand Down
18 changes: 18 additions & 0 deletions opts.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ typedef struct opts {
unsigned int debug : 1;
unsigned int detach : 1;
unsigned int sslcomp : 1;
#if defined(SSL_OP_NO_SSLv2) && defined(WITH_SSLV2)
unsigned int no_ssl2 : 1;
#endif /* SSL_OP_NO_SSLv2 && WITH_SSLV2 */
#ifdef SSL_OP_NO_SSLv3
unsigned int no_ssl3 : 1;
#endif /* SSL_OP_NO_SSLv3 */
#ifdef SSL_OP_NO_TLSv1
unsigned int no_tls10 : 1;
#endif /* SSL_OP_NO_TLSv1 */
#ifdef SSL_OP_NO_TLSv1_1
unsigned int no_tls11 : 1;
#endif /* SSL_OP_NO_TLSv1_1 */
#ifdef SSL_OP_NO_TLSv1_2
unsigned int no_tls12 : 1;
#endif /* SSL_OP_NO_TLSv1_2 */
unsigned int passthrough : 1;
unsigned int deny_ocsp : 1;
unsigned int contentlogdir : 1;
Expand All @@ -68,6 +83,7 @@ typedef struct opts {
char *pidfile;
char *connectlog;
char *contentlog;
const SSL_METHOD *(*sslmethod)(void);
X509 *cacrt;
EVP_PKEY *cakey;
EVP_PKEY *key;
Expand All @@ -84,6 +100,8 @@ typedef struct opts {
opts_t *opts_new(void) MALLOC;
void opts_free(opts_t *) NONNULL(1);
int opts_has_ssl_spec(opts_t *) NONNULL(1) WUNRES;
void opts_proto_force(opts_t *, const char *, const char *) NONNULL(1,2,3);
void opts_proto_disable(opts_t *, const char *, const char *) NONNULL(1,2,3);
#define OPTS_DEBUG(opts) unlikely((opts)->debug)

proxyspec_t * proxyspec_parse(int *, char **[], const char *) MALLOC;
Expand Down
82 changes: 69 additions & 13 deletions pxyconn.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,11 @@ pxy_log_connect_http(pxy_conn_ctx_t *ctx)
* the refcount decrementing. In other words, return 0 if we did not
* keep a pointer to the object (which we never do here).
*/
#if defined(WANT_SSLV2_CLIENT) || defined(WANT_SSLV2_SERVER)
#ifdef WITH_SSLV2
#define MAYBE_UNUSED
#else /* !(WANT_SSLV2_CLIENT || WANT_SSLV2_SERVER) */
#else /* !WITH_SSLV2 */
#define MAYBE_UNUSED UNUSED
#endif /* !(WANT_SSLV2_CLIENT || WANT_SSLV2_SERVER) */
#endif /* !WITH_SSLV2 */
static int
pxy_ossl_sessnew_cb(MAYBE_UNUSED SSL *ssl, SSL_SESSION *sess)
#undef MAYBE_UNUSED
Expand All @@ -408,15 +408,15 @@ pxy_ossl_sessnew_cb(MAYBE_UNUSED SSL *ssl, SSL_SESSION *sess)
log_dbg_print("(null)\n");
}
#endif /* DEBUG_SESSION_CACHE */
#if defined(WANT_SSLV2_CLIENT) || defined(WANT_SSLV2_SERVER)
#ifdef WITH_SSLV2
/* Session resumption seems to fail for SSLv2 with protocol
* parsing errors, so we disable caching for SSLv2. */
if (SSL_version(ssl) == SSL2_VERSION) {
log_err_printf("Warning: Session resumption denied to SSLv2"
"client.\n");
return 0;
}
#endif /* WANT_SSLV2_CLIENT || WANT_SSLV2_SERVER */
#endif /* WITH_SSLV2 */
if (sess) {
cachemgr_ssess_set(sess);
}
Expand Down Expand Up @@ -477,7 +477,7 @@ static SSL_CTX *
pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain,
EVP_PKEY *key)
{
SSL_CTX *sslctx = SSL_CTX_new(SSLv23_method());
SSL_CTX *sslctx = SSL_CTX_new(ctx->opts->sslmethod());
if (!sslctx)
return NULL;
SSL_CTX_set_options(sslctx, SSL_OP_ALL);
Expand All @@ -502,9 +502,37 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain,
SSL_CTX_set_options(sslctx, SSL_OP_NO_COMPRESSION);
}
#endif /* SSL_OP_NO_COMPRESSION */
#ifndef WANT_SSLV2_SERVER
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
#endif /* !WANT_SSLV2_SERVER */

#ifdef SSL_OP_NO_SSLv2
#ifdef WITH_SSLV2
if (ctx->opts->no_ssl2) {
#endif /* WITH_SSLV2 */
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
#ifdef WITH_SSLV2
}
#endif /* WITH_SSLV2 */
#endif /* !SSL_OP_NO_SSLv2 */
#ifdef SSL_OP_NO_SSLv3
if (ctx->opts->no_ssl3) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3);
}
#endif /* SSL_OP_NO_SSLv3 */
#ifdef SSL_OP_NO_TLSv1
if (ctx->opts->no_tls10) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1);
}
#endif /* SSL_OP_NO_TLSv1 */
#ifdef SSL_OP_NO_TLSv1_1
if (ctx->opts->no_tls11) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1);
}
#endif /* SSL_OP_NO_TLSv1_1 */
#ifdef SSL_OP_NO_TLSv1_2
if (ctx->opts->no_tls12) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2);
}
#endif /* SSL_OP_NO_TLSv1_2 */

SSL_CTX_set_cipher_list(sslctx, ctx->opts->ciphers);
SSL_CTX_sess_set_new_cb(sslctx, pxy_ossl_sessnew_cb);
SSL_CTX_sess_set_remove_cb(sslctx, pxy_ossl_sessremove_cb);
Expand Down Expand Up @@ -810,7 +838,7 @@ pxy_dstssl_create(pxy_conn_ctx_t *ctx)
SSL *ssl;
SSL_SESSION *sess;

sslctx = SSL_CTX_new(SSLv23_method());
sslctx = SSL_CTX_new(ctx->opts->sslmethod());
if (!sslctx) {
ctx->enomem = 1;
return NULL;
Expand All @@ -834,9 +862,37 @@ pxy_dstssl_create(pxy_conn_ctx_t *ctx)
SSL_CTX_set_options(sslctx, SSL_OP_NO_COMPRESSION);
}
#endif /* SSL_OP_NO_COMPRESSION */
#ifndef WANT_SSLV2_CLIENT
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
#endif /* !WANT_SSLV2_CLIENT */

#ifdef SSL_OP_NO_SSLv2
#ifdef WITH_SSLV2
if (ctx->opts->no_ssl2) {
#endif /* WITH_SSLV2 */
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2);
#ifdef WITH_SSLV2
}
#endif /* WITH_SSLV2 */
#endif /* !SSL_OP_NO_SSLv2 */
#ifdef SSL_OP_NO_SSLv3
if (ctx->opts->no_ssl3) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv3);
}
#endif /* SSL_OP_NO_SSLv3 */
#ifdef SSL_OP_NO_TLSv1
if (ctx->opts->no_tls10) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1);
}
#endif /* SSL_OP_NO_TLSv1 */
#ifdef SSL_OP_NO_TLSv1_1
if (ctx->opts->no_tls11) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_1);
}
#endif /* SSL_OP_NO_TLSv1_1 */
#ifdef SSL_OP_NO_TLSv1_2
if (ctx->opts->no_tls12) {
SSL_CTX_set_options(sslctx, SSL_OP_NO_TLSv1_2);
}
#endif /* SSL_OP_NO_TLSv1_2 */

SSL_CTX_set_cipher_list(sslctx, ctx->opts->ciphers);
SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, NULL);

Expand Down
3 changes: 3 additions & 0 deletions ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ ssl_openssl_version(void)
fprintf(stderr, "Using direct access workaround when loading certs\n");
#endif /* OpenSSL 1.0.0k or 1.0.1e */

fprintf(stderr, "SSL/TLS protocol availability: %s\n",
SSL_PROTO_SUPPORT_S);

fprintf(stderr, "SSL/TLS algorithm availability:");
#ifndef OPENSSL_NO_RSA
fprintf(stderr, " RSA");
Expand Down
Loading

0 comments on commit 6b0e47d

Please sign in to comment.