OpenNHP/opennhp · error
extractInitiatorStaticPubKey: unknown cipher scheme
Error message
extractInitiatorStaticPubKey: unknown cipher scheme %d (pubkey length %d)
What it means
The packet header's CipherScheme field holds a value that is neither CIPHER_SCHEME_CURVE (0) nor CIPHER_SCHEME_GMSM (1). extractInitiatorStaticPubKey (and the wider parser) only knows these two schemes, so the decrypted static field cannot be length-validated or trusted. This almost always means a corrupted header or a sender speaking a newer/foreign protocol dialect.
Solutions
- Drop the packet and log the source address; if it repeats from one IP, firewall it as probing.
- Confirm sender and receiver run the same opennhp version with the same CIPHER_SCHEME_* constants.
- Verify relay integrity — a relay that rewrites packets can corrupt header bytes; upgrade or replace it.
- If you genuinely need a new scheme, add it to NewCipherSuite and to every scheme switch (extractInitiatorStaticPubKey, validatePeer) before sending traffic with it.
Example fix
// before (custom sender) hdr.SetCipherScheme(2) // unknown to this server // after hdr.SetCipherScheme(common.CIPHER_SCHEME_CURVE)
Defensive patterns
Strategy: validation
Validate before calling
switch hdr.CipherScheme() {
case common.CIPHER_SCHEME_CURVE, common.CIPHER_SCHEME_GMSM:
// ok
default:
return fmt.Errorf("rejecting packet with unknown cipher scheme %d from %s", hdr.CipherScheme(), remoteAddr)
} Type guard
func isKnownScheme(s int) bool {
return s == common.CIPHER_SCHEME_CURVE || s == common.CIPHER_SCHEME_GMSM
} Try / catch
peerPk, err := extractInitiatorStaticPubKey(dev, ciphers, header)
if err != nil {
log.Error("drop packet scheme=%d from=%s: %v", header.CipherScheme(), remoteAddr, err)
return err // drop; consider short-term ban on repeats from same IP
} Prevention
- Reject unknown schemes early in packet parsing and log the source address.
- Keep CIPHER_SCHEME_* constants identical across all deployments/forks.
- Treat repeated unknown-scheme packets from one IP as scanning and firewall them.
- Version-gate any new scheme so old receivers don't receive it.
When it happens
Trigger: UDP packet corruption flipping the scheme bits in the header; a sender built from a fork that introduced a third cipher scheme value; random internet traffic/scans hitting the hidden UDP port whose bytes happen to parse as a header with an out-of-range scheme.
Common situations: Scanners probing the NHP UDP port; mixed fork/official deployments; memory corruption or relay bugs rewriting header bytes; future scheme added server-side before agents know it (or vice versa).
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- missing connection data for server
- missing remote address
- keepalive packet size is incorrect
- packet header type does not match device
- extractInitiatorStaticPubKey: curve scheme expected
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/06e5708487bae4cf.
Report an issue: GitHub.
Appendix: source
Thrown at nhp/core/responder.go:199
// Validate the length explicitly before returning so future
// breakage manifests as an error here, not as cookie failures
// further down. Pass nil for the dst so Open allocates exactly
// the right size.
peerPk, err := aead.Open(nil, header.NonceBytes(), header.StaticBytes(), chainHash.Sum(nil))
if err != nil {
return nil, fmt.Errorf("extractInitiatorStaticPubKey: open: %w", err)
}
switch header.CipherScheme() {
case common.CIPHER_SCHEME_CURVE:
if len(peerPk) != PublicKeySize {
return nil, fmt.Errorf("extractInitiatorStaticPubKey: curve scheme expected %d-byte pubkey, got %d", PublicKeySize, len(peerPk))
}
case common.CIPHER_SCHEME_GMSM:
if len(peerPk) != PublicKeySizeEx {
return nil, fmt.Errorf("extractInitiatorStaticPubKey: gmsm scheme expected %d-byte pubkey, got %d", PublicKeySizeEx, len(peerPk))
}
default:
return nil, fmt.Errorf("extractInitiatorStaticPubKey: unknown cipher scheme %d (pubkey length %d)", header.CipherScheme(), len(peerPk))
}
return peerPk, nil
}
type ResponderScheme interface {
CreatePacketParserData(d *Device, pd *PacketData) (ppd *PacketParserData, err error)
DerivePacketParserDataFromPrevAssemblerData(mad *MsgAssemblerData, pkt *Packet, initTime int64) (ppd *PacketParserData)
validatePeer(d *Device, ppd *PacketParserData) (err error)
decryptBody(d *Device, ppd *PacketParserData) (err error)
}
type CookieStore struct {
CurrCookie [CookieSize]byte
PrevCookie [CookieSize]byte
LastCookieTime int64
}
func (cs *CookieStore) Set(cookie []byte) {View on GitHub (pinned to 6e04ca5ff0)