Add tracking of receive credit for unvalidated connections

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26178)
This commit is contained in:
Neil Horman
2024-12-09 10:21:54 -05:00
parent eaa1a143ae
commit d1c3bb2f74
8 changed files with 64 additions and 9 deletions

View File

@@ -570,6 +570,7 @@ static int run_quic_server(SSL_CTX *ctx, BIO *sock)
* Filter on the shutdown error, and only print an error
* message if the cause is not SHUTDOWN
*/
ERR_print_errors_fp(stderr);
errcode = ERR_get_error();
if (ERR_GET_REASON(errcode) != SSL_R_PROTOCOL_IS_SHUTDOWN)
fprintf(stderr, "Failure in accept stream, error %s\n",

View File

@@ -71,7 +71,8 @@ void ossl_quic_tx_packetiser_add_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp
size_t credit);
void ossl_quic_tx_packetiser_consume_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,
size_t credit);
size_t ossl_quic_tx_packetiser_get_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp);
int ossl_quic_tx_packetiser_check_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,
size_t req_credit);
typedef void (ossl_quic_initial_token_free_fn)(const unsigned char *buf,
size_t buf_len, void *arg);

View File

@@ -298,6 +298,10 @@ static int ch_init(QUIC_CHANNEL *ch)
if (ch->txp == NULL)
goto err;
/* clients have no amplification limit, so are considered always valid */
if (!ch->is_server)
ossl_quic_tx_packetiser_set_validated(ch->txp);
ossl_quic_tx_packetiser_set_ack_tx_cb(ch->txp, ch_on_txp_ack_tx, ch);
qrx_args.libctx = ch->port->engine->libctx;
@@ -1052,6 +1056,13 @@ static int ch_on_handshake_complete(void *arg)
if (!ossl_assert(ch->tx_enc_level == QUIC_ENC_LEVEL_1RTT))
return 0;
/*
* When handshake is complete, we no longer need to abide by the
* 3x amplification limit, though we should be validated as soon
* as we see a handshake key encrypted packet (see ossl_quic_handle_packet)
*/
ossl_quic_tx_packetiser_set_validated(ch->txp);
if (!ch->got_remote_transport_params) {
/*
* Was not a valid QUIC handshake if we did not get valid transport

View File

@@ -4436,6 +4436,8 @@ SSL *ossl_quic_accept_connection(SSL *ssl, uint64_t flags)
out:
qctx_unlock(&ctx);
if (qc != NULL)
ossl_quic_do_handshake(&qc->obj.ssl);
return qc != NULL ? &qc->obj.ssl : NULL;
}

View File

@@ -11,6 +11,7 @@
#include "internal/quic_channel.h"
#include "internal/quic_lcidm.h"
#include "internal/quic_srtm.h"
#include "internal/quic_txp.h"
#include "internal/ssl_unwrap.h"
#include "quic_port_local.h"
#include "quic_channel_local.h"
@@ -606,6 +607,12 @@ static void port_bind_channel(QUIC_PORT *port, const BIO_ADDR *peer,
return;
if (odcid->id_len != 0) {
/*
* If we have an odcid, then we wen't through server address validation
* and as such, this channel need not conform to the 3x validation cap
* See RFC 9000 s. 8.1
*/
ossl_quic_tx_packetiser_set_validated(ch->txp);
if (!ossl_quic_bind_channel(ch, peer, scid, dcid, odcid)) {
ossl_quic_channel_free(ch);
return;
@@ -1170,7 +1177,6 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
* RFC 9000 s. 6 and 14.1, we only do so however, if the UDP datagram
* is a minimum of 1200 bytes in size
*/
if (e->data_len < 1200)
goto undesirable;

View File

@@ -1411,6 +1411,7 @@ int ossl_quic_handle_frames(QUIC_CHANNEL *ch, OSSL_QRX_PKT *qpacket)
PACKET pkt;
OSSL_ACKM_RX_PKT ackm_data;
uint32_t enc_level;
size_t dgram_len = qpacket->datagram_len;
/*
* ok has three states:
@@ -1444,6 +1445,19 @@ int ossl_quic_handle_frames(QUIC_CHANNEL *ch, OSSL_QRX_PKT *qpacket)
ok = 0; /* Still assume the worst */
ackm_data.pkt_space = ossl_quic_enc_level_to_pn_space(enc_level);
/*
* RFC 9000 s. 8.1
* We can consider the connection to be validated, if we receive a packet
* from the client protected via handshake keys, meaning that the
* amplification limit no longer applies (i.e. we can set it as validated.
* Otherwise, add the size of this packet to the unvalidated credit for
* the connection.
*/
if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE)
ossl_quic_tx_packetiser_set_validated(ch->txp);
else
ossl_quic_tx_packetiser_add_unvalidated_credit(ch->txp, dgram_len);
/* Now that special cases are out of the way, parse frames */
if (!PACKET_buf_init(&pkt, qpacket->hdr->data, qpacket->hdr->len)
|| !depack_process_frames(ch, &pkt, qpacket,

View File

@@ -485,11 +485,12 @@ void ossl_quic_tx_packetiser_add_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp
size_t credit)
{
if (txp->unvalidated_credit != SIZE_MAX) {
if (SIZE_MAX - txp->unvalidated_credit < credit * 3)
if ((SIZE_MAX - txp->unvalidated_credit) > (credit * 3))
txp->unvalidated_credit += credit * 3;
else
txp->unvalidated_credit = SIZE_MAX - 1;
}
return;
}
@@ -507,9 +508,12 @@ void ossl_quic_tx_packetiser_add_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp
void ossl_quic_tx_packetiser_consume_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,
size_t credit)
{
if (txp->unvalidated_credit != SIZE_MAX)
txp->unvalidated_credit -= credit;
if (txp->unvalidated_credit != SIZE_MAX) {
if (txp->unvalidated_credit < credit)
txp->unvalidated_credit = 0;
else
txp->unvalidated_credit -= credit;
}
}
/**
@@ -525,9 +529,10 @@ void ossl_quic_tx_packetiser_consume_unvalidated_credit(OSSL_QUIC_TX_PACKETISER
*
* @return 1 if the unvalidated credit exceeds `req_credit`, 0 otherwise.
*/
int ossl_quic_tx_packetiser_check_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp, size_t req_credit)
int ossl_quic_tx_packetiser_check_unvalidated_credit(OSSL_QUIC_TX_PACKETISER *txp,
size_t req_credit)
{
return txp->unvalidated_credit;
return (txp->unvalidated_credit > req_credit);
}
OSSL_QUIC_TX_PACKETISER *ossl_quic_tx_packetiser_new(const OSSL_QUIC_TX_PACKETISER_ARGS *args)
@@ -859,12 +864,13 @@ int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp,
uint64_t cc_limit = txp->args.cc_method->get_tx_allowance(txp->args.cc_data);
int need_padding = 0, txpim_pkt_reffed;
memset(status, 0, sizeof(*status));
for (enc_level = QUIC_ENC_LEVEL_INITIAL;
enc_level < QUIC_ENC_LEVEL_NUM;
++enc_level)
pkt[enc_level].h_valid = 0;
memset(status, 0, sizeof(*status));
/*
* Should not be needed, but a sanity check in case anyone else has been
@@ -986,6 +992,13 @@ int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp,
/* Nothing was generated for this EL, so skip. */
continue;
if (!ossl_quic_tx_packetiser_check_unvalidated_credit(txp,
pkt[enc_level].h.bytes_appended)) {
res = TXP_ERR_SPACE;
goto out;
}
ossl_quic_tx_packetiser_consume_unvalidated_credit(txp, pkt[enc_level].h.bytes_appended);
rc = txp_pkt_commit(txp, &pkt[enc_level], archetype,
&txpim_pkt_reffed);
if (rc) {
@@ -1006,6 +1019,7 @@ int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp,
goto out;
++pkts_done;
}
/* Flush & Cleanup */

View File

@@ -212,6 +212,12 @@ static int helper_init(struct helper *h)
if (!TEST_ptr(h->txp = ossl_quic_tx_packetiser_new(&h->args)))
goto err;
/*
* Our helper should always skip validation
* as the tests are not written to expect delayed connections
*/
ossl_quic_tx_packetiser_set_validated(h->txp);
if (!TEST_ptr(h->demux = ossl_quic_demux_new(h->bio2, 8,
fake_now, NULL)))
goto err;