1
0
mirror of https://github.com/nmap/nmap.git synced 2025-12-20 14:39:02 +00:00

Add DTLS and ALPN support to Ncat. Closes #446

This commit is contained in:
dmiller
2017-07-29 05:55:30 +00:00
parent bf54157855
commit fdfc36778b
17 changed files with 336 additions and 88 deletions

View File

@@ -1,5 +1,9 @@
# Nmap Changelog ($Id$); -*-text-*- # Nmap Changelog ($Id$); -*-text-*-
o [Ncat][GH#446] Added Datagram TLS (DTLS) support to Ncat in connect (client)
mode with --udp --ssl. Also added Application Layer Protocol Negotiation
(ALPN) support with the --ssl-alpn option. [denandz, Daniel Miller]
o Updated the default ciphers list for Ncat and the secure ciphers list for o Updated the default ciphers list for Ncat and the secure ciphers list for
Nsock to use "!aNULL:!eNULL" instead of "!ADH". With the addition of ECDH Nsock to use "!aNULL:!eNULL" instead of "!ADH". With the addition of ECDH
ciphersuites, anonymous ECDH suites were being allowed. [Daniel Miller] ciphersuites, anonymous ECDH suites were being allowed. [Daniel Miller]

View File

@@ -314,6 +314,8 @@
particularly handy for talking to SSL enabled HTTP servers, etc.</para> particularly handy for talking to SSL enabled HTTP servers, etc.</para>
<para>In server mode, this option listens for incoming SSL connections, <para>In server mode, this option listens for incoming SSL connections,
rather than plain untunneled traffic.</para> rather than plain untunneled traffic.</para>
<para>In UDP connect mode, this option enables Datagram TLS (DTLS).
This is not supported in server mode.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -395,6 +397,20 @@
<literal>ALL:!aNULL:!eNULL:!LOW:!EXP:!MD5:@STRENGTH</literal></para> <literal>ALL:!aNULL:!eNULL:!LOW:!EXP:!MD5:@STRENGTH</literal></para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>--ssl-alpn <replaceable>ALPN list</replaceable></option> (Specify ALPN protocol list)
<indexterm><primary><option>--ssl-alpn</option> (Ncat option)</primary></indexterm>
</term>
<listitem>
<para>This option allows you to specify a comma-separated list of
protocols to send via the Application-Layer Protocol Negotiation
(ALPN) TLS extension. Not supported by all versions of OpenSSL.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@@ -308,8 +308,8 @@ Content-Type: text/html; charset=UTF-8
with only one client, and the with only one client, and the
<option>--keep-open</option><indexterm><primary><option>--keep-open</option> (Ncat option)</primary><secondary>not supported with UDP</secondary></indexterm> <option>--keep-open</option><indexterm><primary><option>--keep-open</option> (Ncat option)</primary><secondary>not supported with UDP</secondary></indexterm>
option doesn't work, the reason for this being that UDP has no notion option doesn't work, the reason for this being that UDP has no notion
of a connection. UDP may not be combined with of a connection. UDP may be secured by a form of SSL called Datagram TLS (DTLS)<indexterm><primary>DTLS</primary><secondary>Datagram TLS</secondary></indexterm>.
SSL.<indexterm><primary>SSL</primary><secondary>not supported with UDP</secondary></indexterm> This is currently only supported in connect (client) mode.<indexterm><primary>SSL</primary><secondary>not supported with UDP in server mode</secondary></indexterm>
</para> </para>
<para> <para>

View File

@@ -256,6 +256,30 @@ static void set_ssl_ctx_options(SSL_CTX *ctx)
if (!SSL_CTX_set_cipher_list(ctx, o.sslciphers)) if (!SSL_CTX_set_cipher_list(ctx, o.sslciphers))
bye("Unable to set OpenSSL cipher list: %s", ERR_error_string(ERR_get_error(), NULL)); bye("Unable to set OpenSSL cipher list: %s", ERR_error_string(ERR_get_error(), NULL));
} }
#ifdef HAVE_ALPN_SUPPORT
if (o.sslalpn) {
size_t alpn_len;
unsigned char *alpn = next_protos_parse(&alpn_len, o.sslalpn);
if (alpn == NULL)
bye("Could not parse ALPN string");
if (o.debug)
logdebug("Using ALPN String %s\n", o.sslalpn);
/* SSL_CTX_set_alpn_protos returns 0 on success */
if (SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len) != 0){
free(alpn);
bye("SSL_CTX_set_alpn_protos: %s.", ERR_error_string(ERR_get_error(), NULL));
}
free(alpn);
}
#endif
} }
#endif #endif
@@ -878,6 +902,51 @@ static int do_proxy_socks5(void)
return(sd); return(sd);
} }
static nsock_iod new_iod(nsock_pool mypool) {
nsock_iod nsi = nsock_iod_new(mypool, NULL);
if (nsi == NULL)
bye("Failed to create nsock_iod.");
if (nsock_iod_set_hostname(nsi, o.target) == -1)
bye("Failed to set hostname on iod.");
switch (srcaddr.storage.ss_family) {
case AF_UNSPEC:
break;
case AF_INET:
nsock_iod_set_localaddr(nsi, &srcaddr.storage,
sizeof(srcaddr.in));
break;
#ifdef AF_INET6
case AF_INET6:
nsock_iod_set_localaddr(nsi, &srcaddr.storage,
sizeof(srcaddr.in6));
break;
#endif
#if HAVE_SYS_UN_H
case AF_UNIX:
nsock_iod_set_localaddr(nsi, &srcaddr.storage,
SUN_LEN((struct sockaddr_un *)&srcaddr.storage));
break;
#endif
default:
nsock_iod_set_localaddr(nsi, &srcaddr.storage,
sizeof(srcaddr.storage));
break;
}
if (o.numsrcrtes) {
unsigned char *ipopts = NULL;
size_t ipoptslen = 0;
if (o.af != AF_INET)
bye("Sorry, -g can only currently be used with IPv4.");
ipopts = buildsrcrte(targetaddrs->addr.in.sin_addr, o.srcrtes, o.numsrcrtes, o.srcrteptr, &ipoptslen);
nsock_iod_set_ipoptions(nsi, ipopts, ipoptslen);
free(ipopts); /* Nsock has its own copy */
}
return nsi;
}
int ncat_connect(void) int ncat_connect(void)
{ {
@@ -908,18 +977,15 @@ int ncat_connect(void)
nsock_pool_set_broadcast(mypool, 1); nsock_pool_set_broadcast(mypool, 1);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
set_ssl_ctx_options((SSL_CTX *) nsock_pool_ssl_init(mypool, 0)); #ifdef HAVE_DTLS_CLIENT_METHOD
if(o.proto == IPPROTO_UDP)
set_ssl_ctx_options((SSL_CTX *) nsock_pool_dtls_init(mypool, 0));
else
#endif
set_ssl_ctx_options((SSL_CTX *) nsock_pool_ssl_init(mypool, 0));
#endif #endif
if (!o.proxytype) { if (!o.proxytype) {
/* A non-proxy connection. Create an iod for a new socket. */
cs.sock_nsi = nsock_iod_new(mypool, NULL);
if (cs.sock_nsi == NULL)
bye("Failed to create nsock_iod.");
if (nsock_iod_set_hostname(cs.sock_nsi, o.target) == -1)
bye("Failed to set hostname on iod.");
#if HAVE_SYS_UN_H #if HAVE_SYS_UN_H
/* For DGRAM UNIX socket we have to use source socket */ /* For DGRAM UNIX socket we have to use source socket */
if (o.af == AF_UNIX && o.proto == IPPROTO_UDP) if (o.af == AF_UNIX && o.proto == IPPROTO_UDP)
@@ -945,50 +1011,13 @@ int ncat_connect(void)
strncpy(srcaddr.un.sun_path, tmp_name, sizeof(srcaddr.un.sun_path)); strncpy(srcaddr.un.sun_path, tmp_name, sizeof(srcaddr.un.sun_path));
free (tmp_name); free (tmp_name);
} }
nsock_iod_set_localaddr(cs.sock_nsi, &srcaddr.storage,
SUN_LEN((struct sockaddr_un *)&srcaddr.storage));
if (o.verbose) if (o.verbose)
loguser("[%s] used as source DGRAM Unix domain socket.\n", srcaddr.un.sun_path); loguser("[%s] used as source DGRAM Unix domain socket.\n", srcaddr.un.sun_path);
} }
else
#endif #endif
switch (srcaddr.storage.ss_family) { /* A non-proxy connection. Create an iod for a new socket. */
case AF_UNSPEC: cs.sock_nsi = new_iod(mypool);
break;
case AF_INET:
nsock_iod_set_localaddr(cs.sock_nsi, &srcaddr.storage,
sizeof(srcaddr.in));
break;
#ifdef AF_INET6
case AF_INET6:
nsock_iod_set_localaddr(cs.sock_nsi, &srcaddr.storage,
sizeof(srcaddr.in6));
break;
#endif
#if HAVE_SYS_UN_H
case AF_UNIX:
nsock_iod_set_localaddr(cs.sock_nsi, &srcaddr.storage,
SUN_LEN((struct sockaddr_un *)&srcaddr.storage));
break;
#endif
default:
nsock_iod_set_localaddr(cs.sock_nsi, &srcaddr.storage,
sizeof(srcaddr.storage));
break;
}
if (o.numsrcrtes) {
unsigned char *ipopts = NULL;
size_t ipoptslen = 0;
if (o.af != AF_INET)
bye("Sorry, -g can only currently be used with IPv4.");
ipopts = buildsrcrte(targetaddrs->addr.in.sin_addr, o.srcrtes, o.numsrcrtes, o.srcrteptr, &ipoptslen);
nsock_iod_set_ipoptions(cs.sock_nsi, ipopts, ipoptslen);
free(ipopts); /* Nsock has its own copy */
}
#if HAVE_SYS_UN_H #if HAVE_SYS_UN_H
if (o.af == AF_UNIX) { if (o.af == AF_UNIX) {
@@ -1068,35 +1097,27 @@ int ncat_connect(void)
static void try_nsock_connect(nsock_pool nsp, struct sockaddr_list *conn_addr) static void try_nsock_connect(nsock_pool nsp, struct sockaddr_list *conn_addr)
{ {
#ifdef HAVE_OPENSSL
if (o.ssl) {
nsock_connect_ssl(nsp, cs.sock_nsi, connect_handler,
o.conntimeout, (void *)conn_addr->next,
&conn_addr->addr.sockaddr, conn_addr->addrlen,
o.proto, inet_port(&conn_addr->addr),
NULL);
}
else
#endif
if (o.proto == IPPROTO_UDP) { if (o.proto == IPPROTO_UDP) {
nsock_connect_udp(nsp, cs.sock_nsi, connect_handler, (void *)conn_addr->next, nsock_connect_udp(nsp, cs.sock_nsi, connect_handler, (void *)conn_addr->next,
&conn_addr->addr.sockaddr, conn_addr->addrlen, &conn_addr->addr.sockaddr, conn_addr->addrlen,
inet_port(&conn_addr->addr)); inet_port(&conn_addr->addr));
} }
#ifdef HAVE_OPENSSL
else if (o.proto == IPPROTO_SCTP && o.ssl) {
nsock_connect_ssl(nsp, cs.sock_nsi, connect_handler,
o.conntimeout, (void *)conn_addr->next,
&conn_addr->addr.sockaddr, conn_addr->addrlen,
IPPROTO_SCTP, inet_port(&conn_addr->addr),
NULL);
}
#endif
else if (o.proto == IPPROTO_SCTP) { else if (o.proto == IPPROTO_SCTP) {
nsock_connect_sctp(nsp, cs.sock_nsi, connect_handler, nsock_connect_sctp(nsp, cs.sock_nsi, connect_handler,
o.conntimeout, (void *)conn_addr->next, o.conntimeout, (void *)conn_addr->next,
&conn_addr->addr.sockaddr, conn_addr->addrlen, &conn_addr->addr.sockaddr, conn_addr->addrlen,
inet_port(&conn_addr->addr)); inet_port(&conn_addr->addr));
} }
#ifdef HAVE_OPENSSL
else if (o.ssl) {
nsock_connect_ssl(nsp, cs.sock_nsi, connect_handler,
o.conntimeout, (void *)conn_addr->next,
&conn_addr->addr.sockaddr, conn_addr->addrlen,
IPPROTO_TCP, inet_port(&conn_addr->addr),
NULL);
}
#endif
else { else {
nsock_connect_tcp(nsp, cs.sock_nsi, connect_handler, nsock_connect_tcp(nsp, cs.sock_nsi, connect_handler,
o.conntimeout, (void *)conn_addr->next, o.conntimeout, (void *)conn_addr->next,
@@ -1132,6 +1153,13 @@ static void connect_handler(nsock_pool nsp, nsock_event evt, void *data)
loguser("Connection to %s failed: %s.\n", inet_socktop(&peer), socket_strerror(errcode)); loguser("Connection to %s failed: %s.\n", inet_socktop(&peer), socket_strerror(errcode));
loguser("Trying next address...\n"); loguser("Trying next address...\n");
} }
#ifdef HAVE_OPENSSL
/* If it's an SSL reconnect, clear out any old session info */
if (nsock_iod_check_ssl(cs.sock_nsi)) {
nsock_iod_delete(cs.sock_nsi, NSOCK_PENDING_NOTIFY);
cs.sock_nsi = new_iod(nsp);
}
#endif
try_nsock_connect(nsp, next_addr); try_nsock_connect(nsp, next_addr);
return; return;
} }

View File

@@ -215,6 +215,7 @@ void options_init(void)
o.sslverify = 0; o.sslverify = 0;
o.ssltrustfile = NULL; o.ssltrustfile = NULL;
o.sslciphers = NULL; o.sslciphers = NULL;
o.sslalpn = NULL;
#endif #endif
} }

View File

@@ -218,6 +218,7 @@ struct options {
int sslverify; int sslverify;
char *ssltrustfile; char *ssltrustfile;
char *sslciphers; char *sslciphers;
char *sslalpn;
int zerobyte; int zerobyte;
}; };

View File

@@ -264,6 +264,8 @@ static int ncat_listen_stream(int proto)
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
if (o.ssl) if (o.ssl)
if (o.sslalpn)
bye("ALPN is not supported in listen mode\n");
setup_ssl_listen(); setup_ssl_listen();
#endif #endif
@@ -712,6 +714,11 @@ static int ncat_listen_dgram(int proto)
struct timeval *tvp = NULL; struct timeval *tvp = NULL;
unsigned int num_sockets; unsigned int num_sockets;
#ifdef HAVE_OPENSSL
if(o.ssl)
bye("DTLS is not supported in listen mode\n");
#endif
for (i = 0; i < NUM_LISTEN_ADDRS; i++) { for (i = 0; i < NUM_LISTEN_ADDRS; i++) {
sockfd[i].fd = -1; sockfd[i].fd = -1;
sockfd[i].addr.storage.ss_family = AF_UNSPEC; sockfd[i].addr.storage.ss_family = AF_UNSPEC;

View File

@@ -320,12 +320,14 @@ int main(int argc, char *argv[])
{"ssl-verify", no_argument, NULL, 0}, {"ssl-verify", no_argument, NULL, 0},
{"ssl-trustfile", required_argument, NULL, 0}, {"ssl-trustfile", required_argument, NULL, 0},
{"ssl-ciphers", required_argument, NULL, 0}, {"ssl-ciphers", required_argument, NULL, 0},
{"ssl-alpn", required_argument, NULL, 0},
#else #else
{"ssl-cert", optional_argument, NULL, 0}, {"ssl-cert", optional_argument, NULL, 0},
{"ssl-key", optional_argument, NULL, 0}, {"ssl-key", optional_argument, NULL, 0},
{"ssl-verify", no_argument, NULL, 0}, {"ssl-verify", no_argument, NULL, 0},
{"ssl-trustfile", optional_argument, NULL, 0}, {"ssl-trustfile", optional_argument, NULL, 0},
{"ssl-ciphers", optional_argument, NULL, 0}, {"ssl-ciphers", optional_argument, NULL, 0},
{"ssl-alpn", optional_argument, NULL, 0},
#endif #endif
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@@ -536,7 +538,16 @@ int main(int argc, char *argv[])
} else if (strcmp(long_options[option_index].name, "ssl-ciphers") == 0) { } else if (strcmp(long_options[option_index].name, "ssl-ciphers") == 0) {
o.ssl = 1; o.ssl = 1;
o.sslciphers = Strdup(optarg); o.sslciphers = Strdup(optarg);
#ifdef HAVE_ALPN_SUPPORT
} else if (strcmp(long_options[option_index].name, "ssl-alpn") == 0) {
o.ssl = 1;
o.sslalpn = Strdup(optarg);
} }
#else
} else if (strcmp(long_options[option_index].name, "ssl-alpn") == 0) {
bye("OpenSSL does not have ALPN support compiled in. The --ssl-alpn option cannot be chosen.");
}
#endif
#else #else
else if (strcmp(long_options[option_index].name, "ssl-cert") == 0) { else if (strcmp(long_options[option_index].name, "ssl-cert") == 0) {
bye("OpenSSL isn't compiled in. The --ssl-cert option cannot be chosen."); bye("OpenSSL isn't compiled in. The --ssl-cert option cannot be chosen.");
@@ -548,6 +559,8 @@ int main(int argc, char *argv[])
bye("OpenSSL isn't compiled in. The --ssl-trustfile option cannot be chosen."); bye("OpenSSL isn't compiled in. The --ssl-trustfile option cannot be chosen.");
} else if (strcmp(long_options[option_index].name, "ssl-ciphers") == 0) { } else if (strcmp(long_options[option_index].name, "ssl-ciphers") == 0) {
bye("OpenSSL isn't compiled in. The --ssl-ciphers option cannot be chosen."); bye("OpenSSL isn't compiled in. The --ssl-ciphers option cannot be chosen.");
} else if (strcmp(long_options[option_index].name, "ssl-alpn") == 0) {
bye("OpenSSL isn't compiled in. The --ssl-alpn option cannot be chosen.");
} }
#endif #endif
#ifdef HAVE_LUA #ifdef HAVE_LUA
@@ -637,6 +650,7 @@ int main(int argc, char *argv[])
" --ssl-verify Verify trust and domain name of certificates\n" " --ssl-verify Verify trust and domain name of certificates\n"
" --ssl-trustfile PEM file containing trusted SSL certificates\n" " --ssl-trustfile PEM file containing trusted SSL certificates\n"
" --ssl-ciphers Cipherlist containing SSL ciphers to use\n" " --ssl-ciphers Cipherlist containing SSL ciphers to use\n"
" --ssl-alpn ALPN protocol list to use.\n"
#endif #endif
" --version Display Ncat's version information and exit\n" " --version Display Ncat's version information and exit\n"
"\n" "\n"
@@ -903,9 +917,11 @@ int main(int argc, char *argv[])
} }
if (o.proto == IPPROTO_UDP) { if (o.proto == IPPROTO_UDP) {
/* Don't allow a false sense of security if someone tries SSL over UDP. */
#ifndef HAVE_DTLS_CLIENT_METHOD
if (o.ssl) if (o.ssl)
bye("UDP mode does not support SSL."); bye("OpenSSL does not have DTLS support compiled in.");
#endif
if (o.keepopen && o.cmdexec == NULL) if (o.keepopen && o.cmdexec == NULL)
bye("UDP mode does not support the -k or --keep-open options, except with --exec or --sh-exec."); bye("UDP mode does not support the -k or --keep-open options, except with --exec or --sh-exec.");
if (o.broker) if (o.broker)

View File

@@ -750,3 +750,39 @@ int fix_line_endings(char *src, int *len, char **dst, int *state)
return 1; return 1;
} }
/*-
* next_protos_parse parses a comma separated list of strings into a string
* in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
* outlen: (output) set to the length of the resulting buffer on success.
* err: NULL on failure
* in: a NULL terminated string like "abc,def,ghi"
*
* returns: a malloc'd buffer or NULL on failure.
*/
unsigned char *next_protos_parse(size_t *outlen, const char *in)
{
size_t len;
unsigned char *out;
size_t i, start = 0;
len = strlen(in);
if (len >= 65535)
return NULL;
out = safe_malloc(strlen(in) + 1);
for (i = 0; i <= len; ++i) {
if (i == len || in[i] == ',') {
if (i - start > 255) {
free(out);
return NULL;
}
out[start] = i - start;
start = i + 1;
} else
out[i + 1] = in[i];
}
*outlen = len + 1;
return out;
}

