[openssl-commits] [openssl] master update

Matt Caswell matt at openssl.org
Tue Apr 25 13:01:29 UTC 2017


The branch master has been updated
       via  f7b3cb2ad0fac9d5ea0025c4d84ff4603a78b64e (commit)
       via  561f6f1ed237cb9a5a9020e58a368dd9d351b40b (commit)
       via  ce466c96f0eb14e5c35181e54e52164de1afe921 (commit)
       via  e829142846467b4815d96fe9198e73d5e4d9bbf1 (commit)
       via  c90da922ddaa3b470f4c1c11d02f370589a31912 (commit)
       via  0f5df0f1037590de12cc11eeab26fe29bf3f16a3 (commit)
       via  cf1560092316c7d2318c5783192781d4e2d41277 (commit)
       via  00da4f4dd9d02c8e0d0d499ba7a0d29e7c1989a4 (commit)
       via  4ef8a6b22b830d89d5f3e2ff0d63c2040a9f0cac (commit)
       via  978b945b9493ddc5930e5b2186feb584b9952460 (commit)
       via  83964ca0dac18df510a315ff486ecc346521e15d (commit)
       via  41b3c9ce2a02195aa7cf74c90b80468354ac708d (commit)
       via  aefb925647175a310df73416c9c7253424a65106 (commit)
       via  bd79bcb42bab120575fc398692b7b61b1c5e6ed2 (commit)
       via  c4666bfa13480c1e700a0d487300da2a56e889af (commit)
       via  dcf88c5b79cbd433ee37276cdf63cdb5d49673cd (commit)
       via  8ccc237720d59cdf249c2c901d19f1fec739e66e (commit)
       via  72d0bc84de394e93f7d756a997c0d42a4ae35058 (commit)
       via  5114d8227e0516fffc0c8653f5118290709f6494 (commit)
      from  b3c42fc2503a685a9e51427c1a83c8f09487389d (commit)


- Log -----------------------------------------------------------------
commit f7b3cb2ad0fac9d5ea0025c4d84ff4603a78b64e
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 15:36:02 2017 +0100

    Fix doc-nits issue
    
    BIO_lookup_ex() should be in the NAME section
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 561f6f1ed237cb9a5a9020e58a368dd9d351b40b
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 14:15:49 2017 +0100

    Address review feedback for the SCTP changes
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit ce466c96f0eb14e5c35181e54e52164de1afe921
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 13:58:07 2017 +0100

    Fix issue in 18-dtls-renegotiate.conf.in
    
    Don't skip all tests if SCTP is disabled!
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit e829142846467b4815d96fe9198e73d5e4d9bbf1
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 11:46:09 2017 +0100

    Document BIO_lookup_ex()
    
    We also change the enum type to an int.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit c90da922ddaa3b470f4c1c11d02f370589a31912
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 11:45:42 2017 +0100

    Fix some variable references in init_client
    
    We were incorrectly using "res" when we meant "ai"
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 0f5df0f1037590de12cc11eeab26fe29bf3f16a3
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 11:19:05 2017 +0100

    Add SCTP testing for 04-client_auth.conf
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit cf1560092316c7d2318c5783192781d4e2d41277
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 11:03:11 2017 +0100

    Add SCTP testing for 11-dtls_resumption.conf
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 00da4f4dd9d02c8e0d0d499ba7a0d29e7c1989a4
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 10:16:21 2017 +0100

    Add SCTP testing to 07-dtls-protocol-version.conf
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 4ef8a6b22b830d89d5f3e2ff0d63c2040a9f0cac
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 09:43:17 2017 +0100

    Add SCTP testing to 18-dtls-renegotiate.conf
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 978b945b9493ddc5930e5b2186feb584b9952460
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 09:42:53 2017 +0100

    Add SCTP testing to 16-dtls-certstatus.conf
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 83964ca0dac18df510a315ff486ecc346521e15d
Author: Matt Caswell <matt at openssl.org>
Date:   Mon Apr 24 09:42:28 2017 +0100

    Add support to test_ssl_new for testing with DTLS over SCTP
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 41b3c9ce2a02195aa7cf74c90b80468354ac708d
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Apr 21 16:56:06 2017 +0100

    Fix problem with SCTP close_notify alerts
    
    In SCTP the code was only allowing a send of a close_notify alert if the
    socket is dry. If the socket isn't dry then it was attempting to save away
    the close_notify alert to resend later when it is dry and then it returned
    success. However because the application then thinks that the close_notify
    alert has been successfully sent it never re-enters the DTLS code to
    actually resend the alert. A much simpler solution is to just fail with a
    retryable error in the event that the socket isn't dry. That way the
    application knows to retry sending the close_notify alert.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit aefb925647175a310df73416c9c7253424a65106
Author: Matt Caswell <matt at openssl.org>
Date:   Fri Apr 21 14:00:20 2017 +0100

    Don't attempt to send fragments > max_send_fragment in DTLS
    
    We were allocating the write buffer based on the size of max_send_fragment,
    but ignoring it when writing data. We should fragment handshake messages
    if they exceed max_send_fragment and reject application data writes that
    are too large.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit bd79bcb42bab120575fc398692b7b61b1c5e6ed2
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 20 15:13:28 2017 +0100

    Remove special case code for SCTP reneg handling
    
    There was code existing which attempted to handle the case where application
    data is received after a reneg handshake has started in SCTP. In normal DTLS
    we just fail the connection if this occurs, so there doesn't seem any reason
    to try and work around it for SCTP. In practice it didn't work properly
    anyway and is probably a bad idea to start with.
    
    Fixes #3251
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit c4666bfa13480c1e700a0d487300da2a56e889af
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 20 14:45:33 2017 +0100

    Ask libssl if we should retry not the socket
    
    s_server was asking the underlying socket if it is a retryable error rather
    than libssl which has more information.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit dcf88c5b79cbd433ee37276cdf63cdb5d49673cd
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 20 10:58:27 2017 +0100

    Add better error logging if SCTP AUTH chunks are not enabled
    
    In order to use SCTP over DTLS we need ACTP AUTH chunks to be enabled in
    the kernel.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 8ccc237720d59cdf249c2c901d19f1fec739e66e
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 20 09:57:12 2017 +0100

    Add a -sctp option to s_client
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 72d0bc84de394e93f7d756a997c0d42a4ae35058
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 20 09:56:56 2017 +0100

    Add a -sctp option to s_server
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

commit 5114d8227e0516fffc0c8653f5118290709f6494
Author: Matt Caswell <matt at openssl.org>
Date:   Thu Apr 20 09:51:55 2017 +0100

    Add a BIO_lookup_ex() function
    
    The existing BIO_lookup() wraps a call to getaddrinfo and provides an
    abstracted capability to lookup addresses based on socket type and family.
    However it provides no ability to lookup based on protocol. Normally,
    when dealing with TCP/UDP this is not required. However getaddrinfo (at
    least on linux) never returns SCTP addresses unless you specifically ask
    for them in the protocol field. Therefore BIO_lookup_ex() is added which
    provides the protocol field.
    
    Reviewed-by: Richard Levitte <levitte at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/3286)

-----------------------------------------------------------------------

Summary of changes:
 apps/s_apps.h                              |   6 +-
 apps/s_client.c                            |  40 +++-
 apps/s_server.c                            |  72 +++++--
 apps/s_socket.c                            |  65 +++++-
 crypto/bio/b_addr.c                        |  33 ++--
 crypto/bio/bio_err.c                       |   4 +-
 crypto/bio/bss_dgram.c                     |  60 ++----
 doc/man3/BIO_ADDRINFO.pod                  |  41 +++-
 include/openssl/bio.h                      |   5 +
 include/openssl/ssl.h                      |   1 +
 ssl/d1_msg.c                               |  13 +-
 ssl/record/rec_layer_d1.c                  |  28 +--
 ssl/ssl_err.c                              |   2 +
 ssl/statem/statem.c                        |  23 ---
 ssl/statem/statem.h                        |   7 -
 ssl/statem/statem_clnt.c                   |  24 +--
 ssl/statem/statem_dtls.c                   |   3 +
 ssl/statem/statem_lib.c                    |   5 +-
 ssl/statem/statem_srvr.c                   |  37 ----
 test/handshake_helper.c                    | 207 ++++++++++++++++---
 test/recipes/80-test_ssl_new.t             |  10 +-
 test/ssl-tests/02-protocol-version.conf    | 208 ++++++++++----------
 test/ssl-tests/04-client_auth.conf.in      | 264 +++++++++++++------------
 test/ssl-tests/16-dtls-certstatus.conf.in  |  35 +++-
 test/ssl-tests/18-dtls-renegotiate.conf    |   9 +
 test/ssl-tests/18-dtls-renegotiate.conf.in | 306 +++++++++++++++--------------
 test/ssl-tests/protocol_version.pm         | 143 +++++++-------
 test/ssl_test_ctx.c                        |   2 +
 test/ssl_test_ctx.h                        |   2 +
 util/libcrypto.num                         |   1 +
 30 files changed, 956 insertions(+), 700 deletions(-)

