S14: NPE fail-closed adapter; npe mode never falls back to lab-xor
This commit is contained in:
parent
d67509e470
commit
9eed0b1942
4 changed files with 112 additions and 2 deletions
|
|
@ -75,8 +75,10 @@ def seal(
|
|||
raise ValueError("lab_key required for lab-xor")
|
||||
key = hashlib.sha256(lab_key).digest() # 32-byte key
|
||||
ct = _xor(key, raw).hex() # hex ct
|
||||
elif mode == "npe": # production — sidecar not in this module
|
||||
raise NotImplementedError("npe: attach NPE sidecar; do not HPKE here")
|
||||
elif mode == "npe": # production — sidecar only
|
||||
from .npe_adapter import seal_npe # fail-closed import
|
||||
|
||||
ct = seal_npe(to, body) # never lab-xor here
|
||||
else: # unknown
|
||||
raise ValueError("unknown crypto.mode " + mode)
|
||||
token = hashlib.sha256(nonce + b"error-token").hexdigest()[:32] # return-path token stub
|
||||
|
|
|
|||
40
python/secure_messaging/npe_adapter.py
Normal file
40
python/secure_messaging/npe_adapter.py
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
"""NPE sidecar adapter (fail-closed).
|
||||
|
||||
Production ``crypto.mode=npe`` must not fall back to lab-xor.
|
||||
If the ``npe`` binary is missing, raise NpeRequired.
|
||||
Live ns1 must not set this until CI review (see UserReview.MD).
|
||||
"""
|
||||
|
||||
from __future__ import annotations # annotations as strings
|
||||
|
||||
import json # encode sidecar request
|
||||
import shutil # look up npe on PATH
|
||||
import subprocess # run sidecar
|
||||
from typing import Any, Dict, Mapping # types
|
||||
|
||||
|
||||
class NpeRequired(RuntimeError):
|
||||
"""Raised when NPE is required but the sidecar is not usable."""
|
||||
|
||||
|
||||
def npe_bin() -> str:
|
||||
"""Return path to npe or raise."""
|
||||
path = shutil.which("npe") # PATH lookup
|
||||
if not path: # missing
|
||||
raise NpeRequired("npe binary not on PATH; attach sidecar") # fail closed
|
||||
return path # found
|
||||
|
||||
|
||||
def seal_npe(to: str, body: Mapping[str, Any]) -> str:
|
||||
"""Ask sidecar to HPKE-seal body for mailbox ``to``. Returns hex ct."""
|
||||
raw = json.dumps(body, sort_keys=True, separators=(",", ":")).encode() # canonical body
|
||||
proc = subprocess.run( # npe CLI contract: stdin body, arg dest
|
||||
[npe_bin(), "seal", "--to", to],
|
||||
input=raw,
|
||||
capture_output=True,
|
||||
timeout=15,
|
||||
check=False,
|
||||
)
|
||||
if proc.returncode != 0: # sidecar failed
|
||||
raise NpeRequired("npe seal failed: " + proc.stderr.decode(errors="replace")[:200])
|
||||
return proc.stdout.strip().decode() # hex or token from sidecar
|
||||
Loading…
Add table
Add a link
Reference in a new issue