Add packaged DLP broker and protected Windows service foundation
This commit is contained in:
1 parent
95d23f4e0b
commit
7b5057901a
140 files changed
+11215
-60
No files matched your search
@@ -0,0 +1,147 @@
|
||||
# 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.
|
||||
Reference in new issue
Block a user