diff --git a/apps/s_apps.h b/apps/s_apps.h
index aa0565d..38c6b67 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
@@ -38,7 +38,7 @@ int ssl_print_groups(BIO *out, SSL *s, int noshared);
 #endif
 int ssl_print_tmp_key(BIO *out, SSL *s);
 int init_client(int *sock, const char *host, const char *port,
-                int family, int type);
+                int family, int type, int protocol);
 int should_retry(int i);
 
 long bio_dump_callback(BIO *bio, int cmd, const char *argp,
diff --git a/apps/s_client.c b/apps/s_client.c
index 9267393..52b99ce 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -539,7 +539,7 @@ typedef enum OPTION_choice {
 #endif
     OPT_SSL3, OPT_SSL_CONFIG,
     OPT_TLS1_3, OPT_TLS1_2, OPT_TLS1_1, OPT_TLS1, OPT_DTLS, OPT_DTLS1,
-    OPT_DTLS1_2, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS,
+    OPT_DTLS1_2, OPT_SCTP, OPT_TIMEOUT, OPT_MTU, OPT_KEYFORM, OPT_PASS,
     OPT_CERT_CHAIN, OPT_CAPATH, OPT_NOCAPATH, OPT_CHAINCAPATH,
         OPT_VERIFYCAPATH,
     OPT_KEY, OPT_RECONNECT, OPT_BUILD_CHAIN, OPT_CAFILE, OPT_NOCAFILE,
@@ -699,6 +699,9 @@ const OPTIONS s_client_options[] = {
 #ifndef OPENSSL_NO_DTLS1_2
     {"dtls1_2", OPT_DTLS1_2, '-', "Just use DTLSv1.2"},
 #endif
+#ifndef OPENSSL_NO_SCTP
+    {"sctp", OPT_SCTP, '-', "Use SCTP"},
+#endif
 #ifndef OPENSSL_NO_SSL_TRACE
     {"trace", OPT_TRACE, '-', "Show trace output of protocol messages"},
 #endif
@@ -847,7 +850,7 @@ int s_client_main(int argc, char **argv)
     int reconnect = 0, verify = SSL_VERIFY_NONE, vpmtouched = 0;
     int ret = 1, in_init = 1, i, nbio_test = 0, s = -1, k, width, state = 0;
     int sbuf_len, sbuf_off, cmdletters = 1;
-    int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM;
+    int socket_family = AF_UNSPEC, socket_type = SOCK_STREAM, protocol = 0;
     int starttls_proto = PROTO_OFF, crl_format = FORMAT_PEM, crl_download = 0;
     int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending;
 #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS)
@@ -900,6 +903,7 @@ int s_client_main(int argc, char **argv)
 #endif
     BIO *bio_c_msg = NULL;
     const char *keylog_file = NULL, *early_data_file = NULL;
+    int isdtls = 0;
 
     FD_ZERO(&readfds);
     FD_ZERO(&writefds);
@@ -1217,6 +1221,7 @@ int s_client_main(int argc, char **argv)
 #ifndef OPENSSL_NO_DTLS
             meth = DTLS_client_method();
             socket_type = SOCK_DGRAM;
+            isdtls = 1;
 #endif
             break;
         case OPT_DTLS1:
@@ -1225,6 +1230,7 @@ int s_client_main(int argc, char **argv)
             min_version = DTLS1_VERSION;
             max_version = DTLS1_VERSION;
             socket_type = SOCK_DGRAM;
+            isdtls = 1;
 #endif
             break;
         case OPT_DTLS1_2:
@@ -1233,6 +1239,12 @@ int s_client_main(int argc, char **argv)
             min_version = DTLS1_2_VERSION;
             max_version = DTLS1_2_VERSION;
             socket_type = SOCK_DGRAM;
+            isdtls = 1;
+#endif
+            break;
+        case OPT_SCTP:
+#ifndef OPENSSL_NO_SCTP
+            protocol = IPPROTO_SCTP;
 #endif
             break;
         case OPT_TIMEOUT:
@@ -1432,6 +1444,17 @@ int s_client_main(int argc, char **argv)
         goto end;
     }
 
+#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;
@@ -1804,7 +1827,8 @@ int s_client_main(int argc, char **argv)
     }
 
  re_start:
-    if (init_client(&s, host, port, socket_family, socket_type) == 0) {
+    if (init_client(&s, host, port, socket_family, socket_type, protocol)
+            == 0) {
         BIO_printf(bio_err, "connect:errno=%d\n", get_last_socket_error());
         BIO_closesocket(s);
         goto end;
@@ -1819,10 +1843,16 @@ int s_client_main(int argc, char **argv)
         BIO_printf(bio_c_out, "Turned on non blocking io\n");
     }
 #ifndef OPENSSL_NO_DTLS
-    if (socket_type == SOCK_DGRAM) {
+    if (isdtls) {
         union BIO_sock_info_u peer_info;
 
-        sbio = BIO_new_dgram(s, BIO_NOCLOSE);
+#ifndef OPENSSL_NO_SCTP
+        if (protocol == IPPROTO_SCTP)
+            sbio = BIO_new_dgram_sctp(s, BIO_NOCLOSE);
+        else
+#endif
+            sbio = BIO_new_dgram(s, BIO_NOCLOSE);
+
         if ((peer_info.addr = BIO_ADDR_new()) == NULL) {
             BIO_printf(bio_err, "memory allocation failure\n");
             BIO_closesocket(s);
diff --git a/apps/s_server.c b/apps/s_server.c
index 4bd2620..7fb7772 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);
@@ -1431,6 +1434,11 @@ int s_server_main(int argc, char *argv[])
             socket_type = SOCK_DGRAM;
 #endif
             break;
+        case OPT_SCTP:
+#ifndef OPENSSL_NO_SCTP
+            protocol = IPPROTO_SCTP;
+#endif
+            break;
         case OPT_TIMEOUT:
 #ifndef OPENSSL_NO_DTLS
             enable_timeouts = 1;
@@ -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;
 
@@ -2608,7 +2646,7 @@ static int init_ssl_connection(SSL *con)
         i = SSL_accept(con);
 
         if (i <= 0)
-            retry = BIO_sock_should_retry(i);
+            retry = !SSL_want_nothing(con);
 #ifdef CERT_CB_TEST_RETRY
         {
             while (i <= 0
@@ -2618,7 +2656,7 @@ static int init_ssl_connection(SSL *con)
                            "LOOKUP from certificate callback during accept\n");
                 i = SSL_accept(con);
                 if (i <= 0)
-                    retry = BIO_sock_should_retry(i);
+                    retry = !SSL_want_nothing(con);
             }
         }
 #endif
@@ -2639,7 +2677,7 @@ static int init_ssl_connection(SSL *con)
                 BIO_printf(bio_s_out, "LOOKUP not successful\n");
             i = SSL_accept(con);
             if (i <= 0)
-                retry = BIO_sock_should_retry(i);
+                retry = !SSL_want_nothing(con);
         }
 #endif
     } while (i < 0 && SSL_waiting_for_async(con));
@@ -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 d16f5ad..1c5c137 100644
--- a/apps/s_socket.c
+++ b/apps/s_socket.c
@@ -44,6 +44,7 @@ typedef unsigned int u_int;
  * @family: desired socket family, may be AF_INET, AF_INET6, AF_UNIX or
  *  AF_UNSPEC
  * @type: socket type, must be SOCK_STREAM or SOCK_DGRAM
+ * @protocol: socket protocol, e.g. IPPROTO_TCP or IPPROTO_UDP (or 0 for any)
  *
  * This will create a socket and use it to connect to a host:port, or if
  * family == AF_UNIX, to the path found in host.
@@ -55,7 +56,7 @@ typedef unsigned int u_int;
  * Returns 1 on success, 0 on failure.
  */
 int init_client(int *sock, const char *host, const char *port,
-                int family, int type)
+                int family, int type, int protocol)
 {
     BIO_ADDRINFO *res = NULL;
     const BIO_ADDRINFO *ai = NULL;
@@ -64,7 +65,8 @@ int init_client(int *sock, const char *host, const char *port,
     if (!BIO_sock_init())
         return 0;
 
-    ret = BIO_lookup(host, port, BIO_LOOKUP_CLIENT, family, type, &res);
+    ret = BIO_lookup_ex(host, port, BIO_LOOKUP_CLIENT, family, type, protocol,
+                        &res);
     if (ret == 0) {
         ERR_print_errors(bio_err);
         return 0;
@@ -75,17 +77,39 @@ int init_client(int *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)));
+        OPENSSL_assert((family == AF_UNSPEC
+                        || family == BIO_ADDRINFO_family(ai))
+                       && (type == 0 || type == BIO_ADDRINFO_socktype(ai))
+                       && (protocol == 0
+                           || protocol == BIO_ADDRINFO_protocol(ai)));
 
         *sock = BIO_socket(BIO_ADDRINFO_family(ai), BIO_ADDRINFO_socktype(ai),
-                           BIO_ADDRINFO_protocol(res), 0);
+                           BIO_ADDRINFO_protocol(ai), 0);
         if (*sock == INVALID_SOCKET) {
             /* Maybe the kernel doesn't support the socket family, even if
              * BIO_lookup() added it in the returned result...
              */
             continue;
         }
+
+#ifndef OPENSSL_NO_SCTP
+        if (protocol == IPPROTO_SCTP) {
+            /*
+             * For SCTP we have to set various options on the socket prior to
+             * connecting. 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(*sock, BIO_NOCLOSE);
+
+            if (tmpbio == NULL) {
+                ERR_print_errors(bio_err);
+                return 0;
+            }
+            BIO_free(tmpbio);
+        }
+#endif
+
         if (!BIO_connect(*sock, BIO_ADDRINFO_address(ai), 0)) {
             BIO_closesocket(*sock);
             *sock = INVALID_SOCKET;
@@ -128,7 +152,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 +164,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 +173,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 +187,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 +221,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)
diff --git a/crypto/bio/b_addr.c b/crypto/bio/b_addr.c
index 289404c..b8e1f96 100644
--- a/crypto/bio/b_addr.c
+++ b/crypto/bio/b_addr.c
@@ -609,8 +609,15 @@ DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init)
     return bio_lookup_lock != NULL;
 }
 
+int BIO_lookup(const char *host, const char *service,
+               enum BIO_lookup_type lookup_type,
+               int family, int socktype, BIO_ADDRINFO **res)
+{
+    return BIO_lookup_ex(host, service, lookup_type, family, socktype, 0, res);
+}
+
 /*-
- * BIO_lookup - look up the node and service you want to connect to.
+ * BIO_lookup_ex - look up the node and service you want to connect to.
  * @node: the node you want to connect to.
  * @service: the service you want to connect to.
  * @lookup_type: declare intent with the result, client or server.
@@ -618,6 +625,10 @@ DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init)
  *  AF_INET, AF_INET6 or AF_UNIX.
  * @socktype: The socket type you want to use.  Can be SOCK_STREAM, SOCK_DGRAM
  *  or 0 for all.
+ * @protocol: The protocol to use, e.g. IPPROTO_TCP or IPPROTO_UDP or 0 for all.
+ *            Note that some platforms may not return IPPROTO_SCTP without
+ *            explicitly requesting it (i.e. IPPROTO_SCTP may not be returned
+ *            with 0 for the protocol)
  * @res: Storage place for the resulting list of returned addresses
  *
  * This will do a lookup of the node and service that you want to connect to.
@@ -627,9 +638,8 @@ DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init)
  *
  * The return value is 1 on success or 0 in case of error.
  */
-int BIO_lookup(const char *host, const char *service,
-               enum BIO_lookup_type lookup_type,
-               int family, int socktype, BIO_ADDRINFO **res)
+int BIO_lookup_ex(const char *host, const char *service, int lookup_type,
+                  int family, int socktype, int protocol, BIO_ADDRINFO **res)
 {
     int ret = 0;                 /* Assume failure */
 
@@ -646,7 +656,7 @@ int BIO_lookup(const char *host, const char *service,
 #endif
         break;
     default:
-        BIOerr(BIO_F_BIO_LOOKUP, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY);
+        BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY);
         return 0;
     }
 
@@ -655,7 +665,7 @@ int BIO_lookup(const char *host, const char *service,
         if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res))
             return 1;
         else
-            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
+            BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE);
         return 0;
     }
 #endif
@@ -672,6 +682,7 @@ int BIO_lookup(const char *host, const char *service,
 
         hints.ai_family = family;
         hints.ai_socktype = socktype;
+        hints.ai_protocol = protocol;
 
         if (lookup_type == BIO_LOOKUP_SERVER)
             hints.ai_flags |= AI_PASSIVE;
@@ -683,14 +694,14 @@ int BIO_lookup(const char *host, const char *service,
 # ifdef EAI_SYSTEM
         case EAI_SYSTEM:
             SYSerr(SYS_F_GETADDRINFO, get_last_socket_error());
-            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
+            BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB);
             break;
 # endif
         case 0:
             ret = 1;             /* Success */
             break;
         default:
-            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB);
+            BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB);
             ERR_add_error_data(1, gai_strerror(gai_ret));
             break;
         }
@@ -732,7 +743,7 @@ int BIO_lookup(const char *host, const char *service,
 #endif
 
         if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) {
-            BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
+            BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE);
             ret = 0;
             goto err;
         }
