Skip to content

feat(adapters/pkcs11): HSM-backed MAC (vault.Macer) verified against SoftHSM2#11

Closed
canaan5 wants to merge 6 commits into
mainfrom
feat/pkcs11-foundation
Closed

feat(adapters/pkcs11): HSM-backed MAC (vault.Macer) verified against SoftHSM2#11
canaan5 wants to merge 6 commits into
mainfrom
feat/pkcs11-foundation

Conversation

@canaan5

@canaan5 canaan5 commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Turns the PKCS#11 foundation into a working, capability-correct MAC adapter for a general-purpose HSM.

What it does

Implements vault.Macer (GenerateMAC/VerifyMAC) for ISO 9797-1 algorithm 1 (single-DES CBC-MAC) and algorithm 3 (ANSI X9.19 retail MAC), composed from the token's 3DES primitives (CKM_DES3_CBC/CKM_DES3_ECB). Modern tokens disable single-DES and expose no retail-MAC mechanism, so a single-DES E_K is obtained by presenting K as a triple-length key K‖K‖K. The key never leaves the token; only the public padding/message are host-side.

Output is byte-for-byte identical to vault.GenerateMAC — cross-checked against a real token under SoftHSM2 (new CI job; also verified locally on SoftHSM 2.7.0): both algorithms, both paddings, empty/partial/multi-block messages, plus verify match / 4-byte-truncated / tamper.

Capability surface (the security property)

The type now advertises exactly vault.Macer. The PIN methods are removed, not stubbed, so the type does not structurally satisfy vault.PINTranslator — callers rely on that interface's presence to mean the op is PIN-secure, and a stock PKCS#11 HSM has no PCI-compliant atomic translate. A test asserts the type is not a PINTranslator/PINEncryptor/Vault. PIN translation lives in the payment-HSM adapter (#13, payShield).

Tests

  • No-HSM (run anywhere): capability surface, ISO 9797-1 padding vectors, config validation.
  • SoftHSM2 (env-gated, skips without a token): provisions its own keys, cross-checks adapter MAC == vault.GenerateMAC, verify/tamper.

Note on stacking

Built on #12 (vault capability interfaces), required for Macer. Until #12 merges, this diff includes #12's commits; it cleans up once #12 lands. Separate cgo module; the core stays stdlib-only.

canaan5 added 2 commits June 3, 2026 16:03
Foundation for a PKCS#11/HSM-backed vault.Vault, in a separate cgo module so the
stdlib-only core is untouched. NOT production-ready.

Implemented and build-verified (cgo, miekg/pkcs11):
- Config + Open/Close: module load, token selection, session, C_Login.
- Key lookup by CKA_LABEL (keyRef -> object handle).
- Compile-time vault.Vault conformance; no-HSM tests for stubs + config.

Deliberately stubbed (return ErrNotImplemented), with documented intended
PKCS#11 mappings:
- GenerateMAC/VerifyMAC: ISO 9797-1 -> mechanism mapping is HSM-specific; must be
  verified against SoftHSM and security-reviewed.
- EncryptPINBlock: EncodePINBlock + CKM_DES3_ECB (forms clear PIN block in host).
- TranslatePIN: BLOCKED. A secure HSM translate is an atomic operation where the
  clear PIN never leaves the token; stock PKCS#11 has no such mechanism, and the
  decrypt-reencrypt emulation of the current vault.Vault contract would expose
  the clear PIN block in host memory (PCI PIN Security violation).

This surfaces a v1 vault-API decision (see README + ROADMAP B1): the production
HSM path likely needs HSM-oriented operations over encrypted PIN blocks, rather
than the software-model clear-PIN interface. No working/secure crypto is shipped
here on purpose.
Make the key-management façade HSM-adapter-ready by splitting it into small
capability interfaces, so an adapter implements exactly what its device supports.

- Add PINEncryptor, PINTranslator, and Macer. Vault is now their composition,
  so it keeps the same method set — source-compatible; SoftVault and SealedVault
  still satisfy Vault unchanged.
- PINTranslator documents the PCI PIN Security contract: a conforming hardware
  implementation must re-encipher the PIN block atomically inside the device so
  the clear PIN never leaves it; an adapter that cannot (e.g. stock PKCS#11) must
  not implement the interface, since callers rely on its presence to mean the
  operation is PIN-secure.
- A general-purpose PKCS#11 HSM provides Macer (and possibly PINEncryptor); a
  payment HSM (Thales payShield, Futurex) additionally provides PINTranslator.
  Callers type-assert for the narrowest capability they need.

Adds capability-detection tests. gofmt/vet clean; ./... builds, vault/flow/gateway
pass under -race.
canaan5 added 3 commits June 4, 2026 03:07
Turn the PKCS#11 foundation into a working, capability-correct MAC adapter.

What it does:
- Implements vault.Macer (GenerateMAC/VerifyMAC) for ISO 9797-1 algorithm 1
  (single-DES CBC-MAC) and algorithm 3 (ANSI X9.19 retail MAC).
- Composes the MAC from the token's 3DES primitives (CKM_DES3_CBC/CKM_DES3_ECB),
  since modern tokens disable single-DES and expose no retail-MAC mechanism: a
  single-DES E_K is obtained by presenting K as a triple-length key K||K||K. The
  key never leaves the token; only the public padding/message are host-side.
- Output is byte-for-byte identical to vault.GenerateMAC, cross-checked against a
  real token under SoftHSM2 (new CI job; verified locally on SoftHSM 2.7.0).

Capability surface (the security property):
- The type now advertises exactly vault.Macer. The PIN methods are REMOVED, not
  stubbed, so the type does not structurally satisfy vault.PINTranslator —
  callers rely on that interface's presence to mean the op is PIN-secure, and a
  stock PKCS#11 HSM has no PCI-compliant atomic translate. EncryptPINBlock is a
  clear-PIN issuer-context op and likewise omitted. A test asserts the type is
  not a PINTranslator/PINEncryptor/Vault.

Tests:
- No-HSM: capability surface, ISO 9797-1 padding vectors, config validation.
- SoftHSM2 (env-gated, skips without a token): provisions its own keys and
  cross-checks adapter MAC == vault.GenerateMAC across both algorithms, both
  paddings, empty/partial/multi-block messages, plus verify match/truncate/tamper.

CI: new adapters/pkcs11 job installs softhsm2, provisions a token, runs the
race suite. README rewritten for the MAC-only capability and key provisioning.
@canaan5 canaan5 marked this pull request as ready for review June 4, 2026 07:19
@canaan5 canaan5 changed the title feat(adapters/pkcs11): HSM Vault adapter foundation (B1) [draft] feat(adapters/pkcs11): HSM-backed MAC (vault.Macer) verified against SoftHSM2 Jun 4, 2026
@canaan5 canaan5 closed this Jun 9, 2026
@canaan5 canaan5 deleted the feat/pkcs11-foundation branch June 9, 2026 11:45
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 9, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant