]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add tracking of receive credit for unvalidated connections
authorNeil Horman <nhorman@openssl.org>
Mon, 9 Dec 2024 15:21:54 +0000 (10:21 -0500)
committerNeil Horman <nhorman@openssl.org>
Mon, 17 Feb 2025 16:27:33 +0000 (11:27 -0500)
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)

demos/guide/quic-hq-interop-server.c
include/internal/quic_txp.h
ssl/quic/quic_channel.c
ssl/quic/quic_impl.c
ssl/quic/quic_port.c
ssl/quic/quic_rx_depack.c
ssl/quic/quic_txp.c
test/quic_txp_test.c

index df3864fcebfa7b3ba24b06cff819152a6edc6850..226d9d10c2f5177544a4a12ebb2101da0e9e19db 100644 (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",
index a4b8125c8eaed21f9c958dbd1a2bb4eee3fe8e2c..70bbd05a0c3bd9ced292513c81ab9c9c4b2837f9 100644 (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);
index e96dc4dbf28655ab3fcff1f3d2c6d6581613573d..61611bf3145dc8fb429f9a33717ea128fd39098d 100644 (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
index e8b0888bcad00636c2547199cff2b30f56c7cb5e..17d0d621ceea610192becccc9e356167b0086d0a 100644 (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;
 }
 
index 28457f3bcd3901cb10d879a77fb80eb12f047a07..5124aebc16c40945be72261354c6ded605e1f259 100644 (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;
 
index 58a8edf03cdca820843feaf0a277322009f10b0b..31e311554ee09826d8883e90119803489d094e4a 100644 (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,
index ff67ea9d570d6b24a1a7552a2d8e46949bca42b5..9ff0e5aee5d265fe88397e00f6c49d7feaac9ef3 100644 (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 */
index 6c646f239b33c1140484bfca1df355086df86a9e..e77707613e6e9aa4829adb9679888c7f26a082f2 100644 (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;