From b7d11c21d7f15dc11ae7354a7ec97299eacd7045 Mon Sep 17 00:00:00 2001 From: Joerg Schmidbauer Date: Wed, 6 Nov 2024 13:12:11 +0100 Subject: [PATCH] fips update: Dynamically update service indicator based on IV usage Fix handling to differentiate if the call to AES-GCM encryption API was approved or not. If the IV was set externally, it's non-approved, otherwise with internal IV it's approved. Bind the service indicator to the service by checking the behavior of the GCM IV in the gcm API. Signed-off-by: Joerg Schmidbauer --- src/ica_api.c | 6 ++++++ src/include/fips.h | 54 +++++++++++++++++++++++++++++++++++++++++++--- src/s390_crypto.c | 16 ++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/ica_api.c b/src/ica_api.c index d071f61..c1bb4e1 100644 --- a/src/ica_api.c +++ b/src/ica_api.c @@ -3727,6 +3727,8 @@ unsigned int ica_aes_gcm(unsigned char *plaintext, #ifdef ICA_FIPS if (fips & ICA_FIPS_MODE) return EPERM; + if (!fips_approved(AES_GCM) && !fips_override(AES_GCM)) + return EPERM; #endif /* ICA_FIPS */ return ica_aes_gcm_internal(plaintext, plaintext_length, ciphertext, @@ -3776,6 +3778,8 @@ unsigned int ica_aes_gcm_initialize(const unsigned char *iv, if (!ica_external_gcm_iv_in_fips_mode_allowed && direction == ENCRYPT && (fips & ICA_FIPS_MODE)) return EPERM; + if (!fips_approved(AES_GCM) && !fips_override(AES_GCM)) + return EPERM; #endif /* ICA_FIPS */ return ica_aes_gcm_initialize_internal(iv, iv_length, key, key_length, @@ -4025,6 +4029,8 @@ int ica_aes_gcm_kma_init(unsigned int direction, if (!ica_external_gcm_iv_in_fips_mode_allowed && direction == ICA_ENCRYPT && (fips & ICA_FIPS_MODE)) return EPERM; + if (!fips_approved(AES_GCM_KMA) && !fips_override(AES_GCM_KMA)) + return EPERM; #endif /* ICA_FIPS */ return ica_aes_gcm_kma_init_internal(direction, iv, iv_length, diff --git a/src/include/fips.h b/src/include/fips.h index c0af6b6..0a6e0bd 100644 --- a/src/include/fips.h +++ b/src/include/fips.h @@ -68,19 +68,19 @@ unsigned int ica_aes_gcm_initialize_internal(const unsigned char *iv, /* * List of non-fips-approved algorithms */ -static const int FIPS_BLACKLIST[] = {DES_ECB, DES_CBC, DES_CBC_CS, DES_OFB, +static int FIPS_BLACKLIST[] = {DES_ECB, DES_CBC, DES_CBC_CS, DES_OFB, DES_CFB, DES_CTR, DES_CTRLST, DES_CBC_MAC, DES_CMAC, P_RNG, DES3_ECB, DES3_CBC, DES3_CBC_CS, DES3_OFB, DES3_CFB, DES3_CTR, DES3_CTRLST, DES3_CBC_MAC, DES3_CMAC, ED25519_KEYGEN, ED25519_SIGN, ED25519_VERIFY, ED448_KEYGEN, ED448_SIGN, ED448_VERIFY, X25519_KEYGEN, X25519_DERIVE, - X448_KEYGEN, X448_DERIVE, RSA_ME, RSA_CRT, SHA512_DRNG }; + X448_KEYGEN, X448_DERIVE, RSA_ME, RSA_CRT, SHA512_DRNG, -1, -1 }; static const size_t FIPS_BLACKLIST_LEN = sizeof(FIPS_BLACKLIST) / sizeof(FIPS_BLACKLIST[0]); /* * FIPS service indicator: List of tolerated but non-approved algorithms. */ -static const int FIPS_OVERRIDE_LIST[] = { RSA_ME, RSA_CRT, SHA512_DRNG }; +static int FIPS_OVERRIDE_LIST[] = { RSA_ME, RSA_CRT, SHA512_DRNG, -1, -1 }; static const size_t FIPS_OVERRIDE_LIST_LEN = sizeof(FIPS_OVERRIDE_LIST) / sizeof(FIPS_OVERRIDE_LIST[0]); @@ -117,5 +117,53 @@ static inline int fips_override(int id) return 0; } + +static inline void add_to_fips_black_list(int id) +{ + size_t i; + + for (i = 0; i < FIPS_BLACKLIST_LEN; i++) { + if (FIPS_BLACKLIST[i] == -1) { + FIPS_BLACKLIST[i] = id; + return; + } + } +} + +static inline void add_to_fips_override_list(int id) +{ + size_t i; + + for (i = 0; i < FIPS_OVERRIDE_LIST_LEN; i++) { + if (FIPS_OVERRIDE_LIST[i] == -1) { + FIPS_OVERRIDE_LIST[i] = id; + return; + } + } +} + +static inline void remove_from_fips_black_list(int id) +{ + size_t i; + + for (i = 0; i < FIPS_BLACKLIST_LEN; i++) { + if (FIPS_BLACKLIST[i] == id) { + FIPS_BLACKLIST[i] = -1; + return; + } + } +} + +static inline void remove_from_fips_override_list(int id) +{ + size_t i; + + for (i = 0; i < FIPS_OVERRIDE_LIST_LEN; i++) { + if (FIPS_OVERRIDE_LIST[i] == id) { + FIPS_OVERRIDE_LIST[i] = -1; + return; + } + } +} #endif /* FIPS_H */ #endif /* ICA_FIPS */ diff --git a/src/s390_crypto.c b/src/s390_crypto.c index 623864b..03655e7 100644 --- a/src/s390_crypto.c +++ b/src/s390_crypto.c @@ -30,6 +30,10 @@ #include "init.h" #include "s390_crypto.h" +#ifdef ICA_FIPS +extern int ica_external_gcm_iv_in_fips_mode_allowed; +#endif + unsigned long long facility_bits[3]; unsigned int sha1_switch, sha256_switch, sha512_switch, sha3_switch, des_switch, tdes_switch, aes128_switch, aes192_switch, aes256_switch, @@ -810,6 +814,18 @@ int s390_get_fips_indicator(libica_fips_indicator_element *indicator_list, if (*indicator_list_len < (sizeof(icaList) / sizeof(libica_func_list_element_int))) return EINVAL; + if (ica_external_gcm_iv_in_fips_mode_allowed) { + add_to_fips_black_list(AES_GCM); + add_to_fips_override_list(AES_GCM); + add_to_fips_black_list(AES_GCM_KMA); + add_to_fips_override_list(AES_GCM_KMA); + } else { + remove_from_fips_black_list(AES_GCM); + remove_from_fips_override_list(AES_GCM); + remove_from_fips_black_list(AES_GCM_KMA); + remove_from_fips_override_list(AES_GCM_KMA); + } + for (i = 0; i < *indicator_list_len; i++) { indicator_list[i].mech_mode_id = icaList[i].mech_mode_id; indicator_list[i].fips_approved = fips_approved(icaList[i].mech_mode_id);