Blame SOURCES/bz1484264-3-totemcrypto-Use-different-method-to-import-key.patch

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