/* first unhandled streams ID, set by MUX after release */
uint64_t stream_max_uni;
uint64_t stream_max_bidi;
+
+ /* Number of received packets which failed authentication. */
+ uint64_t auth_fails;
} rx;
struct {
struct quic_tls_kp prv_rx;
}
}
+/* Return the number of packets which may fail authentication with <aead> as
+ * AEAD algorithm, as stated by RFC 9001 6.6.
+ */
+static inline uint64_t quic_aead_integrity_limit(const QUIC_AEAD *aead)
+{
+ /* Note that QUIC_AEAD_API is defined only if OPENSSL_IS_AWSLC is defined.
+ *
+ * tls_aead() may only return, depending on the library:
+ * AWS-LC : aes_128_gcm, aes_256_gcm, chacha20_poly1305
+ * wolfSSL : aes_128_gcm, aes_256_gcm, chacha20_poly1305
+ * LibreSSL < 4.0: aes_128_gcm, aes_256_gcm, aes_128_ccm
+ * others : the four of them
+ */
+#ifdef QUIC_AEAD_API
+ if (aead == EVP_aead_chacha20_poly1305())
+ return 1ULL << 36;
+ if (aead == EVP_aead_aes_128_gcm() ||
+ aead == EVP_aead_aes_256_gcm())
+ return 1ULL << 52;
+#else /* !QUIC_AEAD_API */
+ switch (EVP_CIPHER_nid(aead)) {
+#if !defined(USE_OPENSSL_WOLFSSL)
+ case NID_aes_128_ccm:
+ /* 2^21.5 */
+ return 2965820;
+#endif
+#if (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x4000000fL)
+ case NID_chacha20_poly1305:
+ return 1ULL << 36;
+#endif
+ case NID_aes_128_gcm:
+ case NID_aes_256_gcm:
+ return 1ULL << 52;
+ }
+#endif
+ return 0;
+}
+
static inline const EVP_MD *tls_md(const SSL_CIPHER *cipher)
{
switch (SSL_CIPHER_get_id(cipher)) {
memset(&qc->rx.params, 0, sizeof(qc->rx.params));
qc->rx.buf = b_make(qc->rx.buf.area, QUIC_CONN_RX_BUFSZ, 0, 0);
qc->rx.stream_max_uni = qc->rx.stream_max_bidi = 0;
+ qc->rx.auth_fails = 0;
qc->max_udp_payload = l ?
l->bind_conf->quic_params.max_udp_payload_size :
rx_ctx, tls_ctx->rx.aead, rx_key, iv);
if (!ret) {
TRACE_ERROR("quic_tls_decrypt() failed", QUIC_EV_CONN_RXPKT, qc);
+
+ /* RFC 9001 6.6. Limits on AEAD Usage
+ *
+ * If the total number of received packets that fail
+ * authentication within the connection, across all keys,
+ * exceeds the integrity limit for the selected AEAD, the
+ * endpoint MUST immediately close the connection with a
+ * connection error of type AEAD_LIMIT_REACHED and not process
+ * any more packets.
+ */
+ if (++qc->rx.auth_fails > quic_aead_integrity_limit(tls_ctx->rx.aead)) {
+ TRACE_ERROR("AEAD integrity limit reached", QUIC_EV_CONN_RXPKT, qc);
+ quic_set_connection_close(qc, quic_err_transport(QC_ERR_AEAD_LIMIT_REACHED));
+ }
+
goto leave;
}