Skip to content

Move the QUIC and TLS key-holding structs onto nish:secret #430

Closed

Description

@amritk

nish/net/quic-packet's QuicKeys (key, IV and header-protection key) and nish/net/tls's traffic secrets are held as plain u8[] and are never wiped. QUIC-1 in docs/security/quic.md and TLS-1 in docs/security/tls.md record this.

Since #418, nish:secret is available to std/, and CLAUDE.md asks that secret material be a Secret that is wiped. These modules cannot simply retype their fields, because a Secret may not be a struct field (NL2430). Adopting it means redesigning the key API: keys passed and returned as Secret<u8[]> and computed on inside expose, rather than stored in a struct across calls. QUIC connections (Q2a/Q2b in #395) and the TLS record layer (T2) consume that API, so the redesign should land before Q2's connection keys ship.

Done when QUIC-1 and TLS-1 are closed, or narrowed to what a wipe cannot reach, with a test that pins the wipes under -O2.

Part of #395

Activity

  1. added 3 commits that reference this issue on Oct 3, 2026
  2. amritk commented on Oct 6, 2026

    @amritk
    OwnerAuthor

    Scope check against the records on main at d43ba05. Besides QUIC-1 and TLS-1, three more open findings name this issue as their follow-up, so this issue covers them too:

    • TLS-2 (std/net/tls/record.ts, TlsRecordProtection): a direction's key, IV and AES key schedule live in fields. The key and IV are wiped with secureZero, but the schedule is zeroed only by ordinary stores.
    • QUIC-2 (std/net/quic.ts, each level's QuicConnSpace): a connection keeps every level's QuicKeys between calls.
    • QUIC-5 (QuicServerConfig, QuicListener): the stateless-reset key and the Retry token key are plain fields of the caller's config.

    HMAC and HKDF taking Secret keys and wiping their own state is filed separately as #476. The derivations here run through them, so the two should land in a compatible order.


    Generated by Claude Code

  3. amritk commented on Oct 16, 2026

    @amritk
    OwnerAuthor

    Status after the #626 run: all five stages are merged.

    Stage PR
    AES/ChaCha wipes and -O2 pins #639
    TLS holders #652
    QUIC holders #653
    QUIC server keys #664
    one-shot derivations take and return Secret #665
    • Closed: TLS-2, QUIC-2 and QUIC-5.
    • Open, narrowed: TLS-1 and QUIC-1. Each remainder is key material held in a class field, where a Secret may not be stored (NL2430). Those bytes are still volatile-wiped at every end of life; what's missing is the checker's compile-time guarantees.

    This issue stays open until #668, which lets a Secret be a field, closes TLS-1 and QUIC-1.


    Generated by Claude Code

  4. added a commit that references this issue on Oct 16, 2026
  5. amritk commented on Oct 19, 2026

    @amritk
    OwnerAuthor

    Closing as completed, at the owner's confirmation. The two findings #430's run left Open, narrowed, TLS-1 and QUIC-1, are now Closed by the secret-fields run (#674, plan #668):

    PR change
    #684 Held HKDF, TLS-schedule, record and QUIC derivations into a borrowed Secret.
    #685 A Secret may be a readonly field of a class whose wipe() provably wipes it (NL2540–NL2548). This lifts NL2430 for that shape.
    #705 TlsServer and TlsRecordServer hold their secrets in Secret fields, which closes TLS-1.
    #706 QuicConnection holds its traffic secrets in Secret fields, and quicKeys/quicKeysUpdate write into a caller's slot. This closes QUIC-1, and #668 is fixed.

    Acceptance on main @ 27f86d9 is recorded on #674. On it, npm test passes 21,322 with 0 failed, wasi, performance and bootstrap --verify are green, and each TLS and QUIC secret is read back as zero at each end of life.

    What stays plain, and why, is recorded in docs/security/tls.md and quic.md:

    • per-record keys (NL2448/NL2450);
    • the transient install and KeyUpdate clone;
    • the QUIC reset and config keys, which are not yet held in Secret fields.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions