Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 76 additions & 4 deletions pxyconn.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ typedef struct pxy_conn_ctx {

/* server name indicated by client in SNI TLS extension */
char *sni;
unsigned char *alpn;
unsigned int alpnLen;

/* log strings from socket */
char *srchost_str;
Expand Down Expand Up @@ -288,6 +290,9 @@ pxy_conn_ctx_free(pxy_conn_ctx_t *ctx)
if (ctx->sni) {
free(ctx->sni);
}
if (ctx->alpn) {
free(ctx->alpn);
}
if (WANT_CONTENT_LOG(ctx) && ctx->logctx) {
if (log_content_close(&ctx->logctx) == -1) {
log_err_printf("Warning: Content log close failed\n");
Expand All @@ -306,6 +311,15 @@ static void pxy_fd_readcb(evutil_socket_t, short, void *);
/* forward declaration of OpenSSL callbacks */
#ifndef OPENSSL_NO_TLSEXT
static int pxy_ossl_servername_cb(SSL *ssl, int *al, void *arg);
#ifndef OPENSSL_NO_ALPNEXT
static int pxy_ossl_alpn_select_cb(
UNUSED SSL *ssl,
const unsigned char **out,
unsigned char *outlen,
UNUSED const unsigned char *in,
UNUSED unsigned int inlen,
void *arg);
#endif /* !OPENSSL_NO_ALPNEXT */
#endif /* !OPENSSL_NO_TLSEXT */
static int pxy_ossl_sessnew_cb(SSL *, SSL_SESSION *);
static void pxy_ossl_sessremove_cb(SSL_CTX *, SSL_SESSION *);
Expand Down Expand Up @@ -714,6 +728,11 @@ pxy_srcsslctx_create(pxy_conn_ctx_t *ctx, X509 *crt, STACK_OF(X509) *chain,
#ifndef OPENSSL_NO_TLSEXT
SSL_CTX_set_tlsext_servername_callback(sslctx, pxy_ossl_servername_cb);
SSL_CTX_set_tlsext_servername_arg(sslctx, ctx);
#ifndef OPENSSL_NO_ALPNEXT
if (!ctx->spec->http) {
SSL_CTX_set_alpn_select_cb(sslctx, pxy_ossl_alpn_select_cb, ctx);
}
#endif /* !OPENSSL_NO_ALPNEXT */
#endif /* !OPENSSL_NO_TLSEXT */
#ifndef OPENSSL_NO_DH
if (ctx->opts->dh) {
Expand Down Expand Up @@ -944,6 +963,30 @@ pxy_srcssl_create(pxy_conn_ctx_t *ctx, SSL *origssl)
ctx->enomem = 1;
return NULL;
}

#ifndef OPENSSL_NO_ALPNEXT
/* Try and get ALPN reply from real server. */
if (!ctx->spec->http) {
const unsigned char *alpn = 0;
unsigned int alpnLen = 0;
SSL_get0_alpn_selected(origssl, &alpn, &alpnLen);

if (alpn != 0 && alpnLen > 0) {

if ( ctx->alpn != 0 ) {
free(ctx->alpn);
ctx->alpn = 0;
ctx->alpnLen = 0;
}
ctx->alpn = malloc(alpnLen);
memcpy(ctx->alpn, alpn, alpnLen);
ctx->alpnLen = alpnLen;

log_dbg_printf("Received ALPN from real server.\n");
}
}
#endif /* !OPENSSL_NO_ALPNEXT */

SSL *ssl = SSL_new(sslctx);
SSL_CTX_free(sslctx); /* SSL_new() increments refcount */
if (!ssl) {
Expand Down Expand Up @@ -1067,6 +1110,27 @@ pxy_ossl_servername_cb(SSL *ssl, UNUSED int *al, void *arg)

return SSL_TLSEXT_ERR_OK;
}
#ifndef OPENSSL_NO_ALPNEXT
static int
pxy_ossl_alpn_select_cb(
UNUSED SSL *ssl,
const unsigned char **out,
unsigned char *outlen,
UNUSED const unsigned char *in,
UNUSED unsigned int inlen,
void *arg)
{
pxy_conn_ctx_t *ctx = (pxy_conn_ctx_t *)arg;

*out = ctx->alpn;
*outlen = ctx->alpnLen;

log_dbg_printf("ALPN callback, need to relay choice to real client\n");

return SSL_TLSEXT_ERR_OK;
}
#endif /* !OPENSSL_NO_ALPNEXT */

#endif /* !OPENSSL_NO_TLSEXT */

/*
Expand Down Expand Up @@ -1100,6 +1164,13 @@ pxy_dstssl_create(pxy_conn_ctx_t *ctx)
if (ctx->sni) {
SSL_set_tlsext_host_name(ssl, ctx->sni);
}
#ifndef OPENSSL_NO_ALPNEXT
if (!ctx->spec->http) {
if (ctx->alpn) {
SSL_set_alpn_protos(ssl, ctx->alpn, ctx->alpnLen);
}
}
#endif /* !OPENSSL_NO_ALPNEXT */
#endif /* !OPENSSL_NO_TLSEXT */

#ifdef SSL_MODE_RELEASE_BUFFERS
Expand Down Expand Up @@ -1515,7 +1586,8 @@ pxy_conn_autossl_peek_and_upgrade(pxy_conn_ctx_t *ctx)
if (evbuffer_peek(inbuf, 1024, 0, vec_out, 1)) {
if (ssl_tls_clienthello_parse(vec_out[0].iov_base,
vec_out[0].iov_len,
0, &chello, &ctx->sni) == 0) {
0, &chello, &ctx->sni,
&ctx->alpn, &ctx->alpnLen) == 0) {
if (OPTS_DEBUG(ctx->opts)) {
log_dbg_printf("Peek found ClientHello\n");
}
Expand Down Expand Up @@ -1986,7 +2058,7 @@ pxy_bev_eventcb(struct bufferevent *bev, short events, void *arg)
SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {
/* these can happen due to client cert auth,
* only log error if debugging is activated */
log_dbg_printf("Error from bufferevent: "
log_dbg_printf("Error from bufferevent_dbg: "
"%i:%s %lu:%i:%s:%i:%s:%i:%s\n",
errno,
errno ? strerror(errno) : "-",
Expand All @@ -2013,7 +2085,7 @@ pxy_bev_eventcb(struct bufferevent *bev, short events, void *arg)
}
} else {
/* real errors */
log_err_printf("Error from bufferevent: "
log_err_printf("Error from bufferevent_err: "
"%i:%s %lu:%i:%s:%i:%s:%i:%s\n",
errno,
errno ? strerror(errno) : "-",
Expand Down Expand Up @@ -2242,7 +2314,7 @@ pxy_fd_readcb(MAYBE_UNUSED evutil_socket_t fd, UNUSED short what, void *arg)
return;
}

rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni);
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni, &ctx->alpn, &ctx->alpnLen);
if ((rv == 1) && !chello) {
log_err_printf("Peeking did not yield a (truncated) "
"ClientHello message, "
Expand Down
63 changes: 61 additions & 2 deletions ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ ssl_openssl_version(void)
fprintf(stderr, "OpenSSL has no support for TLS extensions\n"
"TLS Server Name Indication (SNI) not supported\n");
#endif /* OPENSSL_NO_TLSEXT */
#ifndef OPENSSL_NO_ALPNEXT
fprintf(stderr, "TLS Application Layer Protocol Negotiation (ALPN) supported\n");
#else /* OPENSSL_NO_ALPNEXT */
fprintf(stderr, "TLS Application Layer Protocol Negotiation (ALPN) not supported\n");
#endif /* OPENSSL_NO_ALPNEXT */
#ifdef OPENSSL_THREADS
#ifndef OPENSSL_NO_THREADID
fprintf(stderr, "OpenSSL is thread-safe with THREADID\n");
Expand Down Expand Up @@ -1737,14 +1742,18 @@ ssl_is_ocspreq(const unsigned char *buf, size_t sz)
* RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2
* RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions
*/
//#define DEBUG_CLIENTHELLO_PARSER
int
ssl_tls_clienthello_parse(const unsigned char *buf, ssize_t sz, int search,
const unsigned char **clienthello, char **servername)
const unsigned char **clienthello, char **servername,
unsigned char **alpn, unsigned int *alpnLen)
{
#ifdef DEBUG_CLIENTHELLO_PARSER
#define DBG_printf(...) log_dbg_printf("ClientHello parser: " __VA_ARGS__)
#define DBG_printf_plain(...) log_dbg_printf(__VA_ARGS__)
#else /* !DEBUG_CLIENTHELLO_PARSER */
#define DBG_printf(...)
#define DBG_printf_plain(...)
#endif /* !DEBUG_CLIENTHELLO_PARSER */
const unsigned char *p = buf;
ssize_t n = sz;
Expand Down Expand Up @@ -1930,7 +1939,7 @@ ssl_tls_clienthello_parse(const unsigned char *buf, ssize_t sz, int search,
if (n < extlen)
goto continue_search;
switch (exttype) {
case 0: {
case 0x0: {
ssize_t extn = extlen;
const unsigned char *extp = p;

Expand Down Expand Up @@ -1980,12 +1989,62 @@ ssl_tls_clienthello_parse(const unsigned char *buf, ssize_t sz, int search,
}
break;
}
#ifndef OPENSSL_NO_ALPNEXT
case 0x10: {
DBG_printf("Extracting ALPN\n");
ssize_t extn = extlen;
const unsigned char *extp = p;

if (extn < 2)
goto continue_search;
DBG_printf("list length %02x %02x\n",
extp[0], extp[1]);
ssize_t alpnlistlen = extp[1] + (extp[0] << 8);
DBG_printf("alpnlistln = %zd\n", alpnlistlen);
extp += 2;
extn -= 2;

if (alpnlistlen != extn)
goto continue_search;

/* Only care if we have the entire ALPN extension. */
if (alpnlistlen > n)
goto continue_search;

//if (alpnlistlen > TLSEXT_MAXLEN_alpn)
if (alpnlistlen > 255)
goto continue_search;

if (alpn != NULL && (*alpn) == NULL) {
*alpn = malloc(extn);
memcpy(*alpn, extp, extn);
*alpnLen = extn;
}

#ifdef DEBUG_CLIENTHELLO_PARSER
DBG_printf("Extracted ALPN:\n");
for (ssize_t i = 0; i < extn; ) {
for ( int j = 0; j < 8 && i < extn; ++i, ++j) {
int num = (int)((*alpn)[i]) & 0xff;
DBG_printf_plain(" ");
if ( num <= 0xf )
DBG_printf_plain("0");
DBG_printf_plain("%x", num);
}
DBG_printf_plain("\n");
}
#endif /* DEBUG_CLIENTHELLO_PARSER */

break;
}
#endif /* !OPENSSL_NO_ALPNEXT */
default:
DBG_printf("skipped\n");
break;
}
p += extlen;
n -= extlen;

} /* while have more extensions */

#ifdef DEBUG_CLIENTHELLO_PARSER
Expand Down
10 changes: 9 additions & 1 deletion ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
#if (OPENSSL_VERSION_NUMBER < 0x0090802FL) && !defined(OPENSSL_NO_EC)
#define OPENSSL_NO_EC
#endif
#if (OPENSSL_VERSION_NUMBER < 0x10002000) && !defined(OPENSSL_NO_ALPNEXT)
#define OPENSSL_NO_ALPNEXT
#endif

/*
* The constructors returning a SSL_METHOD * were changed to return
Expand Down Expand Up @@ -84,6 +87,10 @@ X509 * ssl_ssl_cert_get(SSL *);
#ifndef TLSEXT_MAXLEN_host_name
#define TLSEXT_MAXLEN_host_name 255
#endif /* !TLSEXT_MAXLEN_host_name */

#ifndef TLSEXT_MAXLEN_alpn
#define TLSEXT_MAXLEN_alpn 255
#endif /* !TLSEXT_MAXLEN_alpn */
#endif /* OPENSSL_NO_TLSEXT */

/*
Expand Down Expand Up @@ -198,7 +205,8 @@ int ssl_session_is_valid(SSL_SESSION *) NONNULL(1);
int ssl_is_ocspreq(const unsigned char *, size_t) NONNULL(1) WUNRES;

int ssl_tls_clienthello_parse(const unsigned char *, ssize_t, int,
const unsigned char **, char **)
const unsigned char **, char **,
unsigned char **, unsigned int *)
NONNULL(1,4) WUNRES;
int ssl_dnsname_match(const char *, size_t, const char *, size_t)
NONNULL(1,3) WUNRES;
Expand Down
Loading