148 lines
9.8 KiB
Markdown
148 lines
9.8 KiB
Markdown
# Native Windows service host
|
|
|
|
This component uses Windows SCM, named pipes and Job objects around the stock
|
|
Node broker. It does not rebuild Electron/Chromium or modify installed Chrome.
|
|
It has not been installed or proven as the production network boundary.
|
|
|
|
Run `node scripts/build-windows-service-host.mjs --self-test` on Windows with
|
|
Visual Studio C++ Build Tools and SDK 10.0.26100.0. The builder uses explicit
|
|
compiler/include/library paths, /W4 /WX, static runtime, CFG, ASLR and DEP. Output
|
|
and fixed metadata evidence remain under ignored `artifacts/native-service-host`.
|
|
It changes no execution policy, service, firewall, DNS setting or user profile.
|
|
The builder accepts `--self-test` or `--compile-only`. Compile-only never launches
|
|
the executable and writes separate evidence. It bakes a disposable public key, retains
|
|
private test keys only in memory, and signs synthetic inventory fixtures after
|
|
compilation. It never creates a production release key or registers a service.
|
|
|
|
The actual negative tests verify: missing SCM service identity, unauthorized
|
|
client image, oversized frame, wrong file hash, second pipe instance denied by
|
|
its DACL, and a child plus grandchild retained in a non-breakaway kill-on-close
|
|
Job and both observed terminal after closing the Job. These are meaningful
|
|
native component tests; they do not prove an installed SCM or WFP deployment.
|
|
|
|
The fixed bridge is `\\.\pipe\SafetyNet.Broker.v1`, local-only, one authenticated
|
|
browser connection at a time. An enabled SCM service SID, protected code and
|
|
independently pinned deployment material are required before broker launch. The
|
|
client is the protected installed helper launched by the protected installed
|
|
SafetyNet.exe. Both must have matching medium/high, non-AppContainer user
|
|
tokens and sessions. Its process token and impersonated pipe token must agree
|
|
on user SID and session. The process handle remains retained and monitored;
|
|
client exit terminates the broker Job. The ACL excludes FILE_CREATE_PIPE_INSTANCE
|
|
from employee rights. No trust arises from a pipe name or claimed PID in JSON.
|
|
|
|
Frames are uint32 little-endian length followed by UTF-8 JSON. The first
|
|
parent-to-child frame is bounded to 2 MiB; subsequent frames and child responses
|
|
are 64 KiB. The constant child receives only inherited stdin/stdout handles and
|
|
`--service-stdio`; stderr goes to NUL. Seven Windows profile/runtime variables
|
|
and one fixed OS-derived `SAFETYNET_SERVICE_CLIENT_SID` are passed. No caller
|
|
environment supplies that SID. The Node adapter must validate the existing
|
|
v1 generation, monotonic sequence, typed audit/certificate receipts and pinned
|
|
service deployment authority. Framing does not authenticate policy or allow a
|
|
caller to replace its public key, device identity or version floor.
|
|
|
|
The `--client-stdio` mode connects once and authenticates the actual connected
|
|
handle's retained server process against signed release hashes, the exact
|
|
installed path and an enabled SCM service SID. It never probes and reconnects.
|
|
`--trust-snapshot` requires a service-token helper and a retained signed Node
|
|
parent. It returns bounded framed public anchor/SID/registry-floor metadata,
|
|
without accepting a registry path or trust key from its caller.
|
|
|
|
The fixed child entry is `resources/broker/apps/network-broker/service-entry.cjs`.
|
|
The prepared `--topology-snapshot` helper uses the compiled broker port 43120,
|
|
fixed installed browser/broker paths and the real SCM service SID. Service-token,
|
|
signed Node-parent and signed user-assignment checks precede its read-only BFE
|
|
enumeration. It verifies all eight owned filter keys, actions, conditions,
|
|
weights and service descriptor bytes, checks equal-priority collisions and BFE
|
|
state, and reports bounded metadata. It never accepts a plan, port or visibility
|
|
flag from IPC. The new topology source compiled, but its latest self-test launch
|
|
failed with `UNKNOWN:spawn`; compile-only evidence is separate from earlier
|
|
successful native tests. This helper has no installed execution proof yet.
|
|
|
|
Windows enumerators omit unreadable objects and notifications are asynchronous
|
|
and unreliable. Therefore the helper reports `allObjectsReadable:false` even at
|
|
successful EOF. Production admission requires an independently reviewed,
|
|
protected deployment prerequisite; token elevation or an ordinary JSON flag
|
|
cannot establish it. Ordinary-user enforcement assumes trusted administrators;
|
|
user-mode monitoring cannot promise zero packets during hostile privileged
|
|
kernel/BFE changes. See Microsoft's [access control](https://learn.microsoft.com/en-us/windows/win32/fwp/access-control)
|
|
and [notification contract](https://learn.microsoft.com/en-us/windows/win32/fwp/change-notifications).
|
|
|
|
The fixed 64-bit HKLM key `SOFTWARE\SafetyNet\Trust` contains one canonical
|
|
`AcceptanceState` REG_BINARY value, including release/deployment digests and
|
|
sorted per-user policy floors. Missing or corrupt state fails closed. The
|
|
snapshot exposes `{version, authenticatedSid, releaseAnchor, acceptanceState}`.
|
|
`--commit-acceptance` accepts only `{expectedPreviousSHA, candidateState}`,
|
|
checks a full monotonic transition under an authenticated fixed mutex, writes
|
|
one value, flushes and verifies readback before returning
|
|
`{persisted:true,stateSha256}`. State bytes are capped at 2 MiB minus 1024 bytes;
|
|
all stdio frames have a single bounded deadline. The trusted Node gate must
|
|
verify the actual signed policy before requesting a commit. Policy digests hash
|
|
the original base64url payload string; manifest digests hash canonical decoded
|
|
JSON bytes.
|
|
|
|
The prepared `--management-credential` command accepts exactly device ID,
|
|
canonical HTTPS origin, policy version, policy-key DER SHA256 and the accepted
|
|
policy-payload digest. It binds them to the native service-minted user SID,
|
|
signed v2 deployment and exact protected acceptance record. Its private reply
|
|
contains only the same fields and the token, bounded to 8 KiB. The separate fixed
|
|
key `SOFTWARE\SafetyNet\ManagementCredentials` requires a protected DACL owned
|
|
by SYSTEM/administrators, granting access only to them and the exact service SID.
|
|
Encrypted records use LocalMachine DPAPI with canonical metadata as entropy;
|
|
this is Windows encryption, not a post-quantum storage claim.
|
|
|
|
Each read first validates the exact current accepted policy request. It then
|
|
selects the unique highest stored version at or below that request for the same
|
|
SID, device, origin and policy key. Same-version digest conflicts, ambiguous
|
|
duplicates and future versions fail closed. Decryption uses the record's own
|
|
original metadata; the reply echoes the verified current request. Advancing a
|
|
policy therefore does not require re-encrypting an otherwise valid credential.
|
|
Provisioning replaces all records for that stable identity and preserves other
|
|
identities, preventing a new record for every policy revision.
|
|
|
|
Internal `--provision-management-credential` additionally requires the previous
|
|
encrypted-store SHA256 and token. It uses the same authenticated service role,
|
|
serialized mutex, bounded canonical store (256 records/1 MiB), CAS, flush and
|
|
readback before returning a receipt. It accepts no registry path, user SID or
|
|
key selector. Neither command creates keys or supplies an initial empty store.
|
|
No renderer/enrollment provisioning endpoint is exposed. Initial protected
|
|
provisioning and actual service-token DPAPI/registry execution remain unproven;
|
|
the latest native source has compile-only evidence, not execution evidence.
|
|
|
|
The mutex uses an OWNER_RIGHTS read-control ACE rather than assuming the service
|
|
SID can own objects. Actual native tests show owner WRITE_DAC denial while
|
|
synchronization and modification remain allowed. Commit source is prepared,
|
|
but no registry write, installed service positive or durable commit has been
|
|
performed. Current uninstalled snapshot/commit/client tests require exit 5.
|
|
|
|
`signed-manifest.h` verifies canonical manifests using Windows CNG P-256/SHA256
|
|
and fixed 64-byte IEEE-P1363 signatures. The baked vendor key verifies release
|
|
inventory; its delegated customer key verifies deployment and user assignment.
|
|
This is a classical release signature, not a post-quantum signature. Actual
|
|
native tests verify positive delegation and reject tampering, the wrong customer
|
|
key, expiry and equal-sequence digest mismatch. A larger signed inventory tests
|
|
real envelope parsing. These fixture tests do not attest installed resource ACLs.
|
|
|
|
Before deployment, implement and independently verify these remaining gates:
|
|
|
|
- Actual vendor signing/provisioning and complete final inventory, including
|
|
every broker, inspector, model and browser resource. The external signature
|
|
avoids circular browser/host hashes; synthetic fixtures are not a release.
|
|
- Installed positive client/server authentication and lifecycle tests; current
|
|
native negatives cannot prove a correctly provisioned SCM service.
|
|
- Protected initial acceptance-state provisioning and an actual service-token
|
|
CAS/flush/readback proof before listen. Prepared source and uninstalled
|
|
negative tests do not establish durable installed behavior.
|
|
- Real SCM provisioning under a least-privileged service identity, protected
|
|
resource/state ACLs, actual service-start/stop and bounded I/O timeout tests.
|
|
- Per-user signed assignment binding and typed management/inspector/OTLP RPC.
|
|
Interactive DPAPI audit persistence stays in the authenticated user parent.
|
|
- Transactional WFP outbound filters and receiver service-descriptor soft-permit
|
|
plus lower block in the same owned sublayer, preserving corporate veto.
|
|
- Native readback and physical IPv4/IPv6/UDP/DNS/port-takeover tests, including
|
|
another instance of the same stock Node executable and service crashes.
|
|
- Effective WFP hard-permit topology validation and BFE change monitoring;
|
|
a low-priority sublayer or a static rule inventory cannot prove enforcement.
|
|
Browser inbound-first IPv4/IPv6 TCP/UDP denies need physical receiver tests.
|
|
|
|
Until those gates pass, retain existing browser quarantine and enforcement.
|