diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /comm/third_party/libgcrypt/src/global.c | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/third_party/libgcrypt/src/global.c')
-rw-r--r-- | comm/third_party/libgcrypt/src/global.c | 1368 |
1 files changed, 1368 insertions, 0 deletions
diff --git a/comm/third_party/libgcrypt/src/global.c b/comm/third_party/libgcrypt/src/global.c new file mode 100644 index 0000000000..8940cea03b --- /dev/null +++ b/comm/third_party/libgcrypt/src/global.c @@ -0,0 +1,1368 @@ +/* global.c - global control functions + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 + * 2004, 2005, 2006, 2008, 2011, + * 2012 Free Software Foundation, Inc. + * Copyright (C) 2013, 2014, 2017 g10 Code GmbH + * + * This file is part of Libgcrypt. + * + * Libgcrypt 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. + * + * Libgcrypt 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/>. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> +#include <errno.h> +#include <unistd.h> +#ifdef HAVE_SYSLOG +# include <syslog.h> +#endif /*HAVE_SYSLOG*/ + +#include "g10lib.h" +#include "gcrypt-testapi.h" +#include "cipher.h" +#include "stdmem.h" /* our own memory allocator */ +#include "secmem.h" /* our own secmem allocator */ + + + + +/**************** + * flag bits: 0 : general cipher debug + * 1 : general MPI debug + */ +static unsigned int debug_flags; + +/* gcry_control (GCRYCTL_SET_FIPS_MODE), sets this flag so that the + initialization code switched fips mode on. */ +static int force_fips_mode; + +/* Controlled by global_init(). */ +int _gcry_global_any_init_done; + +/* + * Functions called before and after blocking syscalls. + * Initialized by global_init and used via + * _gcry_pre_syscall and _gcry_post_syscall. + */ +static void (*pre_syscall_func)(void); +static void (*post_syscall_func)(void); + + +/* Memory management. */ + +static gcry_handler_alloc_t alloc_func; +static gcry_handler_alloc_t alloc_secure_func; +static gcry_handler_secure_check_t is_secure_func; +static gcry_handler_realloc_t realloc_func; +static gcry_handler_free_t free_func; +static gcry_handler_no_mem_t outofcore_handler; +static void *outofcore_handler_value; +static int no_secure_memory; + +/* Prototypes. */ +static gpg_err_code_t external_lock_test (int cmd); + + + + +/* This is our handmade constructor. It gets called by any function + likely to be called at startup. The suggested way for an + application to make sure that this has been called is by using + gcry_check_version. */ +static void +global_init (void) +{ + gcry_error_t err = 0; + + if (_gcry_global_any_init_done) + return; + _gcry_global_any_init_done = 1; + + /* Tell the random module that we have seen an init call. */ + _gcry_set_preferred_rng_type (0); + + /* Get the system call clamp functions. */ + if (!pre_syscall_func) + gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func); + + /* See whether the system is in FIPS mode. This needs to come as + early as possible but after ATH has been initialized. */ + _gcry_initialize_fips_mode (force_fips_mode); + + /* Before we do any other initialization we need to test available + hardware features. */ + _gcry_detect_hw_features (); + + /* Initialize the modules - this is mainly allocating some memory and + creating mutexes. */ + err = _gcry_cipher_init (); + if (err) + goto fail; + err = _gcry_md_init (); + if (err) + goto fail; + err = _gcry_mac_init (); + if (err) + goto fail; + err = _gcry_pk_init (); + if (err) + goto fail; + err = _gcry_primegen_init (); + if (err) + goto fail; + err = _gcry_secmem_module_init (); + if (err) + goto fail; + err = _gcry_mpi_init (); + if (err) + goto fail; + + return; + + fail: + BUG (); +} + + +/* This function is called by the macro fips_is_operational and makes + sure that the minimal initialization has been done. This is far + from a perfect solution and hides problems with an improper + initialization but at least in single-threaded mode it should work + reliable. + + The reason we need this is that a lot of applications don't use + Libgcrypt properly by not running any initialization code at all. + They just call a Libgcrypt function and that is all what they want. + Now with the FIPS mode, that has the side effect of entering FIPS + mode (for security reasons, FIPS mode is the default if no + initialization has been done) and bailing out immediately because + the FSM is in the wrong state. If we always run the init code, + Libgcrypt can test for FIPS mode and at least if not in FIPS mode, + it will behave as before. Note that this on-the-fly initialization + is only done for the cryptographic functions subject to FIPS mode + and thus not all API calls will do such an initialization. */ +int +_gcry_global_is_operational (void) +{ + if (!_gcry_global_any_init_done) + { +#ifdef HAVE_SYSLOG + syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: " + "missing initialization - please fix the application"); +#endif /*HAVE_SYSLOG*/ + global_init (); + } + return _gcry_fips_is_operational (); +} + + + + +/* Version number parsing. */ + +/* This function parses the first portion of the version number S and + stores it in *NUMBER. On success, this function returns a pointer + into S starting with the first character, which is not part of the + initial number portion; on failure, NULL is returned. */ +static const char* +parse_version_number( const char *s, int *number ) +{ + int val = 0; + + if( *s == '0' && isdigit(s[1]) ) + return NULL; /* leading zeros are not allowed */ + for ( ; isdigit(*s); s++ ) { + val *= 10; + val += *s - '0'; + } + *number = val; + return val < 0? NULL : s; +} + +/* This function breaks up the complete string-representation of the + version number S, which is of the following struture: <major + number>.<minor number>.<micro number><patch level>. The major, + minor and micro number components will be stored in *MAJOR, *MINOR + and *MICRO. + + On success, the last component, the patch level, will be returned; + in failure, NULL will be returned. */ + +static const char * +parse_version_string( const char *s, int *major, int *minor, int *micro ) +{ + s = parse_version_number( s, major ); + if( !s || *s != '.' ) + return NULL; + s++; + s = parse_version_number( s, minor ); + if( !s || *s != '.' ) + return NULL; + s++; + s = parse_version_number( s, micro ); + if( !s ) + return NULL; + return s; /* patchlevel */ +} + +/* If REQ_VERSION is non-NULL, check that the version of the library + is at minimum the requested one. Returns the string representation + of the library version if the condition is satisfied; return NULL + if the requested version is newer than that of the library. + + If a NULL is passed to this function, no check is done, but the + string representation of the library is simply returned. */ +const char * +_gcry_check_version (const char *req_version) +{ + const char *ver = VERSION; + int my_major, my_minor, my_micro; + int rq_major, rq_minor, rq_micro; + const char *my_plvl; + + if (req_version && req_version[0] == 1 && req_version[1] == 1) + return _gcry_compat_identification (); + + /* Initialize library. */ + global_init (); + + if ( !req_version ) + /* Caller wants our version number. */ + return ver; + + /* Parse own version number. */ + my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro ); + if ( !my_plvl ) + /* very strange our own version is bogus. Shouldn't we use + assert() here and bail out in case this happens? -mo. */ + return NULL; + + /* Parse requested version number. */ + if (!parse_version_string (req_version, &rq_major, &rq_minor, &rq_micro)) + return NULL; /* req version string is invalid, this can happen. */ + + /* Compare version numbers. */ + if ( my_major > rq_major + || (my_major == rq_major && my_minor > rq_minor) + || (my_major == rq_major && my_minor == rq_minor + && my_micro > rq_micro) + || (my_major == rq_major && my_minor == rq_minor + && my_micro == rq_micro)) + { + return ver; + } + + return NULL; +} + + +static void +print_config (const char *what, gpgrt_stream_t fp) +{ + int i; + const char *s; + + if (!what || !strcmp (what, "version")) + { + gpgrt_fprintf (fp, "version:%s:%x:%s:%x:\n", + VERSION, GCRYPT_VERSION_NUMBER, + GPGRT_VERSION, GPGRT_VERSION_NUMBER); + } + if (!what || !strcmp (what, "cc")) + { + gpgrt_fprintf (fp, "cc:%d:%s:\n", +#if GPGRT_VERSION_NUMBER >= 0x011b00 /* 1.27 */ + GPGRT_GCC_VERSION +#else + _GPG_ERR_GCC_VERSION /* Due to a bug in gpg-error.h. */ +#endif + , +#ifdef __clang__ + "clang:" __VERSION__ +#elif __GNUC__ + "gcc:" __VERSION__ +#else + ":" +#endif + ); + } + + if (!what || !strcmp (what, "ciphers")) + gpgrt_fprintf (fp, "ciphers:%s:\n", LIBGCRYPT_CIPHERS); + if (!what || !strcmp (what, "pubkeys")) + gpgrt_fprintf (fp, "pubkeys:%s:\n", LIBGCRYPT_PUBKEY_CIPHERS); + if (!what || !strcmp (what, "digests")) + gpgrt_fprintf (fp, "digests:%s:\n", LIBGCRYPT_DIGESTS); + + if (!what || !strcmp (what, "rnd-mod")) + { + gpgrt_fprintf (fp, "rnd-mod:" +#if USE_RNDEGD + "egd:" +#endif +#if USE_RNDLINUX + "linux:" +#endif +#if USE_RNDUNIX + "unix:" +#endif +#if USE_RNDW32 + "w32:" +#endif + "\n"); + } + + if (!what || !strcmp (what, "cpu-arch")) + { + gpgrt_fprintf (fp, "cpu-arch:" +#if defined(HAVE_CPU_ARCH_X86) + "x86" +#elif defined(HAVE_CPU_ARCH_ALPHA) + "alpha" +#elif defined(HAVE_CPU_ARCH_SPARC) + "sparc" +#elif defined(HAVE_CPU_ARCH_MIPS) + "mips" +#elif defined(HAVE_CPU_ARCH_M68K) + "m68k" +#elif defined(HAVE_CPU_ARCH_PPC) + "ppc" +#elif defined(HAVE_CPU_ARCH_ARM) + "arm" +#endif + ":\n"); + } + + if (!what || !strcmp (what, "mpi-asm")) + gpgrt_fprintf (fp, "mpi-asm:%s:\n", _gcry_mpi_get_hw_config ()); + + if (!what || !strcmp (what, "hwflist")) + { + unsigned int hwfeatures, afeature; + + hwfeatures = _gcry_get_hw_features (); + gpgrt_fprintf (fp, "hwflist:"); + for (i=0; (s = _gcry_enum_hw_features (i, &afeature)); i++) + if ((hwfeatures & afeature)) + gpgrt_fprintf (fp, "%s:", s); + gpgrt_fprintf (fp, "\n"); + } + + if (!what || !strcmp (what, "fips-mode")) + { + /* We use y/n instead of 1/0 for the stupid reason that + * Emacsen's compile error parser would accidentally flag that + * line when printed during "make check" as an error. */ + gpgrt_fprintf (fp, "fips-mode:%c:%c:\n", + fips_mode ()? 'y':'n', + _gcry_enforced_fips_mode ()? 'y':'n' ); + } + + if (!what || !strcmp (what, "rng-type")) + { + /* The currently used RNG type. */ + unsigned int jver; + int active; + + i = _gcry_get_rng_type (0); + switch (i) + { + case GCRY_RNG_TYPE_STANDARD: s = "standard"; break; + case GCRY_RNG_TYPE_FIPS: s = "fips"; break; + case GCRY_RNG_TYPE_SYSTEM: s = "system"; break; + default: BUG (); + } + jver = _gcry_rndjent_get_version (&active); + gpgrt_fprintf (fp, "rng-type:%s:%d:%u:%d:\n", s, i, jver, active); + } + + if (!what || !strcmp (what, "compliance")) + { + /* Right now we have no certification for 1.9 so we return an + * empty string. As soon as this version has been approved for + * VS-Nfd we will put the string "de-vs" into the second + * field. If further specifications are required they are added + * as parameters to that field. Other certifications will go + * into field 3 and so on. + * field 1: keyword "compliance" + * field 2: German VS-Nfd is marked with "de-vs" + * field 3: reserved for FIPS. + */ + gpgrt_fprintf (fp, "compliance:%s::\n", ""); + } +} + + +/* With a MODE of 0 return a malloced string with configured features. + * In that case a WHAT of NULL returns everything in the same way + * GCRYCTL_PRINT_CONFIG would do. With a specific WHAT string only + * the requested feature is returned (w/o the trailing LF. On error + * NULL is returned. */ +char * +_gcry_get_config (int mode, const char *what) +{ + gpgrt_stream_t fp; + int save_errno; + void *data; + char *p; + + if (mode) + { + gpg_err_set_errno (EINVAL); + return NULL; + } + + fp = gpgrt_fopenmem (0, "w+b,samethread"); + if (!fp) + return NULL; + + print_config (what, fp); + + if (!what) + { + /* Null-terminate bulk output. */ + gpgrt_fwrite ("\0", 1, 1, fp); + } + + if (gpgrt_ferror (fp)) + { + save_errno = errno; + gpgrt_fclose (fp); + gpg_err_set_errno (save_errno); + return NULL; + } + + gpgrt_rewind (fp); + if (gpgrt_fclose_snatch (fp, &data, NULL)) + { + save_errno = errno; + gpgrt_fclose (fp); + gpg_err_set_errno (save_errno); + return NULL; + } + + if (!data) + { + /* Nothing was printed (unknown value for WHAT). This is okay, + * so clear ERRNO to indicate this. */ + gpg_err_set_errno (0); + return NULL; + } + + /* Strip trailing LF. */ + if (what && (p = strchr (data, '\n'))) + *p = 0; + + return data; +} + + + + +#if _GCRY_GCC_VERSION >= 40200 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wswitch" +#endif + +/* Command dispatcher function, acting as general control + function. */ +gcry_err_code_t +_gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr) +{ + static int init_finished = 0; + gcry_err_code_t rc = 0; + + switch (cmd) + { + case GCRYCTL_ENABLE_M_GUARD: + _gcry_private_enable_m_guard (); + break; + + case GCRYCTL_ENABLE_QUICK_RANDOM: + _gcry_set_preferred_rng_type (0); + _gcry_enable_quick_random_gen (); + break; + + case GCRYCTL_FAKED_RANDOM_P: + /* Return an error if the RNG is faked one (e.g. enabled by + ENABLE_QUICK_RANDOM. */ + if (_gcry_random_is_faked ()) + rc = GPG_ERR_GENERAL; /* Use as TRUE value. */ + break; + + case GCRYCTL_DUMP_RANDOM_STATS: + _gcry_random_dump_stats (); + break; + + case GCRYCTL_DUMP_MEMORY_STATS: + /*m_print_stats("[fixme: prefix]");*/ + break; + + case GCRYCTL_DUMP_SECMEM_STATS: + _gcry_secmem_dump_stats (0); + break; + + case GCRYCTL_DROP_PRIVS: + global_init (); + _gcry_secmem_init (0); + break; + + case GCRYCTL_DISABLE_SECMEM: + global_init (); + no_secure_memory = 1; + break; + + case GCRYCTL_INIT_SECMEM: + global_init (); + _gcry_secmem_init (va_arg (arg_ptr, unsigned int)); + if ((_gcry_secmem_get_flags () & GCRY_SECMEM_FLAG_NOT_LOCKED)) + rc = GPG_ERR_GENERAL; + break; + + case GCRYCTL_TERM_SECMEM: + global_init (); + _gcry_secmem_term (); + break; + + case GCRYCTL_DISABLE_SECMEM_WARN: + _gcry_set_preferred_rng_type (0); + _gcry_secmem_set_flags ((_gcry_secmem_get_flags () + | GCRY_SECMEM_FLAG_NO_WARNING)); + break; + + case GCRYCTL_SUSPEND_SECMEM_WARN: + _gcry_set_preferred_rng_type (0); + _gcry_secmem_set_flags ((_gcry_secmem_get_flags () + | GCRY_SECMEM_FLAG_SUSPEND_WARNING)); + break; + + case GCRYCTL_RESUME_SECMEM_WARN: + _gcry_set_preferred_rng_type (0); + _gcry_secmem_set_flags ((_gcry_secmem_get_flags () + & ~GCRY_SECMEM_FLAG_SUSPEND_WARNING)); + break; + + case GCRYCTL_AUTO_EXPAND_SECMEM: + _gcry_secmem_set_auto_expand (va_arg (arg_ptr, unsigned int)); + break; + + case GCRYCTL_USE_SECURE_RNDPOOL: + global_init (); + _gcry_secure_random_alloc (); /* Put random number into secure memory. */ + break; + + case GCRYCTL_SET_RANDOM_SEED_FILE: + _gcry_set_preferred_rng_type (0); + _gcry_set_random_seed_file (va_arg (arg_ptr, const char *)); + break; + + case GCRYCTL_UPDATE_RANDOM_SEED_FILE: + _gcry_set_preferred_rng_type (0); + if ( fips_is_operational () ) + _gcry_update_random_seed_file (); + break; + + case GCRYCTL_SET_VERBOSITY: + _gcry_set_preferred_rng_type (0); + _gcry_set_log_verbosity (va_arg (arg_ptr, int)); + break; + + case GCRYCTL_SET_DEBUG_FLAGS: + debug_flags |= va_arg (arg_ptr, unsigned int); + break; + + case GCRYCTL_CLEAR_DEBUG_FLAGS: + debug_flags &= ~va_arg (arg_ptr, unsigned int); + break; + + case GCRYCTL_DISABLE_INTERNAL_LOCKING: + /* Not used anymore. */ + global_init (); + break; + + case GCRYCTL_ANY_INITIALIZATION_P: + if (_gcry_global_any_init_done) + rc = GPG_ERR_GENERAL; + break; + + case GCRYCTL_INITIALIZATION_FINISHED_P: + if (init_finished) + rc = GPG_ERR_GENERAL; /* Yes. */ + break; + + case GCRYCTL_INITIALIZATION_FINISHED: + /* This is a hook which should be used by an application after + all initialization has been done and right before any threads + are started. It is not really needed but the only way to be + really sure that all initialization for thread-safety has + been done. */ + if (! init_finished) + { + global_init (); + /* Do only a basic random initialization, i.e. init the + mutexes. */ + _gcry_random_initialize (0); + init_finished = 1; + /* Force us into operational state if in FIPS mode. */ + (void)fips_is_operational (); + } + break; + + case GCRYCTL_SET_THREAD_CBS: + /* This is now a dummy call. We used to install our own thread + library here. */ + _gcry_set_preferred_rng_type (0); + global_init (); + break; + + case GCRYCTL_FAST_POLL: + _gcry_set_preferred_rng_type (0); + /* We need to do make sure that the random pool is really + initialized so that the poll function is not a NOP. */ + _gcry_random_initialize (1); + + if ( fips_is_operational () ) + _gcry_fast_random_poll (); + break; + + case GCRYCTL_SET_RNDEGD_SOCKET: +#if USE_RNDEGD + _gcry_set_preferred_rng_type (0); + rc = _gcry_rndegd_set_socket_name (va_arg (arg_ptr, const char *)); +#else + rc = GPG_ERR_NOT_SUPPORTED; +#endif + break; + + case GCRYCTL_SET_RANDOM_DAEMON_SOCKET: + _gcry_set_preferred_rng_type (0); + _gcry_set_random_daemon_socket (va_arg (arg_ptr, const char *)); + break; + + case GCRYCTL_USE_RANDOM_DAEMON: + /* We need to do make sure that the random pool is really + initialized so that the poll function is not a NOP. */ + _gcry_set_preferred_rng_type (0); + _gcry_random_initialize (1); + _gcry_use_random_daemon (!! va_arg (arg_ptr, int)); + break; + + case GCRYCTL_CLOSE_RANDOM_DEVICE: + _gcry_random_close_fds (); + break; + + /* This command dumps information pertaining to the + configuration of libgcrypt to the given stream. It may be + used before the initialization has been finished but not + before a gcry_version_check. See also gcry_get_config. */ + case GCRYCTL_PRINT_CONFIG: + { + FILE *fp = va_arg (arg_ptr, FILE *); + char *tmpstr; + _gcry_set_preferred_rng_type (0); + tmpstr = _gcry_get_config (0, NULL); + if (tmpstr) + { + if (fp) + fputs (tmpstr, fp); + else + log_info ("%s", tmpstr); + xfree (tmpstr); + } + } + break; + + case GCRYCTL_OPERATIONAL_P: + /* Returns true if the library is in an operational state. This + is always true for non-fips mode. */ + _gcry_set_preferred_rng_type (0); + if (_gcry_fips_test_operational ()) + rc = GPG_ERR_GENERAL; /* Used as TRUE value */ + break; + + case GCRYCTL_FIPS_MODE_P: + if (fips_mode () + && !_gcry_is_fips_mode_inactive () + && !no_secure_memory) + rc = GPG_ERR_GENERAL; /* Used as TRUE value */ + break; + + case GCRYCTL_FORCE_FIPS_MODE: + /* Performing this command puts the library into fips mode. If + the library has already been initialized into fips mode, a + selftest is triggered. It is not possible to put the libraty + into fips mode after having passed the initialization. */ + _gcry_set_preferred_rng_type (0); + if (!_gcry_global_any_init_done) + { + /* Not yet initialized at all. Set a flag so that we are put + into fips mode during initialization. */ + force_fips_mode = 1; + } + else + { + /* Already initialized. If we are already operational we + run a selftest. If not we use the is_operational call to + force us into operational state if possible. */ + if (_gcry_fips_test_error_or_operational ()) + _gcry_fips_run_selftests (1); + if (_gcry_fips_is_operational ()) + rc = GPG_ERR_GENERAL; /* Used as TRUE value */ + } + break; + + case GCRYCTL_SELFTEST: + /* Run a selftest. This works in fips mode as well as in + standard mode. In contrast to the power-up tests, we use an + extended version of the selftests. Returns 0 on success or an + error code. */ + global_init (); + rc = _gcry_fips_run_selftests (1); + break; + + case PRIV_CTL_INIT_EXTRNG_TEST: /* Init external random test. */ + rc = GPG_ERR_NOT_SUPPORTED; + break; + case PRIV_CTL_RUN_EXTRNG_TEST: /* Run external DRBG test. */ + { + struct gcry_drbg_test_vector *test = + va_arg (arg_ptr, struct gcry_drbg_test_vector *); + unsigned char *buf = va_arg (arg_ptr, unsigned char *); + + if (buf) + rc = _gcry_rngdrbg_cavs_test (test, buf); + else + rc = _gcry_rngdrbg_healthcheck_one (test); + } + break; + case PRIV_CTL_DEINIT_EXTRNG_TEST: /* Deinit external random test. */ + rc = GPG_ERR_NOT_SUPPORTED; + break; + case PRIV_CTL_EXTERNAL_LOCK_TEST: /* Run external lock test */ + rc = external_lock_test (va_arg (arg_ptr, int)); + break; + case PRIV_CTL_DUMP_SECMEM_STATS: + _gcry_secmem_dump_stats (1); + break; + + case GCRYCTL_DISABLE_HWF: + { + const char *name = va_arg (arg_ptr, const char *); + rc = _gcry_disable_hw_feature (name); + } + break; + + case GCRYCTL_SET_ENFORCED_FIPS_FLAG: + if (!_gcry_global_any_init_done) + { + /* Not yet initialized at all. Set the enforced fips mode flag */ + _gcry_set_preferred_rng_type (0); + _gcry_set_enforced_fips_mode (); + } + else + rc = GPG_ERR_GENERAL; + break; + + case GCRYCTL_SET_PREFERRED_RNG_TYPE: + /* This may be called before gcry_check_version. */ + { + int i = va_arg (arg_ptr, int); + /* Note that we may not pass 0 to _gcry_set_preferred_rng_type. */ + if (i > 0) + _gcry_set_preferred_rng_type (i); + } + break; + + case GCRYCTL_GET_CURRENT_RNG_TYPE: + { + int *ip = va_arg (arg_ptr, int*); + if (ip) + *ip = _gcry_get_rng_type (!_gcry_global_any_init_done); + } + break; + + case GCRYCTL_DISABLE_LOCKED_SECMEM: + _gcry_set_preferred_rng_type (0); + _gcry_secmem_set_flags ((_gcry_secmem_get_flags () + | GCRY_SECMEM_FLAG_NO_MLOCK)); + break; + + case GCRYCTL_DISABLE_PRIV_DROP: + _gcry_set_preferred_rng_type (0); + _gcry_secmem_set_flags ((_gcry_secmem_get_flags () + | GCRY_SECMEM_FLAG_NO_PRIV_DROP)); + break; + + case GCRYCTL_INACTIVATE_FIPS_FLAG: + case GCRYCTL_REACTIVATE_FIPS_FLAG: + rc = GPG_ERR_NOT_IMPLEMENTED; + break; + + case GCRYCTL_DRBG_REINIT: + { + const char *flagstr = va_arg (arg_ptr, const char *); + gcry_buffer_t *pers = va_arg (arg_ptr, gcry_buffer_t *); + int npers = va_arg (arg_ptr, int); + if (va_arg (arg_ptr, void *) || npers < 0) + rc = GPG_ERR_INV_ARG; + else if (_gcry_get_rng_type (!_gcry_global_any_init_done) + != GCRY_RNG_TYPE_FIPS) + rc = GPG_ERR_NOT_SUPPORTED; + else + rc = _gcry_rngdrbg_reinit (flagstr, pers, npers); + } + break; + + case GCRYCTL_REINIT_SYSCALL_CLAMP: + if (!pre_syscall_func) + gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func); + break; + + default: + _gcry_set_preferred_rng_type (0); + rc = GPG_ERR_INV_OP; + } + + return rc; +} + +#if _GCRY_GCC_VERSION >= 40200 +# pragma GCC diagnostic pop +#endif + + +/* Set custom allocation handlers. This is in general not useful + * because the libgcrypt allocation functions are guaranteed to + * provide proper allocation handlers which zeroize memory if needed. + * NOTE: All 5 functions should be set. */ +void +_gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func, + gcry_handler_alloc_t new_alloc_secure_func, + gcry_handler_secure_check_t new_is_secure_func, + gcry_handler_realloc_t new_realloc_func, + gcry_handler_free_t new_free_func) +{ + global_init (); + + if (fips_mode ()) + { + /* We do not want to enforce the fips mode, but merely set a + flag so that the application may check whether it is still in + fips mode. */ + _gcry_inactivate_fips_mode ("custom allocation handler"); + } + + alloc_func = new_alloc_func; + alloc_secure_func = new_alloc_secure_func; + is_secure_func = new_is_secure_func; + realloc_func = new_realloc_func; + free_func = new_free_func; +} + + + +/**************** + * Set an optional handler which is called in case the xmalloc functions + * ran out of memory. This handler may do one of these things: + * o free some memory and return true, so that the xmalloc function + * tries again. + * o Do whatever it like and return false, so that the xmalloc functions + * use the default fatal error handler. + * o Terminate the program and don't return. + * + * The handler function is called with 3 arguments: The opaque value set with + * this function, the requested memory size, and a flag with these bits + * currently defined: + * bit 0 set = secure memory has been requested. + */ +void +_gcry_set_outofcore_handler (int (*f)(void*, size_t, unsigned int), void *value) +{ + global_init (); + + if (fips_mode () ) + { + log_info ("out of core handler ignored in FIPS mode\n"); + return; + } + + outofcore_handler = f; + outofcore_handler_value = value; +} + +/* Return the no_secure_memory flag. */ +static int +get_no_secure_memory (void) +{ + if (!no_secure_memory) + return 0; + if (_gcry_enforced_fips_mode ()) + { + no_secure_memory = 0; + return 0; + } + return no_secure_memory; +} + + +static gcry_err_code_t +do_malloc (size_t n, unsigned int flags, void **mem) +{ + gcry_err_code_t err = 0; + void *m; + + if ((flags & GCRY_ALLOC_FLAG_SECURE) && !get_no_secure_memory ()) + { + if (alloc_secure_func) + m = (*alloc_secure_func) (n); + else + m = _gcry_private_malloc_secure (n, !!(flags & GCRY_ALLOC_FLAG_XHINT)); + } + else + { + if (alloc_func) + m = (*alloc_func) (n); + else + m = _gcry_private_malloc (n); + } + + if (!m) + { + /* Make sure that ERRNO has been set in case a user supplied + memory handler didn't it correctly. */ + if (!errno) + gpg_err_set_errno (ENOMEM); + err = gpg_err_code_from_errno (errno); + } + else + *mem = m; + + return err; +} + +void * +_gcry_malloc (size_t n) +{ + void *mem = NULL; + + do_malloc (n, 0, &mem); + + return mem; +} + +static void * +_gcry_malloc_secure_core (size_t n, int xhint) +{ + void *mem = NULL; + + do_malloc (n, (GCRY_ALLOC_FLAG_SECURE | (xhint? GCRY_ALLOC_FLAG_XHINT:0)), + &mem); + + return mem; +} + +void * +_gcry_malloc_secure (size_t n) +{ + return _gcry_malloc_secure_core (n, 0); +} + +int +_gcry_is_secure (const void *a) +{ + if (get_no_secure_memory ()) + return 0; + if (is_secure_func) + return is_secure_func (a) ; + return _gcry_private_is_secure (a); +} + +void +_gcry_check_heap( const void *a ) +{ + (void)a; + + /* FIXME: implement this*/ +#if 0 + if( some_handler ) + some_handler(a) + else + _gcry_private_check_heap(a) +#endif +} + +static void * +_gcry_realloc_core (void *a, size_t n, int xhint) +{ + void *p; + + /* To avoid problems with non-standard realloc implementations and + our own secmem_realloc, we divert to malloc and free here. */ + if (!a) + return _gcry_malloc (n); + if (!n) + { + xfree (a); + return NULL; + } + + if (realloc_func) + p = realloc_func (a, n); + else + p = _gcry_private_realloc (a, n, xhint); + if (!p && !errno) + gpg_err_set_errno (ENOMEM); + return p; +} + + +void * +_gcry_realloc (void *a, size_t n) +{ + return _gcry_realloc_core (a, n, 0); +} + + +void +_gcry_free (void *p) +{ + int save_errno; + + if (!p) + return; + + /* In case ERRNO is set we better save it so that the free machinery + may not accidentally change ERRNO. We restore it only if it was + already set to comply with the usual C semantic for ERRNO. */ + save_errno = errno; + if (free_func) + free_func (p); + else + _gcry_private_free (p); + + if (save_errno) + gpg_err_set_errno (save_errno); +} + +void * +_gcry_calloc (size_t n, size_t m) +{ + size_t bytes; + void *p; + + bytes = n * m; /* size_t is unsigned so the behavior on overflow is + defined. */ + if (m && bytes / m != n) + { + gpg_err_set_errno (ENOMEM); + return NULL; + } + + p = _gcry_malloc (bytes); + if (p) + memset (p, 0, bytes); + return p; +} + +void * +_gcry_calloc_secure (size_t n, size_t m) +{ + size_t bytes; + void *p; + + bytes = n * m; /* size_t is unsigned so the behavior on overflow is + defined. */ + if (m && bytes / m != n) + { + gpg_err_set_errno (ENOMEM); + return NULL; + } + + p = _gcry_malloc_secure (bytes); + if (p) + memset (p, 0, bytes); + return p; +} + + +static char * +_gcry_strdup_core (const char *string, int xhint) +{ + char *string_cp = NULL; + size_t string_n = 0; + + string_n = strlen (string); + + if (_gcry_is_secure (string)) + string_cp = _gcry_malloc_secure_core (string_n + 1, xhint); + else + string_cp = _gcry_malloc (string_n + 1); + + if (string_cp) + strcpy (string_cp, string); + + return string_cp; +} + +/* Create and return a copy of the null-terminated string STRING. If + * it is contained in secure memory, the copy will be contained in + * secure memory as well. In an out-of-memory condition, NULL is + * returned. */ +char * +_gcry_strdup (const char *string) +{ + return _gcry_strdup_core (string, 0); +} + +void * +_gcry_xmalloc( size_t n ) +{ + void *p; + + while ( !(p = _gcry_malloc( n )) ) + { + if ( fips_mode () + || !outofcore_handler + || !outofcore_handler (outofcore_handler_value, n, 0) ) + { + _gcry_fatal_error (gpg_err_code_from_errno (errno), NULL); + } + } + return p; +} + +void * +_gcry_xrealloc( void *a, size_t n ) +{ + void *p; + + while (!(p = _gcry_realloc_core (a, n, 1))) + { + if ( fips_mode () + || !outofcore_handler + || !outofcore_handler (outofcore_handler_value, n, + _gcry_is_secure(a)? 3:2)) + { + _gcry_fatal_error (gpg_err_code_from_errno (errno), NULL ); + } + } + return p; +} + +void * +_gcry_xmalloc_secure( size_t n ) +{ + void *p; + + while (!(p = _gcry_malloc_secure_core (n, 1))) + { + if ( fips_mode () + || !outofcore_handler + || !outofcore_handler (outofcore_handler_value, n, 1) ) + { + _gcry_fatal_error (gpg_err_code_from_errno (errno), + _("out of core in secure memory")); + } + } + return p; +} + + +void * +_gcry_xcalloc( size_t n, size_t m ) +{ + size_t nbytes; + void *p; + + nbytes = n * m; + if (m && nbytes / m != n) + { + gpg_err_set_errno (ENOMEM); + _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL ); + } + + p = _gcry_xmalloc ( nbytes ); + memset ( p, 0, nbytes ); + return p; +} + +void * +_gcry_xcalloc_secure( size_t n, size_t m ) +{ + size_t nbytes; + void *p; + + nbytes = n * m; + if (m && nbytes / m != n) + { + gpg_err_set_errno (ENOMEM); + _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL ); + } + + p = _gcry_xmalloc_secure ( nbytes ); + memset ( p, 0, nbytes ); + return p; +} + +char * +_gcry_xstrdup (const char *string) +{ + char *p; + + while ( !(p = _gcry_strdup_core (string, 1)) ) + { + size_t n = strlen (string); + int is_sec = !!_gcry_is_secure (string); + + if (fips_mode () + || !outofcore_handler + || !outofcore_handler (outofcore_handler_value, n, is_sec) ) + { + _gcry_fatal_error (gpg_err_code_from_errno (errno), + is_sec? _("out of core in secure memory"):NULL); + } + } + + return p; +} + + +/* Used before blocking system calls. */ +void +_gcry_pre_syscall (void) +{ + if (pre_syscall_func) + pre_syscall_func (); +} + + +/* Used after blocking system calls. */ +void +_gcry_post_syscall (void) +{ + if (post_syscall_func) + post_syscall_func (); +} + + +int +_gcry_get_debug_flag (unsigned int mask) +{ + if ( fips_mode () ) + return 0; + return (debug_flags & mask); +} + + + +/* It is often useful to get some feedback of long running operations. + This function may be used to register a handler for this. + The callback function CB is used as: + + void cb (void *opaque, const char *what, int printchar, + int current, int total); + + Where WHAT is a string identifying the the type of the progress + output, PRINTCHAR the character usually printed, CURRENT the amount + of progress currently done and TOTAL the expected amount of + progress. A value of 0 for TOTAL indicates that there is no + estimation available. + + Defined values for WHAT: + + "need_entropy" X 0 number-of-bytes-required + When running low on entropy + "primegen" '\n' 0 0 + Prime generated + '!' + Need to refresh the prime pool + '<','>' + Number of bits adjusted + '^' + Looking for a generator + '.' + Fermat tests on 10 candidates failed + ':' + Restart with a new random value + '+' + Rabin Miller test passed + "pk_elg" '+','-','.','\n' 0 0 + Only used in debugging mode. + "pk_dsa" + Only used in debugging mode. +*/ +void +_gcry_set_progress_handler (void (*cb)(void *,const char*,int, int, int), + void *cb_data) +{ +#if USE_DSA + _gcry_register_pk_dsa_progress (cb, cb_data); +#endif +#if USE_ELGAMAL + _gcry_register_pk_elg_progress (cb, cb_data); +#endif + _gcry_register_primegen_progress (cb, cb_data); + _gcry_register_random_progress (cb, cb_data); +} + + + +/* This is a helper for the regression test suite to test Libgcrypt's locks. + It works using a one test lock with CMD controlling what to do: + + 30111 - Allocate and init lock + 30112 - Take lock + 30113 - Release lock + 30114 - Destroy lock. + + This function is used by tests/t-lock.c - it is not part of the + public API! + */ +static gpg_err_code_t +external_lock_test (int cmd) +{ + GPGRT_LOCK_DEFINE (testlock); + gpg_err_code_t rc = 0; + + switch (cmd) + { + case 30111: /* Init Lock. */ + rc = gpgrt_lock_init (&testlock); + break; + + case 30112: /* Take Lock. */ + rc = gpgrt_lock_lock (&testlock); + break; + + case 30113: /* Release Lock. */ + rc = gpgrt_lock_unlock (&testlock); + break; + + case 30114: /* Destroy Lock. */ + rc = gpgrt_lock_destroy (&testlock); + break; + + default: + rc = GPG_ERR_INV_OP; + break; + } + + return rc; +} |