mirror of
https://github.com/alexhopeoconnor/firmware.git
synced 2026-10-17 09:01:30 +10:00
Signing and ingress hardening (#11282)
* Include warm-tier signers in the identity update gate * Fail the send when PKI encryption fails * Require signatures on licensed unicasts * Include warm-tier signers in the NodeInfo downgrade drop * Clamp hop fields on UDP multicast ingress * Address review comments on signing hardening Condense the updateUser rationale to two lines and stop calling the Balanced-mode drop a broadcast now that licensed unicasts reach it.
This commit is contained in:
+10
-11
@@ -681,20 +681,14 @@ bool checkXeddsaReceivePolicy(meshtastic_MeshPacket *p)
|
||||
if (compatible)
|
||||
return true;
|
||||
|
||||
// In Balanced, preserve legacy unsigned-unicast compatibility and only reject the class a
|
||||
// signing node always signs: a non-PKI broadcast whose signed encoding would still fit the
|
||||
// LoRa frame. Canonical sizing removes unknown protobuf fields before mirroring the
|
||||
// sender-side signedDataFits() gate, so this counts the same fields that gate counted.
|
||||
// Unicast packets and broadcasts too big to carry a signature are never signed, so they
|
||||
// must not be hard-failed here even for a known signer (PKI already returned above).
|
||||
// isKnownXeddsaSigner consults the warm tier too: a signer evicted from the hot store
|
||||
// must not become impersonatable via unsigned broadcasts until it is re-heard.
|
||||
if (nodeDB->isKnownXeddsaSigner(p->from) && isBroadcast(p->to)) {
|
||||
// Balanced rejects only what a signer always signs: non-PKI broadcasts whose signed encoding
|
||||
// would have fit, plus unicasts on ham where licensed senders sign too. Mirrors perhapsEncode.
|
||||
if (nodeDB->isKnownXeddsaSigner(p->from) && (isBroadcast(p->to) || owner.is_licensed)) {
|
||||
size_t canonicalSize;
|
||||
if (!canonicalSignableSize(&p->decoded, &canonicalSize))
|
||||
return true; // can't size it; never drop on a sizing failure
|
||||
if (canonicalSize + XEDDSA_SIGNATURE_FIELD_BYTES + MESHTASTIC_HEADER_LENGTH <= MAX_LORA_PAYLOAD_LEN) {
|
||||
LOG_WARN("Dropping unsigned broadcast from 0x%08x that previously signed", p->from);
|
||||
LOG_WARN("Dropping unsigned packet from 0x%08x that previously signed", p->from);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1172,7 +1166,12 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p)
|
||||
*destKey.bytes);
|
||||
return meshtastic_Routing_Error_PKI_FAILED;
|
||||
}
|
||||
crypto->encryptCurve25519(p->to, getFrom(p), destKey, p->id, numbytes, bytes, p->encrypted.bytes);
|
||||
// On failure encrypted.bytes holds no ciphertext, so continuing would put the plaintext
|
||||
// on the air labelled pki_encrypted.
|
||||
if (!crypto->encryptCurve25519(p->to, getFrom(p), destKey, p->id, numbytes, bytes, p->encrypted.bytes)) {
|
||||
LOG_WARN("PKI encryption failed for destination node 0x%08x", p->to);
|
||||
return meshtastic_Routing_Error_PKI_FAILED;
|
||||
}
|
||||
numbytes += MESHTASTIC_PKC_OVERHEAD;
|
||||
p->channel = 0;
|
||||
p->pki_encrypted = true;
|
||||
|
||||
Reference in New Issue
Block a user