@@ -824,7 +835,7 @@ int BIO_lookup(const char *host, const char *service,
                     goto err;
                 }
             } else {
-                BIOerr(BIO_F_BIO_LOOKUP, BIO_R_MALFORMED_HOST_OR_SERVICE);
+                BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_MALFORMED_HOST_OR_SERVICE);
                 goto err;
             }
         }
@@ -866,7 +877,7 @@ int BIO_lookup(const char *host, const char *service,
              addrinfo_malloc_err:
                 BIO_ADDRINFO_free(*res);
                 *res = NULL;
-                BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE);
+                BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE);
                 ret = 0;
                 goto err;
             }
diff --git a/crypto/bio/bio_err.c b/crypto/bio/bio_err.c
index b8cb1eb..9442d80 100644
--- a/crypto/bio/bio_err.c
+++ b/crypto/bio/bio_err.c
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the OpenSSL license (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -33,8 +33,10 @@ static ERR_STRING_DATA BIO_str_functs[] = {
     {ERR_FUNC(BIO_F_BIO_GET_PORT), "BIO_get_port"},
     {ERR_FUNC(BIO_F_BIO_LISTEN), "BIO_listen"},
     {ERR_FUNC(BIO_F_BIO_LOOKUP), "BIO_lookup"},
+    {ERR_FUNC(BIO_F_BIO_LOOKUP_EX), "BIO_lookup_ex"},
     {ERR_FUNC(BIO_F_BIO_MAKE_PAIR), "bio_make_pair"},
     {ERR_FUNC(BIO_F_BIO_NEW), "BIO_new"},
+    {ERR_FUNC(BIO_F_BIO_NEW_DGRAM_SCTP), "BIO_new_dgram_sctp"},
     {ERR_FUNC(BIO_F_BIO_NEW_FILE), "BIO_new_file"},
     {ERR_FUNC(BIO_F_BIO_NEW_MEM_BUF), "BIO_new_mem_buf"},
     {ERR_FUNC(BIO_F_BIO_NREAD), "BIO_nread"},
diff --git a/crypto/bio/bss_dgram.c b/crypto/bio/bss_dgram.c
index d43e8dc..7ef4281 100644
--- a/crypto/bio/bss_dgram.c
+++ b/crypto/bio/bss_dgram.c
@@ -135,7 +135,6 @@ typedef struct bio_dgram_sctp_data_st {
     int ccs_sent;
     int save_shutdown;
     int peer_auth_tested;
-    bio_dgram_sctp_save_message saved_message;
 } bio_dgram_sctp_data;
 # endif
 
@@ -842,6 +841,8 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag)
                    sizeof(struct sctp_authchunk));
     if (ret < 0) {
         BIO_vfree(bio);
+        BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB);
+        ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel");
         return (NULL);
     }
     auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE;
@@ -850,13 +851,16 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag)
                    sizeof(struct sctp_authchunk));
     if (ret < 0) {
         BIO_vfree(bio);
+        BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB);
+        ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel");
         return (NULL);
     }
 
     /*
      * Test if activation was successful. When using accept(), SCTP-AUTH has
      * to be activated for the listening socket already, otherwise the
-     * connected socket won't use it.
+     * connected socket won't use it. Similarly with connect(): the socket
+     * prior to connection must be activated for SCTP-AUTH
      */
     sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t));
     authchunks = OPENSSL_zalloc(sockopt_len);
@@ -883,8 +887,14 @@ BIO *BIO_new_dgram_sctp(int fd, int close_flag)
 
     OPENSSL_free(authchunks);
 
-    OPENSSL_assert(auth_data);
-    OPENSSL_assert(auth_forward);
+    if (!auth_data || !auth_forward) {
+        BIO_vfree(bio);
+        BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB);
+        ERR_add_error_data(1,
+                           "Ensure SCTP AUTH chunks are enabled on the "
+                           "underlying socket");
+        return NULL;
+    }
 
 #  ifdef SCTP_AUTHENTICATION_EVENT
 #   ifdef SCTP_EVENT
@@ -967,10 +977,8 @@ static int dgram_sctp_free(BIO *a)
         return 0;
 
     data = (bio_dgram_sctp_data *) a->ptr;
-    if (data != NULL) {
-        OPENSSL_free(data->saved_message.data);
+    if (data != NULL)
         OPENSSL_free(data);
-    }
 
     return (1);
 }
@@ -1072,22 +1080,6 @@ static int dgram_sctp_read(BIO *b, char *out, int outl)
                     struct sctp_event_subscribe event;
                     socklen_t eventsize;
 #  endif
-                    /*
-                     * If a message has been delayed until the socket is dry,
-                     * it can be sent now.
-                     */
-                    if (data->saved_message.length > 0) {
-                        i = dgram_sctp_write(data->saved_message.bio,
-                                         data->saved_message.data,
-                                         data->saved_message.length);
-                        if (i < 0) {
-                            ret = i;
-                            break;
-                        }
-                        OPENSSL_free(data->saved_message.data);
-                        data->saved_message.data = NULL;
-                        data->saved_message.length = 0;
-                    }
 
                     /* disable sender dry event */
 #  ifdef SCTP_EVENT
@@ -1270,27 +1262,15 @@ static int dgram_sctp_write(BIO *b, const char *in, int inl)
         sinfo = &handshake_sinfo;
     }
 
-    /*
-     * If we have to send a shutdown alert message and the socket is not dry
-     * yet, we have to save it and send it as soon as the socket gets dry.
-     */
+    /* We can only send a shutdown alert if the socket is dry */
     if (data->save_shutdown) {
         ret = BIO_dgram_sctp_wait_for_dry(b);
-        if (ret < 0) {
+        if (ret < 0)
             return -1;
-        }
         if (ret == 0) {
-            char *tmp;
-            data->saved_message.bio = b;
-            if ((tmp = OPENSSL_malloc(inl)) == NULL) {
-                BIOerr(BIO_F_DGRAM_SCTP_WRITE, ERR_R_MALLOC_FAILURE);
-                return -1;
-            }
-            OPENSSL_free(data->saved_message.data);
-            data->saved_message.data = tmp;
-            memcpy(data->saved_message.data, in, inl);
-            data->saved_message.length = inl;
-            return inl;
+            BIO_clear_retry_flags(b);
+            BIO_set_retry_write(b);
+            return -1;
         }
     }
 
diff --git a/doc/man3/BIO_ADDRINFO.pod b/doc/man3/BIO_ADDRINFO.pod
index 7811da4..8ca6454 100644
--- a/doc/man3/BIO_ADDRINFO.pod
+++ b/doc/man3/BIO_ADDRINFO.pod
@@ -6,6 +6,7 @@ BIO_lookup_type,
 BIO_ADDRINFO, BIO_ADDRINFO_next, BIO_ADDRINFO_free,
 BIO_ADDRINFO_family, BIO_ADDRINFO_socktype, BIO_ADDRINFO_protocol,
 BIO_ADDRINFO_address,
+BIO_lookup_ex,
 BIO_lookup
 - BIO_ADDRINFO type and routines
 
@@ -19,6 +20,9 @@ BIO_lookup
  enum BIO_lookup_type {
      BIO_LOOKUP_CLIENT, BIO_LOOKUP_SERVER
  };
+
+ int BIO_lookup_ex(const char *host, const char *service, int lookup_type,
+                   int family, int socktype, int protocol, BIO_ADDRINFO **res);
  int BIO_lookup(const char *node, const char *service,
                 enum BIO_lookup_type lookup_type,
                 int family, int socktype, BIO_ADDRINFO **res);
@@ -38,18 +42,24 @@ types provided on your platform.
 B<BIO_ADDRINFO> normally forms a chain of several that can be
 picked at one by one.
 
-BIO_lookup() looks up a specified B<host> and B<service>, and
+BIO_lookup_ex() looks up a specified B<host> and B<service>, and
 uses B<lookup_type> to determine what the default address should
-be if B<host> is B<NULL>.  B<family>, B<socktype> are used to
-determine what protocol family and protocol should be used for
+be if B<host> is B<NULL>. B<family>, B<socktype> and B<protocol> are used to
+determine what protocol family, socket type and protocol should be used for
 the lookup.  B<family> can be any of AF_INET, AF_INET6, AF_UNIX and
-AF_UNSPEC, and B<socktype> can be SOCK_STREAM or SOCK_DGRAM.
-B<res> points at a pointer to hold the start of a B<BIO_ADDRINFO>
+AF_UNSPEC. B<socktype> can be SOCK_STREAM, SOCK_DGRAM or 0. Specifying 0
+indicates that any type can be used. B<protocol> specifies a protocol such as
+IPPROTO_TCP, IPPROTO_UDP or IPPORTO_SCTP. If set to 0 than any protocol can be
+used. B<res> points at a pointer to hold the start of a B<BIO_ADDRINFO>
 chain.
-For the family B<AF_UNIX>, BIO_lookup() will ignore the B<service>
+
+For the family B<AF_UNIX>, BIO_lookup_ex() will ignore the B<service>
 parameter and expects the B<node> parameter to hold the path to the
 socket file.
 
+BIO_lookup() does the same as BIO_lookup_ex() but does not provide the ability
+to select based on the protocol (any protocol may be returned).
+
 BIO_ADDRINFO_family() returns the family of the given
 B<BIO_ADDRINFO>.  The result will be one of the constants
 AF_INET, AF_INET6 and AF_UNIX.
@@ -73,15 +83,28 @@ with the given one.
 
 =head1 RETURN VALUES
 
-BIO_lookup() returns 1 on success and 0 when an error occurred, and
-will leave an error indication on the OpenSSL error stack in that case.
+BIO_lookup_ex() and BIO_lookup() return 1 on success and 0 when an error
+occurred, and will leave an error indication on the OpenSSL error stack in that
+case.
 
 All other functions described here return 0 or B<NULL> when the
 information they should return isn't available.
 
+=head1 NOTES
+
+The BIO_lookup_ex() implementation uses the platform provided getaddrinfo()
+function. On Linux it is known that specifying 0 for the protocol will not
+return any SCTP based addresses when calling getaddrinfo(). Therefore if an SCTP
+address is required then the B<protocol> parameter to BIO_lookup_ex() should be
+explicitly set to IPPROTO_SCTP. The same may be true on other platforms.
+
+=head1 HISTORY
+
+The BIO_lookup_ex() function was added in OpenSSL 1.1.1.
+
 =head1 COPYRIGHT
 
-Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
+Copyright 2016-2017 The OpenSSL Project Authors. All Rights Reserved.
 
 Licensed under the OpenSSL license (the "License").  You may not use
 this file except in compliance with the License.  You can obtain a copy
diff --git a/include/openssl/bio.h b/include/openssl/bio.h
index 6585ec0..b1276a5 100644
--- a/include/openssl/bio.h
+++ b/include/openssl/bio.h
@@ -667,6 +667,9 @@ enum BIO_lookup_type {
 int BIO_lookup(const char *host, const char *service,
                enum BIO_lookup_type lookup_type,
                int family, int socktype, BIO_ADDRINFO **res);
+int BIO_lookup_ex(const char *host, const char *service,
+                  int lookup_type, int family, int socktype, int protocol,
+                  BIO_ADDRINFO **res);
 int BIO_sock_error(int sock);
 int BIO_socket_ioctl(int fd, long type, void *arg);
 int BIO_socket_nbio(int fd, int mode);
@@ -805,8 +808,10 @@ int ERR_load_BIO_strings(void);
 # define BIO_F_BIO_GET_PORT                               107
 # define BIO_F_BIO_LISTEN                                 139
 # define BIO_F_BIO_LOOKUP                                 135
+# define BIO_F_BIO_LOOKUP_EX                              143
 # define BIO_F_BIO_MAKE_PAIR                              121
 # define BIO_F_BIO_NEW                                    108
+# define BIO_F_BIO_NEW_DGRAM_SCTP                         145
 # define BIO_F_BIO_NEW_FILE                               109
 # define BIO_F_BIO_NEW_MEM_BUF                            126
 # define BIO_F_BIO_NREAD                                  123
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 6e3b9c5..c14859f 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2607,6 +2607,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_ENCRYPTED_LENGTH_TOO_LONG                  150
 # define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST              151
 # define SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN             204
+# define SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE                  194
 # define SSL_R_EXCESSIVE_MESSAGE_SIZE                     152
 # define SSL_R_EXTRA_DATA_IN_MESSAGE                      153
 # define SSL_R_EXT_LENGTH_MISMATCH                        163
diff --git a/ssl/d1_msg.c b/ssl/d1_msg.c
index a8253b9..aaee3ca 100644
--- a/ssl/d1_msg.c
+++ b/ssl/d1_msg.c
@@ -15,18 +15,7 @@ int dtls1_write_app_data_bytes(SSL *s, int type, const void *buf_, size_t len,
 {
     int i;
 
-#ifndef OPENSSL_NO_SCTP
-    /*
-     * Check if we have to continue an interrupted handshake for reading
-     * belated app data with SCTP.
-     */
-    if ((SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) ||
-        (BIO_dgram_is_sctp(SSL_get_wbio(s)) &&
-         ossl_statem_in_sctp_read_sock(s)))
-#else
-    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s))
-#endif
-    {
+    if (SSL_in_init(s) && !ossl_statem_get_in_handshake(s)) {
         i = s->handshake_func(s);
         if (i < 0)
             return (i);
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index cd6343a..243eff7 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -367,18 +367,7 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * type == SSL3_RT_HANDSHAKE.
      */
 
-#ifndef OPENSSL_NO_SCTP
-    /*
-     * Continue handshake if it had to be interrupted to read app data with
-     * SCTP.
-     */
-    if ((!ossl_statem_get_in_handshake(s) && SSL_in_init(s)) ||
-        (BIO_dgram_is_sctp(SSL_get_rbio(s))
-         && ossl_statem_in_sctp_read_sock(s)
-         && s->s3->in_read_app_data != 2))
-#else
     if (!ossl_statem_get_in_handshake(s) && SSL_in_init(s))
-#endif
     {
         /* type == SSL3_RT_APPLICATION_DATA */
         i = s->handshake_func(s);
@@ -521,18 +510,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
         }
 #ifndef OPENSSL_NO_SCTP
         /*
-         * We were about to renegotiate but had to read belated application
-         * data first, so retry.
-         */
-        if (BIO_dgram_is_sctp(SSL_get_rbio(s)) &&
-            SSL3_RECORD_get_type(rr) == SSL3_RT_APPLICATION_DATA &&
-            ossl_statem_in_sctp_read_sock(s)) {
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-        }
-
-        /*
          * We might had to delay a close_notify alert because of reordered
          * app data. If there was an alert and there is no message to read
          * anymore, finally set shutdown.
@@ -905,6 +882,11 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf,
     if (len == 0 && !create_empty_fragment)
         return 0;
 
+    if (len > s->max_send_fragment) {
+        SSLerr(SSL_F_DO_DTLS1_WRITE, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE);
+        return 0;
+    }
+
     sess = s->session;
 
     if ((sess == NULL) ||
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index c7e407f..296ce0d 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -590,6 +590,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
      "error in received cipher list"},
     {ERR_REASON(SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN),
      "error setting tlsa base domain"},
+    {ERR_REASON(SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE),
+     "exceeds max fragment size"},
     {ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE), "excessive message size"},
     {ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE), "extra data in message"},
     {ERR_REASON(SSL_R_EXT_LENGTH_MISMATCH), "ext length mismatch"},
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index e63d0ad..52beac7 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -885,26 +885,3 @@ int ossl_statem_app_data_allowed(SSL *s)
 
     return 0;
 }
-
-#ifndef OPENSSL_NO_SCTP
-/*
- * Set flag used by SCTP to determine whether we are in the read sock state
- */
-void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock)
-{
-    s->statem.in_sctp_read_sock = read_sock;
-}
-
-/*
- * Called by the record layer to determine whether we are in the read sock
- * state or not.
- *
- * Return values are:
- *   1: Yes (we are in the read sock state)
- *   0: No (we are not in the read sock state)
- */
-int ossl_statem_in_sctp_read_sock(SSL *s)
-{
-    return s->statem.in_sctp_read_sock;
-}
-#endif
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
index 7012115..98c8291 100644
--- a/ssl/statem/statem.h
+++ b/ssl/statem/statem.h
@@ -100,9 +100,6 @@ struct ossl_statem_st {
     /* Should we skip the CertificateVerify message? */
     unsigned int no_cert_verify;
     int use_timer;
-#ifndef OPENSSL_NO_SCTP
-    int in_sctp_read_sock;
-#endif
 };
 typedef struct ossl_statem_st OSSL_STATEM;
 
@@ -126,7 +123,3 @@ __owur int ossl_statem_skip_early_data(SSL *s);
 void ossl_statem_check_finish_init(SSL *s, int send);
 void ossl_statem_set_hello_verify_done(SSL *s);
 __owur int ossl_statem_app_data_allowed(SSL *s);
-#ifndef OPENSSL_NO_SCTP
-void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock);
-__owur int ossl_statem_in_sctp_read_sock(SSL *s);
-#endif
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 0452729..7bcd3ac 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1022,21 +1022,6 @@ WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst)
 
     case TLS_ST_CR_CERT_REQ:
         return tls_prepare_client_certificate(s, wst);
-
-#ifndef OPENSSL_NO_SCTP
-    case TLS_ST_CR_SRVR_DONE:
-        /* We only get here if we are using SCTP and we are renegotiating */
-        if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-            s->s3->in_read_app_data = 2;
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-            ossl_statem_set_sctp_read_sock(s, 1);
-            return WORK_MORE_A;
-        }
-        ossl_statem_set_sctp_read_sock(s, 0);
-        return WORK_FINISHED_STOP;
-#endif
     }
 }
 
@@ -2691,14 +2676,7 @@ MSG_PROCESS_RETURN tls_process_server_done(SSL *s, PACKET *pkt)
     if (!tls_process_initial_server_flight(s, &al))
         goto err;
 
-#ifndef OPENSSL_NO_SCTP
-    /* Only applies to renegotiation */
-    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))
-        && s->renegotiate != 0)
-        return MSG_PROCESS_CONTINUE_PROCESSING;
-    else
-#endif
-        return MSG_PROCESS_FINISHED_READING;
+    return MSG_PROCESS_FINISHED_READING;
 
  err:
     ssl3_send_alert(s, SSL3_AL_FATAL, al);
diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c
index 34964db..b2ba357 100644
--- a/ssl/statem/statem_dtls.c
+++ b/ssl/statem/statem_dtls.c
@@ -214,6 +214,9 @@ int dtls1_do_write(SSL *s, int type)
         else
             len = s->init_num;
 
+        if (len > s->max_send_fragment)
+            len = s->max_send_fragment;
+
         /*
          * XDTLS: this function is too long.  split out the CCS part
          */
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index d5e87f7..0180445 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -418,10 +418,7 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    if (SSL_IS_TLS13(s))
-        ret = MSG_PROCESS_CONTINUE_READING;
-    else
-        ret = MSG_PROCESS_CONTINUE_PROCESSING;
+    ret = MSG_PROCESS_CONTINUE_READING;
     if (0) {
  f_err:
         ssl3_send_alert(s, SSL3_AL_FATAL, al);
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index d931c7f..919469f 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1106,24 +1106,6 @@ WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst)
 
     case TLS_ST_SR_KEY_EXCH:
         return tls_post_process_client_key_exchange(s, wst);
-
-    case TLS_ST_SR_CERT_VRFY:
-#ifndef OPENSSL_NO_SCTP
-        if (                    /* Is this SCTP? */
-               BIO_dgram_is_sctp(SSL_get_wbio(s))
-               /* Are we renegotiating? */
-               && s->renegotiate && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-            s->s3->in_read_app_data = 2;
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-            ossl_statem_set_sctp_read_sock(s, 1);
-            return WORK_MORE_A;
-        } else {
-            ossl_statem_set_sctp_read_sock(s, 0);
-        }
-#endif
-        return WORK_FINISHED_CONTINUE;
     }
     return WORK_FINISHED_CONTINUE;
 }
@@ -3144,25 +3126,6 @@ WORK_STATE tls_post_process_client_key_exchange(SSL *s, WORK_STATE wst)
             BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
                      sizeof(sctpauthkey), sctpauthkey);
         }
-        wst = WORK_MORE_B;
-    }
-
-    if ((wst == WORK_MORE_B)
-        /* Is this SCTP? */
-        && BIO_dgram_is_sctp(SSL_get_wbio(s))
-        /* Are we renegotiating? */
-        && s->renegotiate
-        /* Are we going to skip the CertificateVerify? */
-        && (s->session->peer == NULL || s->statem.no_cert_verify)
-        && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-        s->s3->in_read_app_data = 2;
-        s->rwstate = SSL_READING;
-        BIO_clear_retry_flags(SSL_get_rbio(s));
-        BIO_set_retry_read(SSL_get_rbio(s));
-        ossl_statem_set_sctp_read_sock(s, 1);
-        return WORK_MORE_B;
-    } else {
-        ossl_statem_set_sctp_read_sock(s, 0);
     }
 #endif
 
diff --git a/test/handshake_helper.c b/test/handshake_helper.c
index 94fa5c5..8ad35ce 100644
--- a/test/handshake_helper.c
+++ b/test/handshake_helper.c
@@ -16,6 +16,11 @@
 #include <openssl/srp.h>
 #endif
 
+#ifndef OPENSSL_NO_SOCK
+# define USE_SOCKETS
+# include "e_os.h"
+#endif
+
 #include "handshake_helper.h"
 #include "testutil.h"
 
@@ -631,7 +636,8 @@ static void configure_handshake_ssl(SSL *server, SSL *client,
 typedef enum {
     PEER_SUCCESS,
     PEER_RETRY,
-    PEER_ERROR
+    PEER_ERROR,
+    PEER_WAITING
 } peer_status_t;
 
 /* An SSL object and associated read-write buffers. */
@@ -898,8 +904,8 @@ static void do_shutdown_step(PEER *peer)
         peer->status = PEER_SUCCESS;
     } else if (ret < 0) { /* On 0, we retry. */
         int error = SSL_get_error(peer->ssl, ret);
-        /* Memory bios should never block with SSL_ERROR_WANT_WRITE. */
-        if (error != SSL_ERROR_WANT_READ)
+
+        if (error != SSL_ERROR_WANT_READ && error != SSL_ERROR_WANT_WRITE)
             peer->status = PEER_ERROR;
     }
 }
