diff --git a/README.md b/README.md index f785368..c573390 100644 --- a/README.md +++ b/README.md @@ -257,12 +257,13 @@ Toolkit versions ≤ v1.0.3 stored acme-dns credentials using DPAPI in `CurrentU - `%ProgramData%\win-acme\acme-v02.api.letsencrypt.org\Log\log-*.txt` contains `ConvertTo-SecureString : ... CryptographicException` and `Failed to decrypt password. This usually means the credential was stored by a different user or on a different machine.` - The credential JSON in `%ProgramData%\WinCertManager\Config\acme-dns\` reports `"StorageMethod": "DPAPI"` -**Fix:** `scripts/Recovery/Repair-AcmeDnsCredential.ps1` re-encrypts the credential under DPAPI `LocalMachine` scope (so SYSTEM can decrypt it) without changing the acme-dns subdomain registration — no DNS changes required. Run it once per affected host. Toolkit ≥ v1.0.4 stores new credentials in `LocalMachine` scope by default, so fresh installs are unaffected. +**Fix:** `scripts/Recovery/Repair-AcmeDnsCredential.ps1` re-encrypts the credential under DPAPI `LocalMachine` scope (so SYSTEM can decrypt it) without changing the acme-dns subdomain registration — no DNS changes required. Run it once per affected host as the same admin that originally registered the domain; the script then recovers the password from the existing DPAPI blob automatically, so you don't need it from a password manager. It also clears any stale win-acme ARI cache entries that may be holding a "replacement" slot for the failed cert and offers to run the renewal interactively. Toolkit ≥ v1.0.4 stores new credentials in `LocalMachine` scope by default, so fresh installs are unaffected. -> **Verify the script before running it.** Open it in a text editor or run `Get-AuthenticodeSignature` against a copy from a signed release ZIP. The script will prompt for the original acme-dns password (the `password` field returned by `/register`, retrievable from your password manager). +> **Verify the script before running it.** Open it in a text editor or run `Get-AuthenticodeSignature` against a copy from a signed release ZIP. If you're running as a different operator from the one that originally registered the domain, the script will fall back to prompting for the `password` field returned by `/register` (retrievable from your password manager). ```powershell -# On the affected host, in an elevated PowerShell session: +# On the affected host, in an elevated PowerShell session, +# signed in as the admin that originally registered the domain: $url = 'https://raw.githubusercontent.com/realworldtech/wincertmanager/main/scripts/Recovery/Repair-AcmeDnsCredential.ps1' $dest = Join-Path $env:TEMP 'Repair-AcmeDnsCredential.ps1' Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing @@ -270,11 +271,9 @@ Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing # REVIEW the file before executing: notepad $dest -# Then run for the affected domain (will prompt for the acme-dns password): +# Then run for the affected domain. Auto-recovers the password, +# clears the ARI cache, and prompts to run wacs.exe --renew: & $dest -Domain 'dc01.internal.example.com' - -# After repair, force a renewal to confirm: -& 'C:\Tools\win-acme\wacs.exe' --renew --force --verbose ``` If you prefer a signed copy, download the latest release ZIP from the [Releases page](https://github.com/realworldtech/wincertmanager/releases), verify the SHA256, and run the script from `scripts/Recovery/` inside the extracted directory. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 0c3e180..ebc8397 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -194,17 +194,18 @@ The renewal log will show the error inside `Get-AcmeDnsCredential.ps1` while run **Solutions:** -For cause 1 (DPAPI scope mismatch), use the recovery tool to re-encrypt under machine scope without losing the existing acme-dns subdomain registration (no DNS changes needed): +For cause 1 (DPAPI scope mismatch), use the recovery tool to re-encrypt under machine scope without losing the existing acme-dns subdomain registration (no DNS changes needed). Run it as the same admin that originally registered the domain — the script then unwraps the password from the existing CurrentUser DPAPI blob and you don't need to supply it: ```powershell .\scripts\Recovery\Repair-AcmeDnsCredential.ps1 -Domain "example.com" -# Prompts for the original acme-dns password from /register ``` -After the repair, force a renewal to confirm: +The script also clears stale win-acme ARI cache entries for the domain (so the next `new-order` doesn't fail with `urn:ietf:params:acme:error:alreadyReplaced` because of leftover pending orders from earlier failed attempts) and prompts to run `wacs.exe --renew --force --verbose` immediately. For unattended runs, pass `-RunRenewal Yes` (or `No`) to skip the prompt; if you're running as a different operator from the one that registered, pass `-Password` (a `[SecureString]`) explicitly: ```powershell -C:\Tools\win-acme\wacs.exe --renew --force --verbose +# Unattended, original user not available: +$pw = ConvertTo-SecureString $env:ACMEDNS_PASSWORD -AsPlainText -Force +.\scripts\Recovery\Repair-AcmeDnsCredential.ps1 -Password $pw -RunRenewal Yes -Confirm:$false ``` Toolkit ≥ v1.0.4 registers new credentials with `StorageMethod = DPAPI-LocalMachine` by default, so this issue does not affect fresh installs. Existing legacy installs only need the repair script run once.