diff --git a/src/fips.c b/src/fips.c
index bcadc5f2..5499aee8 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -1,909 +1,926 @@
/* fips.c - FIPS mode management
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* 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 .
*/
#include
#include
#include
#include
#include
#include
#ifdef ENABLE_HMAC_BINARY_CHECK
# include
# include
#endif
#ifdef HAVE_SYSLOG
# include
#endif /*HAVE_SYSLOG*/
/* The name of the file used to force libgcrypt into fips mode. */
#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
#include "g10lib.h"
#include "cipher-proto.h"
#include "../random/random.h"
/* The states of the finite state machine used in fips mode. */
enum module_states
{
/* POWEROFF cannot be represented. */
STATE_POWERON = 0,
STATE_INIT,
STATE_SELFTEST,
STATE_OPERATIONAL,
STATE_ERROR,
STATE_FATALERROR,
STATE_SHUTDOWN
};
/* Flag telling whether we are in fips mode. It uses inverse logic so
that fips mode is the default unless changed by the initialization
code. To check whether fips mode is enabled, use the function
fips_mode()! */
int _gcry_no_fips_mode_required;
/* This is the lock we use to protect the FSM. */
GPGRT_LOCK_DEFINE (fsm_lock);
/* The current state of the FSM. The whole state machinery is only
used while in fips mode. Change this only while holding fsm_lock. */
static enum module_states current_state;
static void fips_new_state (enum module_states new_state);
/* Convert lowercase hex digits; assumes valid hex digits. */
#define loxtoi_1(p) (*(p) <= '9'? (*(p)- '0'): (*(p)-'a'+10))
#define loxtoi_2(p) ((loxtoi_1(p) * 16) + loxtoi_1((p)+1))
/* Returns true if P points to a lowercase hex digit. */
#define loxdigit_p(p) !!strchr ("01234567890abcdef", *(p))
+/*
+ * Returns 1 if the FIPS mode is to be activated based on the
+ * environment variable LIBGCRYPT_FORCE_FIPS_MODE, the file defined by
+ * FIPS_FORCE_FILE, or /proc/sys/crypto/fips_enabled.
+ * This function aborts on misconfigured filesystems.
+ */
static int
check_fips_system_setting (void)
{
/* Do we have the environment variable set? */
if (getenv ("LIBGCRYPT_FORCE_FIPS_MODE"))
return 1;
/* For testing the system it is useful to override the system
provided detection of the FIPS mode and force FIPS mode using a
file. The filename is hardwired so that there won't be any
confusion on whether /etc/gcrypt/ or /usr/local/etc/gcrypt/ is
actually used. The file itself may be empty. */
if ( !access (FIPS_FORCE_FILE, F_OK) )
return 1;
/* Checking based on /proc file properties. */
{
static const char procfname[] = "/proc/sys/crypto/fips_enabled";
FILE *fp;
int saved_errno;
fp = fopen (procfname, "r");
if (fp)
{
char line[256];
if (fgets (line, sizeof line, fp) && atoi (line))
{
/* System is in fips mode. */
fclose (fp);
return 1;
}
fclose (fp);
}
else if ((saved_errno = errno) != ENOENT
&& saved_errno != EACCES
&& !access ("/proc/version", F_OK) )
{
/* Problem reading the fips file despite that we have the proc
file system. We better stop right away. */
log_info ("FATAL: error reading `%s' in libgcrypt: %s\n",
procfname, strerror (saved_errno));
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
"reading `%s' failed: %s - abort",
procfname, strerror (saved_errno));
#endif /*HAVE_SYSLOG*/
abort ();
}
}
return 0;
}
+/*
+ * Initial check if the FIPS mode should be activated on startup.
+ * Called by the constructor at the initialization of the library.
+ */
+int
+_gcry_fips_to_activate (void)
+{
+ return check_fips_system_setting ();
+}
+
+
/* Check whether the OS is in FIPS mode and record that in a module
local variable. If FORCE is passed as true, fips mode will be
enabled anyway. Note: This function is not thread-safe and should
be called before any threads are created. This function may only
be called once. */
void
_gcry_initialize_fips_mode (int force)
{
static int done;
gpg_error_t err;
/* Make sure we are not accidentally called twice. */
if (done)
{
if ( fips_mode () )
{
fips_new_state (STATE_FATALERROR);
fips_noreturn ();
}
/* If not in fips mode an assert is sufficient. */
gcry_assert (!done);
}
done = 1;
/* If the calling application explicitly requested fipsmode, do so. */
if (force)
{
gcry_assert (!_gcry_no_fips_mode_required);
goto leave;
}
/* If the system explicitly requested fipsmode, do so. */
if (check_fips_system_setting ())
{
gcry_assert (!_gcry_no_fips_mode_required);
goto leave;
}
/* Fips not not requested, set flag. */
_gcry_no_fips_mode_required = 1;
leave:
if (!_gcry_no_fips_mode_required)
{
/* Yes, we are in FIPS mode. */
/* Intitialize the lock to protect the FSM. */
err = gpgrt_lock_init (&fsm_lock);
if (err)
{
/* If that fails we can't do anything but abort the
process. We need to use log_info so that the FSM won't
get involved. */
log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n",
gpg_strerror (err));
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
"creating FSM lock failed: %s - abort",
gpg_strerror (err));
#endif /*HAVE_SYSLOG*/
abort ();
}
/* Now get us into the INIT state. */
fips_new_state (STATE_INIT);
}
return;
}
static void
lock_fsm (void)
{
gpg_error_t err;
err = gpgrt_lock_lock (&fsm_lock);
if (err)
{
log_info ("FATAL: failed to acquire the FSM lock in libgrypt: %s\n",
gpg_strerror (err));
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
"acquiring FSM lock failed: %s - abort",
gpg_strerror (err));
#endif /*HAVE_SYSLOG*/
abort ();
}
}
static void
unlock_fsm (void)
{
gpg_error_t err;
err = gpgrt_lock_unlock (&fsm_lock);
if (err)
{
log_info ("FATAL: failed to release the FSM lock in libgrypt: %s\n",
gpg_strerror (err));
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
"releasing FSM lock failed: %s - abort",
gpg_strerror (err));
#endif /*HAVE_SYSLOG*/
abort ();
}
}
static const char *
state2str (enum module_states state)
{
const char *s;
switch (state)
{
case STATE_POWERON: s = "Power-On"; break;
case STATE_INIT: s = "Init"; break;
case STATE_SELFTEST: s = "Self-Test"; break;
case STATE_OPERATIONAL: s = "Operational"; break;
case STATE_ERROR: s = "Error"; break;
case STATE_FATALERROR: s = "Fatal-Error"; break;
case STATE_SHUTDOWN: s = "Shutdown"; break;
default: s = "?"; break;
}
return s;
}
/* Return true if the library is in the operational state. */
int
_gcry_fips_is_operational (void)
{
int result;
if (!fips_mode ())
result = 1;
else
{
lock_fsm ();
if (current_state == STATE_INIT)
{
/* If we are still in the INIT state, we need to run the
selftests so that the FSM can eventually get into
operational state. Given that we would need a 2-phase
initialization of libgcrypt, but that has traditionally
not been enforced, we use this on demand self-test
checking. Note that Proper applications would do the
application specific libgcrypt initialization between a
gcry_check_version() and gcry_control
(GCRYCTL_INITIALIZATION_FINISHED) where the latter will
run the selftests. The drawback of these on-demand
self-tests are a small chance that self-tests are
performed by several threads; that is no problem because
our FSM make sure that we won't oversee any error. */
unlock_fsm ();
_gcry_fips_run_selftests (0);
/* Release resources for random. */
_gcry_random_close_fds ();
lock_fsm ();
}
result = (current_state == STATE_OPERATIONAL);
unlock_fsm ();
}
return result;
}
/* This is test on whether the library is in the operational state. In
contrast to _gcry_fips_is_operational this function won't do a
state transition on the fly. */
int
_gcry_fips_test_operational (void)
{
int result;
if (!fips_mode ())
result = 1;
else
{
lock_fsm ();
result = (current_state == STATE_OPERATIONAL);
unlock_fsm ();
}
return result;
}
int
_gcry_fips_indicator (va_list arg_ptr)
{
enum gcry_cipher_algos alg = va_arg (arg_ptr, enum gcry_cipher_algos);
enum gcry_cipher_modes mode;
switch (alg)
{
case GCRY_CIPHER_AES:
case GCRY_CIPHER_AES192:
case GCRY_CIPHER_AES256:
mode = va_arg (arg_ptr, enum gcry_cipher_modes);
switch (mode)
{
case GCRY_CIPHER_MODE_ECB:
case GCRY_CIPHER_MODE_CBC:
case GCRY_CIPHER_MODE_CFB:
case GCRY_CIPHER_MODE_CFB8:
case GCRY_CIPHER_MODE_OFB:
case GCRY_CIPHER_MODE_CTR:
case GCRY_CIPHER_MODE_CCM:
case GCRY_CIPHER_MODE_GCM:
case GCRY_CIPHER_MODE_XTS:
return GPG_ERR_NO_ERROR;
default:
return GPG_ERR_NOT_SUPPORTED;
}
default:
return GPG_ERR_NOT_SUPPORTED;
}
}
/* This is a test on whether the library is in the error or
operational state. */
int
_gcry_fips_test_error_or_operational (void)
{
int result;
if (!fips_mode ())
result = 1;
else
{
lock_fsm ();
result = (current_state == STATE_OPERATIONAL
|| current_state == STATE_ERROR);
unlock_fsm ();
}
return result;
}
static void
reporter (const char *domain, int algo, const char *what, const char *errtxt)
{
if (!errtxt && !_gcry_log_verbosity (2))
return;
log_info ("libgcrypt selftest: %s %s%s (%d): %s%s%s%s\n",
!strcmp (domain, "hmac")? "digest":domain,
!strcmp (domain, "hmac")? "HMAC-":"",
!strcmp (domain, "cipher")? _gcry_cipher_algo_name (algo) :
!strcmp (domain, "digest")? _gcry_md_algo_name (algo) :
!strcmp (domain, "hmac")? _gcry_md_algo_name (algo) :
!strcmp (domain, "pubkey")? _gcry_pk_algo_name (algo) : "",
algo, errtxt? errtxt:"Okay",
what?" (":"", what? what:"", what?")":"");
}
/* Run self-tests for all required cipher algorithms. Return 0 on
success. */
static int
run_cipher_selftests (int extended)
{
static int algos[] =
{
GCRY_CIPHER_AES128,
GCRY_CIPHER_AES192,
GCRY_CIPHER_AES256,
0
};
int idx;
gpg_error_t err;
int anyerr = 0;
for (idx=0; algos[idx]; idx++)
{
err = _gcry_cipher_selftest (algos[idx], extended, reporter);
reporter ("cipher", algos[idx], NULL,
err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
}
return anyerr;
}
/* Run self-tests for all required hash algorithms. Return 0 on
success. */
static int
run_digest_selftests (int extended)
{
static int algos[] =
{
GCRY_MD_SHA1,
GCRY_MD_SHA224,
#ifndef ENABLE_HMAC_BINARY_CHECK
GCRY_MD_SHA256,
#endif
GCRY_MD_SHA384,
GCRY_MD_SHA512,
0
};
int idx;
gpg_error_t err;
int anyerr = 0;
for (idx=0; algos[idx]; idx++)
{
err = _gcry_md_selftest (algos[idx], extended, reporter);
reporter ("digest", algos[idx], NULL,
err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
}
return anyerr;
}
/* Run self-tests for MAC algorithms. Return 0 on success. */
static int
run_mac_selftests (int extended)
{
static int algos[] =
{
GCRY_MAC_HMAC_SHA1,
GCRY_MAC_HMAC_SHA224,
#ifndef ENABLE_HMAC_BINARY_CHECK
GCRY_MAC_HMAC_SHA256,
#endif
GCRY_MAC_HMAC_SHA384,
GCRY_MAC_HMAC_SHA512,
GCRY_MAC_HMAC_SHA3_224,
GCRY_MAC_HMAC_SHA3_256,
GCRY_MAC_HMAC_SHA3_384,
GCRY_MAC_HMAC_SHA3_512,
GCRY_MAC_CMAC_AES,
0
};
int idx;
gpg_error_t err;
int anyerr = 0;
for (idx=0; algos[idx]; idx++)
{
err = _gcry_mac_selftest (algos[idx], extended, reporter);
reporter ("mac", algos[idx], NULL,
err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
}
return anyerr;
}
/* Run self-tests for all KDF algorithms. Return 0 on success. */
static int
run_kdf_selftests (int extended)
{
static int algos[] =
{
GCRY_KDF_PBKDF2,
0
};
int idx;
gpg_error_t err;
int anyerr = 0;
for (idx=0; algos[idx]; idx++)
{
err = _gcry_kdf_selftest (algos[idx], extended, reporter);
reporter ("kdf", algos[idx], NULL, err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
}
return anyerr;
}
/* Run self-tests for all required public key algorithms. Return 0 on
success. */
static int
run_pubkey_selftests (int extended)
{
static int algos[] =
{
GCRY_PK_RSA,
GCRY_PK_ECC,
0
};
int idx;
gpg_error_t err;
int anyerr = 0;
for (idx=0; algos[idx]; idx++)
{
err = _gcry_pk_selftest (algos[idx], extended, reporter);
reporter ("pubkey", algos[idx], NULL,
err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
}
return anyerr;
}
/* Run self-tests for the random number generator. Returns 0 on
success. */
static int
run_random_selftests (void)
{
gpg_error_t err;
err = _gcry_random_selftest (reporter);
reporter ("random", 0, NULL, err? gpg_strerror (err):NULL);
return !!err;
}
#ifdef ENABLE_HMAC_BINARY_CHECK
# ifndef KEY_FOR_BINARY_CHECK
# define KEY_FOR_BINARY_CHECK "What am I, a doctor or a moonshuttle conductor?"
# endif
#define HMAC_LEN 32
static const unsigned char __attribute__ ((section (".rodata1")))
hmac_for_the_implementation[HMAC_LEN];
static gpg_error_t
hmac256_check (const char *filename, const char *key, struct link_map *lm)
{
gpg_error_t err;
FILE *fp;
gcry_md_hd_t hd;
size_t buffer_size, nread;
char *buffer;
unsigned long paddr;
unsigned long off = 0;
paddr = (unsigned long)hmac_for_the_implementation - lm->l_addr;
fp = fopen (filename, "rb");
if (!fp)
return gpg_error (GPG_ERR_INV_OBJ);
err = _gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (err)
{
fclose (fp);
return err;
}
err = _gcry_md_setkey (hd, key, strlen (key));
if (err)
{
fclose (fp);
_gcry_md_close (hd);
return err;
}
buffer_size = 32768;
buffer = xtrymalloc (buffer_size + HMAC_LEN);
if (!buffer)
{
err = gpg_error_from_syserror ();
fclose (fp);
_gcry_md_close (hd);
return err;
}
nread = fread (buffer, 1, HMAC_LEN, fp);
off += nread;
if (nread < HMAC_LEN)
{
xfree (buffer);
fclose (fp);
_gcry_md_close (hd);
return gpg_error (GPG_ERR_TOO_SHORT);
}
while (1)
{
nread = fread (buffer+HMAC_LEN, 1, buffer_size, fp);
if (nread < buffer_size)
{
if (off - HMAC_LEN <= paddr && paddr <= off + nread)
memset (buffer + HMAC_LEN + paddr - off, 0, HMAC_LEN);
_gcry_md_write (hd, buffer, nread+HMAC_LEN);
off += nread;
break;
}
if (off - HMAC_LEN <= paddr && paddr <= off + nread)
memset (buffer + HMAC_LEN + paddr - off, 0, HMAC_LEN);
_gcry_md_write (hd, buffer, nread);
memcpy (buffer, buffer+buffer_size, HMAC_LEN);
off += nread;
}
if (ferror (fp))
err = gpg_error (GPG_ERR_INV_HANDLE);
else
{
unsigned char *digest;
digest = _gcry_md_read (hd, 0);
if (!memcmp (digest, hmac_for_the_implementation, HMAC_LEN))
/* Success. */
err = 0;
else
err = gpg_error (GPG_ERR_CHECKSUM);
}
_gcry_md_close (hd);
xfree (buffer);
fclose (fp);
return err;
}
/* Run an integrity check on the binary. Returns 0 on success. */
static int
check_binary_integrity (void)
{
gpg_error_t err;
Dl_info info;
const char *key = KEY_FOR_BINARY_CHECK;
void *extra_info;
if (!dladdr1 (hmac_for_the_implementation,
&info, &extra_info, RTLD_DL_LINKMAP))
err = gpg_error_from_syserror ();
else
err = hmac256_check (info.dli_fname, key, extra_info);
reporter ("binary", 0, NULL, err? gpg_strerror (err):NULL);
#ifdef HAVE_SYSLOG
if (err)
syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
"integrity check failed: %s",
gpg_strerror (err));
#endif /*HAVE_SYSLOG*/
return !!err;
}
/* Run self-tests for HMAC-SHA256 algorithm before verifying library integrity.
* Return 0 on success. */
static int
run_hmac_sha256_selftests (int extended)
{
gpg_error_t err;
int anyerr = 0;
err = _gcry_md_selftest (GCRY_MD_SHA256, extended, reporter);
reporter ("digest", GCRY_MD_SHA256, NULL,
err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
err = _gcry_mac_selftest (GCRY_MAC_HMAC_SHA256, extended, reporter);
reporter ("mac", GCRY_MAC_HMAC_SHA256, NULL,
err? gpg_strerror (err):NULL);
if (err)
anyerr = 1;
return anyerr;
}
#endif
/* Run the self-tests. If EXTENDED is true, extended versions of the
selftest are run, that is more tests than required by FIPS. */
gpg_err_code_t
_gcry_fips_run_selftests (int extended)
{
enum module_states result = STATE_ERROR;
gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED;
if (fips_mode ())
fips_new_state (STATE_SELFTEST);
#ifdef ENABLE_HMAC_BINARY_CHECK
if (run_hmac_sha256_selftests (extended))
goto leave;
if (fips_mode ())
{
/* Now check the integrity of the binary. We do this this after
having checked the HMAC code. */
if (check_binary_integrity ())
goto leave;
}
#endif
if (run_cipher_selftests (extended))
goto leave;
if (run_digest_selftests (extended))
goto leave;
if (run_mac_selftests (extended))
goto leave;
if (run_kdf_selftests (extended))
goto leave;
/* Run random tests before the pubkey tests because the latter
require random. */
if (run_random_selftests ())
goto leave;
if (run_pubkey_selftests (extended))
goto leave;
/* All selftests passed. */
result = STATE_OPERATIONAL;
ec = 0;
leave:
if (fips_mode ())
fips_new_state (result);
return ec;
}
/* This function is used to tell the FSM about errors in the library.
The FSM will be put into an error state. This function should not
be called directly but by one of the macros
fips_signal_error (description)
fips_signal_fatal_error (description)
where DESCRIPTION is a string describing the error. */
void
_gcry_fips_signal_error (const char *srcfile, int srcline, const char *srcfunc,
int is_fatal, const char *description)
{
if (!fips_mode ())
return; /* Not required. */
/* Set new state before printing an error. */
fips_new_state (is_fatal? STATE_FATALERROR : STATE_ERROR);
/* Print error. */
log_info ("%serror in libgcrypt, file %s, line %d%s%s: %s\n",
is_fatal? "fatal ":"",
srcfile, srcline,
srcfunc? ", function ":"", srcfunc? srcfunc:"",
description? description : "no description available");
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
"%serror in file %s, line %d%s%s: %s",
is_fatal? "fatal ":"",
srcfile, srcline,
srcfunc? ", function ":"", srcfunc? srcfunc:"",
description? description : "no description available");
#endif /*HAVE_SYSLOG*/
}
/* Perform a state transition to NEW_STATE. If this is an invalid
transition, the module will go into a fatal error state. */
static void
fips_new_state (enum module_states new_state)
{
int ok = 0;
enum module_states last_state;
lock_fsm ();
last_state = current_state;
switch (current_state)
{
case STATE_POWERON:
if (new_state == STATE_INIT
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR)
ok = 1;
break;
case STATE_INIT:
if (new_state == STATE_SELFTEST
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR)
ok = 1;
break;
case STATE_SELFTEST:
if (new_state == STATE_OPERATIONAL
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR)
ok = 1;
break;
case STATE_OPERATIONAL:
if (new_state == STATE_SHUTDOWN
|| new_state == STATE_SELFTEST
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR)
ok = 1;
break;
case STATE_ERROR:
if (new_state == STATE_SHUTDOWN
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR
|| new_state == STATE_SELFTEST)
ok = 1;
break;
case STATE_FATALERROR:
if (new_state == STATE_SHUTDOWN )
ok = 1;
break;
case STATE_SHUTDOWN:
/* We won't see any transition *from* Shutdown because the only
allowed new state is Power-Off and that one can't be
represented. */
break;
}
if (ok)
{
current_state = new_state;
}
unlock_fsm ();
if (!ok || _gcry_log_verbosity (2))
log_info ("libgcrypt state transition %s => %s %s\n",
state2str (last_state), state2str (new_state),
ok? "granted":"denied");
if (!ok)
{
/* Invalid state transition. Halting library. */
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR,
"Libgcrypt error: invalid state transition %s => %s",
state2str (last_state), state2str (new_state));
#endif /*HAVE_SYSLOG*/
fips_noreturn ();
}
else if (new_state == STATE_ERROR || new_state == STATE_FATALERROR)
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_WARNING,
"Libgcrypt notice: state transition %s => %s",
state2str (last_state), state2str (new_state));
#endif /*HAVE_SYSLOG*/
}
}
/* This function should be called to ensure that the execution shall
not continue. */
void
_gcry_fips_noreturn (void)
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_ERR, "Libgcrypt terminated the application");
#endif /*HAVE_SYSLOG*/
fflush (NULL);
abort ();
/*NOTREACHED*/
}
diff --git a/src/g10lib.h b/src/g10lib.h
index d2e718a5..c12cfef3 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -1,478 +1,479 @@
/* g10lib.h - Internal definitions for libgcrypt
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
* 2007, 2011 Free Software Foundation, Inc.
*
* 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 .
*/
/* This header is to be used inside of libgcrypt in place of gcrypt.h.
This way we can better distinguish between internal and external
usage of gcrypt.h. */
#ifndef G10LIB_H
#define G10LIB_H 1
#ifdef _GCRYPT_H
#error gcrypt.h already included
#endif
#ifndef _GCRYPT_IN_LIBGCRYPT
#error something is wrong with config.h
#endif
#include
#include
#include "visibility.h"
#include "types.h"
/* Attribute handling macros. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
#define JNLIB_GCC_M_FUNCTION 1
#define JNLIB_GCC_A_NR __attribute__ ((noreturn))
#define JNLIB_GCC_A_PRINTF( f, a ) __attribute__ ((format (printf,f,a)))
#define JNLIB_GCC_A_NR_PRINTF( f, a ) \
__attribute__ ((noreturn, format (printf,f,a)))
#define GCC_ATTR_NORETURN __attribute__ ((__noreturn__))
#else
#define JNLIB_GCC_A_NR
#define JNLIB_GCC_A_PRINTF( f, a )
#define JNLIB_GCC_A_NR_PRINTF( f, a )
#define GCC_ATTR_NORETURN
#endif
#if __GNUC__ >= 3
/* According to glibc this attribute is available since 2.8 however we
better play safe and use it only with gcc 3 or newer. */
#define GCC_ATTR_FORMAT_ARG(a) __attribute__ ((format_arg (a)))
#else
#define GCC_ATTR_FORMAT_ARG(a)
#endif
/* I am not sure since when the unused attribute is really supported.
In any case it it only needed for gcc versions which print a
warning. Thus let us require gcc >= 3.5. */
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 5 )
#define GCC_ATTR_UNUSED __attribute__ ((unused))
#else
#define GCC_ATTR_UNUSED
#endif
#if __GNUC__ > 3
#define NOINLINE_FUNC __attribute__((noinline))
#else
#define NOINLINE_FUNC
#endif
#if __GNUC__ >= 3
#define LIKELY(expr) __builtin_expect( !!(expr), 1 )
#define UNLIKELY(expr) __builtin_expect( !!(expr), 0 )
#define CONSTANT_P(expr) __builtin_constant_p( expr )
#else
#define LIKELY(expr) (!!(expr))
#define UNLIKELY(expr) (!!(expr))
#define CONSTANT_P(expr) (0)
#endif
/* Gettext macros. */
#define _(a) _gcry_gettext(a)
#define N_(a) (a)
/* Some handy macros */
#ifndef STR
#define STR(v) #v
#endif
#define STR2(v) STR(v)
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member)
#define my_isascii(c) (!((c) & 0x80))
/*-- src/global.c -*/
extern int _gcry_global_any_init_done;
int _gcry_global_is_operational (void);
gcry_err_code_t _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr);
void _gcry_check_heap (const void *a);
void _gcry_pre_syscall (void);
void _gcry_post_syscall (void);
int _gcry_get_debug_flag (unsigned int mask);
char *_gcry_get_config (int mode, const char *what);
/* Malloc functions and common wrapper macros. */
void *_gcry_malloc (size_t n) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_calloc (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_malloc_secure (size_t n) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_calloc_secure (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_realloc (void *a, size_t n);
char *_gcry_strdup (const char *string) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_xmalloc (size_t n) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_xcalloc (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_xmalloc_secure (size_t n) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_xcalloc_secure (size_t n, size_t m) _GCRY_GCC_ATTR_MALLOC;
void *_gcry_xrealloc (void *a, size_t n);
char *_gcry_xstrdup (const char * a) _GCRY_GCC_ATTR_MALLOC;
void _gcry_free (void *a);
int _gcry_is_secure (const void *a) _GCRY_GCC_ATTR_PURE;
#define xtrymalloc(a) _gcry_malloc ((a))
#define xtrycalloc(a,b) _gcry_calloc ((a),(b))
#define xtrymalloc_secure(a) _gcry_malloc_secure ((a))
#define xtrycalloc_secure(a,b) _gcry_calloc_secure ((a),(b))
#define xtryrealloc(a,b) _gcry_realloc ((a),(b))
#define xtrystrdup(a) _gcry_strdup ((a))
#define xmalloc(a) _gcry_xmalloc ((a))
#define xcalloc(a,b) _gcry_xcalloc ((a),(b))
#define xmalloc_secure(a) _gcry_xmalloc_secure ((a))
#define xcalloc_secure(a,b) _gcry_xcalloc_secure ((a),(b))
#define xrealloc(a,b) _gcry_xrealloc ((a),(b))
#define xstrdup(a) _gcry_xstrdup ((a))
#define xfree(a) _gcry_free ((a))
/*-- src/misc.c --*/
#if defined(JNLIB_GCC_M_FUNCTION) || __STDC_VERSION__ >= 199901L
void _gcry_bug (const char *file, int line,
const char *func) GCC_ATTR_NORETURN;
void _gcry_assert_failed (const char *expr, const char *file, int line,
const char *func) GCC_ATTR_NORETURN;
#else
void _gcry_bug (const char *file, int line);
void _gcry_assert_failed (const char *expr, const char *file, int line);
#endif
void _gcry_divide_by_zero (void) JNLIB_GCC_A_NR;
const char *_gcry_gettext (const char *key) GCC_ATTR_FORMAT_ARG(1);
void _gcry_fatal_error(int rc, const char *text ) JNLIB_GCC_A_NR;
void _gcry_logv (int level,
const char *fmt, va_list arg_ptr) JNLIB_GCC_A_PRINTF(2,0);
void _gcry_log( int level, const char *fmt, ... ) JNLIB_GCC_A_PRINTF(2,3);
void _gcry_log_bug( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2);
void _gcry_log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2);
void _gcry_log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
void _gcry_log_info( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
void _gcry_log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
void _gcry_log_printf ( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
void _gcry_log_printhex (const char *text, const void *buffer, size_t length);
void _gcry_log_printmpi (const char *text, gcry_mpi_t mpi);
void _gcry_log_printsxp (const char *text, gcry_sexp_t sexp);
void _gcry_set_log_verbosity( int level );
int _gcry_log_verbosity( int level );
#ifdef JNLIB_GCC_M_FUNCTION
#define BUG() _gcry_bug( __FILE__ , __LINE__, __FUNCTION__ )
#define gcry_assert(expr) (LIKELY(expr)? (void)0 \
: _gcry_assert_failed (STR(expr), __FILE__, __LINE__, __FUNCTION__))
#elif __STDC_VERSION__ >= 199901L
#define BUG() _gcry_bug( __FILE__ , __LINE__, __func__ )
#define gcry_assert(expr) (LIKELY(expr)? (void)0 \
: _gcry_assert_failed (STR(expr), __FILE__, __LINE__, __func__))
#else
#define BUG() _gcry_bug( __FILE__ , __LINE__ )
#define gcry_assert(expr) (LIKELY(expr)? (void)0 \
: _gcry_assert_failed (STR(expr), __FILE__, __LINE__))
#endif
#define log_bug _gcry_log_bug
#define log_fatal _gcry_log_fatal
#define log_error _gcry_log_error
#define log_info _gcry_log_info
#define log_debug _gcry_log_debug
#define log_printf _gcry_log_printf
#define log_printhex _gcry_log_printhex
#define log_printmpi _gcry_log_printmpi
#define log_printsxp _gcry_log_printsxp
/* Compatibility macro. */
#define log_mpidump _gcry_log_printmpi
/* Tokeninze STRING and return a malloced array. */
char **_gcry_strtokenize (const char *string, const char *delim);
/*-- src/hwfeatures.c --*/
#if defined(HAVE_CPU_ARCH_X86)
#define HWF_PADLOCK_RNG (1 << 0)
#define HWF_PADLOCK_AES (1 << 1)
#define HWF_PADLOCK_SHA (1 << 2)
#define HWF_PADLOCK_MMUL (1 << 3)
#define HWF_INTEL_CPU (1 << 4)
#define HWF_INTEL_FAST_SHLD (1 << 5)
#define HWF_INTEL_BMI2 (1 << 6)
#define HWF_INTEL_SSSE3 (1 << 7)
#define HWF_INTEL_SSE4_1 (1 << 8)
#define HWF_INTEL_PCLMUL (1 << 9)
#define HWF_INTEL_AESNI (1 << 10)
#define HWF_INTEL_RDRAND (1 << 11)
#define HWF_INTEL_AVX (1 << 12)
#define HWF_INTEL_AVX2 (1 << 13)
#define HWF_INTEL_FAST_VPGATHER (1 << 14)
#define HWF_INTEL_RDTSC (1 << 15)
#define HWF_INTEL_SHAEXT (1 << 16)
#define HWF_INTEL_VAES_VPCLMUL (1 << 17)
#elif defined(HAVE_CPU_ARCH_ARM)
#define HWF_ARM_NEON (1 << 0)
#define HWF_ARM_AES (1 << 1)
#define HWF_ARM_SHA1 (1 << 2)
#define HWF_ARM_SHA2 (1 << 3)
#define HWF_ARM_PMULL (1 << 4)
#elif defined(HAVE_CPU_ARCH_PPC)
#define HWF_PPC_VCRYPTO (1 << 0)
#define HWF_PPC_ARCH_3_00 (1 << 1)
#define HWF_PPC_ARCH_2_07 (1 << 2)
#elif defined(HAVE_CPU_ARCH_S390X)
#define HWF_S390X_MSA (1 << 0)
#define HWF_S390X_MSA_4 (1 << 1)
#define HWF_S390X_MSA_8 (1 << 2)
#define HWF_S390X_MSA_9 (1 << 3)
#define HWF_S390X_VX (1 << 4)
#endif
gpg_err_code_t _gcry_disable_hw_feature (const char *name);
void _gcry_detect_hw_features (void);
unsigned int _gcry_get_hw_features (void);
const char *_gcry_enum_hw_features (int idx, unsigned int *r_feature);
/*-- mpi/mpiutil.c --*/
const char *_gcry_mpi_get_hw_config (void);
/*-- cipher/pubkey.c --*/
/* FIXME: shouldn't this go into mpi.h? */
#ifndef mpi_powm
#define mpi_powm(w,b,e,m) gcry_mpi_powm( (w), (b), (e), (m) )
#endif
/*-- primegen.c --*/
gcry_err_code_t _gcry_primegen_init (void);
gcry_mpi_t _gcry_generate_secret_prime (unsigned int nbits,
gcry_random_level_t random_level,
int (*extra_check)(void*, gcry_mpi_t),
void *extra_check_arg);
gcry_mpi_t _gcry_generate_public_prime (unsigned int nbits,
gcry_random_level_t random_level,
int (*extra_check)(void*, gcry_mpi_t),
void *extra_check_arg);
gcry_err_code_t _gcry_generate_elg_prime (int mode,
unsigned int pbits,
unsigned int qbits,
gcry_mpi_t g,
gcry_mpi_t *r_prime,
gcry_mpi_t **factors);
gcry_mpi_t _gcry_derive_x931_prime (const gcry_mpi_t xp,
const gcry_mpi_t xp1, const gcry_mpi_t xp2,
const gcry_mpi_t e,
gcry_mpi_t *r_p1, gcry_mpi_t *r_p2);
gpg_err_code_t _gcry_generate_fips186_2_prime
(unsigned int pbits, unsigned int qbits,
const void *seed, size_t seedlen,
gcry_mpi_t *r_q, gcry_mpi_t *r_p,
int *r_counter,
void **r_seed, size_t *r_seedlen);
gpg_err_code_t _gcry_generate_fips186_3_prime
(unsigned int pbits, unsigned int qbits,
const void *seed, size_t seedlen,
gcry_mpi_t *r_q, gcry_mpi_t *r_p,
int *r_counter,
void **r_seed, size_t *r_seedlen, int *r_hashalgo);
gpg_err_code_t _gcry_fips186_4_prime_check (const gcry_mpi_t x,
unsigned int bits);
/* Replacements of missing functions (missing-string.c). */
#ifndef HAVE_STPCPY
char *stpcpy (char *a, const char *b);
#endif
#ifndef HAVE_STRCASECMP
int strcasecmp (const char *a, const char *b) _GCRY_GCC_ATTR_PURE;
#endif
#include "../compat/libcompat.h"
/* Macros used to rename missing functions. */
#ifndef HAVE_STRTOUL
#define strtoul(a,b,c) ((unsigned long)strtol((a),(b),(c)))
#endif
#ifndef HAVE_MEMMOVE
#define memmove(d, s, n) bcopy((s), (d), (n))
#endif
#ifndef HAVE_STRICMP
#define stricmp(a,b) strcasecmp( (a), (b) )
#endif
#ifndef HAVE_ATEXIT
#define atexit(a) (on_exit((a),0))
#endif
#ifndef HAVE_RAISE
#define raise(a) kill(getpid(), (a))
#endif
/* Stack burning. */
#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
#define __gcry_burn_stack_dummy() asm volatile ("":::"memory")
#else
void __gcry_burn_stack_dummy (void);
#endif
void __gcry_burn_stack (unsigned int bytes);
#define _gcry_burn_stack(bytes) \
do { __gcry_burn_stack (bytes); \
__gcry_burn_stack_dummy (); } while(0)
/* To avoid that a compiler optimizes certain memset calls away, this
macro may be used instead. For constant length buffers, memory
wiping is inlined. Dead store elimination of inlined memset is
avoided here by using assembly block after memset. For non-constant
length buffers, memory is wiped through _gcry_fast_wipememory. */
#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
#define fast_wipememory2_inline(_ptr,_set,_len) do { \
memset((_ptr), (_set), (_len)); \
asm volatile ("\n" :: "r" (_ptr) : "memory"); \
} while(0)
#else
#define fast_wipememory2_inline(_ptr,_set,_len) \
_gcry_fast_wipememory2((void *)_ptr, _set, _len)
#endif
#define wipememory2(_ptr,_set,_len) do { \
if (!CONSTANT_P(_len) || !CONSTANT_P(_set)) { \
if (CONSTANT_P(_set) && (_set) == 0) \
_gcry_fast_wipememory((void *)(_ptr), (_len)); \
else \
_gcry_fast_wipememory2((void *)(_ptr), (_set), (_len)); \
} else { \
fast_wipememory2_inline((void *)(_ptr), (_set), (_len)); \
} \
} while(0)
#define wipememory(_ptr,_len) wipememory2((_ptr),0,(_len))
void _gcry_fast_wipememory(void *ptr, size_t len);
void _gcry_fast_wipememory2(void *ptr, int set, size_t len);
/* Digit predicates. */
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define octdigitp(p) (*(p) >= '0' && *(p) <= '7')
#define alphap(a) ( (*(a) >= 'A' && *(a) <= 'Z') \
|| (*(a) >= 'a' && *(a) <= 'z'))
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
/* Init functions. */
gcry_err_code_t _gcry_cipher_init (void);
gcry_err_code_t _gcry_md_init (void);
gcry_err_code_t _gcry_mac_init (void);
gcry_err_code_t _gcry_pk_init (void);
gcry_err_code_t _gcry_secmem_module_init (void);
gcry_err_code_t _gcry_mpi_init (void);
/* Memory management. */
#define GCRY_ALLOC_FLAG_SECURE (1 << 0)
#define GCRY_ALLOC_FLAG_XHINT (1 << 1) /* Called from xmalloc. */
/*-- sexp.c --*/
gcry_err_code_t _gcry_sexp_vbuild (gcry_sexp_t *retsexp, size_t *erroff,
const char *format, va_list arg_ptr);
char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number);
gpg_err_code_t _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
const char *list, va_list arg_ptr);
/*-- fips.c --*/
extern int _gcry_no_fips_mode_required;
void _gcry_initialize_fips_mode (int force);
+int _gcry_fips_to_activate (void);
/* This macro returns true if fips mode is enabled. This is
independent of the fips required finite state machine and only used
to enable fips specific code.
No locking is required because we have the requirement that this
variable is only initialized once with no other threads
existing. */
#define fips_mode() (!_gcry_no_fips_mode_required)
void _gcry_fips_signal_error (const char *srcfile,
int srcline,
const char *srcfunc,
int is_fatal,
const char *description);
#ifdef JNLIB_GCC_M_FUNCTION
# define fips_signal_error(a) \
_gcry_fips_signal_error (__FILE__, __LINE__, __FUNCTION__, 0, (a))
# define fips_signal_fatal_error(a) \
_gcry_fips_signal_error (__FILE__, __LINE__, __FUNCTION__, 1, (a))
#else
# define fips_signal_error(a) \
_gcry_fips_signal_error (__FILE__, __LINE__, NULL, 0, (a))
# define fips_signal_fatal_error(a) \
_gcry_fips_signal_error (__FILE__, __LINE__, NULL, 1, (a))
#endif
int _gcry_fips_indicator (va_list arg_ptr);
int _gcry_fips_is_operational (void);
/* Return true if the library is in the operational state. */
#define fips_is_operational() \
(!_gcry_global_any_init_done ? \
_gcry_global_is_operational() : \
(!fips_mode () || _gcry_global_is_operational ()))
#define fips_not_operational() (GPG_ERR_NOT_OPERATIONAL)
int _gcry_fips_test_operational (void);
int _gcry_fips_test_error_or_operational (void);
gpg_err_code_t _gcry_fips_run_selftests (int extended);
void _gcry_fips_noreturn (void);
#define fips_noreturn() (_gcry_fips_noreturn ())
#endif /* G10LIB_H */
diff --git a/src/global.c b/src/global.c
index 47dd80ec..ad2e95a4 100644
--- a/src/global.c
+++ b/src/global.c
@@ -1,1362 +1,1381 @@
/* 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 .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef HAVE_SYSLOG
# include
#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 ();
}
+#ifdef ENABLE_HMAC_BINARY_CHECK
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7 )
+# define GCC_ATTR_CONSTRUCTOR __attribute__ ((__constructor__))
+
+static void GCC_ATTR_CONSTRUCTOR
+_gcry_global_constructor (void)
+{
+ force_fips_mode = _gcry_fips_to_activate ();
+ if (force_fips_mode)
+ {
+ no_secure_memory = 1;
+ global_init ();
+ _gcry_fips_run_selftests (0);
+ _gcry_random_close_fds ();
+ no_secure_memory = 0;
+ }
+}
+# endif
+#endif /* ENABLE_HMAC_BINARY_CHECK */
/* 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: ... 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_RNDGETENTROPY
"getentropy:"
#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. The
* second field is obsolete and thus empty (used to be used for
* a so-called enforced-fips-mode). The third field has an
* option static string describing the module versions; this is
* an optional configure option. */
gpgrt_fprintf (fp, "fips-mode:%c::%s:\n",
fips_mode ()? 'y':'n',
#ifdef FIPS_MODULE_VERSION
fips_mode () ? FIPS_MODULE_VERSION : ""
#else
""
#endif /* FIPS_MODULE_VERSION */
);
}
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 ();
/* When FIPS enabled, no effect at all. */
if (!fips_mode ())
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:
rc = GPG_ERR_NOT_SUPPORTED;
break;
case GCRYCTL_USE_RANDOM_DAEMON:
rc = GPG_ERR_NOT_SUPPORTED;
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 ())
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 GCRYCTL_FIPS_SERVICE_INDICATOR:
/* Get FIPS Service Indicator for a given algorithm and optional mode.
* Returns GPG_ERR_NO_ERROR if algorithm is allowed or
* GPG_ERR_NOT_SUPPORTED otherwise */
rc = _gcry_fips_indicator (arg_ptr);
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:
/* Obsolete - ignore */
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 ())
{
/* In FIPS mode, we can not use custom allocation handlers because
* fips requires explicit zeroization and we can not guarantee that
* with custom free functions (and we can not do it transparently as
* in free we do not know the zize). */
return;
}
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;
}
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) && !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 (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 && save_errno != 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;
}