Skip to content

Commit 60eb756

Browse files
committed
ci: test cert
1 parent 5bffda2 commit 60eb756

4 files changed

Lines changed: 205 additions & 214 deletions

File tree

Lines changed: 71 additions & 203 deletions
Original file line numberDiff line numberDiff line change
@@ -1,230 +1,98 @@
1-
# Connect-SimplySign-Enhanced.ps1
2-
# Registry-Enhanced TOTP Authentication for SimplySign Desktop
3-
# Uses registry pre-configuration + TOTP credential injection approach
4-
51
param(
6-
[string]$OtpUri = $env:CERTUM_OTP_URI,
7-
[string]$UserId = $env:CERTUM_USERNAME,
8-
[string]$ExePath = $env:CERTUM_EXE_PATH
2+
[Parameter(Mandatory=$true)]
3+
[string]$FileToSign
94
)
105

11-
# Validate required parameters
12-
if (-not $OtpUri) {
13-
Write-Host "ERROR: CERTUM_OTP_URI environment variable not provided"
14-
exit 1
15-
}
6+
$ErrorActionPreference = "Stop"
167

17-
if (-not $UserId) {
18-
Write-Host "ERROR: CERTUM_USERNAME environment variable not provided"
19-
exit 1
8+
function Find-SignTool {
9+
if ($env:TAURI_WINDOWS_SIGNTOOL_PATH -and (Test-Path $env:TAURI_WINDOWS_SIGNTOOL_PATH)) {
10+
return $env:TAURI_WINDOWS_SIGNTOOL_PATH
11+
}
12+
$hits = Get-ChildItem "C:\Program Files (x86)\Windows Kits\10\bin\*\x64\signtool.exe" -ErrorAction SilentlyContinue |
13+
Sort-Object FullName -Descending
14+
if ($hits -and $hits.Count -gt 0) { return $hits[0].FullName }
15+
throw "signtool.exe not found. Set TAURI_WINDOWS_SIGNTOOL_PATH."
2016
}
2117

22-
if (-not $ExePath) {
23-
$ExePath = "C:\Program Files\Certum\SimplySign Desktop\SimplySignDesktop.exe"
18+
function Ensure-SmartCardService {
19+
sc.exe config SCardSvr start= demand | Out-Null
20+
sc.exe start SCardSvr | Out-Null
2421
}
2522

26-
Write-Host "=== REGISTRY-ENHANCED TOTP AUTHENTICATION ==="
27-
Write-Host "Using registry pre-configuration + credential injection"
28-
Write-Host "OTP URI provided (length: $($OtpUri.Length))"
29-
Write-Host "User ID: $UserId"
30-
Write-Host "Executable: $ExePath"
31-
Write-Host ""
32-
33-
# Verify SimplySign Desktop exists
34-
if (-not (Test-Path $ExePath)) {
35-
Write-Host "ERROR: SimplySign Desktop not found at: $ExePath"
36-
exit 1
23+
function Clear-ReadOnly($path) {
24+
if (Test-Path $path) { & attrib -R $path | Out-Null }
3725
}
3826

39-
# Parse the otpauth:// URI
40-
$uri = [Uri]$OtpUri
41-
42-
# Parse query parameters (compatible with both PowerShell 5.1 and 7+)
43-
try {
44-
$q = [System.Web.HttpUtility]::ParseQueryString($uri.Query)
45-
} catch {
46-
$q = @{}
47-
foreach ($part in $uri.Query.TrimStart('?') -split '&') {
48-
$kv = $part -split '=', 2
49-
if ($kv.Count -eq 2) {
50-
$q[$kv[0]] = [Uri]::UnescapeDataString($kv[1])
51-
}
52-
}
27+
function Restart-SimplySignDesktop {
28+
$p = Get-Process -Name "SimplySignDesktop" -ErrorAction SilentlyContinue
29+
if ($p) {
30+
$p | Stop-Process -Force -ErrorAction SilentlyContinue
31+
Start-Sleep -Seconds 2
32+
}
33+
34+
# best-effort paths
35+
$cands = @(
36+
"$env:ProgramFiles\SimplySign\SimplySignDesktop.exe",
37+
"$env:ProgramFiles(x86)\SimplySign\SimplySignDesktop.exe"
38+
)
39+
foreach ($c in $cands) {
40+
if (Test-Path $c) { Start-Process -FilePath $c | Out-Null; break }
41+
}
42+
Start-Sleep -Seconds 5
5343
}
5444

55-
$Base32 = $q['secret']
56-
$Digits = if ($q['digits']) { [int]$q['digits'] } else { 6 }
57-
$Period = if ($q['period']) { [int]$q['period'] } else { 30 }
58-
$Algorithm = if ($q['algorithm']) { $q['algorithm'].ToUpper() } else { 'SHA256' }
59-
60-
# Validate supported algorithms
61-
$SupportedAlgorithms = @('SHA1', 'SHA256', 'SHA512')
62-
if ($Algorithm -notin $SupportedAlgorithms) {
63-
Write-Host "ERROR: Unsupported algorithm: $Algorithm. Supported: $($SupportedAlgorithms -join ', ')"
64-
exit 1
45+
function Run-SignTool($signtool, $args) {
46+
$p = Start-Process -FilePath $signtool -ArgumentList $args -NoNewWindow -Wait -PassThru
47+
return $p.ExitCode
6548
}
6649

67-
# TOTP Generator (inline C# implementation)
68-
Add-Type -Language CSharp @"
69-
using System;
70-
using System.Security.Cryptography;
71-
72-
public static class Totp
73-
{
74-
private const string B32 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
75-
76-
private static byte[] Base32Decode(string s)
77-
{
78-
s = s.TrimEnd('=').ToUpperInvariant();
79-
int byteCount = s.Length * 5 / 8;
80-
byte[] bytes = new byte[byteCount];
81-
82-
int bitBuffer = 0, bitsLeft = 0, idx = 0;
83-
foreach (char c in s)
84-
{
85-
int val = B32.IndexOf(c);
86-
if (val < 0) throw new ArgumentException("Invalid Base32 char: " + c);
87-
88-
bitBuffer = (bitBuffer << 5) | val;
89-
bitsLeft += 5;
90-
91-
if (bitsLeft >= 8)
92-
{
93-
bytes[idx++] = (byte)(bitBuffer >> (bitsLeft - 8));
94-
bitsLeft -= 8;
95-
}
96-
}
97-
return bytes;
98-
}
99-
100-
private static HMAC GetHmacAlgorithm(string algorithm, byte[] key)
101-
{
102-
switch (algorithm.ToUpper())
103-
{
104-
case "SHA1":
105-
return new HMACSHA1(key);
106-
case "SHA256":
107-
return new HMACSHA256(key);
108-
case "SHA512":
109-
return new HMACSHA512(key);
110-
default:
111-
throw new ArgumentException("Unsupported algorithm: " + algorithm);
112-
}
113-
}
114-
115-
public static string Now(string secret, int digits, int period, string algorithm = "SHA256")
116-
{
117-
byte[] key = Base32Decode(secret);
118-
long counter = DateTimeOffset.UtcNow.ToUnixTimeSeconds() / period;
119-
120-
byte[] cnt = BitConverter.GetBytes(counter);
121-
if (BitConverter.IsLittleEndian) Array.Reverse(cnt);
122-
123-
byte[] hash;
124-
using (var hmac = GetHmacAlgorithm(algorithm, key))
125-
{
126-
hash = hmac.ComputeHash(cnt);
127-
}
128-
129-
int offset = hash[hash.Length - 1] & 0x0F;
130-
int binary =
131-
((hash[offset] & 0x7F) << 24) |
132-
((hash[offset + 1] & 0xFF) << 16) |
133-
((hash[offset + 2] & 0xFF) << 8) |
134-
(hash[offset + 3] & 0xFF);
135-
136-
int otp = binary % (int)Math.Pow(10, digits);
137-
return otp.ToString(new string('0', digits));
138-
}
139-
}
140-
"@
50+
$signtool = Find-SignTool
51+
$ts = $env:TAURI_SIGN_TIMESTAMP_URL
52+
if (-not $ts) { $ts = "http://time.certum.pl" }
14153

142-
function Get-TotpCode {
143-
param([string]$Secret, [int]$Digits = 6, [int]$Period = 30, [string]$Algorithm = 'SHA256')
144-
[Totp]::Now($Secret, $Digits, $Period, $Algorithm)
145-
}
54+
Write-Host "== SimplySign custom signing =="
55+
Write-Host "signtool: $signtool"
56+
Write-Host "file: $FileToSign"
57+
Write-Host "ts: $ts"
14658

147-
# Generate current TOTP code
148-
$otp = Get-TotpCode -Secret $Base32 -Digits $Digits -Period $Period -Algorithm $Algorithm
149-
Write-Host "Generated TOTP: $otp (using $Algorithm algorithm)"
150-
Write-Host ""
59+
Ensure-SmartCardService
60+
Clear-ReadOnly $FileToSign
15161

152-
# Launch SimplySign Desktop (registry should auto-open login dialog)
153-
Write-Host "Launching SimplySign Desktop..."
154-
Write-Host "Registry pre-configuration should auto-open login dialog"
155-
$proc = Start-Process -FilePath $ExePath -PassThru
156-
Write-Host "Process started with ID: $($proc.Id)"
157-
Write-Host ""
62+
$base = @("sign", "/fd", "sha256", "/tr", $ts, "/td", "sha256")
15863

159-
# Wait for the application to initialize
160-
Write-Host "Waiting for SimplySign Desktop to initialize..."
161-
Start-Sleep -Seconds 3
162-
163-
# Create WScript.Shell for window interaction
164-
$wshell = New-Object -ComObject WScript.Shell
64+
# Try KSP first, then legacy CSP. NO /as.
65+
$strategies = @(
66+
@{ name="KSP-auto"; args= $base + @("/csp","SimplySign KSP","/a",$FileToSign) },
67+
@{ name="CSP-auto"; args= $base + @("/csp","SimplySign CSP","/a",$FileToSign) }
68+
)
16569

166-
# Try to focus the SimplySign Desktop window
167-
Write-Host "Attempting to focus SimplySign Desktop window..."
168-
$focused = $false
70+
$max = 10
71+
$ok = $false
16972

170-
# Method 1: Focus by process ID (most reliable)
171-
$focused = $wshell.AppActivate($proc.Id)
73+
for ($i=1; $i -le $max; $i++) {
74+
foreach ($s in $strategies) {
75+
Write-Host "Attempt $i/$max => $($s.name)"
76+
$code = Run-SignTool $signtool $s.args
77+
if ($code -eq 0) { $ok = $true; break }
78+
Write-Host " Sign failed exit=$code"
79+
}
17280

173-
# Method 2: Focus by window title (fallback)
174-
if (-not $focused) {
175-
$focused = $wshell.AppActivate('SimplySign Desktop')
176-
}
81+
if ($ok) { break }
17782

178-
# Method 3: Multiple attempts with slight delays
179-
for ($i = 0; (-not $focused) -and ($i -lt 10); $i++) {
180-
Start-Sleep -Milliseconds 500
181-
$focused = $wshell.AppActivate($proc.Id) -or $wshell.AppActivate('SimplySign Desktop')
182-
Write-Host "Focus attempt $($i + 1): $focused"
83+
Write-Host "Self-heal: ensure SCardSvr + restart SimplySignDesktop (attempt $i)"
84+
Ensure-SmartCardService
85+
Restart-SimplySignDesktop
86+
Start-Sleep -Seconds (2 * $i)
18387
}
18488

185-
if (-not $focused) {
186-
Write-Host "ERROR: Could not bring SimplySign Desktop to foreground"
187-
Write-Host "Login dialog may not be visible for credential injection"
188-
exit 1
89+
if (-not $ok) {
90+
throw "Signing failed after $max attempts for: $FileToSign"
18991
}
19092

191-
Write-Host "Successfully focused SimplySign Desktop window"
192-
Write-Host ""
193-
194-
# Small delay to ensure window is ready for input
195-
Start-Sleep -Milliseconds 400
196-
197-
# Inject credentials: Username + TAB + TOTP + ENTER
198-
Write-Host "Injecting credentials into login dialog..."
199-
Write-Host "Sending: Username -> TAB -> TOTP -> ENTER"
200-
201-
# Send the credential sequence
202-
$wshell.SendKeys($UserId)
203-
Start-Sleep -Milliseconds 200
204-
$wshell.SendKeys("{TAB}")
205-
Start-Sleep -Milliseconds 200
206-
$wshell.SendKeys($otp)
207-
Start-Sleep -Milliseconds 200
208-
$wshell.SendKeys("{ENTER}")
209-
210-
Write-Host "Credentials injected successfully"
211-
Write-Host ""
212-
213-
# Wait for authentication to process
214-
Write-Host "Waiting for authentication to complete..."
215-
Start-Sleep -Seconds 5
216-
217-
# Verify SimplySign Desktop is still running
218-
$stillRunning = Get-Process -Id $proc.Id -ErrorAction SilentlyContinue
219-
if ($stillRunning) {
220-
Write-Host "SUCCESS: SimplySign Desktop is running"
221-
Write-Host "Authentication should be complete"
222-
Write-Host "Cloud certificate should now be available"
223-
} else {
224-
Write-Host "WARNING: SimplySign Desktop process has exited"
225-
Write-Host "This may indicate authentication failure"
93+
Write-Host "Verifying signature..."
94+
$verifyCode = Run-SignTool $signtool @("verify","/pa","/v",$FileToSign)
95+
if ($verifyCode -ne 0) {
96+
throw "signtool verify failed exit=$verifyCode for: $FileToSign"
22697
}
227-
228-
Write-Host ""
229-
Write-Host "=== TOTP AUTHENTICATION COMPLETE ==="
230-
Write-Host "Registry pre-configuration + credential injection finished"
98+
Write-Host "✅ signed + verified"

0 commit comments

Comments
 (0)