summaryrefslogtreecommitdiff
path: root/test/helpers
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2023-03-13 17:36:24 +0000
committerPauli <pauli@openssl.org>2023-03-20 09:35:55 +1100
commit0c593328fe811583da68d25b0c8bf87ba842acbb (patch)
treef11d86cdc06dac4da4315f67cb1cf8595c4234d1 /test/helpers
parentc2212dc19eb280e22bda7d0538b23eef0be040e9 (diff)
downloadopenssl-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.c137
-rw-r--r--test/helpers/quictestlib.h13
-rw-r--r--test/helpers/ssltestlib.c72
-rw-r--r--test/helpers/ssltestlib.h3
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);