Summary
The CSA NHP standard describes the 32-byte header HMAC field as a keyed HMAC, such as HMAC-SHA256, over the header excluding the HMAC field plus the payload ciphertext, using key material derived from the Noise chaining key.
Current OpenNHP main names this field HMAC, but the implementation appears to compute a running hash over the header prefix, with optional cookie input for NHP_RKN, rather than a CSA-standard keyed HMAC over header plus payload ciphertext:
nhp/core/initiator.go: initializes mad.hmacHash with NewHash(...) and InitialHashString.
nhp/core/initiator.go: addHMAC writes header.Bytes()[0:header.Size()-HashSize] and optional cookie, then writes the digest into HMACBytes().
nhp/core/initiator.go: body ciphertext is produced after addHMAC, so the payload ciphertext is not part of the HMAC input.
nhp/core/responder.go: checkHMAC reconstructs the same header-prefix digest for verification.
This issue is about spec conformance and interoperability. It is not claiming an immediate auth bypass; the encrypted body still has AEAD protection. The concern is that the wire field's semantics differ from the standard and from the field name.
Why This Matters
A peer implementing the CSA-standard keyed header+payload HMAC will reject OpenNHP packets, and OpenNHP will reject standard packets. The naming can also mislead integrators into assuming the field authenticates more of the packet than it does.
Suggested Acceptance Criteria
- Decide whether OpenNHP should implement the CSA-standard keyed HMAC semantics.
- If yes, add versioned/backward-compatible migration for existing peers.
- Add golden vectors that include header, ciphertext, Noise-derived HMAC key, and expected HMAC.
- If not, document OpenNHP's current field as a non-standard header digest/profile behavior.
Summary
The CSA NHP standard describes the 32-byte header
HMACfield as a keyed HMAC, such as HMAC-SHA256, over the header excluding the HMAC field plus the payload ciphertext, using key material derived from the Noise chaining key.Current OpenNHP
mainnames this fieldHMAC, but the implementation appears to compute a running hash over the header prefix, with optional cookie input forNHP_RKN, rather than a CSA-standard keyed HMAC over header plus payload ciphertext:nhp/core/initiator.go: initializesmad.hmacHashwithNewHash(...)andInitialHashString.nhp/core/initiator.go:addHMACwritesheader.Bytes()[0:header.Size()-HashSize]and optional cookie, then writes the digest intoHMACBytes().nhp/core/initiator.go: body ciphertext is produced afteraddHMAC, so the payload ciphertext is not part of the HMAC input.nhp/core/responder.go:checkHMACreconstructs the same header-prefix digest for verification.This issue is about spec conformance and interoperability. It is not claiming an immediate auth bypass; the encrypted body still has AEAD protection. The concern is that the wire field's semantics differ from the standard and from the field name.
Why This Matters
A peer implementing the CSA-standard keyed header+payload HMAC will reject OpenNHP packets, and OpenNHP will reject standard packets. The naming can also mislead integrators into assuming the field authenticates more of the packet than it does.
Suggested Acceptance Criteria