Merge pull request #10967 from RCGV1/codex/packet-auth-policy
This commit is contained in:
@@ -159,7 +159,8 @@ void test_E1_perhaps_decode_fuzz(void)
|
||||
|
||||
DecodeState st = perhapsDecode(&p);
|
||||
// Any verdict is fine; the contract is that arbitrary ciphertext never crashes the pipeline.
|
||||
TEST_ASSERT_TRUE(st == DECODE_SUCCESS || st == DECODE_FAILURE || st == DECODE_FATAL);
|
||||
TEST_ASSERT_TRUE(st == DECODE_SUCCESS || st == DECODE_FAILURE || st == DECODE_OPAQUE || st == DECODE_FATAL ||
|
||||
st == DECODE_POLICY_REJECT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,15 @@ class MockRouter : public Router
|
||||
class MockMeshService : public MeshService
|
||||
{
|
||||
public:
|
||||
// No PhoneAPI reader exists in these tests, so packets the receive pipeline forwards to the phone
|
||||
// (MeshService::sendToPhone enqueues pooled copies into toPhoneQueue) would leak at teardown. Drain
|
||||
// the queue like the phone would. This surfaced once sendLocal() began dispatching local packets
|
||||
// through handleReceived() directly rather than via the (mock-overridden) enqueueReceivedMessage().
|
||||
~MockMeshService()
|
||||
{
|
||||
while (meshtastic_MeshPacket *p = getForPhone())
|
||||
releaseToPool(p);
|
||||
}
|
||||
void sendMqttMessageToClientProxy(meshtastic_MqttClientProxyMessage *m) override
|
||||
{
|
||||
messages_.emplace_back(*m);
|
||||
@@ -334,6 +343,7 @@ const meshtastic_MeshPacket encrypted = {
|
||||
// Initialize mocks and configuration before running each test.
|
||||
void setUp(void)
|
||||
{
|
||||
config = meshtastic_LocalConfig_init_zero;
|
||||
moduleConfig.mqtt =
|
||||
meshtastic_ModuleConfig_MQTTConfig{.enabled = true, .map_reporting_enabled = true, .has_map_report_settings = true};
|
||||
moduleConfig.mqtt.map_report_settings = meshtastic_ModuleConfig_MapReportSettings{
|
||||
@@ -627,6 +637,8 @@ void test_receiveWithoutChannelDownlink(void)
|
||||
// Test receiving an encrypted MeshPacket on the PKI topic.
|
||||
void test_receiveEncryptedPKITopicToUs(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_STRICT;
|
||||
meshtastic_MeshPacket e = encrypted;
|
||||
e.to = myNodeInfo.my_node_num;
|
||||
|
||||
@@ -718,6 +730,8 @@ static meshtastic_MeshPacket makeDecodedBroadcast()
|
||||
// signing node (audit F3).
|
||||
void test_receiveDropsUnsignedBroadcastFromSigner(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_BALANCED;
|
||||
mockNodeDB->emptyNode.bitfield |= NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_MASK;
|
||||
|
||||
const meshtastic_MeshPacket p = makeDecodedBroadcast();
|
||||
@@ -729,6 +743,8 @@ void test_receiveDropsUnsignedBroadcastFromSigner(void)
|
||||
// The same unsigned broadcast from a node never seen signing is accepted.
|
||||
void test_receiveAcceptsUnsignedBroadcastFromNonSigner(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_BALANCED;
|
||||
const meshtastic_MeshPacket p = makeDecodedBroadcast();
|
||||
unitTest->publish(&p);
|
||||
|
||||
@@ -760,6 +776,8 @@ void test_receiveVerifiesSignedDecodedDownlink(void)
|
||||
// A decoded downlink carrying a signature that fails verification is dropped.
|
||||
void test_receiveDropsBadSignatureOnDecodedDownlink(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_COMPATIBLE;
|
||||
uint8_t pub[32], priv[32];
|
||||
crypto->generateKeyPair(pub, priv);
|
||||
mockNodeDB->emptyNode.public_key.size = 32;
|
||||
@@ -775,6 +793,53 @@ void test_receiveDropsBadSignatureOnDecodedDownlink(void)
|
||||
|
||||
TEST_ASSERT_TRUE(mockRouter->packets_.empty());
|
||||
}
|
||||
|
||||
void test_receiveCompatibleAcceptsUnsignedBroadcastFromSigner(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_COMPATIBLE;
|
||||
mockNodeDB->emptyNode.bitfield |= NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_MASK;
|
||||
|
||||
const meshtastic_MeshPacket p = makeDecodedBroadcast();
|
||||
unitTest->publish(&p);
|
||||
|
||||
TEST_ASSERT_EQUAL(1, mockRouter->packets_.size());
|
||||
}
|
||||
|
||||
void test_receiveStrictDropsUnsignedPortnumsAndUnicast(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_STRICT;
|
||||
const meshtastic_PortNum ports[] = {
|
||||
meshtastic_PortNum_TEXT_MESSAGE_APP, meshtastic_PortNum_POSITION_APP, meshtastic_PortNum_TELEMETRY_APP,
|
||||
meshtastic_PortNum_NODEINFO_APP, meshtastic_PortNum_WAYPOINT_APP,
|
||||
};
|
||||
for (const auto port : ports) {
|
||||
meshtastic_MeshPacket p = makeDecodedBroadcast();
|
||||
p.decoded.portnum = port;
|
||||
unitTest->publish(&p);
|
||||
}
|
||||
|
||||
meshtastic_MeshPacket unicast = makeDecodedBroadcast();
|
||||
unicast.to = myNodeInfo.my_node_num;
|
||||
unicast.decoded.portnum = meshtastic_PortNum_POSITION_APP;
|
||||
unitTest->publish(&unicast);
|
||||
|
||||
TEST_ASSERT_TRUE(mockRouter->packets_.empty());
|
||||
}
|
||||
|
||||
// A plaintext broker assertion is not evidence that AES-CCM authentication succeeded locally.
|
||||
void test_receiveStrictDoesNotTrustDecodedPkiFlag(void)
|
||||
{
|
||||
config.security.packet_signature_policy =
|
||||
meshtastic_Config_SecurityConfig_PacketSignaturePolicy_PACKET_SIGNATURE_POLICY_STRICT;
|
||||
meshtastic_MeshPacket p = makeDecodedBroadcast();
|
||||
p.to = myNodeInfo.my_node_num;
|
||||
p.pki_encrypted = true;
|
||||
unitTest->publish(&p);
|
||||
|
||||
TEST_ASSERT_TRUE(mockRouter->packets_.empty());
|
||||
}
|
||||
#endif // !(MESHTASTIC_EXCLUDE_PKI) && !(MESHTASTIC_EXCLUDE_XEDDSA)
|
||||
|
||||
// Only the same fields that are transmitted over LoRa should be set in MQTT messages.
|
||||
@@ -1096,6 +1161,9 @@ void setup()
|
||||
RUN_TEST(test_receiveAcceptsUnsignedBroadcastFromNonSigner);
|
||||
RUN_TEST(test_receiveVerifiesSignedDecodedDownlink);
|
||||
RUN_TEST(test_receiveDropsBadSignatureOnDecodedDownlink);
|
||||
RUN_TEST(test_receiveCompatibleAcceptsUnsignedBroadcastFromSigner);
|
||||
RUN_TEST(test_receiveStrictDropsUnsignedPortnumsAndUnicast);
|
||||
RUN_TEST(test_receiveStrictDoesNotTrustDecodedPkiFlag);
|
||||
#endif
|
||||
RUN_TEST(test_receiveIgnoresUnexpectedFields);
|
||||
RUN_TEST(test_receiveIgnoresInvalidHopLimit);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user