Files
hsm/signer_pkcs11.go
zeekay 36a27aa04a airgap: export AirgapTransport/Format + nitrokey/pkcs11/yubihsm surface
The hardware-wallet signers committed in 6d2dc12 reference AirgapTransport,
AirgapFormat, AirgapChallenge and the airgap session helpers. Those types
plus the PKCS#11 / YubiHSM / Nitrokey signers were left untracked, so a
fresh checkout could not compile and the factory cases for coldcard,
foundation, keystone, and ngrave were not actually reachable from
NewSigner — the surface luxfi/mpc cmd/mpcd airgap_command.go is gated on.

This lands the missing files unchanged (real implementation, not stubs):

  airgap.go                      AirgapTransport interface + MockTransport
  airgap_random.go               crypto/rand wrapper for session IDs
  signer_nitrokey.go             Nitrokey HSM 2 (PKCS#11 wrapper)
  signer_pkcs11.go               Universal PKCS#11 entrypoint
  signer_pkcs11_cgo.go           Real cgo build (//go:build pkcs11)
  signer_pkcs11_stub.go          Build-tag stub for non-cgo builds
  signer_yubihsm.go              YubiHSM 2 over yubihsm-connector
  signer_yubihsm_helpers.go      Object-ID parsing helpers
  signer_yubihsm_test.go         Coverage for YubiHSM helpers

After this commit hsm.NewSigner("coldcard"|"foundation"|"keystone"|
"ngrave", cfg) returns a real Signer; the file-mediated airgap ceremony
in luxfi/mpc cmd/mpcd remains the operator UX layer (Coldcard microSD is
the canonical product flow), but in-process signers are now wireable for
tests and kiosk transports.
2025-12-27 17:00:00 -08:00

77 lines
3.1 KiB
Go

// Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package hsm
// PKCS11Config configures a PKCS#11 v2.40 token. The same configuration
// type covers Thales SafeNet Luna, Utimaco u.trust SecurityServer,
// Entrust nShield, Marvell LiquidSecurity, AWS CloudHSM (PKCS#11 client),
// GCP Cloud HSM (PKCS#11 client), Azure Dedicated HSM, IBM Cloud HSM,
// Oracle Cloud HSM, SoftHSM2, and Nitrokey HSM 2 (via OpenSC).
//
// The real signer compiled with `-tags pkcs11` lives in
// signer_pkcs11_cgo.go and depends on github.com/miekg/pkcs11 (BSD-3,
// Cloudflare-maintained) which calls into the vendor's libCryptoki
// shared library via CGO.
//
// The default build (no tag) ships only the configuration types and the
// stub returned by NewPKCS11Signer so packages that import luxfi/hsm do
// not require a CGO toolchain. Operators who need PKCS#11 support build
// mpcd with `-tags pkcs11`.
type PKCS11Config struct {
// LibraryPath is the absolute filesystem path to the vendor's
// PKCS#11 shared library. Examples:
// Thales Luna: /usr/safenet/lunaclient/lib/libCryptoki2_64.so
// Utimaco: /opt/utimaco/p11/libcs_pkcs11_R3.so
// Entrust: /opt/nfast/toolkits/pkcs11/libcknfast.so
// AWS CloudHSM: /opt/cloudhsm/lib/libcloudhsm_pkcs11.so
// SoftHSM2: /usr/lib/softhsm/libsofthsm2.so
// Nitrokey: /usr/lib/opensc-pkcs11.so (via signer_nitrokey.go)
LibraryPath string
// SlotID is the PKCS#11 slot containing the token. Operators read
// available slots with `pkcs11-tool --list-slots -L`.
SlotID uint
// TokenLabel is an alternative to SlotID — when non-empty the signer
// scans all slots for a token whose CKA_LABEL matches. Preferred
// when multiple tokens may be present.
TokenLabel string
// Pin is the user PIN used for C_Login. In production this MUST be
// supplied via KMS — never embedded in config files. When empty
// the signer reads MPC_HSM_PKCS11_PIN at sign time.
Pin string
// KeyLabel is the CKA_LABEL of the asymmetric key on the token.
// The signer locates the key via C_FindObjectsInit with a template
// of {CKA_LABEL, CKA_CLASS=CKO_PRIVATE_KEY}.
KeyLabel string
// Mechanism is the PKCS#11 signing mechanism. Common values:
// "ECDSA" — CKM_ECDSA (raw, host pre-hashes)
// "ECDSA_SHA256" — CKM_ECDSA_SHA256
// "EDDSA" — CKM_EDDSA (Ed25519)
// "RSA_PKCS" — CKM_RSA_PKCS
// "RSA_PKCS_PSS" — CKM_RSA_PKCS_PSS
// When empty the signer defaults to "ECDSA_SHA256".
Mechanism string
}
// pkcs11ProviderName is the canonical Provider() string returned by
// PKCS11Signer regardless of which underlying token is in use.
const pkcs11ProviderName = "pkcs11"
// pinFromConfig returns the configured PIN or the value of
// MPC_HSM_PKCS11_PIN. The function is shared by the stub and the CGO
// implementation so PIN resolution behavior is identical.
func (c PKCS11Config) pinFromEnv(envLookup func(string) string) (string, error) {
if c.Pin != "" {
return c.Pin, nil
}
if v := envLookup("MPC_HSM_PKCS11_PIN"); v != "" {
return v, nil
}
return "", errPKCS11NoPin
}