mirror of
https://github.com/openssl/openssl.git
synced 2026-01-25 02:56:43 +00:00
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:
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user