Home | History | Annotate | Line # | Download | only in quic
      1 /*
      2  * Copyright 2022-2026 The OpenSSL Project Authors. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License 2.0 (the "License").  You may not use
      5  * this file except in compliance with the License.  You can obtain a copy
      6  * in the file LICENSE in the source distribution or at
      7  * https://www.openssl.org/source/license.html
      8  */
      9 
     10 #include "internal/quic_record_tx.h"
     11 #include "internal/qlog_event_helpers.h"
     12 #include "internal/bio_addr.h"
     13 #include "internal/common.h"
     14 #include "quic_record_shared.h"
     15 #include "internal/list.h"
     16 #include "../ssl_local.h"
     17 
     18 /*
     19  * TXE
     20  * ===
     21  * Encrypted packets awaiting transmission are kept in TX Entries (TXEs), which
     22  * are queued in linked lists just like TXEs.
     23  */
     24 typedef struct txe_st TXE;
     25 
     26 struct txe_st {
     27     OSSL_LIST_MEMBER(txe, TXE);
     28     size_t data_len, alloc_len;
     29 
     30     /*
     31      * Destination and local addresses, as applicable. Both of these are only
     32      * used if the family is not AF_UNSPEC.
     33      */
     34     BIO_ADDR peer, local;
     35 
     36     /*
     37      * alloc_len allocated bytes (of which data_len bytes are valid) follow this
     38      * structure.
     39      */
     40 };
     41 
     42 DEFINE_LIST_OF(txe, TXE);
     43 typedef OSSL_LIST(txe) TXE_LIST;
     44 
     45 static ossl_inline unsigned char *txe_data(const TXE *e)
     46 {
     47     return (unsigned char *)(e + 1);
     48 }
     49 
     50 /*
     51  * QTX
     52  * ===
     53  */
     54 struct ossl_qtx_st {
     55     OSSL_LIB_CTX *libctx;
     56     const char *propq;
     57 
     58     /* Per encryption-level state. */
     59     OSSL_QRL_ENC_LEVEL_SET el_set;
     60 
     61     /* TX BIO. */
     62     BIO *bio;
     63 
     64     /* QLOG instance retrieval callback if in use, or NULL. */
     65     QLOG *(*get_qlog_cb)(void *arg);
     66     void *get_qlog_cb_arg;
     67 
     68     /* TX maximum datagram payload length. */
     69     size_t mdpl;
     70 
     71     /*
     72      * List of TXEs which are not currently in use. These are moved to the
     73      * pending list (possibly via tx_cons first) as they are filled.
     74      */
     75     TXE_LIST free;
     76 
     77     /*
     78      * List of TXEs which are filled with completed datagrams ready to be
     79      * transmitted.
     80      */
     81     TXE_LIST pending;
     82     size_t pending_count; /* items in list */
     83     size_t pending_bytes; /* sum(txe->data_len) in pending */
     84 
     85     /*
     86      * TXE which is under construction for coalescing purposes, if any.
     87      * This TXE is neither on the free nor pending list. Once the datagram
     88      * is completed, it is moved to the pending list.
     89      */
     90     TXE *cons;
     91     size_t cons_count; /* num packets */
     92 
     93     /*
     94      * Number of packets transmitted in this key epoch. Used to enforce AEAD
     95      * confidentiality limit.
     96      */
     97     uint64_t epoch_pkt_count;
     98 
     99     /* Datagram counter. Increases monotonically per datagram (not per packet). */
    100     uint64_t datagram_count;
    101 
    102     ossl_mutate_packet_cb mutatecb;
    103     ossl_finish_mutate_cb finishmutatecb;
    104     void *mutatearg;
    105 
    106     /* Message callback related arguments */
    107     ossl_msg_cb msg_callback;
    108     void *msg_callback_arg;
    109     SSL *msg_callback_ssl;
    110 };
    111 
    112 /* Instantiates a new QTX. */
    113 OSSL_QTX *ossl_qtx_new(const OSSL_QTX_ARGS *args)
    114 {
    115     OSSL_QTX *qtx;
    116 
    117     if (args->mdpl < QUIC_MIN_INITIAL_DGRAM_LEN)
    118         return 0;
    119 
    120     qtx = OPENSSL_zalloc(sizeof(OSSL_QTX));
    121     if (qtx == NULL)
    122         return 0;
    123 
    124     qtx->libctx = args->libctx;
    125     qtx->propq = args->propq;
    126     qtx->bio = args->bio;
    127     qtx->mdpl = args->mdpl;
    128     qtx->get_qlog_cb = args->get_qlog_cb;
    129     qtx->get_qlog_cb_arg = args->get_qlog_cb_arg;
    130 
    131     return qtx;
    132 }
    133 
    134 static void qtx_cleanup_txl(TXE_LIST *l)
    135 {
    136     TXE *e, *enext;
    137 
    138     for (e = ossl_list_txe_head(l); e != NULL; e = enext) {
    139         enext = ossl_list_txe_next(e);
    140         OPENSSL_free(e);
    141     }
    142 }
    143 
    144 /* Frees the QTX. */
    145 void ossl_qtx_free(OSSL_QTX *qtx)
    146 {
    147     uint32_t i;
    148 
    149     if (qtx == NULL)
    150         return;
    151 
    152     /* Free TXE queue data. */
    153     qtx_cleanup_txl(&qtx->pending);
    154     qtx_cleanup_txl(&qtx->free);
    155     OPENSSL_free(qtx->cons);
    156 
    157     /* Drop keying material and crypto resources. */
    158     for (i = 0; i < QUIC_ENC_LEVEL_NUM; ++i)
    159         ossl_qrl_enc_level_set_discard(&qtx->el_set, i);
    160 
    161     OPENSSL_free(qtx);
    162 }
    163 
    164 /* Set mutator callbacks for test framework support */
    165 void ossl_qtx_set_mutator(OSSL_QTX *qtx, ossl_mutate_packet_cb mutatecb,
    166     ossl_finish_mutate_cb finishmutatecb, void *mutatearg)
    167 {
    168     qtx->mutatecb = mutatecb;
    169     qtx->finishmutatecb = finishmutatecb;
    170     qtx->mutatearg = mutatearg;
    171 }
    172 
    173 void ossl_qtx_set_qlog_cb(OSSL_QTX *qtx, QLOG *(*get_qlog_cb)(void *arg),
    174     void *get_qlog_cb_arg)
    175 {
    176     qtx->get_qlog_cb = get_qlog_cb;
    177     qtx->get_qlog_cb_arg = get_qlog_cb_arg;
    178 }
    179 
    180 int ossl_qtx_provide_secret(OSSL_QTX *qtx,
    181     uint32_t enc_level,
    182     uint32_t suite_id,
    183     EVP_MD *md,
    184     const unsigned char *secret,
    185     size_t secret_len)
    186 {
    187     if (enc_level >= QUIC_ENC_LEVEL_NUM)
    188         return 0;
    189 
    190     return ossl_qrl_enc_level_set_provide_secret(&qtx->el_set,
    191         qtx->libctx,
    192         qtx->propq,
    193         enc_level,
    194         suite_id,
    195         md,
    196         secret,
    197         secret_len,
    198         0,
    199         /*is_tx=*/1);
    200 }
    201 
    202 int ossl_qtx_discard_enc_level(OSSL_QTX *qtx, uint32_t enc_level)
    203 {
    204     if (enc_level >= QUIC_ENC_LEVEL_NUM)
    205         return 0;
    206 
    207     ossl_qrl_enc_level_set_discard(&qtx->el_set, enc_level);
    208     return 1;
    209 }
    210 
    211 int ossl_qtx_is_enc_level_provisioned(OSSL_QTX *qtx, uint32_t enc_level)
    212 {
    213     return ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1) != NULL;
    214 }
    215 
    216 /* Allocate a new TXE. */
    217 static TXE *qtx_alloc_txe(size_t alloc_len)
    218 {
    219     TXE *txe;
    220 
    221     if (alloc_len >= SIZE_MAX - sizeof(TXE))
    222         return NULL;
    223 
    224     txe = OPENSSL_malloc(sizeof(TXE) + alloc_len);
    225     if (txe == NULL)
    226         return NULL;
    227 
    228     ossl_list_txe_init_elem(txe);
    229     txe->alloc_len = alloc_len;
    230     txe->data_len = 0;
    231     return txe;
    232 }
    233 
    234 /*
    235  * Ensures there is at least one TXE in the free list, allocating a new entry
    236  * if necessary. The returned TXE is in the free list; it is not popped.
    237  *
    238  * alloc_len is a hint which may be used to determine the TXE size if allocation
    239  * is necessary. Returns NULL on allocation failure.
    240  */
    241 static TXE *qtx_ensure_free_txe(OSSL_QTX *qtx, size_t alloc_len)
    242 {
    243     TXE *txe;
    244 
    245     txe = ossl_list_txe_head(&qtx->free);
    246     if (txe != NULL)
    247         return txe;
    248 
    249     txe = qtx_alloc_txe(alloc_len);
    250     if (txe == NULL)
    251         return NULL;
    252 
    253     ossl_list_txe_insert_tail(&qtx->free, txe);
    254     return txe;
    255 }
    256 
    257 /*
    258  * Resize the data buffer attached to an TXE to be n bytes in size. The address
    259  * of the TXE might change; the new address is returned, or NULL on failure, in
    260  * which case the original TXE remains valid.
    261  */
    262 static TXE *qtx_resize_txe(OSSL_QTX *qtx, TXE *txe, size_t n)
    263 {
    264     TXE *txe2;
    265 
    266     /* Should never happen. */
    267     if (txe == NULL)
    268         return NULL;
    269 
    270     if (n >= SIZE_MAX - sizeof(TXE))
    271         return NULL;
    272 
    273     /*
    274      * to resize txe, the caller must detach it from the list first,
    275      * fail if txe is still attached.
    276      */
    277     if (!ossl_assert(ossl_list_txe_prev(txe) == NULL
    278             && ossl_list_txe_next(txe) == NULL))
    279         return NULL;
    280 
    281     /*
    282      * NOTE: We do not clear old memory, although it does contain decrypted
    283      * data.
    284      */
    285     txe2 = OPENSSL_realloc(txe, sizeof(TXE) + n);
    286     if (txe2 == NULL)
    287         return NULL;
    288 
    289     if (qtx->cons == txe)
    290         qtx->cons = txe2;
    291 
    292     txe2->alloc_len = n;
    293     return txe2;
    294 }
    295 
    296 /*
    297  * Ensure the data buffer attached to an TXE is at least n bytes in size.
    298  * Returns NULL on failure.
    299  */
    300 static TXE *qtx_reserve_txe(OSSL_QTX *qtx, TXE *txe, size_t n)
    301 {
    302     if (txe->alloc_len >= n)
    303         return txe;
    304 
    305     return qtx_resize_txe(qtx, txe, n);
    306 }
    307 
    308 /* Move a TXE from pending to free. */
    309 static void qtx_pending_to_free(OSSL_QTX *qtx)
    310 {
    311     TXE *txe = ossl_list_txe_head(&qtx->pending);
    312 
    313     assert(txe != NULL);
    314     ossl_list_txe_remove(&qtx->pending, txe);
    315     --qtx->pending_count;
    316     qtx->pending_bytes -= txe->data_len;
    317     ossl_list_txe_insert_tail(&qtx->free, txe);
    318 }
    319 
    320 /* Add a TXE not currently in any list to the pending list. */
    321 static void qtx_add_to_pending(OSSL_QTX *qtx, TXE *txe)
    322 {
    323     ossl_list_txe_insert_tail(&qtx->pending, txe);
    324     ++qtx->pending_count;
    325     qtx->pending_bytes += txe->data_len;
    326 }
    327 
    328 struct iovec_cur {
    329     const OSSL_QTX_IOVEC *iovec;
    330     size_t num_iovec, idx, byte_off, bytes_remaining;
    331 };
    332 
    333 static size_t iovec_total_bytes(const OSSL_QTX_IOVEC *iovec,
    334     size_t num_iovec)
    335 {
    336     size_t i, l = 0;
    337 
    338     for (i = 0; i < num_iovec; ++i)
    339         l += iovec[i].buf_len;
    340 
    341     return l;
    342 }
    343 
    344 static void iovec_cur_init(struct iovec_cur *cur,
    345     const OSSL_QTX_IOVEC *iovec,
    346     size_t num_iovec)
    347 {
    348     cur->iovec = iovec;
    349     cur->num_iovec = num_iovec;
    350     cur->idx = 0;
    351     cur->byte_off = 0;
    352     cur->bytes_remaining = iovec_total_bytes(iovec, num_iovec);
    353 }
    354 
    355 /*
    356  * Get an extent of bytes from the iovec cursor. *buf is set to point to the
    357  * buffer and the number of bytes in length of the buffer is returned. This
    358  * value may be less than the max_buf_len argument. If no more data is
    359  * available, returns 0.
    360  */
    361 static size_t iovec_cur_get_buffer(struct iovec_cur *cur,
    362     const unsigned char **buf,
    363     size_t max_buf_len)
    364 {
    365     size_t l;
    366 
    367     if (max_buf_len == 0) {
    368         *buf = NULL;
    369         return 0;
    370     }
    371 
    372     for (;;) {
    373         if (cur->idx >= cur->num_iovec)
    374             return 0;
    375 
    376         l = cur->iovec[cur->idx].buf_len - cur->byte_off;
    377         if (l > max_buf_len)
    378             l = max_buf_len;
    379 
    380         if (l > 0) {
    381             *buf = cur->iovec[cur->idx].buf + cur->byte_off;
    382             cur->byte_off += l;
    383             cur->bytes_remaining -= l;
    384             return l;
    385         }
    386 
    387         /*
    388          * Zero-length iovec entry or we already consumed all of it, try the
    389          * next iovec.
    390          */
    391         ++cur->idx;
    392         cur->byte_off = 0;
    393     }
    394 }
    395 
    396 /* Determines the size of the AEAD output given the input size. */
    397 int ossl_qtx_calculate_ciphertext_payload_len(OSSL_QTX *qtx, uint32_t enc_level,
    398     size_t plaintext_len,
    399     size_t *ciphertext_len)
    400 {
    401     OSSL_QRL_ENC_LEVEL *el
    402         = ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1);
    403     size_t tag_len;
    404 
    405     if (el == NULL) {
    406         *ciphertext_len = 0;
    407         return 0;
    408     }
    409 
    410     /*
    411      * We currently only support ciphers with a 1:1 mapping between plaintext
    412      * and ciphertext size, save for authentication tag.
    413      */
    414     tag_len = ossl_qrl_get_suite_cipher_tag_len(el->suite_id);
    415 
    416     *ciphertext_len = plaintext_len + tag_len;
    417     return 1;
    418 }
    419 
    420 /* Determines the size of the AEAD input given the output size. */
    421 int ossl_qtx_calculate_plaintext_payload_len(OSSL_QTX *qtx, uint32_t enc_level,
    422     size_t ciphertext_len,
    423     size_t *plaintext_len)
    424 {
    425     OSSL_QRL_ENC_LEVEL *el
    426         = ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1);
    427     size_t tag_len;
    428 
    429     if (el == NULL) {
    430         *plaintext_len = 0;
    431         return 0;
    432     }
    433 
    434     tag_len = ossl_qrl_get_suite_cipher_tag_len(el->suite_id);
    435 
    436     if (ciphertext_len <= tag_len) {
    437         *plaintext_len = 0;
    438         return 0;
    439     }
    440 
    441     *plaintext_len = ciphertext_len - tag_len;
    442     return 1;
    443 }
    444 
    445 /* Any other error (including packet being too big for MDPL). */
    446 #define QTX_FAIL_GENERIC (-1)
    447 
    448 /*
    449  * Returned where there is insufficient room in the datagram to write the
    450  * packet.
    451  */
    452 #define QTX_FAIL_INSUFFICIENT_LEN (-2)
    453 
    454 static int qtx_write_hdr(OSSL_QTX *qtx, const QUIC_PKT_HDR *hdr, TXE *txe,
    455     QUIC_PKT_HDR_PTRS *ptrs)
    456 {
    457     WPACKET wpkt;
    458     size_t l = 0;
    459     unsigned char *data = txe_data(txe) + txe->data_len;
    460 
    461     if (!WPACKET_init_static_len(&wpkt, data, txe->alloc_len - txe->data_len, 0))
    462         return 0;
    463 
    464     if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, hdr->dst_conn_id.id_len,
    465             hdr, ptrs)
    466         || !WPACKET_get_total_written(&wpkt, &l)) {
    467         WPACKET_finish(&wpkt);
    468         return 0;
    469     }
    470     WPACKET_finish(&wpkt);
    471 
    472     if (qtx->msg_callback != NULL)
    473         qtx->msg_callback(1, OSSL_QUIC1_VERSION, SSL3_RT_QUIC_PACKET, data, l,
    474             qtx->msg_callback_ssl, qtx->msg_callback_arg);
    475 
    476     txe->data_len += l;
    477 
    478     return 1;
    479 }
    480 
    481 static int qtx_encrypt_into_txe(OSSL_QTX *qtx, struct iovec_cur *cur, TXE *txe,
    482     uint32_t enc_level, QUIC_PN pn,
    483     const unsigned char *hdr, size_t hdr_len,
    484     QUIC_PKT_HDR_PTRS *ptrs)
    485 {
    486     int l = 0, l2 = 0, nonce_len;
    487     OSSL_QRL_ENC_LEVEL *el
    488         = ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1);
    489     unsigned char nonce[EVP_MAX_IV_LENGTH];
    490     size_t i;
    491     EVP_CIPHER_CTX *cctx = NULL;
    492 
    493     /* We should not have been called if we do not have key material. */
    494     if (!ossl_assert(el != NULL)) {
    495         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
    496         return 0;
    497     }
    498 
    499     /*
    500      * Have we already encrypted the maximum number of packets using the current
    501      * key?
    502      */
    503     if (el->op_count >= ossl_qrl_get_suite_max_pkt(el->suite_id)) {
    504         ERR_raise(ERR_LIB_SSL, SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED);
    505         return 0;
    506     }
    507 
    508     /*
    509      * TX key update is simpler than for RX; once we initiate a key update, we
    510      * never need the old keys, as we never deliberately send a packet with old
    511      * keys. Thus the EL always uses keyslot 0 for the TX side.
    512      */
    513     cctx = el->cctx[0];
    514     if (!ossl_assert(cctx != NULL)) {
    515         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
    516         return 0;
    517     }
    518 
    519     /* Construct nonce (nonce=IV ^ PN). */
    520     nonce_len = EVP_CIPHER_CTX_get_iv_length(cctx);
    521     if (!ossl_assert(nonce_len >= (int)sizeof(QUIC_PN))) {
    522         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
    523         return 0;
    524     }
    525 
    526     memcpy(nonce, el->iv[0], (size_t)nonce_len);
    527     for (i = 0; i < sizeof(QUIC_PN); ++i)
    528         nonce[nonce_len - i - 1] ^= (unsigned char)(pn >> (i * 8));
    529 
    530     /* type and key will already have been setup; feed the IV. */
    531     if (EVP_CipherInit_ex(cctx, NULL, NULL, NULL, nonce, /*enc=*/1) != 1) {
    532         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
    533         return 0;
    534     }
    535 
    536     /* Feed AAD data. */
    537     if (EVP_CipherUpdate(cctx, NULL, &l, hdr, hdr_len) != 1) {
    538         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
    539         return 0;
    540     }
    541 
    542     /* Encrypt plaintext directly into TXE. */
    543     for (;;) {
    544         const unsigned char *src;
    545         size_t src_len;
    546 
    547         src_len = iovec_cur_get_buffer(cur, &src, SIZE_MAX);
    548         if (src_len == 0)
    549             break;
    550 
    551         if (EVP_CipherUpdate(cctx, txe_data(txe) + txe->data_len,
    552                 &l, src, src_len)
    553             != 1) {
    554             ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
    555             return 0;
    556         }
    557 
    558 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    559         /* Ignore what we just encrypted and overwrite it with the plaintext */
    560         memcpy(txe_data(txe) + txe->data_len, src, l);
    561 #endif
    562 
    563         assert(l > 0 && src_len == (size_t)l);
    564         txe->data_len += src_len;
    565     }
    566 
    567     /* Finalise and get tag. */
    568     if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
    569         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
    570         return 0;
    571     }
    572 
    573     if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG,
    574             el->tag_len, txe_data(txe) + txe->data_len)
    575         != 1) {
    576         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
    577         return 0;
    578     }
    579 
    580     txe->data_len += el->tag_len;
    581 
    582     /* Apply header protection. */
    583     if (!ossl_quic_hdr_protector_encrypt(&el->hpr, ptrs))
    584         return 0;
    585 
    586     ++el->op_count;
    587     return 1;
    588 }
    589 
    590 /*
    591  * Append a packet to the TXE buffer, serializing and encrypting it in the
    592  * process.
    593  */
    594 static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
    595     uint32_t enc_level, QUIC_PKT_HDR *hdr,
    596     const OSSL_QTX_IOVEC *iovec, size_t num_iovec)
    597 {
    598     int ret, needs_encrypt;
    599     size_t hdr_len, pred_hdr_len, payload_len, pkt_len, space_left;
    600     size_t min_len, orig_data_len;
    601     struct iovec_cur cur;
    602     QUIC_PKT_HDR_PTRS ptrs;
    603     unsigned char *hdr_start;
    604     OSSL_QRL_ENC_LEVEL *el = NULL;
    605 
    606     /*
    607      * Determine if the packet needs encryption and the minimum conceivable
    608      * serialization length.
    609      */
    610     if (!ossl_quic_pkt_type_is_encrypted(hdr->type)) {
    611         needs_encrypt = 0;
    612         min_len = QUIC_MIN_VALID_PKT_LEN;
    613     } else {
    614         needs_encrypt = 1;
    615         min_len = QUIC_MIN_VALID_PKT_LEN_CRYPTO;
    616         el = ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1);
    617         if (!ossl_assert(el != NULL)) /* should already have been checked */
    618             return 0;
    619     }
    620 
    621     orig_data_len = txe->data_len;
    622     space_left = txe->alloc_len - txe->data_len;
    623     if (space_left < min_len) {
    624         /* Not even a possibility of it fitting. */
    625         ret = QTX_FAIL_INSUFFICIENT_LEN;
    626         goto err;
    627     }
    628 
    629     /* Set some fields in the header we are responsible for. */
    630     if (hdr->type == QUIC_PKT_TYPE_1RTT)
    631         hdr->key_phase = (unsigned char)(el->key_epoch & 1);
    632 
    633     /* Walk the iovecs to determine actual input payload length. */
    634     iovec_cur_init(&cur, iovec, num_iovec);
    635 
    636     if (cur.bytes_remaining == 0) {
    637         /* No zero-length payloads allowed. */
    638         ret = QTX_FAIL_GENERIC;
    639         goto err;
    640     }
    641 
    642     /* Determine encrypted payload length. */
    643     if (needs_encrypt)
    644         ossl_qtx_calculate_ciphertext_payload_len(qtx, enc_level,
    645             cur.bytes_remaining,
    646             &payload_len);
    647     else
    648         payload_len = cur.bytes_remaining;
    649 
    650     /* Determine header length. */
    651     hdr->data = NULL;
    652     hdr->len = payload_len;
    653     pred_hdr_len = ossl_quic_wire_get_encoded_pkt_hdr_len(hdr->dst_conn_id.id_len,
    654         hdr);
    655     if (pred_hdr_len == 0) {
    656         ret = QTX_FAIL_GENERIC;
    657         goto err;
    658     }
    659 
    660     /* We now definitively know our packet length. */
    661     pkt_len = pred_hdr_len + payload_len;
    662 
    663     if (pkt_len > space_left) {
    664         ret = QTX_FAIL_INSUFFICIENT_LEN;
    665         goto err;
    666     }
    667 
    668     if (ossl_quic_pkt_type_has_pn(hdr->type)) {
    669         if (!ossl_quic_wire_encode_pkt_hdr_pn(pkt->pn,
    670                 hdr->pn,
    671                 hdr->pn_len)) {
    672             ret = QTX_FAIL_GENERIC;
    673             goto err;
    674         }
    675     }
    676 
    677     /* Append the header to the TXE. */
    678     hdr_start = txe_data(txe) + txe->data_len;
    679     if (!qtx_write_hdr(qtx, hdr, txe, &ptrs)) {
    680         ret = QTX_FAIL_GENERIC;
    681         goto err;
    682     }
    683 
    684     hdr_len = (txe_data(txe) + txe->data_len) - hdr_start;
    685     assert(hdr_len == pred_hdr_len);
    686 
    687     if (!needs_encrypt) {
    688         /* Just copy the payload across. */
    689         const unsigned char *src;
    690         size_t src_len;
    691 
    692         for (;;) {
    693             /* Buffer length has already been checked above. */
    694             src_len = iovec_cur_get_buffer(&cur, &src, SIZE_MAX);
    695             if (src_len == 0)
    696                 break;
    697 
    698             memcpy(txe_data(txe) + txe->data_len, src, src_len);
    699             txe->data_len += src_len;
    700         }
    701     } else {
    702         /* Encrypt into TXE. */
    703         if (!qtx_encrypt_into_txe(qtx, &cur, txe, enc_level, pkt->pn,
    704                 hdr_start, hdr_len, &ptrs)) {
    705             ret = QTX_FAIL_GENERIC;
    706             goto err;
    707         }
    708 
    709         assert(txe->data_len - orig_data_len == pkt_len);
    710     }
    711 
    712     return 1;
    713 
    714 err:
    715     /*
    716      * Restore original length so we don't leave a half-written packet in the
    717      * TXE.
    718      */
    719     txe->data_len = orig_data_len;
    720     return ret;
    721 }
    722 
    723 static TXE *qtx_ensure_cons(OSSL_QTX *qtx)
    724 {
    725     TXE *txe = qtx->cons;
    726 
    727     if (txe != NULL)
    728         return txe;
    729 
    730     txe = qtx_ensure_free_txe(qtx, qtx->mdpl);
    731     if (txe == NULL)
    732         return NULL;
    733 
    734     ossl_list_txe_remove(&qtx->free, txe);
    735     qtx->cons = txe;
    736     qtx->cons_count = 0;
    737     txe->data_len = 0;
    738     return txe;
    739 }
    740 
    741 static QLOG *qtx_get_qlog(OSSL_QTX *qtx)
    742 {
    743     if (qtx->get_qlog_cb == NULL)
    744         return NULL;
    745 
    746     return qtx->get_qlog_cb(qtx->get_qlog_cb_arg);
    747 }
    748 
    749 static int qtx_mutate_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
    750     uint32_t enc_level)
    751 {
    752     int ret;
    753     QUIC_PKT_HDR *hdr;
    754     const OSSL_QTX_IOVEC *iovec;
    755     size_t num_iovec;
    756 
    757     /* If we are running tests then mutate_packet may be non NULL */
    758     if (qtx->mutatecb != NULL) {
    759         if (!qtx->mutatecb(pkt->hdr, pkt->iovec, pkt->num_iovec, &hdr,
    760                 &iovec, &num_iovec, qtx->mutatearg))
    761             return QTX_FAIL_GENERIC;
    762     } else {
    763         hdr = pkt->hdr;
    764         iovec = pkt->iovec;
    765         num_iovec = pkt->num_iovec;
    766     }
    767 
    768     ret = qtx_write(qtx, pkt, txe, enc_level,
    769         hdr, iovec, num_iovec);
    770     if (ret == 1)
    771         ossl_qlog_event_transport_packet_sent(qtx_get_qlog(qtx), hdr, pkt->pn,
    772             iovec, num_iovec,
    773             qtx->datagram_count);
    774 
    775     if (qtx->finishmutatecb != NULL)
    776         qtx->finishmutatecb(qtx->mutatearg);
    777 
    778     return ret;
    779 }
    780 
    781 static int addr_eq(const BIO_ADDR *a, const BIO_ADDR *b)
    782 {
    783     return ((a == NULL || BIO_ADDR_family(a) == AF_UNSPEC)
    784                && (b == NULL || BIO_ADDR_family(b) == AF_UNSPEC))
    785         || (a != NULL && b != NULL && memcmp(a, b, sizeof(*a)) == 0);
    786 }
    787 
    788 int ossl_qtx_write_pkt(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt)
    789 {
    790     int ret;
    791     int coalescing = (pkt->flags & OSSL_QTX_PKT_FLAG_COALESCE) != 0;
    792     int was_coalescing;
    793     TXE *txe;
    794     uint32_t enc_level;
    795 
    796     /* Must have EL configured, must have header. */
    797     if (pkt->hdr == NULL)
    798         return 0;
    799 
    800     enc_level = ossl_quic_pkt_type_to_enc_level(pkt->hdr->type);
    801 
    802     /* Some packet types must be in a packet all by themselves. */
    803     if (!ossl_quic_pkt_type_can_share_dgram(pkt->hdr->type))
    804         ossl_qtx_finish_dgram(qtx);
    805     else if (enc_level >= QUIC_ENC_LEVEL_NUM
    806         || ossl_qrl_enc_level_set_have_el(&qtx->el_set, enc_level) != 1) {
    807         /* All other packet types are encrypted. */
    808         return 0;
    809     }
    810 
    811     was_coalescing = (qtx->cons != NULL && qtx->cons->data_len > 0);
    812     if (was_coalescing)
    813         if (!addr_eq(&qtx->cons->peer, pkt->peer)
    814             || !addr_eq(&qtx->cons->local, pkt->local)) {
    815             /* Must stop coalescing if addresses have changed */
    816             ossl_qtx_finish_dgram(qtx);
    817             was_coalescing = 0;
    818         }
    819 
    820     for (;;) {
    821         /*
    822          * Start a new coalescing session or continue using the existing one and
    823          * serialize/encrypt the packet. We always encrypt packets as soon as
    824          * our caller gives them to us, which relieves the caller of any need to
    825          * keep the plaintext around.
    826          *
    827          * the txe can have three distinct states:
    828          *	- attached to free list
    829          *	- attached to tx list
    830          *	- detached.
    831          *
    832          * if txe is detached (not member of free/tx list), then it is kept
    833          * in qtx->cons. The qtx_ensure_cons() here either returns the txe
    834          * from free list or existing ->cons txe. The txe we obtain here
    835          * is detached.
    836          */
    837         txe = qtx_ensure_cons(qtx);
    838         if (txe == NULL)
    839             return 0; /* allocation failure */
    840 
    841         /*
    842          * Ensure TXE has at least MDPL bytes allocated. This should only be
    843          * possible if the MDPL has increased.
    844          */
    845         txe = qtx_reserve_txe(qtx, txe, qtx->mdpl);
    846         if (txe == NULL) {
    847             /*
    848              * realloc of txe failed. however it is still kept in ->cons,
    849              * no memory leak.
    850              * The question is what we should do here to handle error,
    851              * is doing `return 0` enough? or shall we discard ->cons and
    852              * put it back to free list?
    853              * or just stop coalescing the packet and dispatch it to network
    854              * right now so the next packet tx can start from fresh?
    855              * I think this is the problem for another day.
    856              */
    857             return 0;
    858         }
    859 
    860         if (!was_coalescing) {
    861             /* Set addresses in TXE. */
    862             if (pkt->peer != NULL) {
    863                 if (!BIO_ADDR_copy(&txe->peer, pkt->peer))
    864                     return 0;
    865             } else {
    866                 BIO_ADDR_clear(&txe->peer);
    867             }
    868 
    869             if (pkt->local != NULL) {
    870                 if (!BIO_ADDR_copy(&txe->local, pkt->local))
    871                     return 0;
    872             } else {
    873                 BIO_ADDR_clear(&txe->local);
    874             }
    875         }
    876 
    877         ret = qtx_mutate_write(qtx, pkt, txe, enc_level);
    878         if (ret == 1) {
    879             break;
    880         } else if (ret == QTX_FAIL_INSUFFICIENT_LEN) {
    881             if (was_coalescing) {
    882                 /*
    883                  * We failed due to insufficient length, so end the current
    884                  * datagram and try again.
    885                  *
    886                  * the ossl_qtx_finish_dgram() also puts the txe (-.cons) to
    887                  * tx list, so ->cons becomes attached again. The function also
    888                  * sets ->cons to NULL so the next loop iteration starts with
    889                  * fresh txe (which is also safe to resize).
    890                  */
    891                 ossl_qtx_finish_dgram(qtx);
    892                 was_coalescing = 0;
    893             } else {
    894                 /*
    895                  * We failed due to insufficient length, but we were not
    896                  * coalescing/started with an empty datagram, so any future
    897                  * attempt to write this packet must also fail.
    898                  */
    899                 return 0;
    900             }
    901         } else {
    902             return 0; /* other error */
    903         }
    904     }
    905 
    906     ++qtx->cons_count;
    907 
    908     /*
    909      * Some packet types cannot have another packet come after them.
    910      */
    911     if (ossl_quic_pkt_type_must_be_last(pkt->hdr->type))
    912         coalescing = 0;
    913 
    914     if (!coalescing)
    915         ossl_qtx_finish_dgram(qtx);
    916 
    917     return 1;
    918 }
    919 
    920 /*
    921  * Finish any incomplete datagrams for transmission which were flagged for
    922  * coalescing. If there is no current coalescing datagram, this is a no-op.
    923  */
    924 void ossl_qtx_finish_dgram(OSSL_QTX *qtx)
    925 {
    926     TXE *txe = qtx->cons;
    927 
    928     if (txe == NULL)
    929         return;
    930 
    931     if (txe->data_len == 0)
    932         /*
    933          * If we did not put anything in the datagram, just move it back to the
    934          * free list.
    935          */
    936         ossl_list_txe_insert_tail(&qtx->free, txe);
    937     else
    938         qtx_add_to_pending(qtx, txe);
    939 
    940     qtx->cons = NULL;
    941     qtx->cons_count = 0;
    942     ++qtx->datagram_count;
    943 }
    944 
    945 static void txe_to_msg(TXE *txe, BIO_MSG *msg)
    946 {
    947     msg->data = txe_data(txe);
    948     msg->data_len = txe->data_len;
    949     msg->flags = 0;
    950     msg->peer
    951         = BIO_ADDR_family(&txe->peer) != AF_UNSPEC ? &txe->peer : NULL;
    952     msg->local
    953         = BIO_ADDR_family(&txe->local) != AF_UNSPEC ? &txe->local : NULL;
    954 }
    955 
    956 #define MAX_MSGS_PER_SEND 32
    957 
    958 int ossl_qtx_flush_net(OSSL_QTX *qtx)
    959 {
    960     BIO_MSG msg[MAX_MSGS_PER_SEND];
    961     size_t wr, i, total_written = 0;
    962     TXE *txe;
    963     int res;
    964 
    965     if (ossl_list_txe_head(&qtx->pending) == NULL)
    966         return QTX_FLUSH_NET_RES_OK; /* Nothing to send. */
    967 
    968     if (qtx->bio == NULL)
    969         return QTX_FLUSH_NET_RES_PERMANENT_FAIL;
    970 
    971     for (;;) {
    972         for (txe = ossl_list_txe_head(&qtx->pending), i = 0;
    973             txe != NULL && i < OSSL_NELEM(msg);
    974             txe = ossl_list_txe_next(txe), ++i)
    975             txe_to_msg(txe, &msg[i]);
    976 
    977         if (!i)
    978             /* Nothing to send. */
    979             break;
    980 
    981         ERR_set_mark();
    982         res = BIO_sendmmsg(qtx->bio, msg, sizeof(BIO_MSG), i, 0, &wr);
    983         if (res && wr == 0) {
    984             /*
    985              * Treat 0 messages sent as a transient error and just stop for now.
    986              */
    987             ERR_clear_last_mark();
    988             break;
    989         } else if (!res) {
    990             /*
    991              * We did not get anything, so further calls will probably not
    992              * succeed either.
    993              */
    994             if (BIO_err_is_non_fatal(ERR_peek_last_error())) {
    995                 /* Transient error, just stop for now, clearing the error. */
    996                 ERR_pop_to_mark();
    997                 break;
    998             } else {
    999                 /* Non-transient error, fail and do not clear the error. */
   1000                 ERR_clear_last_mark();
   1001                 return QTX_FLUSH_NET_RES_PERMANENT_FAIL;
   1002             }
   1003         }
   1004 
   1005         ERR_clear_last_mark();
   1006 
   1007         /*
   1008          * Remove everything which was successfully sent from the pending queue.
   1009          */
   1010         for (i = 0; i < wr; ++i) {
   1011             if (qtx->msg_callback != NULL)
   1012                 qtx->msg_callback(1, OSSL_QUIC1_VERSION, SSL3_RT_QUIC_DATAGRAM,
   1013                     msg[i].data, msg[i].data_len,
   1014                     qtx->msg_callback_ssl,
   1015                     qtx->msg_callback_arg);
   1016             qtx_pending_to_free(qtx);
   1017         }
   1018 
   1019         total_written += wr;
   1020     }
   1021 
   1022     return total_written > 0
   1023         ? QTX_FLUSH_NET_RES_OK
   1024         : QTX_FLUSH_NET_RES_TRANSIENT_FAIL;
   1025 }
   1026 
   1027 int ossl_qtx_pop_net(OSSL_QTX *qtx, BIO_MSG *msg)
   1028 {
   1029     TXE *txe = ossl_list_txe_head(&qtx->pending);
   1030 
   1031     if (txe == NULL)
   1032         return 0;
   1033 
   1034     txe_to_msg(txe, msg);
   1035     qtx_pending_to_free(qtx);
   1036     return 1;
   1037 }
   1038 
   1039 void ossl_qtx_set_bio(OSSL_QTX *qtx, BIO *bio)
   1040 {
   1041     qtx->bio = bio;
   1042 }
   1043 
   1044 int ossl_qtx_set_mdpl(OSSL_QTX *qtx, size_t mdpl)
   1045 {
   1046     if (mdpl < QUIC_MIN_INITIAL_DGRAM_LEN)
   1047         return 0;
   1048 
   1049     qtx->mdpl = mdpl;
   1050     return 1;
   1051 }
   1052 
   1053 size_t ossl_qtx_get_mdpl(OSSL_QTX *qtx)
   1054 {
   1055     return qtx->mdpl;
   1056 }
   1057 
   1058 size_t ossl_qtx_get_queue_len_datagrams(OSSL_QTX *qtx)
   1059 {
   1060     return qtx->pending_count;
   1061 }
   1062 
   1063 size_t ossl_qtx_get_queue_len_bytes(OSSL_QTX *qtx)
   1064 {
   1065     return qtx->pending_bytes;
   1066 }
   1067 
   1068 size_t ossl_qtx_get_cur_dgram_len_bytes(OSSL_QTX *qtx)
   1069 {
   1070     return qtx->cons != NULL ? qtx->cons->data_len : 0;
   1071 }
   1072 
   1073 size_t ossl_qtx_get_unflushed_pkt_count(OSSL_QTX *qtx)
   1074 {
   1075     return qtx->cons_count;
   1076 }
   1077 
   1078 int ossl_qtx_trigger_key_update(OSSL_QTX *qtx)
   1079 {
   1080     return ossl_qrl_enc_level_set_key_update(&qtx->el_set,
   1081         QUIC_ENC_LEVEL_1RTT);
   1082 }
   1083 
   1084 uint64_t ossl_qtx_get_cur_epoch_pkt_count(OSSL_QTX *qtx, uint32_t enc_level)
   1085 {
   1086     OSSL_QRL_ENC_LEVEL *el;
   1087 
   1088     el = ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1);
   1089     if (el == NULL)
   1090         return UINT64_MAX;
   1091 
   1092     return el->op_count;
   1093 }
   1094 
   1095 uint64_t ossl_qtx_get_max_epoch_pkt_count(OSSL_QTX *qtx, uint32_t enc_level)
   1096 {
   1097     OSSL_QRL_ENC_LEVEL *el;
   1098 
   1099     el = ossl_qrl_enc_level_set_get(&qtx->el_set, enc_level, 1);
   1100     if (el == NULL)
   1101         return UINT64_MAX;
   1102 
   1103     return ossl_qrl_get_suite_max_pkt(el->suite_id);
   1104 }
   1105 
   1106 void ossl_qtx_set_msg_callback(OSSL_QTX *qtx, ossl_msg_cb msg_callback,
   1107     SSL *msg_callback_ssl)
   1108 {
   1109     qtx->msg_callback = msg_callback;
   1110     qtx->msg_callback_ssl = msg_callback_ssl;
   1111 }
   1112 
   1113 void ossl_qtx_set_msg_callback_arg(OSSL_QTX *qtx, void *msg_callback_arg)
   1114 {
   1115     qtx->msg_callback_arg = msg_callback_arg;
   1116 }
   1117 
   1118 uint64_t ossl_qtx_get_key_epoch(OSSL_QTX *qtx)
   1119 {
   1120     OSSL_QRL_ENC_LEVEL *el;
   1121 
   1122     el = ossl_qrl_enc_level_set_get(&qtx->el_set, QUIC_ENC_LEVEL_1RTT, 1);
   1123     if (el == NULL)
   1124         return 0;
   1125 
   1126     return el->key_epoch;
   1127 }
   1128