View File

@@ -230,4 +230,6 @@ struct fdinfo *get_fdinfo(const fd_list_t *, int);
int fix_line_endings(char *src, int *len, char **dst, int *state); int fix_line_endings(char *src, int *len, char **dst, int *state);
unsigned char *next_protos_parse(size_t *outlen, const char *in);
#endif #endif

View File

@@ -248,6 +248,13 @@ void nsock_pool_set_device(nsock_pool nsp, const char *device);
#define NSOCK_SSL_MAX_SPEED (1 << 0) #define NSOCK_SSL_MAX_SPEED (1 << 0)
nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags); nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags);
/* Initializes an Nsock pool to create a DTLS connect. This sets and internal
* SSL_CTX, which is like a template that sets options for all connections that
* are made from it. Returns the SSL_CTX so tyou can set your own options.
*
* Functionally similar to nsock_pool_ssl_init, just for the DTLS */
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags);
/* Enforce use of a given IO engine. /* Enforce use of a given IO engine.
* The engine parameter is a zero-terminated string that will be * The engine parameter is a zero-terminated string that will be
* strup()'ed by the library. No validity check is performed by this function, * strup()'ed by the library. No validity check is performed by this function,

View File

@@ -82,6 +82,8 @@
#undef HAVE_OPENSSL #undef HAVE_OPENSSL
#undef HAVE_SSL_SET_TLSEXT_HOST_NAME #undef HAVE_SSL_SET_TLSEXT_HOST_NAME
#undef HAVE_DTLS_CLIENT_METHOD
#undef HAVE_ALPN_SUPPORT
#undef HAVE_EPOLL #undef HAVE_EPOLL
#undef HAVE_POLL #undef HAVE_POLL

60
nsock/src/configure vendored
View File

@@ -664,6 +664,7 @@ infodir
docdir docdir
oldincludedir oldincludedir
includedir includedir
runstatedir
localstatedir localstatedir
sharedstatedir sharedstatedir
sysconfdir sysconfdir
@@ -738,6 +739,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc' sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com' sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var' localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include' includedir='${prefix}/include'
oldincludedir='/usr/include' oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}' docdir='${datarootdir}/doc/${PACKAGE}'
@@ -990,6 +992,15 @@ do
| -silent | --silent | --silen | --sile | --sil) | -silent | --silent | --silen | --sile | --sil)
silent=yes ;; silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;; ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1127,7 +1138,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \ datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir libdir localedir mandir runstatedir
do do
eval ac_val=\$$ac_var eval ac_val=\$$ac_var
# Remove trailing slashes. # Remove trailing slashes.
@@ -1280,6 +1291,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var] --localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib] --libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include] --includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include] --oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -4908,6 +4920,52 @@ if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }; $as_echo "#define HAVE_SSL_SET_TLSEXT_HOST_NAME 1" >>confdefs.h $as_echo "yes" >&6; }; $as_echo "#define HAVE_SSL_SET_TLSEXT_HOST_NAME 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DTLS_client_method" >&5
$as_echo_n "checking for DTLS_client_method... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ssl.h>
int
main ()
{
DTLS_client_method()
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }; $as_echo "#define HAVE_DTLS_CLIENT_METHOD 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SSL_set_alpn_protos" >&5
$as_echo_n "checking for SSL_set_alpn_protos... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <openssl/ssl.h>
int
main ()
{
SSL_set_alpn_protos(NULL, NULL, 0)
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }; $as_echo "#define HAVE_ALPN_SUPPORT 1" >>confdefs.h
else else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; } $as_echo "no" >&6; }

View File

@@ -263,6 +263,14 @@ if test "$use_openssl" = "yes"; then
AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_tlsext_host_name(NULL, NULL)], AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_tlsext_host_name(NULL, NULL)],
[AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_SSL_SET_TLSEXT_HOST_NAME)], [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_SSL_SET_TLSEXT_HOST_NAME)],
[AC_MSG_RESULT([no])]) [AC_MSG_RESULT([no])])
AC_MSG_CHECKING([for DTLS_client_method])
AC_TRY_LINK([#include <openssl/ssl.h>], [DTLS_client_method()],
[AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_DTLS_CLIENT_METHOD)],
[AC_MSG_RESULT([no])])
AC_MSG_CHECKING([for SSL_set_alpn_protos])
AC_TRY_LINK([#include <openssl/ssl.h>], [SSL_set_alpn_protos(NULL, NULL, 0)],
[AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_ALPN_SUPPORT)],
[AC_MSG_RESULT([no])])
LIBS="$LIBS_TMP" LIBS="$LIBS_TMP"
fi fi

View File

@@ -184,8 +184,8 @@ int nsock_setup_udp(nsock_pool nsp, nsock_iod ms_iod, int af) {
return nsi->sd; return nsi->sd;
} }
/* This does the actual logistics of requesting a TCP connection. It is shared /* This does the actual logistics of requesting a connection. It is shared
* by nsock_connect_tcp and nsock_connect_ssl */ * by nsock_connect_tcp and nsock_connect_ssl, among others */
void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen,
unsigned short port) { unsigned short port) {
@@ -256,7 +256,7 @@ void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int
if (ms->engine->io_operations->iod_connect(ms, iod->sd, (struct sockaddr *)ss, sslen) == -1) { if (ms->engine->io_operations->iod_connect(ms, iod->sd, (struct sockaddr *)ss, sslen) == -1) {
int err = socket_errno(); int err = socket_errno();
if (proto == IPPROTO_UDP || (err != EINPROGRESS && err != EAGAIN)) { if ((proto == IPPROTO_UDP) || (err != EINPROGRESS && err != EAGAIN)) {
nse->event_done = 1; nse->event_done = 1;
nse->status = NSE_STATUS_ERROR; nse->status = NSE_STATUS_ERROR;
nse->errnum = err; nse->errnum = err;
@@ -376,7 +376,7 @@ nsock_event_id nsock_connect_sctp(nsock_pool nsp, nsock_iod ms_iod, nsock_ev_han
return nse->id; return nse->id;
} }
/* Request an SSL over TCP/SCTP connection to another system (by IP address). /* Request an SSL over TCP/SCTP/UDP connection to another system (by IP address).
* The in_addr is normal network byte order, but the port number should be given * The in_addr is normal network byte order, but the port number should be given
* in HOST BYTE ORDER. This function will call back only after it has made the * in HOST BYTE ORDER. This function will call back only after it has made the
* connection AND done the initial SSL negotiation. From that point on, you use * connection AND done the initial SSL negotiation. From that point on, you use
@@ -397,7 +397,12 @@ nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handl
struct nevent *nse; struct nevent *nse;
if (!ms->sslctx) if (!ms->sslctx)
nsock_pool_ssl_init(ms, 0); {
if (proto == IPPROTO_UDP)
nsock_pool_dtls_init(ms, 0);
else
nsock_pool_ssl_init(ms, 0);
}
assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN); assert(nsi->state == NSIOD_STATE_INITIAL || nsi->state == NSIOD_STATE_UNKNOWN);
@@ -405,14 +410,22 @@ nsock_event_id nsock_connect_ssl(nsock_pool nsp, nsock_iod nsiod, nsock_ev_handl
assert(nse); assert(nse);
/* Set our SSL_SESSION so we can benefit from session-id reuse. */ /* Set our SSL_SESSION so we can benefit from session-id reuse. */
nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session); /* but not with DTLS; save space in ClientHello message */
if (proto != IPPROTO_UDP)
nsi_set_ssl_session(nsi, (SSL_SESSION *)ssl_session);
nsock_log_info("SSL connection requested to %s:%hu/%s (IOD #%li) EID %li", if (proto == IPPROTO_UDP)
nsock_log_info("DTLS connection requested to %s:%hu/udp (IOD #%li) EID %li",
inet_ntop_ez(ss, sslen), port, nsi->id, nse->id);
else
nsock_log_info("SSL connection requested to %s:%hu/%s (IOD #%li) EID %li",
inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"), inet_ntop_ez(ss, sslen), port, (proto == IPPROTO_TCP ? "tcp" : "sctp"),
nsi->id, nse->id); nsi->id, nse->id);
/* Do the actual connect() */ /* Do the actual connect() */
nsock_connect_internal(ms, nse, SOCK_STREAM, proto, ss, sslen, port); nsock_connect_internal(ms, nse, (proto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM), proto, ss, sslen, port);
nsock_pool_add_event(ms, nse); nsock_pool_add_event(ms, nse);
return nse->id; return nse->id;

View File

@@ -377,7 +377,9 @@ void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status
} }
#if HAVE_SSL_SET_TLSEXT_HOST_NAME #if HAVE_SSL_SET_TLSEXT_HOST_NAME
if (iod->hostname != NULL) { /* Avoid sending SNI extension with DTLS because many servers don't allow
* fragmented ClientHello messages. */
if (iod->hostname != NULL && iod->lastproto != IPPROTO_UDP) {
if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1) if (SSL_set_tlsext_host_name(iod->ssl, iod->hostname) != 1)
fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL)); fatal("SSL_set_tlsext_host_name failed: %s", ERR_error_string(ERR_get_error(), NULL));
} }

View File

@@ -80,8 +80,7 @@
extern struct timeval nsock_tod; extern struct timeval nsock_tod;
/* Create an SSL_CTX and do initialization that is common to all init modes. */ static SSL_CTX *ssl_init_helper(const SSL_METHOD *method) {
static SSL_CTX *ssl_init_common() {
SSL_CTX *ctx; SSL_CTX *ctx;
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined LIBRESSL_VERSION_NUMBER
@@ -89,7 +88,7 @@ static SSL_CTX *ssl_init_common() {
SSL_library_init(); SSL_library_init();
#endif #endif
ctx = SSL_CTX_new(SSLv23_client_method()); ctx = SSL_CTX_new(method);
if (!ctx) { if (!ctx) {
fatal("OpenSSL failed to create a new SSL_CTX: %s", fatal("OpenSSL failed to create a new SSL_CTX: %s",
ERR_error_string(ERR_get_error(), NULL)); ERR_error_string(ERR_get_error(), NULL));
@@ -105,18 +104,19 @@ static SSL_CTX *ssl_init_common() {
return ctx; return ctx;
} }
/* Create an SSL_CTX and do initialization that is common to all init modes. */
static SSL_CTX *ssl_init_common() {
return ssl_init_helper(SSLv23_client_method());
}
/* Initializes an Nsock pool to create SSL connections. This sets an internal /* Initializes an Nsock pool to create SSL connections. This sets an internal
* SSL_CTX, which is like a template that sets options for all connections that * SSL_CTX, which is like a template that sets options for all connections that
* are made from it. The connections made from this context will use only secure * are made from it. The connections made from this context will use only secure
* ciphers but no server certificate verification is done. Returns the SSL_CTX * ciphers but no server certificate verification is done. Returns the SSL_CTX
* so you can set your own options. */ * so you can set your own options. */
nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) { static nsock_ssl_ctx nsock_pool_ssl_init_helper(struct npool *ms, int flags) {
struct npool *ms = (struct npool *)ms_pool;
char rndbuf[128]; char rndbuf[128];
if (ms->sslctx == NULL)
ms->sslctx = ssl_init_common();
/* Get_random_bytes may or may not provide high-quality randomness. Add it to /* Get_random_bytes may or may not provide high-quality randomness. Add it to
* the entropy pool without increasing the entropy estimate (third argument of * the entropy pool without increasing the entropy estimate (third argument of
* RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly * RAND_add is 0). We rely on OpenSSL's entropy gathering, called implicitly
@@ -146,6 +146,49 @@ nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
return ms->sslctx; return ms->sslctx;
} }
nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
struct npool *ms = (struct npool *)ms_pool;
if (ms->sslctx == NULL)
ms->sslctx = ssl_init_common();
return nsock_pool_ssl_init_helper(ms, flags);
}
#ifdef HAVE_DTLS_CLIENT_METHOD
/* Create an SSL_CTX and do initialisation, creating a DTLS client */
static SSL_CTX *dtls_init_common() {
return ssl_init_helper(DTLS_client_method());
}
/* Initializes an Nsock pool to create DTLS connections. Very much similar to
* nsock_pool_ssl_init, just with DTLS. */
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
SSL_CTX *dtls_ctx = NULL;
struct npool *ms = (struct npool *)ms_pool;
if (ms->sslctx == NULL)
ms->sslctx = dtls_init_common();
dtls_ctx = (SSL_CTX *) nsock_pool_ssl_init_helper(ms, flags);
/* Don't add padding or the ClientHello will fragment and not connect properly. */
SSL_CTX_clear_options(dtls_ctx, SSL_OP_TLSEXT_PADDING);
if (!SSL_CTX_set_cipher_list(dtls_ctx, "DEFAULT"))
fatal("Unable to set OpenSSL cipher list: %s",
ERR_error_string(ERR_get_error(), NULL));
return dtls_ctx;
}
#else /* OpenSSL Version does not support DTLS */
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
fatal("%s called with no OpenSSL DTLS support", __func__);
}
#endif
/* Check server certificate verification, after a connection is established. We /* Check server certificate verification, after a connection is established. We
* check first that a certificate was even offered, then call * check first that a certificate was even offered, then call
* SSL_get_verify_result to get the overall status of verification. (Just * SSL_get_verify_result to get the overall status of verification. (Just
@@ -180,6 +223,10 @@ nsock_ssl_ctx nsock_pool_ssl_init(nsock_pool ms_pool, int flags) {
fatal("%s called with no OpenSSL support", __func__); fatal("%s called with no OpenSSL support", __func__);
} }
nsock_ssl_ctx nsock_pool_dtls_init(nsock_pool ms_pool, int flags) {
fatal("%s called with no OpenSSL support", __func__);
}
int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) { int nsi_ssl_post_connect_verify(const nsock_iod nsockiod) {
return 1; return 1;
} }