mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-07-31 14:02:26 +02:00
Add more aggressive packet validity checking. Closes #315.
This commit is contained in:
@@ -11,6 +11,8 @@ from enum import IntEnum
|
||||
|
||||
import nacl.bindings
|
||||
from Crypto.Cipher import AES
|
||||
from nacl.exceptions import BadSignatureError
|
||||
from nacl.signing import VerifyKey
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -377,6 +379,56 @@ def parse_advertisement(
|
||||
)
|
||||
|
||||
|
||||
# Advertisement layout constants, mirroring firmware MeshCore.h / Mesh.cpp.
|
||||
# pub_key(32) || timestamp(4) || signature(64) || app_data(<= MAX_ADVERT_DATA_SIZE)
|
||||
_ADVERT_PUB_KEY_SIZE = 32
|
||||
_ADVERT_TIMESTAMP_SIZE = 4
|
||||
_ADVERT_SIGNATURE_SIZE = 64
|
||||
_ADVERT_MAX_APP_DATA_SIZE = 32 # firmware MAX_ADVERT_DATA_SIZE
|
||||
_ADVERT_HEADER_SIZE = _ADVERT_PUB_KEY_SIZE + _ADVERT_TIMESTAMP_SIZE + _ADVERT_SIGNATURE_SIZE # 100
|
||||
|
||||
|
||||
def verify_advert_signature(payload: bytes) -> bool:
|
||||
"""Verify a MeshCore advertisement's Ed25519 signature.
|
||||
|
||||
Mirrors the firmware check in ``Mesh.cpp`` ``onRecvPacket()`` for
|
||||
``PAYLOAD_TYPE_ADVERT``: the signed message is
|
||||
``pub_key(32) || timestamp(4) || app_data``, where ``app_data`` is
|
||||
everything following the 64-byte signature, clamped to
|
||||
``MAX_ADVERT_DATA_SIZE`` (32) bytes. The signature is verified against the
|
||||
public key embedded in the advert itself, so a bit-flip in the key, the
|
||||
signed body, or the signature all cause rejection.
|
||||
|
||||
``payload`` must be the advert payload starting at the public key (i.e.
|
||||
``PacketInfo.payload`` for an ADVERT packet). Returns ``True`` only when the
|
||||
signature is valid; any malformed input or verification failure returns
|
||||
``False`` so callers fail closed and never ingest a forged advert.
|
||||
"""
|
||||
if len(payload) < _ADVERT_HEADER_SIZE:
|
||||
return False
|
||||
|
||||
public_key = payload[0:_ADVERT_PUB_KEY_SIZE]
|
||||
signature = payload[_ADVERT_PUB_KEY_SIZE + _ADVERT_TIMESTAMP_SIZE : _ADVERT_HEADER_SIZE]
|
||||
app_data_len = min(len(payload) - _ADVERT_HEADER_SIZE, _ADVERT_MAX_APP_DATA_SIZE)
|
||||
|
||||
# pub_key || timestamp is the contiguous slice payload[0:36]; append app_data.
|
||||
message = (
|
||||
payload[0 : _ADVERT_PUB_KEY_SIZE + _ADVERT_TIMESTAMP_SIZE]
|
||||
+ payload[_ADVERT_HEADER_SIZE : _ADVERT_HEADER_SIZE + app_data_len]
|
||||
)
|
||||
|
||||
try:
|
||||
VerifyKey(public_key).verify(message, signature)
|
||||
return True
|
||||
except BadSignatureError:
|
||||
return False
|
||||
except Exception:
|
||||
# Malformed/non-canonical public key or other unexpected failure — treat
|
||||
# as invalid rather than propagating into the packet pipeline.
|
||||
logger.warning("Advert signature verification errored; treating as invalid", exc_info=True)
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Direct Message (TEXT_MESSAGE) Decryption
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user