Accept a pending key only for the key-verification exchange (#11107)
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.
This commit is contained in:
co-authored by
GitHub
parent
61750d9118
commit
d9f8839241
@@ -202,6 +202,33 @@ void test_wrong_admin_key_does_not_decode(void)
|
||||
TEST_ASSERT_NULL(mockNodeDB->getMeshNode(ADMIN_NODE));
|
||||
}
|
||||
|
||||
// A pending key is an unverified identity claim from whoever opened a key-verification handshake, so it
|
||||
// must decrypt only the exchange itself. Otherwise they could send DMs that look PKI-authenticated as a
|
||||
// node they never proved they are.
|
||||
void test_pending_key_decrypts_only_key_verification(void)
|
||||
{
|
||||
// PEER is unknown to us; the handshake stashed its claimed key as pending.
|
||||
static constexpr NodeNum PEER = 0x0C0C0C0C;
|
||||
uint8_t peerPub[32], peerPriv[32];
|
||||
crypto->generateKeyPair(peerPub, peerPriv);
|
||||
crypto->setDHPrivateKey(ourPriv); // generateKeyPair changed it
|
||||
crypto->setPendingPublicKey(PEER, peerPub);
|
||||
|
||||
// A DM on any other port must not decode, even though the pending key would decrypt it.
|
||||
meshtastic_MeshPacket spoofed = makePkiPacket(PEER, meshtastic_PortNum_TEXT_MESSAGE_APP, 16, peerPriv);
|
||||
TEST_ASSERT_NOT_EQUAL_MESSAGE(DECODE_SUCCESS, perhapsDecode(&spoofed), "pending key must not decrypt a text DM");
|
||||
TEST_ASSERT_FALSE_MESSAGE(spoofed.pki_encrypted, "spoofed DM must not be marked PKI-authenticated");
|
||||
|
||||
// The key-verification exchange itself still works, so bootstrapping is unaffected.
|
||||
meshtastic_MeshPacket handshake = makePkiPacket(PEER, meshtastic_PortNum_KEY_VERIFICATION_APP, 16, peerPriv);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(DECODE_SUCCESS, perhapsDecode(&handshake), "key verification must still decrypt");
|
||||
TEST_ASSERT_TRUE(handshake.pki_encrypted);
|
||||
|
||||
// A pending key is never persisted, so the peer stays unknown until verification commits it.
|
||||
TEST_ASSERT_NULL_MESSAGE(mockNodeDB->getMeshNode(PEER), "pending key must not be learned into NodeDB");
|
||||
crypto->clearPendingPublicKey();
|
||||
}
|
||||
|
||||
#endif // !(MESHTASTIC_EXCLUDE_PKI)
|
||||
|
||||
void setup()
|
||||
@@ -216,6 +243,7 @@ void setup()
|
||||
RUN_TEST(test_admin_key_slot2_only_decrypts);
|
||||
RUN_TEST(test_no_admin_key_unknown_sender_not_decoded);
|
||||
RUN_TEST(test_wrong_admin_key_does_not_decode);
|
||||
RUN_TEST(test_pending_key_decrypts_only_key_verification);
|
||||
#endif
|
||||
exit(UNITY_END());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user