Skip to content

Latest commit

 

History

History
201 lines (157 loc) · 7.7 KB

File metadata and controls

201 lines (157 loc) · 7.7 KB

Entrust nShield notes

Vendor-specific operational details for running sq-pkcs11 against an Entrust nShield HSM (FIPS 140-3 Security World). The main README covers the portable PKCS#11 / OpenPGP surface; this file collects the nShield-specific paths, behaviours, and recipes that don't belong there.

Module path

export PKCS11_MODULE_PATH=/opt/nfast/toolkits/pkcs11/libcknfast.so

Or pass -m /opt/nfast/toolkits/pkcs11/libcknfast.so per invocation. The Linux client must have the nfast group membership and the hardserver running for the module to initialise.

Vendor tooling reference

The integration with sq-pkcs11 is purely PKCS#11 — but provisioning, Security World administration, and operational verification all run through nShield's own command-line tools:

Tool Used for
generatekey pkcs11 … provision keys (FIPS-mode runs require ACS auth)
createocs / ppmk create Operator Card Sets / softcards
nfkminfo inspect Security World, list keys, dump key metadata
cklist (in /opt/nfast/bin) dump full PKCS#11 attribute set per object, including vendor CKA_NFKM_*
preload run the K/N OCS quorum ceremony and hand off an authenticated session to sq-pkcs11 (the recommended path for K>1 logins)

OCS K/N quorum login via preload

For Operator Card Sets with K > 1 (a quorum of cards), wrap the sq-pkcs11 invocation in nShield's preload utility. preload runs the interactive ceremony — slot polling, "X of K cards read" progress, per-card passphrase prompts — and then exec()s the child process with the preloaded OCS available through the PKCS#11 module:

preload -c openssl-release-primary -- \
  sq-pkcs11 cert-export \
    --key-label  openssl-release-primary \
    --userid     "OpenSSL Release Key <openssl-security@openssl.org>" \
    ...

From sq-pkcs11's side the session looks already-authenticated — no --pin-file is needed, and there is no --ocs flag. The PKCS#11 module picks up the preloaded cardset and treats the session as logged-in; with most nShield setups the standard C_Login is bypassed internally.

Why preload rather than calling C_LoginBegin / C_LoginNext / C_LoginEnd ourselves:

  • preload is the canonical nShield UX for K/N ceremonies — mature slot-state display, ESN feedback, card-swap handling.
  • Works in HSM Pool and load-sharing topologies, where the C_LoginBegin trio does not.
  • Removes a vendor-specific dlopen of nShield-only symbols from sq-pkcs11, keeping the binary portable to other PKCS#11 modules.

Environment requirements for the child:

  • CKNFAST_LOADSHARING=1 should be set (it is the default in modern Security World installs; verify on legacy hosts). Without it, the PKCS#11 module won't see the preloaded OCS and sq-pkcs11 will observe an un-authenticated session.
  • Cards must be inserted into readers connected to the nShield host before the quorum prompts, exactly as today.

For K = 1 OCS, plain C_Login still works — use --pin-file <path> (or the SQ_PKCS11_PIN env var) directly, without preload.

Vendor CKA_NFKM_* attributes

Visible via cklist -n --cka-label=<LABEL> on every nShield-resident key. The ones that matter operationally:

Attribute Meaning
CKA_NFKM_APPNAME Always pkcs11 for keys generated by generatekey pkcs11.
CKA_NFKM_ID The Security World ident — bridge from PKCS#11 to nfkminfo.
CKA_UNIQUE_ID <NFKM_ID>-NNNNNNNN per object handle.
CKA_NFKM_HASH 20-byte SHA-1 of the key blob — useful for cross-checks.

Things you might expect but won't find:

Attribute Status on nShield
CKA_START_DATE Always 0000 00 00 — never populated by generatekey.
CKA_END_DATE Same — empty.
CKA_KEY_GEN_MECHANISM Always CK_UNAVAILABLE_INFORMATION.
Any vendor "key creation time" attribute Does not exist.

