Code signing utility for PE executables using YubiKey PIV certificates with OpenSSL-based Authenticode signatures. Supports local signing with a directly connected YubiKey or remote signing via an HTTP proxy server.
- YubiKey with certificate in PIV slot
- Windows: PC/SC Smart Card service enabled
- Linux: pcscd service running (
sudo systemctl start pcscd) - macOS: No additional setup required
- Network access to a running
yubikey-proxyserver - Authentication token matching the proxy configuration
Sign a file in-place (replaces the original):
yubikey-signer sign myapp.exeSave signed file to a different location:
yubikey-signer sign myapp.exe -o myapp-signed.exeSign using a remote YubiKey proxy server:
yubikey-signer sign myapp.exe -o signed.exe --remote http://192.168.1.100:18443With authentication token:
export YUBIKEY_PROXY_TOKEN="your-secret-token"
yubikey-signer sign myapp.exe -o signed.exe --remote http://proxy:18443With custom HTTP headers (for reverse proxies like Cloudflare Access):
yubikey-signer sign myapp.exe -o signed.exe \
--remote https://sign.example.com \
--header "CF-Access-Client-Id: your-client-id.access" \
--header "CF-Access-Client-Secret: your-client-secret"With timestamp server:
yubikey-signer sign myapp.exe --timestamp http://timestamp.digicert.comWithout timestamping (not recommended for production):
yubikey-signer sign myapp.exe --timestamp ""Specify a specific PIV slot:
yubikey-signer sign myapp.exe --slot 0x9cFind suitable certificates on your YubiKey:
yubikey-signer discoverGet detailed certificate information:
yubikey-signer discover --detailedView current configuration:
yubikey-signer config showInitialize default configuration:
yubikey-signer config initSet configuration values:
yubikey-signer config set default_piv_slot 0x9cLocal signing - Set YubiKey PIN via environment variable:
export YUBICO_PIN=123456 # Linux/macOS
$env:YUBICO_PIN = "123456" # Windows PowerShellRemote signing - Set proxy authentication token:
export YUBIKEY_PROXY_TOKEN="your-secret-token" # Linux/macOS
$env:YUBIKEY_PROXY_TOKEN = "your-secret-token" # Windows PowerShellDownload from GitHub Releases:
- Windows:
yubikey-signer-x86_64-pc-windows-msvc.exe - Linux:
yubikey-signer-x86_64-unknown-linux-gnu - macOS (Intel):
yubikey-signer-x86_64-apple-darwin - macOS (Apple Silicon):
yubikey-signer-aarch64-apple-darwin
# Run the automated setup script (PowerShell as Administrator)
.\setup-windows-build.ps1
# Or use the batch file
.\setup-windows-build.bat
# Then build normally
cargo build --releaseThe setup script will automatically:
- Install vcpkg if not present (respects existing
VCPKG_ROOT) - Install OpenSSL via vcpkg
- Configure the build environment
If you already have vcpkg:
# Install OpenSSL via your existing vcpkg
vcpkg install openssl:x64-windows
# Set environment variable (if not already set)
set VCPKG_ROOT=C:\your\vcpkg\path
# Build normally
cargo build --release# Uses system OpenSSL or vendored if system not available
cargo build --release
# Force vendored OpenSSL (requires dependencies)
cargo build --release --features vendored-opensslWindows PowerShell (optional):
Get-AuthenticodeSignature myapp-signed.exeThe CLI provides four main commands:
sign- Sign PE executables with YubiKey certificates (local or remote)proxy- Run a signing proxy server for remote signingdiscover- Find and analyze certificates on your YubiKeyconfig- Manage application configuration
yubikey-signer sign [OPTIONS] <FILE>
Arguments:
<FILE> PE executable file to sign
Options:
-o, --output <FILE> Output file (default: sign in-place)
-s, --slot <SLOT> PIV slot (hex: 0x9c, 9c, or decimal: 156)
-t, --timestamp [<URL>] Timestamp server URL (default: http://ts.ssl.com)
-r, --remote <URL> Remote signing proxy URL
--header <HEADER> Custom HTTP header (format: "Name: Value"), repeatable
--dry-run Preview signing without making changes
-v, --verbose Enable verbose output
-h, --help Print help
Start a signing proxy server (requires YubiKey connected to the host):
yubikey-signer proxy [OPTIONS]
Options:
-b, --bind <ADDR> Bind address (default: 127.0.0.1:18443)
-v, --verbose Enable verbose output
-h, --help Print help
Environment:
YUBICO_PIN YubiKey PIN for signing operations
YUBIKEY_PROXY_TOKEN Required authentication token for clients
yubikey-signer discover [OPTIONS]
Options:
--detailed Show detailed certificate information
-v, --verbose Enable verbose output
-h, --help Print help
yubikey-signer config <SUBCOMMAND>
Subcommands:
show Display current configuration
init Create default configuration file
set Set configuration value
export Export configuration
import Import configuration
help Print help
Common YubiKey PIV slots for code signing:
0x9a(154): Authentication - Default slot for signing0x9c(156): Digital Signature - Primary slot for code signing0x9d(157): Key Management - Alternative signing slot0x9e(158): Card Authentication - Alternative signing slot
Remote signing allows code signing from machines without a directly connected YubiKey. The YubiKey remains connected to a secure server running the proxy.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐
│ Build Machine │ HTTPS │ Proxy Server │ USB │ YubiKey │
│ │ ──────► │ (yubikey-proxy)│ ──────► │ │
│ yubikey-signer │ │ │ │ PIV Cert │
│ --remote URL │ ◄────── │ Port 18443 │ ◄────── │ Private Key│
└─────────────────┘ └─────────────────┘ └─────────────┘
-
Connect YubiKey to the server
-
Set environment variables:
export YUBICO_PIN="your-yubikey-pin" export YUBIKEY_PROXY_TOKEN="$(openssl rand -base64 36)"
-
Start the proxy:
yubikey-signer proxy --bind 0.0.0.0:18443
-
For production, place behind a TLS-terminating reverse proxy (nginx, Caddy, Cloudflare Tunnel)
The proxy exposes these endpoints:
| Method | Path | Description |
|---|---|---|
| POST | /api/v1/status |
Server and YubiKey status |
| POST | /api/v1/certificate |
Get certificate from PIV slot |
| POST | /api/v1/sign |
Sign a hash digest |
All endpoints require the Authorization: Bearer <token> header.
- The proxy does not handle TLS directly; use a reverse proxy for HTTPS
- Generate a strong random token (minimum 32 bytes)
- Restrict network access to trusted clients
- The YubiKey PIN is stored server-side; clients only need the proxy token
- Consider additional authentication layers (VPN, Cloudflare Access, mTLS)
CI builds and releases are tested for:
x86_64-pc-windows-msvcx86_64-unknown-linux-gnux86_64-apple-darwinaarch64-apple-darwinaarch64-unknown-linux-musl(proxy binary with direct USB support for embedded Linux)
Automated dependency scanning and license compliance is handled by cargo-deny, configured via deny.toml.
cargo install cargo-deny
# Complete dependency compliance check (licenses, advisories, bans, sources)
cargo deny check
# Individual checks
cargo deny check licenses
cargo deny check advisories
cargo deny check bans
cargo deny check sourcesIgnored advisories are documented with justification and expiry inside deny.toml. Remove or update entries once upstream crates patch vulnerabilities.
CI GitHub Actions workflow runs these checks on pushes, pull requests, and a daily schedule; any new unignored vulnerability or disallowed license will fail the workflow.
This project is licensed under the Apache License, Version 2.0. See the LICENSE file for details.
This software includes third-party components under their respective licenses:
- OpenSSL (when using
--use-openssloption): Apache License 2.0- Full license text in
LICENSE-OpenSSL - Copyright and attribution notices in
THIRD-PARTY-NOTICES.md
- Full license text in
- Other Rust dependencies: Various permissive licenses
- Run
cargo licensefor a complete list
- Run
See THIRD-PARTY-NOTICES.md for complete attribution and license information for all third-party components.