提交 83964ca0 编写于 作者: M Matt Caswell

Add support to test_ssl_new for testing with DTLS over SCTP

Reviewed-by: NRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3286)
上级 41b3c9ce
......@@ -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;
}
}
......
......@@ -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,
......
......@@ -244,9 +244,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);
......
......@@ -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. */
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册