@@ -1000,11 +1006,16 @@ static handshake_status_t handshake_status(peer_status_t last_status,
                                            int client_spoke_last)
 {
     switch (last_status) {
+    case PEER_WAITING:
+        /* Shouldn't ever happen */
+        return INTERNAL_ERROR;
+
     case PEER_SUCCESS:
         switch (previous_status) {
         case PEER_SUCCESS:
             /* Both succeeded. */
             return HANDSHAKE_SUCCESS;
+        case PEER_WAITING:
         case PEER_RETRY:
             /* Let the first peer finish. */
             return HANDSHAKE_RETRY;
@@ -1017,18 +1028,13 @@ static handshake_status_t handshake_status(peer_status_t last_status,
         }
 
     case PEER_RETRY:
-        if (previous_status == PEER_RETRY) {
-            /* Neither peer is done. */
-            return HANDSHAKE_RETRY;
-        } else {
-            /*
-             * Deadlock: second peer is waiting for more input while first
-             * peer thinks they're done (no more input is coming).
-             */
-            return INTERNAL_ERROR;
-        }
+        return HANDSHAKE_RETRY;
+
     case PEER_ERROR:
         switch (previous_status) {
+        case PEER_WAITING:
+            /* The client failed immediately before sending the ClientHello */
+            return client_spoke_last ? CLIENT_ERROR : INTERNAL_ERROR;
         case PEER_SUCCESS:
             /*
              * First peer succeeded but second peer errored.
@@ -1091,6 +1097,107 @@ static int peer_pkey_type(SSL *s)
     return NID_undef;
 }
 
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+static int set_sock_as_sctp(int sock)
+{
+    /*
+     * For SCTP we have to set various options on the socket prior to
+     * connecting. 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(sock, BIO_NOCLOSE);
+
+    if (tmpbio == NULL)
+        return 0;
+    BIO_free(tmpbio);
+
+    return 1;
+}
+
+static int create_sctp_socks(int *ssock, int *csock)
+{
+    BIO_ADDRINFO *res = NULL;
+    const BIO_ADDRINFO *ai = NULL;
+    int lsock = INVALID_SOCKET, asock = INVALID_SOCKET;
+    int consock = INVALID_SOCKET;
+    int ret = 0;
+    int family = 0;
+
+    if (!BIO_sock_init())
+        return 0;
+
+    /*
+     * Port is 4463. It could be anything. It will fail if it's already being
+     * used for some other SCTP service. It seems unlikely though so we don't
+     * worry about it here.
+     */
+    if (!BIO_lookup_ex(NULL, "4463", BIO_LOOKUP_SERVER, family, SOCK_STREAM,
+                       IPPROTO_SCTP, &res))
+        return 0;
+
+    for (ai = res; ai != NULL; ai = BIO_ADDRINFO_next(ai)) {
+        family = BIO_ADDRINFO_family(ai);
+        lsock = BIO_socket(family, SOCK_STREAM, IPPROTO_SCTP, 0);
+        if (lsock == INVALID_SOCKET) {
+            /* Maybe the kernel doesn't support the socket family, even if
+             * BIO_lookup() added it in the returned result...
+             */
+            continue;
+        }
+
+        if (!set_sock_as_sctp(lsock)
+                || !BIO_listen(lsock, BIO_ADDRINFO_address(ai),
+                               BIO_SOCK_REUSEADDR)) {
+            BIO_closesocket(lsock);
+            lsock = INVALID_SOCKET;
+            continue;
+        }
+
+        /* Success, don't try any more addresses */
+        break;
+    }
+
+    if (lsock == INVALID_SOCKET)
+        goto err;
+
+    BIO_ADDRINFO_free(res);
+    res = NULL;
+
+    if (!BIO_lookup_ex(NULL, "4463", BIO_LOOKUP_CLIENT, family, SOCK_STREAM,
+                        IPPROTO_SCTP, &res))
+        goto err;
+
+    consock = BIO_socket(family, SOCK_STREAM, IPPROTO_SCTP, 0);
+    if (consock == INVALID_SOCKET)
+        goto err;
+
+    if (!set_sock_as_sctp(consock)
+            || !BIO_connect(consock, BIO_ADDRINFO_address(res), 0)
+            || !BIO_socket_nbio(consock, 1))
+        goto err;
+
+    asock = BIO_accept_ex(lsock, NULL, BIO_SOCK_NONBLOCK);
+    if (asock == INVALID_SOCKET)
+        goto err;
+
+    *csock = consock;
+    *ssock = asock;
+    consock = asock = INVALID_SOCKET;
+    ret = 1;
+
+ err:
+    BIO_ADDRINFO_free(res);
+    if (consock != INVALID_SOCKET)
+        BIO_closesocket(consock);
+    if (lsock != INVALID_SOCKET)
+        BIO_closesocket(lsock);
+    if (asock != INVALID_SOCKET)
+        BIO_closesocket(asock);
+    return ret;
+}
+#endif
+
 /*
  * Note that |extra| points to the correct client/server configuration
  * within |test_ctx|. When configuring the handshake, general mode settings
@@ -1110,7 +1217,7 @@ static HANDSHAKE_RESULT *do_handshake_internal(
     SSL_SESSION *session_in, SSL_SESSION **session_out)
 {
     PEER server, client;
-    BIO *client_to_server, *server_to_client;
+    BIO *client_to_server = NULL, *server_to_client = NULL;
     HANDSHAKE_EX_DATA server_ex_data, client_ex_data;
     CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data;
     HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new();
@@ -1125,6 +1232,7 @@ static HANDSHAKE_RESULT *do_handshake_internal(
     unsigned int proto_len = 0;
     EVP_PKEY *tmp_key;
     const STACK_OF(X509_NAME) *names;
+    time_t start;
 
     memset(&server_ctx_data, 0, sizeof(server_ctx_data));
     memset(&server2_ctx_data, 0, sizeof(server2_ctx_data));
@@ -1154,8 +1262,19 @@ static HANDSHAKE_RESULT *do_handshake_internal(
 
     ret->result = SSL_TEST_INTERNAL_ERROR;
 
-    client_to_server = BIO_new(BIO_s_mem());
-    server_to_client = BIO_new(BIO_s_mem());
+    if (test_ctx->use_sctp) {
+#if !defined(OPENSSL_NO_SCTP) && !defined(OPENSSL_NO_SOCK)
+        int csock, ssock;
+
+        if (create_sctp_socks(&ssock, &csock)) {
+            client_to_server = BIO_new_dgram_sctp(csock, BIO_CLOSE);
+            server_to_client = BIO_new_dgram_sctp(ssock, BIO_CLOSE);
+        }
+#endif
+    } else {
+        client_to_server = BIO_new(BIO_s_mem());
+        server_to_client = BIO_new(BIO_s_mem());
+    }
 
     TEST_check(client_to_server != NULL);
     TEST_check(server_to_client != NULL);
@@ -1168,10 +1287,15 @@ static HANDSHAKE_RESULT *do_handshake_internal(
     SSL_set_accept_state(server.ssl);
 
     /* The bios are now owned by the SSL object. */
-    SSL_set_bio(client.ssl, server_to_client, client_to_server);
-    TEST_check(BIO_up_ref(server_to_client) > 0);
-    TEST_check(BIO_up_ref(client_to_server) > 0);
-    SSL_set_bio(server.ssl, client_to_server, server_to_client);
+    if (test_ctx->use_sctp) {
+        SSL_set_bio(client.ssl, client_to_server, client_to_server);
+        SSL_set_bio(server.ssl, server_to_client, server_to_client);
+    } else {
+        SSL_set_bio(client.ssl, server_to_client, client_to_server);
+        TEST_check(BIO_up_ref(server_to_client) > 0);
+        TEST_check(BIO_up_ref(client_to_server) > 0);
+        SSL_set_bio(server.ssl, client_to_server, server_to_client);
+    }
 
     ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL);
     TEST_check(ex_data_idx >= 0);
@@ -1182,7 +1306,10 @@ static HANDSHAKE_RESULT *do_handshake_internal(
     SSL_set_info_callback(server.ssl, &info_cb);
     SSL_set_info_callback(client.ssl, &info_cb);
 
-    client.status = server.status = PEER_RETRY;
+    client.status = PEER_RETRY;
+    server.status = PEER_WAITING;
+
+    start = time(NULL);
 
     /*
      * Half-duplex handshake loop.
@@ -1197,6 +1324,8 @@ static HANDSHAKE_RESULT *do_handshake_internal(
             do_connect_step(test_ctx, &client, phase);
             status = handshake_status(client.status, server.status,
                                       1 /* client went last */);
+            if (server.status == PEER_WAITING)
+                server.status = PEER_RETRY;
         } else {
             do_connect_step(test_ctx, &server, phase);
             status = handshake_status(server.status, client.status,
@@ -1231,18 +1360,36 @@ static HANDSHAKE_RESULT *do_handshake_internal(
             ret->result = SSL_TEST_INTERNAL_ERROR;
             goto err;
         case HANDSHAKE_RETRY:
-            if (client_turn_count++ >= 2000) {
+            if (test_ctx->use_sctp) {
+                if (time(NULL) - start > 3) {
+                    /*
+                     * We've waited for too long. Give up.
+                     */
+                    ret->result = SSL_TEST_INTERNAL_ERROR;
+                    goto err;
+                }
                 /*
-                 * At this point, there's been so many PEER_RETRY in a row
-                 * that it's likely both sides are stuck waiting for a read.
-                 * It's time to give up.
+                 * With "real" sockets we only swap to processing the peer
+                 * if they are expecting to retry. Otherwise we just retry the
+                 * same endpoint again.
                  */
-                ret->result = SSL_TEST_INTERNAL_ERROR;
-                goto err;
-            }
+                if ((client_turn && server.status == PEER_RETRY)
+                        || (!client_turn && client.status == PEER_RETRY))
+                    client_turn ^= 1;
+            } else {
+                if (client_turn_count++ >= 2000) {
+                    /*
+                     * At this point, there's been so many PEER_RETRY in a row
+                     * that it's likely both sides are stuck waiting for a read.
+                     * It's time to give up.
+                     */
+                    ret->result = SSL_TEST_INTERNAL_ERROR;
+                    goto err;
+                }
 
-            /* Continue. */
-            client_turn ^= 1;
+                /* Continue. */
+                client_turn ^= 1;
+            }
             break;
         }
     }
diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t
index 5005794..fbcb46a 100644
--- a/test/recipes/80-test_ssl_new.t
+++ b/test/recipes/80-test_ssl_new.t
@@ -55,13 +55,15 @@ my $no_ocsp = disabled("ocsp");
 # expectations dynamically based on the OpenSSL compile-time config.
 my %conf_dependent_tests = (
   "02-protocol-version.conf" => !$is_default_tls,
-  "04-client_auth.conf" => !$is_default_tls || !$is_default_dtls,
+  "04-client_auth.conf" => !$is_default_tls || !$is_default_dtls
+                           || !disabled("sctp"),
   "05-sni.conf" => disabled("tls1_1"),
-  "07-dtls-protocol-version.conf" => !$is_default_dtls,
+  "07-dtls-protocol-version.conf" => !$is_default_dtls || !disabled("sctp"),
   "10-resumption.conf" => !$is_default_tls,
-  "11-dtls_resumption.conf" => !$is_default_dtls,
+  "11-dtls_resumption.conf" => !$is_default_dtls || !disabled("sctp"),
+  "16-dtls-certstatus.conf" => !$is_default_dtls || !disabled("sctp"),
   "17-renegotiate.conf" => disabled("tls1_2"),
-  "18-dtls-renegotiate.conf" => disabled("dtls1_2"),
+  "18-dtls-renegotiate.conf" => disabled("dtls1_2") || !disabled("sctp"),
   "19-mac-then-encrypt.conf" => !$is_default_tls,
   "20-cert-select.conf" => !$is_default_tls || $no_dh || $no_dsa,
   "22-compression.conf" => !$is_default_tls,
diff --git a/test/ssl-tests/02-protocol-version.conf b/test/ssl-tests/02-protocol-version.conf
index d5e0779..f18d6a3 100644
--- a/test/ssl-tests/02-protocol-version.conf
+++ b/test/ssl-tests/02-protocol-version.conf
@@ -700,7 +700,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-0]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -725,7 +725,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-1]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -750,7 +750,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-2]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -775,7 +775,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-3]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -800,7 +800,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-4]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -824,7 +824,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-5]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -850,7 +850,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-6]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -876,7 +876,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-7]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -902,7 +902,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-8]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -928,7 +928,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-9]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -954,7 +954,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-10]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -979,7 +979,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-11]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1005,7 +1005,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-12]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1031,7 +1031,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-13]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1057,7 +1057,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-14]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1083,7 +1083,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-15]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1108,7 +1108,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-16]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1134,7 +1134,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-17]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1160,7 +1160,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-18]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1186,7 +1186,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-19]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1211,7 +1211,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-20]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1237,7 +1237,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-21]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1263,7 +1263,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-22]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1288,7 +1288,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-23]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1314,7 +1314,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-24]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -1339,7 +1339,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-25]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4759,7 +4759,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-156]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4785,7 +4785,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-157]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4811,7 +4811,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-158]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4837,7 +4837,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-159]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4863,7 +4863,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-160]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4888,7 +4888,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-161]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4915,7 +4915,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-162]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4942,7 +4942,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-163]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4969,7 +4969,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-164]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -4996,7 +4996,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-165]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5023,7 +5023,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-166]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5049,7 +5049,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-167]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5076,7 +5076,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-168]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5103,7 +5103,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-169]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5130,7 +5130,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-170]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5157,7 +5157,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-171]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5183,7 +5183,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-172]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5210,7 +5210,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-173]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5237,7 +5237,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-174]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5264,7 +5264,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-175]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5290,7 +5290,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-176]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5317,7 +5317,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-177]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5344,7 +5344,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-178]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5370,7 +5370,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-179]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5397,7 +5397,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-180]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -5423,7 +5423,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-181]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17393,7 +17393,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-624]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17419,7 +17419,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-625]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17445,7 +17445,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-626]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17471,7 +17471,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-627]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17497,7 +17497,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-628]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17522,7 +17522,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-629]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17549,7 +17549,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-630]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17576,7 +17576,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-631]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17603,7 +17603,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-632]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17630,7 +17630,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-633]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17657,7 +17657,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-634]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17683,7 +17683,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-635]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17710,7 +17710,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-636]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17737,7 +17737,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-637]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17764,7 +17764,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-638]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17791,7 +17791,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-639]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17817,7 +17817,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-640]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17844,7 +17844,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-641]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17871,7 +17871,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-642]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17898,7 +17898,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-643]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17924,7 +17924,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-644]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17951,7 +17951,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-645]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -17978,7 +17978,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-646]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18004,7 +18004,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-647]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18031,7 +18031,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-648]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18057,7 +18057,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-649]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18082,7 +18082,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-650]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18107,7 +18107,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-651]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18132,7 +18132,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-652]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18157,7 +18157,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-653]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18182,7 +18182,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-654]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18206,7 +18206,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-655]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18232,7 +18232,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-656]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18258,7 +18258,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-657]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18284,7 +18284,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-658]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18310,7 +18310,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-659]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18336,7 +18336,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-660]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18361,7 +18361,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-661]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18387,7 +18387,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-662]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18413,7 +18413,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-663]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18439,7 +18439,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-664]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18465,7 +18465,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-665]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18490,7 +18490,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-666]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18516,7 +18516,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-667]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18542,7 +18542,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-668]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18568,7 +18568,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-669]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18593,7 +18593,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-670]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18619,7 +18619,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-671]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18645,7 +18645,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-672]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18670,7 +18670,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-673]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18696,7 +18696,7 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-674]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
 # ===========================================================
