Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions Interface/MeshCore_Channel_Interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
baudrate = 115200
channel_idx = 39
channel_name = RNSTunnel
channel_secret = c4d2b6c8254e3b11200f57e95dcb1197
channel_secret = <your-32-hex-char-secret> # openssl rand -hex 16
fragment_delay = 1.5
fragment_timeout = 3600
debug_level = debug
Expand All @@ -88,7 +88,7 @@
transport = remoteterm
remoteterm_url = http://localhost:8000
channel_name = RNSTunnel
channel_secret = c4d2b6c8254e3b11200f57e95dcb1197
channel_secret = <your-32-hex-char-secret> # openssl rand -hex 16
fragment_delay = 1.5
fragment_timeout = 3600
debug_level = debug
Expand All @@ -103,7 +103,7 @@
remoteterm_url = https://host.docker.internal:8000
remoteterm_ssl_verify = false # set false for self-signed certs
channel_name = RNSTunnel
channel_secret = c4d2b6c8254e3b11200f57e95dcb1197
channel_secret = <your-32-hex-char-secret> # openssl rand -hex 16
fragment_delay = 1.5
fragment_timeout = 3600
debug_level = debug
Expand Down Expand Up @@ -243,16 +243,56 @@ def __init__(self, owner, configuration):
self._rt_ssl_ctx = _ctx
RNS.log(
f"MeshCore_Channel_Interface [{self.name}]: "
"SSL certificate verification DISABLED (self-signed cert mode)",
"WARNING — SSL certificate verification DISABLED. "
"This exposes the connection to man-in-the-middle attacks. "
"Only use this for trusted networks with self-signed certs.",
RNS.LOG_WARNING
)
else:
self._rt_ssl_ctx = None

# ---- channel (both modes) ----
self.channel_name = cfg.get("channel_name", "RNSTunnel")
self.channel_secret_hex = cfg.get("channel_secret",
"c4d2b6c8254e3b11200f57e95dcb1197")
self.channel_secret_hex = cfg.get("channel_secret", "")

# Validate channel_secret: refuse to start with a missing or insecure
# default. A known/hardcoded key means traffic is effectively
# unencrypted — any eavesdropper who reads this source can decode and
# inject packets.
_INSECURE_DEFAULTS = (
"",
"00000000000000000000000000000000",
"c4d2b6c8254e3b11200f57e95dcb1197", # old hardcoded default
)
if self.channel_secret_hex.lower().strip() in _INSECURE_DEFAULTS:
RNS.log(
f"MeshCore_Channel_Interface [{self.name}]: CRITICAL — "
f"'channel_secret' is missing or set to an insecure default. "
f"All nodes sharing this interface MUST use a unique secret. "
f"Generate one with: openssl rand -hex 16",
RNS.LOG_CRITICAL
)
raise ValueError(
f"MeshCore_Channel_Interface [{self.name}]: "
"channel_secret is missing or insecure — refusing to start. "
"Set a unique 32-character hex secret (openssl rand -hex 16)."
)

# Validate format: must be valid hex and exactly 16 bytes (32 hex chars)
try:
_secret_bytes = bytes.fromhex(self.channel_secret_hex)
except ValueError:
raise ValueError(
f"MeshCore_Channel_Interface [{self.name}]: "
f"channel_secret is not valid hexadecimal: "
f"'{self.channel_secret_hex[:8]}...'"
)
if len(_secret_bytes) != 16:
raise ValueError(
f"MeshCore_Channel_Interface [{self.name}]: "
f"channel_secret must be exactly 16 bytes (32 hex chars), "
f"got {len(_secret_bytes)} bytes."
)

# conversation_key as RemoteTerm reports it — populated in
# _rt_ensure_channel() once we learn the actual key format RemoteTerm uses.
Expand Down
40 changes: 38 additions & 2 deletions Interface/MeshCore_Dynamic_Interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,44 @@ def __init__(self, owner, configuration):
# --- Channel identity ----------------------------------------------
self.channel_idx = int(str(cfg.get("channel_idx", 0)).strip())
self.channel_name = cfg.get("channel_name", "RNSTunnel")
self.channel_secret_hex = cfg.get("channel_secret",
"00000000000000000000000000000000")
self.channel_secret_hex = cfg.get("channel_secret", "")

# Validate channel_secret: refuse to start with a missing or insecure
# default. A known/all-zeros key means traffic is effectively
# unencrypted — any eavesdropper can decode and inject packets.
_INSECURE_DEFAULTS = (
"",
"00000000000000000000000000000000",
)
if self.channel_secret_hex.lower().strip() in _INSECURE_DEFAULTS:
RNS.log(
f"MeshCore_Dynamic_Interface [{self.name}]: CRITICAL — "
f"'channel_secret' is missing or set to an insecure default. "
f"All nodes sharing this interface MUST use a unique secret. "
f"Generate one with: openssl rand -hex 16",
RNS.LOG_CRITICAL
)
raise ValueError(
f"MeshCore_Dynamic_Interface [{self.name}]: "
"channel_secret is missing or insecure — refusing to start. "
"Set a unique 32-character hex secret (openssl rand -hex 16)."
)

# Validate format: must be valid hex and exactly 16 bytes (32 hex chars)
try:
_secret_bytes = bytes.fromhex(self.channel_secret_hex)
except ValueError:
raise ValueError(
f"MeshCore_Dynamic_Interface [{self.name}]: "
f"channel_secret is not valid hexadecimal: "
f"'{self.channel_secret_hex[:8]}...'"
)
if len(_secret_bytes) != 16:
raise ValueError(
f"MeshCore_Dynamic_Interface [{self.name}]: "
f"channel_secret must be exactly 16 bytes (32 hex chars), "
f"got {len(_secret_bytes)} bytes."
)

# --- Optional radio parameter overrides ----------------------------
self.radio_freq = float(cfg.get("freq", 0))
Expand Down