/*
* Copyright 2022-2023 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 "internal/quic_record_tx.h"
#include "internal/bio_addr.h"
#include "internal/common.h"
#include "quic_record_shared.h"
#include "internal/list.h"
#include "../ssl_local.h"
/*
* TXE
* ===
* Encrypted packets awaiting transmission are kept in TX Entries (TXEs), which
* are queued in linked lists just like TXEs.
*/
typedef struct txe_st TXE;
struct txe_st {
OSSL_LIST_MEMBER(txe, TXE);
size_t data_len, alloc_len;
/*
* Destination and local addresses, as applicable. Both of these are only
* used if the family is not AF_UNSPEC.
*/
BIO_ADDR peer, local;
/*
* alloc_len allocated bytes (of which data_len bytes are valid) follow this
* structure.
*/
};
DEFINE_LIST_OF(txe, TXE);
typedef OSSL_LIST(txe) TXE_LIST;
static ossl_inline unsigned char *txe_data(const TXE *e)
{
return (unsigned char *)(e + 1);
}
/*
* QTX
* ===
*/
struct ossl_qtx_st {
OSSL_LIB_CTX *libctx;
const char *propq;
/* Per encryption-level state. */
OSSL_QRL_ENC_LEVEL_SET el_set;
/* TX BIO. */
BIO *bio;
/* TX maximum datagram payload length. */
size_t mdpl;
/*
* List of TXEs which are not currently in use. These are moved to the
* pending list (possibly via tx_cons first) as they are filled.
*/
TXE_LIST free;
/*
* List of TXEs which are filled with completed datagrams ready to be
* transmitted.
*/
TXE_LIST pending;
size_t pending_count; /* items in list */
size_t pending_bytes; /* sum(txe->data_len) in pending */
/*
* TXE which is under construction for coalescing purposes, if any.
* This TXE is neither on the free nor pending list. Once the datagram
* is completed, it is moved to the pending list.
*/
TXE *cons;
size_t cons_count; /* num packets */
/*
* Number of packets transmitted in this key epoch. Used to enforce AEAD
* confidentiality limit.
*/
uint64_t epoch_pkt_count;
ossl_mutate_packet_cb mutatecb;
ossl_finish_mutate_cb finishmutatecb;
void *mutatearg;
/* Message callback related arguments */
ossl_msg_cb msg_callback;
void *msg_callback_arg;
SSL *msg_callback_ssl;
};
/* Instantiates a new QTX. */
OSSL_QTX *ossl_qtx_new(const OSSL_QTX_ARGS *args)
{
OSSL_QTX *qtx;
if (args->mdpl < QUIC_MIN_INITIAL_DGRAM_LEN)
return 0;
qtx = OPENSSL_zalloc(sizeof(OSSL_QTX));
if (qtx == NULL)
return 0;
qtx->libctx = args->libctx;
qtx->propq = args->propq;
qtx->bio = args->bio;
qtx->mdpl = args->mdpl;
return qtx;
}
static void qtx_cleanup_txl(TXE_LIST *l)
{
TXE *e, *enext;
for (e = ossl_list_txe_head(l); e != NULL; e = enext) {
enext = ossl_list_txe_next(e);
OPENSSL_free(e);
}
}
/* Frees the QTX. */
void ossl_qtx_free(OSSL_QTX *qtx)
{
uint32_t i;
if (qtx == NULL)
return;
/* Free TXE queue data. */
qtx_cleanup_txl(&qtx->pending);
qtx_cleanup_txl(&qtx->free);
OPENSSL_free(qtx->cons);
/* Drop keying material and crypto resources. */
for (i = 0; i < QUIC_ENC_LEVEL_NUM; ++i)
ossl_qrl_enc_level_set_discard(&qtx->el_set, i);
OPENSSL_free(qtx);
}
/* Set mutator callbacks for test framework support */
void ossl_qtx_set_mutator(OSSL_QTX *qtx, ossl_mutate_packet_cb mutatecb,
ossl_finish_mutate_cb finishmutatecb, void *mutatearg)
{
qtx->mutatecb = mutatecb;
qtx->finishmutatecb = finishmutatecb;
qtx->mutatearg = mutatearg;
}
int ossl_qtx_provide_secret(OSSL_QTX *qtx,
uint32_t enc_level,
uint32_t suite_id,