Add Windows card reader, code-signing helpers and playlist diagnostics
- windows/win_card_reader.py: Windows-native card reader via the Raw Input API with a low-level keyboard-hook fallback. - windows/sign_exe.ps1: sign the built executable with a .pfx certificate. - windows/create_self_signed_cert.ps1: generate a self-signed cert for local testing (not trusted by Smart App Control). - windows/verify_sendinput_fix.py: verification helper for the SendInput foreground-unlock fix in run_win.py. - documentation/CODE_SIGNING_SMART_APP_CONTROL.md: signing guidance. - working_files/execute_playlist_retrieve.py, working_files/raw_server_playlist.json: playlist retrieval diagnostics. Note: windows/archive_list.txt and windows/build_last.txt are build output and were committed by request rather than by convention.
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
<#
|
||||
================================================================================
|
||||
Kiwy Signage Player - Code Signing Script
|
||||
================================================================================
|
||||
Signs the built KiwySignagePlayer.exe with an Authenticode certificate.
|
||||
|
||||
For PRODUCTION PCs that have Smart App Control (SAC) ENABLED:
|
||||
- The cert MUST be issued by a reputable public CA (e.g. Sectigo, SSL.com,
|
||||
DigiCert, GlobalSign). Self-signed certs will NOT satisfy SAC.
|
||||
- You must use this script with -CertPath pointing at your .pfx/.p12.
|
||||
|
||||
For DEV/TEST machines where you have admin rights:
|
||||
- A self-signed cert trusted in the local Root store + Trusted Publisher
|
||||
works (see create_self_signed_cert.ps1), but it does NOT satisfy SAC.
|
||||
|
||||
Usage:
|
||||
.\sign_exe.ps1 -CertPath "C:\certs\mycodesign.pfx" -CertPassword "secret"
|
||||
.\sign_exe.ps1 -CertPath "C:\certs\mycodesign.pfx" # prompt for pwd
|
||||
.\sign_exe.ps1 -CertThumbprint "A1B2..." # from cert store
|
||||
.\sign_exe.ps1 -CertPath "C:\certs\mycodesign.pfx" -SkipTimestamp $false
|
||||
|
||||
Optional:
|
||||
-TimestampUrl RFC3161 timestamp server (default DigiCert).
|
||||
Timestamping is REQUIRED for the signature to stay valid
|
||||
after the cert expires and to satisfy Smart App Control.
|
||||
-ExePath Path to the exe to sign (default dist\KiwySignagePlayer\KiwySignagePlayer.exe)
|
||||
-Force Re-sign even if already signed
|
||||
================================================================================
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$CertPath,
|
||||
[string]$CertPassword,
|
||||
[string]$CertThumbprint,
|
||||
[string]$ExePath = (Join-Path $PSScriptRoot 'dist\KiwySignagePlayer\KiwySignagePlayer.exe'),
|
||||
[string]$TimestampUrl = 'http://timestamp.digicert.com',
|
||||
[switch]$SkipTimestamp,
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
Set-Location $PSScriptRoot
|
||||
|
||||
function Find-Signtool {
|
||||
$candidates = @(
|
||||
(Get-Command signtool.exe -ErrorAction SilentlyContinue).Source,
|
||||
"$env:ProgramFiles(x86)\Windows Kits\10\bin\10.0.26100.0\x64\signtool.exe",
|
||||
"$env:ProgramFiles(x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe",
|
||||
"$env:ProgramFiles(x86)\Windows Kits\10\bin\10.0.22000.0\x64\signtool.exe",
|
||||
"$env:ProgramFiles(x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe"
|
||||
)
|
||||
foreach ($c in $candidates) {
|
||||
if ($c -and (Test-Path $c)) { return $c }
|
||||
}
|
||||
# Fallback: newest SDK on disk
|
||||
$sdkBin = "$env:ProgramFiles(x86)\Windows Kits\10\bin"
|
||||
if (Test-Path $sdkBin) {
|
||||
$found = Get-ChildItem $sdkBin -Recurse -Filter signtool.exe -ErrorAction SilentlyContinue |
|
||||
Sort-Object FullName -Descending | Select-Object -First 1 -ExpandProperty FullName
|
||||
if ($found) { return $found }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
$signtool = Find-Signtool
|
||||
if ($signtool) {
|
||||
Write-Host "[INFO ] signtool: $signtool" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[WARN ] signtool.exe not found - will use PowerShell Set-AuthenticodeSignature fallback." -ForegroundColor Yellow
|
||||
Write-Host "[WARN ] NOTE: the fallback cannot apply an RFC3161 timestamp. For production (SAC),"
|
||||
Write-Host "[WARN ] install the Windows SDK signtool: winget install Microsoft.WindowsSDK.10.0.26100"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $ExePath)) {
|
||||
Write-Host "[ERROR] Exe not found: $ExePath" -ForegroundColor Red
|
||||
Write-Host "Run build_win.bat first, or pass -ExePath."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Already signed?
|
||||
$sig = Get-AuthenticodeSignature -FilePath $ExePath
|
||||
if ($sig.Status -eq 'Valid' -and -not $Force) {
|
||||
Write-Host "[INFO ] Exe is already validly signed by: $($sig.SignerCertificate.Subject)" -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ── Load the certificate ────────────────────────────────────────────
|
||||
$cert = $null
|
||||
if ($CertThumbprint) {
|
||||
$cert = Get-ChildItem Cert:\CurrentUser\My, Cert:\LocalMachine\My -Recurse -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.Thumbprint -eq $CertThumbprint } | Select-Object -First 1
|
||||
if (-not $cert) {
|
||||
Write-Host "[ERROR] No certificate with thumbprint $CertThumbprint in My store." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
} elseif ($CertPath) {
|
||||
if (-not (Test-Path $CertPath)) {
|
||||
Write-Host "[ERROR] Cert file not found: $CertPath" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
if (-not $CertPassword) {
|
||||
$secure = Read-Host "Certificate password for $CertPath" -AsSecureString
|
||||
$CertPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto(
|
||||
[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure))
|
||||
}
|
||||
$securePwd = ConvertTo-SecureString -String $CertPassword -Force -AsPlainText
|
||||
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($CertPath, $securePwd)
|
||||
} else {
|
||||
Write-Host "[ERROR] Provide -CertPath or -CertThumbprint." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ── Sign (signtool preferred, PowerShell fallback) ──────────────────
|
||||
if ($signtool) {
|
||||
$args = @()
|
||||
if ($CertThumbprint) {
|
||||
$args = @('sign', '/sha1', $CertThumbprint, '/fd', 'SHA256')
|
||||
} else {
|
||||
$args = @('sign', '/f', $CertPath, '/p', $CertPassword, '/fd', 'SHA256')
|
||||
}
|
||||
if (-not $SkipTimestamp) {
|
||||
$args += @('/tr', $TimestampUrl, '/td', 'SHA256')
|
||||
}
|
||||
$args += @('"' + $ExePath + '"')
|
||||
$cmd = "& `"$signtool`" " + ($args -join ' ')
|
||||
Write-Host "[INFO ] Signing with signtool..." -ForegroundColor Cyan
|
||||
Write-Host "[CMD ] $cmd"
|
||||
Invoke-Expression $cmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "[ERROR] signtool failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
} else {
|
||||
Write-Host "[INFO ] Signing with PowerShell Set-AuthenticodeSignature (no timestamp)..." -ForegroundColor Cyan
|
||||
if (-not $cert.HasPrivateKey) {
|
||||
Write-Host "[ERROR] Certificate has no private key - cannot sign." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
$sig = Set-AuthenticodeSignature -FilePath $ExePath -Certificate $cert -HashAlgorithm SHA256
|
||||
if ($sig.Status -notin @('Valid','UnknownError')) {
|
||||
Write-Host "[ERROR] Signing failed: $($sig.StatusMessage)" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Verify
|
||||
$sig = Get-AuthenticodeSignature -FilePath $ExePath
|
||||
Write-Host ""
|
||||
Write-Host "[INFO ] Signature status: $($sig.Status)" -ForegroundColor Green
|
||||
Write-Host "[INFO ] Signer: $($sig.SignerCertificate.Subject)" -ForegroundColor Green
|
||||
if ($sig.Status -eq 'Valid') {
|
||||
Write-Host "[OK ] KiwySignagePlayer.exe is now digitally signed." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "[WARN ] Signature status is '$($sig.Status)' - inspect above." -ForegroundColor Yellow
|
||||
Write-Host "[WARN ] If no timestamp was applied, SAC may still block after cert expiry." -ForegroundColor Yellow
|
||||
}
|
||||
Reference in New Issue
Block a user