[PATCH] QUIC: refined sending CONNECTION_CLOSE in various packet types
Roman Arutyunyan
arut at nginx.com
Fri Sep 1 09:55:56 UTC 2023
Hi,
On Thu, Aug 31, 2023 at 06:59:46PM +0400, Sergey Kandaurov wrote:
> # HG changeset patch
> # User Sergey Kandaurov <pluknet at nginx.com>
> # Date 1693493736 -14400
> # Thu Aug 31 18:55:36 2023 +0400
> # Node ID 358c657a4a7afef502a00b9a41bddbe08f6859ae
> # Parent 015353ca1be7acc176f6369ed92ec6c49975ee6a
> QUIC: refined sending CONNECTION_CLOSE in various packet types.
>
> As per RFC 9000, section 10.2.3, to ensure that peer successfully removed
> packet protection, CONNECTION_CLOSE can be sent in multiple packets using
> different packet protection levels.
>
> Specifically, new logic is added to more strictly follow these rules:
>
> - by default, the highest available level of packet protection is used;
> - unless handshake is confirmed, but we have got application keys available,
> that means the client may have or may have not application keys to remove
may *not* have ?
> 1-RTT packet protection; in such case, send both 1-RTT and HS packets;
> - additionally, if we still have initial protection keys not yet discarded,
> which happens if the path was not yet validated by successfully removing
> Handshake packet protection, that means the client may not have handshake
> keys; in such case, send an Initial packet too.
>
> This roughly resembles the following paragraph:
>
> * Prior to confirming the handshake, a peer might be unable to process 1-RTT
> packets, so an endpoint SHOULD send a CONNECTION_CLOSE frame in both Handshake
> and 1-RTT packets. A server SHOULD also send a CONNECTION_CLOSE frame in an
> Initial packet.
>
> In practice, this change allows to avoid sending Initial packet when we know
> the client has handshake keys, and fixes sending CONNECTION_CLOSE when using
> QuicTLS with old QUIC API, where TLS stack releases application read keys
> before handshake confirmation, sending it additionally in a Handshake packet.
>
> diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c
> --- a/src/event/quic/ngx_event_quic.c
> +++ b/src/event/quic/ngx_event_quic.c
> @@ -540,8 +540,20 @@ ngx_quic_close_connection(ngx_connection
>
> (void) ngx_quic_send_cc(c);
>
> - if (qc->error_level == ssl_encryption_handshake) {
> - /* for clients that might not have handshake keys */
> + if (qc->error_level == ssl_encryption_application
> + && ngx_quic_keys_available(qc->keys,
> + ssl_encryption_handshake))
> + {
> + /* handshake not confirmed, client may not have app keys */
> + qc->error_level = ssl_encryption_handshake;
> + (void) ngx_quic_send_cc(c);
> + }
> +
> + if (qc->error_level == ssl_encryption_handshake
> + && ngx_quic_keys_available(qc->keys,
> + ssl_encryption_initial))
> + {
> + /* path not validated, client may not have hs keys */
> qc->error_level = ssl_encryption_initial;
> (void) ngx_quic_send_cc(c);
> }
I have a feeling that we can just send CC for all levels for which keys are
available:
for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
ctx = &qc->send_ctx[i];
if (!ngx_quic_keys_available(qc->keys, ctx->level)) {
continue;
}
qc->error_level = ctx->level;
(void) ngx_quic_send_cc(c);
if (rc == NGX_OK && !qc->close.timer_set) {
ngx_add_timer(&qc->close, 3 * ngx_quic_pto(c, ctx));
}
}
--
Roman Arutyunyan
More information about the nginx-devel
mailing list