From 4e1541f489be31a97f713ece3eb4b2b5c9334b3d Mon Sep 17 00:00:00 2001 From: Johnathan Corgan Date: Tue, 25 Aug 2026 20:19:56 +0100 Subject: [PATCH] Record why the session's handshake hash is not cleared on drop `SymmetricState` gained a `Zeroize` derive with the key-material work, so the handshake hash it holds is erased when the handshake state drops. The value does not stay there: `into_session` copies it into `NoiseSession`, which outlives the handshake by the life of the link and clears nothing. The copy is fine where it is. The hash is a transcript hash, no key is derived from it in this crate, and `handshake_hash()` publishes it to any caller, so treating it as secret in one type while handing it out from another would be incoherent. What was wrong was that the declaration said none of this, leaving the reader to guess whether the omission was an oversight. Say it at the field, and name the change that would make the answer different. (cherry picked from commit 88ca5f09c37fbfc7674c8385c611f9094e7d3a92) --- src/noise/session.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/noise/session.rs b/src/noise/session.rs index 92a8a059..99d17ac5 100644 --- a/src/noise/session.rs +++ b/src/noise/session.rs @@ -14,7 +14,17 @@ pub struct NoiseSession { send_cipher: CipherState, /// Cipher for receiving. recv_cipher: CipherState, - /// Handshake hash. + /// Handshake hash, copied out of the handshake's `SymmetricState`. + /// + /// Deliberately not cleared on drop, unlike the copy it came from. That + /// copy is cleared because it sits beside the chaining key in a type whose + /// contract is that it erases what it holds; this one is a transcript hash + /// that nothing derives a key from, and `handshake_hash()` hands it out to + /// any caller. A type cannot both publish a value and treat it as secret. + /// + /// Revisit if the hash ever becomes key-adjacent: feeding it to the AEAD as + /// associated data, or building channel binding or an exporter on it, would + /// make this session's copy the long-lived home of something worth erasing. handshake_hash: [u8; 32], /// Remote peer's static public key. remote_static: PublicKey,