The key generation timestamp is held only in the Security World blob and exposed only via nfkminfo text output — see the next section.

Reading the key generation time from the Security World

The OpenPGP fingerprint is derived from key material and a creation timestamp; see the README's --creation-time discussion. If you'd like that timestamp to align with the actual nShield key-generation event (rather than picking an arbitrary fixed value), extract it from nfkminfo:

$ nfkminfo -k pkcs11 uab282744a02232accec4ccef07cde5cdeb6b1cd5b
Key AppName pkcs11 Ident uab282744a02232accec4ccef07cde5cdeb6b1cd5b
 ...
 protection            Module
 gentime               2026-04-30 15:55:33
 ...

A small helper that maps a CKA_LABEL to its RFC 3339 gentime, ready to feed to --creation-time:

#!/usr/bin/env bash
# hsm-gentime <CKA_LABEL>
# Prints e.g. 2026-04-30T15:55:33Z
set -euo pipefail
label=$1

# Step 1: CKA_LABEL → CKA_NFKM_ID
ident=$(/opt/nfast/bin/cklist -n --cka-label="$label" \
        | awk -F'"' '/CKA_NFKM_ID/ { print $2; exit }')

# Step 2: ident → gentime (whitespace-separated date and time fields)
/opt/nfast/bin/nfkminfo -k pkcs11 "$ident" \
    | awk '/^[ \t]*gentime/ { printf "%sT%sZ\n", $2, $3 }'

Usage:

KEY_TIME=$(./hsm-gentime openssl-release-primary)
./sq-pkcs11 cert-export --creation-time "$KEY_TIME" ...
./sq-pkcs11 sign        --creation-time "$KEY_TIME" ...

Timezone caveat

The gentime value is whatever the host clock reported when generatekey ran — there is no timezone marker stored in the key blob. The script above appends Z (UTC) on the assumption that the HSM client was running in UTC at provisioning time, which is the safest convention for shared release infrastructure.

If your client was on local time during generatekey, translate explicitly before feeding the value to sq-pkcs11:

# host was on Europe/Berlin during generatekey:
TZ=UTC date -d "2026-04-30 15:55:33 Europe/Berlin" +"%Y-%m-%dT%H:%M:%SZ"

Once you've extracted and converted the timestamp the first time, document it and treat it as fixed forever — exactly like any other manually-chosen --creation-time value. The Security World is the source of truth, but for verifiers all that matters is that the OpenPGP certificate consistently embeds the same value.

Multi-module Security Worlds

sq-pkcs11 automatically handles the case where two or more nShield modules participate in one Security World: every module-protected key appears identically on each module's accelerator slot, and the tool picks the first reachable slot for module-protected operations (LoginMode::None). No action is required from the operator.

For OCS-protected keys (whether single-card via --pin-file or K/N quorum via preload), the OCS slot must be addressed explicitly via --key-uri pkcs11:token=<ocs-name>;... since multiple slots may carry the same OCS state — see the README's authentication section for the URI patterns.

FIPS 140-3 algorithm constraints

The algorithm subset in sq-pkcs11 (RSA-3072 / RSA-4096 / ECDSA P-256 / P-384 / P-521 with SHA-256/384/512) was chosen specifically to match what nShield permits in FIPS 140-3 strict mode. Notable exclusions imposed by that mode:

  • Ed25519 — not approved before nShield firmware V13.7, and even then deployment-dependent. The tool does not advertise Ed25519 support.
  • SHA-1 in any signing role — forbidden. All certificate self-signatures use SHA-256 or stronger.
  • RSA-PKCS#1 with arbitrary hash — forbidden. We use CKM_RSA_PKCS with a pre-computed DigestInfo (built in src/signer.rs::digest_info_prefix), not the all-in-one CKM_SHA*_RSA_PKCS mechanisms.

See also