From 3a30a0421e349451902aaf68306f7f5430194b90 Mon Sep 17 00:00:00 2001 From: sysadmin Date: Mon, 8 Jun 2026 15:35:13 +0100 Subject: [PATCH] docs(windows): add ISO-builder design + scaffold the windows/ tree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add windows/iso-builder.md: reproducible custom-packed-ISO pipeline design for SilverMetal Enhanced - Windows on IoT Enterprise LTSC. Covers the licensing frame (IoT = blessed channel for preinstalled custom images; self-apply stays a builder), 7 build stages (verify/extract/DISM-service/inject-unattend/brand/ oscdimg-repack/attest), the offline-vs-first-boot-vs-firmware control split, an honest reproducibility scope (pinned inputs + SBOM + attestation, NOT bit- identical on Windows), and M0-M4 milestones. Scaffold windows/ per the planned layout: - installer/ build.ps1 (7-stage orchestrator, stages stubbed to M2), inputs.manifest.json (pinned-input schema), autounattend.xml (local-account OOBE), oem/SetupComplete.cmd (first-boot runner) - hardening/ shared §A-H PowerShell modules + Verify-SilverMetalWindows.ps1 (used by BOTH the ISO first-boot path and the self-apply track). BitLocker module enforces TPM+PIN and blocks TPM-only. - policies/ wdac/ debloat/ stack-installer/ drivers/ tests/ scaffolded with READMEs; wdac/ documents audit->enforce; debloat/ flags Tiny11/NTLite as an anti-pattern; rename applocker/ -> wdac/ realised. All 11 PowerShell scripts parse clean; manifest JSON + autounattend XML valid. Module bodies are M1 scaffold (safe: log + policy-set; interactive/firmware steps documented, not faked). Co-Authored-By: Claude Opus 4.8 --- windows/debloat/README.md | 10 ++ windows/debloat/appx-remove.txt | 17 +++ windows/drivers/README.md | 15 ++ windows/hardening/00-provisioning.ps1 | 27 ++++ windows/hardening/01-boot-firmware.ps1 | 23 +++ windows/hardening/02-data-at-rest.ps1 | 28 ++++ windows/hardening/03-kernel-credential.ps1 | 38 +++++ windows/hardening/04-app-control.ps1 | 36 +++++ windows/hardening/05-network-radios.ps1 | 31 +++++ windows/hardening/06-physical-lock.ps1 | 32 +++++ windows/hardening/07-privacy-update.ps1 | 36 +++++ windows/hardening/08-stack-install.ps1 | 27 ++++ .../hardening/Verify-SilverMetalWindows.ps1 | 59 ++++++++ windows/installer/README.md | 17 +++ .../installer/autounattend/autounattend.xml | 65 +++++++++ windows/installer/build.ps1 | 100 +++++++++++++ windows/installer/inputs.manifest.json | 38 +++++ windows/installer/oem/SetupComplete.cmd | 32 +++++ windows/iso-builder.md | 131 ++++++++++++++++++ windows/policies/README.md | 9 ++ windows/stack-installer/README.md | 16 +++ windows/tests/README.md | 14 ++ windows/wdac/README.md | 11 ++ 23 files changed, 812 insertions(+) create mode 100644 windows/debloat/README.md create mode 100644 windows/debloat/appx-remove.txt create mode 100644 windows/drivers/README.md create mode 100644 windows/hardening/00-provisioning.ps1 create mode 100644 windows/hardening/01-boot-firmware.ps1 create mode 100644 windows/hardening/02-data-at-rest.ps1 create mode 100644 windows/hardening/03-kernel-credential.ps1 create mode 100644 windows/hardening/04-app-control.ps1 create mode 100644 windows/hardening/05-network-radios.ps1 create mode 100644 windows/hardening/06-physical-lock.ps1 create mode 100644 windows/hardening/07-privacy-update.ps1 create mode 100644 windows/hardening/08-stack-install.ps1 create mode 100644 windows/hardening/Verify-SilverMetalWindows.ps1 create mode 100644 windows/installer/README.md create mode 100644 windows/installer/autounattend/autounattend.xml create mode 100644 windows/installer/build.ps1 create mode 100644 windows/installer/inputs.manifest.json create mode 100644 windows/installer/oem/SetupComplete.cmd create mode 100644 windows/iso-builder.md create mode 100644 windows/policies/README.md create mode 100644 windows/stack-installer/README.md create mode 100644 windows/tests/README.md create mode 100644 windows/wdac/README.md diff --git a/windows/debloat/README.md b/windows/debloat/README.md new file mode 100644 index 0000000..8b38d09 --- /dev/null +++ b/windows/debloat/README.md @@ -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. diff --git a/windows/debloat/appx-remove.txt b/windows/debloat/appx-remove.txt new file mode 100644 index 0000000..7697f15 --- /dev/null +++ b/windows/debloat/appx-remove.txt @@ -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. diff --git a/windows/drivers/README.md b/windows/drivers/README.md new file mode 100644 index 0000000..9cfa6f5 --- /dev/null +++ b/windows/drivers/README.md @@ -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. diff --git a/windows/hardening/00-provisioning.ps1 b/windows/hardening/00-provisioning.ps1 new file mode 100644 index 0000000..5a778b6 --- /dev/null +++ b/windows/hardening/00-provisioning.ps1 @@ -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)' diff --git a/windows/hardening/01-boot-firmware.ps1 b/windows/hardening/01-boot-firmware.ps1 new file mode 100644 index 0000000..dd3020c --- /dev/null +++ b/windows/hardening/01-boot-firmware.ps1 @@ -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)' diff --git a/windows/hardening/02-data-at-rest.ps1 b/windows/hardening/02-data-at-rest.ps1 new file mode 100644 index 0000000..21e8069 --- /dev/null +++ b/windows/hardening/02-data-at-rest.ps1 @@ -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." diff --git a/windows/hardening/03-kernel-credential.ps1 b/windows/hardening/03-kernel-credential.ps1 new file mode 100644 index 0000000..d72e833 --- /dev/null +++ b/windows/hardening/03-kernel-credential.ps1 @@ -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.' diff --git a/windows/hardening/04-app-control.ps1 b/windows/hardening/04-app-control.ps1 new file mode 100644 index 0000000..3ece881 --- /dev/null +++ b/windows/hardening/04-app-control.ps1 @@ -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.' diff --git a/windows/hardening/05-network-radios.ps1 b/windows/hardening/05-network-radios.ps1 new file mode 100644 index 0000000..9104718 --- /dev/null +++ b/windows/hardening/05-network-radios.ps1 @@ -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.' diff --git a/windows/hardening/06-physical-lock.ps1 b/windows/hardening/06-physical-lock.ps1 new file mode 100644 index 0000000..6b83930 --- /dev/null +++ b/windows/hardening/06-physical-lock.ps1 @@ -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.' diff --git a/windows/hardening/07-privacy-update.ps1 b/windows/hardening/07-privacy-update.ps1 new file mode 100644 index 0000000..d39c568 --- /dev/null +++ b/windows/hardening/07-privacy-update.ps1 @@ -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.' diff --git a/windows/hardening/08-stack-install.ps1 b/windows/hardening/08-stack-install.ps1 new file mode 100644 index 0000000..a7be816 --- /dev/null +++ b/windows/hardening/08-stack-install.ps1 @@ -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.' diff --git a/windows/hardening/Verify-SilverMetalWindows.ps1 b/windows/hardening/Verify-SilverMetalWindows.ps1 new file mode 100644 index 0000000..caf67a9 --- /dev/null +++ b/windows/hardening/Verify-SilverMetalWindows.ps1 @@ -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 diff --git a/windows/installer/README.md b/windows/installer/README.md new file mode 100644 index 0000000..0439c89 --- /dev/null +++ b/windows/installer/README.md @@ -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. diff --git a/windows/installer/autounattend/autounattend.xml b/windows/installer/autounattend/autounattend.xml new file mode 100644 index 0000000..29d92ef --- /dev/null +++ b/windows/installer/autounattend/autounattend.xml @@ -0,0 +1,65 @@ + + + + + + + en-GB + 0809:00000809 + en-GB + en-GB + en-GB + + + + + + true + + + + + + + + true + true + true + 3 + + + + + + silvermetal + Administrators + SilverMetal + + + + + + 1 + cmd /c C:\Windows\Setup\Scripts\SetupComplete.cmd + SilverMetal first-boot hardening + + + + + + diff --git a/windows/installer/build.ps1 b/windows/installer/build.ps1 new file mode 100644 index 0000000..3612fcf --- /dev/null +++ b/windows/installer/build.ps1 @@ -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 diff --git a/windows/installer/inputs.manifest.json b/windows/installer/inputs.manifest.json new file mode 100644 index 0000000..90d8317 --- /dev/null +++ b/windows/installer/inputs.manifest.json @@ -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" + } +} diff --git a/windows/installer/oem/SetupComplete.cmd b/windows/installer/oem/SetupComplete.cmd new file mode 100644 index 0000000..87bf28e --- /dev/null +++ b/windows/installer/oem/SetupComplete.cmd @@ -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 diff --git a/windows/iso-builder.md b/windows/iso-builder.md new file mode 100644 index 0000000..c4de73c --- /dev/null +++ b/windows/iso-builder.md @@ -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)? diff --git a/windows/policies/README.md b/windows/policies/README.md new file mode 100644 index 0000000..9a043db --- /dev/null +++ b/windows/policies/README.md @@ -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. diff --git a/windows/stack-installer/README.md b/windows/stack-installer/README.md new file mode 100644 index 0000000..31a617d --- /dev/null +++ b/windows/stack-installer/README.md @@ -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**. diff --git a/windows/tests/README.md b/windows/tests/README.md new file mode 100644 index 0000000..9859c34 --- /dev/null +++ b/windows/tests/README.md @@ -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. diff --git a/windows/wdac/README.md b/windows/wdac/README.md new file mode 100644 index 0000000..590eca6 --- /dev/null +++ b/windows/wdac/README.md @@ -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.