Skip to content

Commit

Permalink
Add option --sni-nomatch-abort.
Browse files Browse the repository at this point in the history
This makes hitch abort a handshake when a client submits an SNI server
name that is not recognized by any of the configured certificates.

Fixes: #24
  • Loading branch information
daghf committed Jun 11, 2015
1 parent 10a816b commit c444d95
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 18 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ Detail about the entire set of options can be found by invoking `hitch -h`:
--proxy-proxy Proxy HaProxy's PROXY (IPv4 or IPv6) protocol line
before actual data
(Default: off)
--sni-nomatch-abort Abort handshake when client submits an unrecognized SNI server name
(Default: off)

-t --test Test configuration and exit
-p --pidfile=FILE PID file
Expand Down
18 changes: 17 additions & 1 deletion src/configuration.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
#define CFG_RING_SLOTS "ring-slots"
#define CFG_RING_DATA_LEN "ring-data-len"
#define CFG_PIDFILE "pidfile"
#define CFG_SNI_NOMATCH_ABORT "sni-nomatch-abort"

#ifdef USE_SHARED_CACHE
#define CFG_SHARED_CACHE "shared-cache"
Expand Down Expand Up @@ -140,6 +141,7 @@ hitch_config * config_new (void) {
r->CIPHER_SUITE = NULL;
r->ENGINE = NULL;
r->BACKLOG = 100;
r->SNI_NOMATCH_ABORT = 0;

VTAILQ_INIT(&r->LISTEN_ARGS);
ALLOC_OBJ(fa, FRONT_ARG_MAGIC);
Expand Down Expand Up @@ -793,6 +795,9 @@ void config_param_validate (char *k, char *v, hitch_config *cfg, char *file, int
else if (strcmp(k, CFG_RING_DATA_LEN) == 0) {
r = config_param_val_int_pos(v, &cfg->RING_DATA_LEN);
}
else if (strcmp(k, CFG_SNI_NOMATCH_ABORT) == 0) {
r = config_param_val_bool(v, &cfg->SNI_NOMATCH_ABORT);
}
else {
fprintf(
stderr,
Expand Down Expand Up @@ -1018,6 +1023,10 @@ void config_print_usage_fd (char *prog, hitch_config *cfg, FILE *out) {
fprintf(out, " --proxy-proxy Proxy HaProxy's PROXY (IPv4 or IPv6) protocol line\n" );
fprintf(out, " before actual data\n");
fprintf(out, " (Default: %s)\n", config_disp_bool(cfg->PROXY_PROXY_LINE));
fprintf(out, " --sni-nomatch-abort Abort handshake when client "
"submits an unrecognized SNI server name\n" );
fprintf(out, " (Default: %s)\n",
config_disp_bool(cfg->SNI_NOMATCH_ABORT));
fprintf(out, "\n");
fprintf(out, " -t --test Test configuration and exit\n");
fprintf(out, " -p --pidfile=FILE PID file\n");
Expand Down Expand Up @@ -1223,6 +1232,13 @@ void config_print_default (FILE *fd, hitch_config *cfg) {
fprintf(fd, FMT_STR, CFG_PROXY_PROXY, config_disp_bool(cfg->PROXY_PROXY_LINE));
fprintf(fd, "\n");

fprintf(fd, "# Abort handshake when the client submits an unrecognized SNI"
" server name.\n");
fprintf(fd, "#\n");
fprintf(fd, "# type: boolean\n");
fprintf(fd, FMT_STR, CFG_SNI_NOMATCH_ABORT, config_disp_bool(cfg->SNI_NOMATCH_ABORT));
fprintf(fd, "\n");

fprintf(fd, "# EOF\n");
}
#endif /* NO_CONFIG_FILE */
Expand Down Expand Up @@ -1272,7 +1288,7 @@ void config_parse_cli(int argc, char **argv, hitch_config *cfg) {
{ CFG_WRITE_PROXY, 0, &cfg->WRITE_PROXY_LINE, 1 },
{ CFG_WRITE_PROXY_V2, 0, &cfg->WRITE_PROXY_LINE_V2, 1 },
{ CFG_PROXY_PROXY, 0, &cfg->PROXY_PROXY_LINE, 1 },

{ CFG_SNI_NOMATCH_ABORT, 0, &cfg->SNI_NOMATCH_ABORT, 1 },
{ "test", 0, NULL, 't' },
{ "version", 0, NULL, 'V' },
{ "help", 0, NULL, 'h' },
Expand Down
1 change: 1 addition & 0 deletions src/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ struct __hitch_config {
int RING_SLOTS;
int RING_DATA_LEN;
char *PIDFILE;
int SNI_NOMATCH_ABORT;
};

typedef struct __hitch_config hitch_config;
Expand Down
37 changes: 21 additions & 16 deletions src/hitch.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,23 +739,28 @@ sni_match(const struct ctx_list *cl, const char *srvname)
* based on the SNI header
*/
int sni_switch_ctx(SSL *ssl, int *al, void *data) {
(void)data;
(void)al;
const char *servername;
const ctx_list *cl;

servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (!servername) return SSL_TLSEXT_ERR_NOACK;

VTAILQ_FOREACH(cl, &sni_ctxs, list) {
CHECK_OBJ_NOTNULL(cl, CTX_LIST_MAGIC);
if (sni_match(cl, servername)) {
SSL_set_SSL_CTX(ssl, cl->ctx);
return SSL_TLSEXT_ERR_NOACK;
}
}
(void)data;
(void)al;
const char *servername;
const ctx_list *cl;

servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
if (!servername)
return SSL_TLSEXT_ERR_NOACK;

VTAILQ_FOREACH(cl, &sni_ctxs, list) {
CHECK_OBJ_NOTNULL(cl, CTX_LIST_MAGIC);
if (sni_match(cl, servername)) {
SSL_set_SSL_CTX(ssl, cl->ctx);
return SSL_TLSEXT_ERR_OK;
}
}

return SSL_TLSEXT_ERR_NOACK;
/* No matching certs */
if (CONFIG->SNI_NOMATCH_ABORT)
return SSL_TLSEXT_ERR_ALERT_FATAL;
else
return SSL_TLSEXT_ERR_NOACK;
}
#endif /* OPENSSL_NO_TLSEXT */

Expand Down
2 changes: 1 addition & 1 deletion tests/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ die() {

runcurl() {
# Verify that we got a HTTP reply.
BUF=$(curl --silent --insecure https://$1:$2/ 2>&1)
BUF=$(curl $CURL_EXTRA --silent --insecure https://$1:$2/ 2>&1)
test "$?" = "0" || die "Incorrect HTTP response code."
}
34 changes: 34 additions & 0 deletions tests/test07-nomatch-abort
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#/bin/bash
#
# Test --sni-nomatch-abort
#
. common.sh
set +o errexit

#PORT2=$(($RANDOM + 1024))

$HITCH $HITCH_ARGS --backend=[hyse.org]:80 --frontend=[${LISTENADDR}]:$LISTENPORT \
certs/site1.example.com certs/site2.example.com certs/default.example.com \
--sni-nomatch-abort
test "$?" = "0" || die "Hitch did not start."

# No SNI - should not be affected.
echo -e "\n" | openssl s_client -prexit -connect $LISTENADDR:$LISTENPORT 2>/dev/null > $DUMPFILE
test "$?" = "0" || die "s_client failed"
grep -q -c "subject=/CN=default.example.com" $DUMPFILE
test "$?" = "0" || die "s_client got wrong certificate on listen port #1"

# SNI request w/ valid servername
echo -e "\n" | openssl s_client -servername site1.example.com -prexit -connect $LISTENADDR:$LISTENPORT 2>/dev/null > $DUMPFILE
test "$?" = "0" || die "s_client failed"
grep -q -c "subject=/CN=site1.example.com" $DUMPFILE
test "$?" = "0" || die "s_client got wrong certificate in listen port #2"

# SNI w/ unknown servername
echo | openssl s_client -servername invalid.example.com -prexit -connect $LISTENADDR:$LISTENPORT > $DUMPFILE 2>&1
test "$?" != "0" || die "s_client did NOT fail when it should have. "
grep -q -c "unrecognized name" $DUMPFILE
test "$?" = "0" || die "Expected 'unrecognized name' error."

CURL_EXTRA="--resolve site1.example.com:$LISTENPORT:127.0.0.1"
runcurl site1.example.com $LISTENPORT

0 comments on commit c444d95

Please sign in to comment.