Keychain Support
Ghostunnel can load certificates and private keys directly from the macOS Keychain or Windows Certificate Store. This lets you use Secure Enclave-backed keys on Touch ID MacBooks, hardware-backed keys via CNG on Windows, or simply manage certificates through the OS instead of as files on disk.
Prerequisites: Creating a PKCS#12 Bundle
Both macOS and Windows import certificates from PKCS#12
(.p12 / .pfx) files. If you have a PEM certificate and key, bundle them
first:
openssl pkcs12 -export \
-in server-cert.pem \
-inkey server-key.pem \
-out server.p12 \
-passout pass:<password>
If you also need to include intermediate CA certificates in the bundle, add
-certfile intermediate-ca.pem.
macOS
Importing into the Keychain
Using the CLI (recommended for automation):
security import server.p12 \
-k ~/Library/Keychains/login.keychain-db \
-f pkcs12 \
-P <password> \
-A
The -A flag allows all applications to access the imported key without a
confirmation prompt. Omit it if you prefer per-application access control.
You can also double-click the .p12 file in Finder or use the
Keychain Access app to import through the GUI.
Verify the import succeeded:
security find-identity -v
This lists all identities (certificate + private key pairs) in your keychain search list. Look for your certificate’s Common Name in the output.
See also Apple’s Keychain Services documentation and TN3137: On Mac keychain APIs and implementations.
Secure Enclave and Hardware Tokens
On Touch ID MacBooks, private keys can live in the Secure Enclave. Pass
--keychain-require-token so Ghostunnel only loads keys backed by a hardware
token (e.g. the Secure Enclave or a smart card):
ghostunnel server \
--keychain-identity <common-name> \
--keychain-require-token \
--listen localhost:8443 \
--target localhost:8080 \
--cacert cacert.pem \
--allow-ou=client
This flag is only available on macOS.
See Apple’s Protecting keys with the Secure Enclave and the Secure Enclave security overview for more on hardware-backed keys.
Windows
Importing into the Certificate Store
Using certutil (recommended for automation):
certutil -f -p <password> -user -importpfx MY server.p12
This imports the certificate and private key into the current user’s “MY”
(Personal) store. The -user flag targets the current user context. To import
into the Local Machine store instead, omit -user (and run as administrator).
Using PowerShell:
Import-PfxCertificate -FilePath server.p12 `
-CertStoreLocation Cert:\CurrentUser\My `
-Password (ConvertTo-SecureString -String "<password>" -AsPlainText -Force)
Verify the import:
Get-ChildItem Cert:\CurrentUser\My | Format-Table Subject, Thumbprint, NotAfter
Which stores does Ghostunnel search? When --keychain-identity is used
on Windows, Ghostunnel searches three stores in this order:
- MY (Current User), the personal certificate store
- CURRENT_SERVICE, the current service account’s certificates (if accessible, since v1.8.1)
- LOCAL_MACHINE, machine-wide certificates (if accessible; may require elevation, since v1.8.1)
Stores that fail to open are skipped rather than causing an error.
See Microsoft’s certutil reference, System Store Locations, and the Import-PfxCertificate cmdlet docs for more.
Selecting a Certificate
Certificates from the keychain can be selected using one or both of the following flags:
--keychain-identity: match by the certificate’s Common Name (CN) or serial number. Ghostunnel collects all certificates where either field matches.--keychain-issuer: match by the issuer’s Common Name (CN).
When both flags are specified, Ghostunnel selects certificates where both attributes match (logical AND). If multiple certificates match, the one with the latest expiration date (NotAfter) is used.
Usage Examples
macOS
Load an identity from the login keychain by subject name:
ghostunnel client \
--keychain-identity <common-name-or-serial> \
--listen unix:/path/to/unix/socket \
--target example.com:443 \
--cacert cacert.pem
Or filter by issuer name:
ghostunnel client \
--keychain-issuer <issuer-common-name> \
--listen unix:/path/to/unix/socket \
--target example.com:443 \
--cacert cacert.pem
Windows
On Windows, --keychain-identity and --keychain-issuer work the same way
but search the Windows Certificate Store (MY, CURRENT_SERVICE, and
LOCAL_MACHINE stores, as described above):
ghostunnel client \
--keychain-identity <common-name-or-serial> \
--listen localhost:8080 \
--target example.com:443 \
--cacert cacert.pem
Certificate Reloading
Keychain certificates support reloading via SIGHUP/SIGUSR1 (Unix only) or
--timed-reload (all platforms). On reload, Ghostunnel re-queries the keychain for a
certificate matching the same identity/issuer criteria. If the certificate
has been updated in the keychain (e.g. renewed), the new certificate will
be used for subsequent connections.
Removing Certificates
macOS: remove an identity (certificate + private key) by Common Name:
security delete-identity -c <common-name>
Or use the Keychain Access app to find and delete the certificate in the GUI.
Windows: remove via PowerShell:
Get-ChildItem Cert:\CurrentUser\My |
Where-Object { $_.Subject -match "CN=<common-name>" } |
Remove-Item -DeleteKey
The -DeleteKey flag also removes the private key. You can alternatively
use certutil -delstore MY <serial-or-thumbprint>.
Troubleshooting
macOS: certificate not found
- Check the keychain search list:
security list-keychains - Unlock the keychain if locked:
security unlock-keychain - List available identities:
security find-identity -v - Make sure the CN or serial matches what you passed to
--keychain-identity
Windows: certificate not found
- List certs in the store:
Get-ChildItem Cert:\CurrentUser\My - If using the Local Machine store, make sure Ghostunnel runs with sufficient permissions
- Make sure the CN or serial matches what you passed to
--keychain-identity
Access denied / permission errors
- macOS: the keychain may prompt for access. Use
-Aduring import to allow all apps, or grant access to Ghostunnel specifically in Keychain Access. - Windows: the account running Ghostunnel needs read access to the private key. You can manage private key permissions through the Certificates MMC snap-in (right-click a certificate, then “All Tasks > Manage Private Keys”).