Fix: Capture handshake hash before split() clears symmetric state

Addresses Codex review feedback on PR #948: the getTransportCiphers()
method now returns the handshake hash as part of its return tuple,
capturing it BEFORE split() calls clearSensitiveData().

Previously, calling getHandshakeHash() after getTransportCiphers()
would return an all-zero value since split() clears the symmetric
state. This broke channel binding functionality.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jack
2026-01-12 11:32:17 -10:00
co-authored by Claude Opus 4.5
parent f41a390a94
commit b533d9560d
2 changed files with 23 additions and 19 deletions
+8 -4
View File
@@ -833,16 +833,20 @@ final class NoiseHandshakeState {
return currentPattern >= messagePatterns.count
}
func getTransportCiphers(useExtractedNonce: Bool) throws -> (send: NoiseCipherState, receive: NoiseCipherState) {
func getTransportCiphers(useExtractedNonce: Bool) throws -> (send: NoiseCipherState, receive: NoiseCipherState, handshakeHash: Data) {
guard isHandshakeComplete() else {
throw NoiseError.handshakeNotComplete
}
// BCH-01-010: Capture handshake hash BEFORE split() clears symmetric state
let finalHandshakeHash = symmetricState.getHandshakeHash()
let (c1, c2) = symmetricState.split(useExtractedNonce: useExtractedNonce)
// Initiator uses c1 for sending, c2 for receiving
// Responder uses c2 for sending, c1 for receiving
return role == .initiator ? (c1, c2) : (c2, c1)
let ciphers = role == .initiator ? (c1, c2) : (c2, c1)
return (send: ciphers.0, receive: ciphers.1, handshakeHash: finalHandshakeHash)
}
func getRemoteStaticPublicKey() -> Curve25519.KeyAgreement.PublicKey? {