Skip to content

zfs: fix FIPS_PRIVATE_KEY_LOCKED_E (-287) on encrypted dataset creation under wolfCrypt FIPS#341

Open
ColtonWilley wants to merge 1 commit into
wolfSSL:masterfrom
ColtonWilley:zfs-fips-private-key-unlock
Open

zfs: fix FIPS_PRIVATE_KEY_LOCKED_E (-287) on encrypted dataset creation under wolfCrypt FIPS#341
ColtonWilley wants to merge 1 commit into
wolfSSL:masterfrom
ColtonWilley:zfs-fips-private-key-unlock

Conversation

@ColtonWilley

Copy link
Copy Markdown
Contributor

Problem

Building the wolfZFS patch against a wolfCrypt FIPS wolfssl (e.g. --enable-fips=ready --enable-linuxkm --enable-wolfzfs=kernel --enable-cryptonly) loads and POSTs fine, but zfs create -o encryption=aes-256-gcm panics the kernel:

error: wc_HKDF: -287
VERIFY0(zio_crypt_key_init(crypt, &dck.dck_key)) failed (5)
PANIC at dsl_crypt.c:2583:dsl_crypto_key_create_sync()   [txg_sync]

-287 = FIPS_PRIVATE_KEY_LOCKED_E. This is not a CAST/self-test failure (those would surface as HMAC_KAT_FIPS_E / FIPS_NOT_ALLOWED_E): under FIPS 140-3, KDF output is keying material (a CSP), so every KDF service is gated behind the operator private-key-read lock (privateKeyReadEnable in wolfcrypt/src/fips.c). In kernel mode that lock is one module-global atomic, default locked, and nothing in the ZFS module ever raises it — so in-kernel wc_HKDF() always returns -287 regardless of FIPS version (the gate exists in every FIPS ≥ 5.1).

The gap is invisible in the current (non-FIPS) demo configuration because PRIVATE_KEY_UNLOCK() compiles to a no-op without FIPS.

Fix

Bracket the wc_HKDF() call in hkdf_sha512() (module/zfs/hkdf.c) with PRIVATE_KEY_UNLOCK() / PRIVATE_KEY_LOCK() — the same pattern wolfSSL's own linuxkm crypto-API glue uses (linuxkm/lkcapi_ecdh_glue.c, lkcapi_dh_glue.c) and wolfProvider uses in userspace (src/wp_hkdf.c). The kernel-mode lock is counter-based, so the bracket is concurrency-safe. Non-FIPS builds are unaffected (macros are no-ops).

This is the only unlock the in-kernel path needs: of the wolfCrypt services ZFS uses in-kernel, only the KDF is lock-gated (AES-GCM/CCM, SHA-2, HMAC, RNG are not).

Verification

Debian 13 (6.12.90), wolfssl-5.9.1-gplv3-fips-ready, in-kernel FIPS module with passing startup POST:

  • Before: encrypted dataset create reproducibly hits wc_HKDF: -287spl_panic from txg_sync (dmesg above).
  • After (only zfs.ko rebuilt; same libwolfssl.ko binary): encrypted create (aes-256-gcm, keyformat=passphrase, checksum=sha512), 64 MB zvol write/readback round-trip after cache drop, zfs unload-key/load-key, zpool scrub (0 errors), and reboot → zpool importload-key → data intact — all pass.
  • nm zfs.ko shows U wolfCrypt_SetPrivateKeyReadEnable_fips (macro expanded to the FIPS call; symbol is exported by libwolfssl.ko).

Reviewing the regenerated patch file

The patch file was regenerated with git am + amend + git format-patch on OpenZFS cd06f79e2. Diffing it against the previous version shows changes only in: the embedded commit hash, the module/zfs/hkdf.c diffstat/summary lines, and the hkdf_sha512() hunk (+7 lines). git apply --check passes on a pristine cd06f79e2 tree.

Under a wolfCrypt FIPS 140-3 build (any FIPS version >= 5.1), KDF
services are gated behind the operator private-key-read lock: wc_HKDF()
resolves to wc_HKDF_fips(), which returns FIPS_PRIVATE_KEY_LOCKED_E
(-287) unless wolfCrypt_SetPrivateKeyReadEnable_fips(1, WC_KEYTYPE_ALL)
has been raised (wolfcrypt/src/fips.c, privateKeyReadEnable gate). In
kernel mode the lock is a module-global atomic counter defaulting to
locked, and nothing in the ZFS module raises it, so
`zfs create -o encryption=aes-256-gcm` fails HKDF-SHA512 dataset-key
derivation and panics: VERIFY0(zio_crypt_key_init()) -> spl_panic from
the txg_sync kthread (PANIC at dsl_crypt.c:2583).

Bracket the wc_HKDF() call in hkdf_sha512() with PRIVATE_KEY_UNLOCK()/
PRIVATE_KEY_LOCK(), the same pattern wolfSSL's own linuxkm crypto-API
glue uses (linuxkm/lkcapi_ecdh_glue.c, lkcapi_dh_glue.c) and wolfProvider
uses in userspace (src/wp_hkdf.c). The macros are defined in
wolfssl/wolfcrypt/types.h behind FIPS_VERSION_GE(5,1) and compile to
no-ops in non-FIPS builds, so the existing (non-FIPS) demo configuration
is unaffected. The kernel-mode lock is counter-based, so the bracket is
safe under concurrent HKDF calls.

Verified on Debian 13 (kernel 6.12.90) with wolfssl-5.9.1-gplv3-fips-ready
configured --enable-fips=ready --enable-linuxkm --enable-wolfzfs=kernel
--enable-cryptonly: without this change, encrypted dataset creation
reproducibly fails (dmesg: "error: wc_HKDF: -287" followed by the
dsl_crypto_key_create_sync PANIC); with it, encrypted dataset create,
64 MB zvol write/readback round-trip, zfs unload-key/load-key, zpool
scrub, and reboot+import+load-key all pass on the in-kernel FIPS module
(FIPS 140-3 startup self-test passing).

The patch file was regenerated via git am + amend + git format-patch on
OpenZFS cd06f79e2; only the module/zfs/hkdf.c section and the diffstat
changed relative to the previous version.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant