gosigner

command module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: MIT Imports: 18 Imported by: 0

README

gosigner

Remote Microsoft Authenticode signing for Windows PE files (.exe, .dll) over the Spot end-to-end-encrypted network. A USB code-signing token lives on one trusted machine; developers anywhere sign without ever holding the PIN or the certificate.

Everything is pure Go. No osslsigncode, no PKCS#11 engine, no closed-source vendor library — pcscd (open-source pcsc-lite) is the only system service required on the daemon host.

How it works

┌──────────────────────┐                          ┌────────────────────────┐
│ developer machine    │   Util/TempFile          │ daemon (token holder)  │
│                      │ ←────  blob store  ─→    │                        │
│ signreq:             │                          │ gosigner:              │
│ • AES-256-GCM encrypt│                          │ • verify shared secret │
│ • upload ciphertext  │                          │ • download + decrypt   │
│ • Query peer/sign ───┼──── E2E Spot message ───→│ • authenticode.Sign    │
│ • download reply     │                          │   driven by hsm.Key    │
│ • decrypt + write    │←──── E2E Spot reply ─────│ • re-encrypt + upload  │
└──────────────────────┘                          └────────────────────────┘
                                                            │
                                                            ▼ APDUs over pcscd
                                                  ┌────────────────────────┐
                                                  │ USB token (eToken etc.)│
                                                  └────────────────────────┘

Spot messages are E2E encrypted by spotlib; blob payloads on Util/TempFile are independently AES-256-GCM encrypted with a per-transfer key carried inside the Spot message. The daemon authorizes by a shared secret (constant-time compared), not by the client's identity. Clients use an ephemeral Spot key.

Signing uses github.com/KarpelesLab/authenticode for the PE + CMS + RFC 3161 path and github.com/KarpelesLab/hsm (HSM=idprime) to drive the USB token over pcsc-lite's Unix socket. The plaintext binary never touches the daemon's disk.

Client (developer side)

No clone, no install:

go run github.com/KarpelesLab/gosigner/cli/signreq@latest \
    -peer   k.PEER-ID-FROM-DAEMON \
    -secret "shared-secret" \
    -o      mybinary.signed.exe \
    mybinary.exe

The client picks an ephemeral Spot identity, encrypts the binary, hands it to the daemon over Spot, and writes the signed result.

signreq flags
Flag Env Default Notes
-peer GOSIGNER_PEER (required) Daemon Spot peer id, k.…
-secret GOSIGNER_SECRET (required) Shared secret matching the daemon's -secret
-o <name>.signed<ext> Output path
-name (none) Program name embedded in SpcSpOpusInfo (publisher's display name — equivalent to signtool /d, osslsigncode -n)
-url (none) Program URL embedded in SpcSpOpusInfo (the "More information" link — equivalent to signtool /du, osslsigncode -i)
-endpoint GOSIGNER_ENDPOINT sign Spot endpoint name on the daemon
-timeout 5m Overall timeout for the round trip

Example with publisher metadata:

go run github.com/KarpelesLab/gosigner/cli/signreq@latest \
    -peer   k.PEER-ID \
    -secret '<shared-secret>' \
    -name   "ACME Widget Installer 3.2" \
    -url    "https://acme.example/installer" \
    -o      installer.signed.exe installer.exe

Daemon (token side)

The host that physically holds the token runs:

HSM=idprime IDPRIME_PIN='<token-pin>' gosigner \
    -identity ./gosigner.key \
    -secret   '<shared-secret>'

On first launch it generates ./gosigner.key (an ed25519 PKCS#8 PEM, mode 0600) and prints its peer id (k.…). The peer id is stable across restarts as long as that key file is kept. Hand the peer id + shared secret to the developers who need to sign.

The signing certificate, certificate chain, key reference, and algorithm OID are all discovered automatically from the card — no -cert, -key-id, or -pkcs11-module flags. The PIN goes through IDPRIME_PIN (env) so it stays out of ps / shell history.

Daemon flags
Flag Env Default Notes
-identity GOSIGNER_IDENTITY ./gosigner.key ed25519 Spot identity (created if absent)
-secret GOSIGNER_SECRET (required) Shared secret clients must present
-key-cn GOSIGNER_KEY_CN (none) Optional Subject.CN filter when the card carries multiple keys
-timestamp-url GOSIGNER_TIMESTAMP_URL http://timestamp.digicert.com RFC 3161 TSA; empty disables timestamping
-hash GOSIGNER_HASH sha384 sha256 / sha384 / sha512
-endpoint GOSIGNER_ENDPOINT sign Spot endpoint name

The HSM is selected via the HSM env var (defaults to idprime); the IDPrime backend reads IDPRIME_PIN, IDPRIME_READER, etc. — see KarpelesLab/hsm.

What the daemon ever writes to disk

Just the ed25519 identity (./gosigner.key, one-time on first launch). The binary being signed, the cert chain, the PIN, and the AES keys are kept only in memory. Token I/O is via the pcsc-lite Unix socket; signing runs in-process.

Verifying a signed binary

Any Authenticode verifier works — for example:

osslsigncode verify -in mybinary.signed.exe

License

See LICENSE.

Documentation

Overview

Command gosigner is the daemon side of the remote Authenticode signer.

It holds a static ed25519 Spot identity (so its peer id is stable) and the USB code-signing token. It listens on the Spot network for sign requests carrying a shared secret, downloads the caller's encrypted binary from Util/TempFile, signs it natively in Go via the github.com/KarpelesLab/authenticode and github.com/KarpelesLab/hsm libraries (no osslsigncode, no PKCS#11 engine, no closed library), re-encrypts the result, uploads it back, and replies with the new location + AES key over the end-to-end-encrypted Spot channel.

Directories

Path Synopsis
cli
signreq command
Command signreq is the client side of the remote Authenticode signer.
Command signreq is the client side of the remote Authenticode signer.
internal
proto
Package proto holds the wire types and shared helpers used by both the gosigner daemon and the signreq client: the Spot request/response envelope, per-transfer AES-256-GCM file encryption, the static ed25519 identity store, and Util/TempFile upload/download (tunneled through Spot).
Package proto holds the wire types and shared helpers used by both the gosigner daemon and the signreq client: the Spot request/response envelope, per-transfer AES-256-GCM file encryption, the static ed25519 identity store, and Util/TempFile upload/download (tunneled through Spot).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL