From 268432bf4220502535dbd373344b60b8fd10e3ce Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Fri, 17 Jul 2015 22:08:00 -0400 Subject: [PATCH] Add OpenSSL snihost option for TLS SNI extension --- doc/socat.yo | 9 +++++++-- xio-openssl.c | 16 +++++++++++++++- xio-openssl.h | 2 ++ xioopts.c | 2 ++ xioopts.h | 1 + 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/socat.yo b/doc/socat.yo index 65e9894..18269da 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -502,13 +502,15 @@ label(ADDRESS_OPENSSL_CONNECT)dit(bf(tt(OPENSSL::))) link(openssl-commonname)(OPTION_OPENSSL_COMMONNAME) option. Socat tries to match it against the certificates subject commonName, and the certifications extension subjectAltName DNS names. Wildcards in the - certificate are supported.nl() + certificate are supported. To specify the TLS SNI hostname to set use the + link(snihost)(OPTION_OPENSSL_SNIHOST) option.nl() Option groups: link(FD)(GROUP_FD),link(SOCKET)(GROUP_SOCKET),link(IP4)(GROUP_IP4),link(IP6)(GROUP_IP6),link(TCP)(GROUP_TCP),link(OPENSSL)(GROUP_OPENSSL),link(RETRY)(GROUP_RETRY) nl() Useful options: link(cipher)(OPTION_OPENSSL_CIPHERLIST), link(method)(OPTION_OPENSSL_METHOD), link(verify)(OPTION_OPENSSL_VERIFY), - link(commonname)(OPTION_OPENSSL_COMMONNAME) + link(commonname)(OPTION_OPENSSL_COMMONNAME), + link(snihost)(OPTION_OPENSSL_SNIHOST), link(cafile)(OPTION_OPENSSL_CAFILE), link(capath)(OPTION_OPENSSL_CAPATH), link(certificate)(OPTION_OPENSSL_CERTIFICATE), @@ -2700,6 +2702,9 @@ label(OPTION_OPENSSL_COMMONNAME)dit(bf(tt(commonname=))) certificates commonname. This option has only meaning when option link(verify)(OPTION_OPENSSL_VERIFY) is not disabled and the choosen cipher provides a peer certificate. +label(OPTION_OPENSSL_SNIHOST)dit(bf(tt(snihost=))) + Specify the SNI hostname for the TLS request. The server can use this TLS + extension to choose which certificate to send. label(OPTION_OPENSSL_FIPS)dit(bf(tt(fips))) Enables FIPS mode if compiled in. For info about the FIPS encryption implementation standard see lurl(http://oss-institute.org/fips-faq.html). diff --git a/xio-openssl.c b/xio-openssl.c index 665430d..a04e5bf 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -117,6 +117,7 @@ const struct optdesc opt_openssl_compress = { "openssl-compress", "compress const struct optdesc opt_openssl_fips = { "openssl-fips", "fips", OPT_OPENSSL_FIPS, GROUP_OPENSSL, PH_SPEC, TYPE_BOOL, OFUNC_SPEC }; #endif const struct optdesc opt_openssl_commonname = { "openssl-commonname", "cn", OPT_OPENSSL_COMMONNAME, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC }; +const struct optdesc opt_openssl_snihost = { "openssl-snihost", "snihost", OPT_OPENSSL_SNIHOST, GROUP_OPENSSL, PH_SPEC, TYPE_STRING, OFUNC_SPEC }; /* If FIPS is compiled in, we need to track if the user asked for FIPS mode. @@ -197,6 +198,7 @@ static int bool opt_ver = true; /* verify peer certificate */ char *opt_cert = NULL; /* file name of client certificate */ const char *opt_commonname = NULL; /* for checking peer certificate */ + const char *opt_snihost = NULL; /* for sni host */ int result; if (!(xioflags & XIO_MAYCONVERT)) { @@ -226,10 +228,15 @@ static int retropt_string(opts, OPT_OPENSSL_CERTIFICATE, &opt_cert); retropt_string(opts, OPT_OPENSSL_COMMONNAME, (char **)&opt_commonname); + retropt_string(opts, OPT_OPENSSL_SNIHOST, (char **)&opt_snihost); if (opt_commonname == NULL) { opt_commonname = hostname; } + /* could do this, but might not be desired? + if (opt_snihost == NULL) { + opt_snihost = hostname; + } */ result = _xioopen_openssl_prepare(opts, xfd, false, &opt_ver, opt_cert, &ctx); @@ -289,7 +296,7 @@ static int return result; } - result = _xioopen_openssl_connect(xfd, opt_ver, opt_commonname, ctx, level); + result = _xioopen_openssl_connect(xfd, opt_ver, opt_commonname, opt_snihost, ctx, level); switch (result) { case STAT_OK: break; #if WITH_RETRY @@ -358,6 +365,7 @@ static int int _xioopen_openssl_connect(struct single *xfd, bool opt_ver, const char *opt_commonname, + const char *opt_snihost, SSL_CTX *ctx, int level) { SSL *ssl; @@ -382,6 +390,12 @@ int _xioopen_openssl_connect(struct single *xfd, return result; } + if (opt_snihost && !SSL_set_tlsext_host_name(ssl, opt_snihost)) { + sycSSL_free(xfd->para.openssl.ssl); + xfd->para.openssl.ssl = NULL; + return STAT_NORETRY; + } + result = xioSSL_connect(xfd, opt_commonname, opt_ver, level); if (result != STAT_OK) { sycSSL_free(xfd->para.openssl.ssl); diff --git a/xio-openssl.h b/xio-openssl.h index 9cad8f4..4c577e0 100644 --- a/xio-openssl.h +++ b/xio-openssl.h @@ -30,6 +30,7 @@ extern const struct optdesc opt_openssl_compress; extern const struct optdesc opt_openssl_fips; #endif extern const struct optdesc opt_openssl_commonname; +extern const struct optdesc opt_openssl_snihost; extern int _xioopen_openssl_prepare(struct opt *opts, struct single *xfd, @@ -38,6 +39,7 @@ extern int extern int _xioopen_openssl_connect(struct single *xfd, bool opt_ver, const char *opt_commonname, + const char *opt_snihost, SSL_CTX *ctx, int level); extern int _xioopen_openssl_listen(struct single *xfd, bool opt_ver, diff --git a/xioopts.c b/xioopts.c index 3b0f300..660e366 100644 --- a/xioopts.c +++ b/xioopts.c @@ -1109,6 +1109,7 @@ const struct optname optionnames[] = { IF_OPENSSL("openssl-key", &opt_openssl_key) IF_OPENSSL("openssl-method", &opt_openssl_method) IF_OPENSSL("openssl-pseudo", &opt_openssl_pseudo) + IF_OPENSSL("openssl-snihost", &opt_openssl_snihost) IF_OPENSSL("openssl-verify", &opt_openssl_verify) IF_TERMIOS("opost", &opt_opost) #if defined(HAVE_TERMIOS_ISPEED) && defined(OSPEED_OFFSET) && (OSPEED_OFFSET != -1) @@ -1377,6 +1378,7 @@ const struct optname optionnames[] = { #ifdef SO_SNDTIMEO IF_SOCKET ("sndtimeo", &opt_so_sndtimeo) #endif + IF_OPENSSL("snihost", &opt_openssl_snihost) #ifdef SO_ACCEPTCONN /* AIX433 */ IF_SOCKET ("so-acceptconn", &opt_so_acceptconn) #endif /* SO_ACCEPTCONN */ diff --git a/xioopts.h b/xioopts.h index ebcf315..1310dd0 100644 --- a/xioopts.h +++ b/xioopts.h @@ -483,6 +483,7 @@ enum e_optcode { OPT_OPENSSL_KEY, OPT_OPENSSL_METHOD, OPT_OPENSSL_PSEUDO, + OPT_OPENSSL_SNIHOST, OPT_OPENSSL_VERIFY, OPT_OPOST, /* termios.c_oflag */ OPT_OSPEED, /* termios.c_ospeed */