From 72d0bc84de394e93f7d756a997c0d42a4ae35058 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 20 Apr 2017 09:56:56 +0100 Subject: [PATCH] Add a -sctp option to s_server Reviewed-by: Richard Levitte (Merged from https://github.com/openssl/openssl/pull/3286) --- apps/s_apps.h | 4 +-- apps/s_server.c | 66 ++++++++++++++++++++++++++++++++++++++----------- apps/s_socket.c | 31 +++++++++++++++++++---- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/apps/s_apps.h b/apps/s_apps.h index aa0565d360..1f76009b8d 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -20,9 +20,9 @@ #define PORT "4433" #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 family, int type, + int family, int type, int protocol, do_server_cb cb, unsigned char *context, int naccept); #ifdef HEADER_X509_H diff --git a/apps/s_server.c b/apps/s_server.c index 4bd2620c9f..81c3973d6f 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -91,9 +91,9 @@ typedef unsigned int u_int; #endif 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 www_body(int s, int stype, unsigned char *context); -static int rev_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, int prot, unsigned char *context); +static int rev_body(int s, int stype, int prot, unsigned char *context); static void close_accept_socket(void); static int init_ssl_connection(SSL *s); 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_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_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_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN, OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN, @@ -903,6 +903,9 @@ const OPTIONS s_server_options[] = { #ifndef OPENSSL_NO_DTLS1_2 {"dtls1_2", OPT_DTLS1_2, '-', "Just talk DTLSv1.2"}, #endif +#ifndef OPENSSL_NO_SCTP + {"sctp", OPT_SCTP, '-', "Use SCTP"}, +#endif #ifndef OPENSSL_NO_DH {"no_dhe", OPT_NO_DHE, '-', "Disable ephemeral DH"}, #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_dcert_format = FORMAT_PEM, s_dkey_format = FORMAT_PEM; 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; char *host = NULL; char *port = BUF_strdup(PORT); @@ -1429,6 +1432,11 @@ int s_server_main(int argc, char *argv[]) min_version = DTLS1_2_VERSION; max_version = DTLS1_2_VERSION; socket_type = SOCK_DGRAM; +#endif + break; + case OPT_SCTP: +#ifndef OPENSSL_NO_SCTP + protocol = IPPROTO_SCTP; #endif break; case OPT_TIMEOUT: @@ -1543,6 +1551,17 @@ int s_server_main(int argc, char *argv[]) } #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) { BIO_printf(bio_err, "Bad split send fragment size\n"); goto end; @@ -2018,7 +2037,7 @@ int s_server_main(int argc, char *argv[]) && unlink_unix_path) unlink(host); #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); print_stats(bio_s_out, ctx); ret = 0; @@ -2090,7 +2109,7 @@ static void print_stats(BIO *bio, SSL_CTX *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; fd_set readfds; @@ -2105,6 +2124,13 @@ static int sv_body(int s, int stype, unsigned char *context) #else struct timeval *timeoutp; #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"); if (s_nbio) { @@ -2136,9 +2162,13 @@ static int sv_body(int s, int stype, unsigned char *context) goto err; } #ifndef OPENSSL_NO_DTLS - if (stype == SOCK_DGRAM) { - - sbio = BIO_new_dgram(s, BIO_NOCLOSE); + if (isdtls) { +#ifndef OPENSSL_NO_SCTP + if (prot == IPPROTO_SCTP) + sbio = BIO_new_dgram_sctp(s, BIO_NOCLOSE); + else +#endif + sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (enable_timeouts) { timeout.tv_sec = 0; @@ -2169,12 +2199,20 @@ static int sv_body(int s, int stype, unsigned char *context) /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); - /* turn on cookie exchange */ - SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); + if (prot != IPPROTO_SCTP) { + /* Turn on cookie exchange. Not necessary for SCTP */ + SSL_set_options(con, SSL_OP_COOKIE_EXCHANGE); + } } else #endif 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) { BIO *test; @@ -2767,7 +2805,7 @@ static DH *load_dh_param(const char *dhfile) } #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; int ret = 1; @@ -3153,7 +3191,7 @@ static int www_body(int s, int stype, unsigned char *context) 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; int i; diff --git a/apps/s_socket.c b/apps/s_socket.c index d16f5ad817..97dc9afffb 100644 --- a/apps/s_socket.c +++ b/apps/s_socket.c @@ -128,7 +128,7 @@ int init_client(int *sock, const char *host, const char *port, * 0 on failure, something other on success. */ 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) { int asock = 0; @@ -140,7 +140,8 @@ int do_server(int *accept_sock, const char *host, const char *port, if (!BIO_sock_init()) 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); 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 * anything in the BIO_ADDRINFO chain that we haven't asked for */ 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), BIO_ADDRINFO_protocol(res), 0); @@ -161,6 +163,25 @@ int do_server(int *accept_sock, const char *host, const char *port, 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); res = NULL; @@ -176,10 +197,10 @@ int do_server(int *accept_sock, const char *host, const char *port, BIO_closesocket(asock); break; } - i = (*cb)(sock, type, context); + i = (*cb)(sock, type, protocol, context); BIO_closesocket(sock); } else { - i = (*cb)(asock, type, context); + i = (*cb)(asock, type, protocol, context); } if (naccept != -1)