docs(windows): Enhanced-Windows hardening spec (GPD Pocket 4 reference) #2
@@ -11,11 +11,12 @@ Tier C — config-layer hardening only. Honest positioning: we cannot modify the
|
|||||||
LTSC IoT-based installer that transforms a vanilla Windows install into a SilverMetal-hardened build:
|
LTSC IoT-based installer that transforms a vanilla Windows install into a SilverMetal-hardened build:
|
||||||
|
|
||||||
- Windows 11 IoT Enterprise LTSC base (no Cortana, no Store, no Edge baked in, ~10-year support)
|
- Windows 11 IoT Enterprise LTSC base (no Cortana, no Store, no Edge baked in, ~10-year support)
|
||||||
- Group Policy hardening (telemetry off, services disabled, sane defaults)
|
- Group Policy hardening (telemetry at `Security` floor, services disabled, sane defaults)
|
||||||
|
- VBS + HVCI + Credential Guard + Kernel DMA Protection (Microsoft's hardware-backed isolation)
|
||||||
- Defender ASR rules at maximum
|
- Defender ASR rules at maximum
|
||||||
- AppLocker allow-list mode
|
- WDAC (App Control for Business) allow-list — kernel-enforced, audit-first then enforce (AppLocker is the documented fallback, not the primary)
|
||||||
- BitLocker enforced (TPM-bound)
|
- BitLocker enforced — **TPM + PIN** (never TPM-only; PIN defeats the faulTPM-class offline attack on the AMD fTPM)
|
||||||
- Telemetry blocked at hosts file + service + GP layers
|
- Telemetry suppressed at GP + service + firewall layers (**not** hosts-file blocking of Microsoft domains — that breaks Windows Update); residual published, not claimed zero
|
||||||
- Edge / Chrome replaced with SilverBrowser default
|
- Edge / Chrome replaced with SilverBrowser default
|
||||||
- Full SilverLABS Stack preinstalled (native Windows builds)
|
- Full SilverLABS Stack preinstalled (native Windows builds)
|
||||||
- SilverVPN MAUI Windows client integrated from existing [`SilverLABS/SilverVPN`](https://git.silverlabs.uk/SilverLABS/SilverVPN)
|
- SilverVPN MAUI Windows client integrated from existing [`SilverLABS/SilverVPN`](https://git.silverlabs.uk/SilverLABS/SilverVPN)
|
||||||
@@ -34,7 +35,7 @@ To be populated in Phase 3W. Initial structure planned:
|
|||||||
windows/
|
windows/
|
||||||
├── installer/ # PowerShell / WiX-based installer
|
├── installer/ # PowerShell / WiX-based installer
|
||||||
├── policies/ # Group Policy templates, ADMX
|
├── policies/ # Group Policy templates, ADMX
|
||||||
├── applocker/ # AppLocker rules
|
├── wdac/ # WDAC (App Control) policies (AppLocker fallback rules if needed)
|
||||||
├── debloat/ # Removal scripts (Edge, Cortana residue, telemetry)
|
├── debloat/ # Removal scripts (Edge, Cortana residue, telemetry)
|
||||||
├── stack-installer/ # Native SilverLABS Stack package builders
|
├── stack-installer/ # Native SilverLABS Stack package builders
|
||||||
└── tests/ # Telemetry-leak test, hardening-baseline test
|
└── tests/ # Telemetry-leak test, hardening-baseline test
|
||||||
@@ -43,10 +44,15 @@ windows/
|
|||||||
## Verification gates
|
## Verification gates
|
||||||
|
|
||||||
- Telemetry-leak test on hardened install — minimum-feasible Microsoft contact, *documented in full* (we cannot reach zero on Windows; we publish what remains)
|
- Telemetry-leak test on hardened install — minimum-feasible Microsoft contact, *documented in full* (we cannot reach zero on Windows; we publish what remains)
|
||||||
- BitLocker enabled with TPM binding verified
|
- BitLocker enabled with **TPM + PIN** binding verified (TPM-only is rejected)
|
||||||
- AppLocker allow-list functional and documented
|
- VBS / HVCI / Credential Guard verified running
|
||||||
|
- WDAC allow-list functional (enforced) and documented
|
||||||
- Stack apps install and function
|
- Stack apps install and function
|
||||||
|
|
||||||
|
## Full hardening specification
|
||||||
|
|
||||||
|
The detailed control spec — eight control domains, verification commands, residual-risk statement, and productization notes — lives in [`hardening-spec.md`](hardening-spec.md). Reference device: GPD Pocket 4 (AMD Strix Point).
|
||||||
|
|
||||||
## Upstream we depend on
|
## Upstream we depend on
|
||||||
|
|
||||||
- **Windows 11 IoT Enterprise LTSC** — base OS (licensed)
|
- **Windows 11 IoT Enterprise LTSC** — base OS (licensed)
|
||||||
|
|||||||
10
windows/debloat/README.md
Normal file
10
windows/debloat/README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# windows/debloat
|
||||||
|
|
||||||
|
Residue removal for the lean IoT Enterprise LTSC base.
|
||||||
|
|
||||||
|
- `appx-remove.txt` — provisioned-package removal list (short by design; LTSC is already minimal).
|
||||||
|
- Service-disable lists are applied by [`../hardening/00-provisioning.ps1`](../hardening/00-provisioning.ps1) and [`07-privacy-update.ps1`](../hardening/07-privacy-update.ps1) (telemetry/feedback services only — never update/security services).
|
||||||
|
|
||||||
|
**Anti-pattern (do not do):** Tiny11/NTLite-style component amputation. It breaks
|
||||||
|
servicing and genuineness, violating design-principles #2 and #13. LTSC gives the
|
||||||
|
lean base without the breakage.
|
||||||
17
windows/debloat/appx-remove.txt
Normal file
17
windows/debloat/appx-remove.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# SilverMetal Enhanced - Windows : provisioned appx removal list.
|
||||||
|
# One package family name (or prefix) per line; '#' comments ignored.
|
||||||
|
# IoT Enterprise LTSC is already lean, so this list is intentionally SHORT and
|
||||||
|
# only targets residue. Do NOT remove servicing/Store-for-Business components
|
||||||
|
# that LTSC relies on. Verify per-build (TODO-M2).
|
||||||
|
#
|
||||||
|
# Removed offline in the WIM by build.ps1 (DISM /Remove-ProvisionedAppxPackage)
|
||||||
|
# and at first boot for the provisioned user where applicable.
|
||||||
|
|
||||||
|
Microsoft.Windows.Copilot
|
||||||
|
Microsoft.549981C3F5F10 # Cortana
|
||||||
|
Microsoft.BingWeather
|
||||||
|
Microsoft.BingNews
|
||||||
|
Microsoft.GamingApp
|
||||||
|
Microsoft.XboxGamingOverlay
|
||||||
|
Microsoft.MicrosoftSolitaireCollection
|
||||||
|
# TODO-M2: confirm against the actual LTSC media manifest before enabling removal.
|
||||||
15
windows/drivers/README.md
Normal file
15
windows/drivers/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# windows/drivers
|
||||||
|
|
||||||
|
GPD Pocket 4 driver pack, injected offline into the WIM (`DISM /Add-Driver`) by
|
||||||
|
`../installer/build.ps1` stage 3.
|
||||||
|
|
||||||
|
Targets the Pocket 4 hardware a vanilla LTSC install may lack: Strix Point GPU,
|
||||||
|
sensors / auto-rotate, Wi-Fi, fingerprint, modular-port controllers, fan/EC.
|
||||||
|
|
||||||
|
**Sourcing (M2):** confirm redistribution terms for the GPD driver pack. If
|
||||||
|
redistribution is not permitted, store a **sourced manifest** (URL + SHA-256 +
|
||||||
|
version, pinned in `../installer/inputs.manifest.json`) and fetch at build time
|
||||||
|
rather than committing the binaries.
|
||||||
|
|
||||||
|
Open question (hardening-spec §8): which drivers are actually absent from a
|
||||||
|
vanilla LTSC install — determine on the physical unit.
|
||||||
217
windows/hardening-spec.md
Normal file
217
windows/hardening-spec.md
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
# SilverMetal Enhanced — Windows: Hardening Specification
|
||||||
|
|
||||||
|
> **Status**: v1 draft — 2026-06-08. Reference device: **GPD Pocket 4** (AMD Ryzen AI 9 HX 370 / Strix Point UMPC).
|
||||||
|
> **Tier C** — configuration-layer hardening only. We do not modify the Windows kernel or boot chain; we turn every dial Microsoft exposes, and we honestly document the dials they do not.
|
||||||
|
|
||||||
|
This spec defines the hardened configuration applied to a Windows 11 install to make it a *SilverMetal Enhanced — Windows* build. It refines the v1 scope in [`README.md`](README.md) and is bound by [`../docs/threat-model.md`](../docs/threat-model.md) and [`../docs/design-principles.md`](../docs/design-principles.md).
|
||||||
|
|
||||||
|
It serves two purposes at once (per the brief): a **one-off hardening guide** for the immediate reference unit, and the **prototype of the productized SKU build** that will graduate to an LTSC-based installer. Productization notes are called out inline.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Why this is a Tier C product (the honest frame)
|
||||||
|
|
||||||
|
SilverMetal ships the strongest hardening each platform *physically allows*. On Windows that ceiling is real and we state it up front (design-principle #2, "honesty over marketing"):
|
||||||
|
|
||||||
|
- **Closed kernel** — no KSPP, no hardened_malloc, no extensible MAC framework (no AppArmor/SELinux equivalent we control).
|
||||||
|
- **No developer-controlled verified boot** — we can enrol our own Secure Boot keys, but the firmware root of trust remains the OEM's.
|
||||||
|
- **Telemetry cannot reach zero** — we minimise it and *publish what remains* rather than claim "zero".
|
||||||
|
- **The hardware floor is the Pocket 4's** — see §10. Closed AMI-class BIOS, an always-on AMD PSP, no hardware kill switches. None of this is fixable in software.
|
||||||
|
|
||||||
|
What Tier C *does* deliver is a genuinely strong posture against the threats that actually dominate a pocket everyday device: **device loss/theft, opportunistic malware, network surveillance, and coerced/borders access** — the core of who [`threat-model.md`](../docs/threat-model.md) defends.
|
||||||
|
|
||||||
|
## 2. Threat model for this device (mapped to the program threat model)
|
||||||
|
|
||||||
|
This is a **pocket-sized everyday carry**, so the realistic threat ranking differs from a desk machine. Mapped onto the program tiers in [`threat-model.md`](../docs/threat-model.md):
|
||||||
|
|
||||||
|
| Rank | Threat (this device) | Program-threat-model row | Primary controls |
|
||||||
|
|---|---|---|---|
|
||||||
|
| 1 | **Loss / theft, powered-off** | "Physical seizure, powered off" → *Yes, defended* | BitLocker XTS-AES-256 **+ PIN** (§E), Secure Boot (§B) |
|
||||||
|
| 2 | **Opportunistic malware / remote** | "Targeted commercial spyware", "remote exploitation (partial)" | VBS/HVCI, Credential Guard, WDAC, ASR, Defender (§C–D) |
|
||||||
|
| 3 | **Network surveillance** | "Network observation" → *Yes* | SilverVPN always-on + kill-switch, encrypted DNS, firewall (§F) |
|
||||||
|
| 4 | **Coerced unlock / border / theft powered-on** | "Coercion / duress" → *Partial* | Lock-screen hygiene (§G), **SilverDuress** panic-wipe (Stack) |
|
||||||
|
| 5 | **Evil-maid / targeted physical** | "Hardware implant" → *Partial* | TPM+PIN (defeats faulTPM-class offline attack), DMA-port lockdown (§G) |
|
||||||
|
| — | **Dedicated state actor / firmware implant** | *Explicitly NOT defended* | Out of scope — acknowledged in §10, not claimed |
|
||||||
|
|
||||||
|
**Decision of record:** SilverMetal Enhanced — Windows does **not** claim the nation-state/firmware tier on the Pocket 4. The closed BIOS, the PSP-resident fTPM, and the absence of hardware kill switches put that tier out of reach of any software configuration. This is stated to the buyer, not buried.
|
||||||
|
|
||||||
|
## 3. Edition baseline
|
||||||
|
|
||||||
|
| | This unit (prototype) | Shipping SKU (target) |
|
||||||
|
|---|---|---|
|
||||||
|
| Edition | **Windows 11 Enterprise** (available now) | **Windows 11 IoT Enterprise LTSC** (per [`README.md`](README.md)) |
|
||||||
|
| Telemetry floor | `Security` (level 0) via GP | `Security` (level 0) — same |
|
||||||
|
| Credential Guard / WDAC | Full | Full |
|
||||||
|
| Servicing | Annual feature updates | ~10-year LTSC, no feature-update churn |
|
||||||
|
| Default bloat | Consumer apps present (remove in §A) | Minimal (no Store/Cortana/Edge baked in) |
|
||||||
|
|
||||||
|
At the **hardening layer the two are equivalent** — identical GP, Defender, VBS, and WDAC capability. The deltas are bloat surface and servicing channel only. IoT Enterprise GAC is an acceptable intermediate if LTSC licensing is unavailable, at the cost of the LTSC servicing guarantee.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Control domains
|
||||||
|
|
||||||
|
Each domain lists the controls, the rationale, and a **verification check** (a command or observable that *proves* the control is active — evidence before assertions). Apply order is A → H.
|
||||||
|
|
||||||
|
### A. Provisioning baseline
|
||||||
|
|
||||||
|
Goal: start from a clean, de-clouded, debloated install with telemetry at its floor.
|
||||||
|
|
||||||
|
- Install from a **clean Microsoft ISO** (not an OEM image); wipe the GPD factory Windows entirely.
|
||||||
|
- **Local account only** — no Microsoft Account sign-in, no OneDrive linkage, no cloud key escrow. (OOBE: bypass MSA via `BYPASSNRO` / offline-account path.)
|
||||||
|
- Set diagnostic data to **Security (0)**: `Computer\Policies\...\DataCollection\AllowTelemetry = 0` (Enterprise/LTSC only honour level 0).
|
||||||
|
- Disable: Advertising ID, Activity History / Timeline, Tailored Experiences, Suggested Content, Find-My-Device, Recall (Windows AI), Copilot, Cortana, Customer Experience Improvement Program, Connected User Experiences (`DiagTrack`, `dmwappushservice`).
|
||||||
|
- Remove consumer provisioned apps (Enterprise prototype only; LTSC ships without them).
|
||||||
|
- Region/keyboard/time without "send my data to improve" toggles.
|
||||||
|
|
||||||
|
**Verify:** `Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' -Name AllowTelemetry` returns `0`; `Get-Service DiagTrack` is `Stopped`/`Disabled`; no Microsoft Account under `Settings → Accounts`.
|
||||||
|
|
||||||
|
### B. Boot & firmware trust
|
||||||
|
|
||||||
|
Goal: make the boot chain ours as far as the OEM firmware permits, and lock the firmware's own settings.
|
||||||
|
|
||||||
|
- **Secure Boot ON.** Enrol **our own PK/KEK/db** so the chain trusts SilverMetal-signed components — but **retain Microsoft's UEFI CA** keys (option-ROM / GPU / NIC firmware on the Pocket 4 are MS-signed; purging them risks an unbootable device). Honest note: this is *additive* trust, not a clean-room root — the OEM firmware is still the ultimate root (§10).
|
||||||
|
- **Set a BIOS/UEFI administrator password** (blocks casual firmware reconfig / boot-order change at a checkpoint).
|
||||||
|
- Disable unused boot paths: network/PXE boot, boot from removable unless needed, legacy/CSM.
|
||||||
|
- **fTPM enabled** (it is PSP-resident — see §10; we use it but do not over-trust it).
|
||||||
|
- **Firmware-update hygiene:** GPD ships BIOS as a Windows `.exe` in a RAR archive (not a signed capsule, not on LVFS). Treat every BIOS update as a supply-chain event: download only from the verified GPD source, record the version, apply deliberately, and **re-verify §B/§E settings survive the update** (open question: whether enrolled Secure Boot keys persist across a GPD BIOS flash — must be tested per update).
|
||||||
|
|
||||||
|
**Verify:** `Confirm-SecureBootUEFI` returns `True`; `Get-SecureBootPolicy` / `[System.Text.Encoding]` dump of `db` shows our key present; firmware admin password prompts on entry.
|
||||||
|
|
||||||
|
### C. Data at rest (the crown jewel for this device)
|
||||||
|
|
||||||
|
Goal: a stolen powered-off device yields nothing.
|
||||||
|
|
||||||
|
- **BitLocker, XTS-AES-256**, OS volume + any data volume.
|
||||||
|
- **TPM + PIN — never TPM-only.** *This is the single most important control on this device.* The faulTPM research class extracts the BitLocker VMK from an AMD fTPM via ~$200 voltage-fault injection with a few hours' physical access — but that defeats *TPM-internal* authorisation only; **a strong PIN forces an offline brute-force the attacker cannot shortcut.** (Demonstrated on Zen 2/3; the Pocket 4's Zen 5 is untested, so we treat the risk as live by analogy.) Use a **≥8-char alphanumeric enhanced PIN**.
|
||||||
|
- **No recovery key in the Microsoft cloud.** Recovery key is printed/stored offline by the user (or in SilverKeys). `OSManageDRA`/GP set to forbid cloud escrow.
|
||||||
|
- Disable automatic device encryption that would silently bind TPM-only before PIN is set.
|
||||||
|
- Bind to a sane PCR set and disable BitLocker standby/auto-unlock that would re-derive the key on resume without a PIN (ties to §G).
|
||||||
|
|
||||||
|
**Verify:** `Get-BitLockerVolume` shows `ProtectionStatus On`, `EncryptionMethod XtsAes256`, and KeyProtectors include **`TpmPin`** (not `Tpm` alone); `manage-bde -protectors -get C:` confirms no numerical recovery password is cloud-escrowed.
|
||||||
|
|
||||||
|
### D. Kernel & credential isolation
|
||||||
|
|
||||||
|
Goal: use Microsoft's hardware-backed isolation primitives — the genuinely strong part of hardened Windows.
|
||||||
|
|
||||||
|
- **VBS (Virtualization-Based Security) ON** with **HVCI / Memory Integrity** enforced.
|
||||||
|
- **Credential Guard ON** (VBS-isolated LSA — defeats Mimikatz/pass-the-hash credential theft).
|
||||||
|
- **LSA protection (RunAsPPL)** enabled.
|
||||||
|
- **Kernel DMA Protection ON** — on AMD this depends on the firmware setting the ACPI **IVRS `DMA_REMAP`** bit; if the Pocket 4 firmware does not, fall back to disabling/blocking the Thunderbolt/USB4 DMA path (§G). (Open question: confirm `iommu_dma_protection` is actually reported.)
|
||||||
|
- System Guard / DRTM where the platform exposes it (likely absent on the Pocket 4 — document, don't claim).
|
||||||
|
|
||||||
|
**Verify:** `msinfo32` → "Virtualization-based security" = **Running**, services = "Credential Guard, HVCI"; `Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard` shows `SecurityServicesRunning` includes `1` (CG) and `2` (HVCI); `Settings → Privacy & security → Device security → Core isolation → Memory integrity = On`; Kernel DMA Protection shows "On" in System Information.
|
||||||
|
|
||||||
|
### E. Application control
|
||||||
|
|
||||||
|
Goal: only trusted code runs; aggressively reduce exploit surface. **Balanced posture: audit first, then enforce.**
|
||||||
|
|
||||||
|
- **WDAC (App Control for Business)** as the primary allow-listing engine — kernel-enforced, the modern successor to AppLocker (which is *not* kernel-enforced and is treated as legacy). **Deploy in AUDIT mode first** (logs what *would* be blocked) for a real-usage shakedown period, then promote to **ENFORCE**. AppLocker remains the documented fallback where WDAC policy authoring is impractical.
|
||||||
|
- *Productization note:* the SKU ships a pre-authored base WDAC policy (Windows + Stack + common dev tools signed/approved); the prototype builds that policy from its own audit logs.
|
||||||
|
- **Defender ASR rules at maximum** (block credential theft from LSASS, Office child-process creation, obfuscated scripts, executable content from email/USB, etc.).
|
||||||
|
- **Microsoft Defender** real-time + cloud-delivered protection ON for detection, but **automatic sample submission OFF** (privacy — design-principle #5/#8: we do not exfiltrate user files for "improvement").
|
||||||
|
- **SmartScreen** ON; **Controlled Folder Access** (anti-ransomware) ON with Stack apps allow-listed.
|
||||||
|
- **Exploit Protection** (system-wide DEP, ASLR, CFG, SEHOP) at default-hardened.
|
||||||
|
|
||||||
|
**Verify:** `Get-CimInstance -Namespace root\Microsoft\Windows\DeviceGuard -ClassName Win32_DeviceGuard` shows `CodeIntegrityPolicyEnforcementStatus = 2` (enforced) after promotion; `Get-MpPreference | Select Attack*` lists ASR rules in Block (1) mode; `Get-MpPreference SubmitSamplesConsent` = `2` (never send).
|
||||||
|
|
||||||
|
### F. Network & radios (distrust the network — principle #11)
|
||||||
|
|
||||||
|
- **SilverVPN always-on with kill-switch** — if the tunnel drops, traffic stops (no plaintext fallback). Integrated from the existing [`SilverLABS/SilverVPN`](https://git.silverlabs.uk/SilverLABS/SilverVPN) MAUI Windows client.
|
||||||
|
- **Encrypted DNS** (DoH) system-wide; disable plaintext DNS fallback.
|
||||||
|
- **Windows Firewall: default-deny inbound**, outbound restricted to the VPN + essential update/licensing endpoints.
|
||||||
|
- **Disable LAN-leak vectors:** LLMNR, NetBIOS-over-TCP/IP, mDNS responder, WPAD, SMB1, link-local multicast name resolution.
|
||||||
|
- **WiFi-only — do not fit the 4G/5G module.** The optional Pocket 4 cellular module adds a baseband processor (an unauditable radio with independent firmware and potential independent memory access). Omitting it removes the entire baseband attack/telemetry surface — the cleanest available substitute for the hardware kill switch the device lacks (§10).
|
||||||
|
- Bluetooth off unless actively used.
|
||||||
|
|
||||||
|
**Verify:** `Get-DnsClientDohServerAddress` populated + `Get-DnsClientGlobalSetting`; `Get-NetFirewallProfile` shows `DefaultInboundAction Block`; `Get-WindowsOptionalFeature -Online -FeatureName SMB1Protocol` = Disabled; VPN kill-switch tested by pulling the tunnel and confirming no egress; no WWAN adapter present.
|
||||||
|
|
||||||
|
### G. Physical & lock-screen hygiene (theft is threat #1)
|
||||||
|
|
||||||
|
- **Short auto-lock** (≤2 min idle → lock) and **lock on lid-close**; require **PIN/Windows Hello on every wake** (no "stay unlocked" grace).
|
||||||
|
- **Disable BitLocker auto-unlock across sleep/standby** so a powered-on-but-locked stolen device cannot resume into an unlocked session without the PIN. Prefer **hibernate over sleep** (keys not left in RAM as long); document the battery/UX trade.
|
||||||
|
- **USB / DMA port policy:** with the Pocket 4's USB4/Thunderbolt-class ports, restrict device installation to an allow-list and block new DMA-capable devices at the lock screen (`Disable new DMA devices when this computer is locked`). If §D's Kernel DMA Protection isn't firmware-backed, this is the compensating control.
|
||||||
|
- **SilverDuress** (Stack, v1.1) — duress PIN / panic-wipe for coerced-unlock and border scenarios (the program's "Partial" answer to the coercion row).
|
||||||
|
- **No hardware kill switches exist on the Pocket 4** — so camera/mic are mitigated in software (disable in Device Manager / privacy settings, per-app camera+mic denial) plus the physical stopgaps (camera shutter/tape). Stated honestly: software disable trusts the firmware not to lie; it is not equivalent to a severed line.
|
||||||
|
|
||||||
|
**Verify:** `Get-CimInstance Win32_OperatingSystem` lock policy via `secpol`/GP (`InactivityTimeoutSecs` ≤120); resume-from-sleep prompts for PIN; lock-screen DMA policy set (`HKLM\...\FVE\DisableExternalDMAUnderLock = 1`); camera/mic show disabled in Device Manager.
|
||||||
|
|
||||||
|
### H. Privacy minimisation & update integrity
|
||||||
|
|
||||||
|
- Telemetry floor (§A) + scheduled-task and service trim (disable telemetry/feedback/CEIP tasks; keep update, time-sync, and security tasks).
|
||||||
|
- **Do NOT block Microsoft domains in the hosts file.** Modern telemetry bypasses hosts (hardcoded IPs/DoH), and hosts-blocking MS endpoints breaks Windows Update — violating design-principle #13 ("Update or die"). Telemetry suppression lives at the **GP + service + firewall** layers; endpoint blocking is reserved for *non-essential, non-update* domains only.
|
||||||
|
- **Windows Update stays ON** (signed, automatic, with rollback) — patching is the single largest real-world risk reducer. We minimise *telemetry*, never *patching*.
|
||||||
|
- **Publish the residual telemetry** — run the telemetry-leak test (§ Verification) and document, in full, the minimum-feasible Microsoft contact that remains. We do not claim zero.
|
||||||
|
|
||||||
|
**Verify:** telemetry-leak capture (below); `Get-Service wuauserv` running; hosts file contains no Microsoft update/licensing domains.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. The SilverLABS Stack on this device
|
||||||
|
|
||||||
|
Per design-principle #7 ("the Stack is the spine, not the OS"), the durable privacy value is the Stack, shipped as native Windows builds:
|
||||||
|
|
||||||
|
| Component | Role on this device | Maps to |
|
||||||
|
|---|---|---|
|
||||||
|
| **SilverBrowser** | Default browser; replaces Edge/Chrome | A, H |
|
||||||
|
| **SilverVPN** | Always-on tunnel + kill-switch | F |
|
||||||
|
| **SilverSync** | Replaces OneDrive (client-side encrypted) | A |
|
||||||
|
| **SilverChat** | E2EE messaging (Signal Protocol over VPN) | F |
|
||||||
|
| **SilverDuress** | Duress PIN / panic-wipe | G |
|
||||||
|
| **SilverKeys** | Password + 2FA + offline BitLocker recovery-key store | C, A |
|
||||||
|
|
||||||
|
The host OS is treated as semi-trusted even hardened (principle #12): Stack apps client-side-encrypt before disk write and do not rely on the Windows credential store for the most sensitive secrets.
|
||||||
|
|
||||||
|
## 5. Residual-risk statement (buyer-facing, honest)
|
||||||
|
|
||||||
|
SilverMetal Enhanced — Windows on the GPD Pocket 4 **does not protect against**:
|
||||||
|
|
||||||
|
1. **Firmware-tier compromise** — the OEM BIOS is closed, delivered as an unsigned-from-documentation Windows installer, with no coreboot/Heads port; we cannot audit or replace it.
|
||||||
|
2. **The AMD PSP** — an always-on, pre-x86 security processor that is the true boot root of trust; it cannot be disabled (no AMD equivalent of Intel ME-disable/HAP exists — see [`../docs/hardware-skus.md`](../docs/hardware-skus.md)).
|
||||||
|
3. **Evil-maid against the fTPM** — mitigated, not eliminated, by BitLocker TPM+**PIN** (offline brute-force only).
|
||||||
|
4. **Camera/mic/radio at the hardware level** — there are no hardware kill switches; software disable trusts the firmware. (Mitigated by not fitting the cellular module and by physical camera cover.)
|
||||||
|
5. **A dedicated, well-resourced state actor** targeting this user specifically — undefendable on commodity hardware, per [`../docs/threat-model.md`](../docs/threat-model.md).
|
||||||
|
6. **Irreducible Windows telemetry** — minimised to the `Security` floor and published; not zero.
|
||||||
|
|
||||||
|
If a buyer's threat model centres on #1, #2, or #5, the correct product is **SilverMetal OS — Linux** on coreboot/ME-neutralised hardware ([`../docs/hardware-skus.md`](../docs/hardware-skus.md)), not Enhanced-Windows on a consumer UMPC.
|
||||||
|
|
||||||
|
## 6. Verification gates (must pass before a build is "SilverMetal")
|
||||||
|
|
||||||
|
Aligned with [`README.md`](README.md) and design-principle #4 (verifiable):
|
||||||
|
|
||||||
|
1. **Telemetry-leak test** — capture all egress on a clean hardened build (VPN off, to a controlled resolver/proxy) for a fixed window; classify every Microsoft contact; **publish the residual**. Pass = no telemetry beyond the documented minimum.
|
||||||
|
2. **BitLocker** — `Get-BitLockerVolume` shows XTS-AES-256 + **`TpmPin`** protector; no cloud-escrowed recovery key.
|
||||||
|
3. **VBS/HVCI/Credential Guard** — `Win32_DeviceGuard` shows all three running.
|
||||||
|
4. **WDAC** — enforced policy active (`CodeIntegrityPolicyEnforcementStatus = 2`); audit-log review documented.
|
||||||
|
5. **VPN kill-switch** — tunnel-drop test shows zero egress.
|
||||||
|
6. **Secure Boot** — `Confirm-SecureBootUEFI = True` with our `db` key enrolled.
|
||||||
|
7. **Stack** — all six components install and function on the hardened build.
|
||||||
|
8. **Update path intact** — `wuauserv` healthy; a test update applies and rolls back.
|
||||||
|
|
||||||
|
A reusable PowerShell **`Verify-SilverMetalWindows.ps1`** (productization) asserts gates 2–6 and 8 and emits a signed attestation report.
|
||||||
|
|
||||||
|
## 7. Productization notes (one-off → SKU)
|
||||||
|
|
||||||
|
- Re-base from **Enterprise** to **IoT Enterprise LTSC** (no functional hardening change; less bloat, longer servicing).
|
||||||
|
- Convert the prototype's hand-applied settings into the planned [`windows/`](README.md) layout: `installer/` (PowerShell/WiX), `policies/` (GP/ADMX export), `applocker/` → **`wdac/`** (rename to reflect the WDAC primary decision), `debloat/`, `stack-installer/`, `tests/` (telemetry-leak + baseline).
|
||||||
|
- Author the **base WDAC policy** from this unit's audit logs.
|
||||||
|
- Decide Secure Boot key custody (the program signing key per [`../docs/trust-model.md`](../docs/trust-model.md) vs a Windows-specific subkey).
|
||||||
|
- Track the open questions (§8) per BIOS revision.
|
||||||
|
|
||||||
|
## 8. Open questions (carry until resolved on the physical unit)
|
||||||
|
|
||||||
|
1. Confirmed **UEFI vendor** (AMI vs Insyde) — inferred AMI-pattern from the Windows-flash flow; verify on the unit.
|
||||||
|
2. Do **enrolled Secure Boot keys survive a GPD BIOS update**? (Test across one update cycle.)
|
||||||
|
3. Does the firmware set the ACPI **IVRS `DMA_REMAP`** bit so Kernel DMA Protection is real, or must §G's lock-screen DMA block carry it alone?
|
||||||
|
4. Is the **faulTPM** voltage-fault class reproducible on Zen 5 Strix Point, or did AMD add SVI countermeasures?
|
||||||
|
5. Does the optional **4G/5G baseband** have independent DMA/memory access? (Moot if not fitted — and we don't fit it.)
|
||||||
|
|
||||||
|
## 9. References
|
||||||
|
|
||||||
|
- Deep-research assessment (2026-06-08), summarised in operator memory `silvermetal-pocket4-security-assessment`.
|
||||||
|
- faulTPM — defeating AMD fTPM via voltage fault injection: <https://arxiv.org/abs/2304.14717>, <https://github.com/PSPReverse/ftpm_attack>
|
||||||
|
- AMD PSP as boot root of trust / fTPM trustlet: <https://doc.coreboot.org/soc/amd/psp_integration.html>
|
||||||
|
- Kernel DMA Protection on AMD (IVRS DMA_REMAP): <https://patchwork.kernel.org/project/linux-usb/patch/20220315162455.5190-2-mario.limonciello@amd.com/>
|
||||||
|
- GPD Pocket 4 BIOS update method (Windows EXE in RAR): <https://gpdstore.net/kb/gpd-pocket-4-support-hub/kb-article/how-to-update-the-gpd-pocket-4-bios/>
|
||||||
|
- Microsoft: VBS/HVCI, Credential Guard, WDAC (App Control for Business), BitLocker enhanced PIN, ASR rules — Microsoft Learn (current docs).
|
||||||
|
- SilverMetal program: [`../docs/threat-model.md`](../docs/threat-model.md), [`../docs/design-principles.md`](../docs/design-principles.md), [`../docs/hardware-skus.md`](../docs/hardware-skus.md).
|
||||||
27
windows/hardening/00-provisioning.ps1
Normal file
27
windows/hardening/00-provisioning.ps1
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain A: Provisioning baseline
|
||||||
|
De-cloud, debloat, telemetry -> Security floor. Idempotent.
|
||||||
|
Spec: ../hardening-spec.md (A) | SCAFFOLD (M1): verify on the unit.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[A] Provisioning baseline'
|
||||||
|
|
||||||
|
# Telemetry floor (level 0 'Security' is honoured only on Enterprise/Education/LTSC).
|
||||||
|
$dc = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection'
|
||||||
|
New-Item -Path $dc -Force | Out-Null
|
||||||
|
Set-ItemProperty $dc -Name AllowTelemetry -Type DWord -Value 0
|
||||||
|
Set-ItemProperty $dc -Name DoNotShowFeedbackNotifications -Type DWord -Value 1
|
||||||
|
|
||||||
|
# Kill connected-experience / advertising / activity surfaces.
|
||||||
|
$svc = 'DiagTrack','dmwappushservice'
|
||||||
|
foreach ($s in $svc) { Get-Service $s -EA SilentlyContinue | Set-Service -StartupType Disabled -PassThru | Stop-Service -Force -EA SilentlyContinue }
|
||||||
|
|
||||||
|
# Advertising ID, Tailored experiences, Activity feed (machine policies).
|
||||||
|
$adv = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\AdvertisingInfo'
|
||||||
|
New-Item $adv -Force | Out-Null; Set-ItemProperty $adv -Name DisabledByGroupPolicy -Type DWord -Value 1
|
||||||
|
|
||||||
|
# TODO-M1: Recall/Copilot/Cortana off; remove residual provisioned appx (Enterprise prototype);
|
||||||
|
# confirm no MSA bound (OOBE handled this via autounattend).
|
||||||
|
|
||||||
|
Write-Host ' [A] applied (telemetry=0, DiagTrack disabled, ad-ID off)'
|
||||||
23
windows/hardening/01-boot-firmware.ps1
Normal file
23
windows/hardening/01-boot-firmware.ps1
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain B: Boot & firmware trust
|
||||||
|
Most of B is a FIRMWARE step (Secure Boot custom-key enrollment, BIOS admin
|
||||||
|
password) that an OS image cannot perform. This module STAGES our keys and
|
||||||
|
reports Secure Boot state; the enrollment itself is done in UEFI setup at
|
||||||
|
provisioning (SKU) or as a documented user step (self-apply).
|
||||||
|
Spec: ../hardening-spec.md (B) | SCAFFOLD (M1).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[B] Boot & firmware trust'
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (Confirm-SecureBootUEFI) { Write-Host ' Secure Boot: ENABLED' }
|
||||||
|
else { Write-Warning ' Secure Boot is DISABLED - enable + enrol custom keys in UEFI setup.' }
|
||||||
|
} catch { Write-Warning " Secure Boot state unavailable (legacy/CSM?): $_" }
|
||||||
|
|
||||||
|
# TODO-M1: stage SilverMetal PK/KEK/db (retain Microsoft UEFI CA for option ROMs) to a known path
|
||||||
|
# for KeyTool/manual enrollment; document the firmware-side procedure.
|
||||||
|
# REMINDER (manual, NOT scriptable here): set a BIOS admin password; disable PXE/legacy/CSM;
|
||||||
|
# verify enrolled keys survive a GPD BIOS update (open question, hardening-spec.md §8).
|
||||||
|
|
||||||
|
Write-Host ' [B] staged (firmware enrollment is a documented manual step)'
|
||||||
28
windows/hardening/02-data-at-rest.ps1
Normal file
28
windows/hardening/02-data-at-rest.ps1
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain C: Data at rest (crown jewel)
|
||||||
|
BitLocker XTS-AES-256 with TPM + PIN. NEVER TPM-only: the faulTPM class
|
||||||
|
extracts the VMK from the AMD fTPM; a PIN forces an offline brute-force.
|
||||||
|
The PIN is set INTERACTIVELY by the user (cannot be shipped in an image).
|
||||||
|
Spec: ../hardening-spec.md (C) | SCAFFOLD (M1): run on the unit.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param([string]$MountPoint = $env:SystemDrive)
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[C] Data at rest (BitLocker TPM+PIN)'
|
||||||
|
|
||||||
|
# Enforce TPM+PIN at startup and forbid cloud recovery escrow via policy.
|
||||||
|
$fve = 'HKLM:\SOFTWARE\Policies\Microsoft\FVE'
|
||||||
|
New-Item $fve -Force | Out-Null
|
||||||
|
Set-ItemProperty $fve -Name UseAdvancedStartup -Type DWord -Value 1 # require startup auth
|
||||||
|
Set-ItemProperty $fve -Name UseTPMPIN -Type DWord -Value 1 # TPM+PIN required
|
||||||
|
Set-ItemProperty $fve -Name UseTPM -Type DWord -Value 2 # TPM-only NOT allowed
|
||||||
|
Set-ItemProperty $fve -Name EnableNonTPM -Type DWord -Value 0
|
||||||
|
Set-ItemProperty $fve -Name MinimumPIN -Type DWord -Value 8 # enhanced PIN length
|
||||||
|
Set-ItemProperty $fve -Name OSEncryptionType -Type DWord -Value 1 # full (not used-space-only)
|
||||||
|
# No Microsoft-account / AD escrow of recovery key:
|
||||||
|
Set-ItemProperty $fve -Name OSManageDRA -Type DWord -Value 0
|
||||||
|
|
||||||
|
# TODO-M1 (interactive on the unit): prompt the user for a >=8-char enhanced PIN, then:
|
||||||
|
# Enable-BitLocker -MountPoint $MountPoint -EncryptionMethod XtsAes256 -TpmAndPinProtector -Pin $securePin
|
||||||
|
# Add a recovery password and store it OFFLINE (SilverKeys), never cloud-escrowed.
|
||||||
|
|
||||||
|
Write-Host " [C] policy set (TPM+PIN required, TPM-only blocked). PIN enrollment = interactive."
|
||||||
38
windows/hardening/03-kernel-credential.ps1
Normal file
38
windows/hardening/03-kernel-credential.ps1
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain D: Kernel & credential isolation
|
||||||
|
VBS + HVCI + Credential Guard + LSA protection + Kernel DMA Protection.
|
||||||
|
The genuinely strong, hardware-backed part of hardened Windows.
|
||||||
|
Spec: ../hardening-spec.md (D) | SCAFFOLD (M1).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[D] Kernel & credential isolation'
|
||||||
|
|
||||||
|
# VBS + HVCI (Memory Integrity)
|
||||||
|
$dg = 'HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard'
|
||||||
|
New-Item $dg -Force | Out-Null
|
||||||
|
Set-ItemProperty $dg -Name EnableVirtualizationBasedSecurity -Type DWord -Value 1
|
||||||
|
Set-ItemProperty $dg -Name RequirePlatformSecurityFeatures -Type DWord -Value 1 # Secure Boot
|
||||||
|
$hvci = "$dg\Scenarios\HypervisorEnforcedCodeIntegrity"
|
||||||
|
New-Item $hvci -Force | Out-Null
|
||||||
|
Set-ItemProperty $hvci -Name Enabled -Type DWord -Value 1
|
||||||
|
|
||||||
|
# Credential Guard
|
||||||
|
$lsacfg = "$dg\Scenarios\CredentialGuard"
|
||||||
|
New-Item $lsacfg -Force | Out-Null
|
||||||
|
Set-ItemProperty $lsacfg -Name Enabled -Type DWord -Value 1
|
||||||
|
|
||||||
|
# LSA protection (RunAsPPL)
|
||||||
|
$lsa = 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa'
|
||||||
|
Set-ItemProperty $lsa -Name RunAsPPL -Type DWord -Value 1
|
||||||
|
|
||||||
|
# Kernel DMA Protection: on AMD this is firmware-gated (ACPI IVRS DMA_REMAP bit).
|
||||||
|
# Block new DMA devices while locked as the compensating control (see Domain G).
|
||||||
|
$ki = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Kernel DMA Protection'
|
||||||
|
New-Item $ki -Force | Out-Null
|
||||||
|
Set-ItemProperty $ki -Name DeviceEnumerationPolicy -Type DWord -Value 0 # block until authorized
|
||||||
|
|
||||||
|
# TODO-M1: confirm msinfo32 reports VBS=Running + Credential Guard + HVCI after reboot;
|
||||||
|
# confirm whether Kernel DMA Protection shows On (IVRS bit) — open question §8.
|
||||||
|
|
||||||
|
Write-Host ' [D] policy set (VBS/HVCI/CredGuard/LSA-PPL/DMA). Effective after reboot.'
|
||||||
36
windows/hardening/04-app-control.ps1
Normal file
36
windows/hardening/04-app-control.ps1
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain E: Application control
|
||||||
|
WDAC (App Control) AUDIT-first then enforce; Defender ASR at max; Defender
|
||||||
|
on for detection but sample submission OFF (privacy); SmartScreen; CFA.
|
||||||
|
Balanced posture = audit before enforce (don't brick the dev workflow).
|
||||||
|
Spec: ../hardening-spec.md (E) | SCAFFOLD (M1).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[E] Application control'
|
||||||
|
|
||||||
|
# --- Defender: detection on, but do NOT exfiltrate user files ---
|
||||||
|
Set-MpPreference -MAPSReporting Advanced
|
||||||
|
Set-MpPreference -SubmitSamplesConsent 2 # 2 = never send samples
|
||||||
|
Set-MpPreference -PUAProtection Enabled
|
||||||
|
Set-MpPreference -EnableControlledFolderAccess Enabled
|
||||||
|
|
||||||
|
# --- ASR rules at max (Block) ---
|
||||||
|
$asr = @{
|
||||||
|
'BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550'=1 # block executable content from email/webmail
|
||||||
|
'9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2'=1 # block credential stealing from lsass
|
||||||
|
'D4F940AB-401B-4EFC-AADC-AD5F3C50688A'=1 # block Office child processes
|
||||||
|
'3B576869-A4EC-4529-8536-B80A7769E899'=1 # block Office executable content creation
|
||||||
|
'5BEB7EFE-FD9A-4556-801D-275E5FFC04CC'=1 # block obfuscated scripts
|
||||||
|
'D3E037E1-3EB8-44C8-A917-57927947596D'=1 # block JS/VBS launching downloaded content
|
||||||
|
'B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4'=1 # block untrusted/unsigned from USB
|
||||||
|
}
|
||||||
|
foreach ($id in $asr.Keys) { Add-MpPreference -AttackSurfaceReductionRules_Ids $id -AttackSurfaceReductionRules_Actions $asr[$id] }
|
||||||
|
|
||||||
|
# --- WDAC: deploy base policy in AUDIT first ---
|
||||||
|
# TODO-M1: compile ..\wdac\silvermetal-base.xml -> .cip in AUDIT mode (option 3 'Audit Mode' set),
|
||||||
|
# stage to C:\Windows\System32\CodeIntegrity\CiPolicies\Active, CiTool --refresh.
|
||||||
|
# After a real-usage shakedown, regenerate from audit events and PROMOTE to enforce.
|
||||||
|
Write-Warning ' WDAC base policy authoring is M1 (audit) -> M2 (enforce). Not yet deployed.'
|
||||||
|
|
||||||
|
Write-Host ' [E] Defender+ASR applied; WDAC pending policy authoring.'
|
||||||
31
windows/hardening/05-network-radios.ps1
Normal file
31
windows/hardening/05-network-radios.ps1
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain F: Network & radios
|
||||||
|
Distrust the network: firewall default-deny inbound, encrypted DNS, kill
|
||||||
|
LAN name-resolution leak vectors, WiFi-only (no baseband module). SilverVPN
|
||||||
|
always-on kill-switch is installed by 08-stack-install.ps1.
|
||||||
|
Spec: ../hardening-spec.md (F) | SCAFFOLD (M1).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[F] Network & radios'
|
||||||
|
|
||||||
|
# Firewall: default-deny inbound on all profiles.
|
||||||
|
Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block -DefaultOutboundAction Allow -Enabled True
|
||||||
|
|
||||||
|
# Disable SMBv1 + LAN name-resolution leak vectors.
|
||||||
|
Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart -EA SilentlyContinue | Out-Null
|
||||||
|
$dns = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient'
|
||||||
|
New-Item $dns -Force | Out-Null
|
||||||
|
Set-ItemProperty $dns -Name EnableMulticast -Type DWord -Value 0 # LLMNR off
|
||||||
|
$nbt = 'HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters'
|
||||||
|
Set-ItemProperty $nbt -Name NodeType -Type DWord -Value 2 # NetBIOS: P-node (no broadcast)
|
||||||
|
|
||||||
|
# Encrypted DNS (DoH) auto + WPAD off.
|
||||||
|
$doh = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient'
|
||||||
|
Set-ItemProperty $doh -Name DoHPolicy -Type DWord -Value 3 # require DoH
|
||||||
|
Set-Service WinHttpAutoProxySvc -StartupType Disabled -EA SilentlyContinue
|
||||||
|
|
||||||
|
# TODO-M1: configure DoH server template; verify NO WWAN adapter present (we do not fit the
|
||||||
|
# 4G/5G baseband module); disable Bluetooth radio unless in use.
|
||||||
|
|
||||||
|
Write-Host ' [F] firewall default-deny, SMB1 off, LLMNR/NetBIOS/WPAD off, DoH required.'
|
||||||
32
windows/hardening/06-physical-lock.ps1
Normal file
32
windows/hardening/06-physical-lock.ps1
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain G: Physical & lock-screen hygiene
|
||||||
|
Theft is threat #1 for a pocket device. Short auto-lock, PIN on wake, block
|
||||||
|
DMA while locked, prefer hibernate, no HW kill switch (software cam/mic).
|
||||||
|
Spec: ../hardening-spec.md (G) | SCAFFOLD (M1).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[G] Physical & lock-screen hygiene'
|
||||||
|
|
||||||
|
# Auto-lock: machine inactivity limit (seconds) + require password on wake.
|
||||||
|
$sys = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
|
||||||
|
New-Item $sys -Force | Out-Null
|
||||||
|
Set-ItemProperty $sys -Name InactivityTimeoutSecs -Type DWord -Value 120 # lock after 2 min idle
|
||||||
|
$pol = 'HKLM:\SOFTWARE\Policies\Microsoft\Power\PowerSettings\0e796bdb-100d-47d6-a2d5-f7d2daa51f51'
|
||||||
|
New-Item $pol -Force | Out-Null
|
||||||
|
Set-ItemProperty $pol -Name ACSettingIndex -Type DWord -Value 1 # require password on wake (AC)
|
||||||
|
Set-ItemProperty $pol -Name DCSettingIndex -Type DWord -Value 1 # ... and on battery
|
||||||
|
|
||||||
|
# Block new DMA-capable devices while the screen is locked (compensates if firmware
|
||||||
|
# Kernel DMA Protection is absent - see Domain D / open question §8).
|
||||||
|
$fve = 'HKLM:\SOFTWARE\Policies\Microsoft\FVE'
|
||||||
|
New-Item $fve -Force | Out-Null
|
||||||
|
Set-ItemProperty $fve -Name DisableExternalDMAUnderLock -Type DWord -Value 1
|
||||||
|
|
||||||
|
# Prefer hibernate over sleep (keys not left resident in RAM as long).
|
||||||
|
powercfg /hibernate on 2>$null
|
||||||
|
# TODO-M1: set lid-close + idle -> hibernate via powercfg; deny camera/mic per-app
|
||||||
|
# (Device Manager disable is the stopgap; the Pocket 4 has NO hardware kill switch).
|
||||||
|
# NOTE: SilverDuress (Stack, v1.1) provides duress-PIN / panic-wipe - installed by module 08.
|
||||||
|
|
||||||
|
Write-Host ' [G] auto-lock=120s, password-on-wake, DMA-blocked-while-locked, hibernate on.'
|
||||||
36
windows/hardening/07-privacy-update.ps1
Normal file
36
windows/hardening/07-privacy-update.ps1
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Domain H: Privacy minimisation & update integrity
|
||||||
|
Trim telemetry tasks/services at GP+service+firewall layers. Do NOT block
|
||||||
|
Microsoft domains in the hosts file (breaks Windows Update; violates
|
||||||
|
design-principle #13). Keep Windows Update ON. Publish residual telemetry.
|
||||||
|
Spec: ../hardening-spec.md (H) | SCAFFOLD (M1).
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param()
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[H] Privacy minimisation & update integrity'
|
||||||
|
|
||||||
|
# Disable telemetry/feedback scheduled tasks (keep update/time/security tasks).
|
||||||
|
$tasks = @(
|
||||||
|
'\Microsoft\Windows\Application Experience\Microsoft Compatibility Appraiser'
|
||||||
|
'\Microsoft\Windows\Application Experience\ProgramDataUpdater'
|
||||||
|
'\Microsoft\Windows\Customer Experience Improvement Program\Consolidator'
|
||||||
|
'\Microsoft\Windows\Customer Experience Improvement Program\UsbCeip'
|
||||||
|
'\Microsoft\Windows\Feedback\Siuf\DmClient'
|
||||||
|
)
|
||||||
|
foreach ($t in $tasks) { Disable-ScheduledTask -TaskPath (Split-Path $t) -TaskName (Split-Path $t -Leaf) -EA SilentlyContinue | Out-Null }
|
||||||
|
|
||||||
|
# CEIP off.
|
||||||
|
$sqm = 'HKLM:\SOFTWARE\Policies\Microsoft\SQMClient\Windows'
|
||||||
|
New-Item $sqm -Force | Out-Null; Set-ItemProperty $sqm -Name CEIPEnable -Type DWord -Value 0
|
||||||
|
|
||||||
|
# Windows Update STAYS ON (update-or-die). We minimise telemetry, never patching.
|
||||||
|
Get-Service wuauserv | Set-Service -StartupType Automatic
|
||||||
|
# Guard: assert the hosts file contains no Microsoft update/licensing domains (anti-footgun).
|
||||||
|
$hosts = Get-Content "$env:windir\System32\drivers\etc\hosts" -EA SilentlyContinue
|
||||||
|
if ($hosts -match 'microsoft\.com|windowsupdate|msftncsi|login\.live') {
|
||||||
|
Write-Warning ' hosts file blocks Microsoft domains - REMOVE (breaks Windows Update).'
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO-M1: run tests\telemetry-leak test; document the irreducible residual (we publish, not claim zero).
|
||||||
|
|
||||||
|
Write-Host ' [H] telemetry tasks/CEIP off; Windows Update preserved.'
|
||||||
27
windows/hardening/08-stack-install.ps1
Normal file
27
windows/hardening/08-stack-install.ps1
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | SilverLABS Application Stack
|
||||||
|
The Stack is the spine (design-principle #7). Install native Windows builds
|
||||||
|
and set SilverBrowser default + SilverVPN always-on kill-switch.
|
||||||
|
Spec: ../hardening-spec.md (#4) | SCAFFOLD (M4): some components are
|
||||||
|
Linux-MVP today (windows/README.md) - their Windows builds may lag.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param([string]$StackDir = "$PSScriptRoot\..\stack-installer")
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Stop'
|
||||||
|
Write-Host '[Stack] SilverLABS Application Stack'
|
||||||
|
|
||||||
|
# Component -> hardening-spec mapping:
|
||||||
|
# SilverBrowser (A,H) default browser | SilverVPN (F) always-on kill-switch
|
||||||
|
# SilverSync (A) replaces OneDrive | SilverChat (F) E2EE over VPN
|
||||||
|
# SilverDuress (G) duress/panic-wipe | SilverKeys (C,A) pwd/2FA + offline BL recovery key
|
||||||
|
$components = 'SilverBrowser','SilverVPN','SilverSync','SilverChat','SilverDuress','SilverKeys'
|
||||||
|
|
||||||
|
foreach ($c in $components) {
|
||||||
|
# TODO-M4: install $StackDir\$c\*.msi/.exe silently; verify signature against the
|
||||||
|
# SilverLABS signing key (trust-model.md) before install.
|
||||||
|
Write-Warning " $c install pending native Windows build (M4)."
|
||||||
|
}
|
||||||
|
|
||||||
|
# TODO-M4: set SilverBrowser as default http/https handler; enable SilverVPN kill-switch
|
||||||
|
# (no plaintext fallback); register SilverDuress.
|
||||||
|
|
||||||
|
Write-Host ' [Stack] mapping staged; installs land at M4.'
|
||||||
59
windows/hardening/Verify-SilverMetalWindows.ps1
Normal file
59
windows/hardening/Verify-SilverMetalWindows.ps1
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<# SilverMetal Enhanced - Windows | Verification
|
||||||
|
Asserts the hardening-spec.md verification gates and emits a report. Evidence
|
||||||
|
before assertions: each check reports the observed value, not a claim.
|
||||||
|
Spec: ../hardening-spec.md (§6) | SCAFFOLD (M1): fill remaining gates.
|
||||||
|
Exit code 0 = all pass; non-zero = count of failed gates.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()] param([string]$ReportPath = "$env:ProgramData\SilverMetal\verify-report.json")
|
||||||
|
Set-StrictMode -Version Latest; $ErrorActionPreference = 'Continue'
|
||||||
|
|
||||||
|
$results = [ordered]@{}
|
||||||
|
function Test-Gate { param([string]$Name,[scriptblock]$Check)
|
||||||
|
try { $v = & $Check; $results[$Name] = @{ pass = [bool]$v.pass; detail = $v.detail } }
|
||||||
|
catch { $results[$Name] = @{ pass = $false; detail = "error: $_" } }
|
||||||
|
}
|
||||||
|
|
||||||
|
Test-Gate 'Telemetry=Security(0)' {
|
||||||
|
$v = (Get-ItemProperty 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' -Name AllowTelemetry -EA Stop).AllowTelemetry
|
||||||
|
@{ pass = ($v -eq 0); detail = "AllowTelemetry=$v" }
|
||||||
|
}
|
||||||
|
Test-Gate 'BitLocker XtsAes256 + TpmPin' {
|
||||||
|
$bl = Get-BitLockerVolume -MountPoint $env:SystemDrive -EA Stop
|
||||||
|
$hasPin = ($bl.KeyProtector.KeyProtectorType -contains 'TpmPin')
|
||||||
|
@{ pass = ($bl.ProtectionStatus -eq 'On' -and $bl.EncryptionMethod -eq 'XtsAes256' -and $hasPin)
|
||||||
|
detail = "$($bl.ProtectionStatus)/$($bl.EncryptionMethod)/TpmPin=$hasPin" }
|
||||||
|
}
|
||||||
|
Test-Gate 'VBS + HVCI + CredentialGuard running' {
|
||||||
|
$dg = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard -EA Stop
|
||||||
|
$svc = $dg.SecurityServicesRunning
|
||||||
|
@{ pass = (($svc -contains 1) -and ($svc -contains 2)); detail = "running=$($svc -join ',')" }
|
||||||
|
}
|
||||||
|
Test-Gate 'WDAC enforced' {
|
||||||
|
$dg = Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard -EA Stop
|
||||||
|
@{ pass = ($dg.CodeIntegrityPolicyEnforcementStatus -eq 2)
|
||||||
|
detail = "enforcement=$($dg.CodeIntegrityPolicyEnforcementStatus) (2=enforced,1=audit)" }
|
||||||
|
}
|
||||||
|
Test-Gate 'Secure Boot enabled' {
|
||||||
|
@{ pass = (Confirm-SecureBootUEFI); detail = 'Confirm-SecureBootUEFI' }
|
||||||
|
}
|
||||||
|
Test-Gate 'Firewall default-deny inbound' {
|
||||||
|
$p = Get-NetFirewallProfile -EA Stop
|
||||||
|
@{ pass = -not ($p.DefaultInboundAction -contains 'Allow'); detail = ($p.DefaultInboundAction -join ',') }
|
||||||
|
}
|
||||||
|
Test-Gate 'Windows Update healthy' {
|
||||||
|
$s = Get-Service wuauserv -EA Stop
|
||||||
|
@{ pass = ($s.StartType -ne 'Disabled'); detail = "$($s.Status)/$($s.StartType)" }
|
||||||
|
}
|
||||||
|
# TODO-M1: VPN kill-switch egress test; telemetry-leak capture; Stack functional check.
|
||||||
|
|
||||||
|
$pass = ($results.Values | Where-Object { $_.pass }).Count
|
||||||
|
$fail = ($results.Values | Where-Object { -not $_.pass }).Count
|
||||||
|
New-Item (Split-Path $ReportPath) -ItemType Directory -Force -EA SilentlyContinue | Out-Null
|
||||||
|
$results | ConvertTo-Json -Depth 4 | Set-Content $ReportPath
|
||||||
|
$results.GetEnumerator() | ForEach-Object {
|
||||||
|
$c = if ($_.Value.pass) { 'Green' } else { 'Red' }
|
||||||
|
Write-Host ("[{0}] {1} - {2}" -f ($(if($_.Value.pass){'PASS'}else{'FAIL'}), $_.Key, $_.Value.detail)) -ForegroundColor $c
|
||||||
|
}
|
||||||
|
Write-Host "`n$pass passed, $fail failed. Report: $ReportPath"
|
||||||
|
exit $fail
|
||||||
17
windows/installer/README.md
Normal file
17
windows/installer/README.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# windows/installer
|
||||||
|
|
||||||
|
The custom packed-ISO build pipeline. See [`../iso-builder.md`](../iso-builder.md) for the design.
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `build.ps1` | Pipeline orchestrator (7 stages). Run on Windows + Windows ADK. |
|
||||||
|
| `inputs.manifest.json` | Pinned inputs — base ISO SHA-256, driver-pack/Stack/tool versions. The Microsoft ISO is an **input, never committed**. |
|
||||||
|
| `autounattend/autounattend.xml` | OOBE automation — local account (no MSA), regional, BitLocker-ready disk layout, hands off to first-boot. |
|
||||||
|
| `oem/SetupComplete.cmd` | First-boot entry point — runs the shared `../hardening/` modules, then schedules `Verify`. |
|
||||||
|
|
||||||
|
**Usage (M2+):**
|
||||||
|
```powershell
|
||||||
|
.\build.ps1 -SourceIso 'D:\Win11_IoT_Enterprise_LTSC_x64.iso'
|
||||||
|
```
|
||||||
|
|
||||||
|
Current status: **M0 scaffold** — stages 2–7 throw `NotImplemented` until M2/M3.
|
||||||
65
windows/installer/autounattend/autounattend.xml
Normal file
65
windows/installer/autounattend/autounattend.xml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
SilverMetal Enhanced - Windows : Windows 11 IoT Enterprise LTSC answer file.
|
||||||
|
|
||||||
|
Purpose: automate OOBE, force a LOCAL account (no Microsoft Account / no cloud
|
||||||
|
key escrow), set regional defaults, prepare a BitLocker-ready disk layout, and
|
||||||
|
hand off to $OEM$\SetupComplete.cmd for first-boot hardening.
|
||||||
|
|
||||||
|
SCAFFOLD (M0). Disk layout + image selectors are filled at M2 against the
|
||||||
|
licensed media. Do NOT embed product keys, PINs, or secrets here.
|
||||||
|
|
||||||
|
Design: ../../iso-builder.md Controls: ../../hardening-spec.md (domains A, C)
|
||||||
|
-->
|
||||||
|
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||||
|
|
||||||
|
<settings pass="windowsPE">
|
||||||
|
<component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64"
|
||||||
|
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<SetupUILanguage><UILanguage>en-GB</UILanguage></SetupUILanguage>
|
||||||
|
<InputLocale>0809:00000809</InputLocale>
|
||||||
|
<SystemLocale>en-GB</SystemLocale>
|
||||||
|
<UILanguage>en-GB</UILanguage>
|
||||||
|
<UserLocale>en-GB</UserLocale>
|
||||||
|
</component>
|
||||||
|
<component name="Microsoft-Windows-Setup" processorArchitecture="amd64"
|
||||||
|
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<!-- TODO-M2: DiskConfiguration (GPT, ESP + MSR + Windows), single GPT disk, BitLocker-ready.
|
||||||
|
ImageInstall/OSImage/InstallFrom MetaData = IoT Enterprise LTSC index (see inputs.manifest.json). -->
|
||||||
|
<UserData>
|
||||||
|
<ProductKey><!-- TODO-M2: IoT Enterprise LTSC key, build-time injected; NOT committed --></ProductKey>
|
||||||
|
<AcceptEula>true</AcceptEula>
|
||||||
|
</UserData>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
|
||||||
|
<settings pass="oobeSystem">
|
||||||
|
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64"
|
||||||
|
publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||||
|
<OOBE>
|
||||||
|
<HideEULAPage>true</HideEULAPage>
|
||||||
|
<HideOnlineAccountScreens>true</HideOnlineAccountScreens> <!-- force local account -->
|
||||||
|
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
||||||
|
<ProtectYourPC>3</ProtectYourPC> <!-- disable "send data" express settings -->
|
||||||
|
</OOBE>
|
||||||
|
<UserAccounts>
|
||||||
|
<!-- TODO-M2: provision a local admin (no MSA). Password set at provisioning, not committed. -->
|
||||||
|
<LocalAccounts>
|
||||||
|
<LocalAccount wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
||||||
|
<Name>silvermetal</Name>
|
||||||
|
<Group>Administrators</Group>
|
||||||
|
<DisplayName>SilverMetal</DisplayName>
|
||||||
|
</LocalAccount>
|
||||||
|
</LocalAccounts>
|
||||||
|
</UserAccounts>
|
||||||
|
<FirstLogonCommands>
|
||||||
|
<SynchronousCommand wcm:action="add" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
|
||||||
|
<Order>1</Order>
|
||||||
|
<CommandLine>cmd /c C:\Windows\Setup\Scripts\SetupComplete.cmd</CommandLine>
|
||||||
|
<Description>SilverMetal first-boot hardening</Description>
|
||||||
|
</SynchronousCommand>
|
||||||
|
</FirstLogonCommands>
|
||||||
|
</component>
|
||||||
|
</settings>
|
||||||
|
|
||||||
|
</unattend>
|
||||||
100
windows/installer/build.ps1
Normal file
100
windows/installer/build.ps1
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
SilverMetal Enhanced - Windows : custom packed ISO build pipeline.
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Turns an official Windows 11 IoT Enterprise LTSC ISO (an INPUT, never
|
||||||
|
redistributed) plus the SilverMetal config layer into a hardened, branded,
|
||||||
|
UEFI-bootable ISO with a signed build attestation.
|
||||||
|
|
||||||
|
Design: ../iso-builder.md Controls: ../hardening-spec.md
|
||||||
|
|
||||||
|
Build host requirement: Windows + Windows ADK (DISM + oscdimg).
|
||||||
|
|
||||||
|
.NOTES
|
||||||
|
SCAFFOLD (M0). Stage bodies are stubbed; they are fleshed out at M2.
|
||||||
|
Each stage maps 1:1 to iso-builder.md section 3.
|
||||||
|
#>
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory)] [string] $SourceIso, # licensed IoT Enterprise LTSC ISO
|
||||||
|
[string] $Manifest = "$PSScriptRoot\inputs.manifest.json",
|
||||||
|
[string] $WorkDir = "$env:TEMP\silvermetal-build",
|
||||||
|
[string] $OutputIso = "$PSScriptRoot\out\SilverMetal-Enhanced-Windows.iso",
|
||||||
|
[switch] $SkipInputVerify
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Write-Stage { param([string]$Msg) Write-Host "==> $Msg" -ForegroundColor Cyan }
|
||||||
|
|
||||||
|
# --- 1. Verify input -------------------------------------------------------
|
||||||
|
function Invoke-VerifyInput {
|
||||||
|
Write-Stage 'Stage 1: verify input ISO against pinned manifest'
|
||||||
|
$m = Get-Content $Manifest -Raw | ConvertFrom-Json
|
||||||
|
$expected = $m.baseImage.isoSha256
|
||||||
|
if ($SkipInputVerify -or $expected -like 'TODO*') {
|
||||||
|
Write-Warning 'Input hash not pinned yet (M2). Skipping verification.'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$actual = (Get-FileHash -Algorithm SHA256 -Path $SourceIso).Hash
|
||||||
|
if ($actual -ne $expected) { throw "Source ISO SHA-256 mismatch.`n expected: $expected`n actual: $actual" }
|
||||||
|
Write-Host ' ISO hash verified.'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 2. Extract ------------------------------------------------------------
|
||||||
|
function Invoke-Extract {
|
||||||
|
Write-Stage 'Stage 2: extract ISO to work dir'
|
||||||
|
# TODO-M2: mount $SourceIso, copy contents to $WorkDir\iso, export install.wim to $WorkDir\wim
|
||||||
|
throw 'NotImplemented (M2): extract'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 3. Service the WIM offline (DISM) -------------------------------------
|
||||||
|
function Invoke-ServiceWim {
|
||||||
|
Write-Stage 'Stage 3: offline-service install.wim (drivers, updates, debloat, baseline policy, Stack staging)'
|
||||||
|
# TODO-M2: DISM /Mount-Image; /Add-Driver (windows\drivers); /Add-Package (cumulative);
|
||||||
|
# remove appx from windows\debloat; load offline hives + apply windows\policies baseline;
|
||||||
|
# stage Stack + $OEM$ payload; /Unmount-Image /Commit
|
||||||
|
throw 'NotImplemented (M2): service WIM'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 4. Inject answer file + first-boot payload ----------------------------
|
||||||
|
function Invoke-InjectUnattend {
|
||||||
|
Write-Stage 'Stage 4: inject autounattend.xml + $OEM$\SetupComplete.cmd + hardening modules'
|
||||||
|
# TODO-M2: copy autounattend\autounattend.xml to ISO root; lay $OEM$\SetupComplete.cmd
|
||||||
|
# + windows\hardening\* into the image so first boot can run them
|
||||||
|
throw 'NotImplemented (M2): inject unattend'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 5. Brand --------------------------------------------------------------
|
||||||
|
function Invoke-Brand {
|
||||||
|
Write-Stage 'Stage 5: apply branding (boot/OOBE wallpaper, computer-name pattern)'
|
||||||
|
# TODO-M4: from ..\..\shared\branding
|
||||||
|
Write-Warning ' Branding deferred to M4.'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 6. Repack -------------------------------------------------------------
|
||||||
|
function Invoke-Repack {
|
||||||
|
Write-Stage 'Stage 6: repack UEFI-bootable ISO via oscdimg'
|
||||||
|
# TODO-M2: oscdimg -m -o -u2 -udfver102 -bootdata:2#... -> $OutputIso
|
||||||
|
throw 'NotImplemented (M2): repack'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 7. Attest -------------------------------------------------------------
|
||||||
|
function Invoke-Attest {
|
||||||
|
Write-Stage 'Stage 7: emit SHA-256 + SBOM + signed build attestation'
|
||||||
|
# TODO-M3: hash $OutputIso; build SBOM from manifest + tool versions; sign (trust-model.md)
|
||||||
|
throw 'NotImplemented (M3): attest'
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- orchestrate -----------------------------------------------------------
|
||||||
|
Invoke-VerifyInput
|
||||||
|
Invoke-Extract
|
||||||
|
Invoke-ServiceWim
|
||||||
|
Invoke-InjectUnattend
|
||||||
|
Invoke-Brand
|
||||||
|
Invoke-Repack
|
||||||
|
Invoke-Attest
|
||||||
|
Write-Host "`nBuild complete: $OutputIso" -ForegroundColor Green
|
||||||
38
windows/installer/inputs.manifest.json
Normal file
38
windows/installer/inputs.manifest.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"$comment": "Pinned inputs for a reproducible SilverMetal Enhanced - Windows ISO build. The base Windows ISO is licensed and NEVER committed; it is referenced by SHA-256 only. Fill the TODO hashes/versions at M2 against the actual licensed media and driver pack.",
|
||||||
|
"schemaVersion": 1,
|
||||||
|
"product": "SilverMetal Enhanced - Windows",
|
||||||
|
"referenceDevice": "GPD Pocket 4 (AMD Ryzen AI 9 HX 370 / Strix Point)",
|
||||||
|
"baseImage": {
|
||||||
|
"edition": "Windows 11 IoT Enterprise LTSC",
|
||||||
|
"arch": "x64",
|
||||||
|
"isoSha256": "TODO-M2-pin-against-licensed-media",
|
||||||
|
"wimImageName": "Windows 11 IoT Enterprise LTSC",
|
||||||
|
"wimImageIndex": null
|
||||||
|
},
|
||||||
|
"driverPack": {
|
||||||
|
"name": "GPD Pocket 4 driver pack",
|
||||||
|
"version": "TODO-M2",
|
||||||
|
"sha256": "TODO-M2",
|
||||||
|
"source": "https://gpd.hk (verify) — confirm redistribution terms"
|
||||||
|
},
|
||||||
|
"cumulativeUpdate": {
|
||||||
|
"kb": "TODO-M2-latest-at-build",
|
||||||
|
"sha256": "TODO-M2"
|
||||||
|
},
|
||||||
|
"stack": {
|
||||||
|
"$comment": "Native Windows builds; some components are Linux-MVP per windows/README.md and may lag.",
|
||||||
|
"SilverBrowser": "TODO",
|
||||||
|
"SilverVPN": "from SilverLABS/SilverVPN (MAUI Windows client)",
|
||||||
|
"SilverSync": "TODO",
|
||||||
|
"SilverChat": "from SilverVPN.Client.Chat",
|
||||||
|
"SilverDuress": "TODO",
|
||||||
|
"SilverKeys": "TODO"
|
||||||
|
},
|
||||||
|
"tooling": {
|
||||||
|
"$comment": "Recorded for the build attestation (reproducibility scope: pinned inputs + recorded tools + output SHA + SBOM; not bit-identical).",
|
||||||
|
"windowsAdk": "TODO-M2",
|
||||||
|
"dism": "TODO-M2",
|
||||||
|
"oscdimg": "TODO-M2"
|
||||||
|
}
|
||||||
|
}
|
||||||
32
windows/installer/oem/SetupComplete.cmd
Normal file
32
windows/installer/oem/SetupComplete.cmd
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
@echo off
|
||||||
|
REM ===========================================================================
|
||||||
|
REM SilverMetal Enhanced - Windows : first-boot entry point.
|
||||||
|
REM Invoked once by autounattend.xml FirstLogonCommands. Runs the shared
|
||||||
|
REM hardening/ modules in order, logs to disk, then schedules verification.
|
||||||
|
REM
|
||||||
|
REM The hardening/ modules are staged into C:\Windows\Setup\Scripts\hardening
|
||||||
|
REM by build.ps1 (stage 4). They are SHARED with the self-apply track.
|
||||||
|
REM
|
||||||
|
REM Design: ../../iso-builder.md Controls: ../../hardening-spec.md
|
||||||
|
REM SCAFFOLD (M0): module bodies stubbed; safe to run (modules log and no-op
|
||||||
|
REM until implemented at M1).
|
||||||
|
REM ===========================================================================
|
||||||
|
|
||||||
|
set LOG=C:\Windows\Setup\Scripts\silvermetal-firstboot.log
|
||||||
|
set HARD=C:\Windows\Setup\Scripts\hardening
|
||||||
|
|
||||||
|
echo [%DATE% %TIME%] SilverMetal first-boot start >> "%LOG%"
|
||||||
|
|
||||||
|
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||||
|
"$ErrorActionPreference='Stop';" ^
|
||||||
|
"Get-ChildItem '%HARD%\0*.ps1' | Sort-Object Name | ForEach-Object {" ^
|
||||||
|
" Write-Host \"--> $($_.Name)\";" ^
|
||||||
|
" & $_.FullName *>> '%LOG%'" ^
|
||||||
|
"}" >> "%LOG%" 2>&1
|
||||||
|
|
||||||
|
REM Register the verification task to run after the first full boot/login.
|
||||||
|
schtasks /Create /TN "SilverMetal\Verify" /SC ONLOGON /RL HIGHEST /F ^
|
||||||
|
/TR "powershell -NoProfile -ExecutionPolicy Bypass -File %HARD%\Verify-SilverMetalWindows.ps1" >> "%LOG%" 2>&1
|
||||||
|
|
||||||
|
echo [%DATE% %TIME%] SilverMetal first-boot done >> "%LOG%"
|
||||||
|
exit /b 0
|
||||||
131
windows/iso-builder.md
Normal file
131
windows/iso-builder.md
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
# SilverMetal Enhanced — Windows: ISO Builder
|
||||||
|
|
||||||
|
> **Status**: v1 design — 2026-06-08. Implements the productized SKU build for the hardening defined in [`hardening-spec.md`](hardening-spec.md). Reference device: GPD Pocket 4.
|
||||||
|
|
||||||
|
This document describes the **reproducible build pipeline** that turns an official Windows 11 IoT Enterprise LTSC ISO plus the SilverMetal config layer into a hardened, branded, UEFI-bootable **custom packed ISO**, with a signed build attestation.
|
||||||
|
|
||||||
|
It is bound by the same documents as the hardening spec: [`../docs/threat-model.md`](../docs/threat-model.md), [`../docs/design-principles.md`](../docs/design-principles.md), and [`../docs/trust-model.md`](../docs/trust-model.md).
|
||||||
|
|
||||||
|
## 1. Licensing frame (why this is legitimate)
|
||||||
|
|
||||||
|
Windows 11 **IoT Enterprise LTSC** is licensed through the OEM / embedded channel, whose explicit purpose is building **customized, locked-down, preinstalled images** on devices a solution-builder ships. Creating a custom packed image and preinstalling it on hardware we sell is the *intended, blessed* use — not a grey area.
|
||||||
|
|
||||||
|
| Track | Status under IoT Enterprise LTSC |
|
||||||
|
|---|---|
|
||||||
|
| **Preflashed SilverMetal SKU** (we sell the device) | ✅ Build + ship our custom image — licensed per device, intended use |
|
||||||
|
| **Self-apply free track** (user hardens own device) | ⚠️ No public prebuilt-ISO redistribution. Ships as a **builder** that consumes the user's own official ISO + license — the same `hardening/` modules, applied to their image |
|
||||||
|
|
||||||
|
The Microsoft ISO is therefore always an **input**, never committed to this repo. We ship *our layer*; the licensee provides the base.
|
||||||
|
|
||||||
|
> **Procurement note (verify before pricing the SKU):** IoT Enterprise LTSC is obtained via authorized OEM distributors; per-device licensing may carry minimum-order / agreement terms. Confirm with the distributor.
|
||||||
|
|
||||||
|
## 2. Inputs
|
||||||
|
|
||||||
|
All inputs are pinned by hash in [`installer/inputs.manifest.json`](installer/inputs.manifest.json):
|
||||||
|
|
||||||
|
| Input | Source | In repo? |
|
||||||
|
|---|---|---|
|
||||||
|
| Windows 11 IoT Enterprise LTSC ISO | Licensed (operator/distributor) | No — pinned by SHA-256 |
|
||||||
|
| GPD Pocket 4 driver pack | GPD (verified source) | `drivers/` or sourced manifest |
|
||||||
|
| SilverLABS Stack (native Windows builds) | Stack component repos / artifacts | Referenced by version |
|
||||||
|
| SilverMetal config layer | This repo (`hardening/`, `policies/`, `wdac/`, `debloat/`, `autounattend/`, `oem/`, branding) | Yes |
|
||||||
|
|
||||||
|
## 3. Build stages
|
||||||
|
|
||||||
|
Orchestrated by [`installer/build.ps1`](installer/build.ps1). Runs on a **Windows host with the Windows ADK** (DISM + `oscdimg`).
|
||||||
|
|
||||||
|
1. **Verify input** — assert the source ISO SHA-256 matches the pinned manifest (supply-chain integrity).
|
||||||
|
2. **Extract** — expand the ISO to a working directory.
|
||||||
|
3. **Service the WIM offline (DISM)**:
|
||||||
|
- Select the IoT Enterprise LTSC image index.
|
||||||
|
- `/Add-Driver` the GPD Pocket 4 driver pack (Strix Point GPU, sensors/auto-rotate, Wi-Fi, fingerprint).
|
||||||
|
- `/Add-Package` the latest cumulative update (slipstream).
|
||||||
|
- Trim residual provisioned appx (LTSC is already lean — minimal list in `debloat/`).
|
||||||
|
- Load offline registry hives → apply the **offline-able baseline** (telemetry floor, service disables) from `policies/`.
|
||||||
|
- Stage the Stack installers + first-boot payload into the image.
|
||||||
|
- Commit + unmount.
|
||||||
|
4. **Inject answer file + first-boot payload**:
|
||||||
|
- `autounattend.xml` — OOBE automation, **local account** (no MSA), regional settings, BitLocker-ready disk layout.
|
||||||
|
- `$OEM$\SetupComplete.cmd` — first-boot entry point that runs the online `hardening/` modules and installs the Stack.
|
||||||
|
5. **Brand** — boot/OOBE wallpaper + computer-name pattern from [`../shared/branding`](../shared/branding).
|
||||||
|
6. **Repack** — `oscdimg` produces a UEFI-bootable ISO (efisys boot image, El Torito).
|
||||||
|
7. **Attest** — emit output ISO SHA-256, an **SBOM** (every component + version), and a signed build attestation (design-principle #4).
|
||||||
|
|
||||||
|
## 4. Where each hardening control is applied
|
||||||
|
|
||||||
|
The control domains in [`hardening-spec.md`](hardening-spec.md) split across three layers:
|
||||||
|
|
||||||
|
| Layer | Controls | Mechanism |
|
||||||
|
|---|---|---|
|
||||||
|
| **Baked offline (in WIM)** | Telemetry floor, service disables, appx trim, drivers, baseline registry policy, Stack staging | DISM + offline hive edits |
|
||||||
|
| **First-boot (online)** | Local account, VBS/HVCI/Credential Guard, ASR rules, **WDAC (audit)**, firewall, encrypted DNS, Stack + SilverVPN install, scheduled `Verify` task | `SetupComplete.cmd` → `hardening/` modules |
|
||||||
|
| **Interactive / firmware — NOT in ISO** | Secure Boot custom-key enrollment, **BitLocker PIN**, BIOS admin password | Operator at provisioning (SKU) or documented user step (self-apply). The ISO *enables* BitLocker and *forces* PIN enrollment; it cannot ship a PIN or touch firmware. |
|
||||||
|
|
||||||
|
**The `hardening/` modules are shared.** The same module set is invoked by the ISO's first-boot path *and* by the self-apply / milestone-1 standalone path. Write once, used both ways.
|
||||||
|
|
||||||
|
## 5. Reproducibility (honest scope)
|
||||||
|
|
||||||
|
Windows image servicing is **not bit-for-bit deterministic** the way the Linux ISO pipeline is (WIM internal timestamps, servicing-stack non-determinism). So for this product, "reproducible" means:
|
||||||
|
|
||||||
|
- **Pinned inputs** (every source hashed in the manifest)
|
||||||
|
- **Recorded tool versions** (ADK, DISM, servicing stack)
|
||||||
|
- **Output ISO SHA-256 + SBOM** published per build
|
||||||
|
- **Signed build attestation** linking published artifact ↔ published source + inputs
|
||||||
|
|
||||||
|
Bit-identical rebuild is a **stretch goal**, documented as such — we do not claim it (design-principle #2). This is weaker than the Linux line's reproducible-build guarantee, and we say so to buyers.
|
||||||
|
|
||||||
|
## 6. Directory layout
|
||||||
|
|
||||||
|
```
|
||||||
|
windows/
|
||||||
|
├── installer/
|
||||||
|
│ ├── build.ps1 # pipeline orchestrator
|
||||||
|
│ ├── inputs.manifest.json # pinned ISO SHA, driver-pack ver, Stack vers, tool vers
|
||||||
|
│ ├── autounattend/
|
||||||
|
│ │ └── autounattend.xml # OOBE automation + local account + disk layout
|
||||||
|
│ ├── oem/
|
||||||
|
│ │ └── SetupComplete.cmd # first-boot entry → runs hardening/ modules
|
||||||
|
│ └── README.md
|
||||||
|
├── hardening/ # §A–H PowerShell modules + Verify ← SHARED (ISO + self-apply)
|
||||||
|
│ ├── 00-provisioning.ps1 # A
|
||||||
|
│ ├── 01-boot-firmware.ps1 # B (stages keys; firmware steps documented)
|
||||||
|
│ ├── 02-data-at-rest.ps1 # C (BitLocker TPM+PIN)
|
||||||
|
│ ├── 03-kernel-credential.ps1# D (VBS/HVCI/CredGuard/DMA)
|
||||||
|
│ ├── 04-app-control.ps1 # E (WDAC audit, ASR, Defender)
|
||||||
|
│ ├── 05-network-radios.ps1 # F (firewall, DNS, WiFi-only)
|
||||||
|
│ ├── 06-physical-lock.ps1 # G (lock-screen, DMA lock, cam/mic)
|
||||||
|
│ ├── 07-privacy-update.ps1 # H (telemetry trim, update integrity)
|
||||||
|
│ ├── 08-stack-install.ps1 # SilverLABS Stack
|
||||||
|
│ └── Verify-SilverMetalWindows.ps1
|
||||||
|
├── policies/ # GP/ADMX exports + offline .reg/.pol baseline
|
||||||
|
├── wdac/ # WDAC base policy (XML) + compiled .cip
|
||||||
|
├── debloat/ # appx removal list, service-disable scripts
|
||||||
|
├── stack-installer/ # Stack package builders/installers
|
||||||
|
├── drivers/ # GPD Pocket 4 driver pack (or sourced manifest)
|
||||||
|
└── tests/ # telemetry-leak test, hardening-baseline test
|
||||||
|
```
|
||||||
|
|
||||||
|
## 7. Milestones
|
||||||
|
|
||||||
|
| Milestone | Deliverable | Needs hardware? |
|
||||||
|
|---|---|---|
|
||||||
|
| **M0** | This design + scaffolded tree | No |
|
||||||
|
| **M1** | `autounattend.xml` + `hardening/` modules runnable standalone — hardens the Pocket 4 with no pipeline | Yes (the unit) |
|
||||||
|
| **M2** | DISM servicing + `oscdimg` repack → first packed ISO, built locally on a Windows + ADK box | Driver pack |
|
||||||
|
| **M3** | `.gitea/workflows/build-iso-windows.yaml` (Windows runner) + attestation/SBOM + telemetry-leak gate | Windows runner |
|
||||||
|
| **M4** | Branding, full Stack integration, all verification gates green | Stack Windows builds |
|
||||||
|
|
||||||
|
## 8. Build environment & deferred items
|
||||||
|
|
||||||
|
- **Build host**: Windows + Windows ADK (DISM + `oscdimg`). A Windows CI runner is required for M3 (mirrors the existing Linux `.gitea/workflows/build-iso-linux.yaml`).
|
||||||
|
- **Cross-build on Linux** (wimlib + xorriso) is possible but UEFI boot-file assembly is fiddly — **deferred**, Windows-runner path is canonical.
|
||||||
|
- **Stack Windows builds**: some Stack components are still "Linux MVP" per [`README.md`](README.md); their native Windows builds may lag M4.
|
||||||
|
- **Driver-pack sourcing**: confirm redistribution terms for the GPD Pocket 4 driver pack, or source at build time from the verified GPD location.
|
||||||
|
|
||||||
|
## 9. Open questions
|
||||||
|
|
||||||
|
Carried from [`hardening-spec.md`](hardening-spec.md) §8 (resolve on the physical unit), plus builder-specific:
|
||||||
|
|
||||||
|
1. Does the IoT Enterprise LTSC media expose the expected image index and OOBE bypass path for `autounattend.xml`?
|
||||||
|
2. Which Pocket 4 drivers are absent from a vanilla LTSC install and must be injected?
|
||||||
|
3. Does `oscdimg` produce a Pocket 4-bootable UEFI image with the device's firmware (test on the unit)?
|
||||||
9
windows/policies/README.md
Normal file
9
windows/policies/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# windows/policies
|
||||||
|
|
||||||
|
Group Policy / ADMX exports and the **offline-applicable baseline** (`.reg` / `.pol`)
|
||||||
|
that `build.ps1` applies into the WIM via offline hive editing (telemetry floor,
|
||||||
|
service disables). The online/runtime policy is applied by the `../hardening/`
|
||||||
|
modules at first boot.
|
||||||
|
|
||||||
|
Populated at **M2** by exporting the prototype unit's applied policy
|
||||||
|
(`LGPO.exe` / registry export) after the `hardening/` modules run on the device.
|
||||||
16
windows/stack-installer/README.md
Normal file
16
windows/stack-installer/README.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# windows/stack-installer
|
||||||
|
|
||||||
|
Native Windows installers for the SilverLABS Application Stack, staged into the
|
||||||
|
image and run by [`../hardening/08-stack-install.ps1`](../hardening/08-stack-install.ps1).
|
||||||
|
|
||||||
|
| Component | hardening-spec mapping | Status |
|
||||||
|
|---|---|---|
|
||||||
|
| SilverBrowser | A, H (default browser) | Linux MVP — Windows build TBD |
|
||||||
|
| SilverVPN | F (always-on kill-switch) | Existing — MAUI Windows client (`SilverLABS/SilverVPN`) |
|
||||||
|
| SilverSync | A (replaces OneDrive) | Linux MVP — Windows build TBD |
|
||||||
|
| SilverChat | F (E2EE over VPN) | Existing (`SilverVPN.Client.Chat`) |
|
||||||
|
| SilverDuress | G (duress / panic-wipe) | v1.1 |
|
||||||
|
| SilverKeys | C, A (pwd/2FA + offline BL recovery key) | v1.1 |
|
||||||
|
|
||||||
|
Installers must be **signature-verified against the SilverLABS signing key**
|
||||||
|
([`../../docs/trust-model.md`](../../docs/trust-model.md)) before install. Lands at **M4**.
|
||||||
14
windows/tests/README.md
Normal file
14
windows/tests/README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# windows/tests
|
||||||
|
|
||||||
|
Verification gates for a SilverMetal Enhanced — Windows build
|
||||||
|
([`../hardening-spec.md`](../hardening-spec.md) §6).
|
||||||
|
|
||||||
|
| Test | What it proves | Status |
|
||||||
|
|---|---|---|
|
||||||
|
| **Hardening-baseline** | All control gates pass | [`../hardening/Verify-SilverMetalWindows.ps1`](../hardening/Verify-SilverMetalWindows.ps1) (M1) |
|
||||||
|
| **Telemetry-leak** | Captures egress on a clean build; classifies every Microsoft contact; **publishes the residual** (we do not claim zero) | TODO-M3 |
|
||||||
|
| **VPN kill-switch** | Tunnel-drop → zero egress | TODO-M1 |
|
||||||
|
| **Update path** | A test update applies + rolls back (update-or-die) | TODO-M3 |
|
||||||
|
|
||||||
|
The telemetry-leak test is the honesty gate: it documents the minimum-feasible
|
||||||
|
Microsoft contact that remains, per design-principle #2.
|
||||||
11
windows/wdac/README.md
Normal file
11
windows/wdac/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# windows/wdac
|
||||||
|
|
||||||
|
WDAC (App Control for Business) policy — the **primary**, kernel-enforced
|
||||||
|
application-control engine for SilverMetal Enhanced — Windows. AppLocker is the
|
||||||
|
documented fallback only.
|
||||||
|
|
||||||
|
**Workflow (design-principle: balanced / audit-first):**
|
||||||
|
1. **M1** — author `silvermetal-base.xml` and deploy in **AUDIT** mode on the prototype unit; run real workloads; collect `CodeIntegrity` audit events.
|
||||||
|
2. **M2** — regenerate the policy from audit events (Windows + Stack + approved dev tools signed/allowed), compile to `.cip`, and **PROMOTE to ENFORCE**.
|
||||||
|
|
||||||
|
The base policy ships pre-authored in the SKU; the prototype builds it from its own audit logs. See [`../hardening-spec.md`](../hardening-spec.md) Domain E.
|
||||||
Reference in New Issue
Block a user