|
|
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 |
|