Gate identity learning on signature in NodeDB::updateUser (#11084)

This commit is contained in:
Thomas Göttgens
2026-07-20 11:56:42 +02:00
committed by GitHub
co-authored by GitHub
parent 405a6bfd8a
commit 5ded0ec8c5
5 changed files with 96 additions and 7 deletions
+8 -1
View File
@@ -3310,13 +3310,20 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact)
/** Update user info and channel for this node based on received user data
*/
bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex)
bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex, bool xeddsaSigned)
{
meshtastic_NodeInfoLite *info = getOrCreateMeshNode(nodeId);
if (!info) {
return false;
}
// Once a node has proven it signs, only a signed update may change its identity. The public-key guard
// below is no help - an attacker can replay the victim's real (public) key. Our own record is exempt.
if (nodeId != getNodeNum() && nodeInfoLiteHasXeddsaSigned(info) && !xeddsaSigned) {
LOG_WARN("Refusing unsigned identity update for node 0x%08x that previously signed", nodeId);
return false;
}
#if !(MESHTASTIC_EXCLUDE_PKI)
if (p.public_key.size == 32 && nodeId != nodeDB->getNodeNum()) {
printBytes("Incoming Pubkey: ", p.public_key.bytes, 32);
+3 -3
View File
@@ -255,9 +255,9 @@ class NodeDB
*/
void updateTelemetry(uint32_t nodeId, const meshtastic_Telemetry &t, RxSource src = RX_SRC_RADIO);
/** Update user info and channel for this node based on received user data
*/
bool updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex = 0);
/** Update user info and channel for this node based on received user data.
* A known signer's identity is only learned when xeddsaSigned; defaults false so callers fail closed. */
bool updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelIndex = 0, bool xeddsaSigned = false);
/*
* Sets a node either favorite or unfavorite. Returns true if the node ends
+3 -1
View File
@@ -61,7 +61,9 @@ bool NodeInfoModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
// Coerce user.id to be derived from the node number
snprintf(p.id, sizeof(p.id), "!%08x", getFrom(&mp));
bool hasChanged = nodeDB->updateUser(getFrom(&mp), p, mp.channel);
// updateUser() refuses the identity write for a known signer sending unsigned (all unicast
// NodeInfo), so the exchange above still proceeds but cannot spoof the stored name.
bool hasChanged = nodeDB->updateUser(getFrom(&mp), p, mp.channel, mp.xeddsa_signed);
bool wasBroadcast = isBroadcast(mp.to);
+1 -1
View File
@@ -734,7 +734,7 @@ ProcessMessage TrafficManagementModule::handleReceived(const meshtastic_MeshPack
meshtastic_User requester = meshtastic_User_init_zero;
if (!unauthenticatedSigner &&
pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, &meshtastic_User_msg, &requester)) {
nodeDB->updateUser(getFrom(&mp), requester, mp.channel);
nodeDB->updateUser(getFrom(&mp), requester, mp.channel, mp.xeddsa_signed);
}
logAction("respond", &mp, "nodeinfo-cache");
incrementStat(&stats.nodeinfo_cache_hits);