diff options
Diffstat (limited to 'test/helpers/ssltestlib.c')
-rw-r--r-- | test/helpers/ssltestlib.c | 375 |
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) |