@@ -18721,6 +18721,6 @@ VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem
 VerifyMode = Peer
 
 [test-675]
-ExpectedResult = InternalError
+ExpectedResult = ClientFail
 
 
diff --git a/test/ssl-tests/04-client_auth.conf.in b/test/ssl-tests/04-client_auth.conf.in
index 3da76a3..a780e00 100644
--- a/test/ssl-tests/04-client_auth.conf.in
+++ b/test/ssl-tests/04-client_auth.conf.in
@@ -8,7 +8,7 @@ use strict;
 use warnings;
 
 use OpenSSL::Test;
-use OpenSSL::Test::Utils qw(anydisabled);
+use OpenSSL::Test::Utils qw(anydisabled disabled);
 setup("no_test_here");
 
 # We test version-flexible negotiation (undef) and each protocol version.
@@ -25,6 +25,7 @@ sub generate_tests() {
         my $protocol_name = $protocol || "flex";
         my $caalert;
         my $method;
+        my $sctpenabled = 0;
         if (!$is_disabled[$_]) {
             if ($protocol_name eq "SSLv3") {
                 $caalert = "BadCertificate";
@@ -33,6 +34,7 @@ sub generate_tests() {
             }
             if ($protocol_name =~ m/^DTLS/) {
                 $method = "DTLS";
+                $sctpenabled = 1 if !disabled("sctp");
             }
             my $clihash;
             my $clisigtype;
@@ -43,134 +45,148 @@ sub generate_tests() {
                 $clisigtype = "RSA";
                 $clisigalgs = "SHA256+RSA";
             }
-            # Sanity-check simple handshake.
-            push @tests, {
-                name => "server-auth-${protocol_name}",
-                server => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol
-                },
-                client => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol
-                },
-                test   => {
-                    "ExpectedResult" => "Success",
-                    "Method" => $method,
-                },
-            };
+            for (my $sctp = 0; $sctp <= $sctpenabled; $sctp++) {
+                # Sanity-check simple handshake.
+                push @tests, {
+                    name => "server-auth-${protocol_name}"
+                            .($sctp ? "-sctp" : ""),
+                    server => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol
+                    },
+                    client => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol
+                    },
+                    test   => {
+                        "ExpectedResult" => "Success",
+                        "Method" => $method,
+                    },
+                };
+                $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
 
-            # Handshake with client cert requested but not required or received.
-            push @tests, {
-                name => "client-auth-${protocol_name}-request",
-                server => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "VerifyMode" => "Request"
-                },
-                client => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol
-                },
-                test   => {
-                    "ExpectedResult" => "Success",
-                    "Method" => $method,
-                },
-            };
+                # Handshake with client cert requested but not required or received.
+                push @tests, {
+                    name => "client-auth-${protocol_name}-request"
+                            .($sctp ? "-sctp" : ""),
+                    server => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "VerifyMode" => "Request"
+                    },
+                    client => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol
+                    },
+                    test   => {
+                        "ExpectedResult" => "Success",
+                        "Method" => $method,
+                    },
+                };
+                $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
 
-            # Handshake with client cert required but not present.
-            push @tests, {
-                name => "client-auth-${protocol_name}-require-fail",
-                server => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "VerifyCAFile" => test_pem("root-cert.pem"),
-                    "VerifyMode" => "Require",
-                },
-                client => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol
-                },
-                test   => {
-                    "ExpectedResult" => "ServerFail",
-                    "ExpectedServerAlert" => "HandshakeFailure",
-                    "Method" => $method,
-                },
-            };
+                # Handshake with client cert required but not present.
+                push @tests, {
+                    name => "client-auth-${protocol_name}-require-fail"
+                            .($sctp ? "-sctp" : ""),
+                    server => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "VerifyCAFile" => test_pem("root-cert.pem"),
+                        "VerifyMode" => "Require",
+                    },
+                    client => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol
+                    },
+                    test   => {
+                        "ExpectedResult" => "ServerFail",
+                        "ExpectedServerAlert" => "HandshakeFailure",
+                        "Method" => $method,
+                    },
+                };
+                $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
 
-            # Successful handshake with client authentication.
-            push @tests, {
-                name => "client-auth-${protocol_name}-require",
-                server => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "ClientSignatureAlgorithms" => $clisigalgs,
-                    "VerifyCAFile" => test_pem("root-cert.pem"),
-                    "VerifyMode" => "Request",
-                },
-                client => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "Certificate" => test_pem("ee-client-chain.pem"),
-                    "PrivateKey"  => test_pem("ee-key.pem"),
-                },
-                test   => {
-                    "ExpectedResult" => "Success",
-                    "ExpectedClientCertType" => "RSA",
-                    "ExpectedClientSignType" => $clisigtype,
-                    "ExpectedClientSignHash" => $clihash,
-                    "ExpectedClientCANames" => "empty",
-                    "Method" => $method,
-                },
-            };
+                # Successful handshake with client authentication.
+                push @tests, {
+                    name => "client-auth-${protocol_name}-require"
+                             .($sctp ? "-sctp" : ""),
+                    server => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "ClientSignatureAlgorithms" => $clisigalgs,
+                        "VerifyCAFile" => test_pem("root-cert.pem"),
+                        "VerifyMode" => "Request",
+                    },
+                    client => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "Certificate" => test_pem("ee-client-chain.pem"),
+                        "PrivateKey"  => test_pem("ee-key.pem"),
+                    },
+                    test   => {
+                        "ExpectedResult" => "Success",
+                        "ExpectedClientCertType" => "RSA",
+                        "ExpectedClientSignType" => $clisigtype,
+                        "ExpectedClientSignHash" => $clihash,
+                        "ExpectedClientCANames" => "empty",
+                        "Method" => $method,
+                    },
+                };
+                $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
 
