summaryrefslogtreecommitdiffstats
path: root/test/handshake_helper.c
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2017-04-24 09:42:28 +0100
committerMatt Caswell <matt@openssl.org>2017-04-25 11:13:39 +0100
commit83964ca0dac18df510a315ff486ecc346521e15d (patch)
treeeff904a5d40c8de502573fdfc6e3d5826eeaa6c4 /test/handshake_helper.c
parent41b3c9ce2a02195aa7cf74c90b80468354ac708d (diff)
Add support to test_ssl_new for testing with DTLS over SCTP
Reviewed-by: Richard Levitte <levitte@openssl.org> (Merged from https://github.com/openssl/openssl/pull/3286)
Diffstat (limited to 'test/handshake_helper.c')
-rw-r--r--test/handshake_helper.c202
1 files changed, 172 insertions, 30 deletions
diff --git a/test/handshake_helper.c b/test/handshake_helper.c
index 94fa5c578f..4943e82d83 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;
}
}
@@ -1017,18 +1023,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 +1092,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 +1212,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 +1227,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 +1257,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 +1282,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 +1301,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 +1319,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 +1355,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;
}
}