diff options
Diffstat (limited to 'lib/fips.h')
-rw-r--r-- | lib/fips.h | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/lib/fips.h b/lib/fips.h new file mode 100644 index 0000000..3a74f25 --- /dev/null +++ b/lib/fips.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2013 Red Hat + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/> + * + */ + +#ifndef GNUTLS_LIB_FIPS_H +#define GNUTLS_LIB_FIPS_H + +#include "gnutls_int.h" +#include <gnutls/gnutls.h> + +#define FIPS140_RND_KEY_SIZE 32 + +typedef enum { + LIB_STATE_POWERON, + LIB_STATE_INIT, + LIB_STATE_SELFTEST, + LIB_STATE_OPERATIONAL, + LIB_STATE_ERROR, + LIB_STATE_SHUTDOWN +} gnutls_lib_state_t; + +/* do not access directly */ +extern unsigned int _gnutls_lib_state; +extern gnutls_crypto_rnd_st _gnutls_fips_rnd_ops; + +void _gnutls_switch_fips_state(gnutls_fips140_operation_state_t state); + +inline static +void _gnutls_switch_lib_state(gnutls_lib_state_t state) +{ + /* Once into zombie state no errors can change us */ + _gnutls_lib_state = state; +} + +inline static gnutls_lib_state_t _gnutls_get_lib_state(void) +{ + return _gnutls_lib_state; +} + +int _gnutls_fips_perform_self_checks1(void); +int _gnutls_fips_perform_self_checks2(void); +void _gnutls_fips_mode_reset_zombie(void); + +#ifdef ENABLE_FIPS140 +unsigned _gnutls_fips_mode_enabled(void); +#else +# define _gnutls_fips_mode_enabled() 0 +#endif + +# define HAVE_LIB_ERROR() unlikely(_gnutls_get_lib_state() != LIB_STATE_OPERATIONAL && _gnutls_get_lib_state() != LIB_STATE_SELFTEST) + +# define FAIL_IF_LIB_ERROR \ + if (HAVE_LIB_ERROR()) return GNUTLS_E_LIB_IN_ERROR_STATE + +void _gnutls_switch_lib_state(gnutls_lib_state_t state); + +void _gnutls_lib_simulate_error(void); +void _gnutls_lib_force_operational(void); + +inline static bool +is_mac_algo_approved_in_fips(gnutls_mac_algorithm_t algo) +{ + switch (algo) { + case GNUTLS_MAC_SHA1: + case GNUTLS_MAC_SHA256: + case GNUTLS_MAC_SHA384: + case GNUTLS_MAC_SHA512: + case GNUTLS_MAC_SHA224: + case GNUTLS_MAC_SHA3_224: + case GNUTLS_MAC_SHA3_256: + case GNUTLS_MAC_SHA3_384: + case GNUTLS_MAC_SHA3_512: + case GNUTLS_MAC_AES_CMAC_128: + case GNUTLS_MAC_AES_CMAC_256: + case GNUTLS_MAC_AES_GMAC_128: + case GNUTLS_MAC_AES_GMAC_192: + case GNUTLS_MAC_AES_GMAC_256: + return true; + default: + return false; + } +} + +inline static bool +is_mac_algo_allowed_in_fips(gnutls_mac_algorithm_t algo) +{ + return is_mac_algo_approved_in_fips(algo); +} + +inline static bool +is_cipher_algo_approved_in_fips(gnutls_cipher_algorithm_t algo) +{ + switch (algo) { + case GNUTLS_CIPHER_AES_128_CBC: + case GNUTLS_CIPHER_AES_256_CBC: + case GNUTLS_CIPHER_AES_192_CBC: + case GNUTLS_CIPHER_AES_128_CCM: + case GNUTLS_CIPHER_AES_256_CCM: + case GNUTLS_CIPHER_AES_128_CCM_8: + case GNUTLS_CIPHER_AES_256_CCM_8: + case GNUTLS_CIPHER_AES_128_CFB8: + case GNUTLS_CIPHER_AES_192_CFB8: + case GNUTLS_CIPHER_AES_256_CFB8: + case GNUTLS_CIPHER_AES_128_XTS: + case GNUTLS_CIPHER_AES_256_XTS: + return true; + default: + return false; + } +} + +inline static bool +is_cipher_algo_allowed_in_fips(gnutls_cipher_algorithm_t algo) +{ + if (is_cipher_algo_approved_in_fips(algo)) { + return true; + } + + /* GCM is only approved in TLS */ + switch (algo) { + case GNUTLS_CIPHER_AES_128_GCM: + case GNUTLS_CIPHER_AES_192_GCM: + case GNUTLS_CIPHER_AES_256_GCM: + return true; + default: + return false; + } +} + +#ifdef ENABLE_FIPS140 +/* This will test the condition when in FIPS140-2 mode + * and return an error if necessary or ignore */ +# define FIPS_RULE(condition, ret_error, ...) { \ + gnutls_fips_mode_t _mode = _gnutls_fips_mode_enabled(); \ + if (_mode != GNUTLS_FIPS140_DISABLED) { \ + if (condition) { \ + if (_mode == GNUTLS_FIPS140_LOG) { \ + _gnutls_audit_log(NULL, "fips140-2: allowing "__VA_ARGS__); \ + } else if (_mode != GNUTLS_FIPS140_LAX) { \ + _gnutls_debug_log("fips140-2: disallowing "__VA_ARGS__); \ + return ret_error; \ + } \ + } \ + }} + +inline static bool +is_mac_algo_allowed(gnutls_mac_algorithm_t algo) +{ + gnutls_fips_mode_t mode = _gnutls_fips_mode_enabled(); + if (_gnutls_get_lib_state() != LIB_STATE_SELFTEST && + !is_mac_algo_allowed_in_fips(algo)) { + switch (mode) { + case GNUTLS_FIPS140_LOG: + _gnutls_audit_log(NULL, + "fips140-2: allowing access to %s\n", + gnutls_mac_get_name(algo)); + FALLTHROUGH; + case GNUTLS_FIPS140_DISABLED: + case GNUTLS_FIPS140_LAX: + return true; + default: + return false; + } + } + + return true; +} + +inline static bool +is_cipher_algo_allowed(gnutls_cipher_algorithm_t algo) +{ + gnutls_fips_mode_t mode = _gnutls_fips_mode_enabled(); + if (_gnutls_get_lib_state() != LIB_STATE_SELFTEST && + !is_cipher_algo_allowed_in_fips(algo)) { + switch (mode) { + case GNUTLS_FIPS140_LOG: + _gnutls_audit_log(NULL, "fips140-2: allowing access to %s\n", + gnutls_cipher_get_name(algo)); + FALLTHROUGH; + case GNUTLS_FIPS140_DISABLED: + case GNUTLS_FIPS140_LAX: + return true; + default: + return false; + } + } + + return true; +} +#else +# define is_mac_algo_allowed(x) true +# define is_cipher_algo_allowed(x) true +# define FIPS_RULE(condition, ret_error, ...) +#endif + +#endif /* GNUTLS_LIB_FIPS_H */ |