aboutsummaryrefslogtreecommitdiff
path: root/test/helpers/ssltestlib.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/helpers/ssltestlib.c')
-rw-r--r--test/helpers/ssltestlib.c375
1 files changed, 325 insertions, 50 deletions
diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c
index b0ef7d719c53..e9a51c9c30d0 100644
--- a/test/helpers/ssltestlib.c
+++ b/test/helpers/ssltestlib.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -18,21 +18,16 @@
#include <string.h>
#include <openssl/engine.h>
+#include "internal/e_os.h"
#include "internal/nelem.h"
#include "ssltestlib.h"
#include "../testutil.h"
-#include "e_os.h" /* for ossl_sleep() etc. */
-
-#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/e_winsock.h"
+# include "internal/sockets.h"
+# include <openssl/bio.h>
#endif
static int tls_dump_new(BIO *bi);
@@ -44,13 +39,15 @@ static int tls_dump_gets(BIO *bp, char *buf, int size);
static int tls_dump_puts(BIO *bp, const char *str);
/* Choose a sufficiently large type likely to be unused for this custom BIO */
-#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER)
+#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER)
#define BIO_TYPE_MEMPACKET_TEST 0x81
#define BIO_TYPE_ALWAYS_RETRY 0x82
+#define BIO_TYPE_MAYBE_RETRY (0x83 | BIO_TYPE_FILTER)
static BIO_METHOD *method_tls_dump = NULL;
static BIO_METHOD *meth_mem = NULL;
static BIO_METHOD *meth_always_retry = NULL;
+static BIO_METHOD *meth_maybe_retry = NULL;
static int retry_err = -1;
/* Note: Not thread safe! */
@@ -59,7 +56,7 @@ const BIO_METHOD *bio_f_tls_dump_filter(void)
if (method_tls_dump == NULL) {
method_tls_dump = BIO_meth_new(BIO_TYPE_TLS_DUMP_FILTER,
"TLS dump filter");
- if ( method_tls_dump == NULL
+ if (method_tls_dump == NULL
|| !BIO_meth_set_write(method_tls_dump, tls_dump_write)
|| !BIO_meth_set_read(method_tls_dump, tls_dump_read)
|| !BIO_meth_set_puts(method_tls_dump, tls_dump_puts)
@@ -273,7 +270,7 @@ static void mempacket_free(MEMPACKET *pkt)
typedef struct mempacket_test_ctx_st {
STACK_OF(MEMPACKET) *pkts;
- unsigned int epoch;
+ uint16_t epoch;
unsigned int currrec;
unsigned int currpkt;
unsigned int lastpkt;
@@ -819,6 +816,100 @@ static int always_retry_puts(BIO *bio, const char *str)
return retry_err;
}
+struct maybe_retry_data_st {
+ unsigned int retrycnt;
+};
+
+static int maybe_retry_new(BIO *bi);
+static int maybe_retry_free(BIO *a);
+static int maybe_retry_write(BIO *b, const char *in, int inl);
+static long maybe_retry_ctrl(BIO *b, int cmd, long num, void *ptr);
+
+const BIO_METHOD *bio_s_maybe_retry(void)
+{
+ if (meth_maybe_retry == NULL) {
+ if (!TEST_ptr(meth_maybe_retry = BIO_meth_new(BIO_TYPE_MAYBE_RETRY,
+ "Maybe Retry"))
+ || !TEST_true(BIO_meth_set_write(meth_maybe_retry,
+ maybe_retry_write))
+ || !TEST_true(BIO_meth_set_ctrl(meth_maybe_retry,
+ maybe_retry_ctrl))
+ || !TEST_true(BIO_meth_set_create(meth_maybe_retry,
+ maybe_retry_new))
+ || !TEST_true(BIO_meth_set_destroy(meth_maybe_retry,
+ maybe_retry_free)))
+ return NULL;
+ }
+ return meth_maybe_retry;
+}
+
+void bio_s_maybe_retry_free(void)
+{
+ BIO_meth_free(meth_maybe_retry);
+}
+
+static int maybe_retry_new(BIO *bio)
+{
+ struct maybe_retry_data_st *data = OPENSSL_zalloc(sizeof(*data));
+
+ if (data == NULL)
+ return 0;
+
+ BIO_set_data(bio, data);
+ BIO_set_init(bio, 1);
+ return 1;
+}
+
+static int maybe_retry_free(BIO *bio)
+{
+ struct maybe_retry_data_st *data = BIO_get_data(bio);
+
+ OPENSSL_free(data);
+ BIO_set_data(bio, NULL);
+ BIO_set_init(bio, 0);
+ return 1;
+}
+
+static int maybe_retry_write(BIO *bio, const char *in, int inl)
+{
+ struct maybe_retry_data_st *data = BIO_get_data(bio);
+
+ if (data == NULL)
+ return -1;
+
+ if (data->retrycnt == 0) {
+ BIO_set_retry_write(bio);
+ return -1;
+ }
+ data->retrycnt--;
+
+ return BIO_write(BIO_next(bio), in, inl);
+}
+
+static long maybe_retry_ctrl(BIO *bio, int cmd, long num, void *ptr)
+{
+ struct maybe_retry_data_st *data = BIO_get_data(bio);
+
+ if (data == NULL)
+ return 0;
+
+ switch (cmd) {
+ case MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT:
+ data->retrycnt = num;
+ return 1;
+
+ case BIO_CTRL_FLUSH:
+ if (data->retrycnt == 0) {
+ BIO_set_retry_write(bio);
+ return -1;
+ }
+ data->retrycnt--;
+ /* fall through */
+ default:
+ return BIO_ctrl(BIO_next(bio), cmd, num, ptr);
+ }
+}
+
int create_ssl_ctx_pair(OSSL_LIB_CTX *libctx, const SSL_METHOD *sm,
const SSL_METHOD *cm, int min_proto_version,
int max_proto_version, SSL_CTX **sctx, SSL_CTX **cctx,
@@ -898,19 +989,26 @@ 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;
- flags = fcntl(fd,F_GETFL,0);
- if (flags == -1)
- return flags;
- flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- return flags;
+ 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);
+
+ 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";
@@ -922,8 +1020,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)
@@ -932,17 +1031,33 @@ 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;
- while (sfd == -1 || !cfd_connected ) {
+ /*
+ * 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)
goto out;
@@ -953,7 +1068,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;
@@ -976,6 +1091,7 @@ int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
{
SSL *serverssl = NULL, *clientssl = NULL;
BIO *s_to_c_bio = NULL, *c_to_s_bio = NULL;
+ BIO_POLL_DESCRIPTOR rdesc = {0}, wdesc = {0};
if (*sssl != NULL)
serverssl = *sssl;
@@ -990,8 +1106,29 @@ int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
|| !TEST_ptr(c_to_s_bio = BIO_new_socket(cfd, BIO_NOCLOSE)))
goto error;
+ if (!TEST_false(SSL_get_rpoll_descriptor(clientssl, &rdesc)
+ || !TEST_false(SSL_get_wpoll_descriptor(clientssl, &wdesc))))
+ goto error;
+
SSL_set_bio(clientssl, c_to_s_bio, c_to_s_bio);
SSL_set_bio(serverssl, s_to_c_bio, s_to_c_bio);
+
+ if (!TEST_true(SSL_get_rpoll_descriptor(clientssl, &rdesc))
+ || !TEST_true(SSL_get_wpoll_descriptor(clientssl, &wdesc))
+ || !TEST_int_eq(rdesc.type, BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD)
+ || !TEST_int_eq(wdesc.type, BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD)
+ || !TEST_int_eq(rdesc.value.fd, cfd)
+ || !TEST_int_eq(wdesc.value.fd, cfd))
+ goto error;
+
+ if (!TEST_true(SSL_get_rpoll_descriptor(serverssl, &rdesc))
+ || !TEST_true(SSL_get_wpoll_descriptor(serverssl, &wdesc))
+ || !TEST_int_eq(rdesc.type, BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD)
+ || !TEST_int_eq(wdesc.type, BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD)
+ || !TEST_int_eq(rdesc.value.fd, sfd)
+ || !TEST_int_eq(wdesc.value.fd, sfd))
+ goto error;
+
*sssl = serverssl;
*cssl = clientssl;
return 1;
@@ -1003,7 +1140,15 @@ int create_ssl_objects2(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
BIO_free(c_to_s_bio);
return 0;
}
-#endif
+
+#else
+
+int wait_until_sock_readable(int sock)
+{
+ return 0;
+}
+
+#endif /* defined(OSSL_USE_SOCKETS) */
/*
* NOTE: Transfers control of the BIOs - this function will free them on error
@@ -1045,9 +1190,14 @@ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
BIO_set_mem_eof_return(c_to_s_bio, -1);
/* Up ref these as we are passing them to two SSL objects */
+ if (!BIO_up_ref(s_to_c_bio))
+ goto error;
+ if (!BIO_up_ref(c_to_s_bio)) {
+ BIO_free(s_to_c_bio);
+ goto error;
+ }
+
SSL_set_bio(serverssl, c_to_s_bio, s_to_c_bio);
- BIO_up_ref(s_to_c_bio);
- BIO_up_ref(c_to_s_bio);
SSL_set_bio(clientssl, s_to_c_bio, c_to_s_bio);
*sssl = serverssl;
*cssl = clientssl;
@@ -1075,11 +1225,29 @@ int create_ssl_objects(SSL_CTX *serverctx, SSL_CTX *clientctx, SSL **sssl,
* attempt could be restarted by a subsequent call to this function.
*/
int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want,
- int read)
+ int read, int listen)
{
- int retc = -1, rets = -1, err, abortctr = 0;
+ int retc = -1, rets = -1, err, abortctr = 0, ret = 0;
int clienterr = 0, servererr = 0;
int isdtls = SSL_is_dtls(serverssl);
+#ifndef OPENSSL_NO_SOCK
+ BIO_ADDR *peer = NULL;
+
+ if (listen) {
+ if (!isdtls) {
+ TEST_error("DTLSv1_listen requested for non-DTLS object\n");
+ return 0;
+ }
+ peer = BIO_ADDR_new();
+ if (!TEST_ptr(peer))
+ return 0;
+ }
+#else
+ if (listen) {
+ TEST_error("DTLSv1_listen requested in a no-sock build\n");
+ return 0;
+ }
+#endif
do {
err = SSL_ERROR_WANT_WRITE;
@@ -1096,13 +1264,29 @@ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want,
clienterr = 1;
}
if (want != SSL_ERROR_NONE && err == want)
- return 0;
+ goto err;
err = SSL_ERROR_WANT_WRITE;
while (!servererr && rets <= 0 && err == SSL_ERROR_WANT_WRITE) {
- rets = SSL_accept(serverssl);
- if (rets <= 0)
- err = SSL_get_error(serverssl, rets);
+#ifndef OPENSSL_NO_SOCK
+ if (listen) {
+ rets = DTLSv1_listen(serverssl, peer);
+ if (rets < 0) {
+ err = SSL_ERROR_SSL;
+ } else if (rets == 0) {
+ err = SSL_ERROR_WANT_READ;
+ } else {
+ /* Success - stop listening and call SSL_accept from now on */
+ listen = 0;
+ rets = 0;
+ }
+ } else
+#endif
+ {
+ rets = SSL_accept(serverssl);
+ if (rets <= 0)
+ err = SSL_get_error(serverssl, rets);
+ }
}
if (!servererr && rets <= 0
@@ -1114,9 +1298,9 @@ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want,
servererr = 1;
}
if (want != SSL_ERROR_NONE && err == want)
- return 0;
+ goto err;
if (clienterr && servererr)
- return 0;
+ goto err;
if (isdtls && read) {
unsigned char buf[20];
@@ -1125,20 +1309,20 @@ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want,
if (SSL_read(serverssl, buf, sizeof(buf)) > 0) {
/* We don't expect this to succeed! */
TEST_info("Unexpected SSL_read() success!");
- return 0;
+ goto err;
}
}
if (retc > 0 && rets <= 0) {
if (SSL_read(clientssl, buf, sizeof(buf)) > 0) {
/* We don't expect this to succeed! */
TEST_info("Unexpected SSL_read() success!");
- return 0;
+ goto err;
}
}
}
if (++abortctr == MAXLOOPS) {
TEST_info("No progress made");
- return 0;
+ goto err;
}
if (isdtls && abortctr <= 50 && (abortctr % 10) == 0) {
/*
@@ -1146,11 +1330,16 @@ int create_bare_ssl_connection(SSL *serverssl, SSL *clientssl, int want,
* give the DTLS timer a chance to do something. We only do this for
* the first few times to prevent hangs.
*/
- ossl_sleep(50);
+ OSSL_sleep(50);
}
} while (retc <=0 || rets <= 0);
- return 1;
+ ret = 1;
+ err:
+#ifndef OPENSSL_NO_SOCK
+ BIO_ADDR_free(peer);
+#endif
+ return ret;
}
/*
@@ -1163,7 +1352,7 @@ int create_ssl_connection(SSL *serverssl, SSL *clientssl, int want)
unsigned char buf;
size_t readbytes;
- if (!create_bare_ssl_connection(serverssl, clientssl, want, 1))
+ if (!create_bare_ssl_connection(serverssl, clientssl, want, 1, 0))
return 0;
/*
@@ -1192,6 +1381,92 @@ void shutdown_ssl_connection(SSL *serverssl, SSL *clientssl)
SSL_free(clientssl);
}
+SSL_SESSION *create_a_psk(SSL *ssl, size_t mdsize)
+{
+ const SSL_CIPHER *cipher = NULL;
+ const unsigned char key[SHA384_DIGEST_LENGTH] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+ 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
+ 0x2c, 0x2d, 0x2e, 0x2f
+ };
+ SSL_SESSION *sess = NULL;
+
+ if (mdsize == SHA384_DIGEST_LENGTH) {
+ cipher = SSL_CIPHER_find(ssl, TLS13_AES_256_GCM_SHA384_BYTES);
+ } else if (mdsize == SHA256_DIGEST_LENGTH) {
+ /*
+ * Any ciphersuite using SHA256 will do - it will be compatible with
+ * the actual ciphersuite selected as long as it too is based on SHA256
+ */
+ cipher = SSL_CIPHER_find(ssl, TLS13_AES_128_GCM_SHA256_BYTES);
+ } else {
+ /* Should not happen */
+ return NULL;
+ }
+ sess = SSL_SESSION_new();
+ if (!TEST_ptr(sess)
+ || !TEST_ptr(cipher)
+ || !TEST_true(SSL_SESSION_set1_master_key(sess, key, mdsize))
+ || !TEST_true(SSL_SESSION_set_cipher(sess, cipher))
+ || !TEST_true(
+ SSL_SESSION_set_protocol_version(sess,
+ TLS1_3_VERSION))) {
+ SSL_SESSION_free(sess);
+ return NULL;
+ }
+ return sess;
+}
+
+#define NUM_EXTRA_CERTS 40
+
+int ssl_ctx_add_large_cert_chain(OSSL_LIB_CTX *libctx, SSL_CTX *sctx,
+ const char *cert_file)
+{
+ BIO *certbio = NULL;
+ X509 *chaincert = NULL;
+ int certlen;
+ int ret = 0;
+ int i;
+
+ if (!TEST_ptr(certbio = BIO_new_file(cert_file, "r")))
+ goto end;
+
+ if (!TEST_ptr(chaincert = X509_new_ex(libctx, NULL)))
+ goto end;
+
+ if (PEM_read_bio_X509(certbio, &chaincert, NULL, NULL) == NULL)
+ goto end;
+ BIO_free(certbio);
+ certbio = NULL;
+
+ /*
+ * We assume the supplied certificate is big enough so that if we add
+ * NUM_EXTRA_CERTS it will make the overall message large enough. The
+ * default buffer size is requested to be 16k, but due to the way BUF_MEM
+ * works, it ends up allocating a little over 21k (16 * 4/3). So, in this
+ * test we need to have a message larger than that.
+ */
+ certlen = i2d_X509(chaincert, NULL);
+ OPENSSL_assert(certlen * NUM_EXTRA_CERTS >
+ (SSL3_RT_MAX_PLAIN_LENGTH * 4) / 3);
+ for (i = 0; i < NUM_EXTRA_CERTS; i++) {
+ if (!X509_up_ref(chaincert))
+ goto end;
+ if (!SSL_CTX_add_extra_chain_cert(sctx, chaincert)) {
+ X509_free(chaincert);
+ goto end;
+ }
+ }
+
+ ret = 1;
+ end:
+ BIO_free(certbio);
+ X509_free(chaincert);
+ return ret;
+}
+
ENGINE *load_dasync(void)
{
#if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_DYNAMIC_ENGINE)