* 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",
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);
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;
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
out:
qctx_unlock(&ctx);
+ if (qc != NULL)
+ ossl_quic_do_handshake(&qc->obj.ssl);
return qc != NULL ? &qc->obj.ssl : NULL;
}
#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"
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;
* 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;
PACKET pkt;
OSSL_ACKM_RX_PKT ackm_data;
uint32_t enc_level;
+ size_t dgram_len = qpacket->datagram_len;
/*
* ok has three states:
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,
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;
}
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;
+ }
}
/**
*
* @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)
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
/* 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) {
goto out;
++pkts_done;
+
}
/* Flush & Cleanup */
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;