You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rdpwrap/docs/CODE-SIGNING.md

101 lines
3.7 KiB

# Code Signing Guide
Both `build-and-release.yml` and `build-csharp.yml` include a code-signing step that is already wired up and waiting. The step fires automatically as soon as the two secrets below are present in the repository — no workflow edits are needed.
---
## What gets signed
All six framework-dependent executables and all six self-contained executables produced per release:
| File | Contents |
|---|---|
| `RDPWInst_x64.exe`, `RDPWInst_x86.exe`, `RDPWInst_arm64.exe` | CLI installer |
| `RDPConf_x64.exe`, `RDPConf_x86.exe`, `RDPConf_arm64.exe` | GUI configuration tool |
| `RDPCheck_x64.exe`, `RDPCheck_x86.exe`, `RDPCheck_arm64.exe` | GUI connection tester |
| `*_sc.exe` variants | Self-contained copies of the above |
The signing step runs on every `build-and-release.yml` and `build-csharp.yml` triggered build (tag push and manual dispatch), and is **skipped silently** when the secrets are absent.
---
## Obtaining a code-signing certificate
### Option A — Commercial certificate (recommended for public distribution)
Purchase an **EV (Extended Validation) Code Signing Certificate** from a trusted CA:
- [DigiCert Code Signing](https://www.digicert.com/signing/code-signing-certificates)
- [Sectigo (Comodo)](https://sectigo.com/ssl-certificates-tls/code-signing)
- [GlobalSign](https://www.globalsign.com/en/code-signing-certificate/)
> **Windows SmartScreen** initially blocks unsigned or low-reputation executables. A commercial EV certificate builds reputation immediately; a standard OV certificate requires time to accumulate reputation through user downloads. Self-signed certificates (Option B) will always trigger SmartScreen warnings.
### Option B — Self-signed certificate (testing / internal use only)
```powershell
# Run in an elevated PowerShell session
$cert = New-SelfSignedCertificate `
-Type CodeSigningCert `
-Subject "CN=RDP Wrapper" `
-KeySpec Signature `
-KeyAlgorithm RSA `
-KeyLength 4096 `
-HashAlgorithm SHA256 `
-CertStoreLocation "Cert:\CurrentUser\My" `
-NotAfter (Get-Date).AddYears(3)
# Export to PFX (set a strong password)
$pw = Read-Host "PFX password" -AsSecureString
Export-PfxCertificate -Cert $cert -FilePath "rdpwrap-codesign.pfx" -Password $pw
```
---
## Preparing the PFX for GitHub Actions
```powershell
# Base64-encode the PFX so it can be stored as a secret
$b64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes(".\rdpwrap-codesign.pfx"))
$b64 | Set-Clipboard
Write-Host "Base64 PFX copied to clipboard"
```
---
## Adding the secrets to GitHub
Navigate to: **Settings → Secrets and variables → Actions → New repository secret**
| Secret name | Value |
|---|---|
| `CODESIGN_CERT_BASE64` | Paste the base64-encoded PFX string |
| `CODESIGN_CERT_PASSWORD` | The password chosen when exporting the PFX |
> ⚠️ **Security:** Never commit the `.pfx` file or raw base64 string to the repository. Revoke and reissue the certificate if it is accidentally exposed.
---
## Verifying a signed executable
After a signed release is published:
```powershell
# Check signature status
Get-AuthenticodeSignature .\RDPWInst_x64.exe | Format-List
# Expected output (commercial cert):
# Status : Valid
# SignerCertificate : [CN=Your Name, O=Your Org, ...]
# TimeStamperCertificate : [CN=DigiCert Timestamp 2023, ...]
```
---
## Renewing / rotating the certificate
1. Export the new PFX and base64-encode it (see above).
2. Update both `CODESIGN_CERT_BASE64` and `CODESIGN_CERT_PASSWORD` via **Settings → Secrets**.
3. No workflow changes are needed — the `Sign C# executables` step always reads from secrets at runtime.
4. Remove the old PFX from your local machine and revoke the old certificate with the CA if it has not expired.