mirror of
https://github.com/meshtastic/firmware.git
synced 2026-06-15 12:10:42 -04:00
* Test commit for XEdDSA support * Update to Crypto lib in Meshtatic org * Generate a new node identity on key generation (#7628) * Generate a new node identity on key generation * Fixes * Fixes * Fixes * Messed up * Fixes * Update src/modules/AdminModule.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/mesh/NodeDB.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Figured it out! * Cleanup * Update src/mesh/NodeDB.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/mesh/NodeDB.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/modules/AdminModule.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update crypto commit hash * Some fixes for xeddsa pr (#9610) * fix: add null check for getMeshNode() in NodeInfoModule getMeshNode() can return nullptr for unknown nodes. Dereferencing without a check crashes the firmware when receiving NodeInfo from a node not yet in the database. * fix: enforce XEdDSA signature verification and prevent stripping Previously, failed signature verification still allowed the packet through, making signatures purely cosmetic. Now: - Failed verification drops the packet (DECODE_FAILURE) - Successfully verified nodes get HAS_XEDDSA_SIGNED bitfield set - Unsigned packets from previously-signing nodes are rejected - Log levels reduced from WARN/ERROR to DEBUG/WARN as appropriate * fix: include packet metadata in XEdDSA signature The signature now covers [fromNode | packetId | portnum | payload] instead of just the payload bytes. This prevents: - Replay attacks (different packetId fails verification) - Reattribution (different fromNode fails verification) - Portnum redirection (different portnum fails verification) Also adds a key initialization check to xeddsa_sign (returns false if XEdDSA keys are all zeros) and checks the return value in the encode path. * fix: handle existing key pair in AdminModule security config When a user provides both a valid private key and public key via admin config, the crypto engine's DH private key and owner public key were never loaded. DMs and XEdDSA signing would silently break. Add an else branch to load both keys into the crypto engine. * perf: cache Ed25519 public key conversion in xeddsa_verify curve_to_ed_pub() performs field element parsing, inversion, and multiplication on every call. Since packets from the same node tend to arrive in bursts, a single-entry cache avoids repeating this expensive conversion for consecutive packets from one sender. * fix: skip identity cleanup when node number is unchanged createNewIdentity() was called on every generateCryptoKeyPair(), including normal boots where the same key is regenerated. This caused unnecessary NodeDB writes and old-node cleanup logic to run when the node number hadn't actually changed. Also fixes only zeroing byte[0] of the old node's public key instead of clearing the entire array. * fix: replace hardcoded 120 with derived XEDDSA_SIGNATURE_SIZE constant The payload size check for XEdDSA signing used a magic number (120). Replace with a derivation from DATA_PAYLOAD_LEN and XEDDSA_SIGNATURE_SIZE so the limit adjusts automatically if constants change. This also increases the max signable payload from 120 to 169 bytes, which is still safe since the actual encoded size is checked after pb_encode. * fix: add const qualifiers to XEdDSA verify and curve_to_ed_pub inputs pubKey, payload, and signature parameters in xeddsa_verify are input-only and should not be modified. Same for curve_pubkey in curve_to_ed_pub. * chore: remove commented-out old Crypto dependency in portduino.ini * Leave out the admin module change for now --------- Co-authored-by: Jonathan Bennett <jbennett@incomsystems.biz> * trunk * protobuf re-update * Protobufs * Merge resolution fix * Put XEDDSA on the right bit * NodeDB update to new nodeInfoLite accessors, etc * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Refine unsigned packet rejection logic in Router (#10534) * use hardware random to fill the first 32 signature bytes with entropy prior to signing. * Add XEdDSA packet-signing policy tests and update dependencies for macos * Minor fixes * integrate XEdDSA support and update dependencies across multiple modules --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Wessel <github@weebl.me> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com>
393 lines
15 KiB
C++
393 lines
15 KiB
C++
// Tests for XEdDSA packet-signing *policy* — the receive-path accept/reject behavior and the
|
|
// send-path signing policy — as opposed to the raw sign/verify primitive (covered in test_crypto).
|
|
//
|
|
// The decision logic under test lives inside perhapsDecode()/perhapsEncode() (free functions in
|
|
// Router.cpp). It only runs after a packet is decrypted, so every case drives a real
|
|
// encode -> decode round-trip through the default channel (black-box, no production changes).
|
|
//
|
|
// Group A receive-side accept/reject matrix (verify, downgrade protection, signer-bit learning)
|
|
// Group B send-side signing policy (which outgoing packets perhapsEncode signs)
|
|
// Group C NodeInfoModule's stricter "drop unsigned NodeInfo from a known signer" rule
|
|
|
|
#include "MeshTypes.h" // include BEFORE TestUtil.h
|
|
#include "TestUtil.h"
|
|
#include <unity.h>
|
|
|
|
#if !(MESHTASTIC_EXCLUDE_PKI)
|
|
|
|
#include "mesh/Channels.h"
|
|
#include "mesh/CryptoEngine.h"
|
|
#include "mesh/NodeDB.h"
|
|
#include "mesh/Router.h"
|
|
#include "modules/NodeInfoModule.h"
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test fixture identifiers
|
|
// ---------------------------------------------------------------------------
|
|
static constexpr NodeNum LOCAL_NODE = 0x0A0A0A0A;
|
|
static constexpr NodeNum REMOTE_NODE = 0x0B0B0B0B;
|
|
|
|
// A "small" broadcast payload that leaves room for a 64-byte signature (payload + 64 < 233),
|
|
// and an "oversized" one that does not (payload + 64 >= 233) yet still encodes within a LoRa frame.
|
|
static constexpr size_t SMALL_PAYLOAD = 16;
|
|
static constexpr size_t OVERSIZED_PAYLOAD = 180;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// MockNodeDB — inject nodes with controlled public keys / signer bits.
|
|
// Mirrors the pattern in test/test_hop_scaling. meshNodes/numMeshNodes are public on NodeDB.
|
|
// ---------------------------------------------------------------------------
|
|
class MockNodeDB : public NodeDB
|
|
{
|
|
public:
|
|
void clearTestNodes()
|
|
{
|
|
testNodes.clear();
|
|
meshNodes = &testNodes;
|
|
numMeshNodes = 0;
|
|
}
|
|
|
|
// Add a bare node and return a stable handle (fetch via getMeshNode so the pointer stays valid
|
|
// even if the vector reallocates after later adds).
|
|
void addNode(NodeNum num)
|
|
{
|
|
meshtastic_NodeInfoLite node = meshtastic_NodeInfoLite_init_zero;
|
|
node.num = num;
|
|
testNodes.push_back(node);
|
|
meshNodes = &testNodes;
|
|
numMeshNodes = testNodes.size();
|
|
}
|
|
|
|
void setPublicKey(NodeNum num, const uint8_t *pubKey)
|
|
{
|
|
meshtastic_NodeInfoLite *n = getMeshNode(num);
|
|
TEST_ASSERT_NOT_NULL(n);
|
|
n->public_key.size = 32;
|
|
memcpy(n->public_key.bytes, pubKey, 32);
|
|
}
|
|
|
|
void setSignerBit(NodeNum num, bool value)
|
|
{
|
|
meshtastic_NodeInfoLite *n = getMeshNode(num);
|
|
TEST_ASSERT_NOT_NULL(n);
|
|
nodeInfoLiteSetBit(n, NODEINFO_BITFIELD_HAS_XEDDSA_SIGNED_MASK, value);
|
|
}
|
|
|
|
std::vector<meshtastic_NodeInfoLite> testNodes;
|
|
};
|
|
|
|
static MockNodeDB *mockNodeDB = nullptr;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Build a decoded packet with a deterministic payload of the requested size.
|
|
static meshtastic_MeshPacket makeDecoded(NodeNum from, NodeNum to, meshtastic_PortNum port, size_t payloadLen)
|
|
{
|
|
meshtastic_MeshPacket p = meshtastic_MeshPacket_init_zero;
|
|
p.from = from;
|
|
p.to = to;
|
|
p.id = 0x12345678;
|
|
p.channel = 0; // primary channel index (perhapsEncode rewrites this to the channel hash)
|
|
p.which_payload_variant = meshtastic_MeshPacket_decoded_tag;
|
|
p.decoded.portnum = port;
|
|
p.decoded.payload.size = payloadLen;
|
|
for (size_t i = 0; i < payloadLen; i++)
|
|
p.decoded.payload.bytes[i] = (uint8_t)(i & 0xff);
|
|
return p;
|
|
}
|
|
|
|
// Sign a decoded packet with the CryptoEngine's current key — used to simulate a *remote* signer,
|
|
// because perhapsEncode only auto-signs packets that originate from us.
|
|
static void signWithCurrentKey(meshtastic_MeshPacket *p)
|
|
{
|
|
bool ok = crypto->xeddsa_sign(p->from, p->id, p->decoded.portnum, p->decoded.payload.bytes, p->decoded.payload.size,
|
|
p->decoded.xeddsa_signature.bytes);
|
|
TEST_ASSERT_TRUE_MESSAGE(ok, "xeddsa_sign failed in test setup");
|
|
p->decoded.xeddsa_signature.size = XEDDSA_SIGNATURE_SIZE;
|
|
}
|
|
|
|
// Encrypt (perhapsEncode) then decrypt+evaluate (perhapsDecode) the same packet in place.
|
|
static DecodeState roundTrip(meshtastic_MeshPacket *p)
|
|
{
|
|
meshtastic_Routing_Error enc = perhapsEncode(p);
|
|
TEST_ASSERT_EQUAL_MESSAGE(meshtastic_Routing_Error_NONE, enc, "perhapsEncode did not succeed");
|
|
TEST_ASSERT_EQUAL_MESSAGE(meshtastic_MeshPacket_encrypted_tag, p->which_payload_variant,
|
|
"perhapsEncode left packet unencrypted");
|
|
return perhapsDecode(p);
|
|
}
|
|
|
|
static bool remoteSignerBit()
|
|
{
|
|
return nodeInfoLiteHasXeddsaSigned(mockNodeDB->getMeshNode(REMOTE_NODE));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Unity lifecycle
|
|
// ---------------------------------------------------------------------------
|
|
void setUp(void)
|
|
{
|
|
// Clean global config/owner; zeroed config => rebroadcast ALL (no KNOWN_ONLY drop) and
|
|
// security.private_key.size == 0 (PKI encrypt path skipped => simple channel crypto).
|
|
config = meshtastic_LocalConfig_init_zero;
|
|
owner = meshtastic_User_init_zero;
|
|
|
|
mockNodeDB = new MockNodeDB();
|
|
mockNodeDB->clearTestNodes();
|
|
nodeDB = mockNodeDB;
|
|
myNodeInfo.my_node_num = LOCAL_NODE; // drives isFromUs()/getFrom()/isToUs()
|
|
|
|
// Working primary channel with the default PSK so encrypt/decrypt round-trips.
|
|
channels.initDefaults();
|
|
channels.onConfigChanged();
|
|
}
|
|
|
|
void tearDown(void)
|
|
{
|
|
delete mockNodeDB;
|
|
mockNodeDB = nullptr;
|
|
nodeDB = nullptr;
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Group A — receive-side accept/reject matrix
|
|
// ===========================================================================
|
|
|
|
// A1: valid signature from a node whose key we know -> accepted, marked signed, signer bit learned.
|
|
void test_A1_valid_signature_accepted_and_learns_signer(void)
|
|
{
|
|
uint8_t pub[32], priv[32];
|
|
crypto->generateKeyPair(pub, priv); // engine now holds REMOTE's key
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setPublicKey(REMOTE_NODE, pub);
|
|
|
|
TEST_ASSERT_FALSE(remoteSignerBit()); // not known as a signer yet
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, SMALL_PAYLOAD);
|
|
signWithCurrentKey(&p);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
TEST_ASSERT_TRUE(p.xeddsa_signed);
|
|
TEST_ASSERT_TRUE_MESSAGE(remoteSignerBit(), "verified signature must set the signer bit");
|
|
}
|
|
|
|
// A2: a tampered signature from a known key -> dropped.
|
|
void test_A2_bad_signature_dropped(void)
|
|
{
|
|
uint8_t pub[32], priv[32];
|
|
crypto->generateKeyPair(pub, priv);
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setPublicKey(REMOTE_NODE, pub);
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, SMALL_PAYLOAD);
|
|
signWithCurrentKey(&p);
|
|
p.decoded.xeddsa_signature.bytes[0] ^= 0xFF; // corrupt the signature
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_FAILURE, roundTrip(&p));
|
|
}
|
|
|
|
// A3: signed packet but we have no key for the sender -> accepted unverified, signer bit NOT set.
|
|
void test_A3_signed_no_pubkey_accepted_unverified(void)
|
|
{
|
|
uint8_t pub[32], priv[32];
|
|
crypto->generateKeyPair(pub, priv);
|
|
mockNodeDB->addNode(REMOTE_NODE); // node exists, but no public key stored
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, SMALL_PAYLOAD);
|
|
signWithCurrentKey(&p);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
TEST_ASSERT_FALSE_MESSAGE(p.xeddsa_signed, "cannot be marked verified without a key");
|
|
TEST_ASSERT_FALSE_MESSAGE(remoteSignerBit(), "must not learn signer without verifying");
|
|
}
|
|
|
|
// A4: downgrade protection — unsigned small broadcast from a known signer -> dropped.
|
|
void test_A4_downgrade_unsigned_broadcast_from_signer_dropped(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setSignerBit(REMOTE_NODE, true); // we've seen this node sign before
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, SMALL_PAYLOAD);
|
|
// from != us, so perhapsEncode leaves it unsigned.
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_FAILURE, roundTrip(&p));
|
|
}
|
|
|
|
// A5: no prior knowledge — unsigned small broadcast from a non-signer -> accepted.
|
|
void test_A5_unsigned_broadcast_from_nonsigner_accepted(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE); // signer bit clear
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, SMALL_PAYLOAD);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
TEST_ASSERT_FALSE(p.xeddsa_signed);
|
|
}
|
|
|
|
// A6: unsigned UNICAST from a known signer -> accepted (unicasts are never signed).
|
|
void test_A6_unsigned_unicast_from_signer_accepted(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setSignerBit(REMOTE_NODE, true);
|
|
|
|
// Unicast to us; PRIVATE_APP avoids the unrelated legacy-DM rejection for TEXT_MESSAGE_APP.
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, LOCAL_NODE, meshtastic_PortNum_PRIVATE_APP, SMALL_PAYLOAD);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
}
|
|
|
|
// A7: unsigned OVERSIZED broadcast from a known signer -> accepted (couldn't have carried a sig).
|
|
void test_A7_unsigned_oversized_broadcast_from_signer_accepted(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setSignerBit(REMOTE_NODE, true);
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, OVERSIZED_PAYLOAD);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Group B — send-side signing policy (perhapsEncode)
|
|
// ===========================================================================
|
|
|
|
// B1: our own small broadcast is auto-signed (and verifies on the way back in).
|
|
void test_B1_local_broadcast_is_signed(void)
|
|
{
|
|
uint8_t pub[32], priv[32];
|
|
crypto->generateKeyPair(pub, priv); // engine signs with this; store the matching pubkey for us
|
|
mockNodeDB->addNode(LOCAL_NODE);
|
|
mockNodeDB->setPublicKey(LOCAL_NODE, pub);
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(LOCAL_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, SMALL_PAYLOAD);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
TEST_ASSERT_EQUAL_MESSAGE(XEDDSA_SIGNATURE_SIZE, p.decoded.xeddsa_signature.size, "broadcast should be auto-signed");
|
|
TEST_ASSERT_TRUE(p.xeddsa_signed);
|
|
}
|
|
|
|
// B2: our own unicast is NOT signed.
|
|
void test_B2_local_unicast_not_signed(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
|
|
meshtastic_MeshPacket p = makeDecoded(LOCAL_NODE, REMOTE_NODE, meshtastic_PortNum_PRIVATE_APP, SMALL_PAYLOAD);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, p.decoded.xeddsa_signature.size, "unicast must not be signed");
|
|
}
|
|
|
|
// B3: our own oversized broadcast is NOT signed (signature wouldn't fit).
|
|
void test_B3_local_oversized_broadcast_not_signed(void)
|
|
{
|
|
meshtastic_MeshPacket p = makeDecoded(LOCAL_NODE, NODENUM_BROADCAST, meshtastic_PortNum_TEXT_MESSAGE_APP, OVERSIZED_PAYLOAD);
|
|
|
|
TEST_ASSERT_EQUAL(DECODE_SUCCESS, roundTrip(&p));
|
|
TEST_ASSERT_EQUAL_MESSAGE(0, p.decoded.xeddsa_signature.size, "oversized broadcast must not be signed");
|
|
}
|
|
|
|
// ===========================================================================
|
|
// Group C — NodeInfoModule downgrade drop (stricter: any unsigned NodeInfo from a known signer)
|
|
// ===========================================================================
|
|
class NodeInfoTestShim : public NodeInfoModule
|
|
{
|
|
public:
|
|
using NodeInfoModule::handleReceivedProtobuf; // protected virtual -> exposed for direct call
|
|
};
|
|
|
|
static meshtastic_MeshPacket makeNodeInfoPacket(bool signed_)
|
|
{
|
|
// Broadcast so the module's phone-forward path (which needs `service`) is skipped.
|
|
meshtastic_MeshPacket mp = makeDecoded(REMOTE_NODE, NODENUM_BROADCAST, meshtastic_PortNum_NODEINFO_APP, SMALL_PAYLOAD);
|
|
mp.xeddsa_signed = signed_;
|
|
return mp;
|
|
}
|
|
|
|
// C1: unsigned NodeInfo from a node that previously signed -> dropped.
|
|
void test_C1_unsigned_nodeinfo_from_signer_dropped(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setSignerBit(REMOTE_NODE, true);
|
|
|
|
NodeInfoTestShim shim;
|
|
meshtastic_MeshPacket mp = makeNodeInfoPacket(/*signed_=*/false);
|
|
meshtastic_User user = meshtastic_User_init_zero;
|
|
user.is_licensed = owner.is_licensed;
|
|
|
|
TEST_ASSERT_TRUE_MESSAGE(shim.handleReceivedProtobuf(mp, &user), "unsigned NodeInfo from signer must be dropped");
|
|
}
|
|
|
|
// C2: signed NodeInfo from a known signer -> not dropped by this rule.
|
|
void test_C2_signed_nodeinfo_from_signer_not_dropped(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE);
|
|
mockNodeDB->setSignerBit(REMOTE_NODE, true);
|
|
|
|
NodeInfoTestShim shim;
|
|
meshtastic_MeshPacket mp = makeNodeInfoPacket(/*signed_=*/true);
|
|
meshtastic_User user = meshtastic_User_init_zero;
|
|
user.is_licensed = owner.is_licensed;
|
|
|
|
TEST_ASSERT_FALSE(shim.handleReceivedProtobuf(mp, &user));
|
|
}
|
|
|
|
// C3: unsigned NodeInfo from a node we've never seen sign -> not dropped.
|
|
void test_C3_unsigned_nodeinfo_from_nonsigner_not_dropped(void)
|
|
{
|
|
mockNodeDB->addNode(REMOTE_NODE); // signer bit clear
|
|
|
|
NodeInfoTestShim shim;
|
|
meshtastic_MeshPacket mp = makeNodeInfoPacket(/*signed_=*/false);
|
|
meshtastic_User user = meshtastic_User_init_zero;
|
|
user.is_licensed = owner.is_licensed;
|
|
|
|
TEST_ASSERT_FALSE(shim.handleReceivedProtobuf(mp, &user));
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
initializeTestEnvironment();
|
|
UNITY_BEGIN();
|
|
|
|
printf("\n=== Group A: receive-side accept/reject ===\n");
|
|
RUN_TEST(test_A1_valid_signature_accepted_and_learns_signer);
|
|
RUN_TEST(test_A2_bad_signature_dropped);
|
|
RUN_TEST(test_A3_signed_no_pubkey_accepted_unverified);
|
|
RUN_TEST(test_A4_downgrade_unsigned_broadcast_from_signer_dropped);
|
|
RUN_TEST(test_A5_unsigned_broadcast_from_nonsigner_accepted);
|
|
RUN_TEST(test_A6_unsigned_unicast_from_signer_accepted);
|
|
RUN_TEST(test_A7_unsigned_oversized_broadcast_from_signer_accepted);
|
|
|
|
printf("\n=== Group B: send-side signing policy ===\n");
|
|
RUN_TEST(test_B1_local_broadcast_is_signed);
|
|
RUN_TEST(test_B2_local_unicast_not_signed);
|
|
RUN_TEST(test_B3_local_oversized_broadcast_not_signed);
|
|
|
|
printf("\n=== Group C: NodeInfoModule downgrade drop ===\n");
|
|
RUN_TEST(test_C1_unsigned_nodeinfo_from_signer_dropped);
|
|
RUN_TEST(test_C2_signed_nodeinfo_from_signer_not_dropped);
|
|
RUN_TEST(test_C3_unsigned_nodeinfo_from_nonsigner_not_dropped);
|
|
|
|
exit(UNITY_END());
|
|
}
|
|
|
|
void loop() {}
|
|
|
|
#else // MESHTASTIC_EXCLUDE_PKI
|
|
|
|
void setUp(void) {}
|
|
void tearDown(void) {}
|
|
void setup()
|
|
{
|
|
initializeTestEnvironment();
|
|
UNITY_BEGIN();
|
|
exit(UNITY_END());
|
|
}
|
|
void loop() {}
|
|
|
|
#endif
|