/*
* Copyright 2022 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
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#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"
#include "internal/packet.h"
#define GROWTH_ALLOWANCE 1024
struct qtest_fault {
QUIC_TSERVER *qtserv;
/* Plain packet mutations */
/* Header for the plaintext packet */
QUIC_PKT_HDR pplainhdr;
/* iovec for the plaintext packet data buffer */
OSSL_QTX_IOVEC pplainio;
/* Allocated size of the plaintext packet data buffer */
size_t pplainbuf_alloc;
qtest_fault_on_packet_plain_cb pplaincb;
void *pplaincbarg;
/* Handshake message mutations */
/* Handshake message buffer */
unsigned char *handbuf;
/* Allocated size of the handshake message buffer */
size_t handbufalloc;
/* Actual length of the handshake message */
size_t handbuflen;
qtest_fault_on_handshake_cb handshakecb;
void *handshakecbarg;
qtest_fault_on_enc_ext_cb encextcb;
void *encextcbarg;
/* Cipher packet mutations */
qtest_fault_on_packet_cipher_cb pciphercb;
void *pciphercbarg;
/* Datagram mutations */
qtest_fault_on_datagram_cb datagramcb;
void *datagramcbarg;
/* The currently processed message */
BIO_MSG msg;
/* Allocated size of msg data buffer */
size_t msgalloc;
};
static void packet_plain_finish(void *arg);
static void handshake_finish(void *arg);
static BIO_METHOD *get_bio_method(void);
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 */
unsigned char alpn[] = { 8, 'o', 's', 's', 'l', 't', 'e', 's', 't' };
QUIC_TSERVER_ARGS tserver_args = {0};
BIO *cbio = NULL, *sbio = NULL, *fisbio = NULL;
BIO_ADDR *peeraddr = NULL;
struct in_addr ina = {0};
*qtserv = NULL;
if (fault != NULL)
*fault = NULL;
*cssl = SSL_new(clientctx);
if (!TEST_ptr(*cssl))
return 0;
/* SSL_set_alpn_protos returns 0 for success! */
if (!TEST_false(SSL_set_alpn_protos(*cssl, alpn, sizeof(alpn))))
goto err;
if (!TEST_ptr(peeraddr = BIO_ADDR_new()))
goto err;
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;
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;
/* 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);
if (!TEST_true(SSL_set_blocking_mode(*cssl, block)))
goto err;
if (!TEST_true(SSL_set_initial_peer_addr(*cssl, peeraddr)))
goto err;
if (fault != NULL) {
*fault = OPENSSL_zalloc(sizeof(**fault));
if (*fault == NULL)
goto err;
}
fisbio = BIO_new(get_bio_method());
if (!TEST_ptr(fisbio))
goto err;
BIO_set_data(fisbio, fault == NULL ? NULL : *fault);
if (!TEST_ptr(BIO_push(fisbio, sbio)))
goto err;
tserver_args.libctx = libctx;
tserver_args.net_rbio = sbio;
tserver_args.net_wbio = fisbio;
if (!TEST_ptr(*qtserv = ossl_quic_tserver_new(&tserver_args, certfile,
keyfile)))
goto err;
/* Ownership of fisbio and sbio is now held by *qtserv */
sbio = NULL;