#include <openssl/ssl.h>
#include "internal/quic_record_rx.h"
#include "quic_record_shared.h"
#include "internal/common.h"
#include "internal/list.h"
#include "../ssl_local.h"
static ossl_inline void pkt_mark(uint64_t *bitf, size_t pkt_idx)
{
assert(pkt_idx < QUIC_MAX_PKT_PER_URXE);
*bitf |= ((uint64_t)1) << pkt_idx;
}
static ossl_inline int pkt_is_marked(const uint64_t *bitf, size_t pkt_idx)
{
assert(pkt_idx < QUIC_MAX_PKT_PER_URXE);
return (*bitf & (((uint64_t)1) << pkt_idx)) != 0;
}
typedef struct rxe_st RXE;
struct rxe_st {
OSSL_QRX_PKT pkt;
OSSL_LIST_MEMBER(rxe, RXE);
size_t data_len, alloc_len, refcount;
QUIC_PKT_HDR hdr;
QUIC_PN pn;
BIO_ADDR peer, local;
OSSL_TIME time;
size_t datagram_len;
uint64_t key_epoch;
uint64_t datagram_id;
};
DEFINE_LIST_OF(rxe, RXE);
typedef OSSL_LIST(rxe) RXE_LIST;
static ossl_inline unsigned char *rxe_data(const RXE *e)
{
return (unsigned char *)(e + 1);
}
struct ossl_qrx_st {
OSSL_LIB_CTX *libctx;
const char *propq;
QUIC_DEMUX *demux;
size_t short_conn_id_len;
size_t max_deferred;
size_t num_deferred;
QUIC_URXE_LIST urx_pending;
QUIC_URXE_LIST urx_deferred;
RXE_LIST rx_free;
RXE_LIST rx_pending;
QUIC_PN largest_pn[QUIC_PN_SPACE_NUM];
OSSL_QRL_ENC_LEVEL_SET el_set;
uint64_t bytes_received;
uint64_t forged_pkt_count;
uint64_t cur_epoch_start_pn;
ossl_qrx_late_validation_cb *validation_cb;
void *validation_cb_arg;
ossl_qrx_key_update_cb *key_update_cb;
void *key_update_cb_arg;
unsigned char init_key_phase_bit;
unsigned char allow_1rtt;
ossl_msg_cb msg_callback;
void *msg_callback_arg;
SSL *msg_callback_ssl;
};
static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len);
static int qrx_validate_hdr_early(OSSL_QRX *qrx, RXE *rxe,
const QUIC_CONN_ID *first_dcid);
static int qrx_relocate_buffer(OSSL_QRX *qrx, RXE **prxe, size_t *pi,
const unsigned char **pptr, size_t buf_len);
static int qrx_validate_hdr(OSSL_QRX *qrx, RXE *rxe);
static RXE *qrx_reserve_rxe(RXE_LIST *rxl, RXE *rxe, size_t n);
static int qrx_decrypt_pkt_body(OSSL_QRX *qrx, unsigned char *dst,
const unsigned char *src,
size_t src_len, size_t *dec_len,
const unsigned char *aad, size_t aad_len,
QUIC_PN pn, uint32_t enc_level,
unsigned char key_phase_bit,
uint64_t *rx_key_epoch);
static int qrx_validate_hdr_late(OSSL_QRX *qrx, RXE *rxe);
static uint32_t rxe_determine_pn_space(RXE *rxe);
static void ignore_res(int x);
OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args)
{
OSSL_QRX *qrx;
size_t i;
if (args->demux == NULL || args->max_deferred == 0)
return NULL;
qrx = OPENSSL_zalloc(sizeof(OSSL_QRX));
if (qrx == NULL)
return NULL;
for (i = 0; i < OSSL_NELEM(qrx->largest_pn); ++i)
qrx->largest_pn[i] = args->init_largest_pn[i];
qrx->libctx = args->libctx;
qrx->propq = args->propq;
qrx->demux = args->demux;
qrx->short_conn_id_len = args->short_conn_id_len;
qrx->init_key_phase_bit = args->init_key_phase_bit;
qrx->max_deferred = args->max_deferred;
return qrx;
}
static void qrx_cleanup_rxl(RXE_LIST *l)
{
RXE *e, *enext;
for (e = ossl_list_rxe_head(l); e != NULL; e = enext) {
enext = ossl_list_rxe_next(e);
ossl_list_rxe_remove(l, e);
OPENSSL_free(e);
}
}
static void qrx_cleanup_urxl(OSSL_QRX *qrx, QUIC_URXE_LIST *l)
{
QUIC_URXE *e, *enext;
for (e = ossl_list_urxe_head(l); e != NULL; e = enext) {
enext = ossl_list_urxe_next(e);
ossl_list_urxe_remove(l, e);
ossl_quic_demux_release_urxe(qrx->demux, e);
}
}
void ossl_qrx_update_pn_space(OSSL_QRX *src, OSSL_QRX *dst)
{
size_t i;
for (i = 0; i < QUIC_PN_SPACE_NUM; i++)
dst->largest_pn[i] = src->largest_pn[i];
return;
}
void ossl_qrx_free(OSSL_QRX *qrx)
{
uint32_t i;
if (qrx == NULL)
return;
qrx_cleanup_rxl(&qrx->rx_free);
qrx_cleanup_rxl(&qrx->rx_pending);
qrx_cleanup_urxl(qrx, &qrx->urx_pending);
qrx_cleanup_urxl(qrx, &qrx->urx_deferred);
for (i = 0; i < QUIC_ENC_LEVEL_NUM; ++i)
ossl_qrl_enc_level_set_discard(&qrx->el_set, i);
OPENSSL_free(qrx);
}
void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe)
{
urxe->processed = 0;
urxe->hpr_removed = 0;
urxe->deferred = 0;
ossl_list_urxe_insert_tail(&qrx->urx_pending, urxe);
if (qrx->msg_callback != NULL)
qrx->msg_callback(0, OSSL_QUIC1_VERSION, SSL3_RT_QUIC_DATAGRAM, urxe + 1,
urxe->data_len, qrx->msg_callback_ssl,
qrx->msg_callback_arg);
}
void ossl_qrx_inject_pkt(OSSL_QRX *qrx, OSSL_QRX_PKT *pkt)
{
RXE *rxe = (RXE *)pkt;
ossl_qrx_pkt_orphan(pkt);
if (ossl_assert(rxe->refcount == 0))
ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
}
static int qrx_validate_initial_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe,
const QUIC_CONN_ID *first_dcid,
size_t datagram_len)
{
PACKET pkt, orig_pkt;
RXE *rxe;
size_t i = 0, aad_len = 0, dec_len = 0;
const unsigned char *sop;
unsigned char *dst;
QUIC_PKT_HDR_PTRS ptrs;
uint32_t pn_space;
OSSL_QRL_ENC_LEVEL *el = NULL;
uint64_t rx_key_epoch = UINT64_MAX;
if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(urxe), urxe->data_len))
return 0;
orig_pkt = pkt;
sop = PACKET_data(&pkt);
rxe = qrx_ensure_free_rxe(qrx, PACKET_remaining(&pkt));
if (rxe == NULL)
return 0;
if (!ossl_quic_wire_decode_pkt_hdr(&pkt,
0,
1,
0,
&rxe->hdr, &ptrs,
NULL))
goto malformed;
if (rxe->hdr.type != QUIC_PKT_TYPE_INITIAL)
goto malformed;
if (!qrx_validate_hdr_early(qrx, rxe, NULL))
goto malformed;
if (ossl_qrl_enc_level_set_have_el(&qrx->el_set, QUIC_ENC_LEVEL_INITIAL) != 1)
goto malformed;
if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) {
const unsigned char *token = rxe->hdr.token;
if (!qrx_relocate_buffer(qrx, &rxe, &i, &token, rxe->hdr.token_len))
goto malformed;
rxe->hdr.token = token;
}
pkt = orig_pkt;
el = ossl_qrl_enc_level_set_get(&qrx->el_set, QUIC_ENC_LEVEL_INITIAL, 1);
assert(el != NULL);
if (!ossl_quic_hdr_protector_decrypt(&el->hpr, &ptrs))
goto malformed;
pkt_mark(&urxe->hpr_removed, 0);
if (ossl_quic_wire_decode_pkt_hdr(&pkt, 0,
0, 0, &rxe->hdr, NULL, NULL)
!= 1)
goto malformed;
if (!qrx_validate_hdr(qrx, rxe))
goto malformed;
aad_len = rxe->hdr.data - sop;
if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len + i)) == NULL)
goto malformed;
dst = (unsigned char *)rxe_data(rxe) + i;
if (!qrx_decrypt_pkt_body(qrx, dst, rxe->hdr.data, rxe->hdr.len,
&dec_len, sop, aad_len, rxe->pn, QUIC_ENC_LEVEL_INITIAL,
rxe->hdr.key_phase, &rx_key_epoch))
goto malformed;
if (!qrx_validate_hdr_late(qrx, rxe))
goto malformed;
pkt_mark(&urxe->processed, 0);
rxe->hdr.data = dst;
rxe->hdr.len = dec_len;
rxe->data_len = dec_len;
rxe->datagram_len = datagram_len;
rxe->key_epoch = rx_key_epoch;
pn_space = rxe_determine_pn_space(rxe);
if (rxe->pn > qrx->largest_pn[pn_space])
qrx->largest_pn[pn_space] = rxe->pn;
rxe->peer = urxe->peer;
rxe->local = urxe->local;
rxe->time = urxe->time;
rxe->datagram_id = urxe->datagram_id;
ossl_list_rxe_remove(&qrx->rx_free, rxe);
ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
return 1;
malformed:
return 0;
}
int ossl_qrx_validate_initial_packet(OSSL_QRX *qrx, QUIC_URXE *urxe,
const QUIC_CONN_ID *dcid)
{
urxe->processed = 0;
urxe->hpr_removed = 0;
urxe->deferred = 0;
return qrx_validate_initial_pkt(qrx, urxe, dcid, urxe->data_len);
}
static void qrx_requeue_deferred(OSSL_QRX *qrx)
{
QUIC_URXE *e;
while ((e = ossl_list_urxe_head(&qrx->urx_deferred)) != NULL) {
ossl_list_urxe_remove(&qrx->urx_deferred, e);
ossl_list_urxe_insert_tail(&qrx->urx_pending, e);
}
}
int ossl_qrx_provide_secret(OSSL_QRX *qrx, uint32_t enc_level,
uint32_t suite_id, EVP_MD *md,
const unsigned char *secret, size_t secret_len)
{
if (enc_level >= QUIC_ENC_LEVEL_NUM)
return 0;
if (!ossl_qrl_enc_level_set_provide_secret(&qrx->el_set,
qrx->libctx,
qrx->propq,
enc_level,
suite_id,
md,
secret,
secret_len,
qrx->init_key_phase_bit,
0))
return 0;
qrx_requeue_deferred(qrx);
return 1;
}
int ossl_qrx_discard_enc_level(OSSL_QRX *qrx, uint32_t enc_level)
{
if (enc_level >= QUIC_ENC_LEVEL_NUM)
return 0;
ossl_qrl_enc_level_set_discard(&qrx->el_set, enc_level);
return 1;
}
int ossl_qrx_processed_read_pending(OSSL_QRX *qrx)
{
return !ossl_list_rxe_is_empty(&qrx->rx_pending);
}
int ossl_qrx_unprocessed_read_pending(OSSL_QRX *qrx)
{
return !ossl_list_urxe_is_empty(&qrx->urx_pending)
|| !ossl_list_urxe_is_empty(&qrx->urx_deferred);
}
static RXE *qrx_pop_pending_rxe(OSSL_QRX *qrx)
{
RXE *rxe = ossl_list_rxe_head(&qrx->rx_pending);
if (rxe == NULL)
return NULL;
ossl_list_rxe_remove(&qrx->rx_pending, rxe);
return rxe;
}
static RXE *qrx_alloc_rxe(size_t alloc_len)
{
RXE *rxe;
if (alloc_len >= SIZE_MAX - sizeof(RXE))
return NULL;
rxe = OPENSSL_malloc(sizeof(RXE) + alloc_len);
if (rxe == NULL)
return NULL;
ossl_list_rxe_init_elem(rxe);
rxe->alloc_len = alloc_len;
rxe->data_len = 0;
rxe->refcount = 0;
return rxe;
}
static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len)
{
RXE *rxe;
if (ossl_list_rxe_head(&qrx->rx_free) != NULL)
return ossl_list_rxe_head(&qrx->rx_free);
rxe = qrx_alloc_rxe(alloc_len);
if (rxe == NULL)
return NULL;
ossl_list_rxe_insert_tail(&qrx->rx_free, rxe);
return rxe;
}
static RXE *qrx_resize_rxe(RXE_LIST *rxl, RXE *rxe, size_t n)
{
RXE *rxe2, *p;
if (rxe == NULL)
return NULL;
if (n >= SIZE_MAX - sizeof(RXE))
return NULL;
p = ossl_list_rxe_prev(rxe);
ossl_list_rxe_remove(rxl, rxe);
if (!ossl_assert(rxe->refcount == 0))
return NULL;
rxe2 = OPENSSL_realloc(rxe, sizeof(RXE) + n);
if (rxe2 == NULL) {
if (p == NULL)
ossl_list_rxe_insert_head(rxl, rxe);
else
ossl_list_rxe_insert_after(rxl, p, rxe);
return NULL;
}
if (p == NULL)
ossl_list_rxe_insert_head(rxl, rxe2);
else
ossl_list_rxe_insert_after(rxl, p, rxe2);
rxe2->alloc_len = n;
return rxe2;
}
static RXE *qrx_reserve_rxe(RXE_LIST *rxl,
RXE *rxe, size_t n)
{
if (rxe->alloc_len >= n)
return rxe;
return qrx_resize_rxe(rxl, rxe, n);
}
static void qrx_recycle_rxe(OSSL_QRX *qrx, RXE *rxe)
{
assert(ossl_list_rxe_prev(rxe) == NULL && ossl_list_rxe_next(rxe) == NULL);
rxe->pkt.hdr = NULL;
rxe->pkt.peer = NULL;
rxe->pkt.local = NULL;
ossl_list_rxe_insert_tail(&qrx->rx_free, rxe);
}
static int qrx_relocate_buffer(OSSL_QRX *qrx, RXE **prxe, size_t *pi,
const unsigned char **pptr, size_t buf_len)
{
RXE *rxe;
unsigned char *dst;
if (!buf_len)
return 1;
if ((rxe = qrx_reserve_rxe(&qrx->rx_free, *prxe, *pi + buf_len)) == NULL)
return 0;
*prxe = rxe;
dst = (unsigned char *)rxe_data(rxe) + *pi;
memcpy(dst, *pptr, buf_len);
*pi += buf_len;
*pptr = dst;
return 1;
}
static uint32_t qrx_determine_enc_level(const QUIC_PKT_HDR *hdr)
{
switch (hdr->type) {
case QUIC_PKT_TYPE_INITIAL:
return QUIC_ENC_LEVEL_INITIAL;
case QUIC_PKT_TYPE_HANDSHAKE:
return QUIC_ENC_LEVEL_HANDSHAKE;
case QUIC_PKT_TYPE_0RTT:
return QUIC_ENC_LEVEL_0RTT;
case QUIC_PKT_TYPE_1RTT:
return QUIC_ENC_LEVEL_1RTT;
default:
assert(0);
case QUIC_PKT_TYPE_RETRY:
case QUIC_PKT_TYPE_VERSION_NEG:
return QUIC_ENC_LEVEL_INITIAL;
}
}
static uint32_t rxe_determine_pn_space(RXE *rxe)
{
uint32_t enc_level;
enc_level = qrx_determine_enc_level(&rxe->hdr);
return ossl_quic_enc_level_to_pn_space(enc_level);
}
static int qrx_validate_hdr_early(OSSL_QRX *qrx, RXE *rxe,
const QUIC_CONN_ID *first_dcid)
{
if (rxe->hdr.version != QUIC_VERSION_1
&& rxe->hdr.version != QUIC_VERSION_NONE)
return 0;
if (rxe->hdr.type == QUIC_PKT_TYPE_0RTT)
return 0;
if (first_dcid != NULL && !ossl_quic_pkt_type_can_share_dgram(rxe->hdr.type))
return 0;
if (first_dcid != NULL) {
if (!ossl_assert(first_dcid->id_len < QUIC_MAX_CONN_ID_LEN)
|| !ossl_quic_conn_id_eq(first_dcid,
&rxe->hdr.dst_conn_id))
return 0;
}
return 1;
}
static int qrx_validate_hdr(OSSL_QRX *qrx, RXE *rxe)
{
int pn_space = rxe_determine_pn_space(rxe);
if (!ossl_quic_wire_decode_pkt_hdr_pn(rxe->hdr.pn, rxe->hdr.pn_len,
qrx->largest_pn[pn_space],
&rxe->pn))
return 0;
return 1;
}
static int qrx_validate_hdr_late(OSSL_QRX *qrx, RXE *rxe)
{
int pn_space = rxe_determine_pn_space(rxe);
if (qrx->validation_cb != NULL
&& !qrx->validation_cb(rxe->pn, pn_space, qrx->validation_cb_arg))
return 0;
return 1;
}
static size_t qrx_get_cipher_ctx_idx(OSSL_QRX *qrx, OSSL_QRL_ENC_LEVEL *el,
uint32_t enc_level,
unsigned char key_phase_bit,
uint64_t *rx_key_epoch,
int *is_old_key)
{
size_t idx;
*is_old_key = 0;
if (enc_level != QUIC_ENC_LEVEL_1RTT) {
*rx_key_epoch = 0;
return 0;
}
if (!ossl_assert(key_phase_bit <= 1))
return SIZE_MAX;
idx = (el->state == QRL_EL_STATE_PROV_COOLDOWN ? el->key_epoch & 1
: key_phase_bit);
switch (el->state) {
case QRL_EL_STATE_PROV_NORMAL:
*rx_key_epoch
= el->key_epoch + ((el->key_epoch & 1) ^ (uint64_t)key_phase_bit);
break;
case QRL_EL_STATE_PROV_UPDATING:
*is_old_key = (el->key_epoch & 1) ^ (uint64_t)key_phase_bit;
*rx_key_epoch = el->key_epoch - (uint64_t)*is_old_key;
break;
case QRL_EL_STATE_PROV_COOLDOWN:
*rx_key_epoch = el->key_epoch;
break;
}
return idx;
}
static int qrx_decrypt_pkt_body(OSSL_QRX *qrx, unsigned char *dst,
const unsigned char *src,
size_t src_len, size_t *dec_len,
const unsigned char *aad, size_t aad_len,
QUIC_PN pn, uint32_t enc_level,
unsigned char key_phase_bit,
uint64_t *rx_key_epoch)
{
int l = 0, l2 = 0, is_old_key, nonce_len;
unsigned char nonce[EVP_MAX_IV_LENGTH];
size_t i, cctx_idx;
OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
enc_level, 1);
EVP_CIPHER_CTX *cctx;
if (src_len > INT_MAX || aad_len > INT_MAX)
return 0;
if (!ossl_assert(el != NULL))
return 0;
if (el->tag_len >= src_len)
return 0;
if (qrx->forged_pkt_count >= ossl_qrl_get_suite_max_forged_pkt(el->suite_id))
return 0;
cctx_idx = qrx_get_cipher_ctx_idx(qrx, el, enc_level, key_phase_bit,
rx_key_epoch, &is_old_key);
if (!ossl_assert(cctx_idx < OSSL_NELEM(el->cctx)))
return 0;
if (is_old_key && pn >= qrx->cur_epoch_start_pn)
return 0;
cctx = el->cctx[cctx_idx];
nonce_len = EVP_CIPHER_CTX_get_iv_length(cctx);
if (!ossl_assert(nonce_len >= (int)sizeof(QUIC_PN)))
return 0;
memcpy(nonce, el->iv[cctx_idx], nonce_len);
for (i = 0; i < sizeof(QUIC_PN); ++i)
nonce[nonce_len - i - 1] ^= (unsigned char)(pn >> (i * 8));
if (EVP_CipherInit_ex(cctx, NULL,
NULL, NULL, nonce, 0)
!= 1)
return 0;
if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_SET_TAG,
el->tag_len,
(unsigned char *)src + src_len - el->tag_len)
!= 1)
return 0;
if (EVP_CipherUpdate(cctx, NULL, &l, aad, aad_len) != 1)
return 0;
if (EVP_CipherUpdate(cctx, dst, &l, src, src_len - el->tag_len) != 1)
return 0;
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
memcpy(dst, src, l);
if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
}
#else
if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
++qrx->forged_pkt_count;
return 0;
}
#endif
*dec_len = l;
return 1;
}
static ossl_inline void ignore_res(int x)
{
}
static void qrx_key_update_initiated(OSSL_QRX *qrx, QUIC_PN pn)
{
if (!ossl_qrl_enc_level_set_key_update(&qrx->el_set, QUIC_ENC_LEVEL_1RTT))
return;
qrx->cur_epoch_start_pn = pn;
if (qrx->key_update_cb != NULL)
qrx->key_update_cb(pn, qrx->key_update_cb_arg);
}
static int qrx_process_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe,
PACKET *pkt, size_t pkt_idx,
QUIC_CONN_ID *first_dcid,
size_t datagram_len)
{
RXE *rxe;
const unsigned char *eop = NULL;
size_t i, aad_len = 0, dec_len = 0;
PACKET orig_pkt = *pkt;
const unsigned char *sop = PACKET_data(pkt);
unsigned char *dst;
char need_second_decode = 0, already_processed = 0;
QUIC_PKT_HDR_PTRS ptrs;
uint32_t pn_space, enc_level;
OSSL_QRL_ENC_LEVEL *el = NULL;
uint64_t rx_key_epoch = UINT64_MAX;
rxe = qrx_ensure_free_rxe(qrx, PACKET_remaining(pkt));
if (rxe == NULL)
return 0;
if (pkt_is_marked(&urxe->processed, pkt_idx))
already_processed = 1;
need_second_decode = !pkt_is_marked(&urxe->hpr_removed, pkt_idx);
if (!ossl_quic_wire_decode_pkt_hdr(pkt,
qrx->short_conn_id_len,
need_second_decode, 0, &rxe->hdr, &ptrs,
NULL))
goto malformed;
eop = PACKET_data(pkt);
if (pkt_idx == 0)
*first_dcid = rxe->hdr.dst_conn_id;
if (already_processed
|| !qrx_validate_hdr_early(qrx, rxe, pkt_idx == 0 ? NULL : first_dcid))
goto malformed;
if (!ossl_quic_pkt_type_is_encrypted(rxe->hdr.type)) {
if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len)) == NULL)
goto malformed;
memcpy(rxe_data(rxe), rxe->hdr.data, rxe->hdr.len);
pkt_mark(&urxe->processed, pkt_idx);
rxe->hdr.data = rxe_data(rxe);
rxe->pn = QUIC_PN_INVALID;
rxe->data_len = rxe->hdr.len;
rxe->datagram_len = datagram_len;
rxe->key_epoch = 0;
rxe->peer = urxe->peer;
rxe->local = urxe->local;
rxe->time = urxe->time;
rxe->datagram_id = urxe->datagram_id;
ossl_list_rxe_remove(&qrx->rx_free, rxe);
ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
return 0;
}
enc_level = qrx_determine_enc_level(&rxe->hdr);
switch (ossl_qrl_enc_level_set_have_el(&qrx->el_set, enc_level)) {
case 1:
if (enc_level == QUIC_ENC_LEVEL_1RTT && !qrx->allow_1rtt)
goto cannot_decrypt;
break;
case 0:
goto cannot_decrypt;
default:
goto malformed;
}
i = 0;
if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) {
const unsigned char *token = rxe->hdr.token;
if (!qrx_relocate_buffer(qrx, &rxe, &i, &token, rxe->hdr.token_len))
goto malformed;
rxe->hdr.token = token;
}
*pkt = orig_pkt;
el = ossl_qrl_enc_level_set_get(&qrx->el_set, enc_level, 1);
assert(el != NULL);
if (need_second_decode) {
if (!ossl_quic_hdr_protector_decrypt(&el->hpr, &ptrs))
goto malformed;
pkt_mark(&urxe->hpr_removed, pkt_idx);
if (ossl_quic_wire_decode_pkt_hdr(pkt, qrx->short_conn_id_len,
0, 0, &rxe->hdr, NULL, NULL)
!= 1)
goto malformed;
}
if (!qrx_validate_hdr(qrx, rxe))
goto malformed;
if (qrx->msg_callback != NULL)
qrx->msg_callback(0, OSSL_QUIC1_VERSION, SSL3_RT_QUIC_PACKET, sop,
eop - sop - rxe->hdr.len, qrx->msg_callback_ssl,
qrx->msg_callback_arg);
aad_len = rxe->hdr.data - sop;
if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len + i)) == NULL) {
eop = NULL;
goto malformed;
}
dst = (unsigned char *)rxe_data(rxe) + i;
if (!qrx_decrypt_pkt_body(qrx, dst, rxe->hdr.data, rxe->hdr.len,
&dec_len, sop, aad_len, rxe->pn, enc_level,
rxe->hdr.key_phase, &rx_key_epoch))
goto malformed;
if (!qrx_validate_hdr_late(qrx, rxe))
goto malformed;
if (rxe->hdr.type == QUIC_PKT_TYPE_1RTT
&& rxe->hdr.key_phase != (el->key_epoch & 1))
qrx_key_update_initiated(qrx, rxe->pn);
pkt_mark(&urxe->processed, pkt_idx);
rxe->hdr.data = dst;
rxe->hdr.len = dec_len;
rxe->data_len = dec_len;
rxe->datagram_len = datagram_len;
rxe->key_epoch = rx_key_epoch;
pn_space = rxe_determine_pn_space(rxe);
if (rxe->pn > qrx->largest_pn[pn_space])
qrx->largest_pn[pn_space] = rxe->pn;
rxe->peer = urxe->peer;
rxe->local = urxe->local;
rxe->time = urxe->time;
rxe->datagram_id = urxe->datagram_id;
ossl_list_rxe_remove(&qrx->rx_free, rxe);
ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
return 0;
cannot_decrypt:
assert(eop != NULL && eop >= PACKET_data(pkt));
ignore_res(PACKET_forward(pkt, eop - PACKET_data(pkt)));
return 1;
malformed:
if (eop != NULL) {
assert(eop >= PACKET_data(pkt));
pkt_mark(&urxe->processed, pkt_idx);
ignore_res(PACKET_forward(pkt, eop - PACKET_data(pkt)));
} else {
pkt_mark(&urxe->processed, pkt_idx);
ignore_res(PACKET_forward(pkt, PACKET_remaining(pkt)));
}
return 0;
}
static int qrx_process_datagram(OSSL_QRX *qrx, QUIC_URXE *e,
const unsigned char *data,
size_t data_len)
{
int have_deferred = 0;
PACKET pkt;
size_t pkt_idx = 0;
QUIC_CONN_ID first_dcid = { 255 };
qrx->bytes_received += data_len;
if (!PACKET_buf_init(&pkt, data, data_len))
return 0;
for (; PACKET_remaining(&pkt) > 0; ++pkt_idx) {
if (PACKET_remaining(&pkt) < QUIC_MIN_VALID_PKT_LEN
|| pkt_idx >= QUIC_MAX_PKT_PER_URXE)
break;
if (qrx_process_pkt(qrx, e, &pkt, pkt_idx, &first_dcid, data_len))
have_deferred = 1;
}
return have_deferred;
}
static int qrx_process_one_urxe(OSSL_QRX *qrx, QUIC_URXE *e)
{
int was_deferred;
if (!ossl_assert(e == ossl_list_urxe_head(&qrx->urx_pending)))
return 0;
was_deferred = qrx_process_datagram(qrx, e, ossl_quic_urxe_data(e),
e->data_len);
ossl_list_urxe_remove(&qrx->urx_pending, e);
if (was_deferred > 0 && (e->deferred || qrx->num_deferred < qrx->max_deferred)) {
ossl_list_urxe_insert_tail(&qrx->urx_deferred, e);
if (!e->deferred) {
e->deferred = 1;
++qrx->num_deferred;
}
} else {
if (e->deferred) {
e->deferred = 0;
--qrx->num_deferred;
}
ossl_quic_demux_release_urxe(qrx->demux, e);
}
return 1;
}
static int qrx_process_pending_urxl(OSSL_QRX *qrx)
{
QUIC_URXE *e;
while ((e = ossl_list_urxe_head(&qrx->urx_pending)) != NULL)
if (!qrx_process_one_urxe(qrx, e))
return 0;
return 1;
}
int ossl_qrx_read_pkt(OSSL_QRX *qrx, OSSL_QRX_PKT **ppkt)
{
RXE *rxe;
if (!ossl_qrx_processed_read_pending(qrx)) {
if (!qrx_process_pending_urxl(qrx))
return 0;
if (!ossl_qrx_processed_read_pending(qrx))
return 0;
}
rxe = qrx_pop_pending_rxe(qrx);
if (!ossl_assert(rxe != NULL))
return 0;
assert(rxe->refcount == 0);
rxe->refcount = 1;
rxe->pkt.hdr = &rxe->hdr;
rxe->pkt.pn = rxe->pn;
rxe->pkt.time = rxe->time;
rxe->pkt.datagram_len = rxe->datagram_len;
rxe->pkt.peer
= BIO_ADDR_family(&rxe->peer) != AF_UNSPEC ? &rxe->peer : NULL;
rxe->pkt.local
= BIO_ADDR_family(&rxe->local) != AF_UNSPEC ? &rxe->local : NULL;
rxe->pkt.key_epoch = rxe->key_epoch;
rxe->pkt.datagram_id = rxe->datagram_id;
rxe->pkt.qrx = qrx;
*ppkt = &rxe->pkt;
return 1;
}
void ossl_qrx_pkt_release(OSSL_QRX_PKT *pkt)
{
RXE *rxe;
if (pkt == NULL)
return;
rxe = (RXE *)pkt;
assert(rxe->refcount > 0);
if (--rxe->refcount == 0)
qrx_recycle_rxe(pkt->qrx, rxe);
}
void ossl_qrx_pkt_orphan(OSSL_QRX_PKT *pkt)
{
RXE *rxe;
if (pkt == NULL)
return;
rxe = (RXE *)pkt;
assert(rxe->refcount > 0);
rxe->refcount--;
assert(ossl_list_rxe_prev(rxe) == NULL && ossl_list_rxe_next(rxe) == NULL);
return;
}
void ossl_qrx_pkt_up_ref(OSSL_QRX_PKT *pkt)
{
RXE *rxe = (RXE *)pkt;
assert(rxe->refcount > 0);
++rxe->refcount;
}
uint64_t ossl_qrx_get_bytes_received(OSSL_QRX *qrx, int clear)
{
uint64_t v = qrx->bytes_received;
if (clear)
qrx->bytes_received = 0;
return v;
}
int ossl_qrx_set_late_validation_cb(OSSL_QRX *qrx,
ossl_qrx_late_validation_cb *cb,
void *cb_arg)
{
qrx->validation_cb = cb;
qrx->validation_cb_arg = cb_arg;
return 1;
}
int ossl_qrx_set_key_update_cb(OSSL_QRX *qrx,
ossl_qrx_key_update_cb *cb,
void *cb_arg)
{
qrx->key_update_cb = cb;
qrx->key_update_cb_arg = cb_arg;
return 1;
}
uint64_t ossl_qrx_get_key_epoch(OSSL_QRX *qrx)
{
OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
QUIC_ENC_LEVEL_1RTT, 1);
return el == NULL ? UINT64_MAX : el->key_epoch;
}
int ossl_qrx_key_update_timeout(OSSL_QRX *qrx, int normal)
{
OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
QUIC_ENC_LEVEL_1RTT, 1);
if (el == NULL)
return 0;
if (el->state == QRL_EL_STATE_PROV_UPDATING
&& !ossl_qrl_enc_level_set_key_update_done(&qrx->el_set,
QUIC_ENC_LEVEL_1RTT))
return 0;
if (normal && el->state == QRL_EL_STATE_PROV_COOLDOWN
&& !ossl_qrl_enc_level_set_key_cooldown_done(&qrx->el_set,
QUIC_ENC_LEVEL_1RTT))
return 0;
return 1;
}
uint64_t ossl_qrx_get_cur_forged_pkt_count(OSSL_QRX *qrx)
{
return qrx->forged_pkt_count;
}
uint64_t ossl_qrx_get_max_forged_pkt_count(OSSL_QRX *qrx,
uint32_t enc_level)
{
OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(&qrx->el_set,
enc_level, 1);
return el == NULL ? UINT64_MAX
: ossl_qrl_get_suite_max_forged_pkt(el->suite_id);
}
void ossl_qrx_allow_1rtt_processing(OSSL_QRX *qrx)
{
if (qrx->allow_1rtt)
return;
qrx->allow_1rtt = 1;
qrx_requeue_deferred(qrx);
}
void ossl_qrx_set_msg_callback(OSSL_QRX *qrx, ossl_msg_cb msg_callback,
SSL *msg_callback_ssl)
{
qrx->msg_callback = msg_callback;
qrx->msg_callback_ssl = msg_callback_ssl;
}
void ossl_qrx_set_msg_callback_arg(OSSL_QRX *qrx, void *msg_callback_arg)
{
qrx->msg_callback_arg = msg_callback_arg;
}
size_t ossl_qrx_get_short_hdr_conn_id_len(OSSL_QRX *qrx)
{
return qrx->short_conn_id_len;
}