-            # Successful handshake with client authentication non-empty names
-            push @tests, {
-                name => "client-auth-${protocol_name}-require-non-empty-names",
-                server => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "ClientSignatureAlgorithms" => $clisigalgs,
-                    "ClientCAFile" => test_pem("root-cert.pem"),
-                    "VerifyCAFile" => test_pem("root-cert.pem"),
-                    "VerifyMode" => "Request",
-                },
-                client => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "Certificate" => test_pem("ee-client-chain.pem"),
-                    "PrivateKey"  => test_pem("ee-key.pem"),
-                },
-                test   => {
-                    "ExpectedResult" => "Success",
-                    "ExpectedClientCertType" => "RSA",
-                    "ExpectedClientSignType" => $clisigtype,
-                    "ExpectedClientSignHash" => $clihash,
-                    "ExpectedClientCANames" => test_pem("root-cert.pem"),
-                    "Method" => $method,
-                },
-            };
+                # Successful handshake with client authentication non-empty names
+                push @tests, {
+                    name => "client-auth-${protocol_name}-require-non-empty-names"
+                            .($sctp ? "-sctp" : ""),
+                    server => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "ClientSignatureAlgorithms" => $clisigalgs,
+                        "ClientCAFile" => test_pem("root-cert.pem"),
+                        "VerifyCAFile" => test_pem("root-cert.pem"),
+                        "VerifyMode" => "Request",
+                    },
+                    client => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "Certificate" => test_pem("ee-client-chain.pem"),
+                        "PrivateKey"  => test_pem("ee-key.pem"),
+                    },
+                    test   => {
+                        "ExpectedResult" => "Success",
+                        "ExpectedClientCertType" => "RSA",
+                        "ExpectedClientSignType" => $clisigtype,
+                        "ExpectedClientSignHash" => $clihash,
+                        "ExpectedClientCANames" => test_pem("root-cert.pem"),
+                        "Method" => $method,
+                    },
+                };
+                $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
 
-            # Handshake with client authentication but without the root certificate.
-            push @tests, {
-                name => "client-auth-${protocol_name}-noroot",
-                server => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "VerifyMode" => "Require",
-                },
-                client => {
-                    "MinProtocol" => $protocol,
-                    "MaxProtocol" => $protocol,
-                    "Certificate" => test_pem("ee-client-chain.pem"),
-                    "PrivateKey"  => test_pem("ee-key.pem"),
-                },
-                test   => {
-                    "ExpectedResult" => "ServerFail",
-                    "ExpectedServerAlert" => $caalert,
-                    "Method" => $method,
-                },
-            };
+                # Handshake with client authentication but without the root certificate.
+                push @tests, {
+                    name => "client-auth-${protocol_name}-noroot"
+                            .($sctp ? "-sctp" : ""),
+                    server => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "VerifyMode" => "Require",
+                    },
+                    client => {
+                        "MinProtocol" => $protocol,
+                        "MaxProtocol" => $protocol,
+                        "Certificate" => test_pem("ee-client-chain.pem"),
+                        "PrivateKey"  => test_pem("ee-key.pem"),
+                    },
+                    test   => {
+                        "ExpectedResult" => "ServerFail",
+                        "ExpectedServerAlert" => $caalert,
+                        "Method" => $method,
+                    },
+                };
+                $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
+            }
         }
     }
 }
diff --git a/test/ssl-tests/16-dtls-certstatus.conf.in b/test/ssl-tests/16-dtls-certstatus.conf.in
index 7280029..2d1766d 100644
--- a/test/ssl-tests/16-dtls-certstatus.conf.in
+++ b/test/ssl-tests/16-dtls-certstatus.conf.in
@@ -13,7 +13,7 @@ use strict;
 use warnings;
 
 package ssltests;
-
+use OpenSSL::Test::Utils;
 
 our @tests = (
     {
@@ -41,5 +41,38 @@ our @tests = (
             "Method" => "DTLS",
             "ExpectedResult" => "ClientFail"
         }
+    }
+);
+
+our @tests_sctp = (
+    {
+        name => "certstatus-good",
+        server => {
+            extra => {
+                "CertStatus" => "GoodResponse",
+            },
+        },
+        client => {},
+        test => {
+            "Method" => "DTLS",
+            "UseSCTP" => "Yes",
+            "ExpectedResult" => "Success"
+        }
+    },
+    {
+        name => "certstatus-bad",
+        server => {
+            extra => {
+                "CertStatus" => "BadResponse",
+            },
+        },
+        client => {},
+        test => {
+            "Method" => "DTLS",
+            "UseSCTP" => "Yes",
+            "ExpectedResult" => "ClientFail"
+        }
     },
 );
+
+push @tests, @tests_sctp unless disabled("sctp") || disabled("sock");
diff --git a/test/ssl-tests/18-dtls-renegotiate.conf b/test/ssl-tests/18-dtls-renegotiate.conf
index 3d8ebd7..9204dd2 100644
--- a/test/ssl-tests/18-dtls-renegotiate.conf
+++ b/test/ssl-tests/18-dtls-renegotiate.conf
@@ -36,6 +36,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateClient
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 
 
 # ===========================================================
@@ -62,6 +63,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateClient
 Method = DTLS
 ResumptionExpected = Yes
+UseSCTP = No
 
 
 # ===========================================================
@@ -88,6 +90,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateServer
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 
 
 # ===========================================================
@@ -118,6 +121,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateServer
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 
 
 # ===========================================================
@@ -148,6 +152,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateServer
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 
 
 # ===========================================================
@@ -175,6 +180,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateClient
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 client = 5-renegotiate-aead-to-non-aead-client-extra
 
 [5-renegotiate-aead-to-non-aead-client-extra]
@@ -206,6 +212,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateClient
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 client = 6-renegotiate-non-aead-to-aead-client-extra
 
 [6-renegotiate-non-aead-to-aead-client-extra]
@@ -237,6 +244,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateClient
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 client = 7-renegotiate-non-aead-to-non-aead-client-extra
 
 [7-renegotiate-non-aead-to-non-aead-client-extra]
@@ -268,6 +276,7 @@ ExpectedResult = Success
 HandshakeMode = RenegotiateClient
 Method = DTLS
 ResumptionExpected = No
+UseSCTP = No
 client = 8-renegotiate-aead-to-aead-client-extra
 
 [8-renegotiate-aead-to-aead-client-extra]
diff --git a/test/ssl-tests/18-dtls-renegotiate.conf.in b/test/ssl-tests/18-dtls-renegotiate.conf.in
index 7a65a85..467d6f2 100644
--- a/test/ssl-tests/18-dtls-renegotiate.conf.in
+++ b/test/ssl-tests/18-dtls-renegotiate.conf.in
@@ -15,160 +15,178 @@ use warnings;
 package ssltests;
 use OpenSSL::Test::Utils;
 
