From 5dadebd21862074deaeb9a337fc9e49f5e9f692a Mon Sep 17 00:00:00 2001 From: Jan Friesse Date: Tue, 20 Jun 2017 17:37:57 +0200 Subject: [PATCH] totemcrypto: Use different method to import key PK11_ImportSymKey doesn't work when FIPS is enabled because NSS is targeting to FIPS Level 2 where loading of unencrypted symmetric key is prohibited. FIPS Level 2 is hard to achieve without breaking compatibility so patch implements "workaround" to make NSS behave like FIPS Level 1 (where is allowed to load unencrypted symmetric key). Workaround is about using temporal key to encrypt corosync authkey in memory and then to unwrap it into valid NSS key. Signed-off-by: Jan Friesse Reviewed-by: Fabio M. Di Nitto Reviewed-by: Christine Caulfield --- exec/totemcrypto.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 91 insertions(+), 7 deletions(-) diff --git a/exec/totemcrypto.c b/exec/totemcrypto.c index 0e98f27..79c4312 100644 --- a/exec/totemcrypto.c +++ b/exec/totemcrypto.c @@ -211,6 +211,8 @@ enum sym_key_type { SYM_KEY_TYPE_HASH }; +#define MAX_WRAPPED_KEY_LEN 128 + /* * crypt/decrypt functions */ @@ -238,9 +240,20 @@ static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum s PK11SymKey *res_key; CK_MECHANISM_TYPE cipher; CK_ATTRIBUTE_TYPE operation; + CK_MECHANISM_TYPE wrap_mechanism; + int wrap_key_len; + PK11SymKey *wrap_key; + PK11Context *wrap_key_crypt_context; + SECItem tmp_sec_item; + SECItem wrapped_key; + int wrapped_key_len; + unsigned char wrapped_key_data[MAX_WRAPPED_KEY_LEN]; memset(&key_item, 0, sizeof(key_item)); slot = NULL; + wrap_key = NULL; + res_key = NULL; + wrap_key_crypt_context = NULL; key_item.type = siBuffer; key_item.data = instance->private_key; @@ -262,18 +275,89 @@ static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum s if (slot == NULL) { log_printf(instance->log_level_security, "Unable to find security slot (%d): %s", PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); - return (NULL); + goto exit_res_key; + } + + /* + * Without FIPS it would be possible to just use + * res_key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, operation, &key_item, NULL); + * with FIPS NSS Level 2 certification has to be "workarounded" (so it becomes Level 1) by using + * following method: + * 1. Generate wrap key + * 2. Encrypt authkey with wrap key + * 3. Unwrap encrypted authkey using wrap key + */ + + /* + * Generate wrapping key + */ + wrap_mechanism = PK11_GetBestWrapMechanism(slot); + wrap_key_len = PK11_GetBestKeyLength(slot, wrap_mechanism); + wrap_key = PK11_KeyGen(slot, wrap_mechanism, NULL, wrap_key_len, NULL); + if (wrap_key == NULL) { + log_printf(instance->log_level_security, "Unable to generate wrapping key (%d): %s", + PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); + goto exit_res_key; + } + + /* + * Encrypt authkey with wrapping key + */ + + /* + * Initialization of IV is not needed because PK11_GetBestWrapMechanism should return ECB mode + */ + memset(&tmp_sec_item, 0, sizeof(tmp_sec_item)); + wrap_key_crypt_context = PK11_CreateContextBySymKey(wrap_mechanism, CKA_ENCRYPT, + wrap_key, &tmp_sec_item); + if (wrap_key_crypt_context == NULL) { + log_printf(instance->log_level_security, "Unable to create encrypt context (%d): %s", + PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); + goto exit_res_key; } - res_key = PK11_ImportSymKey(slot, cipher, PK11_OriginUnwrap, operation, &key_item, NULL); + wrapped_key_len = (int)sizeof(wrapped_key_data); + + if (PK11_CipherOp(wrap_key_crypt_context, wrapped_key_data, &wrapped_key_len, + sizeof(wrapped_key_data), key_item.data, key_item.len) != SECSuccess) { + log_printf(instance->log_level_security, "Unable to encrypt authkey (%d): %s", + PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); + goto exit_res_key; + } + + if (PK11_Finalize(wrap_key_crypt_context) != SECSuccess) { + log_printf(instance->log_level_security, "Unable to finalize encryption of authkey (%d): %s", + PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); + goto exit_res_key; + } + + /* + * Finally unwrap sym key + */ + memset(&tmp_sec_item, 0, sizeof(tmp_sec_item)); + wrapped_key.data = wrapped_key_data; + wrapped_key.len = wrapped_key_len; + + res_key = PK11_UnwrapSymKey(wrap_key, wrap_mechanism, &tmp_sec_item, &wrapped_key, + cipher, operation, key_item.len); if (res_key == NULL) { log_printf(instance->log_level_security, "Failure to import key into NSS (%d): %s", PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); - goto exit_err; + goto exit_res_key; + } + +exit_res_key: + if (wrap_key_crypt_context != NULL) { + PK11_DestroyContext(wrap_key_crypt_context, PR_TRUE); + } + + if (wrap_key != NULL) { + PK11_FreeSymKey(wrap_key); } -exit_err: - PK11_FreeSlot(slot); + if (slot != NULL) { + PK11_FreeSlot(slot); + } return (res_key); } @@ -344,9 +428,9 @@ static int encrypt_nss( nss_sec_param); if (!crypt_context) { log_printf(instance->log_level_security, - "PK11_CreateContext failed (encrypt) crypt_type=%d (err %d)", + "PK11_CreateContext failed (encrypt) crypt_type=%d (%d): %s", (int)cipher_to_nss[instance->crypto_cipher_type], - PR_GetError()); + PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); goto out; } -- 1.7.1