mirror of
https://github.com/openssl/openssl.git
synced 2025-02-17 14:32:04 +08:00
Add the ability to mutate QUIC packets before they are written
We add callbacks so that QUIC packets can be modified by the test framework before they are encrypted and written to the network. This enables us to simulate badly behaving endpoints. Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/20030)
This commit is contained in:
parent
fdd4716dd6
commit
14e3140939
@ -73,6 +73,12 @@ QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args);
|
||||
/* No-op if ch is NULL. */
|
||||
void ossl_quic_channel_free(QUIC_CHANNEL *ch);
|
||||
|
||||
/* Set mutator callbacks for test framework support */
|
||||
int ossl_quic_channel_set_mutator(QUIC_CHANNEL *ch,
|
||||
ossl_mutate_packet_cb mutatecb,
|
||||
ossl_finish_mutate_cb finishmutatecb,
|
||||
void *mutatearg);
|
||||
|
||||
/*
|
||||
* Connection Lifecycle Events
|
||||
* ===========================
|
||||
|
@ -21,8 +21,22 @@
|
||||
* QUIC Record Layer - TX
|
||||
* ======================
|
||||
*/
|
||||
typedef struct ossl_qtx_iovec_st {
|
||||
const unsigned char *buf;
|
||||
size_t buf_len;
|
||||
} OSSL_QTX_IOVEC;
|
||||
|
||||
typedef struct ossl_qtx_st OSSL_QTX;
|
||||
|
||||
typedef int (*ossl_mutate_packet_cb)(const QUIC_PKT_HDR *hdrin,
|
||||
const OSSL_QTX_IOVEC *iovecin, size_t numin,
|
||||
QUIC_PKT_HDR **hdrout,
|
||||
const OSSL_QTX_IOVEC **iovecout,
|
||||
size_t *numout,
|
||||
void *arg);
|
||||
|
||||
typedef void (*ossl_finish_mutate_cb)(void *arg);
|
||||
|
||||
typedef struct ossl_qtx_args_st {
|
||||
OSSL_LIB_CTX *libctx;
|
||||
const char *propq;
|
||||
@ -40,6 +54,10 @@ OSSL_QTX *ossl_qtx_new(const OSSL_QTX_ARGS *args);
|
||||
/* Frees the QTX. */
|
||||
void ossl_qtx_free(OSSL_QTX *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);
|
||||
|
||||
/*
|
||||
* Secret Management
|
||||
* -----------------
|
||||
@ -114,10 +132,6 @@ uint32_t ossl_qrl_get_suite_cipher_tag_len(uint32_t suite_id);
|
||||
* Packet Transmission
|
||||
* -------------------
|
||||
*/
|
||||
typedef struct ossl_qtx_iovec_st {
|
||||
const unsigned char *buf;
|
||||
size_t buf_len;
|
||||
} OSSL_QTX_IOVEC;
|
||||
|
||||
typedef struct ossl_qtx_pkt_st {
|
||||
/* Logical packet header to be serialized. */
|
||||
|
@ -41,6 +41,12 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args,
|
||||
|
||||
void ossl_quic_tserver_free(QUIC_TSERVER *srv);
|
||||
|
||||
/* Set mutator callbacks for test framework support */
|
||||
int ossl_quic_tserver_set_mutator(QUIC_TSERVER *srv,
|
||||
ossl_mutate_packet_cb mutatecb,
|
||||
ossl_finish_mutate_cb finishmutatecb,
|
||||
void *mutatearg);
|
||||
|
||||
/* Advances the state machine. */
|
||||
int ossl_quic_tserver_tick(QUIC_TSERVER *srv);
|
||||
|
||||
|
@ -347,6 +347,19 @@ void ossl_quic_channel_free(QUIC_CHANNEL *ch)
|
||||
OPENSSL_free(ch);
|
||||
}
|
||||
|
||||
/* Set mutator callbacks for test framework support */
|
||||
int ossl_quic_channel_set_mutator(QUIC_CHANNEL *ch,
|
||||
ossl_mutate_packet_cb mutatecb,
|
||||
ossl_finish_mutate_cb finishmutatecb,
|
||||
void *mutatearg)
|
||||
{
|
||||
if (ch->qtx == NULL)
|
||||
return 0;
|
||||
|
||||
ossl_qtx_set_mutator(ch->qtx, mutatecb, finishmutatecb, mutatearg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ossl_quic_channel_get_peer_addr(QUIC_CHANNEL *ch, BIO_ADDR *peer_addr)
|
||||
{
|
||||
*peer_addr = ch->cur_peer_addr;
|
||||
|
@ -90,6 +90,10 @@ struct ossl_qtx_st {
|
||||
* confidentiality limit.
|
||||
*/
|
||||
uint64_t epoch_pkt_count;
|
||||
|
||||
ossl_mutate_packet_cb mutatecb;
|
||||
ossl_finish_mutate_cb finishmutatecb;
|
||||
void *mutatearg;
|
||||
};
|
||||
|
||||
/* Instantiates a new QTX. */
|
||||
@ -141,6 +145,15 @@ void ossl_qtx_free(OSSL_QTX *qtx)
|
||||
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,
|
||||
@ -414,7 +427,7 @@ int ossl_qtx_calculate_plaintext_payload_len(OSSL_QTX *qtx, uint32_t enc_level,
|
||||
*/
|
||||
#define QTX_FAIL_INSUFFICIENT_LEN (-2)
|
||||
|
||||
static int qtx_write_hdr(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
static int qtx_write_hdr(OSSL_QTX *qtx, const QUIC_PKT_HDR *hdr, TXE *txe,
|
||||
QUIC_PKT_HDR_PTRS *ptrs)
|
||||
{
|
||||
WPACKET wpkt;
|
||||
@ -424,8 +437,8 @@ static int qtx_write_hdr(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
txe->alloc_len - txe->data_len, 0))
|
||||
return 0;
|
||||
|
||||
if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, pkt->hdr->dst_conn_id.id_len,
|
||||
pkt->hdr, ptrs)
|
||||
if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, hdr->dst_conn_id.id_len,
|
||||
hdr, ptrs)
|
||||
|| !WPACKET_get_total_written(&wpkt, &l)) {
|
||||
WPACKET_finish(&wpkt);
|
||||
return 0;
|
||||
@ -534,6 +547,9 @@ static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
QUIC_PKT_HDR_PTRS ptrs;
|
||||
unsigned char *hdr_start;
|
||||
OSSL_QRL_ENC_LEVEL *el = NULL;
|
||||
QUIC_PKT_HDR *hdr;
|
||||
const OSSL_QTX_IOVEC *iovec;
|
||||
size_t num_iovec;
|
||||
|
||||
/*
|
||||
* Determine if the packet needs encryption and the minimum conceivable
|
||||
@ -558,8 +574,25 @@ static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set some fields in the header we are responsible for. */
|
||||
if (pkt->hdr->type == QUIC_PKT_TYPE_1RTT)
|
||||
pkt->hdr->key_phase = (unsigned char)(el->key_epoch & 1);
|
||||
|
||||
/* If we are running tests then mutate_packet may be non NULL */
|
||||
if (qtx->mutatecb != NULL) {
|
||||
if (!qtx->mutatecb(pkt->hdr, pkt->iovec, pkt->num_iovec, &hdr,
|
||||
&iovec, &num_iovec, qtx->mutatearg)) {
|
||||
ret = QTX_FAIL_GENERIC;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
hdr = pkt->hdr;
|
||||
iovec = pkt->iovec;
|
||||
num_iovec = pkt->num_iovec;
|
||||
}
|
||||
|
||||
/* Walk the iovecs to determine actual input payload length. */
|
||||
iovec_cur_init(&cur, pkt->iovec, pkt->num_iovec);
|
||||
iovec_cur_init(&cur, iovec, num_iovec);
|
||||
|
||||
if (cur.bytes_remaining == 0) {
|
||||
/* No zero-length payloads allowed. */
|
||||
@ -573,10 +606,10 @@ static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
: cur.bytes_remaining;
|
||||
|
||||
/* Determine header length. */
|
||||
pkt->hdr->data = NULL;
|
||||
pkt->hdr->len = payload_len;
|
||||
pred_hdr_len = ossl_quic_wire_get_encoded_pkt_hdr_len(pkt->hdr->dst_conn_id.id_len,
|
||||
pkt->hdr);
|
||||
hdr->data = NULL;
|
||||
hdr->len = payload_len;
|
||||
pred_hdr_len = ossl_quic_wire_get_encoded_pkt_hdr_len(hdr->dst_conn_id.id_len,
|
||||
hdr);
|
||||
if (pred_hdr_len == 0) {
|
||||
ret = QTX_FAIL_GENERIC;
|
||||
goto err;
|
||||
@ -590,14 +623,10 @@ static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Set some fields in the header we are responsible for. */
|
||||
if (pkt->hdr->type == QUIC_PKT_TYPE_1RTT)
|
||||
pkt->hdr->key_phase = (unsigned char)(el->key_epoch & 1);
|
||||
|
||||
if (ossl_quic_pkt_type_has_pn(pkt->hdr->type)) {
|
||||
if (ossl_quic_pkt_type_has_pn(hdr->type)) {
|
||||
if (!ossl_quic_wire_encode_pkt_hdr_pn(pkt->pn,
|
||||
pkt->hdr->pn,
|
||||
pkt->hdr->pn_len)) {
|
||||
hdr->pn,
|
||||
hdr->pn_len)) {
|
||||
ret = QTX_FAIL_GENERIC;
|
||||
goto err;
|
||||
}
|
||||
@ -605,7 +634,7 @@ static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
|
||||
/* Append the header to the TXE. */
|
||||
hdr_start = txe_data(txe) + txe->data_len;
|
||||
if (!qtx_write_hdr(qtx, pkt, txe, &ptrs)) {
|
||||
if (!qtx_write_hdr(qtx, hdr, txe, &ptrs)) {
|
||||
ret = QTX_FAIL_GENERIC;
|
||||
goto err;
|
||||
}
|
||||
@ -638,6 +667,8 @@ static int qtx_write(OSSL_QTX *qtx, const OSSL_QTX_PKT *pkt, TXE *txe,
|
||||
assert(txe->data_len - orig_data_len == pkt_len);
|
||||
}
|
||||
|
||||
if (qtx->finishmutatecb != NULL)
|
||||
qtx->finishmutatecb(qtx->mutatearg);
|
||||
return 1;
|
||||
|
||||
err:
|
||||
@ -646,6 +677,8 @@ err:
|
||||
* TXE.
|
||||
*/
|
||||
txe->data_len = orig_data_len;
|
||||
if (qtx->finishmutatecb != NULL)
|
||||
qtx->finishmutatecb(qtx->mutatearg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -122,6 +122,16 @@ void ossl_quic_tserver_free(QUIC_TSERVER *srv)
|
||||
OPENSSL_free(srv);
|
||||
}
|
||||
|
||||
/* Set mutator callbacks for test framework support */
|
||||
int ossl_quic_tserver_set_mutator(QUIC_TSERVER *srv,
|
||||
ossl_mutate_packet_cb mutatecb,
|
||||
ossl_finish_mutate_cb finishmutatecb,
|
||||
void *mutatearg)
|
||||
{
|
||||
return ossl_quic_channel_set_mutator(srv->ch, mutatecb, finishmutatecb,
|
||||
mutatearg);
|
||||
}
|
||||
|
||||
int ossl_quic_tserver_tick(QUIC_TSERVER *srv)
|
||||
{
|
||||
ossl_quic_reactor_tick(ossl_quic_channel_get_reactor(srv->ch));
|
||||
|
Loading…
Reference in New Issue
Block a user