From 389d663e1dff3b5484d2c8204118903e6c62858f Mon Sep 17 00:00:00 2001 From: Michal Hlavinka Date: Thu, 12 Feb 2026 12:14:10 +0100 Subject: [PATCH] make getting password from backed up secret FIPS compatible (RHEL-113242) Resolves: RHEL-113242 --- volume_key-0.3.12-fips2.patch | 207 ++++++++++++++++++++++++++++++++++ volume_key.spec | 14 ++- 2 files changed, 217 insertions(+), 4 deletions(-) create mode 100644 volume_key-0.3.12-fips2.patch diff --git a/volume_key-0.3.12-fips2.patch b/volume_key-0.3.12-fips2.patch new file mode 100644 index 0000000..c8894e2 --- /dev/null +++ b/volume_key-0.3.12-fips2.patch @@ -0,0 +1,207 @@ +diff --git a/lib/crypto.c b/lib/crypto.c +index 7554f19..7b8dc39 100644 +--- a/lib/crypto.c ++++ b/lib/crypto.c +@@ -179,6 +179,150 @@ import_sym_key (PK11SlotInfo *slot, CK_MECHANISM_TYPE type, PK11Origin origin, + } + + /* LIBVK_PACKET_FORMAT_ASYMMETRIC */ ++/* ++ * FIPS compliant implementation of PK11_ExtractKeyValue() + PK11_GetKeyData(). ++ * Instead of directly extracting the key value (which is not allowed in FIPS mode), ++ * we wrap the symmetric key with a temporary wrapping key, then decrypt the ++ * wrapped data to get the raw key bytes. ++ * Returns a newly allocated SECItem with the key data on success, NULL on failure. ++ * The caller must free the result with SECITEM_FreeItem(result, PR_TRUE). ++ */ ++static SECItem * ++extract_sym_key (PK11SymKey *sym_key) ++{ ++ CK_MECHANISM_TYPE wrap_mechanism = 0UL; ++ PK11SlotInfo *slot = NULL; ++ PK11SymKey *wrapping_key = NULL; ++ SECItem tmp_sec_item, wrapped_key_item; ++ PK11Context *wrap_key_crypt_context = NULL; ++ int block_size = 0; ++ size_t wrapped_key_size = 0; ++ unsigned char *wrapped_key = NULL; ++ SECItem *clear_key = NULL; ++ int out_len = 0; ++ unsigned int final_len = 0; ++ SECStatus ret = 0; ++ int key_len = 0; ++ ++ /* Fall back to PK11_ExtractKeyValue() + PK11_GetKeyData() if FIPS mode is disabled. */ ++ if (PK11_IsFIPS () == PR_FALSE) ++ { ++ SECItem *key_data; ++ ++ if (PK11_ExtractKeyValue (sym_key) != SECSuccess) ++ return NULL; ++ key_data = PK11_GetKeyData (sym_key); ++ if (key_data == NULL) ++ return NULL; ++ return SECITEM_DupItem (key_data); ++ } ++ ++ slot = PK11_GetSlotFromKey (sym_key); ++ if (slot == NULL) ++ return NULL; ++ ++ /* Get the best mechanism for the wrapping operation. */ ++ wrap_mechanism = PK11_GetBestWrapMechanism (slot); ++ ++ /* Generate a symmetric wrapping key. */ ++ wrapping_key = PK11_KeyGen (slot, wrap_mechanism, NULL, ++ PK11_GetBestKeyLength (slot, wrap_mechanism), ++ NULL); ++ PK11_FreeSlot (slot); ++ if (wrapping_key == NULL) ++ return NULL; ++ ++ /* Get block size and key length. */ ++ block_size = PK11_GetBlockSize (wrap_mechanism, NULL); ++ if (block_size == 0) ++ block_size = 1; ++ key_len = PK11_GetKeyLength (sym_key); ++ if (key_len <= 0) ++ { ++ PK11_FreeSymKey (wrapping_key); ++ return NULL; ++ } ++ ++ /* Allocate space for the wrapped key. ++ * Add extra space for padding (up to one block size). ++ */ ++ wrapped_key_size = key_len + block_size; ++ wrapped_key = g_try_malloc0 (wrapped_key_size); ++ if (wrapped_key == NULL) ++ { ++ PK11_FreeSymKey (wrapping_key); ++ return NULL; ++ } ++ ++ memset (&tmp_sec_item, 0, sizeof (tmp_sec_item)); ++ memset (&wrapped_key_item, 0, sizeof (wrapped_key_item)); ++ wrapped_key_item.data = wrapped_key; ++ wrapped_key_item.len = wrapped_key_size; ++ ++ /* Wrap the symmetric key using the wrapping key. */ ++ ret = PK11_WrapSymKey (wrap_mechanism, &tmp_sec_item, wrapping_key, sym_key, ++ &wrapped_key_item); ++ if (ret != SECSuccess) ++ { ++ g_free (wrapped_key); ++ PK11_FreeSymKey (wrapping_key); ++ return NULL; ++ } ++ ++ /* Now decrypt the wrapped key to get the raw bytes. ++ * Create a decryption context with the wrapping key. ++ */ ++ wrap_key_crypt_context = PK11_CreateContextBySymKey (wrap_mechanism, ++ CKA_DECRYPT, ++ wrapping_key, ++ &tmp_sec_item); ++ if (wrap_key_crypt_context == NULL) ++ { ++ g_free (wrapped_key); ++ PK11_FreeSymKey (wrapping_key); ++ return NULL; ++ } ++ ++ /* Allocate space for the decrypted (clear) key. */ ++ clear_key = SECITEM_AllocItem (NULL, NULL, wrapped_key_item.len); ++ if (clear_key == NULL) ++ { ++ g_free (wrapped_key); ++ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE); ++ PK11_FreeSymKey (wrapping_key); ++ return NULL; ++ } ++ ++ /* Decrypt to get the raw key bytes. */ ++ ret = PK11_CipherOp (wrap_key_crypt_context, clear_key->data, &out_len, ++ clear_key->len, wrapped_key_item.data, ++ wrapped_key_item.len); ++ if (ret != SECSuccess) ++ { ++ SECITEM_FreeItem (clear_key, PR_TRUE); ++ g_free (wrapped_key); ++ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE); ++ PK11_FreeSymKey (wrapping_key); ++ return NULL; ++ } ++ ++ ret = PK11_DigestFinal (wrap_key_crypt_context, clear_key->data + out_len, ++ &final_len, clear_key->len - out_len); ++ g_free (wrapped_key); ++ PK11_DestroyContext (wrap_key_crypt_context, PR_TRUE); ++ PK11_FreeSymKey (wrapping_key); ++ if (ret != SECSuccess) ++ { ++ SECITEM_FreeItem (clear_key, PR_TRUE); ++ return NULL; ++ } ++ ++ /* Adjust the length to the actual key length (remove padding). */ ++ clear_key->len = key_len; ++ ++ return clear_key; ++} ++ + + /* Encrypt DATA of SIZE for CERT. + Return encrypted data (for g_free()), setting RES_SIZE to the size of the +@@ -532,20 +676,19 @@ unwrap_asymmetric (size_t *clear_secret_size, const void *wrapped_secret_data, + error_from_pr (error); + goto err; + } +- if (PK11_ExtractKeyValue (secret_key) != SECSuccess) ++ clear_secret_item = extract_sym_key (secret_key); ++ PK11_FreeSymKey (secret_key); ++ if (clear_secret_item == NULL) + { + error_from_pr (error); +- goto err_secret_key; ++ goto err; + } +- clear_secret_item = PK11_GetKeyData (secret_key); + ret = g_memdup (clear_secret_item->data, clear_secret_item->len); + *clear_secret_size = clear_secret_item->len; +- PK11_FreeSymKey (secret_key); ++ SECITEM_FreeItem (clear_secret_item, PR_TRUE); + + return ret; + +- err_secret_key: +- PK11_FreeSymKey (secret_key); + err: + return NULL; + } +@@ -665,20 +808,19 @@ unwrap_symmetric (size_t *clear_secret_size, PK11SymKey *wrapping_key, + error_from_pr (error); + goto err; + } +- if (PK11_ExtractKeyValue (secret_key) != SECSuccess) ++ clear_secret_item = extract_sym_key (secret_key); ++ PK11_FreeSymKey (secret_key); ++ if (clear_secret_item == NULL) + { + error_from_pr (error); +- goto err_secret_key; ++ goto err; + } +- clear_secret_item = PK11_GetKeyData (secret_key); + ret = g_memdup (clear_secret_item->data, clear_secret_item->len); + *clear_secret_size = clear_secret_item->len; +- PK11_FreeSymKey (secret_key); ++ SECITEM_FreeItem (clear_secret_item, PR_TRUE); + + return ret; + +- err_secret_key: +- PK11_FreeSymKey (secret_key); + err: + return NULL; + } diff --git a/volume_key.spec b/volume_key.spec index 6a50e32..8fc079c 100644 --- a/volume_key.spec +++ b/volume_key.spec @@ -1,7 +1,7 @@ Summary: An utility for manipulating storage encryption keys and passphrases Name: volume_key Version: 0.3.11 -Release: 6%{?dist} +Release: 7%{?dist} # lib/{SECerrs,SSLerrs}.h are both licensed under MPLv1.1, GPLv2 and LGPLv2 License: GPLv2 and (MPLv1.1 or GPLv2 or LGPLv2) Group: Applications/System @@ -17,6 +17,8 @@ Patch0: volume_key-0.3.11-support_LUKS_all.patch Patch1: volume_key-0.3.11-FIPS.patch # Diagnose patch to get more insight on whats wrong Patch2: volume_key-0.3.11-show_get_password_error.patch +# fix getting backup password from secret the FIPS way, RHEL-113242 +Patch3: volume_key-0.3.12-fips2.patch BuildRequires: cryptsetup-luks-devel, gettext-devel, glib2-devel, /usr/bin/gpg2 BuildRequires: gpgme-devel, libblkid-devel, nss-devel, python3-devel # Needed by %%check: @@ -84,9 +86,10 @@ for other formats is possible, some formats are planned for future releases. %prep %setup -q -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 +%patch -P 0 -p1 +%patch -P 1 -p1 +%patch -P 2 -p1 +%patch -P 3 -p1 -b .fips2 %build %configure @@ -135,6 +138,9 @@ rm -rf $RPM_BUILD_ROOT %{python3_sitearch}/__pycache__/volume_key.* %changelog +* Thu Feb 12 2026 Michal Hlavinka - 0.3.11-7 +- make getting password from backed up secret FIPS compatible (RHEL-113242) + * Fri Jul 21 2023 Jiri Kucera - 0.3.11-6 - Make volume_key working in FIPS mode Resolves: #2143223