A cross-platform gRPC service and client proxy architecture for Windows and macOS that lists certificates with private keys from system certificate stores (Windows MY store via CNG/NCrypt, macOS Keychain) and performs remote keyless signing of digests using non-exportable keys (including TPM-backed keys and hardware tokens). Communication between clients and servers is secured with mutual TLS (mTLS).
- Cross-Platform Server (
cmd/cert-server): Runs on both macOS (accessing macOS Keychain) and Windows (accessing WindowsMYstore / NCrypt / TPM). - macOS Provider App & Extension (
mac-provider/): Native macOS App (KeylessProxy) and CryptoTokenKit (CTK) SmartCard Token extension (KeylessProxyExtension) allowing macOS systems and applications to delegate cryptographic signing to a remotecert-server. - Windows CNG KSP (
ksp/): Custom Windows Key Storage Provider DLL that integrates with Windows CryptoAPI/CNG to delegate signing to a remotecert-server. - UDP LAN Discovery: Automatic server discovery over LAN via UDP broadcast on port 6666.
- mTLS Transport Security: Full mutual TLS authentication for gRPC communication between clients/providers and the cert-server.
- Server Host: Windows 10/11 / Windows Server OR macOS 12+
- macOS Provider App / Extension: macOS 12+, Xcode / Xcode Command Line Tools, and
xcodegen(brew install xcodegen) - Windows CNG KSP: Windows 10/11 (C++ build tools and CGO required to compile)
- Go: 1.26+
- Protobuf:
protoc(bundled undertools/protoc/after bootstrap, or install viabrew install protobuf/winget install Google.Protobuf)
go run ./cmd/gencertsThis creates certs/ca.crt, certs/server.crt, certs/server.key, certs/client.crt, and certs/client.key.
The server can run on macOS (reading from Keychain) or Windows (reading from MY store).
On macOS / Linux:
go run ./cmd/cert-server \
-addr 127.0.0.1:50051 \
-ca certs/ca.crt \
-cert certs/server.crt \
-key certs/server.keyOn Windows (PowerShell):
go run ./cmd/cert-server `
-addr 127.0.0.1:50051 `
-ca certs/ca.crt `
-cert certs/server.crt `
-key certs/server.keyThe server listens on localhost by default and requires a valid client certificate.
UDP broadcast discovery is enabled by default on port 6666 (-discovery-addr :6666). Clients on the same LAN can find the server without hard-coding its IP.
To bind gRPC to a reachable network interface for LAN clients:
go run ./cmd/cert-server \
-addr 0.0.0.0:50051 \
-ca certs/ca.crt \
-cert certs/server.crt \
-key certs/server.keyDisable discovery with -discovery=false. Windows Firewall or macOS Application Firewall may require allowing inbound UDP on port 6666 and TCP on 50051.
Discovery protocol: send a UDP broadcast (or unicast) to port 6666:
{"op":"discover","service":"tpm-cert-server"}The server replies with:
{"op":"announce","service":"tpm-cert-server","version":"1","hostname":"HOST","grpc_addr":"192.168.1.50:50051"}Discover servers on the LAN:
go run ./cmd/run-discoverygo run ./cmd/example-client \
-addr 127.0.0.1:50051 \
-ca certs/ca.crt \
-cert certs/client.crt \
-key certs/client.keyThe client will:
- List all certificates on the server (from macOS Keychain or Windows
MYstore) that have accessible private keys - Prompt you to choose a certificate by index
- Prompt for text to sign (or pass
-message "hello") - Compute SHA-256 locally and call
SignHashon the server - Print the digest and signature
The macOS integration provides a native GUI application (KeylessProxy) and a CryptoTokenKit (CTK) SmartCard extension (KeylessProxyExtension). This allows macOS applications, system authentication, and TLS clients to use remote certificates hosted by cert-server as if a smart card were inserted locally.
-
Install prerequisites:
brew install xcodegen
-
Build the app and extension bundle:
./scripts/build-app-bundle.sh
-
Install to
/Applicationsand register the extension:./scripts/install-app-mac.sh
This script builds
KeylessProxy.app, copies it to/Applications/KeylessProxy.app, registers the CTK extension (KeylessProxyExtension.appex) usingpluginkit, and initializes driver configuration.
KeylessProxy.appprovides a UI to configure connection parameters (server address, mTLS certificates, selected identities) and saves shared configuration for the extension.KeylessProxyExtension.appexusesinternal/ctkbridge(a Goc-archivebridge) to communicate with the remotecert-servervia mTLS gRPC when macOS requests signature operations.
The KSP lets Windows applications on a client machine use TPM-backed or store keys hosted on a remote cert-server via NCrypt/CryptoAPI. Private keys never leave the server; the KSP forwards signing requests to cert-server over mTLS gRPC.
Prerequisites:
- Go 1.26+
- CGO Toolchain (MSVCRT x86_64): For Windows CGO builds, use llvm-mingw-20260616-msvcrt-x86_64.zip. Extract and add its
bin/directory to yourPATH(or ensuregccis inPATH). - Visual Studio C++ Build Tools (or GCC from llvm-mingw)
- Inno Setup 6 (for installer compilation):
winget install --id JRSoftware.InnoSetup
powershell -ExecutionPolicy Bypass -File scripts/build-ksp.ps1Outputs in build/:
fredprx_ksp.dll— CNG Key Storage Providerksp-register.exe— register/unregister the provider (admin)ksp-install-cert.exe— install and bind a remote certificateKeylessProxyKsp.exe— graphical certificate management app
The easiest way to install Keyless Proxy Ksp and the graphical Certificate Manager is using the Windows Installer package.
powershell -ExecutionPolicy Bypass -File scripts/build-windows-installer.ps1(Or run powershell -ExecutionPolicy Bypass -File scripts/build-ksp.ps1 -Installer)
This produces build/KeylessProxyKsp-Setup.exe.
Run KeylessProxyKsp-Setup.exe (requires Administrator elevation). The installer:
- Installs
fredprx_ksp.dllintoC:\Windows\System32\and registers Fred Proxy Key Storage Provider with Windows CNG. - Installs Keyless Proxy Ksp Certificate Manager (
KeylessProxyKsp.exe),ksp-register.exe, andksp-install-cert.exeintoC:\Program Files\Keyless Proxy Ksp\. - Creates Start Menu and optional Desktop shortcuts.
- Supports unattended/silent deployment via
/VERYSILENT /NORESTART.
Launch Keyless Proxy Ksp Certificate Manager from the Start Menu or run KeylessProxyKsp.exe:
- Auto-discovers
cert-serverinstances on your LAN. - Configures server connection and mTLS credentials (
ca.crt,client.crt,client.key). - Browses remote certificates and installs them into Current User\MY with one click.
- Manages and uninstalls existing certificate bindings.
Uninstalling through Windows Settings > Apps > Installed apps (or unins000.exe):
- Automatically unregisters the provider from Windows CNG.
- Removes
C:\Windows\System32\fredprx_ksp.dlland application files.
If you prefer building and registering manually without the installer:
- Build binaries:
powershell -ExecutionPolicy Bypass -File scripts/build-ksp.ps1
- Copy
build\fredprx_ksp.dlltoC:\Windows\System32 - Register the provider (elevated PowerShell):
build\ksp-register.exe -register
- Install a remote certificate binding (uses mTLS certificates):
This writes
build\ksp-install-cert.exe ` -addr server.example.com:50051 ` -ca certs\ca.crt ` -cert certs\client.crt ` -key certs\client.key
%ProgramData%\fredprx-ksp\config.json, prompts to select a certificate, and installs it into Current User\MY bound to the KSP provider. Installed bindings are queried directly from the certificate store. - Windows applications can now acquire the private key via
CryptAcquireCertificatePrivateKey; signing is delegated tocert-server.
build\ksp-install-cert.exe -list
build\ksp-install-cert.exe -remove <THUMBPRINT>
build\ksp-register.exe -unregister| Path | Description |
|---|---|
proto/cert/v1/cert.proto |
gRPC API definition |
gen/cert/v1/ |
Generated protobuf/gRPC Go code |
internal/certstore/ |
Platform certificate store enumeration and signing (Windows NCrypt & macOS Keychain) |
internal/server/ |
gRPC service implementation and UDP discovery |
internal/tlsutil/ |
mTLS configuration helpers |
internal/ctkbridge/ |
Go c-archive exports linked into macOS CTK provider |
internal/kspclient/ |
gRPC client library for Windows KSP bridge |
cmd/cert-server/ |
Cross-platform gRPC server entrypoint (macOS & Windows) |
cmd/example-client/ |
Interactive example client |
cmd/run-discovery/ |
UDP LAN discovery client |
cmd/gencerts/ |
Dev mTLS CA/server/client certificate generator |
cmd/local-sign-test-mac/ |
macOS local Keychain signing test utility |
cmd/local-sign-test-win/ |
Windows local CNG signing test utility |
cmd/ksp-register/ |
Register/unregister the Windows CNG KSP (admin) |
cmd/ksp-install-cert/ |
Install a remote cert into Windows MY store and bind to KSP |
ksp/ |
Windows CNG Key Storage Provider DLL sources |
mac-provider/ |
macOS GUI App (KeylessProxy) and CryptoTokenKit (CTK) extension (KeylessProxyExtension) sources |
scripts/build-app-bundle.sh |
Build macOS app and extension bundle via xcodegen and xcodebuild |
scripts/install-app-mac.sh |
Install macOS app bundle to /Applications and register CTK plugin |
scripts/build-release-artifacts.sh |
Build all release binaries/zips and optionally publish to GitHub |
scripts/gen-proto.ps1 |
Regenerate protobuf code |
scripts/build-ksp.ps1 |
Build Windows KSP DLL and helper tools |
- ListCertificates — returns thumbprint, subject, issuer, validity, key type/size, TPM flag, provider name, and certificate DER
- SignHash — signs a pre-computed digest (SHA-256, SHA-384, or SHA-512) with the certificate identified by thumbprint; RSA keys support
pkcs1(default) orpsspadding viarsa_padding
- On Windows, certificates using Microsoft Platform Crypto Provider are flagged as
is_tpm=true. TPM keys are non-exportable and signed in-place viaNCryptSignHash. - On macOS, certificates stored in system or user keychains with non-exportable private keys are accessed via Security framework APIs.
- RSA signing supports PKCS#1 v1.5 (default) and PSS (
-padding psson the example client).
# Windows
powershell -ExecutionPolicy Bypass -File scripts/gen-proto.ps1
# macOS / Linux (if protoc & plugins installed)
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
proto/cert/v1/cert.proto- mTLS transport certs (
cmd/gencerts) are separate from signing certificates. - The server defaults to
127.0.0.1— bind to a broader interface only in trusted networks. certs/is gitignored; regenerate for each environment.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
