Skip to content

Fix: fall back to PNS_INIT when closing connection pre-handshake - #693

Open
gg582 wants to merge 1 commit into
litespeedtech:masterfrom
gg582:fix-ietf-close-pns-init-fallback
Open

gg582 wants to merge 1 commit into
litespeedtech:masterfrom
gg582:fix-ietf-close-pns-init-fallback

Conversation

@gg582

@gg582 gg582 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Problem

In the closing path of immediate_close() (called from ietf_full_conn_ci_tick()), PNS_HSK was selected whenever the client had not sent Handshake CRYPTO. A client that has not yet received the server's Initial flight has no Handshake keys at all, only Initial keys, so encrypting the CONNECTION_CLOSE packet failed and the peer never received it.

Fix

Use the same three-way selection as generate_ping_frame() (and now generate_connection_close_packet(), see #687): fall back to PNS_INIT when the Handshake encryption level is not ready:

if ((conn->ifc_flags & (IFC_SERVER|IFC_IGNORE_HSK)) ||
        (conn->ifc_u.cli.ifcli_flags & IFCLI_HSK_CRYPTO_SENT))
    pns = PNS_APP;
else if (iquic_esf_is_enc_level_ready(conn->ifc_conn.cn_enc_session,
                                                        ENC_LEV_HSK))
    pns = PNS_HSK;
else
    pns = PNS_INIT;

Notes

This is the pre-existing gap noted by @dtikhonov in #687: the PNS selection logic in this closing path lacked the PNS_INIT fallback that generate_ping_frame() already has. When pns is PNS_HSK and an application error is set, the existing code already strips the application error code and reason per RFC 9000 Section 10.2.3; the new PNS_INIT branch emits the same transport-level close frame, so the RFC requirement remains satisfied.

In the closing path of ietf_full_conn_ci_tick(), PNS_HSK was selected
whenever the client had not sent Handshake CRYPTO.  A client that has
not yet received the server's Initial flight has no Handshake keys,
only Initial keys, so encrypting the CONNECTION_CLOSE packet failed
and the peer never received it.  Fall back to PNS_INIT when the
Handshake encryption level is not ready, mirroring the selection in
generate_ping_frame().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant