Commit 83964ca0 authored by Matt Caswell's avatar Matt Caswell
Browse files

Add support to test_ssl_new for testing with DTLS over SCTP

parent 41b3c9ce
Loading
Loading
Loading
Loading
+156 −14
Changes for test/handshake_helper.c: 156 added lines, 14 removed lines.
Original line number Diff line number Diff line
@@ -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;
        }

    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;

    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. */
    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,6 +1355,23 @@ static HANDSHAKE_RESULT *do_handshake_internal(
            ret->result = SSL_TEST_INTERNAL_ERROR;
            goto err;
        case HANDSHAKE_RETRY:
            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;
                }
                /*
                 * With "real" sockets we only swap to processing the peer
                 * if they are expecting to retry. Otherwise we just retry the
                 * same endpoint again.
                 */
                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
@@ -1243,6 +1384,7 @@ static HANDSHAKE_RESULT *do_handshake_internal(

                /* Continue. */
                client_turn ^= 1;
            }
            break;
        }
    }
+2 −1
Changes for test/recipes/80-test_ssl_new.t: 2 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -60,8 +60,9 @@ my %conf_dependent_tests = (
  "07-dtls-protocol-version.conf" => !$is_default_dtls,
  "10-resumption.conf" => !$is_default_tls,
  "11-dtls_resumption.conf" => !$is_default_dtls,
  "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,
+104 −104

File changed.

Preview size limit exceeded, changes collapsed.

+1 −3

File changed.

Preview size limit exceeded, changes collapsed.

+2 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading