--- corosync-2.4.2.orig/exec/totemcrypto.c 2016-11-08 00:39:12.000000000 +0800 +++ corosync-2.4.2/exec/totemcrypto.c 2017-07-12 11:09:43.693227825 +0800 @@ -206,6 +206,13 @@ (const char *)format, ##args); \ } while (0); +enum sym_key_type { + SYM_KEY_TYPE_CRYPT, + SYM_KEY_TYPE_HASH +}; + +#define MAX_WRAPPED_KEY_LEN 128 + /* * crypt/decrypt functions */ @@ -226,38 +233,147 @@ return CRYPTO_CIPHER_TYPE_AES256; } -static int init_nss_crypto(struct crypto_instance *instance) +static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum sym_key_type key_type) { - PK11SlotInfo* crypt_slot = NULL; - SECItem crypt_param; + SECItem key_item; + PK11SlotInfo *slot; + 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; + + switch (key_type) { + case SYM_KEY_TYPE_CRYPT: + key_item.len = cipher_key_len[instance->crypto_cipher_type]; + cipher = cipher_to_nss[instance->crypto_cipher_type]; + operation = CKA_ENCRYPT|CKA_DECRYPT; + break; + case SYM_KEY_TYPE_HASH: + key_item.len = instance->private_key_len; + cipher = hash_to_nss[instance->crypto_hash_type]; + operation = CKA_SIGN; + break; + } + + slot = PK11_GetBestSlot(cipher, NULL); + 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)); + goto exit_res_key; + } - if (!cipher_to_nss[instance->crypto_cipher_type]) { - return 0; + /* + * 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; } - crypt_param.type = siBuffer; - crypt_param.data = instance->private_key; - crypt_param.len = cipher_key_len[instance->crypto_cipher_type]; + /* + * Encrypt authkey with wrapping key + */ - crypt_slot = PK11_GetBestSlot(cipher_to_nss[instance->crypto_cipher_type], NULL); - if (crypt_slot == NULL) { - log_printf(instance->log_level_security, "Unable to find security slot (err %d)", - PR_GetError()); - return -1; + /* + * 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; + } + + 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; } - instance->nss_sym_key = PK11_ImportSymKey(crypt_slot, - cipher_to_nss[instance->crypto_cipher_type], - PK11_OriginUnwrap, CKA_ENCRYPT|CKA_DECRYPT, - &crypt_param, NULL); + /* + * 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_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); + } + + if (slot != NULL) { + PK11_FreeSlot(slot); + } + + return (res_key); +} + +static int init_nss_crypto(struct crypto_instance *instance) +{ + + if (!cipher_to_nss[instance->crypto_cipher_type]) { + return 0; + } + + instance->nss_sym_key = import_symmetric_key(instance, SYM_KEY_TYPE_CRYPT); if (instance->nss_sym_key == NULL) { - log_printf(instance->log_level_security, "Failure to import key into NSS (err %d)", - PR_GetError()); return -1; } - PK11_FreeSlot(crypt_slot); - return 0; } @@ -312,9 +428,9 @@ 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; } @@ -447,36 +563,16 @@ static int init_nss_hash(struct crypto_instance *instance) { - PK11SlotInfo* hash_slot = NULL; - SECItem hash_param; if (!hash_to_nss[instance->crypto_hash_type]) { return 0; } - hash_param.type = siBuffer; - hash_param.data = instance->private_key; - hash_param.len = instance->private_key_len; - - hash_slot = PK11_GetBestSlot(hash_to_nss[instance->crypto_hash_type], NULL); - if (hash_slot == NULL) { - log_printf(instance->log_level_security, "Unable to find security slot (err %d)", - PR_GetError()); - return -1; - } - - instance->nss_sym_key_sign = PK11_ImportSymKey(hash_slot, - hash_to_nss[instance->crypto_hash_type], - PK11_OriginUnwrap, CKA_SIGN, - &hash_param, NULL); + instance->nss_sym_key_sign = import_symmetric_key(instance, SYM_KEY_TYPE_HASH); if (instance->nss_sym_key_sign == NULL) { - log_printf(instance->log_level_security, "Failure to import key into NSS (err %d)", - PR_GetError()); return -1; } - PK11_FreeSlot(hash_slot); - return 0; }