diff options
author | Matt Caswell <matt@openssl.org> | 2023-03-13 17:36:24 +0000 |
---|---|---|
committer | Pauli <pauli@openssl.org> | 2023-03-20 09:35:55 +1100 |
commit | 0c593328fe811583da68d25b0c8bf87ba842acbb (patch) | |
tree | f11d86cdc06dac4da4315f67cb1cf8595c4234d1 /test/helpers | |
parent | c2212dc19eb280e22bda7d0538b23eef0be040e9 (diff) | |
download | openssl-new-0c593328fe811583da68d25b0c8bf87ba842acbb.tar.gz |
Add a simple QUIC test for blocking mode
We create "real" sockets for blocking mode so that we can block on them.
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20514)
Diffstat (limited to 'test/helpers')
-rw-r--r-- | test/helpers/quictestlib.c | 137 | ||||
-rw-r--r-- | test/helpers/quictestlib.h | 13 | ||||
-rw-r--r-- | test/helpers/ssltestlib.c | 72 | ||||
-rw-r--r-- | test/helpers/ssltestlib.h | 3 |
4 files changed, 180 insertions, 45 deletions
diff --git a/test/helpers/quictestlib.c b/test/helpers/quictestlib.c index 657fcd257c..e60573eb6e 100644 --- a/test/helpers/quictestlib.c +++ b/test/helpers/quictestlib.c @@ -8,9 +8,14 @@ */ #include <assert.h> +#include <openssl/configuration.h> #include <openssl/bio.h> #include "quictestlib.h" +#include "ssltestlib.h" #include "../testutil.h" +#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) +# include "../threadstest.h" +#endif #include "internal/quic_wire_pkt.h" #include "internal/quic_record_tx.h" #include "internal/quic_error.h" @@ -61,8 +66,9 @@ static void handshake_finish(void *arg); static BIO_METHOD *get_bio_method(void); -int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, - QUIC_TSERVER **qtserv, SSL **cssl, +int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, + char *certfile, char *keyfile, + int block, QUIC_TSERVER **qtserv, SSL **cssl, QTEST_FAULT **fault) { /* ALPN value as recognised by QUIC_TSERVER */ @@ -79,28 +85,54 @@ int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, if (!TEST_ptr(*cssl)) return 0; - if (!TEST_true(SSL_set_blocking_mode(*cssl, 0))) - goto err; - /* SSL_set_alpn_protos returns 0 for success! */ if (!TEST_false(SSL_set_alpn_protos(*cssl, alpn, sizeof(alpn)))) goto err; - if (!TEST_true(BIO_new_bio_dgram_pair(&cbio, 0, &sbio, 0))) + if (!TEST_ptr(peeraddr = BIO_ADDR_new())) goto err; - if (!TEST_true(BIO_dgram_set_caps(cbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) - || !TEST_true(BIO_dgram_set_caps(sbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR))) + if (block) { +#if !defined(OPENSSL_NO_POSIX_IO) + int cfd, sfd; + + /* + * For blocking mode we need to create actual sockets rather than doing + * everything in memory + */ + if (!TEST_true(create_test_sockets(&cfd, &sfd, SOCK_DGRAM, peeraddr))) + goto err; + cbio = BIO_new_dgram(cfd, 1); + if (!TEST_ptr(cbio)) { + close(cfd); + close(sfd); + goto err; + } + sbio = BIO_new_dgram(sfd, 1); + if (!TEST_ptr(sbio)) { + close(sfd); + goto err; + } +#else goto err; +#endif + } else { + if (!TEST_true(BIO_new_bio_dgram_pair(&cbio, 0, &sbio, 0))) + goto err; - SSL_set_bio(*cssl, cbio, cbio); + if (!TEST_true(BIO_dgram_set_caps(cbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) + || !TEST_true(BIO_dgram_set_caps(sbio, BIO_DGRAM_CAP_HANDLES_DST_ADDR))) + goto err; - if (!TEST_ptr(peeraddr = BIO_ADDR_new())) - goto err; + /* Dummy server address */ + if (!TEST_true(BIO_ADDR_rawmake(peeraddr, AF_INET, &ina, sizeof(ina), + htons(0)))) + goto err; + } + + SSL_set_bio(*cssl, cbio, cbio); - /* Dummy server address */ - if (!TEST_true(BIO_ADDR_rawmake(peeraddr, AF_INET, &ina, sizeof(ina), - htons(0)))) + if (!TEST_true(SSL_set_blocking_mode(*cssl, block))) goto err; if (!TEST_true(SSL_set_initial_peer_addr(*cssl, peeraddr))) @@ -121,6 +153,7 @@ int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, if (!TEST_ptr(BIO_push(fisbio, sbio))) goto err; + tserver_args.libctx = libctx; tserver_args.net_rbio = sbio; tserver_args.net_wbio = fisbio; @@ -144,6 +177,7 @@ int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, BIO_free(fisbio); BIO_free(sbio); SSL_free(*cssl); + *cssl = NULL; ossl_quic_tserver_free(*qtserv); if (fault != NULL) OPENSSL_free(*fault); @@ -151,12 +185,66 @@ int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, return 0; } +int qtest_supports_blocking(void) +{ +#if !defined(OPENSSL_NO_POSIX_IO) && defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) + return 1; +#else + return 0; +#endif +} + #define MAXLOOPS 1000 +#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) +static int globserverret = 0; +static QUIC_TSERVER *globtserv; +static const thread_t thread_zero; + +static void run_server_thread(void) +{ + /* + * This will operate in a busy loop because the server does not block, + * but should be acceptable because it is local and we expect this to be + * fast + */ + globserverret = qtest_create_quic_connection(globtserv, NULL); +} +#endif + int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl) { int retc = -1, rets = 0, err, abortctr = 0, ret = 0; int clienterr = 0, servererr = 0; +#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) + /* + * Pointless initialisation to avoid bogus compiler warnings about using + * t uninitialised + */ + thread_t t = thread_zero; +#endif + + if (!TEST_ptr(qtserv)) { + goto err; + } else if (clientssl == NULL) { + retc = 1; + } else if (SSL_get_blocking_mode(clientssl) > 0) { +#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) + /* + * clientssl is blocking. We will need a thread to complete the + * connection + */ + globtserv = qtserv; + if (!TEST_true(run_thread(&t, run_server_thread))) + goto err; + + qtserv = NULL; + rets = 1; +#else + TEST_error("No thread support in this build"); + goto err; +#endif + } do { err = SSL_ERROR_WANT_WRITE; @@ -191,18 +279,37 @@ int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl) if (clienterr && servererr) goto err; - if (++abortctr == MAXLOOPS) { + if (clientssl != NULL && ++abortctr == MAXLOOPS) { TEST_info("No progress made"); goto err; } } while ((retc <= 0 && !clienterr) || (rets <= 0 && !servererr)); + if (qtserv == NULL && rets > 0) { +#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) + if (!TEST_true(wait_for_thread(t)) || !TEST_true(globserverret)) + goto err; +#else + TEST_error("Should not happen"); + goto err; +#endif + } + if (!clienterr && !servererr) ret = 1; err: return ret; } +int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl) +{ + /* Busy loop in non-blocking mode. It should be quick because its local */ + while (SSL_shutdown(clientssl) != 1) + ossl_quic_tserver_tick(qtserv); + + return 1; +} + int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code) { QUIC_TERMINATE_CAUSE cause; diff --git a/test/helpers/quictestlib.h b/test/helpers/quictestlib.h index 165551aa6a..71cdd91bcb 100644 --- a/test/helpers/quictestlib.h +++ b/test/helpers/quictestlib.h @@ -27,9 +27,10 @@ typedef struct qtest_fault_encrypted_extensions { /* * Given an SSL_CTX for the client and filenames for the server certificate and * keyfile, create a server and client instances as well as a fault injector - * instance + * instance. |block| indicates whether we are using blocking mode or not. */ -int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, +int qtest_create_quic_objects(OSSL_LIB_CTX *libctx, SSL_CTX *clientctx, + char *certfile, char *keyfile, int block, QUIC_TSERVER **qtserv, SSL **cssl, QTEST_FAULT **fault); @@ -38,6 +39,9 @@ int qtest_create_quic_objects(SSL_CTX *clientctx, char *certfile, char *keyfile, */ void qtest_fault_free(QTEST_FAULT *fault); +/* Returns 1 if the quictestlib supports blocking tests */ +int qtest_supports_blocking(void); + /* * Run the TLS handshake to create a QUIC connection between the client and * server. @@ -45,6 +49,11 @@ void qtest_fault_free(QTEST_FAULT *fault); int qtest_create_quic_connection(QUIC_TSERVER *qtserv, SSL *clientssl); /* + * Shutdown the client SSL object gracefully + */ +int qtest_shutdown(QUIC_TSERVER *qtserv, SSL *clientssl); + +/* * Confirm that the server has received the given transport error code. */ int qtest_check_server_transport_err(QUIC_TSERVER *qtserv, uint64_t code); diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c index 727ba7ff6a..94100b9ca4 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -9,20 +9,15 @@ #include <string.h> +#include "internal/e_os.h" #include "internal/nelem.h" #include "ssltestlib.h" #include "../testutil.h" -#ifdef OPENSSL_SYS_UNIX -# include <unistd.h> -# ifndef OPENSSL_NO_KTLS -# include <netinet/in.h> -# include <netinet/in.h> -# include <arpa/inet.h> -# include <sys/socket.h> -# include <unistd.h> -# include <fcntl.h> -# endif +#if (!defined(OPENSSL_NO_KTLS) || !defined(OPENSSL_NO_QUIC)) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_NO_SOCK) +# define OSSL_USE_SOCKETS 1 +# include "internal/sockets.h" +# include <openssl/bio.h> #endif static int tls_dump_new(BIO *bi); @@ -879,19 +874,25 @@ int create_ssl_ctx_pair(OSSL_LIB_CTX *libctx, const SSL_METHOD *sm, #define MAXLOOPS 1000000 -#if !defined(OPENSSL_NO_KTLS) && !defined(OPENSSL_NO_SOCK) -static int set_nb(int fd) +#if defined(OSSL_USE_SOCKETS) +int wait_until_sock_readable(int sock) { - int flags; + fd_set readfds; + struct timeval timeout; + int width; + + width = sock + 1; + FD_ZERO(&readfds); + openssl_fdset(sock, &readfds); + timeout.tv_sec = 10; /* give up after 10 seconds */ + timeout.tv_usec = 0; + + select(width, &readfds, NULL, NULL, &timeout); - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) - return flags; - flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK); - return flags; + return FD_ISSET(sock, &readfds); } -int create_test_sockets(int *cfdp, int *sfdp) +int create_test_sockets(int *cfdp, int *sfdp, int socktype, BIO_ADDR *saddr) { struct sockaddr_in sin; const char *host = "127.0.0.1"; @@ -903,8 +904,9 @@ int create_test_sockets(int *cfdp, int *sfdp) sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(host); - afd = socket(AF_INET, SOCK_STREAM, 0); - if (afd < 0) + afd = BIO_socket(AF_INET, socktype, + socktype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP, 0); + if (afd == INVALID_SOCKET) return 0; if (bind(afd, (struct sockaddr*)&sin, sizeof(sin)) < 0) @@ -913,16 +915,32 @@ int create_test_sockets(int *cfdp, int *sfdp) if (getsockname(afd, (struct sockaddr*)&sin, &slen) < 0) goto out; - if (listen(afd, 1) < 0) + if (saddr != NULL + && !BIO_ADDR_rawmake(saddr, sin.sin_family, &sin.sin_addr, + sizeof(sin.sin_addr), sin.sin_port)) + goto out; + + if (socktype == SOCK_STREAM && listen(afd, 1) < 0) goto out; - cfd = socket(AF_INET, SOCK_STREAM, 0); - if (cfd < 0) + cfd = BIO_socket(AF_INET, socktype, + socktype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP, 0); + if (cfd == INVALID_SOCKET) goto out; - if (set_nb(afd) == -1) + if (!BIO_socket_nbio(afd, 1)) goto out; + /* + * If a DGRAM socket then we don't call "accept" or "connect" - so act like + * we already called them. + */ + if (socktype == SOCK_DGRAM) { + cfd_connected = 1; + sfd = afd; + afd = -1; + } + while (sfd == -1 || !cfd_connected) { sfd = accept(afd, NULL, 0); if (sfd == -1 && errno != EAGAIN) @@ -934,7 +952,7 @@ int create_test_sockets(int *cfdp, int *sfdp) cfd_connected = 1; } - if (set_nb(cfd) == -1 || set_nb(sfd) == -1) + if (!BIO_socket_nbio(cfd, 1) || !BIO_socket_nbio(sfd, 1)) goto out; ret = 1; *cfdp = cfd; @@ -984,7 +1002,7 @@ int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, BIO_free(c_to_s_bio); return 0; } -#endif +#endif /* defined(OSSL_USE_SOCKETS) */ /* * NOTE: Transfers control of the BIOs - this function will free them on error diff --git a/test/helpers/ssltestlib.h b/test/helpers/ssltestlib.h index d8ee6a9b7d..bc06813e72 100644 --- a/test/helpers/ssltestlib.h +++ b/test/helpers/ssltestlib.h @@ -22,7 +22,8 @@ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want, int read, int listen); int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl, SSL **cssl, int sfd, int cfd); -int create_test_sockets(int *cfd, int *sfd); +int wait_until_sock_readable(int sock); +int create_test_sockets(int *cfdp, int *sfdp, int socktype, BIO_ADDR *saddr); int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want); void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl); |