Add a -sctp option to s_server

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3286)
This commit is contained in:
Matt Caswell 2017-04-20 09:56:56 +01:00
parent 5114d8227e
commit 72d0bc84de
3 changed files with 80 additions and 21 deletions

View file

@ -20,9 +20,9 @@
#define PORT "4433" #define PORT "4433"
#define PROTOCOL "tcp" #define PROTOCOL "tcp"
typedef int (*do_server_cb)(int s, int stype, unsigned char *context); typedef int (*do_server_cb)(int s, int stype, int prot, unsigned char *context);
int do_server(int *accept_sock, const char *host, const char *port, int do_server(int *accept_sock, const char *host, const char *port,
int family, int type, int family, int type, int protocol,
do_server_cb cb, do_server_cb cb,
unsigned char *context, int naccept); unsigned char *context, int naccept);
#ifdef HEADER_X509_H #ifdef HEADER_X509_H

View file

@ -91,9 +91,9 @@ typedef unsigned int u_int;
#endif #endif
static int not_resumable_sess_cb(SSL *s, int is_forward_secure); static int not_resumable_sess_cb(SSL *s, int is_forward_secure);
static int sv_body(int s, int stype, unsigned char *context); static int sv_body(int s, int stype, int prot, unsigned char *context);
static int www_body(int s, int stype, unsigned char *context); static int www_body(int s, int stype, int prot, unsigned char *context);
static int rev_body(int s, int stype, unsigned char *context); static int rev_body(int s, int stype, int prot, unsigned char *context);
static void close_accept_socket(void); static void close_accept_socket(void);
static int init_ssl_connection(SSL *s); static int init_ssl_connection(SSL *s);
static void print_stats(BIO *bp, SSL_CTX *ctx); static void print_stats(BIO *bp, SSL_CTX *ctx);
@ -719,7 +719,7 @@ typedef enum OPTION_choice {
OPT_SRPUSERSEED, OPT_REV, OPT_WWW, OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC, OPT_SRPUSERSEED, OPT_REV, OPT_WWW, OPT_UPPER_WWW, OPT_HTTP, OPT_ASYNC,
OPT_SSL_CONFIG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF, OPT_SSL_CONFIG, OPT_SPLIT_SEND_FRAG, OPT_MAX_PIPELINES, OPT_READ_BUF,
OPT_SSL3, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1, OPT_SSL3, OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1,
OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN, OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_LISTEN,
OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL, OPT_ID_PREFIX, OPT_RAND, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
@ -903,6 +903,9 @@ const OPTIONS s_server_options[] = {
#ifndef OPENSSL_NO_DTLS1_2 #ifndef OPENSSL_NO_DTLS1_2
{"dtls1_2", OPT_DTLS1_2, '-', "Just talk DTLSv1.2"}, {"dtls1_2", OPT_DTLS1_2, '-', "Just talk DTLSv1.2"},
#endif #endif
#ifndef OPENSSL_NO_SCTP
{"sctp", OPT_SCTP, '-', "Use SCTP"},
#endif
#ifndef OPENSSL_NO_DH #ifndef OPENSSL_NO_DH
{"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"},
#endif #endif
@ -960,7 +963,7 @@ int s_server_main(int argc, char *argv[])
int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM; int s_cert_format = FORMAT_PEM, s_key_format = FORMAT_PEM;
int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; int s_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM;
int rev = 0, naccept = -1, sdebug = 0; int rev = 0, naccept = -1, sdebug = 0;
int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM; int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM, protocol = 0;
int state = 0, crl_format = FORMAT_PEM, crl_download = 0; int state = 0, crl_format = FORMAT_PEM, crl_download = 0;
char *host = NULL; char *host = NULL;
char *port = BUF_strdup(PORT); char *port = BUF_strdup(PORT);
@ -1429,6 +1432,11 @@ int s_server_main(int argc, char *argv[])
min_version = DTLS1_2_VERSION; min_version = DTLS1_2_VERSION;
max_version = DTLS1_2_VERSION; max_version = DTLS1_2_VERSION;
socket_type = SOCK_DGRAM; socket_type = SOCK_DGRAM;
#endif
break;
case OPT_SCTP:
#ifndef OPENSSL_NO_SCTP
protocol = IPPROTO_SCTP;
#endif #endif
break; break;
case OPT_TIMEOUT: case OPT_TIMEOUT:
@ -1543,6 +1551,17 @@ int s_server_main(int argc, char *argv[])
} }
#endif #endif
#ifndef OPENSSL_NO_SCTP
if (protocol == IPPROTO_SCTP) {
if (socket_type != SOCK_DGRAM) {
BIO_printf(bio_err, "Can't use -sctp without DTLS\n");
goto end;
}
/* SCTP is unusual. It uses DTLS over a SOCK_STREAM protocol */
socket_type = SOCK_STREAM;
}
#endif
if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) { if (split_send_fragment > SSL3_RT_MAX_PLAIN_LENGTH) {
BIO_printf(bio_err, "Bad split send fragment size\n"); BIO_printf(bio_err, "Bad split send fragment size\n");
goto end; goto end;
@ -2018,7 +2037,7 @@ int s_server_main(int argc, char *argv[])
&& unlink_unix_path) && unlink_unix_path)
unlink(host); unlink(host);
#endif #endif
do_server(&accept_socket, host, port, socket_family, socket_type, do_server(&accept_socket, host, port, socket_family, socket_type, protocol,
server_cb, context, naccept); server_cb, context, naccept);
print_stats(bio_s_out, ctx); print_stats(bio_s_out, ctx);
ret = 0; ret = 0;
@ -2090,7 +2109,7 @@ static void print_stats(BIO *bio, SSL_CTX *ssl_ctx)
SSL_CTX_sess_get_cache_size(ssl_ctx)); SSL_CTX_sess_get_cache_size(ssl_ctx));
} }
static int sv_body(int s, int stype, unsigned char *context) static int sv_body(int s, int stype, int prot, unsigned char *context)
{ {
char *buf = NULL; char *buf = NULL;
fd_set readfds; fd_set readfds;
@ -2105,6 +2124,13 @@ static int sv_body(int s, int stype, unsigned char *context)
#else #else
struct timeval *timeoutp; struct timeval *timeoutp;
#endif #endif
#ifndef OPENSSL_NO_DTLS
#ifndef OPENSSL_NO_SCTP
int isdtls = (stype == SOCK_DGRAM || prot == IPPROTO_SCTP);
#else
int isdtls = (stype == SOCK_DGRAM);
#endif
#endif
buf = app_malloc(bufsize, "server buffer"); buf = app_malloc(bufsize, "server buffer");
if (s_nbio) { if (s_nbio) {
@ -2136,9 +2162,13 @@ static int sv_body(int s, int stype, unsigned char *context)
goto err; goto err;
} }
#ifndef OPENSSL_NO_DTLS #ifndef OPENSSL_NO_DTLS
if (stype == SOCK_DGRAM) { if (isdtls) {
#ifndef OPENSSL_NO_SCTP
sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (prot == IPPROTO_SCTP)
sbio = BIO_new_dgram_sctp(s, BIO_NOCLOSE);
else
#endif
sbio = BIO_new_dgram(s, BIO_NOCLOSE);
if (enable_timeouts) { if (enable_timeouts) {
timeout.tv_sec = 0; timeout.tv_sec = 0;
@ -2169,12 +2199,20 @@ static int sv_body(int s, int stype, unsigned char *context)
/* want to do MTU discovery */ /* want to do MTU discovery */
BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL);
/* turn on cookie exchange */ if (prot != IPPROTO_SCTP) {
SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); /* Turn on cookie exchange. Not necessary for SCTP */
SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE);
}
} else } else
#endif #endif
sbio = BIO_new_socket(s, BIO_NOCLOSE); sbio = BIO_new_socket(s, BIO_NOCLOSE);
if (sbio == NULL) {
BIO_printf(bio_err, "Unable to create BIO\n");
ERR_print_errors(bio_err);
goto err;
}
if (s_nbio_test) { if (s_nbio_test) {
BIO *test; BIO *test;
@ -2767,7 +2805,7 @@ static DH *load_dh_param(const char *dhfile)
} }
#endif #endif
static int www_body(int s, int stype, unsigned char *context) static int www_body(int s, int stype, int prot, unsigned char *context)
{ {
char *buf = NULL; char *buf = NULL;
int ret = 1; int ret = 1;
@ -3153,7 +3191,7 @@ static int www_body(int s, int stype, unsigned char *context)
return (ret); return (ret);
} }
static int rev_body(int s, int stype, unsigned char *context) static int rev_body(int s, int stype, int prot, unsigned char *context)
{ {
char *buf = NULL; char *buf = NULL;
int i; int i;

View file

@ -128,7 +128,7 @@ int init_client(int *sock, const char *host, const char *port,
* 0 on failure, something other on success. * 0 on failure, something other on success.
*/ */
int do_server(int *accept_sock, const char *host, const char *port, int do_server(int *accept_sock, const char *host, const char *port,
int family, int type, do_server_cb cb, int family, int type, int protocol, do_server_cb cb,
unsigned char *context, int naccept) unsigned char *context, int naccept)
{ {
int asock = 0; int asock = 0;
@ -140,7 +140,8 @@ int do_server(int *accept_sock, const char *host, const char *port,
if (!BIO_sock_init()) if (!BIO_sock_init())
return 0; return 0;
if (!BIO_lookup(host, port, BIO_LOOKUP_SERVER, family, type, &res)) { if (!BIO_lookup_ex(host, port, BIO_LOOKUP_SERVER, family, type, protocol,
&res)) {
ERR_print_errors(bio_err); ERR_print_errors(bio_err);
return 0; return 0;
} }
@ -148,7 +149,8 @@ int do_server(int *accept_sock, const char *host, const char *port,
/* Admittedly, these checks are quite paranoid, we should not get /* Admittedly, these checks are quite paranoid, we should not get
* anything in the BIO_ADDRINFO chain that we haven't asked for */ * anything in the BIO_ADDRINFO chain that we haven't asked for */
OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res)) OPENSSL_assert((family == AF_UNSPEC || family == BIO_ADDRINFO_family(res))
&& (type == 0 || type == BIO_ADDRINFO_socktype(res))); && (type == 0 || type == BIO_ADDRINFO_socktype(res))
&& (protocol == 0 || protocol == BIO_ADDRINFO_protocol(res)));
asock = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res), asock = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res),
BIO_ADDRINFO_protocol(res), 0); BIO_ADDRINFO_protocol(res), 0);
@ -161,6 +163,25 @@ int do_server(int *accept_sock, const char *host, const char *port,
goto end; goto end;
} }
#ifndef OPENSSL_NO_SCTP
if (protocol == IPPROTO_SCTP) {
/*
* For SCTP we have to set various options on the socket prior to
* accepting. This is done automatically by BIO_new_dgram_sctp().
* We don't actually need the created BIO though so we free it again
* immediately.
*/
BIO *tmpbio = BIO_new_dgram_sctp(asock, BIO_NOCLOSE);
if (tmpbio == NULL) {
BIO_closesocket(asock);
ERR_print_errors(bio_err);
goto end;
}
BIO_free(tmpbio);
}
#endif
BIO_ADDRINFO_free(res); BIO_ADDRINFO_free(res);
res = NULL; res = NULL;
@ -176,10 +197,10 @@ int do_server(int *accept_sock, const char *host, const char *port,
BIO_closesocket(asock); BIO_closesocket(asock);
break; break;
} }
i = (*cb)(sock, type, context); i = (*cb)(sock, type, protocol, context);
BIO_closesocket(sock); BIO_closesocket(sock);
} else { } else {
i = (*cb)(asock, type, context); i = (*cb)(asock, type, protocol, context);
} }
if (naccept != -1) if (naccept != -1)