From 0f8af4f83efde3c8d448ed4bd8ae0879e2112607 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 11 Nov 2013 18:07:17 +0100 Subject: Added support for fips states. This implies that when in FIPS mode and the library is not in operational state (i.e., all self checks succeeded), crypto functionality of the library will fail. This includes: * API functions of gnutls/crypto.h * API functions of gnutls/abstract.h * API functions of gnutls/x509.h * gnutls_init() * API functions of gnutls/xssl.h --- lib/gnutls_global.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'lib/gnutls_global.c') 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 #include #include +#include #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; } -- cgit v1.2.1 From e63f26e13cafef026d349841c4f17d02bb497414 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 22 Nov 2013 14:33:23 +0100 Subject: Better handling of FIPS140-2 initialization --- lib/gnutls_global.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib/gnutls_global.c') diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 12912f73d9..8c8bef8db8 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -282,12 +282,17 @@ int gnutls_global_init(void) #endif _gnutls_cryptodev_init(); - - if (_gnutls_fips_mode_enabled()) { + + result = _gnutls_fips_mode_enabled(); + if (result != 0) { result = _gnutls_fips_perform_self_checks(); - if (result < 0) { - gnutls_assert(); - goto out; + if (_gnutls_get_fips_state() != FIPS_STATE_ZOMBIE) { + if (result < 0) { + gnutls_assert(); + goto out; + } + } else { + result = 0; } _gnutls_switch_fips_state(FIPS_STATE_OPERATIONAL); } -- cgit v1.2.1 From 7ea57bef06f96546a2c61b0463c401813d39c0e8 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Fri, 22 Nov 2013 16:25:47 +0100 Subject: Added gnutls_global_init2(). This allows initializing gnutls in a constructor in FIPS140 mode --- lib/gnutls_global.c | 253 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 171 insertions(+), 82 deletions(-) (limited to 'lib/gnutls_global.c') diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 8c8bef8db8..57bd116f53 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001-2012 Free Software Foundation, Inc. + * Copyright (C) 2001-2013 Free Software Foundation, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -111,7 +111,7 @@ void gnutls_global_set_time_function(gnutls_time_func time_func) /** * gnutls_global_set_log_level: - * @level: it's an integer from 0 to 9. + * @level: it's an integer from 0 to 99. * * This is the function that allows you to set the log level. The * level is an integer between 0 and 9. Higher values mean more @@ -167,9 +167,14 @@ gnutls_global_set_mem_functions(gnutls_alloc_function alloc_func, } static int _gnutls_init = 0; +static unsigned int loaded_modules = 0; + +#define GLOBAL_INIT_ALL (GNUTLS_GLOBAL_INIT_MINIMAL|GNUTLS_GLOBAL_INIT_PKCS11|GNUTLS_GLOBAL_INIT_CRYPTO) /** - * gnutls_global_init: + * gnutls_global_init2: + * + * @flags: it's a %GNUTLS_GLOBAL_* flag * * This function performs any required precalculations, detects * the supported CPU capabilities and initializes the underlying @@ -194,113 +199,188 @@ static int _gnutls_init = 0; * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ -int gnutls_global_init(void) +int gnutls_global_init2(unsigned int flags) { int result = 0; int res, level; const char* e; - if (_gnutls_init++) - goto out; + _gnutls_init++; - _gnutls_switch_fips_state(FIPS_STATE_INIT); - - e = getenv("GNUTLS_DEBUG_LEVEL"); - if (e != NULL) { - level = atoi(e); - gnutls_global_set_log_level(level); - if (_gnutls_log_func == NULL) - gnutls_global_set_log_function(default_log_func); - _gnutls_debug_log("Enabled GnuTLS logging...\n"); + /* rationalize flags */ + if (flags == GNUTLS_GLOBAL_INIT_ALL) + flags = GLOBAL_INIT_ALL; + + flags &= ~loaded_modules; + + if (flags == 0) { /* The requested were already loaded */ + return 0; + } + + if (!(flags & GNUTLS_GLOBAL_INIT_MINIMAL) && + !(loaded_modules & GNUTLS_GLOBAL_INIT_MINIMAL)) { + /* Must always initialize the minimal before everything else */ + _gnutls_init--; + return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } - if (gl_sockets_startup(SOCKETS_1_1)) - return gnutls_assert_val(GNUTLS_E_FILE_ERROR); + loaded_modules |= flags; - bindtextdomain(PACKAGE, LOCALEDIR); + if (flags & GNUTLS_GLOBAL_INIT_MINIMAL) { + _gnutls_switch_fips_state(FIPS_STATE_INIT); - res = gnutls_crypto_init(); - if (res != 0) { - gnutls_assert(); - return GNUTLS_E_CRYPTO_INIT_FAILED; - } + e = getenv("GNUTLS_DEBUG_LEVEL"); + if (e != NULL) { + level = atoi(e); + gnutls_global_set_log_level(level); + if (_gnutls_log_func == NULL) + gnutls_global_set_log_function(default_log_func); + _gnutls_debug_log("Enabled GnuTLS logging...\n"); + } - _gnutls_register_accel_crypto(); + if (gl_sockets_startup(SOCKETS_1_1)) + return gnutls_assert_val(GNUTLS_E_SOCKETS_INIT_ERROR); - /* initialize ASN.1 parser - * This should not deal with files in the final - * version. - */ - if (asn1_check_version(GNUTLS_MIN_LIBTASN1_VERSION) == NULL) { - gnutls_assert(); - _gnutls_debug_log - ("Checking for libtasn1 failed: %s < %s\n", - asn1_check_version(NULL), - GNUTLS_MIN_LIBTASN1_VERSION); - return GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY; - } + bindtextdomain(PACKAGE, LOCALEDIR); - res = asn1_array2tree(pkix_asn1_tab, &_gnutls_pkix1_asn, NULL); - if (res != ASN1_SUCCESS) { - result = _gnutls_asn2err(res); - goto out; - } + res = gnutls_crypto_init(); + if (res != 0) { + gnutls_assert(); + return GNUTLS_E_CRYPTO_INIT_FAILED; + } - res = asn1_array2tree(gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); - if (res != ASN1_SUCCESS) { - result = _gnutls_asn2err(res); - goto out; - } + /* initialize ASN.1 parser + * This should not deal with files in the final + * version. + */ + if (asn1_check_version(GNUTLS_MIN_LIBTASN1_VERSION) == NULL) { + gnutls_assert(); + _gnutls_debug_log + ("Checking for libtasn1 failed: %s < %s\n", + asn1_check_version(NULL), + GNUTLS_MIN_LIBTASN1_VERSION); + return GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY; + } - /* Initialize the random generator */ - result = _gnutls_rnd_init(); - if (result < 0) { - gnutls_assert(); - goto out; - } + res = asn1_array2tree(pkix_asn1_tab, &_gnutls_pkix1_asn, NULL); + if (res != ASN1_SUCCESS) { + result = _gnutls_asn2err(res); + goto out; + } - /* Initialize the default TLS extensions */ - result = _gnutls_ext_init(); - if (result < 0) { - gnutls_assert(); - goto out; - } + res = asn1_array2tree(gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL); + if (res != ASN1_SUCCESS) { + result = _gnutls_asn2err(res); + goto out; + } + + /* Initialize the random generator */ + result = _gnutls_rnd_init(); + if (result < 0) { + gnutls_assert(); + goto out; + } + + /* Initialize the default TLS extensions */ + result = _gnutls_ext_init(); + if (result < 0) { + gnutls_assert(); + goto out; + } - result = gnutls_mutex_init(&_gnutls_file_mutex); - if (result < 0) { - gnutls_assert(); - goto out; + result = gnutls_mutex_init(&_gnutls_file_mutex); + if (result < 0) { + gnutls_assert(); + goto out; + } + + result = gnutls_system_global_init(); + if (result < 0) { + gnutls_assert(); + goto out; + } + } - result = gnutls_system_global_init(); - if (result < 0) { - gnutls_assert(); - goto out; + if (flags & GNUTLS_GLOBAL_INIT_CRYPTO) { + _gnutls_register_accel_crypto(); + + _gnutls_cryptodev_init(); } + #ifdef ENABLE_PKCS11 - gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL); + if (flags & GNUTLS_GLOBAL_INIT_PKCS11) { + gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_AUTO, NULL); + } #endif - _gnutls_cryptodev_init(); - - result = _gnutls_fips_mode_enabled(); - if (result != 0) { - result = _gnutls_fips_perform_self_checks(); - if (_gnutls_get_fips_state() != FIPS_STATE_ZOMBIE) { - if (result < 0) { - gnutls_assert(); - goto out; +#ifdef ENABLE_FIPS140 + /* Perform FIPS140 checks last, so that all modules + * have been loaded */ + if (flags & GNUTLS_GLOBAL_INIT_MINIMAL) { + result = _gnutls_fips_mode_enabled(); + if (result != 0) { + result = _gnutls_fips_perform_self_checks(); + if (_gnutls_get_fips_state() != FIPS_STATE_ZOMBIE) { + if (result < 0) { + gnutls_assert(); + goto out; + } + } else { + result = 0; } - } else { - result = 0; + _gnutls_switch_fips_state(FIPS_STATE_OPERATIONAL); } - _gnutls_switch_fips_state(FIPS_STATE_OPERATIONAL); } +#endif out: return result; } +#ifdef ENABLE_FIPS140 +__attribute__((constructor)) +static void lib_init(void) +{ + if (gnutls_global_init2(GNUTLS_GLOBAL_INIT_MINIMAL|GNUTLS_GLOBAL_INIT_CRYPTO) < 0) { + fprintf(stderr, "Error in GnuTLS initialization"); + abort(); + } +} +#endif + + +/** + * gnutls_global_init: + * + * This function performs any required precalculations, detects + * the supported CPU capabilities and initializes the underlying + * cryptographic backend. In order to free any resources + * taken by this call you should gnutls_global_deinit() + * when gnutls usage is no longer needed. + * + * This function increments a global counter, so that + * gnutls_global_deinit() only releases resources when it has been + * called as many times as gnutls_global_init(). This is useful when + * GnuTLS is used by more than one library in an application. This + * function can be called many times, but will only do something the + * first time. + * + * Note! This function is not thread safe. If two threads call this + * function simultaneously, they can cause a race between checking + * the global counter and incrementing it, causing both threads to + * execute the library initialization code. That could lead to a + * memory leak or even a crash. To handle this, your application should + * invoke this function after aquiring a thread mutex. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, + * otherwise a negative error code is returned. + **/ +int gnutls_global_init(void) +{ + return gnutls_global_init2(GNUTLS_GLOBAL_INIT_ALL); +} + /** * gnutls_global_deinit: * @@ -320,14 +400,23 @@ void gnutls_global_deinit(void) asn1_delete_structure(&_gnutls_gnutls_asn); asn1_delete_structure(&_gnutls_pkix1_asn); _gnutls_crypto_deregister(); - _gnutls_cryptodev_deinit(); gnutls_system_global_deinit(); + + if (loaded_modules & GNUTLS_GLOBAL_INIT_CRYPTO) { + _gnutls_cryptodev_deinit(); + } #ifdef ENABLE_PKCS11 - gnutls_pkcs11_deinit(); + if (loaded_modules & GNUTLS_GLOBAL_INIT_PKCS11) { + gnutls_pkcs11_deinit(); + } #endif + gnutls_mutex_deinit(&_gnutls_file_mutex); + loaded_modules = 0; } - _gnutls_init--; + + if (_gnutls_init > 0) + _gnutls_init--; } /* These functions should be elsewere. Kept here for -- cgit v1.2.1 From de3500e67e61310fa13099f1f8d57cf4208f9b1a Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Thu, 28 Nov 2013 17:35:18 +0100 Subject: Added destructor and moved both *structors to fips.c --- lib/gnutls_global.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'lib/gnutls_global.c') diff --git a/lib/gnutls_global.c b/lib/gnutls_global.c index 57bd116f53..52aa0819b9 100644 --- a/lib/gnutls_global.c +++ b/lib/gnutls_global.c @@ -338,18 +338,6 @@ out: return result; } -#ifdef ENABLE_FIPS140 -__attribute__((constructor)) -static void lib_init(void) -{ - if (gnutls_global_init2(GNUTLS_GLOBAL_INIT_MINIMAL|GNUTLS_GLOBAL_INIT_CRYPTO) < 0) { - fprintf(stderr, "Error in GnuTLS initialization"); - abort(); - } -} -#endif - - /** * gnutls_global_init: * -- cgit v1.2.1