Package: socat Version: 1.7.3.2-2 Severity: wishlist Tags: upstream socat does not support the TLS Server Name Indication extension. This extension has become pretty widely deployed at this point, and socat’s TLS support could be substantially more useful if it sent SNI.
A patch against 1.7.3.0 is available [1]; I’ve also attached it here for convenience. I haven’t tested or reviewed it, though, so its inclusion should not be treated as an endorsement. :) [1] https://github.com/moparisthebest/socat/commit/268432bf4220502535dbd373344b60b8fd10e3ce
>From 268432bf4220502535dbd373344b60b8fd10e3ce Mon Sep 17 00:00:00 2001 From: moparisthebest <[email protected]> Date: Fri, 17 Jul 2015 22:08:00 -0400 Subject: [PATCH 1/1] 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:<host>:<port>))) 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=<string>))) 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=<string>))) + 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 */ -- 2.21.0.392.gf8f6787159e-goog

