diff options
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | lib/Makefile.am | 4 | ||||
-rw-r--r-- | lib/fips.c | 146 | ||||
-rw-r--r-- | lib/fips.h | 70 | ||||
-rw-r--r-- | lib/gnutls_cipher_int.c | 5 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 6 | ||||
-rw-r--r-- | lib/gnutls_global.c | 14 | ||||
-rw-r--r-- | lib/gnutls_hash_int.c | 11 | ||||
-rw-r--r-- | lib/gnutls_privkey.c | 3 | ||||
-rw-r--r-- | lib/gnutls_pubkey.c | 3 | ||||
-rw-r--r-- | lib/gnutls_state.c | 3 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 1 | ||||
-rw-r--r-- | lib/pkcs11_privkey.c | 3 | ||||
-rw-r--r-- | lib/random.c | 2 | ||||
-rw-r--r-- | lib/x509/common.h | 1 | ||||
-rw-r--r-- | lib/x509/crl.c | 2 | ||||
-rw-r--r-- | lib/x509/crq.c | 2 | ||||
-rw-r--r-- | lib/x509/privkey.c | 2 | ||||
-rw-r--r-- | lib/x509/verify-high.c | 6 | ||||
-rw-r--r-- | lib/x509/x509.c | 6 | ||||
-rw-r--r-- | lib/xssl.c | 5 |
21 files changed, 301 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac index 8387847ed6..7681b56b79 100644 --- a/configure.ac +++ b/configure.ac @@ -125,6 +125,16 @@ AM_CONDITIONAL(HAVE_GCC, test "$GCC" = "yes") AC_ARG_ENABLE(self-checks, AS_HELP_STRING([--enable-self-checks], [enable self checking functionality]), enable_self_checks=$enableval, enable_self_checks=no) + +AC_ARG_ENABLE(fips140-mode, + AS_HELP_STRING([--enable-fips140-mode], [enable FIPS140-2 mode (implies self checks)]), + enable_fips=$enableval, enable_fips=no) +AM_CONDITIONAL(ENABLE_FIPS140, test "$enable_fips" = "yes") +if [ test "$enable_fips" = "yes" ];then + enable_self_checks=yes + AC_DEFINE([ENABLE_FIPS140], 1, [Enable FIPS140-2 mode]) +fi + AM_CONDITIONAL(ENABLE_SELF_CHECKS, test "$enable_self_checks" = "yes") if [ test "$enable_self_checks" = "yes" ];then AC_DEFINE([ENABLE_SELF_CHECKS], 1, [Self checks are included in the library]) @@ -729,6 +739,7 @@ if features are disabled) RSA-EXPORT compat: $ac_enable_rsa_export Unicode support: $ac_have_unicode Self checks: $enable_self_checks + FIPS140 mode: $enable_fips ]) AC_MSG_NOTICE([Optional applications: diff --git a/lib/Makefile.am b/lib/Makefile.am index 2f5d5e5fea..62deb9b6df 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -78,7 +78,7 @@ COBJECTS = gnutls_range.c gnutls_record.c \ gnutls_rsa_export.c gnutls_helper.c gnutls_supplemental.c \ random.c crypto-api.c gnutls_privkey.c gnutls_pcert.c \ gnutls_pubkey.c locks.c gnutls_dtls.c system_override.c \ - crypto-backend.c verify-tofu.c pin.c tpm.c + crypto-backend.c verify-tofu.c pin.c tpm.c fips.c if ENABLE_SELF_CHECKS COBJECTS += crypto-selftests.c crypto-selftests-pk.c @@ -105,7 +105,7 @@ HFILES = abstract_int.h debug.h gnutls_compress.h gnutls_cipher.h \ gnutls_state.h gnutls_x509.h crypto-backend.h \ gnutls_srp.h auth/srp.h auth/srp_passwd.h \ gnutls_helper.h gnutls_supplemental.h crypto.h random.h system.h\ - locks.h gnutls_mbuffers.h gnutls_ecc.h pin.h + locks.h gnutls_mbuffers.h gnutls_ecc.h pin.h fips.h if ENABLE_PKCS11 HFILES += pkcs11_int.h diff --git a/lib/fips.c b/lib/fips.c new file mode 100644 index 0000000000..726dae632c --- /dev/null +++ b/lib/fips.c @@ -0,0 +1,146 @@ +/* + * 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 <http://www.gnu.org/licenses/> + * + */ + +#ifdef ENABLE_FIPS140 + +# include <gnutls_int.h> +# include <gnutls/gnutls.h> +# include <unistd.h> + +unsigned int _gnutls_fips_mode = STATE_POWERON; + +unsigned _gnutls_fips_mode_enabled(void) +{ + /* FIXME: There are some subtle differences here. Check it out later */ + if (access("/proc/sys/crypto/fips_enabled", R_OK) == 0 && + access("/etc/system-fips", R_OK) == 0) + return 1; + + return 0; +} + +int _gnutls_fips_perform_self_checks(void) +{ + _gnutls_switch_fips_state(FIPS_STATE_SELFTEST); + + /* Tests the FIPS algorithms */ + + /* ciphers */ + ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_CBC); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_192_CBC); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CBC); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_3DES_CBC); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_GCM); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_GCM); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + /* MAC (includes message digest test) */ + ret = gnutls_mac_self_test(0, GNUTLS_MAC_MD5); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA224); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA256); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA384); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA512); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + /* PK */ + ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + ret = gnutls_pk_self_test(0, GNUTLS_PK_ECDSA); + if (ret < 0) { + gnutls_assert(); + goto error; + } + + return 0; +error: + _gnutls_switch_fips_state(FIPS_STATE_ERROR); + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERR); +} + +#endif diff --git a/lib/fips.h b/lib/fips.h new file mode 100644 index 0000000000..9cd17a40c0 --- /dev/null +++ b/lib/fips.h @@ -0,0 +1,70 @@ +/* + * 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 <http://www.gnu.org/licenses/> + * + */ + +#ifndef FIPS_H +# define FIPS_H + +#include <gnutls/gnutls.h> + +typedef enum { + FIPS_STATE_POWERON, + FIPS_STATE_INIT, + FIPS_STATE_SELFTEST, + FIPS_STATE_OPERATIONAL, + FIPS_STATE_ERROR, + FIPS_STATE_SHUTDOWN +} gnutls_fips_state_t; + +#ifdef ENABLE_FIPS140 + +/* do not access directly */ +extern unsigned int _gnutls_fips_mode; + +inline static +void _gnutls_switch_fips_state(gnutls_fips_state_t state) +{ + _gnutls_fips_mode = state; +} + +inline static gnutls_fips_state_t _gnutls_get_fips_state(void) +{ + return _gnutls_fips_mode; +} + +int _gnutls_fips_perform_self_checks(void); +unsigned _gnutls_fips_mode_enabled(void); + +# define FAIL_IF_FIPS_ERROR \ + if (_gnutls_get_fips_state() != FIPS_STATE_OPERATIONAL) return GNUTLS_E_LIB_IN_ERROR_STATE + +void _gnutls_switch_fips_state(gnutls_fips_state_t state); + +#else + +# define _gnutls_switch_fips_state(x) 0 +# define _gnutls_get_fips_state() STATE_OPERATIONAL +# define FAIL_IF_FIPS_ERROR 0 +# define _gnutls_fips_perform_self_checks() 0 +# define _gnutls_fips_mode_enabled() 0 +#endif + +#endif /* FIPS_H */ diff --git a/lib/gnutls_cipher_int.c b/lib/gnutls_cipher_int.c index d6483ab2d8..184156725e 100644 --- a/lib/gnutls_cipher_int.c +++ b/lib/gnutls_cipher_int.c @@ -27,6 +27,7 @@ #include <gnutls_datum.h> #include <gnutls/crypto.h> #include <crypto.h> +#include <fips.h> #include <algorithms.h> #define SR(x, cleanup) if ( (x)<0 ) { \ @@ -61,6 +62,8 @@ _gnutls_cipher_init(cipher_hd_st * handle, const cipher_entry_st * e, if (unlikely(e == NULL || e->id == GNUTLS_CIPHER_NULL)) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + + FAIL_IF_FIPS_ERROR; handle->e = e; @@ -144,6 +147,8 @@ int _gnutls_auth_cipher_init(auth_cipher_hd_st * handle, if (unlikely(e == NULL)) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); + FAIL_IF_FIPS_ERROR; + memset(handle, 0, sizeof(*handle)); if (e->id != GNUTLS_CIPHER_NULL) { diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 3c932859fa..2c46552799 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -396,6 +396,12 @@ static const gnutls_error_entry error_algorithms[] = { ERROR_ENTRY(N_ ("No common application protocol could be negotiated."), GNUTLS_E_NO_APPLICATION_PROTOCOL, 1), + ERROR_ENTRY(N_("Error while performing self checks."), + GNUTLS_E_SELF_TEST_ERROR, 1), + ERROR_ENTRY(N_("There is no self test for this algorithm."), + GNUTLS_E_NO_SELF_TEST, 1), + ERROR_ENTRY(N_("An error has been detected in the library and cannot continue operations."), + GNUTLS_E_LIB_IN_ERROR_STATE, 1), {NULL, NULL, 0, 0} }; diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 6dbc534dc0..12912f73d9 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -32,6 +32,7 @@ #include <system.h> #include <accelerated/cryptodev.h> #include <accelerated/accelerated.h> +#include <fips.h> #include "sockets.h" #include "gettext.h" @@ -201,6 +202,8 @@ int gnutls_global_init(void) if (_gnutls_init++) goto out; + + _gnutls_switch_fips_state(FIPS_STATE_INIT); e = getenv("GNUTLS_DEBUG_LEVEL"); if (e != NULL) { @@ -279,8 +282,17 @@ int gnutls_global_init(void) #endif _gnutls_cryptodev_init(); + + if (_gnutls_fips_mode_enabled()) { + result = _gnutls_fips_perform_self_checks(); + if (result < 0) { + gnutls_assert(); + goto out; + } + _gnutls_switch_fips_state(FIPS_STATE_OPERATIONAL); + } - out: +out: return result; } diff --git a/lib/gnutls_hash_int.c b/lib/gnutls_hash_int.c index 7f16a54d3e..ddeff10bdb 100644 --- a/lib/gnutls_hash_int.c +++ b/lib/gnutls_hash_int.c @@ -28,12 +28,15 @@ #include <gnutls_hash_int.h> #include <gnutls_errors.h> #include <algorithms.h> +#include <fips.h> int _gnutls_hash_init(digest_hd_st * dig, const mac_entry_st * e) { int result; const gnutls_crypto_digest_st *cc = NULL; + FAIL_IF_FIPS_ERROR; + dig->e = e; /* check if a digest has been registered @@ -84,6 +87,8 @@ _gnutls_hash_fast(gnutls_digest_algorithm_t algorithm, { int ret; const gnutls_crypto_digest_st *cc = NULL; + + FAIL_IF_FIPS_ERROR; /* check if a digest has been registered */ @@ -117,6 +122,8 @@ _gnutls_mac_fast(gnutls_mac_algorithm_t algorithm, const void *key, int ret; const gnutls_crypto_mac_st *cc = NULL; + FAIL_IF_FIPS_ERROR; + /* check if a digest has been registered */ cc = _gnutls_get_crypto_mac(algorithm); @@ -164,6 +171,8 @@ _gnutls_mac_init(mac_hd_st * mac, const mac_entry_st * e, int result; const gnutls_crypto_mac_st *cc = NULL; + FAIL_IF_FIPS_ERROR; + mac->e = e; mac->mac_len = _gnutls_mac_get_algo_len(e); @@ -245,6 +254,8 @@ _gnutls_mac_init_ssl3(digest_hd_st * ret, const mac_entry_st * e, uint8_t ipad[48]; int padsize, result; + FAIL_IF_FIPS_ERROR; + padsize = get_padsize((gnutls_digest_algorithm_t) e->id); if (padsize == 0) { gnutls_assert(); diff --git a/lib/gnutls_privkey.c b/lib/gnutls_privkey.c index 48afb06604..81507fa7f9 100644 --- a/lib/gnutls_privkey.c +++ b/lib/gnutls_privkey.c @@ -33,6 +33,7 @@ #include <openpgp/gnutls_openpgp.h> #include <gnutls_sig.h> #include <algorithms.h> +#include <fips.h> #include <abstract_int.h> /** @@ -237,6 +238,8 @@ _gnutls_privkey_get_public_mpis(gnutls_privkey_t key, **/ int gnutls_privkey_init(gnutls_privkey_t * key) { + FAIL_IF_FIPS_ERROR; + *key = gnutls_calloc(1, sizeof(struct gnutls_privkey_st)); if (*key == NULL) { gnutls_assert(); diff --git a/lib/gnutls_pubkey.c b/lib/gnutls_pubkey.c index d8979f77c0..21826b866d 100644 --- a/lib/gnutls_pubkey.c +++ b/lib/gnutls_pubkey.c @@ -34,6 +34,7 @@ #include <x509/common.h> #include <x509_b64.h> #include <abstract_int.h> +#include <fips.h> #include <gnutls_ecc.h> @@ -110,6 +111,8 @@ int gnutls_pubkey_get_key_usage(gnutls_pubkey_t key, unsigned int *usage) **/ int gnutls_pubkey_init(gnutls_pubkey_t * key) { + FAIL_IF_FIPS_ERROR; + *key = gnutls_calloc(1, sizeof(struct gnutls_pubkey_st)); if (*key == NULL) { gnutls_assert(); diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 231e6b0b64..21a8f99cee 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -45,6 +45,7 @@ #include <gnutls_extensions.h> #include <system.h> #include <random.h> +#include <fips.h> #include <gnutls/dtls.h> /* These should really be static, but src/tests.c calls them. Make @@ -307,6 +308,8 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags) { int ret; record_parameters_st *epoch; + + FAIL_IF_FIPS_ERROR; *session = gnutls_calloc(1, sizeof(struct gnutls_session_int)); if (*session == NULL) diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 742f44f008..541fda6d53 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2288,6 +2288,7 @@ int gnutls_pk_self_test(unsigned all, gnutls_pk_algorithm_t pk); #define GNUTLS_E_SELF_TEST_ERROR -400 #define GNUTLS_E_NO_SELF_TEST -401 +#define GNUTLS_E_LIB_IN_ERROR_STATE -402 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c index 7a0aa38912..d24f6a3dee 100644 --- a/lib/pkcs11_privkey.c +++ b/lib/pkcs11_privkey.c @@ -27,6 +27,7 @@ #include <pkcs11_int.h> #include <gnutls_sig.h> #include <gnutls_pk.h> +#include <fips.h> #include <p11-kit/uri.h> struct gnutls_pkcs11_privkey_st { @@ -51,6 +52,8 @@ struct gnutls_pkcs11_privkey_st { **/ int gnutls_pkcs11_privkey_init(gnutls_pkcs11_privkey_t * key) { + FAIL_IF_FIPS_ERROR; + *key = gnutls_calloc(1, sizeof(struct gnutls_pkcs11_privkey_st)); if (*key == NULL) { gnutls_assert(); diff --git a/lib/random.c b/lib/random.c index 62fa785232..b5f6cd94f9 100644 --- a/lib/random.c +++ b/lib/random.c @@ -26,6 +26,7 @@ #include <gnutls_int.h> #include <gnutls_errors.h> #include <random.h> +#include <fips.h> void *gnutls_rnd_ctx; @@ -65,6 +66,7 @@ void _gnutls_rnd_deinit(void) **/ int gnutls_rnd(gnutls_rnd_level_t level, void *data, size_t len) { + FAIL_IF_FIPS_ERROR; return _gnutls_rnd(level, data, len); } diff --git a/lib/x509/common.h b/lib/x509/common.h index 7ad55c2da7..8bc51d1ee0 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -26,6 +26,7 @@ #include <algorithms.h> #include <abstract_int.h> #include <x509/x509_int.h> +#include <fips.h> #define MAX_STRING_LEN 512 diff --git a/lib/x509/crl.c b/lib/x509/crl.c index bd2560dc78..480074ec39 100644 --- a/lib/x509/crl.c +++ b/lib/x509/crl.c @@ -46,6 +46,8 @@ **/ int gnutls_x509_crl_init(gnutls_x509_crl_t * crl) { + FAIL_IF_FIPS_ERROR; + *crl = gnutls_calloc(1, sizeof(gnutls_x509_crl_int)); if (*crl) { diff --git a/lib/x509/crq.c b/lib/x509/crq.c index 4e28fedd7c..67f425a4a4 100644 --- a/lib/x509/crq.c +++ b/lib/x509/crq.c @@ -49,6 +49,8 @@ int gnutls_x509_crq_init(gnutls_x509_crq_t * crq) { int result; + + FAIL_IF_FIPS_ERROR; *crq = gnutls_calloc(1, sizeof(gnutls_x509_crq_int)); if (!*crq) diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c index 1a779772bc..0c94ac52b4 100644 --- a/lib/x509/privkey.c +++ b/lib/x509/privkey.c @@ -44,6 +44,8 @@ **/ int gnutls_x509_privkey_init(gnutls_x509_privkey_t * key) { + FAIL_IF_FIPS_ERROR; + *key = gnutls_calloc(1, sizeof(gnutls_x509_privkey_int)); if (*key) { diff --git a/lib/x509/verify-high.c b/lib/x509/verify-high.c index 72e6656519..28f89edeeb 100644 --- a/lib/x509/verify-high.c +++ b/lib/x509/verify-high.c @@ -75,7 +75,11 @@ int gnutls_x509_trust_list_init(gnutls_x509_trust_list_t * list, unsigned int size) { - gnutls_x509_trust_list_t tmp = + gnutls_x509_trust_list_t tmp; + + FAIL_IF_FIPS_ERROR; + + tmp = gnutls_calloc(1, sizeof(struct gnutls_x509_trust_list_st)); if (!tmp) diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 9bc677d74d..0bc8617581 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -44,7 +44,11 @@ **/ int gnutls_x509_crt_init(gnutls_x509_crt_t * cert) { - gnutls_x509_crt_t tmp = + gnutls_x509_crt_t tmp; + + FAIL_IF_FIPS_ERROR; + + tmp = gnutls_calloc(1, sizeof(gnutls_x509_crt_int)); int result; diff --git a/lib/xssl.c b/lib/xssl.c index 7b9e198d94..11780ee85f 100644 --- a/lib/xssl.c +++ b/lib/xssl.c @@ -25,6 +25,7 @@ #include <gnutls_num.h> #include <gnutls/xssl.h> #include <auth/cert.h> +#include <fips.h> #include "vasprintf.h" #include <xssl.h> @@ -301,6 +302,8 @@ int xssl_cred_init(xssl_cred_t * c, unsigned vflags, int xssl_sinit(xssl_t * isb, gnutls_session_t session, unsigned int flags) { struct xssl_st *sb; + + FAIL_IF_FIPS_ERROR; sb = gnutls_calloc(1, sizeof(*sb)); if (sb == NULL) @@ -347,6 +350,8 @@ int xssl_client_init(xssl_t * isb, const char *hostname, gnutls_session_t session; int ret; unsigned len; + + FAIL_IF_FIPS_ERROR; ret = gnutls_init(&session, GNUTLS_CLIENT); if (ret < 0) |