Files
Shadowbroker/backend/services/mesh/mesh_wormhole_prekey.py
T
BigBodyCobain 7151563a41 Fix Extra-participant E2E: live contact send and Tor prekey cache path.
Adds connect-contact HTTP endpoint with cached-bundle support, subprocess contact send via docker cp bundle file, and direct Tor prekey fetch to avoid wedging single-worker uvicorn.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 17:00:13 -06:00

1585 lines
68 KiB
Python

"""Wormhole-managed prekey bundles and X3DH-style bootstrap helpers."""
from __future__ import annotations
import base64
import hashlib
import hmac
import json
import logging
import os
import random
import time
import urllib.error
import urllib.parse
import urllib.request
from typing import Any
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ed25519, x25519
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.serialization import Encoding, NoEncryption, PrivateFormat, PublicFormat
from services.mesh.mesh_compatibility import (
LEGACY_AGENT_ID_LOOKUP_TARGET,
legacy_agent_id_lookup_blocked,
record_legacy_agent_id_lookup,
sunset_target_label,
)
from services.mesh.mesh_metadata_exposure import stable_metadata_log_ref
from services.mesh.mesh_crypto import build_signature_payload, derive_node_id, verify_node_binding, verify_signature
from services.mesh.mesh_wormhole_identity import (
_write_identity,
bootstrap_wormhole_identity,
get_prekey_lookup_handle_records,
read_wormhole_identity,
root_identity_fingerprint_for_material,
sign_wormhole_event,
sign_wormhole_message,
trust_fingerprint_for_identity_material,
)
from services.mesh.mesh_wormhole_persona import sign_root_wormhole_event
from services.mesh.mesh_protocol import PROTOCOL_VERSION
PREKEY_TARGET = 8
PREKEY_MIN_THRESHOLD = 3
PREKEY_MAX_THRESHOLD = 5
PREKEY_MIN_TARGET = 7
PREKEY_MAX_TARGET = 9
PREKEY_MIN_REPUBLISH_DELAY_S = 45
PREKEY_MAX_REPUBLISH_DELAY_S = 120
PREKEY_REPUBLISH_THRESHOLD_RANGE = (PREKEY_MIN_THRESHOLD, PREKEY_MAX_THRESHOLD)
PREKEY_REPUBLISH_TARGET_RANGE = (PREKEY_MIN_TARGET, PREKEY_MAX_TARGET)
PREKEY_REPUBLISH_DELAY_RANGE_S = (PREKEY_MIN_REPUBLISH_DELAY_S, PREKEY_MAX_REPUBLISH_DELAY_S)
SIGNED_PREKEY_ROTATE_AFTER_S = 24 * 60 * 60
SIGNED_PREKEY_GRACE_S = 3 * 24 * 60 * 60
DM_PREKEY_ROOT_ATTESTATION_EVENT_TYPE = "dm_prekey_root_attestation"
DM_PREKEY_ROOT_ATTESTATION_TYPE = "stable_dm_root"
logger = logging.getLogger(__name__)
_WARNED_LEGACY_PREKEY_LOOKUPS: set[str] = set()
def _safe_int(val, default=0) -> int:
try:
return int(val)
except (TypeError, ValueError):
return default
def _warn_legacy_prekey_lookup(agent_id: str) -> None:
peer_id = str(agent_id or "").strip().lower()
if not peer_id or peer_id in _WARNED_LEGACY_PREKEY_LOOKUPS:
return
_WARNED_LEGACY_PREKEY_LOOKUPS.add(peer_id)
logger.warning(
"mesh legacy prekey lookup used for %s via direct agent_id; prefer invite-scoped lookup handles before removal in %s",
stable_metadata_log_ref(peer_id, prefix="peer"),
sunset_target_label(LEGACY_AGENT_ID_LOOKUP_TARGET),
)
def _fleet_peer_lookup_user_agent() -> str:
custom = str(os.environ.get("SHADOWBROKER_MESH_PEER_USER_AGENT") or "").strip()
if custom:
return custom
return "Mozilla/5.0 (compatible; ShadowbrokerMesh/1.0)"
_INVITE_LOOKUP_MAX_ELAPSED_S = 120
_INVITE_LOOKUP_MAX_BOOTSTRAP_PEERS = 3
_INVITE_LOOKUP_MAX_PUSH_PEERS = 16
_INVITE_LOOKUP_PARALLEL_WORKERS = 8
def _invite_lookup_request_timeout(peer_url: str) -> tuple[int, int]:
from services.mesh.mesh_router import peer_transport_kind
if peer_transport_kind(peer_url) == "onion":
return (10, 35)
return (5, 15)
def _bootstrap_seed_peer_urls() -> set[str]:
try:
from services.config import get_settings
from services.mesh.mesh_router import parse_configured_relay_peers
seeds: set[str] = set()
raw = str(getattr(get_settings(), "MESH_BOOTSTRAP_SEED_PEERS", "") or "")
for peer in parse_configured_relay_peers(raw):
normalized = str(peer or "").strip().rstrip("/")
if normalized:
seeds.add(normalized)
return seeds
except Exception:
return set()
def _discovered_push_peer_urls(*, limit: int = _INVITE_LOOKUP_MAX_PUSH_PEERS) -> list[str]:
try:
from services.mesh.mesh_router import authenticated_push_peer_urls
seeds = _bootstrap_seed_peer_urls()
peers: list[str] = []
for peer in authenticated_push_peer_urls():
normalized = str(peer or "").strip().rstrip("/")
if not normalized or normalized in seeds:
continue
peers.append(normalized)
if len(peers) >= max(1, int(limit or 1)):
break
return peers
except Exception:
return []
def _prioritized_invite_lookup_peer_urls(*, preferred: list[str] | None = None) -> list[str]:
preferred_urls = [
str(peer or "").strip().rstrip("/")
for peer in list(preferred or [])
if str(peer or "").strip()
]
configured = _configured_public_lookup_peer_urls()
seeds = _bootstrap_seed_peer_urls()
active: list[str] = []
bootstrap: list[str] = []
push_discovery: list[str] = []
seen = set(preferred_urls)
for peer in configured:
if peer in seen:
continue
seen.add(peer)
if peer in seeds:
bootstrap.append(peer)
else:
active.append(peer)
for peer in _discovered_push_peer_urls():
if peer in seen:
continue
seen.add(peer)
push_discovery.append(peer)
ordered = list(preferred_urls)
ordered.extend(active)
ordered.extend(push_discovery)
ordered.extend(bootstrap[:_INVITE_LOOKUP_MAX_BOOTSTRAP_PEERS])
return ordered
def _preferred_invite_lookup_peer_urls(lookup_token: str) -> list[str]:
token = str(lookup_token or "").strip()
if not token:
return []
try:
from services.mesh.mesh_wormhole_contacts import list_wormhole_dm_contacts
except Exception:
return []
peers: list[str] = []
for contact in list_wormhole_dm_contacts() or []:
if not isinstance(contact, dict):
continue
if str(contact.get("invitePinnedPrekeyLookupHandle", "") or "").strip() != token:
continue
peer_url = str(contact.get("invitePinnedLookupPeerUrl", "") or "").strip().rstrip("/")
if peer_url and peer_url not in peers:
peers.append(peer_url)
return peers
def _peer_http_request(
method: str,
peer_url: str,
*,
body_bytes: bytes | None = None,
headers: dict[str, str] | None = None,
timeout: int | tuple[int, int] = 45,
):
"""HTTP to a fleet peer, using Tor SOCKS when the URL is an onion address."""
import requests
from services.mesh.mesh_crypto import normalize_peer_url
from urllib.parse import urlparse
raw_peer_url = str(peer_url or "").strip()
parsed = urlparse(raw_peer_url)
if parsed.path and parsed.path not in {"", "/"}:
# Full request URLs include invite lookup query params; do not
# normalize them away when deriving the peer base URL.
normalized = raw_peer_url
else:
normalized = normalize_peer_url(raw_peer_url)
if not normalized:
raise OSError("invalid peer url")
if isinstance(timeout, tuple):
connect_timeout, read_timeout = timeout
resolved_timeout: int | tuple[int, int] = (
max(1, int(connect_timeout or 5)),
max(1, int(read_timeout or 15)),
)
else:
resolved_timeout = max(1, int(timeout or 45))
request_kwargs: dict[str, Any] = {
"headers": dict(headers or {}),
"timeout": resolved_timeout,
}
try:
from main import _infonet_peer_requests_proxies
proxy_peer_url = normalize_peer_url(f"{parsed.scheme}://{parsed.netloc}")
proxies = _infonet_peer_requests_proxies(proxy_peer_url)
if proxies:
request_kwargs["proxies"] = proxies
except Exception:
pass
if method.upper() == "GET":
return requests.get(normalized, **request_kwargs)
request_kwargs["data"] = body_bytes or b""
return requests.post(normalized, **request_kwargs)
def _fetch_dm_prekey_bundle_from_peer_lookup(lookup_token: str) -> dict[str, Any]:
"""Fetch an invite-scoped prekey bundle from configured authenticated peers.
This is deliberately limited to lookup handles. Stable agent_id lookup stays
local/tier-gated so first-contact convenience does not reintroduce broad
public identity enumeration.
"""
token = str(lookup_token or "").strip()
if not token:
return {"ok": False, "detail": "lookup token required"}
try:
from services.config import get_settings
from services.mesh.mesh_crypto import (
normalize_peer_url,
resolve_peer_key_for_url,
)
from services.mesh.mesh_router import authenticated_push_peer_urls
settings = get_settings()
# Issue #256: secret check moved per-peer below. We still bail out
# cleanly when there are no peers configured at all.
peers = authenticated_push_peer_urls()
if not peers:
return {"ok": False, "detail": "peer prekey lookup unavailable"}
timeout = max(1, _safe_int(getattr(settings, "MESH_RELAY_PUSH_TIMEOUT_S", 10) or 10, 10))
except Exception as exc:
logger.debug("peer prekey lookup setup failed: %s", type(exc).__name__)
return {"ok": False, "detail": "peer prekey lookup unavailable"}
body = json.dumps(
{"lookup_token": token},
sort_keys=True,
separators=(",", ":"),
).encode("utf-8")
last_detail = ""
for peer_url in peers:
normalized_peer_url = str(peer_url or "").strip().rstrip("/")
if not normalized_peer_url:
continue
sender_peer_url = normalize_peer_url(
os.environ.get("MESH_SELF_PEER_URL", "").strip()
or os.environ.get("SB_TEST_NODE_URL", "").strip()
or normalized_peer_url
)
# Issue #256: prefer per-peer secret keyed by the sender URL.
peer_key = resolve_peer_key_for_url(sender_peer_url)
if not peer_key:
continue
headers = {
"Content-Type": "application/json",
"X-Peer-Url": sender_peer_url,
"X-Peer-HMAC": hmac.new(peer_key, body, hashlib.sha256).hexdigest(),
}
try:
response = _peer_http_request(
"POST",
f"{normalized_peer_url}/api/mesh/dm/prekey-peer-lookup",
body_bytes=body,
headers=headers,
timeout=timeout,
)
raw = response.content[: 256 * 1024]
payload = json.loads(raw.decode("utf-8"))
except (json.JSONDecodeError, OSError, Exception) as exc:
last_detail = str(exc) or type(exc).__name__
continue
if isinstance(payload, dict) and payload.get("ok"):
payload["lookup_mode"] = "invite_lookup_handle"
payload["peer_lookup"] = True
return payload
if isinstance(payload, dict):
last_detail = str(payload.get("detail", "") or last_detail)
return {"ok": False, "detail": last_detail or "Prekey bundle not found"}
def _configured_public_lookup_peer_urls() -> list[str]:
try:
from services.config import get_settings
from services.mesh.mesh_router import active_sync_peer_urls, parse_configured_relay_peers
settings = get_settings()
candidates: list[str] = []
# Operator-configured peers first, then recently active fleet nodes.
# Invite handles are minted on a specific node; cold bootstrap seeds
# rarely have them cached and should not be tried before contacts.
for raw in (
getattr(settings, "MESH_DEFAULT_SYNC_PEERS", ""),
):
candidates.extend(parse_configured_relay_peers(str(raw or "")))
candidates.extend(active_sync_peer_urls())
for raw in (
getattr(settings, "MESH_BOOTSTRAP_SEED_PEERS", ""),
):
candidates.extend(parse_configured_relay_peers(str(raw or "")))
except Exception:
return []
seen: set[str] = set()
peers: list[str] = []
for candidate in candidates:
peer = str(candidate or "").strip().rstrip("/")
if not peer or peer in seen:
continue
seen.add(peer)
peers.append(peer)
return peers
def _normalize_remote_lookup_bundle(payload: dict[str, Any]) -> dict[str, Any]:
data = dict(payload or {})
bundle = dict(data.get("bundle") or {})
public_key = str(data.get("public_key", "") or bundle.get("public_key", "") or "").strip()
if not public_key:
return {"ok": False, "detail": "Prekey bundle missing signing key"}
agent_id = str(data.get("agent_id", "") or "").strip() or derive_node_id(public_key)
if not agent_id:
return {"ok": False, "detail": "Prekey bundle public key binding mismatch"}
data["agent_id"] = agent_id
data["public_key"] = public_key
data["public_key_algo"] = str(data.get("public_key_algo", "") or bundle.get("public_key_algo", "Ed25519") or "Ed25519")
data["protocol_version"] = str(data.get("protocol_version", "") or bundle.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION)
data["bundle"] = bundle
ok, reason = _validate_bundle_record(data)
if not ok:
return {"ok": False, "detail": reason}
data["ok"] = True
data["lookup_mode"] = "invite_lookup_handle"
data["public_lookup"] = True
return data
def _try_public_prekey_lookup_peer(
peer_url: str,
encoded: str,
*,
timeout: int | tuple[int, int] | None = None,
) -> dict[str, Any]:
normalized_peer_url = str(peer_url or "").strip().rstrip("/")
if not normalized_peer_url:
return {"ok": False, "detail": "invalid peer url"}
resolved_timeout = timeout or _invite_lookup_request_timeout(normalized_peer_url)
try:
response = _peer_http_request(
"GET",
f"{normalized_peer_url}/api/mesh/dm/prekey-bundle?{encoded}",
headers={
"Accept": "application/json",
"User-Agent": _fleet_peer_lookup_user_agent(),
},
timeout=resolved_timeout,
)
raw = response.content[: 256 * 1024]
payload = json.loads(raw.decode("utf-8"))
except (json.JSONDecodeError, OSError, Exception) as exc:
logger.debug("public prekey lookup failed for %s: %s", normalized_peer_url, type(exc).__name__)
return {"ok": False, "detail": "peer prekey lookup unavailable"}
if not isinstance(payload, dict):
return {"ok": False, "detail": "invalid peer response"}
if payload.get("pending") or str(payload.get("status", "") or "") == "preparing_private_lane":
return {"ok": False, "detail": "peer prekey lookup still preparing"}
if not payload.get("ok"):
return {
"ok": False,
"detail": str(payload.get("detail", "") or "Prekey bundle not found"),
}
if not isinstance(payload.get("bundle"), dict):
return {"ok": False, "detail": "Prekey bundle not found"}
return _normalize_remote_lookup_bundle(payload)
def _fetch_dm_prekey_bundle_from_public_lookup(
lookup_token: str,
*,
extra_preferred_peer_urls: list[str] | None = None,
) -> dict[str, Any]:
"""Fetch an invite-scoped prekey bundle from bootstrap/sync peers.
The token is high-entropy and invite-scoped. This path does not expose a
stable agent_id to the peer; if the ordinary peer response omits agent_id,
derive it from the signed identity public key and validate the bundle before
accepting it.
"""
from concurrent.futures import FIRST_COMPLETED, ThreadPoolExecutor, wait
token = str(lookup_token or "").strip()
if not token:
return {"ok": False, "detail": "lookup token required"}
preferred = list(_preferred_invite_lookup_peer_urls(token))
for peer in list(extra_preferred_peer_urls or []):
normalized = str(peer or "").strip().rstrip("/")
if normalized and normalized not in preferred:
preferred.insert(0, normalized)
peers = _prioritized_invite_lookup_peer_urls(preferred=preferred)
if not peers:
return {"ok": False, "detail": "peer prekey lookup unavailable"}
encoded = urllib.parse.urlencode({"lookup_token": token})
last_detail = ""
hinted_only = bool(list(extra_preferred_peer_urls or []))
hint_timeout = (5, 20)
for peer_url in preferred:
hinted = _try_public_prekey_lookup_peer(
peer_url,
encoded,
timeout=hint_timeout if hinted_only else None,
)
if hinted.get("ok"):
return hinted
if isinstance(hinted, dict):
last_detail = str(hinted.get("detail", "") or last_detail)
remaining_peers = [peer for peer in peers if peer not in set(preferred)]
if not remaining_peers:
return {"ok": False, "detail": last_detail or "Prekey bundle not found"}
if hinted_only:
return {"ok": False, "detail": last_detail or "Prekey bundle not found"}
deadline = time.time() + _INVITE_LOOKUP_MAX_ELAPSED_S
workers = min(_INVITE_LOOKUP_PARALLEL_WORKERS, max(1, len(remaining_peers)))
with ThreadPoolExecutor(max_workers=workers) as executor:
futures = {
executor.submit(_try_public_prekey_lookup_peer, peer_url, encoded): peer_url
for peer_url in remaining_peers
}
while futures and time.time() < deadline:
done, _ = wait(
futures,
timeout=max(0.1, deadline - time.time()),
return_when=FIRST_COMPLETED,
)
if not done:
break
for future in done:
futures.pop(future, None)
try:
result = future.result()
except Exception as exc:
last_detail = str(exc) or type(exc).__name__
continue
if isinstance(result, dict) and result.get("ok"):
for pending in futures:
pending.cancel()
return result
if isinstance(result, dict):
last_detail = str(result.get("detail", "") or last_detail)
for pending in futures:
pending.cancel()
return {"ok": False, "detail": last_detail or "Prekey bundle not found"}
def _b64(data: bytes) -> str:
return base64.b64encode(data).decode("ascii")
def _unb64(data: str | bytes | None) -> bytes:
if not data:
return b""
if isinstance(data, bytes):
return base64.b64decode(data)
return base64.b64decode(data.encode("ascii"))
def _stable_json(value: Any) -> str:
return json.dumps(value, sort_keys=True, separators=(",", ":"))
def _x25519_pair() -> dict[str, str]:
priv = x25519.X25519PrivateKey.generate()
priv_raw = priv.private_bytes(Encoding.Raw, PrivateFormat.Raw, NoEncryption())
pub_raw = priv.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
return {"public_key": _b64(pub_raw), "private_key": _b64(priv_raw)}
def _derive(priv_b64: str, pub_b64: str) -> bytes:
priv = x25519.X25519PrivateKey.from_private_bytes(_unb64(priv_b64))
pub = x25519.X25519PublicKey.from_public_bytes(_unb64(pub_b64))
return priv.exchange(pub)
def _hkdf(ikm: bytes, info: str, length: int = 32) -> bytes:
return HKDF(
algorithm=hashes.SHA256(),
length=length,
salt=b"\xff" * 32,
info=info.encode("utf-8"),
).derive(ikm)
def _bundle_payload(data: dict[str, Any]) -> dict[str, Any]:
one_time_prekeys = [
{
"prekey_id": _safe_int(item.get("prekey_id", 0) or 0),
"public_key": str(item.get("public_key", "") or ""),
}
for item in list(data.get("one_time_prekeys") or [])
if item.get("public_key")
]
return {
"identity_dh_pub_key": str(data.get("dh_pub_key", "") or ""),
"dh_algo": str(data.get("dh_algo", "X25519") or "X25519"),
"signed_prekey_id": _safe_int(data.get("signed_prekey_id", 0) or 0),
"signed_prekey_pub": str(data.get("signed_prekey_pub", "") or ""),
"signed_prekey_signature": str(data.get("signed_prekey_signature", "") or ""),
"signed_prekey_timestamp": _safe_int(data.get("signed_prekey_generated_at", 0) or 0),
"signed_at": _safe_int(data.get("prekey_bundle_signed_at", 0) or 0),
"bundle_signature": str(data.get("prekey_bundle_signature", "") or ""),
"mls_key_package": str(data.get("mls_key_package", "") or ""),
"one_time_prekeys": one_time_prekeys,
"one_time_prekey_count": len(one_time_prekeys),
}
def _bundle_signature_core_payload(data: dict[str, Any]) -> dict[str, Any]:
# OTK binding: One-time key hashes are included in the bundle signature
# as of Sprint 12 (S12-3). Relay substitution of OTKs will now break
# the bundle signature and be rejected by verify_prekey_bundle().
otk_hashes = sorted(
hashlib.sha256(str(item.get("public_key", "")).encode("utf-8")).hexdigest()
for item in (data.get("one_time_prekeys") or [])
)
return {
"identity_dh_pub_key": str(data.get("identity_dh_pub_key", "") or ""),
"dh_algo": str(data.get("dh_algo", "X25519") or "X25519"),
"signed_prekey_id": _safe_int(data.get("signed_prekey_id", 0) or 0),
"signed_prekey_pub": str(data.get("signed_prekey_pub", "") or ""),
"signed_prekey_signature": str(data.get("signed_prekey_signature", "") or ""),
"signed_at": _safe_int(data.get("signed_at", 0) or 0),
"mls_key_package": str(data.get("mls_key_package", "") or ""),
"one_time_prekey_hashes": otk_hashes,
}
def _bundle_root_attestation_binding(attestation: dict[str, Any] | None) -> dict[str, Any]:
current = dict(attestation or {})
if not current:
return {}
return {
"type": str(current.get("type", "") or ""),
"event_type": str(current.get("event_type", "") or ""),
"protocol_version": str(current.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION),
"root_node_id": str(current.get("root_node_id", "") or "").strip(),
"root_public_key": str(current.get("root_public_key", "") or "").strip(),
"root_public_key_algo": str(current.get("root_public_key_algo", "Ed25519") or "Ed25519").strip(),
"root_manifest_fingerprint": str(current.get("root_manifest_fingerprint", "") or "").strip().lower(),
"sequence": _safe_int(current.get("sequence", 0) or 0, 0),
"signature": str(current.get("signature", "") or "").strip(),
"signer_scope": str(current.get("signer_scope", "root") or "root"),
}
def _bundle_signature_payload(data: dict[str, Any]) -> str:
payload = _bundle_signature_core_payload(data)
binding = _bundle_root_attestation_binding(dict(data.get("root_attestation") or {}))
if binding:
payload["root_attestation"] = binding
return _stable_json(payload)
def _max_prekey_bundle_age_s() -> int:
return SIGNED_PREKEY_ROTATE_AFTER_S + SIGNED_PREKEY_GRACE_S
def trust_fingerprint_for_bundle_record(record: dict[str, Any]) -> str:
bundle = dict(record.get("bundle") or record or {})
return trust_fingerprint_for_identity_material(
agent_id=str(record.get("agent_id", "") or ""),
identity_dh_pub_key=str(bundle.get("identity_dh_pub_key", "") or ""),
dh_algo=str(bundle.get("dh_algo", "X25519") or "X25519"),
public_key=str(record.get("public_key", "") or ""),
public_key_algo=str(record.get("public_key_algo", "") or ""),
protocol_version=str(record.get("protocol_version", "") or ""),
)
def transparency_fingerprint_for_bundle_record(record: dict[str, Any]) -> str:
bundle = dict(record.get("bundle") or record or {})
payload = {
"agent_id": str(record.get("agent_id", "") or "").strip(),
"public_key": str(record.get("public_key", "") or "").strip(),
"public_key_algo": str(record.get("public_key_algo", "") or "").strip(),
"protocol_version": str(record.get("protocol_version", "") or "").strip(),
"sequence": _safe_int(record.get("sequence", 0) or 0),
"bundle_payload": _bundle_signature_payload(bundle),
"bundle_signature": str(bundle.get("bundle_signature", "") or "").strip(),
"relay_signature": str(record.get("signature", "") or "").strip(),
}
return hashlib.sha256(_stable_json(payload).encode("utf-8")).hexdigest()
def _bundle_root_attestation_payload(
*,
agent_id: str,
public_key: str,
public_key_algo: str,
protocol_version: str,
bundle: dict[str, Any],
) -> dict[str, Any]:
current_bundle = dict(bundle or {})
current_bundle.pop("root_attestation", None)
root_manifest = dict(current_bundle.get("root_manifest") or {})
root_manifest_fingerprint = ""
if root_manifest:
from services.mesh.mesh_wormhole_root_manifest import manifest_fingerprint_for_envelope
root_manifest_fingerprint = manifest_fingerprint_for_envelope(root_manifest)
return {
"agent_id": str(agent_id or "").strip(),
"public_key": str(public_key or "").strip(),
"public_key_algo": str(public_key_algo or "Ed25519") or "Ed25519",
"protocol_version": str(protocol_version or PROTOCOL_VERSION) or PROTOCOL_VERSION,
"root_manifest_fingerprint": root_manifest_fingerprint,
"bundle_signature_payload": _stable_json(_bundle_signature_core_payload(current_bundle)),
}
def _attach_bundle_root_attestation(
*,
agent_id: str,
public_key: str,
public_key_algo: str,
protocol_version: str,
bundle: dict[str, Any],
) -> dict[str, Any]:
payload = dict(bundle or {})
signed = sign_root_wormhole_event(
event_type=DM_PREKEY_ROOT_ATTESTATION_EVENT_TYPE,
payload=_bundle_root_attestation_payload(
agent_id=agent_id,
public_key=public_key,
public_key_algo=public_key_algo,
protocol_version=protocol_version,
bundle=payload,
),
)
payload["root_attestation"] = {
"type": DM_PREKEY_ROOT_ATTESTATION_TYPE,
"event_type": DM_PREKEY_ROOT_ATTESTATION_EVENT_TYPE,
"protocol_version": str(signed.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION),
"root_node_id": str(signed.get("node_id", "") or "").strip(),
"root_public_key": str(signed.get("public_key", "") or "").strip(),
"root_public_key_algo": str(signed.get("public_key_algo", "Ed25519") or "Ed25519"),
"root_manifest_fingerprint": str(signed.get("payload", {}).get("root_manifest_fingerprint", "") or "").strip().lower(),
"sequence": _safe_int(signed.get("sequence", 0) or 0, 0),
"signature": str(signed.get("signature", "") or "").strip(),
"signer_scope": str(signed.get("identity_scope", "root") or "root"),
}
return payload
def _attach_bundle_root_distribution(bundle: dict[str, Any]) -> dict[str, Any]:
payload = dict(bundle or {})
from services.mesh.mesh_wormhole_root_manifest import get_current_root_manifest
from services.mesh.mesh_wormhole_root_transparency import get_current_root_transparency_record
distribution = get_current_root_manifest()
transparency = get_current_root_transparency_record(distribution=distribution)
payload["root_manifest"] = dict(distribution.get("manifest") or {})
payload["root_manifest_witness"] = dict(distribution.get("witness") or {})
payload["root_manifest_witnesses"] = [
dict(item or {}) for item in list(distribution.get("witnesses") or []) if isinstance(item, dict)
]
payload["root_transparency_record"] = dict(transparency.get("record") or {})
return payload
def _verify_bundle_root_distribution_impl(
record: dict[str, Any],
*,
enforce_local_external_sources: bool = False,
) -> tuple[bool, str, dict[str, Any]]:
bundle = dict(record.get("bundle") or record or {})
manifest = dict(bundle.get("root_manifest") or {})
witnesses = [
dict(item or {})
for item in list(bundle.get("root_manifest_witnesses") or [])
if isinstance(item, dict)
]
legacy_witness = dict(bundle.get("root_manifest_witness") or {})
if legacy_witness and not witnesses:
witnesses = [legacy_witness]
transparency_record = dict(bundle.get("root_transparency_record") or {})
if not manifest:
return False, "prekey bundle root manifest required", {}
if not witnesses:
return False, "prekey bundle root witness receipts required", {}
if not transparency_record:
return False, "prekey bundle root transparency record required", {}
from services.mesh.mesh_wormhole_root_manifest import verify_root_manifest, verify_root_manifest_witness_set
from services.mesh.mesh_wormhole_root_transparency import verify_root_transparency_record
manifest_verified = verify_root_manifest(manifest)
if not manifest_verified.get("ok"):
return False, str(manifest_verified.get("detail", "") or "prekey bundle root manifest invalid"), {}
witness_verified = verify_root_manifest_witness_set(manifest, witnesses)
if not witness_verified.get("ok"):
return False, str(witness_verified.get("detail", "") or "prekey bundle root witness invalid"), {}
transparency_verified = verify_root_transparency_record(transparency_record, manifest, witnesses)
if not transparency_verified.get("ok"):
return (
False,
str(transparency_verified.get("detail", "") or "prekey bundle root transparency record invalid"),
{},
)
external_witness_verified = {"configured": False, "ok": True}
external_transparency_verified = {"configured": False, "ok": True}
if enforce_local_external_sources:
from services.mesh.mesh_wormhole_root_manifest import verify_root_manifest_witnesses_against_external_source
from services.mesh.mesh_wormhole_root_transparency import verify_root_transparency_record_against_external_ledger
external_witness_verified = verify_root_manifest_witnesses_against_external_source(manifest, witnesses)
if external_witness_verified.get("configured") and not external_witness_verified.get("ok"):
return (
False,
str(
external_witness_verified.get("detail", "")
or "prekey bundle external root witness source invalid"
),
{},
)
external_transparency_verified = verify_root_transparency_record_against_external_ledger(
transparency_record
)
if external_transparency_verified.get("configured") and not external_transparency_verified.get("ok"):
return (
False,
str(
external_transparency_verified.get("detail", "")
or "prekey bundle external root transparency invalid"
),
{},
)
resolved = {
"root_manifest_fingerprint": str(manifest_verified.get("manifest_fingerprint", "") or "").strip().lower(),
"root_manifest_generation": _safe_int(manifest_verified.get("generation", 0) or 0, 0),
"root_manifest_policy_version": _safe_int(manifest_verified.get("policy_version", 1) or 1, 1),
"root_witness_policy_fingerprint": str(
manifest_verified.get("witness_policy_fingerprint", "") or ""
).strip().lower(),
"root_witness_threshold": _safe_int(witness_verified.get("witness_threshold", 0) or 0, 0),
"root_witness_count": _safe_int(witness_verified.get("witness_count", 0) or 0, 0),
"root_witness_domain_count": _safe_int(witness_verified.get("witness_domain_count", 0) or 0, 0),
"root_witness_independent_quorum_met": bool(
witness_verified.get("witness_independent_quorum_met")
),
"root_witness_finality_met": bool(witness_verified.get("witness_finality_met")),
"root_rotation_proven": bool(manifest_verified.get("rotation_proven")),
"root_witness_policy_change_proven": bool(manifest_verified.get("policy_change_proven")),
"root_transparency_fingerprint": str(
transparency_verified.get("record_fingerprint", "") or ""
).strip().lower(),
"root_transparency_binding_fingerprint": str(
transparency_verified.get("binding_fingerprint", "") or ""
).strip().lower(),
"root_node_id": str(manifest_verified.get("root_node_id", "") or "").strip(),
"root_public_key": str(manifest_verified.get("root_public_key", "") or "").strip(),
"root_public_key_algo": str(manifest_verified.get("root_public_key_algo", "Ed25519") or "Ed25519"),
"root_external_witness_source_configured": bool(external_witness_verified.get("configured")),
"root_external_transparency_readback_configured": bool(external_transparency_verified.get("configured")),
}
if resolved["root_manifest_generation"] > 1 and not resolved["root_rotation_proven"]:
return False, "prekey bundle root rotation proof required", resolved
if not resolved["root_witness_policy_change_proven"]:
return False, "prekey bundle root witness policy change proof required", resolved
return True, "ok", resolved
def _verify_bundle_root_attestation_impl(
record: dict[str, Any],
*,
enforce_local_external_sources: bool = False,
) -> tuple[bool, str, dict[str, Any]]:
resolved = dict(record or {})
bundle = dict(resolved.get("bundle") or resolved or {})
attestation = dict(bundle.get("root_attestation") or {})
if not attestation:
return False, "prekey bundle root attestation required", {}
root_distribution_ok, root_distribution_detail, root_distribution = _verify_bundle_root_distribution_impl(
resolved,
enforce_local_external_sources=enforce_local_external_sources,
)
if not root_distribution_ok:
return False, root_distribution_detail, root_distribution
root_node_id = str(attestation.get("root_node_id", "") or "").strip()
root_public_key = str(attestation.get("root_public_key", "") or "").strip()
root_public_key_algo = str(
attestation.get("root_public_key_algo", attestation.get("public_key_algo", "Ed25519")) or "Ed25519"
).strip()
root_manifest_fingerprint = str(attestation.get("root_manifest_fingerprint", "") or "").strip().lower()
protocol_version = str(attestation.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION).strip()
sequence = _safe_int(attestation.get("sequence", 0) or 0, 0)
signature = str(attestation.get("signature", "") or "").strip()
if not root_node_id or not root_public_key or not root_manifest_fingerprint or sequence <= 0 or not signature:
return False, "prekey bundle root attestation incomplete", {}
if protocol_version != str(resolved.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION).strip():
return False, "prekey bundle root attestation protocol mismatch", {}
if root_manifest_fingerprint != str(root_distribution.get("root_manifest_fingerprint", "") or "").strip().lower():
return False, "prekey bundle root attestation manifest mismatch", {}
if root_node_id != str(root_distribution.get("root_node_id", "") or "").strip():
return False, "prekey bundle root attestation root mismatch", {}
if root_public_key != str(root_distribution.get("root_public_key", "") or "").strip():
return False, "prekey bundle root attestation root mismatch", {}
if root_public_key_algo != str(root_distribution.get("root_public_key_algo", "Ed25519") or "Ed25519"):
return False, "prekey bundle root attestation root mismatch", {}
if not verify_node_binding(root_node_id, root_public_key):
return False, "prekey bundle root attestation node binding invalid", {}
signed_payload = build_signature_payload(
event_type=DM_PREKEY_ROOT_ATTESTATION_EVENT_TYPE,
node_id=root_node_id,
sequence=sequence,
payload=_bundle_root_attestation_payload(
agent_id=str(resolved.get("agent_id", "") or "").strip(),
public_key=str(resolved.get("public_key", "") or "").strip(),
public_key_algo=str(resolved.get("public_key_algo", "Ed25519") or "Ed25519"),
protocol_version=str(resolved.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION),
bundle=bundle,
),
)
if not verify_signature(
public_key_b64=root_public_key,
public_key_algo=root_public_key_algo,
signature_hex=signature,
payload=signed_payload,
):
return False, "prekey bundle root attestation invalid", {}
return True, "ok", {
"root_node_id": root_node_id,
"root_public_key": root_public_key,
"root_public_key_algo": root_public_key_algo,
"root_manifest_fingerprint": root_manifest_fingerprint,
"root_manifest_generation": _safe_int(root_distribution.get("root_manifest_generation", 0) or 0, 0),
"root_manifest_policy_version": _safe_int(root_distribution.get("root_manifest_policy_version", 1) or 1, 1),
"root_witness_policy_fingerprint": str(
root_distribution.get("root_witness_policy_fingerprint", "") or ""
).strip().lower(),
"root_witness_threshold": _safe_int(root_distribution.get("root_witness_threshold", 0) or 0, 0),
"root_witness_count": _safe_int(root_distribution.get("root_witness_count", 0) or 0, 0),
"root_witness_domain_count": _safe_int(root_distribution.get("root_witness_domain_count", 0) or 0, 0),
"root_witness_independent_quorum_met": bool(
root_distribution.get("root_witness_independent_quorum_met")
),
"root_transparency_fingerprint": str(root_distribution.get("root_transparency_fingerprint", "") or "").strip().lower(),
"root_transparency_binding_fingerprint": str(
root_distribution.get("root_transparency_binding_fingerprint", "") or ""
).strip().lower(),
"root_rotation_proven": bool(root_distribution.get("root_rotation_proven")),
"root_fingerprint": root_identity_fingerprint_for_material(
root_node_id=root_node_id,
root_public_key=root_public_key,
root_public_key_algo=root_public_key_algo,
protocol_version=str(resolved.get("protocol_version", PROTOCOL_VERSION) or PROTOCOL_VERSION),
),
}
def verify_bundle_root_attestation(
record: dict[str, Any],
*,
enforce_local_external_sources: bool = False,
) -> dict[str, Any]:
ok, detail, resolved = _verify_bundle_root_attestation_impl(
record,
enforce_local_external_sources=enforce_local_external_sources,
)
if not ok:
return {"ok": False, "detail": detail, **resolved}
return {"ok": True, **resolved}
def observe_remote_prekey_bundle(peer_id: str, bundle: dict[str, Any]) -> dict[str, Any]:
from services.mesh.mesh_wormhole_contacts import observe_remote_prekey_identity
bundle_record = dict(bundle or {})
bundle_payload = dict(bundle_record.get("bundle") or bundle_record)
trust_fingerprint = str(bundle_record.get("trust_fingerprint", "") or bundle_payload.get("trust_fingerprint", "") or "").strip().lower()
if not trust_fingerprint:
trust_fingerprint = trust_fingerprint_for_bundle_record(
{
"agent_id": str(peer_id or "").strip(),
"bundle": bundle_payload,
"public_key": str(bundle_record.get("public_key", "") or bundle_payload.get("public_key", "") or ""),
"public_key_algo": str(bundle_record.get("public_key_algo", "") or bundle_payload.get("public_key_algo", "") or ""),
"protocol_version": str(bundle_record.get("protocol_version", "") or bundle_payload.get("protocol_version", "") or ""),
}
)
root_attested = verify_bundle_root_attestation(
{
"agent_id": str(peer_id or "").strip(),
"bundle": bundle_payload,
"public_key": str(bundle_record.get("public_key", "") or bundle_payload.get("public_key", "") or ""),
"public_key_algo": str(
bundle_record.get("public_key_algo", "") or bundle_payload.get("public_key_algo", "") or ""
),
"protocol_version": str(
bundle_record.get("protocol_version", "") or bundle_payload.get("protocol_version", "") or ""
),
}
)
return observe_remote_prekey_identity(
str(peer_id or "").strip(),
fingerprint=trust_fingerprint,
sequence=_safe_int(bundle_record.get("sequence", 0) or 0),
signed_at=_safe_int(bundle_payload.get("signed_at", 0) or bundle_record.get("signed_at", 0) or 0),
transparency_head=str(bundle_record.get("prekey_transparency_head", "") or "").strip().lower(),
transparency_size=_safe_int(bundle_record.get("prekey_transparency_size", 0) or 0),
witness_count=_safe_int(bundle_record.get("witness_count", 0) or 0),
witness_latest_at=_safe_int(bundle_record.get("witness_latest_at", 0) or 0),
root_fingerprint=str(root_attested.get("root_fingerprint", "") or ""),
root_manifest_fingerprint=str(root_attested.get("root_manifest_fingerprint", "") or ""),
root_witness_policy_fingerprint=str(root_attested.get("root_witness_policy_fingerprint", "") or ""),
root_witness_threshold=_safe_int(root_attested.get("root_witness_threshold", 0) or 0, 0),
root_witness_count=_safe_int(root_attested.get("root_witness_count", 0) or 0, 0),
root_witness_domain_count=_safe_int(root_attested.get("root_witness_domain_count", 0) or 0, 0),
root_manifest_generation=_safe_int(root_attested.get("root_manifest_generation", 0) or 0, 0),
root_rotation_proven=bool(root_attested.get("root_rotation_proven")),
root_node_id=str(root_attested.get("root_node_id", "") or ""),
root_public_key=str(root_attested.get("root_public_key", "") or ""),
root_public_key_algo=str(root_attested.get("root_public_key_algo", "Ed25519") or "Ed25519"),
)
def _attach_bundle_signature(bundle: dict[str, Any], *, signed_at: int | None = None) -> dict[str, Any]:
# KNOWN LIMITATION: Bundle signature is self-signed by the identity key it contains.
# This proves possession of the private key and detects post-registration tampering,
# but cannot prevent initial impersonation (no external PKI). Mitigated by reputation
# system in Phase 9 (Oracle Rep). See threat-model.md for full analysis.
payload = dict(bundle or {})
resolved_signed_at = _safe_int(payload.get("signed_at", 0) or 0)
if signed_at is not None:
resolved_signed_at = int(signed_at)
elif resolved_signed_at <= 0:
resolved_signed_at = int(time.time())
payload["signed_at"] = resolved_signed_at
signed = sign_wormhole_message(_bundle_signature_payload(payload))
payload["bundle_signature"] = str(signed.get("signature", "") or "")
return payload
def _verify_bundle_signature(bundle: dict[str, Any], public_key: str) -> tuple[bool, str]:
try:
signing_pub = ed25519.Ed25519PublicKey.from_public_bytes(_unb64(public_key))
signing_pub.verify(
bytes.fromhex(str(bundle.get("bundle_signature", "") or "")),
_bundle_signature_payload(bundle).encode("utf-8"),
)
except Exception:
return False, "Prekey bundle signature invalid"
return True, "ok"
def _validate_bundle_record(
record: dict[str, Any],
*,
enforce_local_external_sources: bool = False,
) -> tuple[bool, str]:
bundle = dict(record.get("bundle") or {})
now = time.time()
signed_at = _safe_int(bundle.get("signed_at", 0) or 0)
if signed_at <= 0:
return False, "Prekey bundle missing signed_at"
if signed_at > now + 299:
return False, "Prekey bundle signed_at is in the future"
if not str(bundle.get("bundle_signature", "") or "").strip():
return False, "Prekey bundle missing bundle_signature"
public_key = str(record.get("public_key", "") or "")
if not public_key:
return False, "Prekey bundle missing signing key"
if not dict(bundle.get("root_attestation") or {}):
return False, "prekey bundle root attestation required"
ok, reason = _verify_bundle_signature(bundle, public_key)
if not ok:
return False, reason
if (now - signed_at) > _max_prekey_bundle_age_s():
return False, "Prekey bundle is stale"
if str(record.get("agent_id", "") or "").strip():
derived = derive_node_id(public_key)
if derived != str(record.get("agent_id", "") or "").strip():
return False, "Prekey bundle public key binding mismatch"
root_attestation = verify_bundle_root_attestation(
record,
enforce_local_external_sources=enforce_local_external_sources,
)
if not root_attestation.get("ok"):
return False, str(root_attestation.get("detail", "") or "Prekey bundle root attestation invalid")
return True, "ok"
def _local_external_root_sources_configured() -> bool:
from services.mesh.mesh_wormhole_root_manifest import read_root_distribution_state
state = read_root_distribution_state()
return bool(list(state.get("external_witness_descriptors") or []))
def _jittered_republish_policy(data: dict[str, Any], *, reset: bool = False) -> tuple[int, int]:
threshold = _safe_int(data.get("prekey_republish_threshold", 0) or 0)
target = _safe_int(data.get("prekey_republish_target", 0) or 0)
min_threshold, max_threshold = PREKEY_REPUBLISH_THRESHOLD_RANGE
min_target, max_target = PREKEY_REPUBLISH_TARGET_RANGE
if reset or threshold < min_threshold or threshold > max_threshold:
threshold = random.randint(min_threshold, max_threshold)
data["prekey_republish_threshold"] = threshold
if reset or target < min_target or target > max_target:
target = random.randint(min_target, max_target)
data["prekey_republish_target"] = target
return threshold, target
def _schedule_next_republish_window(data: dict[str, Any]) -> None:
min_delay_s, max_delay_s = PREKEY_REPUBLISH_DELAY_RANGE_S
data["prekey_next_republish_after"] = int(
time.time() + random.randint(min_delay_s, max_delay_s)
)
def _archive_current_signed_prekey(data: dict[str, Any], retired_at: int) -> None:
current_id = _safe_int(data.get("signed_prekey_id", 0) or 0)
current_pub = str(data.get("signed_prekey_pub", "") or "")
current_priv = str(data.get("signed_prekey_priv", "") or "")
current_sig = str(data.get("signed_prekey_signature", "") or "")
current_generated_at = _safe_int(data.get("signed_prekey_generated_at", 0) or 0)
if not current_id or not current_pub or not current_priv:
return
history = list(data.get("signed_prekey_history") or [])
history.append(
{
"signed_prekey_id": current_id,
"signed_prekey_pub": current_pub,
"signed_prekey_priv": current_priv,
"signed_prekey_signature": current_sig,
"signed_prekey_generated_at": current_generated_at,
"retired_at": retired_at,
}
)
cutoff = retired_at - SIGNED_PREKEY_GRACE_S
data["signed_prekey_history"] = [
item
for item in history[-4:]
if _safe_int(item.get("retired_at", retired_at) or retired_at) >= cutoff
]
def _find_signed_prekey_private(data: dict[str, Any], spk_id: int) -> str:
if _safe_int(data.get("signed_prekey_id", 0) or 0) == spk_id:
return str(data.get("signed_prekey_priv", "") or "")
for item in list(data.get("signed_prekey_history") or []):
if _safe_int(item.get("signed_prekey_id", 0) or 0) == spk_id:
return str(item.get("signed_prekey_priv", "") or "")
return ""
def ensure_wormhole_prekeys(force_signed_prekey: bool = False, replenish_target: int = PREKEY_TARGET) -> dict[str, Any]:
data = read_wormhole_identity()
if not data.get("bootstrapped"):
bootstrap_wormhole_identity()
data = read_wormhole_identity()
changed = False
now = int(time.time())
_, jitter_target = _jittered_republish_policy(data)
replenish_target = max(1, _safe_int(replenish_target or jitter_target, 1))
spk_generated_at = _safe_int(data.get("signed_prekey_generated_at", 0) or 0)
spk_too_old = bool(spk_generated_at and (now - spk_generated_at) >= SIGNED_PREKEY_ROTATE_AFTER_S)
if force_signed_prekey or spk_too_old or not data.get("signed_prekey_pub") or not data.get("signed_prekey_priv"):
_archive_current_signed_prekey(data, now)
pair = _x25519_pair()
spk_id = _safe_int(data.get("signed_prekey_id", 0) or 0) + 1
signed_prekey_payload = {
"signed_prekey_id": spk_id,
"signed_prekey_pub": pair["public_key"],
"signed_prekey_timestamp": now,
}
signed = sign_wormhole_event(
event_type="dm_signed_prekey",
payload=signed_prekey_payload,
)
data["signed_prekey_id"] = spk_id
data["signed_prekey_pub"] = pair["public_key"]
data["signed_prekey_priv"] = pair["private_key"]
data["signed_prekey_signature"] = signed["signature"]
data["signed_prekey_generated_at"] = now
changed = True
existing_otks = list(data.get("one_time_prekeys") or [])
next_id = max([_safe_int(item.get("prekey_id", 0) or 0) for item in existing_otks] + [0])
while len(existing_otks) < max(1, replenish_target):
next_id += 1
pair = _x25519_pair()
existing_otks.append(
{
"prekey_id": next_id,
"public_key": pair["public_key"],
"private_key": pair["private_key"],
"created_at": now,
}
)
changed = True
data["one_time_prekeys"] = existing_otks
_jittered_republish_policy(data)
if changed:
_write_identity(data)
return _bundle_payload(data)
def register_wormhole_prekey_bundle(force_signed_prekey: bool = False) -> dict[str, Any]:
data = read_wormhole_identity()
if not data.get("bootstrapped"):
bootstrap_wormhole_identity()
data = read_wormhole_identity()
_, jitter_target = _jittered_republish_policy(data, reset=force_signed_prekey)
if force_signed_prekey:
_schedule_next_republish_window(data)
_write_identity(data)
data = read_wormhole_identity()
bundle = ensure_wormhole_prekeys(force_signed_prekey=force_signed_prekey, replenish_target=jitter_target)
from services.mesh.mesh_dm_mls import export_dm_key_package_for_alias
mls_key_package = export_dm_key_package_for_alias(str(data.get("node_id", "") or ""))
if not mls_key_package.get("ok"):
return {"ok": False, "detail": str(mls_key_package.get("detail", "") or "mls key package unavailable")}
bundle["mls_key_package"] = str(mls_key_package.get("mls_key_package", "") or "")
bundle_signed_at = int(time.time())
bundle["signed_at"] = bundle_signed_at
bundle = _attach_bundle_root_distribution(bundle)
bundle = _attach_bundle_root_attestation(
agent_id=str(data.get("node_id", "") or ""),
public_key=str(data.get("public_key", "") or ""),
public_key_algo=str(data.get("public_key_algo", "Ed25519") or "Ed25519"),
protocol_version=PROTOCOL_VERSION,
bundle=bundle,
)
bundle = _attach_bundle_signature(bundle, signed_at=bundle_signed_at)
enforce_local_external_sources = _local_external_root_sources_configured()
ok, reason = _validate_bundle_record(
{
"bundle": bundle,
"public_key": str(data.get("public_key", "") or ""),
"agent_id": str(data.get("node_id", "") or ""),
},
enforce_local_external_sources=enforce_local_external_sources,
)
if not ok:
return {"ok": False, "detail": reason}
signed = sign_wormhole_event(
event_type="dm_prekey_bundle",
payload=bundle,
)
from services.mesh.mesh_dm_relay import dm_relay
lookup_aliases = get_prekey_lookup_handle_records()
accepted, detail, metadata = dm_relay.register_prekey_bundle(
signed["node_id"],
bundle,
signed["signature"],
signed["public_key"],
signed["public_key_algo"],
signed["protocol_version"],
signed["sequence"],
lookup_aliases=lookup_aliases,
)
if not accepted:
return {"ok": False, "detail": detail}
refreshed = read_wormhole_identity()
refreshed["prekey_bundle_registered_at"] = int(time.time())
refreshed["prekey_bundle_signed_at"] = _safe_int(bundle.get("signed_at", 0) or 0)
refreshed["prekey_bundle_signature"] = str(bundle.get("bundle_signature", "") or "")
refreshed["prekey_transparency_head"] = str(metadata.get("prekey_transparency_head", "") or "") if metadata else ""
refreshed["prekey_transparency_size"] = _safe_int(
metadata.get("prekey_transparency_size", 0) if metadata else 0,
0,
)
_schedule_next_republish_window(refreshed)
_jittered_republish_policy(refreshed, reset=True)
_write_identity(refreshed)
return {
"ok": True,
"agent_id": signed["node_id"],
"bundle": bundle,
"signature": signed["signature"],
"public_key": signed["public_key"],
"public_key_algo": signed["public_key_algo"],
"protocol_version": signed["protocol_version"],
"sequence": signed["sequence"],
**(metadata or {}),
}
def fetch_dm_prekey_bundle(
agent_id: str = "",
lookup_token: str = "",
*,
allow_peer_lookup: bool = True,
lookup_peer_urls: list[str] | None = None,
) -> dict[str, Any]:
from services.mesh.mesh_dm_relay import dm_relay
resolved_id = str(agent_id or "").strip()
stored = None
resolved_lookup = str(lookup_token or "").strip()
lookup_mode = "legacy_agent_id"
if not resolved_lookup and resolved_id:
try:
from services.mesh.mesh_wormhole_contacts import preferred_prekey_lookup_handle
resolved_lookup = preferred_prekey_lookup_handle(resolved_id)
except Exception:
resolved_lookup = ""
# Prefer lookup_token to avoid exposing stable agent_id to the relay.
if resolved_lookup:
found, found_id = dm_relay.get_prekey_bundle_by_lookup(resolved_lookup)
if found and found_id:
stored = found
resolved_id = found_id
lookup_mode = "invite_lookup_handle"
elif allow_peer_lookup:
preferred_peer_urls = list(lookup_peer_urls or [])
public_found = _fetch_dm_prekey_bundle_from_public_lookup(
resolved_lookup,
extra_preferred_peer_urls=preferred_peer_urls,
)
if public_found.get("ok"):
return public_found
peer_found: dict[str, Any] = {"ok": False, "detail": ""}
if not preferred_peer_urls:
peer_found = _fetch_dm_prekey_bundle_from_peer_lookup(resolved_lookup)
if peer_found.get("ok"):
return peer_found
if str(public_found.get("detail", "") or "").strip():
return {"ok": False, "detail": str(public_found.get("detail", "") or "Prekey bundle not found")}
return {"ok": False, "detail": str(peer_found.get("detail", "") or "Prekey bundle not found")}
else:
return {"ok": False, "detail": "Prekey bundle not found"}
# Fallback to direct agent_id lookup (legacy path).
if not stored and resolved_id:
blocked = legacy_agent_id_lookup_blocked()
record_legacy_agent_id_lookup(
resolved_id,
lookup_kind="prekey_bundle",
blocked=blocked,
)
_warn_legacy_prekey_lookup(resolved_id)
if blocked:
return {
"ok": False,
"detail": "legacy agent_id lookup disabled; use invite lookup handle",
"removal_target": sunset_target_label(LEGACY_AGENT_ID_LOOKUP_TARGET),
}
stored = dm_relay.get_prekey_bundle(resolved_id)
if not stored:
return {"ok": False, "detail": "Prekey bundle not found"}
validated_record = {**dict(stored), "agent_id": resolved_id}
ok, reason = _validate_bundle_record(validated_record)
if not ok:
return {"ok": False, "detail": reason}
full_bundle = dict(stored.get("bundle") or {})
bundle = dict(full_bundle)
bundle["one_time_prekeys"] = []
bundle["one_time_prekey_count"] = _safe_int(bundle.get("one_time_prekey_count", 0) or 0)
witnesses = dm_relay.get_witnesses(
resolved_id,
str(bundle.get("identity_dh_pub_key", "") or "").strip() or None,
limit=5,
)
return {
"ok": True,
"agent_id": resolved_id,
"lookup_mode": lookup_mode,
**bundle,
"bundle": full_bundle,
"signature": str(stored.get("signature", "") or ""),
"public_key": str(stored.get("public_key", "") or ""),
"public_key_algo": str(stored.get("public_key_algo", "") or ""),
"protocol_version": str(stored.get("protocol_version", "") or ""),
"sequence": _safe_int(stored.get("sequence", 0) or 0),
"prekey_transparency_head": str(stored.get("prekey_transparency_head", "") or ""),
"prekey_transparency_size": _safe_int(stored.get("prekey_transparency_size", 0) or 0),
"prekey_transparency_fingerprint": str(stored.get("prekey_transparency_fingerprint", "") or ""),
"witness_count": len(witnesses),
"witness_latest_at": max((_safe_int(item.get("timestamp", 0) or 0) for item in witnesses), default=0),
"trust_fingerprint": trust_fingerprint_for_bundle_record(validated_record),
}
def _consume_local_one_time_prekey(prekey_id: int) -> int:
if prekey_id <= 0:
data = read_wormhole_identity()
return len(list(data.get("one_time_prekeys") or []))
data = read_wormhole_identity()
existing = list(data.get("one_time_prekeys") or [])
filtered = [
item for item in existing if _safe_int(item.get("prekey_id", 0) or 0) != _safe_int(prekey_id)
]
if len(filtered) == len(existing):
return len(existing)
data["one_time_prekeys"] = filtered
_write_identity(data)
return len(filtered)
def _classify_root_attestation_failure(peer_id: str) -> tuple[str, bool]:
from services.mesh.mesh_wormhole_contacts import get_contact_trust_level
current_level = str(get_contact_trust_level(peer_id) or "").strip()
if current_level in ("invite_pinned", "sas_verified", "continuity_broken"):
return "continuity_broken", True
if current_level in ("tofu_pinned", "mismatch"):
return "mismatch", True
return "", False
def bootstrap_encrypt_for_peer(
peer_id: str,
plaintext: str,
*,
lookup_token: str = "",
fetched_bundle: dict[str, Any] | None = None,
) -> dict[str, Any]:
token = str(lookup_token or "").strip()
peer = str(peer_id or "").strip()
if fetched_bundle is None:
fetched_bundle = fetch_dm_prekey_bundle(
agent_id=peer if not token else "",
lookup_token=token,
)
if not fetched_bundle.get("ok"):
detail = str(fetched_bundle.get("detail", "") or "")
if "root attestation" in detail.lower():
trust_level, trust_changed = _classify_root_attestation_failure(peer or token)
if trust_level:
return {
"ok": False,
"peer_id": str(peer_id or "").strip(),
"detail": detail,
"trust_changed": trust_changed,
"trust_level": trust_level,
}
return fetched_bundle
from services.mesh.mesh_dm_relay import dm_relay
resolved_peer_id = str(fetched_bundle.get("agent_id", peer) or peer).strip()
stored = dm_relay.get_prekey_bundle(resolved_peer_id)
if not stored:
remote_bundle = dict(fetched_bundle.get("bundle") or {})
if not remote_bundle and fetched_bundle.get("identity_dh_pub_key"):
remote_bundle = fetched_bundle
if remote_bundle:
stored = {
"bundle": remote_bundle,
"signature": str(fetched_bundle.get("signature", "") or ""),
"public_key": str(fetched_bundle.get("public_key", "") or ""),
"public_key_algo": str(fetched_bundle.get("public_key_algo", "") or ""),
"sequence": _safe_int(fetched_bundle.get("sequence", 0) or 0),
}
else:
return {"ok": False, "detail": "Peer prekey bundle not found"}
validated_record = {**dict(stored), "agent_id": resolved_peer_id}
ok, reason = _validate_bundle_record(validated_record)
if not ok:
return {"ok": False, "detail": reason}
trust_state = observe_remote_prekey_bundle(resolved_peer_id, validated_record)
trust_level = str(trust_state.get("trust_level", "") or "")
consent_handshake = False
try:
from services.mesh.mesh_wormhole_dead_drop import parse_contact_consent
consent = parse_contact_consent(str(plaintext or "")) or {}
consent_handshake = str(consent.get("kind", "") or "") in {
"contact_offer",
"contact_accept",
"contact_deny",
}
except Exception:
consent_handshake = False
if not consent_handshake:
from services.mesh.mesh_wormhole_contacts import verified_first_contact_requirement
verified_first_contact = verified_first_contact_requirement(
resolved_peer_id,
trust_level=trust_level,
)
if not verified_first_contact.get("ok"):
return {
"ok": False,
"peer_id": resolved_peer_id,
"detail": str(
verified_first_contact.get("detail", "") or "verified first contact required"
),
"trust_changed": trust_level in ("mismatch", "continuity_broken"),
"trust_level": str(
verified_first_contact.get("trust_level", "") or trust_level or "unpinned"
),
}
peer_bundle_stored = dm_relay.consume_one_time_prekey(resolved_peer_id)
if not peer_bundle_stored:
remote_bundle = dict(stored.get("bundle") or {})
otks = list(remote_bundle.get("one_time_prekeys") or [])
peer_bundle_stored = {
"bundle": remote_bundle,
"claimed_one_time_prekey": dict(otks[0] or {}) if otks else {},
}
if not peer_bundle_stored.get("bundle"):
return {"ok": False, "detail": "Peer prekey bundle not found"}
peer_bundle = dict(peer_bundle_stored.get("bundle") or {})
peer_static = str(peer_bundle.get("identity_dh_pub_key", "") or "")
peer_spk = str(peer_bundle.get("signed_prekey_pub", "") or "")
peer_spk_id = _safe_int(peer_bundle.get("signed_prekey_id", 0) or 0)
peer_otk = dict(peer_bundle_stored.get("claimed_one_time_prekey") or {})
data = read_wormhole_identity()
if not data.get("bootstrapped"):
bootstrap_wormhole_identity()
data = read_wormhole_identity()
my_static_priv = str(data.get("dh_private_key", "") or "")
my_static_pub = str(data.get("dh_pub_key", "") or "")
if not my_static_priv or not my_static_pub or not peer_static or not peer_spk:
return {"ok": False, "detail": "Missing static or signed prekey material"}
eph = _x25519_pair()
dh_parts = [
_derive(my_static_priv, peer_spk),
_derive(eph["private_key"], peer_static),
_derive(eph["private_key"], peer_spk),
]
otk_id = 0
if peer_otk and peer_otk.get("public_key"):
dh_parts.append(_derive(eph["private_key"], str(peer_otk.get("public_key"))))
otk_id = _safe_int(peer_otk.get("prekey_id", 0) or 0)
secret = _hkdf(b"".join(dh_parts), "SB-X3DH", 32)
header = {
"v": 1,
"alg": "X25519",
"ik_pub": my_static_pub,
"ek_pub": eph["public_key"],
"spk_id": peer_spk_id,
"otk_id": otk_id,
}
aad = _stable_json(header).encode("utf-8")
iv = os.urandom(12)
ciphertext = AESGCM(secret).encrypt(iv, plaintext.encode("utf-8"), aad)
envelope = {
"h": header,
"ct": _b64(iv + ciphertext),
}
wrapped = _b64(_stable_json(envelope).encode("utf-8"))
return {
"ok": True,
"result": f"x3dh1:{wrapped}",
"trust_level": trust_level or "unpinned",
}
def bootstrap_decrypt_from_sender(sender_id: str, ciphertext: str) -> dict[str, Any]:
if not ciphertext.startswith("x3dh1:"):
return {"ok": False, "detail": "legacy"}
try:
raw = ciphertext[len("x3dh1:") :]
envelope = json.loads(_unb64(raw).decode("utf-8"))
header = dict(envelope.get("h") or {})
combined = _unb64(str(envelope.get("ct") or ""))
my_data = read_wormhole_identity()
if not my_data.get("bootstrapped"):
bootstrap_wormhole_identity()
my_data = read_wormhole_identity()
sender_static_pub = str(header.get("ik_pub", "") or "")
sender_eph_pub = str(header.get("ek_pub", "") or "")
spk_id = _safe_int(header.get("spk_id", 0) or 0)
otk_id = _safe_int(header.get("otk_id", 0) or 0)
if not sender_static_pub or not sender_eph_pub:
return {"ok": False, "detail": "Missing sender bootstrap keys"}
try:
from services.mesh.mesh_wormhole_contacts import list_wormhole_dm_contacts
contact = dict(list_wormhole_dm_contacts().get(str(sender_id or "").strip(), {}) or {})
pinned_invite_dh = str(contact.get("invitePinnedDhPubKey", "") or "").strip()
if pinned_invite_dh and pinned_invite_dh != sender_static_pub:
return {
"ok": False,
"detail": "sender bootstrap key mismatches pinned invite",
"trust_level": str(contact.get("trust_level", "") or "") or "invite_pinned",
}
except Exception:
pass
from services.mesh.mesh_dm_relay import dm_relay
sender_dh = dm_relay.get_dh_key(sender_id)
if sender_dh and sender_dh.get("dh_pub_key") and str(sender_dh.get("dh_pub_key")) != sender_static_pub:
return {"ok": False, "detail": "Sender static DH key mismatch"}
signed_prekey_priv = _find_signed_prekey_private(my_data, spk_id)
my_static_priv = str(my_data.get("dh_private_key", "") or "")
if not signed_prekey_priv or not my_static_priv:
return {"ok": False, "detail": "Missing local bootstrap private keys"}
dh_parts = [
_derive(signed_prekey_priv, sender_static_pub),
_derive(my_static_priv, sender_eph_pub),
_derive(signed_prekey_priv, sender_eph_pub),
]
if otk_id:
otk_match = next(
(
item
for item in list(my_data.get("one_time_prekeys") or [])
if _safe_int(item.get("prekey_id", 0) or 0) == otk_id and item.get("private_key")
),
None,
)
if not otk_match:
return {"ok": False, "detail": "One-time prekey mismatch"}
dh_parts.append(_derive(str(otk_match.get("private_key", "")), sender_eph_pub))
secret = _hkdf(b"".join(dh_parts), "SB-X3DH", 32)
aad = _stable_json(header).encode("utf-8")
iv = combined[:12]
ct = combined[12:]
plaintext = AESGCM(secret).decrypt(iv, ct, aad).decode("utf-8")
if otk_id:
remaining_otks = _consume_local_one_time_prekey(otk_id)
my_data = read_wormhole_identity()
threshold, target = _jittered_republish_policy(my_data)
next_republish_after = _safe_int(my_data.get("prekey_next_republish_after", 0) or 0)
now_ts = int(time.time())
should_republish = remaining_otks <= 0
if not should_republish and remaining_otks <= threshold and now_ts >= next_republish_after:
should_republish = True
if should_republish:
register_wormhole_prekey_bundle()
else:
_write_identity(my_data)
return {"ok": True, "result": plaintext}
except Exception as exc:
return {"ok": False, "detail": str(exc) or "bootstrap_decrypt_failed"}