Accept a pending key only for the key-verification exchange#11107
Conversation
perhapsDecode fell back to the not-yet-verified key held during a key verification handshake for any incoming PKI unicast. That key is supplied by whoever opened the handshake and proves only that they hold it, not that they are the node they claim to be, so until the session ended they could send DMs on any port that decrypted and were marked pki_encrypted. perhapsEncode already restricts the pending key to KEY_VERIFICATION_APP. The receive path now applies the same rule.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughPKI decryption now distinguishes persisted keys from pending verification keys and rejects pending-key packets outside ChangesPending PKI key security
Estimated code review effort: 3 (Moderate) | ~15–30 minutes Sequence Diagram(s)sequenceDiagram
participant IncomingPacket
participant RouterPerhapsDecode
participant PendingVerification
participant NodeDB
IncomingPacket->>RouterPerhapsDecode: encrypted packet
RouterPerhapsDecode->>PendingVerification: resolve pending public key
RouterPerhapsDecode->>NodeDB: resolve persisted public key
RouterPerhapsDecode->>RouterPerhapsDecode: decrypt and decode packet
RouterPerhapsDecode->>RouterPerhapsDecode: allow pending-key result only for KEY_VERIFICATION_APP
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
⚡ Try this PR in the Web FlasherWarning This is an automated, unreviewed CI test build. Back up your device configuration Supported boards built by this PR (30)
Build artifacts expire on 2026-08-19. Updated for |
Router::perhapsDecoderesolved the sender's key as NodeDB first, else the pending key held during an in-progress key-verification handshake, and then used it for any incoming PKI unicast.That pending key is whatever 32 bytes the initiator put in
hash1.KeyVerificationModule::allocReplystashes it for the claimedfromwhenever that node is not already in NodeDB, which is exactly the bootstrap case. It proves only that the sender holds the key, not that they are the node they claim to be, andgetPendingPublicKeyhas no expiry of its own.So an attacker could open a handshake claiming to be an unknown node, then send DMs on any port as that node. They decrypted, were marked
pki_encrypted, and carried the attacker's key inpublic_key, until the session was reset.perhapsEncodealready restricts the pending key toKEY_VERIFICATION_APPwhen choosing a destination key. The receive path now applies the same rule: a decrypt that used the pending key is rejected unless the payload is the key-verification exchange itself. Keys resolved from NodeDB and the admin-key fallback are unchanged, and a pending key is still never persisted.Bootstrapping is unaffected, since the follow-on handshake packet is on that port.
Adds a regression test: a text DM encrypted with a pending key no longer decodes and is not marked PKI-authenticated, while the key-verification packet still decodes. Verified the test fails without the fix.
Summary by CodeRabbit