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

Reply via email to