zfs: fix FIPS_PRIVATE_KEY_LOCKED_E (-287) on encrypted dataset creation under wolfCrypt FIPS#341
Open
ColtonWilley wants to merge 1 commit into
Open
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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, butzfs create -o encryption=aes-256-gcmpanics the kernel:-287=FIPS_PRIVATE_KEY_LOCKED_E. This is not a CAST/self-test failure (those would surface asHMAC_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 (privateKeyReadEnableinwolfcrypt/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-kernelwc_HKDF()always returns-287regardless 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 inhkdf_sha512()(module/zfs/hkdf.c) withPRIVATE_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:
wc_HKDF: -287→spl_panicfromtxg_sync(dmesg above).zfs.korebuilt; samelibwolfssl.kobinary): 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 import→load-key→ data intact — all pass.nm zfs.koshowsU wolfCrypt_SetPrivateKeyReadEnable_fips(macro expanded to the FIPS call; symbol is exported bylibwolfssl.ko).Reviewing the regenerated patch file
The patch file was regenerated with
git am+ amend +git format-patchon OpenZFScd06f79e2. Diffing it against the previous version shows changes only in: the embedded commit hash, themodule/zfs/hkdf.cdiffstat/summary lines, and thehkdf_sha512()hunk (+7 lines).git apply --checkpasses on a pristinecd06f79e2tree.