[stunnel-users] SNI and some troubles solving

Alexey Drozdov anyquist at yandex.ru
Sat Sep 10 15:53:04 CEST 2011


Hi All,

At first I would like to thank Marzena Trojnara for the useful program!

Occurrence of support SNI has especially interest.
I have decided to use the given possibility, but have detect pair of bugs which has independently successfully solved.

To begin with I dump part of my config:

[virtual_server]
accept  = 443
connect = localhost:1081

cert = /usr/local/etc/stunnel/alexCA.crt
key = /usr/local/etc/stunnel/alexCA.key

; need peer verification for default access 
verify = 2 
CAfile = /usr/local/etc/stunnel/alexCA.crt

; use restricted access form some target services 
[socks5] 
sni = virtual_server:localhost
sni = virtual_server:89.250.5.185
sni = virtual_server:127.0.0.1
sni = virtual_server:server

cert = /usr/local/etc/stunnel/alexCA.crt 
key = /usr/local/etc/stunnel/alexCA.key

verify = 2
CAfile = /usr/local/etc/stunnel/alexCA.crt 
connect = localhost:1081

; public service
[dreamhub_ru]
sni = virtual_server:dreamhub.ru
sni = virtual_server:pad.dreamhub.ru

cert = /usr/local/etc/stunnel/dreamhub.cer
key = /usr/local/etc/stunnel/dreamhub.pem
connect = localhost:80

I want to use stunnel on 443rd port for ssl-socks5 service with peer certificates verification and use public https web-service (https://dreamhub.ru).

And so it has appeared that value for "verify" are always used from global section (in my case [virtual_server]), and values of "verify" parameters from virtual services sections aren't used.

Problem it has appeared that in the SNI check callback

static int servername_cb(SSL *ssl, int *ad, void *arg) ...
for(list=section->servername_list_head; list; list=list->next)
  if(!strcasecmp(servername, list->servername)) {
                c=SSL_get_ex_data(ssl, cli_index);
                c->opt=list->opt;
                SSL_set_SSL_CTX(ssl, c->opt->ctx);
                s_log(LOG_NOTICE, "SNI: switched to section %s",
                               c->opt->servname);                      
                
SSL_set_SSL_CTX(ssl, c->opt->ctx);
does not copy ctx->verify_mode

(SSL*)s->verify_mode=ctx->verify_mode;

It has been solved by explicit calling SSL_set_verify

*** ctx.c       2011-09-07 14:43:50.000000000 +0400
--- ctx.c_patched       2011-09-10 01:12:48.000000000 +0400
***************
*** 156,161 ****
--- 156,162 ----
              c=SSL_get_ex_data(ssl, cli_index);
              c->opt=list->opt;
              SSL_set_SSL_CTX(ssl, c->opt->ctx);
+             SSL_set_verify(ssl, SSL_CTX_get_verify_mode(c->opt->ctx), 
+NULL);
              s_log(LOG_NOTICE, "SNI: switched to section %s",
                  c->opt->servname);
  #ifdef USE_LIBWRAP


The second moment concerns uses stunnel as client through HTTPS a proxy (protocol=connect).
All works perfectly, only it has appeared that value for SNI used from "connect" parameter instead of value of "protocolHost".
On a code all is quite obvious:

if(c->opt->host_name) {
                s_log(LOG_DEBUG, "SNI: host name: %s", c->opt->host_name);
                if(!SSL_set_tlsext_host_name(c->ssl, c->opt->host_name)) {
                               sslerror("SSL_set_tlsext_host_name");
                               longjmp(c->err, 1);
                }
}

I solved it such:

*** options.c   2011-09-07 20:38:56.000000000 +0400
--- options.c_patch     2011-09-10 16:34:56.882619049 +0400
***************
*** 695,700 ****
--- 695,705 ----
              s_log(LOG_INFO, "Cannot resolve '%s' - delaying DNS lookup", arg);
              section->option.delayed_lookup=1;
          }
+
+         /* check - is host_name already filled */
+         if (section->host_name != NULL)
+             return NULL; /* OK */
+
          tmpstr=strrchr(arg, ':');
          if(tmpstr) {
              *tmpstr='\0';
***************
*** 1077,1082 ****
--- 1082,1095 ----
          if(strcasecmp(opt, "protocolHost"))
              break;
          section->protocol_host=str_dup_err(arg);
+
+         /* Overwrite section->host_nam because of
+          protocolHost should be used for client SNI */
+         tmpstr=strrchr(arg, ':');
+         if(tmpstr) {
+             *tmpstr='\0';
+             section->host_name=str_dup_err(arg);
+         }
          return NULL; /* OK */
      case CMD_DEFAULT:
          break;

I think that the given changes can be useful for other :)

/ Alexey Drozdov




More information about the stunnel-users mailing list