{"record":{"id":"06e5708487bae4cf","repo":"OpenNHP/opennhp","slug":"extractinitiatorstaticpubkey-unknown-cipher-schem","errorCode":null,"errorMessage":"extractInitiatorStaticPubKey: unknown cipher scheme %d (pubkey length %d)","messagePattern":"extractInitiatorStaticPubKey: unknown cipher scheme (.+?) \\(pubkey length (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/core/responder.go","lineNumber":199,"sourceCode":"\t// Validate the length explicitly before returning so future\n\t// breakage manifests as an error here, not as cookie failures\n\t// further down. Pass nil for the dst so Open allocates exactly\n\t// the right size.\n\tpeerPk, err := aead.Open(nil, header.NonceBytes(), header.StaticBytes(), chainHash.Sum(nil))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"extractInitiatorStaticPubKey: open: %w\", err)\n\t}\n\tswitch header.CipherScheme() {\n\tcase common.CIPHER_SCHEME_CURVE:\n\t\tif len(peerPk) != PublicKeySize {\n\t\t\treturn nil, fmt.Errorf(\"extractInitiatorStaticPubKey: curve scheme expected %d-byte pubkey, got %d\", PublicKeySize, len(peerPk))\n\t\t}\n\tcase common.CIPHER_SCHEME_GMSM:\n\t\tif len(peerPk) != PublicKeySizeEx {\n\t\t\treturn nil, fmt.Errorf(\"extractInitiatorStaticPubKey: gmsm scheme expected %d-byte pubkey, got %d\", PublicKeySizeEx, len(peerPk))\n\t\t}\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"extractInitiatorStaticPubKey: unknown cipher scheme %d (pubkey length %d)\", header.CipherScheme(), len(peerPk))\n\t}\n\treturn peerPk, nil\n}\n\ntype ResponderScheme interface {\n\tCreatePacketParserData(d *Device, pd *PacketData) (ppd *PacketParserData, err error)\n\tDerivePacketParserDataFromPrevAssemblerData(mad *MsgAssemblerData, pkt *Packet, initTime int64) (ppd *PacketParserData)\n\tvalidatePeer(d *Device, ppd *PacketParserData) (err error)\n\tdecryptBody(d *Device, ppd *PacketParserData) (err error)\n}\n\ntype CookieStore struct {\n\tCurrCookie     [CookieSize]byte\n\tPrevCookie     [CookieSize]byte\n\tLastCookieTime int64\n}\n\nfunc (cs *CookieStore) Set(cookie []byte) {","sourceCodeStart":181,"sourceCodeEnd":217,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/responder.go#L181-L217","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":"// before (custom sender)\nhdr.SetCipherScheme(2) // unknown to this server\n// after\nhdr.SetCipherScheme(common.CIPHER_SCHEME_CURVE)","handlingStrategy":"validation","validationCode":"switch hdr.CipherScheme() {\ncase common.CIPHER_SCHEME_CURVE, common.CIPHER_SCHEME_GMSM:\n\t// ok\ndefault:\n\treturn fmt.Errorf(\"rejecting packet with unknown cipher scheme %d from %s\", hdr.CipherScheme(), remoteAddr)\n}","typeGuard":"func isKnownScheme(s int) bool {\n\treturn s == common.CIPHER_SCHEME_CURVE || s == common.CIPHER_SCHEME_GMSM\n}","tryCatchPattern":"peerPk, err := extractInitiatorStaticPubKey(dev, ciphers, header)\nif err != nil {\n\tlog.Error(\"drop packet scheme=%d from=%s: %v\", header.CipherScheme(), remoteAddr, err)\n\treturn err // drop; consider short-term ban on repeats from same IP\n}","preventionTips":["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."],"tags":["go","protocol","unknown-cipher-scheme","invalid-header"],"backgroundTag":"invalid-enum-value","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}