Page MenuHome GnuPG

No OneTemporary

diff --git a/random/random.c b/random/random.c
index 5649055e..d714c3c2 100644
--- a/random/random.c
+++ b/random/random.c
@@ -1,562 +1,583 @@
/* random.c - Random number switch
* Copyright (C) 2003, 2006, 2008, 2012 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 <http://www.gnu.org/licenses/>.
*/
/*
This module switches between different implementations of random
number generators and provides a few help functions.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif /*HAVE_SYSLOG*/
#include <ctype.h>
#include "g10lib.h"
#include "random.h"
#include "rand-internal.h"
#include "cipher.h" /* For _gcry_sha1_hash_buffer(). */
-/* The name of a file used to globally configure the RNG. */
-#define RANDOM_CONF_FILE "/etc/gcrypt/random.conf"
+/* The name of a file used to globally configure the RNG.
+ * Do not use this macro directly; use get_random_conf_file. */
+#define RANDOM_CONF_FILE "random.conf"
/* If not NULL a progress function called from certain places and the
opaque value passed along. Registered by
_gcry_register_random_progress (). */
static void (*progress_cb) (void *,const char*,int,int, int );
static void *progress_cb_data;
/* Flags indicating the requested RNG types. */
static struct
{
int standard;
int fips;
int system;
} rng_types;
/* This is the lock we use to protect the buffer used by the nonce
generation. */
GPGRT_LOCK_DEFINE (nonce_buffer_lock);
/* --- Functions --- */
/* Used to register a progress callback. This needs to be called
before any threads are created. */
void
_gcry_register_random_progress (void (*cb)(void *,const char*,int,int,int),
void *cb_data )
{
progress_cb = cb;
progress_cb_data = cb_data;
}
/* This progress function is currently used by the random modules to
give hints on how much more entropy is required. */
void
_gcry_random_progress (const char *what, int printchar, int current, int total)
{
if (progress_cb)
progress_cb (progress_cb_data, what, printchar, current, total);
}
+static const char *
+get_random_conf_file (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static char *fname;
+
+ if (!fname)
+ {
+ const char *sysconfdir = _gcry_get_sysconfdir();
+
+ fname = xmalloc (strlen (sysconfdir) + strlen (RANDOM_CONF_FILE) + 1);
+ strcpy (fname, sysconfdir);
+ strcat (fname, RANDOM_CONF_FILE);
+ }
+ return fname;
+#else
+ return "/etc/gcrypt/" RANDOM_CONF_FILE;
+#endif
+}
+
/* Read a file with configure options. The file is a simple text file
* where empty lines and lines with the first non white-space
* character being '#' are ignored. Supported configure options are:
*
* disable-jent - Disable the jitter based extra entropy generator.
* This sets the RANDOM_CONF_DISABLE_JENT bit.
* only-urandom - Always use /dev/urandom instead of /dev/random.
* This sets the RANDOM_CONF_ONLY_URANDOM bit.
*
* The function returns a bit vector with flags read from the file.
*/
unsigned int
_gcry_random_read_conf (void)
{
- const char *fname = RANDOM_CONF_FILE;
+ const char *fname = get_random_conf_file ();
FILE *fp;
char buffer[256];
char *p, *pend;
int lnr = 0;
unsigned int result = 0;
fp = fopen (fname, "r");
if (!fp)
return result;
for (;;)
{
if (!fgets (buffer, sizeof buffer, fp))
{
if (!feof (fp))
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_WARNING,
"Libgcrypt warning: error reading '%s', line %d",
fname, lnr);
#endif /*HAVE_SYSLOG*/
}
fclose (fp);
return result;
}
lnr++;
for (p=buffer; my_isascii (*p) && isspace (*p); p++)
;
pend = strchr (p, '\n');
if (pend)
*pend = 0;
pend = p + (*p? (strlen (p)-1):0);
for ( ;pend > p; pend--)
if (my_isascii (*pend) && isspace (*pend))
*pend = 0;
if (!*p || *p == '#')
continue;
if (!strcmp (p, "disable-jent"))
result |= RANDOM_CONF_DISABLE_JENT;
else if (!strcmp (p, "only-urandom"))
result |= RANDOM_CONF_ONLY_URANDOM;
else
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_WARNING,
"Libgcrypt warning: unknown option in '%s', line %d",
fname, lnr);
#endif /*HAVE_SYSLOG*/
}
}
}
/* Set the preferred RNG type. This may be called at any time even
before gcry_check_version. Thus we can't assume any thread system
initialization. A type of 0 is used to indicate that any Libgcrypt
initialization has been done.*/
void
_gcry_set_preferred_rng_type (int type)
{
static int any_init;
if (!type)
{
any_init = 1;
}
else if (type == GCRY_RNG_TYPE_STANDARD)
{
rng_types.standard = 1;
}
else if (any_init)
{
/* After any initialization has been done we only allow
upgrading to the standard RNG (handled above). All other
requests are ignored. The idea is that the application needs
to declare a preference for a weaker RNG as soon as possible
and before any library sets a preference. We assume that a
library which uses Libgcrypt calls an init function very
early. This way --- even if the library gets initialized
early by the application --- it is unlikely that it can
select a lower priority RNG.
This scheme helps to ensure that existing unmodified
applications (e.g. gpg2), which don't known about the new RNG
selection system, will continue to use the standard RNG and
not be tricked by some library to use a lower priority RNG.
There are some loopholes here but at least most GnuPG stuff
should be save because it calls src_c{gcry_control
(GCRYCTL_SUSPEND_SECMEM_WARN);} quite early and thus inhibits
switching to a low priority RNG.
*/
}
else if (type == GCRY_RNG_TYPE_FIPS)
{
rng_types.fips = 1;
}
else if (type == GCRY_RNG_TYPE_SYSTEM)
{
rng_types.system = 1;
}
}
/* Initialize this random subsystem. If FULL is false, this function
merely calls the basic initialization of the module and does not do
anything more. Doing this is not really required but when running
in a threaded environment we might get a race condition
otherwise. */
void
_gcry_random_initialize (int full)
{
if (fips_mode ())
_gcry_rngdrbg_inititialize (full);
else if (rng_types.standard)
_gcry_rngcsprng_initialize (full);
else if (rng_types.fips)
_gcry_rngdrbg_inititialize (full);
else if (rng_types.system)
_gcry_rngsystem_initialize (full);
else
_gcry_rngcsprng_initialize (full);
}
/* If possible close file descriptors used by the RNG. */
void
_gcry_random_close_fds (void)
{
/* Note that we can't do that directly because each random system
has its own lock functions which need to be used for accessing
the entropy gatherer. */
if (fips_mode ())
_gcry_rngdrbg_close_fds ();
else if (rng_types.standard)
_gcry_rngcsprng_close_fds ();
else if (rng_types.fips)
_gcry_rngdrbg_close_fds ();
else if (rng_types.system)
_gcry_rngsystem_close_fds ();
else
_gcry_rngcsprng_close_fds ();
}
/* Return the current RNG type. IGNORE_FIPS_MODE is a flag used to
skip the test for FIPS. This is useful, so that we are able to
return the type of the RNG even before we have setup FIPS mode
(note that FIPS mode is enabled by default until it is switched off
by the initialization). This is mostly useful for the regression
test. */
int
_gcry_get_rng_type (int ignore_fips_mode)
{
if (!ignore_fips_mode && fips_mode ())
return GCRY_RNG_TYPE_FIPS;
else if (rng_types.standard)
return GCRY_RNG_TYPE_STANDARD;
else if (rng_types.fips)
return GCRY_RNG_TYPE_FIPS;
else if (rng_types.system)
return GCRY_RNG_TYPE_SYSTEM;
else
return GCRY_RNG_TYPE_STANDARD;
}
void
_gcry_random_dump_stats (void)
{
if (fips_mode ())
_gcry_rngdrbg_dump_stats ();
else
_gcry_rngcsprng_dump_stats ();
_gcry_rndjent_dump_stats ();
}
/* This function should be called during initialization and before
initialization of this module to place the random pools into secure
memory. */
void
_gcry_secure_random_alloc (void)
{
if (fips_mode ())
; /* Not used; the FIPS RNG is always in secure mode. */
else
_gcry_rngcsprng_secure_alloc ();
}
/* This may be called before full initialization to degrade the
quality of the RNG for the sake of a faster running test suite. */
void
_gcry_enable_quick_random_gen (void)
{
if (fips_mode ())
; /* Not used. */
else
_gcry_rngcsprng_enable_quick_gen ();
}
/* This function returns true if no real RNG is available or the
quality of the RNG has been degraded for test purposes. */
int
_gcry_random_is_faked (void)
{
if (fips_mode ())
return _gcry_rngdrbg_is_faked ();
else
return _gcry_rngcsprng_is_faked ();
}
/* Add BUFLEN bytes from BUF to the internal random pool. QUALITY
should be in the range of 0..100 to indicate the goodness of the
entropy added, or -1 for goodness not known. */
gcry_err_code_t
_gcry_random_add_bytes (const void *buf, size_t buflen, int quality)
{
if (fips_mode ())
return 0; /* No need for this in fips mode. */
else if (rng_types.standard)
return gpg_err_code (_gcry_rngcsprng_add_bytes (buf, buflen, quality));
else if (rng_types.fips)
return 0;
else if (rng_types.system)
return 0;
else /* default */
return gpg_err_code (_gcry_rngcsprng_add_bytes (buf, buflen, quality));
}
/* Helper function. */
static void
do_randomize (void *buffer, size_t length, enum gcry_random_level level)
{
if (fips_mode ())
_gcry_rngdrbg_randomize (buffer, length, level);
else if (rng_types.standard)
_gcry_rngcsprng_randomize (buffer, length, level);
else if (rng_types.fips)
_gcry_rngdrbg_randomize (buffer, length, level);
else if (rng_types.system)
_gcry_rngsystem_randomize (buffer, length, level);
else /* default */
_gcry_rngcsprng_randomize (buffer, length, level);
}
/* The public function to return random data of the quality LEVEL.
Returns a pointer to a newly allocated and randomized buffer of
LEVEL and NBYTES length. Caller must free the buffer. */
void *
_gcry_random_bytes (size_t nbytes, enum gcry_random_level level)
{
void *buffer;
buffer = xmalloc (nbytes);
do_randomize (buffer, nbytes, level);
return buffer;
}
/* The public function to return random data of the quality LEVEL;
this version of the function returns the random in a buffer allocated
in secure memory. Caller must free the buffer. */
void *
_gcry_random_bytes_secure (size_t nbytes, enum gcry_random_level level)
{
void *buffer;
/* Historical note (1.3.0--1.4.1): The buffer was only allocated
in secure memory if the pool in random-csprng.c was also set to
use secure memory. */
buffer = xmalloc_secure (nbytes);
do_randomize (buffer, nbytes, level);
return buffer;
}
/* Public function to fill the buffer with LENGTH bytes of
cryptographically strong random bytes. Level GCRY_WEAK_RANDOM is
not very strong, GCRY_STRONG_RANDOM is strong enough for most
usage, GCRY_VERY_STRONG_RANDOM is good for key generation stuff but
may be very slow. */
void
_gcry_randomize (void *buffer, size_t length, enum gcry_random_level level)
{
do_randomize (buffer, length, level);
}
/* This function may be used to specify the file to be used as a seed
file for the PRNG. This function should be called prior to the
initialization of the random module. NAME may not be NULL. */
void
_gcry_set_random_seed_file (const char *name)
{
if (fips_mode ())
; /* No need for this in fips mode. */
else if (rng_types.standard)
_gcry_rngcsprng_set_seed_file (name);
else if (rng_types.fips)
;
else if (rng_types.system)
;
else /* default */
_gcry_rngcsprng_set_seed_file (name);
}
/* If a seed file has been setup, this function may be used to write
back the random numbers entropy pool. */
void
_gcry_update_random_seed_file (void)
{
if (fips_mode ())
; /* No need for this in fips mode. */
else if (rng_types.standard)
_gcry_rngcsprng_update_seed_file ();
else if (rng_types.fips)
;
else if (rng_types.system)
;
else /* default */
_gcry_rngcsprng_update_seed_file ();
}
/* The fast random pool function as called at some places in
libgcrypt. This is merely a wrapper to make sure that this module
is initialized and to lock the pool. Note, that this function is a
NOP unless a random function has been used or _gcry_initialize (1)
has been used. We use this hack so that the internal use of this
function in cipher_open and md_open won't start filling up the
random pool, even if no random will be required by the process. */
void
_gcry_fast_random_poll (void)
{
if (fips_mode ())
; /* No need for this in fips mode. */
else if (rng_types.standard)
_gcry_rngcsprng_fast_poll ();
else if (rng_types.fips)
;
else if (rng_types.system)
;
else /* default */
_gcry_rngcsprng_fast_poll ();
}
/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
void
_gcry_create_nonce (void *buffer, size_t length)
{
static unsigned char nonce_buffer[20+8];
static int nonce_buffer_initialized = 0;
static volatile pid_t my_pid; /* The volatile is there to make sure the
compiler does not optimize the code away
in case the getpid function is badly
attributed. */
volatile pid_t apid;
unsigned char *p;
size_t n;
int err;
/* First check whether we shall use the FIPS nonce generator. This
is only done in FIPS mode, in all other modes, we use our own
nonce generator which is seeded by the RNG actual in use. */
if (fips_mode ())
{
_gcry_rngdrbg_randomize (buffer, length, GCRY_WEAK_RANDOM);
return;
}
/* This is the nonce generator, which formerly lived in
random-csprng.c. It is now used by all RNG types except when in
FIPS mode (not that this means it is also used if the FIPS RNG
has been selected but we are not in fips mode). */
/* Make sure we are initialized. */
_gcry_random_initialize (1);
/* Acquire the nonce buffer lock. */
err = gpgrt_lock_lock (&nonce_buffer_lock);
if (err)
log_fatal ("failed to acquire the nonce buffer lock: %s\n",
gpg_strerror (err));
apid = getpid ();
/* The first time initialize our buffer. */
if (!nonce_buffer_initialized)
{
time_t atime = time (NULL);
pid_t xpid = apid;
my_pid = apid;
if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
BUG ();
/* Initialize the first 20 bytes with a reasonable value so that
a failure of gcry_randomize won't affect us too much. Don't
care about the uninitialized remaining bytes. */
p = nonce_buffer;
memcpy (p, &xpid, sizeof xpid);
p += sizeof xpid;
memcpy (p, &atime, sizeof atime);
/* Initialize the never changing private part of 64 bits. */
_gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
nonce_buffer_initialized = 1;
}
else if ( my_pid != apid )
{
/* We forked. Need to reseed the buffer - doing this for the
private part should be sufficient. */
do_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
/* Update the pid so that we won't run into here again and
again. */
my_pid = apid;
}
/* Create the nonce by hashing the entire buffer, returning the hash
and updating the first 20 bytes of the buffer with this hash. */
for (p = buffer; length > 0; length -= n, p += n)
{
_gcry_sha1_hash_buffer (nonce_buffer,
nonce_buffer, sizeof nonce_buffer);
n = length > 20? 20 : length;
memcpy (p, nonce_buffer, n);
}
/* Release the nonce buffer lock. */
err = gpgrt_lock_unlock (&nonce_buffer_lock);
if (err)
log_fatal ("failed to release the nonce buffer lock: %s\n",
gpg_strerror (err));
}
/* Run the self-tests for the RNG. This is currently only implemented
for the FIPS generator. */
gpg_error_t
_gcry_random_selftest (selftest_report_func_t report)
{
if (fips_mode ())
return _gcry_rngdrbg_selftest (report);
else
return 0; /* No selftests yet. */
}
diff --git a/src/fips.c b/src/fips.c
index 7ae89503..d1aff8a5 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -1,1219 +1,1245 @@
/* fips.c - FIPS mode management
* Copyright (C) 2008 Free Software Foundation, Inc.
- *
+ * Copyright (C) 2025 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 <errno.h>
#include <unistd.h>
#include <string.h>
#ifdef ENABLE_HMAC_BINARY_CHECK
# include <dlfcn.h>
# include <elf.h>
# include <limits.h>
# include <link.h>
#endif
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif /*HAVE_SYSLOG*/
/* The name of the file used to force libgcrypt into fips mode. */
-#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
+/* Note: Always use get_fips_force_file to get this name. */
+#define FIPS_FORCE_FILE "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;
struct gcry_thread_context {
unsigned long fips_service_indicator;
unsigned int flags_reject_non_fips;
};
#ifdef HAVE_GCC_STORAGE_CLASS__THREAD
static __thread struct gcry_thread_context the_tc = {
0, GCRY_FIPS_FLAG_REJECT_DEFAULT
};
#else
#error libgcrypt requires thread-local storage to support FIPS mode
#endif
void
_gcry_thread_context_set_reject (unsigned int flags)
{
the_tc.flags_reject_non_fips = flags;
}
int
_gcry_thread_context_check_rejection (unsigned int flag)
{
return !!(the_tc.flags_reject_non_fips & flag);
}
void
_gcry_thread_context_set_fsi (unsigned long fsi)
{
the_tc.fips_service_indicator = fsi;
}
unsigned long
_gcry_thread_context_get_fsi (void)
{
return the_tc.fips_service_indicator;
}
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))
+
+static const char *
+get_fips_force_file (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static char *fname;
+
+ if (!fname)
+ {
+ const char *sysconfdir = _gcry_get_sysconfdir();
+
+ fname = xmalloc (strlen (sysconfdir) + strlen (FIPS_FORCE_FILE) + 1);
+ strcpy (fname, sysconfdir);
+ strcat (fname, FIPS_FORCE_FILE);
+ }
+ return fname;
+#else
+ return "/etc/gcrypt/" FIPS_FORCE_FILE;
+#endif
+}
+
+
/*
* 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) )
+ if ( !access (get_fips_force_file (), F_OK) )
return 1;
/* Checking based on /proc file properties. */
+#ifndef HAVE_W32_SYSTEM
{
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 ();
}
}
+#endif /* Unix */
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;
}
gpg_err_code_t
_gcry_fips_indicator (void)
{
/* If anything recorded, it means that the operation is not
supported under FIPS mode. */
if (_gcry_thread_context_get_fsi ())
return GPG_ERR_NOT_SUPPORTED;
return 0;
}
int
_gcry_fips_indicator_cipher (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:
case GCRY_CIPHER_MODE_AESWRAP:
return GPG_ERR_NO_ERROR;
default:
return GPG_ERR_NOT_SUPPORTED;
}
default:
return GPG_ERR_NOT_SUPPORTED;
}
}
int
_gcry_fips_indicator_mac (va_list arg_ptr)
{
enum gcry_mac_algos alg = va_arg (arg_ptr, enum gcry_mac_algos);
switch (alg)
{
case GCRY_MAC_CMAC_AES:
case GCRY_MAC_HMAC_SHA1:
case GCRY_MAC_HMAC_SHA224:
case GCRY_MAC_HMAC_SHA256:
case GCRY_MAC_HMAC_SHA384:
case GCRY_MAC_HMAC_SHA512:
case GCRY_MAC_HMAC_SHA512_224:
case GCRY_MAC_HMAC_SHA512_256:
case GCRY_MAC_HMAC_SHA3_224:
case GCRY_MAC_HMAC_SHA3_256:
case GCRY_MAC_HMAC_SHA3_384:
case GCRY_MAC_HMAC_SHA3_512:
return GPG_ERR_NO_ERROR;
default:
return GPG_ERR_NOT_SUPPORTED;
}
}
int
_gcry_fips_indicator_md (va_list arg_ptr)
{
enum gcry_md_algos alg = va_arg (arg_ptr, enum gcry_md_algos);
switch (alg)
{
case GCRY_MD_SHA1:
case GCRY_MD_SHA224:
case GCRY_MD_SHA256:
case GCRY_MD_SHA384:
case GCRY_MD_SHA512:
case GCRY_MD_SHA512_224:
case GCRY_MD_SHA512_256:
case GCRY_MD_SHA3_224:
case GCRY_MD_SHA3_256:
case GCRY_MD_SHA3_384:
case GCRY_MD_SHA3_512:
case GCRY_MD_SHAKE128:
case GCRY_MD_SHAKE256:
case GCRY_MD_CSHAKE128:
case GCRY_MD_CSHAKE256:
return GPG_ERR_NO_ERROR;
default:
return GPG_ERR_NOT_SUPPORTED;
}
}
int
_gcry_fips_indicator_kdf (va_list arg_ptr)
{
enum gcry_kdf_algos alg = va_arg (arg_ptr, enum gcry_kdf_algos);
switch (alg)
{
case GCRY_KDF_PBKDF2:
return GPG_ERR_NO_ERROR;
default:
return GPG_ERR_NOT_SUPPORTED;
}
}
int
_gcry_fips_indicator_function (va_list arg_ptr)
{
const char *function = va_arg (arg_ptr, const char *);
if (strcmp (function, "gcry_pk_sign") == 0 ||
strcmp (function, "gcry_pk_verify") == 0 ||
strcmp (function, "gcry_pk_encrypt") == 0 ||
strcmp (function, "gcry_pk_decrypt") == 0 ||
strcmp (function, "gcry_pk_random_override_new") == 0)
return GPG_ERR_NOT_SUPPORTED;
return GPG_ERR_NO_ERROR;
}
/* Note: the array should be sorted. */
static const char *valid_string_in_sexp[] = {
"curve",
"d",
"data",
"e",
"ecdsa",
"eddsa",
"flags",
"genkey",
"hash",
"n",
"nbits",
"pkcs1",
"private-key",
"pss",
"public-key",
"q",
"r",
"raw",
"rsa",
"rsa-use-e",
"s",
"salt-length",
"sig-val",
"value"
};
static int
compare_string (const void *v1, const void *v2)
{
const char * const *p_str1 = v1;
const char * const *p_str2 = v2;
return strcmp (*p_str1, *p_str2);
}
int
_gcry_fips_indicator_pk_flags (va_list arg_ptr)
{
const char *flag = va_arg (arg_ptr, const char *);
if (bsearch (&flag, valid_string_in_sexp, DIM (valid_string_in_sexp),
sizeof (char *), compare_string))
return GPG_ERR_NO_ERROR;
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[] =
{
#if USE_RSA
GCRY_PK_RSA,
#endif /* USE_RSA */
#if USE_ECC
GCRY_PK_ECC,
#endif /* USE_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
/*
* In the ELF file opened as FP, fill the ELF header to the pointer
* EHDR_P, determine the maximum offset of segments in R_OFFSET.
* Also, find the section which contains the hmac value and return it
* in HMAC. Rewinds FP to the beginning on success.
*/
static gpg_error_t
get_file_offset (FILE *fp, ElfW (Ehdr) *ehdr_p,
unsigned long *r_offset, unsigned char hmac[HMAC_LEN])
{
ElfW (Phdr) phdr;
ElfW (Shdr) shdr;
int i;
unsigned long off_segment = 0;
/* Read the ELF header */
if (fseek (fp, 0, SEEK_SET) != 0)
return gpg_error_from_syserror ();
if (fread (ehdr_p, sizeof (*ehdr_p), 1, fp) != 1)
return gpg_error_from_syserror ();
/* The program header entry size should match the size of the phdr struct */
if (ehdr_p->e_phentsize != sizeof (phdr))
return gpg_error (GPG_ERR_INV_OBJ);
if (ehdr_p->e_phoff == 0)
return gpg_error (GPG_ERR_INV_OBJ);
/* Jump to the first program header */
if (fseek (fp, ehdr_p->e_phoff, SEEK_SET) != 0)
return gpg_error_from_syserror ();
/* Iterate over the program headers, determine the last offset of
segments. */
for (i = 0; i < ehdr_p->e_phnum; i++)
{
unsigned long off;
if (fread (&phdr, sizeof (phdr), 1, fp) != 1)
return gpg_error_from_syserror ();
off = phdr.p_offset + phdr.p_filesz;
if (off_segment < off)
off_segment = off;
}
if (!off_segment)
/* No segment found in the file */
return gpg_error (GPG_ERR_INV_OBJ);
/* The section header entry size should match the size of the shdr struct */
if (ehdr_p->e_shentsize != sizeof (shdr))
return gpg_error (GPG_ERR_INV_OBJ);
if (ehdr_p->e_shoff == 0)
return gpg_error (GPG_ERR_INV_OBJ);
/* Jump to the first section header */
if (fseek (fp, ehdr_p->e_shoff, SEEK_SET) != 0)
return gpg_error_from_syserror ();
/* Iterate over the section headers, determine the note section,
read the hmac value. */
for (i = 0; i < ehdr_p->e_shnum; i++)
{
long off;
if (fread (&shdr, sizeof (shdr), 1, fp) != 1)
return gpg_error_from_syserror ();
off = ftell (fp);
if (off < 0)
return gpg_error_from_syserror ();
if (shdr.sh_type == SHT_NOTE && shdr.sh_flags == 0 && shdr.sh_size == 48)
{
const char header_of_the_note[] = {
0x04, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00,
0xca, 0xfe, 0x2a, 0x8e,
'F', 'D', 'O', 0x00
};
unsigned char header[16];
/* Jump to the note section. */
if (fseek (fp, shdr.sh_offset, SEEK_SET) != 0)
return gpg_error_from_syserror ();
if (fread (header, sizeof (header), 1, fp) != 1)
return gpg_error_from_syserror ();
if (!memcmp (header, header_of_the_note, 16))
{
/* Found. Read the hmac value into HMAC. */
if (fread (hmac, HMAC_LEN, 1, fp) != 1)
return gpg_error_from_syserror ();
break;
}
/* Back to the next section header. */
if (fseek (fp, off, SEEK_SET) != 0)
return gpg_error_from_syserror ();
}
}
if (i == ehdr_p->e_shnum)
/* The note section not found. */
return gpg_error (GPG_ERR_INV_OBJ);
/* Fix up the ELF header, clean all section information. */
ehdr_p->e_shoff = 0;
ehdr_p->e_shentsize = 0;
ehdr_p->e_shnum = 0;
ehdr_p->e_shstrndx = 0;
*r_offset = off_segment;
if (fseek (fp, 0, SEEK_SET) != 0)
return gpg_error_from_syserror ();
return 0;
}
static gpg_error_t
hmac256_check (const char *filename, const char *key)
{
gpg_error_t err;
FILE *fp;
gcry_md_hd_t hd;
const size_t buffer_size = 32768;
size_t nread;
char *buffer;
unsigned long offset = 0;
unsigned long pos = 0;
ElfW (Ehdr) ehdr;
unsigned char hmac[HMAC_LEN];
fp = fopen (filename, "rb");
if (!fp)
return gpg_error (GPG_ERR_INV_OBJ);
err = get_file_offset (fp, &ehdr, &offset, hmac);
if (err)
{
fclose (fp);
return err;
}
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 = xtrymalloc (buffer_size);
if (!buffer)
{
err = gpg_error_from_syserror ();
fclose (fp);
_gcry_md_close (hd);
return err;
}
while (1)
{
nread = fread (buffer, 1, buffer_size, fp);
if (pos + nread >= offset)
nread = offset - pos;
/* Copy the fixed ELF header at the beginning. */
if (pos == 0)
memcpy (buffer, &ehdr, sizeof (ehdr));
_gcry_md_write (hd, buffer, nread);
if (nread < buffer_size)
break;
pos += 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, 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;
if (!dladdr (hmac256_check, &info))
err = gpg_error_from_syserror ();
else
err = hmac256_check (info.dli_fname, key);
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 770ae344..bb735e77 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -1,512 +1,514 @@
/* 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 <http://www.gnu.org/licenses/>.
*/
/* 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 <stdio.h>
#include <stdarg.h>
#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_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_set_gpgrt_post_log_handler (void);
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_RDTSC (1 << 14)
#define HWF_INTEL_SHAEXT (1 << 15)
#define HWF_INTEL_VAES_VPCLMUL (1 << 16)
#define HWF_INTEL_AVX512 (1 << 17)
#define HWF_INTEL_GFNI (1 << 18)
#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)
#define HWF_ARM_SHA3 (1 << 5)
#define HWF_ARM_SM3 (1 << 6)
#define HWF_ARM_SM4 (1 << 7)
#define HWF_ARM_SHA512 (1 << 8)
#define HWF_ARM_SVE (1 << 9)
#define HWF_ARM_SVE2 (1 << 10)
#define HWF_ARM_SVEAES (1 << 11)
#define HWF_ARM_SVEPMULL (1 << 12)
#define HWF_ARM_SVESHA3 (1 << 13)
#define HWF_ARM_SVESM4 (1 << 14)
#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)
#define HWF_PPC_ARCH_3_10 (1 << 3)
#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)
#elif defined(HAVE_CPU_ARCH_RISCV)
#define HWF_RISCV_IMAFDC (1 << 0)
#define HWF_RISCV_B (1 << 1)
#define HWF_RISCV_V (1 << 2)
#define HWF_RISCV_ZBB (1 << 3)
#define HWF_RISCV_ZBC (1 << 4)
#define HWF_RISCV_ZVKB (1 << 5)
#define HWF_RISCV_ZVKG (1 << 6)
#define HWF_RISCV_ZVKNED (1 << 7)
#define HWF_RISCV_ZVKNHA (1 << 8)
#define HWF_RISCV_ZVKNHB (1 << 9)
#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);
+const char *_gcry_get_sysconfdir (void);
+
/*-- 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);
void *_gcry_hex2buffer (const char *string, size_t *r_length);
/*-- 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
gpg_err_code_t _gcry_fips_indicator (void);
int _gcry_fips_indicator_cipher (va_list arg_ptr);
int _gcry_fips_indicator_mac (va_list arg_ptr);
int _gcry_fips_indicator_md (va_list arg_ptr);
int _gcry_fips_indicator_kdf (va_list arg_ptr);
int _gcry_fips_indicator_function (va_list arg_ptr);
int _gcry_fips_indicator_pk_flags (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/hwfeatures.c b/src/hwfeatures.c
index edf8d5df..94070b0c 100644
--- a/src/hwfeatures.c
+++ b/src/hwfeatures.c
@@ -1,266 +1,349 @@
/* hwfeatures.c - Detect hardware features.
* Copyright (C) 2007, 2011 Free Software Foundation, Inc.
* Copyright (C) 2012 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 <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#ifdef HAVE_SYSLOG
# include <syslog.h>
#endif /*HAVE_SYSLOG*/
+#ifdef HAVE_W32_SYSTEM
+#include <winsock2.h> /* Due to the stupid mingw64 requirement to
+ include this header before windows.h which
+ is often implicitly included. */
+#include <shlobj.h>
+#ifndef CSIDL_APPDATA
+#define CSIDL_APPDATA 0x001a
+#endif
+#ifndef CSIDL_LOCAL_APPDATA
+#define CSIDL_LOCAL_APPDATA 0x001c
+#endif
+#ifndef CSIDL_COMMON_APPDATA
+#define CSIDL_COMMON_APPDATA 0x0023
+#endif
+#ifndef CSIDL_FLAG_CREATE
+#define CSIDL_FLAG_CREATE 0x8000
+#endif
+#endif /*HAVE_W32_SYSTEM*/
+
+
#include "g10lib.h"
#include "hwf-common.h"
-/* The name of a file used to globally disable selected features. */
-#define HWF_DENY_FILE "/etc/gcrypt/hwf.deny"
+/* The name of a file used to globally disable selected features.
+ * Note: Always used get_hwf_deny_file to get this name */
+#define HWF_DENY_FILE "hwf.deny"
/* A table to map hardware features to a string.
* Note: Remember to add new HW features to 'doc/gcrypt.texi'. */
static struct
{
unsigned int flag;
const char *desc;
} hwflist[] =
{
#if defined(HAVE_CPU_ARCH_X86)
{ HWF_PADLOCK_RNG, "padlock-rng" },
{ HWF_PADLOCK_AES, "padlock-aes" },
{ HWF_PADLOCK_SHA, "padlock-sha" },
{ HWF_PADLOCK_MMUL, "padlock-mmul"},
{ HWF_INTEL_CPU, "intel-cpu" },
{ HWF_INTEL_FAST_SHLD, "intel-fast-shld" },
{ HWF_INTEL_BMI2, "intel-bmi2" },
{ HWF_INTEL_SSSE3, "intel-ssse3" },
{ HWF_INTEL_SSE4_1, "intel-sse4.1" },
{ HWF_INTEL_PCLMUL, "intel-pclmul" },
{ HWF_INTEL_AESNI, "intel-aesni" },
{ HWF_INTEL_RDRAND, "intel-rdrand" },
{ HWF_INTEL_AVX, "intel-avx" },
{ HWF_INTEL_AVX2, "intel-avx2" },
{ HWF_INTEL_RDTSC, "intel-rdtsc" },
{ HWF_INTEL_SHAEXT, "intel-shaext" },
{ HWF_INTEL_VAES_VPCLMUL, "intel-vaes-vpclmul" },
{ HWF_INTEL_AVX512, "intel-avx512" },
{ HWF_INTEL_GFNI, "intel-gfni" },
/* Following removed HW feature strings are kept for API compatibility. */
{ 0, "intel-fast-vpgather" },
#elif defined(HAVE_CPU_ARCH_ARM)
{ HWF_ARM_NEON, "arm-neon" },
{ HWF_ARM_AES, "arm-aes" },
{ HWF_ARM_SHA1, "arm-sha1" },
{ HWF_ARM_SHA2, "arm-sha2" },
{ HWF_ARM_PMULL, "arm-pmull" },
{ HWF_ARM_SHA3, "arm-sha3" },
{ HWF_ARM_SM3, "arm-sm3" },
{ HWF_ARM_SM4, "arm-sm4" },
{ HWF_ARM_SHA512, "arm-sha512" },
{ HWF_ARM_SVE, "arm-sve" },
{ HWF_ARM_SVE2, "arm-sve2" },
{ HWF_ARM_SVEAES, "arm-sveaes" },
{ HWF_ARM_SVEPMULL, "arm-svepmull" },
{ HWF_ARM_SVESHA3, "arm-svesha3" },
{ HWF_ARM_SVESM4, "arm-svesm4" },
#elif defined(HAVE_CPU_ARCH_PPC)
{ HWF_PPC_VCRYPTO, "ppc-vcrypto" },
{ HWF_PPC_ARCH_3_00, "ppc-arch_3_00" },
{ HWF_PPC_ARCH_2_07, "ppc-arch_2_07" },
{ HWF_PPC_ARCH_3_10, "ppc-arch_3_10" },
#elif defined(HAVE_CPU_ARCH_S390X)
{ HWF_S390X_MSA, "s390x-msa" },
{ HWF_S390X_MSA_4, "s390x-msa-4" },
{ HWF_S390X_MSA_8, "s390x-msa-8" },
{ HWF_S390X_MSA_9, "s390x-msa-9" },
{ HWF_S390X_VX, "s390x-vx" },
#elif defined(HAVE_CPU_ARCH_RISCV)
{ HWF_RISCV_IMAFDC, "riscv-imafdc" },
{ HWF_RISCV_B, "riscv-b" },
{ HWF_RISCV_V, "riscv-v" },
{ HWF_RISCV_ZBB, "riscv-zbb" },
{ HWF_RISCV_ZBC, "riscv-zbc" },
{ HWF_RISCV_ZVKB, "riscv-zvkb" },
{ HWF_RISCV_ZVKG, "riscv-zvkg" },
{ HWF_RISCV_ZVKNED, "riscv-zvkned" },
{ HWF_RISCV_ZVKNHA, "riscv-zvknha" },
{ HWF_RISCV_ZVKNHB, "riscv-zvknhb" },
#endif
};
/* A bit vector with the hardware features which shall not be used.
This variable must be set prior to any initialization. */
static unsigned int disabled_hw_features;
/* A bit vector describing the hardware features currently
available. */
static unsigned int hw_features;
+static const char *
+get_hwf_deny_file (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static char *fname;
+
+ if (!fname)
+ {
+ const char *sysconfdir = _gcry_get_sysconfdir();
+
+ fname = xmalloc (strlen (sysconfdir) + strlen (HWF_DENY_FILE) + 1);
+ strcpy (fname, sysconfdir);
+ strcat (fname, HWF_DENY_FILE);
+ }
+ return fname;
+#else
+ return "/etc/gcrypt/" HWF_DENY_FILE;
+#endif
+}
+
+
/* Disable a feature by name. This function must be called *before*
_gcry_detect_hw_features is called. */
gpg_err_code_t
_gcry_disable_hw_feature (const char *name)
{
int i;
size_t n1, n2;
while (name && *name)
{
n1 = strcspn (name, ":,");
if (!n1)
;
else if (n1 == 3 && !strncmp (name, "all", 3))
disabled_hw_features = ~0;
else
{
for (i=0; i < DIM (hwflist); i++)
{
n2 = strlen (hwflist[i].desc);
if (n1 == n2 && !strncmp (hwflist[i].desc, name, n2))
{
disabled_hw_features |= hwflist[i].flag;
break;
}
}
if (!(i < DIM (hwflist)))
return GPG_ERR_INV_NAME;
}
name += n1;
if (*name)
name++; /* Skip delimiter ':' or ','. */
}
return 0;
}
/* Return a bit vector describing the available hardware features.
The HWF_ constants are used to test for them. */
unsigned int
_gcry_get_hw_features (void)
{
return hw_features;
}
/* Enumerate all features. The caller is expected to start with an
IDX of 0 and then increment IDX until NULL is returned. */
const char *
_gcry_enum_hw_features (int idx, unsigned int *r_feature)
{
if (idx < 0 || idx >= DIM (hwflist))
return NULL;
if (r_feature)
*r_feature = hwflist[idx].flag;
return hwflist[idx].desc;
}
/* Read a file with features which shall not be used. The file is a
simple text file where empty lines and lines with the first non
white-space character being '#' are ignored. */
static void
parse_hwf_deny_file (void)
{
- const char *fname = HWF_DENY_FILE;
+ const char *fname = get_hwf_deny_file ();
FILE *fp;
char buffer[256];
char *p, *pend;
int lnr = 0;
fp = fopen (fname, "r");
if (!fp)
return;
for (;;)
{
if (!fgets (buffer, sizeof buffer, fp))
{
if (!feof (fp))
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_WARNING,
"Libgcrypt warning: error reading '%s', line %d",
fname, lnr);
#endif /*HAVE_SYSLOG*/
}
fclose (fp);
return;
}
lnr++;
for (p=buffer; my_isascii (*p) && isspace (*p); p++)
;
pend = strchr (p, '\n');
if (pend)
*pend = 0;
pend = p + (*p? (strlen (p)-1):0);
for ( ;pend > p; pend--)
if (my_isascii (*pend) && isspace (*pend))
*pend = 0;
if (!*p || *p == '#')
continue;
if (_gcry_disable_hw_feature (p) == GPG_ERR_INV_NAME)
{
#ifdef HAVE_SYSLOG
syslog (LOG_USER|LOG_WARNING,
"Libgcrypt warning: unknown feature in '%s', line %d",
fname, lnr);
#endif /*HAVE_SYSLOG*/
}
}
}
/* Detect the available hardware features. This function is called
once right at startup and we assume that no other threads are
running. */
void
_gcry_detect_hw_features (void)
{
hw_features = 0;
parse_hwf_deny_file ();
#if defined (HAVE_CPU_ARCH_X86)
{
hw_features = _gcry_hwf_detect_x86 ();
}
#elif defined (HAVE_CPU_ARCH_ARM)
{
hw_features = _gcry_hwf_detect_arm ();
}
#elif defined (HAVE_CPU_ARCH_PPC)
{
hw_features = _gcry_hwf_detect_ppc ();
}
#elif defined (HAVE_CPU_ARCH_S390X)
{
hw_features = _gcry_hwf_detect_s390x ();
}
#elif defined (HAVE_CPU_ARCH_RISCV)
{
hw_features = _gcry_hwf_detect_riscv ();
}
#endif
hw_features &= ~disabled_hw_features;
}
+
+
+/* This is a helper function to return the system configuration
+ * directory on Windows. On Windows the respective function is used
+ * and if that fails a standard name is used. On Unix "/etc/gcrypt/"
+ * is returned. There is always a traling slash. */
+const char *
+_gcry_get_sysconfdir (void)
+{
+#ifdef HAVE_W32_SYSTEM
+ static char *appdata;
+
+ if (!appdata)
+ {
+ HRESULT (WINAPI *func)(HWND,int,HANDLE,DWORD,LPSTR);
+ void *handle;
+ char *buf;
+
+ handle = LoadLibraryEx ("shell32.dll", NULL, 0);
+ if (handle)
+ {
+ buf = xmalloc (MAX_PATH+17+1); /* Space for "/GNU/etc/gcrypt/" */
+ func = GetProcAddress (handle, "SHGetFolderPathA");
+ if (func && func (NULL, CSIDL_COMMON_APPDATA, NULL, 0, buf) >= 0)
+ {
+ appdata = xmalloc (strlen (buf) + 17 + 1);
+ strcpy (appdata, buf);
+ strcat (appdata, "/GNU/etc/gcrypt/");
+ }
+ xfree (buf);
+ CloseHandle (handle);
+ }
+ if (!appdata)
+ appdata = xstrdup ("c:/ProgramData/GNU/etc/gcrypt/");
+ }
+
+ return appdata;
+#else /*!HAVE_W32_SYSTEM*/
+ return "/etc/gcrypt/";
+#endif /*!HAVE_W32_SYSTEM*/
+}

File Metadata

Mime Type
text/x-diff
Expires
Sat, Dec 6, 10:41 PM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a5/27/f27128758ee6500f1ded94a9e30c

Event Timeline