-our @tests = (
-    {
-        name => "renegotiate-client-no-resume",
-        server => {
-            "Options" => "NoResumptionOnRenegotiation"
-        },
-        client => {},
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateClient",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    },
-    {
-        name => "renegotiate-client-resume",
-        server => {},
-        client => {},
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateClient",
-            "ResumptionExpected" => "Yes",
-            "ExpectedResult" => "Success"
-        }
-    },
-# Note: Unlike the TLS tests, we will never do resumption with server
-# initiated reneg. This is because an OpenSSL DTLS client will always do a full
-# handshake (i.e. it doesn't supply a session id) when it receives a
-# HelloRequest. This is different to the OpenSSL TLS implementation where an
-# OpenSSL client will always try an abbreviated handshake (i.e. it will supply
-# the session id). This goes all the way to commit 48ae85b6f when abbreviated
-# handshake support was first added. Neither behaviour is wrong, but the
-# discrepancy is strange. TODO: Should we harmonise the TLS and DTLS behaviour,
-# and if so, what to?
-    {
-        name => "renegotiate-server-resume",
-        server => {},
-        client => {},
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateServer",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    },
-    {
-        name => "renegotiate-client-auth-require",
-        server => {
-            "VerifyCAFile" => test_pem("root-cert.pem"),
-            "VerifyMode" => "Require",
-        },
-        client => {
-            "Certificate" => test_pem("ee-client-chain.pem"),
-            "PrivateKey"  => test_pem("ee-key.pem"),
-        },
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateServer",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    },
-    {
-        name => "renegotiate-client-auth-once",
-        server => {
-            "VerifyCAFile" => test_pem("root-cert.pem"),
-            "VerifyMode" => "Once",
-        },
-        client => {
-            "Certificate" => test_pem("ee-client-chain.pem"),
-            "PrivateKey"  => test_pem("ee-key.pem"),
-        },
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateServer",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    }
-);
-our @tests_dtls1_2 = (
-    {
-        name => "renegotiate-aead-to-non-aead",
-        server => {
-            "Options" => "NoResumptionOnRenegotiation"
+our @tests = ();
+
+foreach my $sctp ("No", "Yes")
+{
+    next if disabled("sctp") && $sctp eq "Yes";
+
+    my $suffix = ($sctp eq "No") ? "" : "-sctp";
+    our @tests_basic = (
+        {
+            name => "renegotiate-client-no-resume".$suffix,
+            server => {
+                "Options" => "NoResumptionOnRenegotiation"
+            },
+            client => {},
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateClient",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
+            }
         },
-        client => {
-            "CipherString" => "AES128-GCM-SHA256",
-            extra => {
-                "RenegotiateCiphers" => "AES128-SHA"
+        {
+            name => "renegotiate-client-resume".$suffix,
+            server => {},
+            client => {},
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateClient",
+                "ResumptionExpected" => "Yes",
+                "ExpectedResult" => "Success"
             }
         },
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateClient",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    },
-    {
-        name => "renegotiate-non-aead-to-aead",
-        server => {
-            "Options" => "NoResumptionOnRenegotiation"
+        # Note: Unlike the TLS tests, we will never do resumption with server
+        # initiated reneg. This is because an OpenSSL DTLS client will always do a full
+        # handshake (i.e. it doesn't supply a session id) when it receives a
+        # HelloRequest. This is different to the OpenSSL TLS implementation where an
+        # OpenSSL client will always try an abbreviated handshake (i.e. it will supply
+        # the session id). This goes all the way to commit 48ae85b6f when abbreviated
+        # handshake support was first added. Neither behaviour is wrong, but the
+        # discrepancy is strange. TODO: Should we harmonise the TLS and DTLS behaviour,
+        # and if so, what to?
+        {
+            name => "renegotiate-server-resume".$suffix,
+            server => {},
+            client => {},
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateServer",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
+            }
         },
-        client => {
-            "CipherString" => "AES128-SHA",
-            extra => {
-                "RenegotiateCiphers" => "AES128-GCM-SHA256"
+        {
+            name => "renegotiate-client-auth-require".$suffix,
+            server => {
+                "VerifyCAFile" => test_pem("root-cert.pem"),
+                "VerifyMode" => "Require",
+            },
+            client => {
+                "Certificate" => test_pem("ee-client-chain.pem"),
+                "PrivateKey"  => test_pem("ee-key.pem"),
+            },
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateServer",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
             }
         },
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateClient",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
+        {
+            name => "renegotiate-client-auth-once".$suffix,
+            server => {
+                "VerifyCAFile" => test_pem("root-cert.pem"),
+                "VerifyMode" => "Once",
+            },
+            client => {
+                "Certificate" => test_pem("ee-client-chain.pem"),
+                "PrivateKey"  => test_pem("ee-key.pem"),
+            },
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateServer",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
+            }
         }
-    },
-    {
-        name => "renegotiate-non-aead-to-non-aead",
-        server => {
-            "Options" => "NoResumptionOnRenegotiation"
+    );
+    push @tests, @tests_basic;
+
+    next if disabled("dtls1_2");
+    our @tests_dtls1_2 = (
+        {
+            name => "renegotiate-aead-to-non-aead".$suffix,
+            server => {
+                "Options" => "NoResumptionOnRenegotiation"
+            },
+            client => {
+                "CipherString" => "AES128-GCM-SHA256",
+                extra => {
+                    "RenegotiateCiphers" => "AES128-SHA"
+                }
+            },
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateClient",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
+            }
         },
-        client => {
-            "CipherString" => "AES128-SHA",
-            extra => {
-                "RenegotiateCiphers" => "AES256-SHA"
+        {
+            name => "renegotiate-non-aead-to-aead".$suffix,
+            server => {
+                "Options" => "NoResumptionOnRenegotiation"
+            },
+            client => {
+                "CipherString" => "AES128-SHA",
+                extra => {
+                    "RenegotiateCiphers" => "AES128-GCM-SHA256"
+                }
+            },
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateClient",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
             }
         },
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateClient",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    },
-    {
-        name => "renegotiate-aead-to-aead",
-        server => {
-            "Options" => "NoResumptionOnRenegotiation"
+        {
+            name => "renegotiate-non-aead-to-non-aead".$suffix,
+            server => {
+                "Options" => "NoResumptionOnRenegotiation"
+            },
+            client => {
+                "CipherString" => "AES128-SHA",
+                extra => {
+                    "RenegotiateCiphers" => "AES256-SHA"
+                }
+            },
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateClient",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
+            }
         },
-        client => {
-            "CipherString" => "AES128-GCM-SHA256",
-            extra => {
-                "RenegotiateCiphers" => "AES256-GCM-SHA384"
+        {
+            name => "renegotiate-aead-to-aead".$suffix,
+            server => {
+                "Options" => "NoResumptionOnRenegotiation"
+            },
+            client => {
+                "CipherString" => "AES128-GCM-SHA256",
+                extra => {
+                    "RenegotiateCiphers" => "AES256-GCM-SHA384"
+                }
+            },
+            test => {
+                "Method" => "DTLS",
+                "UseSCTP" => $sctp,
+                "HandshakeMode" => "RenegotiateClient",
+                "ResumptionExpected" => "No",
+                "ExpectedResult" => "Success"
             }
         },
-        test => {
-            "Method" => "DTLS",
-            "HandshakeMode" => "RenegotiateClient",
-            "ResumptionExpected" => "No",
-            "ExpectedResult" => "Success"
-        }
-    },
-);
-
-
-push @tests, @tests_dtls1_2 unless disabled("dtls1_2");
+    );
+    push @tests, @tests_dtls1_2;
+}
diff --git a/test/ssl-tests/protocol_version.pm b/test/ssl-tests/protocol_version.pm
index 7c28bcf..f0b3030 100644
--- a/test/ssl-tests/protocol_version.pm
+++ b/test/ssl-tests/protocol_version.pm
@@ -96,31 +96,35 @@ sub generate_version_tests {
 
     my @tests = ();
 
-    foreach my $c_min (0..$#min_protocols) {
-        my $c_max_min = $c_min == 0 ? 0 : $c_min - 1;
-        foreach my $c_max ($c_max_min..$#max_protocols) {
-            foreach my $s_min (0..$#min_protocols) {
-                my $s_max_min = $s_min == 0 ? 0 : $s_min - 1;
-                foreach my $s_max ($s_max_min..$#max_protocols) {
-                    my ($result, $protocol) =
-                        expected_result($c_min, $c_max, $s_min, $s_max,
-                                        $min_enabled, $max_enabled, \@protocols);
-                    push @tests, {
-                        "name" => "version-negotiation",
-                        "client" => {
-                            "MinProtocol" => $min_protocols[$c_min],
-                            "MaxProtocol" => $max_protocols[$c_max],
-                        },
-                        "server" => {
-                            "MinProtocol" => $min_protocols[$s_min],
-                            "MaxProtocol" => $max_protocols[$s_max],
-                        },
-                        "test" => {
-                            "ExpectedResult" => $result,
-                            "ExpectedProtocol" => $protocol,
-                            "Method" => $method,
-                        }
-                    };
+    for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1); $sctp++) {
+        foreach my $c_min (0..$#min_protocols) {
+            my $c_max_min = $c_min == 0 ? 0 : $c_min - 1;
+            foreach my $c_max ($c_max_min..$#max_protocols) {
+                foreach my $s_min (0..$#min_protocols) {
+                    my $s_max_min = $s_min == 0 ? 0 : $s_min - 1;
+                    foreach my $s_max ($s_max_min..$#max_protocols) {
+                        my ($result, $protocol) =
+                            expected_result($c_min, $c_max, $s_min, $s_max,
+                                            $min_enabled, $max_enabled,
+                                            \@protocols);
+                        push @tests, {
+                            "name" => "version-negotiation",
+                            "client" => {
+                                "MinProtocol" => $min_protocols[$c_min],
+                                "MaxProtocol" => $max_protocols[$c_max],
+                            },
+                            "server" => {
+                                "MinProtocol" => $min_protocols[$s_min],
+                                "MaxProtocol" => $max_protocols[$s_max],
+                            },
+                            "test" => {
+                                "ExpectedResult" => $result,
+                                "ExpectedProtocol" => $protocol,
+                                "Method" => $method,
+                            }
+                        };
+                        $tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
+                    }
                 }
             }
         }
@@ -159,46 +163,51 @@ sub generate_resumption_tests {
                 $resumption_expected = "No";
             }
 
-            foreach my $ticket ("SessionTicket", "-SessionTicket") {
-                # Client is flexible, server upgrades/downgrades.
-                push @server_tests, {
-                    "name" => "resumption",
-                    "client" => { },
-                    "server" => {
-                        "MinProtocol" => $protocols[$original_protocol],
-                        "MaxProtocol" => $protocols[$original_protocol],
-                        "Options" => $ticket,
-                    },
-                    "resume_server" => {
-                        "MaxProtocol" => $protocols[$resume_protocol],
-                    },
-                    "test" => {
-                        "ExpectedProtocol" => $protocols[$resume_protocol],
-                        "Method" => $method,
-                        "HandshakeMode" => "Resume",
-                        "ResumptionExpected" => $resumption_expected,
-                    }
-                };
-                # Server is flexible, client upgrades/downgrades.
-                push @client_tests, {
-                    "name" => "resumption",
-                    "client" => {
-                        "MinProtocol" => $protocols[$original_protocol],
-                        "MaxProtocol" => $protocols[$original_protocol],
-                    },
-                    "server" => {
-                        "Options" => $ticket,
-                    },
-                    "resume_client" => {
-                        "MaxProtocol" => $protocols[$resume_protocol],
-                    },
-                    "test" => {
-                        "ExpectedProtocol" => $protocols[$resume_protocol],
-                        "Method" => $method,
-                        "HandshakeMode" => "Resume",
-                        "ResumptionExpected" => $resumption_expected,
-                    }
-                };
+            for (my $sctp = 0; $sctp < ($dtls && !disabled("sctp") ? 2 : 1);
+                 $sctp++) {
+                foreach my $ticket ("SessionTicket", "-SessionTicket") {
+                    # Client is flexible, server upgrades/downgrades.
+                    push @server_tests, {
+                        "name" => "resumption",
+                        "client" => { },
+                        "server" => {
+                            "MinProtocol" => $protocols[$original_protocol],
+                            "MaxProtocol" => $protocols[$original_protocol],
+                            "Options" => $ticket,
+                        },
+                        "resume_server" => {
+                            "MaxProtocol" => $protocols[$resume_protocol],
+                        },
+                        "test" => {
+                            "ExpectedProtocol" => $protocols[$resume_protocol],
+                            "Method" => $method,
+                            "HandshakeMode" => "Resume",
+                            "ResumptionExpected" => $resumption_expected,
+                        }
+                    };
+                    $server_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
+                    # Server is flexible, client upgrades/downgrades.
+                    push @client_tests, {
+                        "name" => "resumption",
+                        "client" => {
+                            "MinProtocol" => $protocols[$original_protocol],
+                            "MaxProtocol" => $protocols[$original_protocol],
+                        },
+                        "server" => {
+                            "Options" => $ticket,
+                        },
+                        "resume_client" => {
+                            "MaxProtocol" => $protocols[$resume_protocol],
+                        },
+                        "test" => {
+                            "ExpectedProtocol" => $protocols[$resume_protocol],
+                            "Method" => $method,
+                            "HandshakeMode" => "Resume",
+                            "ResumptionExpected" => $resumption_expected,
+                        }
+                    };
+                    $client_tests[-1]{"test"}{"UseSCTP"} = "Yes" if $sctp;
+                }
             }
         }
     }
@@ -244,9 +253,7 @@ sub expected_result {
 
     if ($c_min > $c_max) {
         # Client should fail to even send a hello.
-        # This results in an internal error since the server will be
-        # waiting for input that never arrives.
-        return ("InternalError", undef);
+        return ("ClientFail", undef);
     } elsif ($s_min > $s_max) {
         # Server has no protocols, should always fail.
         return ("ServerFail", undef);
diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c
index 6a3b9d1..424eae8 100644
--- a/test/ssl_test_ctx.c
+++ b/test/ssl_test_ctx.c
@@ -406,6 +406,7 @@ const char *ssl_ct_validation_name(ssl_ct_validation_t mode)
 
 IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, resumption_expected)
 IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_SERVER_CONF, server, broken_session_ticket)
+IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, use_sctp)
 
 /* CertStatus */
 
@@ -590,6 +591,7 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = {
     { "ExpectedClientSignHash", &parse_expected_client_sign_hash },
     { "ExpectedClientSignType", &parse_expected_client_sign_type },
     { "ExpectedClientCANames", &parse_expected_client_ca_names },
+    { "UseSCTP", &parse_test_use_sctp },
 };
 
 /* Nested client options. */
diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h
index 54cefb6..ebeddde 100644
--- a/test/ssl_test_ctx.h
+++ b/test/ssl_test_ctx.h
@@ -198,6 +198,8 @@ typedef struct {
     int expected_client_sign_type;
     /* Expected CA names for client auth */
     STACK_OF(X509_NAME) *expected_client_ca_names;
+    /* Whether to use SCTP for the transport */
+    int use_sctp;
 } SSL_TEST_CTX;
 
 const char *ssl_test_result_name(ssl_test_result_t result);
diff --git a/util/libcrypto.num b/util/libcrypto.num
index 725e075..14c4c6a 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4271,3 +4271,4 @@ UINT32_it                               4214	1_1_0f	EXIST:EXPORT_VAR_AS_FUNCTION
 ZINT64_it                               4215	1_1_0f	EXIST:!EXPORT_VAR_AS_FUNCTION:VARIABLE:
 ZINT64_it                               4215	1_1_0f	EXIST:EXPORT_VAR_AS_FUNCTION:FUNCTION:
 CRYPTO_mem_leaks_cb                     4216	1_1_1	EXIST::FUNCTION:CRYPTO_MDEBUG
+BIO_lookup_ex                           4217	1_1_1	EXIST::FUNCTION:SOCK


More information about the openssl-commits mailing list