diff --git a/cipher/md.c b/cipher/md.c
index c1f585f..dfee3df 100644
--- a/cipher/md.c
+++ b/cipher/md.c
@@ -411,11 +411,8 @@ md_enable (gcry_md_hd_t hd, int algorithm)
if (!err && algorithm == GCRY_MD_MD5 && fips_mode ())
{
- _gcry_inactivate_fips_mode ("MD5 used");
if (_gcry_enforced_fips_mode () )
{
- /* We should never get to here because we do not register
- MD5 in enforced fips mode. But better throw an error. */
err = GPG_ERR_DIGEST_ALGO;
}
}
diff --git a/cipher/md.c.fips-ctor b/cipher/md.c.fips-ctor
new file mode 100644
index 0000000..c1f585f
--- /dev/null
+++ b/cipher/md.c.fips-ctor
@@ -0,0 +1,1478 @@
+/* md.c - message digest dispatcher
+ * Copyright (C) 1998, 1999, 2002, 2003, 2006,
+ * 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2013, 2014 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 "g10lib.h"
+#include "cipher.h"
+
+
+/* This is the list of the digest implementations included in
+ libgcrypt. */
+static gcry_md_spec_t *digest_list[] =
+ {
+#if USE_CRC
+ &_gcry_digest_spec_crc32,
+ &_gcry_digest_spec_crc32_rfc1510,
+ &_gcry_digest_spec_crc24_rfc2440,
+#endif
+#if USE_SHA1
+ &_gcry_digest_spec_sha1,
+#endif
+#if USE_SHA256
+ &_gcry_digest_spec_sha256,
+ &_gcry_digest_spec_sha224,
+#endif
+#if USE_SHA512
+ &_gcry_digest_spec_sha512,
+ &_gcry_digest_spec_sha384,
+#endif
+#if USE_SHA3
+ &_gcry_digest_spec_sha3_224,
+ &_gcry_digest_spec_sha3_256,
+ &_gcry_digest_spec_sha3_384,
+ &_gcry_digest_spec_sha3_512,
+ &_gcry_digest_spec_shake128,
+ &_gcry_digest_spec_shake256,
+#endif
+#if USE_GOST_R_3411_94
+ &_gcry_digest_spec_gost3411_94,
+ &_gcry_digest_spec_gost3411_cp,
+#endif
+#if USE_GOST_R_3411_12
+ &_gcry_digest_spec_stribog_256,
+ &_gcry_digest_spec_stribog_512,
+#endif
+#if USE_WHIRLPOOL
+ &_gcry_digest_spec_whirlpool,
+#endif
+#if USE_RMD160
+ &_gcry_digest_spec_rmd160,
+#endif
+#if USE_TIGER
+ &_gcry_digest_spec_tiger,
+ &_gcry_digest_spec_tiger1,
+ &_gcry_digest_spec_tiger2,
+#endif
+#if USE_MD5
+ &_gcry_digest_spec_md5,
+#endif
+#if USE_MD4
+ &_gcry_digest_spec_md4,
+#endif
+#if USE_MD2
+ &_gcry_digest_spec_md2,
+#endif
+#if USE_BLAKE2
+ &_gcry_digest_spec_blake2b_512,
+ &_gcry_digest_spec_blake2b_384,
+ &_gcry_digest_spec_blake2b_256,
+ &_gcry_digest_spec_blake2b_160,
+ &_gcry_digest_spec_blake2s_256,
+ &_gcry_digest_spec_blake2s_224,
+ &_gcry_digest_spec_blake2s_160,
+ &_gcry_digest_spec_blake2s_128,
+#endif
+ NULL
+ };
+
+
+typedef struct gcry_md_list
+{
+ gcry_md_spec_t *spec;
+ struct gcry_md_list *next;
+ size_t actual_struct_size; /* Allocated size of this structure. */
+ PROPERLY_ALIGNED_TYPE context;
+} GcryDigestEntry;
+
+/* This structure is put right after the gcry_md_hd_t buffer, so that
+ * only one memory block is needed. */
+struct gcry_md_context
+{
+ int magic;
+ size_t actual_handle_size; /* Allocated size of this handle. */
+ FILE *debug;
+ struct {
+ unsigned int secure: 1;
+ unsigned int finalized:1;
+ unsigned int bugemu1:1;
+ unsigned int hmac:1;
+ } flags;
+ GcryDigestEntry *list;
+};
+
+
+#define CTX_MAGIC_NORMAL 0x11071961
+#define CTX_MAGIC_SECURE 0x16917011
+
+static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo);
+static void md_close (gcry_md_hd_t a);
+static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen);
+static byte *md_read( gcry_md_hd_t a, int algo );
+static int md_get_algo( gcry_md_hd_t a );
+static int md_digest_length( int algo );
+static void md_start_debug ( gcry_md_hd_t a, const char *suffix );
+static void md_stop_debug ( gcry_md_hd_t a );
+
+
+
+static int
+map_algo (int algo)
+{
+ return algo;
+}
+
+
+/* Return the spec structure for the hash algorithm ALGO. For an
+ unknown algorithm NULL is returned. */
+static gcry_md_spec_t *
+spec_from_algo (int algo)
+{
+ int idx;
+ gcry_md_spec_t *spec;
+
+ algo = map_algo (algo);
+
+ for (idx = 0; (spec = digest_list[idx]); idx++)
+ if (algo == spec->algo)
+ return spec;
+ return NULL;
+}
+
+
+/* Lookup a hash's spec by its name. */
+static gcry_md_spec_t *
+spec_from_name (const char *name)
+{
+ gcry_md_spec_t *spec;
+ int idx;
+
+ for (idx=0; (spec = digest_list[idx]); idx++)
+ {
+ if (!stricmp (name, spec->name))
+ return spec;
+ }
+
+ return NULL;
+}
+
+
+/* Lookup a hash's spec by its OID. */
+static gcry_md_spec_t *
+spec_from_oid (const char *oid)
+{
+ gcry_md_spec_t *spec;
+ gcry_md_oid_spec_t *oid_specs;
+ int idx, j;
+
+ for (idx=0; (spec = digest_list[idx]); idx++)
+ {
+ oid_specs = spec->oids;
+ if (oid_specs)
+ {
+ for (j = 0; oid_specs[j].oidstring; j++)
+ if (!stricmp (oid, oid_specs[j].oidstring))
+ return spec;
+ }
+ }
+
+ return NULL;
+}
+
+
+static gcry_md_spec_t *
+search_oid (const char *oid, gcry_md_oid_spec_t *oid_spec)
+{
+ gcry_md_spec_t *spec;
+ int i;
+
+ if (!oid)
+ return NULL;
+
+ if (!strncmp (oid, "oid.", 4) || !strncmp (oid, "OID.", 4))
+ oid += 4;
+
+ spec = spec_from_oid (oid);
+ if (spec && spec->oids)
+ {
+ for (i = 0; spec->oids[i].oidstring; i++)
+ if (!stricmp (oid, spec->oids[i].oidstring))
+ {
+ if (oid_spec)
+ *oid_spec = spec->oids[i];
+ return spec;
+ }
+ }
+
+ return NULL;
+}
+
+
+/****************
+ * Map a string to the digest algo
+ */
+int
+_gcry_md_map_name (const char *string)
+{
+ gcry_md_spec_t *spec;
+
+ if (!string)
+ return 0;
+
+ /* If the string starts with a digit (optionally prefixed with
+ either "OID." or "oid."), we first look into our table of ASN.1
+ object identifiers to figure out the algorithm */
+ spec = search_oid (string, NULL);
+ if (spec)
+ return spec->algo;
+
+ /* Not found, search a matching digest name. */
+ spec = spec_from_name (string);
+ if (spec)
+ return spec->algo;
+
+ return 0;
+}
+
+
+/****************
+ * This function simply returns the name of the algorithm or some constant
+ * string when there is no algo. It will never return NULL.
+ * Use the macro gcry_md_test_algo() to check whether the algorithm
+ * is valid.
+ */
+const char *
+_gcry_md_algo_name (int algorithm)
+{
+ gcry_md_spec_t *spec;
+
+ spec = spec_from_algo (algorithm);
+ return spec ? spec->name : "?";
+}
+
+
+static gcry_err_code_t
+check_digest_algo (int algorithm)
+{
+ gcry_md_spec_t *spec;
+
+ spec = spec_from_algo (algorithm);
+ if (spec && !spec->flags.disabled)
+ return 0;
+
+ return GPG_ERR_DIGEST_ALGO;
+
+}
+
+
+/****************
+ * Open a message digest handle for use with algorithm ALGO.
+ * More algorithms may be added by md_enable(). The initial algorithm
+ * may be 0.
+ */
+static gcry_err_code_t
+md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
+{
+ gcry_err_code_t err = 0;
+ int secure = !!(flags & GCRY_MD_FLAG_SECURE);
+ int hmac = !!(flags & GCRY_MD_FLAG_HMAC);
+ int bufsize = secure ? 512 : 1024;
+ struct gcry_md_context *ctx;
+ gcry_md_hd_t hd;
+ size_t n;
+
+ /* Allocate a memory area to hold the caller visible buffer with it's
+ * control information and the data required by this module. Set the
+ * context pointer at the beginning to this area.
+ * We have to use this strange scheme because we want to hide the
+ * internal data but have a variable sized buffer.
+ *
+ * +---+------+---........------+-------------+
+ * !ctx! bctl ! buffer ! private !
+ * +---+------+---........------+-------------+
+ * ! ^
+ * !---------------------------!
+ *
+ * We have to make sure that private is well aligned.
+ */
+ n = sizeof (struct gcry_md_handle) + bufsize;
+ n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1)
+ / sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE);
+
+ /* Allocate and set the Context pointer to the private data */
+ if (secure)
+ hd = xtrymalloc_secure (n + sizeof (struct gcry_md_context));
+ else
+ hd = xtrymalloc (n + sizeof (struct gcry_md_context));
+
+ if (! hd)
+ err = gpg_err_code_from_errno (errno);
+
+ if (! err)
+ {
+ hd->ctx = ctx = (void *) ((char *) hd + n);
+ /* Setup the globally visible data (bctl in the diagram).*/
+ hd->bufsize = n - sizeof (struct gcry_md_handle) + 1;
+ hd->bufpos = 0;
+
+ /* Initialize the private data. */
+ memset (hd->ctx, 0, sizeof *hd->ctx);
+ ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
+ ctx->actual_handle_size = n + sizeof (struct gcry_md_context);
+ ctx->flags.secure = secure;
+ ctx->flags.hmac = hmac;
+ ctx->flags.bugemu1 = !!(flags & GCRY_MD_FLAG_BUGEMU1);
+ }
+
+ if (! err)
+ {
+ /* Hmmm, should we really do that? - yes [-wk] */
+ _gcry_fast_random_poll ();
+
+ if (algo)
+ {
+ err = md_enable (hd, algo);
+ if (err)
+ md_close (hd);
+ }
+ }
+
+ if (! err)
+ *h = hd;
+
+ return err;
+}
+
+/* Create a message digest object for algorithm ALGO. FLAGS may be
+ given as an bitwise OR of the gcry_md_flags values. ALGO may be
+ given as 0 if the algorithms to be used are later set using
+ gcry_md_enable. H is guaranteed to be a valid handle or NULL on
+ error. */
+gcry_err_code_t
+_gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
+{
+ gcry_err_code_t rc;
+ gcry_md_hd_t hd;
+
+ if ((flags & ~(GCRY_MD_FLAG_SECURE
+ | GCRY_MD_FLAG_HMAC
+ | GCRY_MD_FLAG_BUGEMU1)))
+ rc = GPG_ERR_INV_ARG;
+ else
+ rc = md_open (&hd, algo, flags);
+
+ *h = rc? NULL : hd;
+ return rc;
+}
+
+
+
+static gcry_err_code_t
+md_enable (gcry_md_hd_t hd, int algorithm)
+{
+ struct gcry_md_context *h = hd->ctx;
+ gcry_md_spec_t *spec;
+ GcryDigestEntry *entry;
+ gcry_err_code_t err = 0;
+
+ for (entry = h->list; entry; entry = entry->next)
+ if (entry->spec->algo == algorithm)
+ return 0; /* Already enabled */
+
+ spec = spec_from_algo (algorithm);
+ if (!spec)
+ {
+ log_debug ("md_enable: algorithm %d not available\n", algorithm);
+ err = GPG_ERR_DIGEST_ALGO;
+ }
+
+
+ if (!err && algorithm == GCRY_MD_MD5 && fips_mode ())
+ {
+ _gcry_inactivate_fips_mode ("MD5 used");
+ if (_gcry_enforced_fips_mode () )
+ {
+ /* We should never get to here because we do not register
+ MD5 in enforced fips mode. But better throw an error. */
+ err = GPG_ERR_DIGEST_ALGO;
+ }
+ }
+
+ if (!err && h->flags.hmac && spec->read == NULL)
+ {
+ /* Expandable output function cannot act as part of HMAC. */
+ err = GPG_ERR_DIGEST_ALGO;
+ }
+
+ if (!err)
+ {
+ size_t size = (sizeof (*entry)
+ + spec->contextsize * (h->flags.hmac? 3 : 1)
+ - sizeof (entry->context));
+
+ /* And allocate a new list entry. */
+ if (h->flags.secure)
+ entry = xtrymalloc_secure (size);
+ else
+ entry = xtrymalloc (size);
+
+ if (! entry)
+ err = gpg_err_code_from_errno (errno);
+ else
+ {
+ entry->spec = spec;
+ entry->next = h->list;
+ entry->actual_struct_size = size;
+ h->list = entry;
+
+ /* And init this instance. */
+ entry->spec->init (&entry->context.c,
+ h->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0);
+ }
+ }
+
+ return err;
+}
+
+
+gcry_err_code_t
+_gcry_md_enable (gcry_md_hd_t hd, int algorithm)
+{
+ return md_enable (hd, algorithm);
+}
+
+
+static gcry_err_code_t
+md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
+{
+ gcry_err_code_t err = 0;
+ struct gcry_md_context *a = ahd->ctx;
+ struct gcry_md_context *b;
+ GcryDigestEntry *ar, *br;
+ gcry_md_hd_t bhd;
+ size_t n;
+
+ if (ahd->bufpos)
+ md_write (ahd, NULL, 0);
+
+ n = (char *) ahd->ctx - (char *) ahd;
+ if (a->flags.secure)
+ bhd = xtrymalloc_secure (n + sizeof (struct gcry_md_context));
+ else
+ bhd = xtrymalloc (n + sizeof (struct gcry_md_context));
+
+ if (!bhd)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto leave;
+ }
+
+ bhd->ctx = b = (void *) ((char *) bhd + n);
+ /* No need to copy the buffer due to the write above. */
+ gcry_assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1));
+ bhd->bufsize = ahd->bufsize;
+ bhd->bufpos = 0;
+ gcry_assert (! ahd->bufpos);
+ memcpy (b, a, sizeof *a);
+ b->list = NULL;
+ b->debug = NULL;
+
+ /* Copy the complete list of algorithms. The copied list is
+ reversed, but that doesn't matter. */
+ for (ar = a->list; ar; ar = ar->next)
+ {
+ if (a->flags.secure)
+ br = xtrymalloc_secure (ar->actual_struct_size);
+ else
+ br = xtrymalloc (ar->actual_struct_size);
+ if (!br)
+ {
+ err = gpg_err_code_from_syserror ();
+ md_close (bhd);
+ goto leave;
+ }
+
+ memcpy (br, ar, ar->actual_struct_size);
+ br->next = b->list;
+ b->list = br;
+ }
+
+ if (a->debug)
+ md_start_debug (bhd, "unknown");
+
+ *b_hd = bhd;
+
+ leave:
+ return err;
+}
+
+
+gcry_err_code_t
+_gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd)
+{
+ gcry_err_code_t rc;
+
+ rc = md_copy (hd, handle);
+ if (rc)
+ *handle = NULL;
+ return rc;
+}
+
+
+/*
+ * Reset all contexts and discard any buffered stuff. This may be used
+ * instead of a md_close(); md_open().
+ */
+void
+_gcry_md_reset (gcry_md_hd_t a)
+{
+ GcryDigestEntry *r;
+
+ /* Note: We allow this even in fips non operational mode. */
+
+ a->bufpos = a->ctx->flags.finalized = 0;
+
+ if (a->ctx->flags.hmac)
+ for (r = a->ctx->list; r; r = r->next)
+ {
+ memcpy (r->context.c, r->context.c + r->spec->contextsize,
+ r->spec->contextsize);
+ }
+ else
+ for (r = a->ctx->list; r; r = r->next)
+ {
+ memset (r->context.c, 0, r->spec->contextsize);
+ (*r->spec->init) (&r->context.c,
+ a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0);
+ }
+}
+
+
+static void
+md_close (gcry_md_hd_t a)
+{
+ GcryDigestEntry *r, *r2;
+
+ if (! a)
+ return;
+ if (a->ctx->debug)
+ md_stop_debug (a);
+ for (r = a->ctx->list; r; r = r2)
+ {
+ r2 = r->next;
+ wipememory (r, r->actual_struct_size);
+ xfree (r);
+ }
+
+ wipememory (a, a->ctx->actual_handle_size);
+ xfree(a);
+}
+
+
+void
+_gcry_md_close (gcry_md_hd_t hd)
+{
+ /* Note: We allow this even in fips non operational mode. */
+ md_close (hd);
+}
+
+
+static void
+md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen)
+{
+ GcryDigestEntry *r;
+
+ if (a->ctx->debug)
+ {
+ if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1)
+ BUG();
+ if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1)
+ BUG();
+ }
+
+ for (r = a->ctx->list; r; r = r->next)
+ {
+ if (a->bufpos)
+ (*r->spec->write) (&r->context.c, a->buf, a->bufpos);
+ (*r->spec->write) (&r->context.c, inbuf, inlen);
+ }
+ a->bufpos = 0;
+}
+
+
+/* Note that this function may be used after finalize and read to keep
+ on writing to the transform function so to mitigate timing
+ attacks. */
+void
+_gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen)
+{
+ md_write (hd, inbuf, inlen);
+}
+
+
+static void
+md_final (gcry_md_hd_t a)
+{
+ GcryDigestEntry *r;
+
+ if (a->ctx->flags.finalized)
+ return;
+
+ if (a->bufpos)
+ md_write (a, NULL, 0);
+
+ for (r = a->ctx->list; r; r = r->next)
+ (*r->spec->final) (&r->context.c);
+
+ a->ctx->flags.finalized = 1;
+
+ if (!a->ctx->flags.hmac)
+ return;
+
+ for (r = a->ctx->list; r; r = r->next)
+ {
+ byte *p;
+ size_t dlen = r->spec->mdlen;
+ byte *hash;
+ gcry_err_code_t err;
+
+ if (r->spec->read == NULL)
+ continue;
+
+ p = r->spec->read (&r->context.c);
+
+ if (a->ctx->flags.secure)
+ hash = xtrymalloc_secure (dlen);
+ else
+ hash = xtrymalloc (dlen);
+ if (!hash)
+ {
+ err = gpg_err_code_from_errno (errno);
+ _gcry_fatal_error (err, NULL);
+ }
+
+ memcpy (hash, p, dlen);
+ memcpy (r->context.c, r->context.c + r->spec->contextsize * 2,
+ r->spec->contextsize);
+ (*r->spec->write) (&r->context.c, hash, dlen);
+ (*r->spec->final) (&r->context.c);
+ xfree (hash);
+ }
+}
+
+
+static gcry_err_code_t
+md_setkey (gcry_md_hd_t h, const unsigned char *key, size_t keylen)
+{
+ gcry_err_code_t rc = 0;
+ GcryDigestEntry *r;
+ int algo_had_setkey = 0;
+
+ if (!h->ctx->list)
+ return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */
+
+ if (h->ctx->flags.hmac)
+ return GPG_ERR_DIGEST_ALGO; /* Tried md_setkey for HMAC md. */
+
+ for (r = h->ctx->list; r; r = r->next)
+ {
+ switch (r->spec->algo)
+ {
+ /* TODO? add spec->init_with_key? */
+ case GCRY_MD_BLAKE2B_512:
+ case GCRY_MD_BLAKE2B_384:
+ case GCRY_MD_BLAKE2B_256:
+ case GCRY_MD_BLAKE2B_160:
+ case GCRY_MD_BLAKE2S_256:
+ case GCRY_MD_BLAKE2S_224:
+ case GCRY_MD_BLAKE2S_160:
+ case GCRY_MD_BLAKE2S_128:
+ algo_had_setkey = 1;
+ memset (r->context.c, 0, r->spec->contextsize);
+ rc = _gcry_blake2_init_with_key (r->context.c,
+ h->ctx->flags.bugemu1
+ ? GCRY_MD_FLAG_BUGEMU1:0,
+ key, keylen, r->spec->algo);
+ break;
+ default:
+ rc = GPG_ERR_DIGEST_ALGO;
+ break;
+ }
+
+ if (rc)
+ break;
+ }
+
+ if (rc && !algo_had_setkey)
+ {
+ /* None of algorithms had setkey implementation, so contexts were not
+ * modified. Just return error. */
+ return rc;
+ }
+ else if (rc && algo_had_setkey)
+ {
+ /* Some of the contexts have been modified, but got error. Reset
+ * all contexts. */
+ _gcry_md_reset (h);
+ return rc;
+ }
+
+ /* Successful md_setkey implies reset. */
+ h->bufpos = h->ctx->flags.finalized = 0;
+
+ return 0;
+}
+
+
+static gcry_err_code_t
+prepare_macpads (gcry_md_hd_t a, const unsigned char *key, size_t keylen)
+{
+ GcryDigestEntry *r;
+
+ if (!a->ctx->list)
+ return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */
+
+ if (!a->ctx->flags.hmac)
+ return GPG_ERR_DIGEST_ALGO; /* Tried prepare_macpads for non-HMAC md. */
+
+ for (r = a->ctx->list; r; r = r->next)
+ {
+ const unsigned char *k;
+ size_t k_len;
+ unsigned char *key_allocated = NULL;
+ int macpad_Bsize;
+ int i;
+
+ switch (r->spec->algo)
+ {
+ /* TODO: add spec->blocksize */
+ case GCRY_MD_SHA3_224:
+ macpad_Bsize = 1152 / 8;
+ break;
+ case GCRY_MD_SHA3_256:
+ macpad_Bsize = 1088 / 8;
+ break;
+ case GCRY_MD_SHA3_384:
+ macpad_Bsize = 832 / 8;
+ break;
+ case GCRY_MD_SHA3_512:
+ macpad_Bsize = 576 / 8;
+ break;
+ case GCRY_MD_SHA384:
+ case GCRY_MD_SHA512:
+ case GCRY_MD_BLAKE2B_512:
+ case GCRY_MD_BLAKE2B_384:
+ case GCRY_MD_BLAKE2B_256:
+ case GCRY_MD_BLAKE2B_160:
+ macpad_Bsize = 128;
+ break;
+ case GCRY_MD_GOSTR3411_94:
+ case GCRY_MD_GOSTR3411_CP:
+ macpad_Bsize = 32;
+ break;
+ default:
+ macpad_Bsize = 64;
+ break;
+ }
+
+ if ( keylen > macpad_Bsize )
+ {
+ k = key_allocated = xtrymalloc_secure (r->spec->mdlen);
+ if (!k)
+ return gpg_err_code_from_errno (errno);
+ _gcry_md_hash_buffer (r->spec->algo, key_allocated, key, keylen);
+ k_len = r->spec->mdlen;
+ gcry_assert ( k_len <= macpad_Bsize );
+ }
+ else
+ {
+ k = key;
+ k_len = keylen;
+ }
+
+ (*r->spec->init) (&r->context.c,
+ a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0);
+ a->bufpos = 0;
+ for (i=0; i < k_len; i++ )
+ _gcry_md_putc (a, k[i] ^ 0x36);
+ for (; i < macpad_Bsize; i++ )
+ _gcry_md_putc (a, 0x36);
+ (*r->spec->write) (&r->context.c, a->buf, a->bufpos);
+ memcpy (r->context.c + r->spec->contextsize, r->context.c,
+ r->spec->contextsize);
+
+ (*r->spec->init) (&r->context.c,
+ a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0);
+ a->bufpos = 0;
+ for (i=0; i < k_len; i++ )
+ _gcry_md_putc (a, k[i] ^ 0x5c);
+ for (; i < macpad_Bsize; i++ )
+ _gcry_md_putc (a, 0x5c);
+ (*r->spec->write) (&r->context.c, a->buf, a->bufpos);
+ memcpy (r->context.c + r->spec->contextsize*2, r->context.c,
+ r->spec->contextsize);
+
+ xfree (key_allocated);
+ }
+
+ a->bufpos = 0;
+ return 0;
+}
+
+
+gcry_err_code_t
+_gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
+{
+ gcry_err_code_t rc = 0;
+
+ (void)buflen; /* Currently not used. */
+
+ switch (cmd)
+ {
+ case GCRYCTL_FINALIZE:
+ md_final (hd);
+ break;
+ case GCRYCTL_START_DUMP:
+ md_start_debug (hd, buffer);
+ break;
+ case GCRYCTL_STOP_DUMP:
+ md_stop_debug ( hd );
+ break;
+ default:
+ rc = GPG_ERR_INV_OP;
+ }
+ return rc;
+}
+
+
+gcry_err_code_t
+_gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
+{
+ gcry_err_code_t rc;
+
+ if (hd->ctx->flags.hmac)
+ {
+ rc = prepare_macpads (hd, key, keylen);
+ if (!rc)
+ _gcry_md_reset (hd);
+ }
+ else
+ {
+ rc = md_setkey (hd, key, keylen);
+ }
+
+ return rc;
+}
+
+
+/* The new debug interface. If SUFFIX is a string it creates an debug
+ file for the context HD. IF suffix is NULL, the file is closed and
+ debugging is stopped. */
+void
+_gcry_md_debug (gcry_md_hd_t hd, const char *suffix)
+{
+ if (suffix)
+ md_start_debug (hd, suffix);
+ else
+ md_stop_debug (hd);
+}
+
+
+/****************
+ * If ALGO is null get the digest for the used algo (which should be
+ * only one)
+ */
+static byte *
+md_read( gcry_md_hd_t a, int algo )
+{
+ GcryDigestEntry *r = a->ctx->list;
+
+ if (! algo)
+ {
+ /* Return the first algorithm */
+ if (r)
+ {
+ if (r->next)
+ log_debug ("more than one algorithm in md_read(0)\n");
+ if (r->spec->read)
+ return r->spec->read (&r->context.c);
+ }
+ }
+ else
+ {
+ for (r = a->ctx->list; r; r = r->next)
+ if (r->spec->algo == algo)
+ {
+ if (r->spec->read)
+ return r->spec->read (&r->context.c);
+ break;
+ }
+ }
+
+ if (r && !r->spec->read)
+ _gcry_fatal_error (GPG_ERR_DIGEST_ALGO,
+ "requested algo has no fixed digest length");
+ else
+ _gcry_fatal_error (GPG_ERR_DIGEST_ALGO, "requested algo not in md context");
+ return NULL;
+}
+
+
+/*
+ * Read out the complete digest, this function implictly finalizes
+ * the hash.
+ */
+byte *
+_gcry_md_read (gcry_md_hd_t hd, int algo)
+{
+ /* This function is expected to always return a digest, thus we
+ can't return an error which we actually should do in
+ non-operational state. */
+ _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
+ return md_read (hd, algo);
+}
+
+
+/****************
+ * If ALGO is null get the digest for the used algo (which should be
+ * only one)
+ */
+static gcry_err_code_t
+md_extract(gcry_md_hd_t a, int algo, void *out, size_t outlen)
+{
+ GcryDigestEntry *r = a->ctx->list;
+
+ if (!algo)
+ {
+ /* Return the first algorithm */
+ if (r && r->spec->extract)
+ {
+ if (r->next)
+ log_debug ("more than one algorithm in md_extract(0)\n");
+ r->spec->extract (&r->context.c, out, outlen);
+ return 0;
+ }
+ }
+ else
+ {
+ for (r = a->ctx->list; r; r = r->next)
+ if (r->spec->algo == algo && r->spec->extract)
+ {
+ r->spec->extract (&r->context.c, out, outlen);
+ return 0;
+ }
+ }
+
+ return GPG_ERR_DIGEST_ALGO;
+}
+
+
+/*
+ * Expand the output from XOF class digest, this function implictly finalizes
+ * the hash.
+ */
+gcry_err_code_t
+_gcry_md_extract (gcry_md_hd_t hd, int algo, void *out, size_t outlen)
+{
+ _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
+ return md_extract (hd, algo, out, outlen);
+}
+
+
+/*
+ * Read out an intermediate digest. Not yet functional.
+ */
+gcry_err_code_t
+_gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen)
+{
+ (void)hd;
+ (void)algo;
+ (void)buffer;
+ (void)buflen;
+
+ /*md_digest ... */
+ fips_signal_error ("unimplemented function called");
+ return GPG_ERR_INTERNAL;
+}
+
+
+/*
+ * Shortcut function to hash a buffer with a given algo. The only
+ * guaranteed supported algorithms are RIPE-MD160 and SHA-1. The
+ * supplied digest buffer must be large enough to store the resulting
+ * hash. No error is returned, the function will abort on an invalid
+ * algo. DISABLED_ALGOS are ignored here. */
+void
+_gcry_md_hash_buffer (int algo, void *digest,
+ const void *buffer, size_t length)
+{
+ if (0)
+ ;
+#if USE_SHA256
+ else if (algo == GCRY_MD_SHA256)
+ _gcry_sha256_hash_buffer (digest, buffer, length);
+#endif
+#if USE_SHA512
+ else if (algo == GCRY_MD_SHA512)
+ _gcry_sha512_hash_buffer (digest, buffer, length);
+#endif
+#if USE_SHA1
+ else if (algo == GCRY_MD_SHA1)
+ _gcry_sha1_hash_buffer (digest, buffer, length);
+#endif
+#if USE_RMD160
+ else if (algo == GCRY_MD_RMD160 && !fips_mode () )
+ _gcry_rmd160_hash_buffer (digest, buffer, length);
+#endif
+ else
+ {
+ /* For the others we do not have a fast function, so we use the
+ normal functions. */
+ gcry_md_hd_t h;
+ gpg_err_code_t err;
+
+ if (algo == GCRY_MD_MD5 && fips_mode ())
+ {
+ _gcry_inactivate_fips_mode ("MD5 used");
+ if (_gcry_enforced_fips_mode () )
+ {
+ /* We should never get to here because we do not register
+ MD5 in enforced fips mode. */
+ _gcry_fips_noreturn ();
+ }
+ }
+
+ err = md_open (&h, algo, 0);
+ if (err)
+ log_bug ("gcry_md_open failed for algo %d: %s",
+ algo, gpg_strerror (gcry_error(err)));
+ md_write (h, (byte *) buffer, length);
+ md_final (h);
+ memcpy (digest, md_read (h, algo), md_digest_length (algo));
+ md_close (h);
+ }
+}
+
+
+/* Shortcut function to hash multiple buffers with a given algo. In
+ contrast to gcry_md_hash_buffer, this function returns an error on
+ invalid arguments or on other problems; disabled algorithms are
+ _not_ ignored but flagged as an error.
+
+ The data to sign is taken from the array IOV which has IOVCNT items.
+
+ The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns
+ this function into a HMAC function; the first item in IOV is then
+ used as the key.
+
+ On success 0 is returned and resulting hash or HMAC is stored at
+ DIGEST which must have been provided by the caller with an
+ appropriate length. */
+gpg_err_code_t
+_gcry_md_hash_buffers (int algo, unsigned int flags, void *digest,
+ const gcry_buffer_t *iov, int iovcnt)
+{
+ int hmac;
+
+ if (!iov || iovcnt < 0)
+ return GPG_ERR_INV_ARG;
+ if (flags & ~(GCRY_MD_FLAG_HMAC))
+ return GPG_ERR_INV_ARG;
+
+ hmac = !!(flags & GCRY_MD_FLAG_HMAC);
+ if (hmac && iovcnt < 1)
+ return GPG_ERR_INV_ARG;
+
+ if (0)
+ ;
+#if USE_SHA256
+ else if (algo == GCRY_MD_SHA256 && !hmac)
+ _gcry_sha256_hash_buffers (digest, iov, iovcnt);
+#endif
+#if USE_SHA512
+ else if (algo == GCRY_MD_SHA512 && !hmac)
+ _gcry_sha512_hash_buffers (digest, iov, iovcnt);
+#endif
+#if USE_SHA1
+ else if (algo == GCRY_MD_SHA1 && !hmac)
+ _gcry_sha1_hash_buffers (digest, iov, iovcnt);
+#endif
+ else
+ {
+ /* For the others we do not have a fast function, so we use the
+ normal functions. */
+ gcry_md_hd_t h;
+ gpg_err_code_t rc;
+ int dlen;
+
+ if (algo == GCRY_MD_MD5 && fips_mode ())
+ {
+ _gcry_inactivate_fips_mode ("MD5 used");
+ if (_gcry_enforced_fips_mode () )
+ {
+ /* We should never get to here because we do not register
+ MD5 in enforced fips mode. */
+ _gcry_fips_noreturn ();
+ }
+ }
+
+ /* Detect SHAKE128 like algorithms which we can't use because
+ * our API does not allow for a variable length digest. */
+ dlen = md_digest_length (algo);
+ if (!dlen)
+ return GPG_ERR_DIGEST_ALGO;
+
+ rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0));
+ if (rc)
+ return rc;
+
+ if (hmac)
+ {
+ rc = _gcry_md_setkey (h,
+ (const char*)iov[0].data + iov[0].off,
+ iov[0].len);
+ if (rc)
+ {
+ md_close (h);
+ return rc;
+ }
+ iov++; iovcnt--;
+ }
+ for (;iovcnt; iov++, iovcnt--)
+ md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len);
+ md_final (h);
+ memcpy (digest, md_read (h, algo), dlen);
+ md_close (h);
+ }
+
+ return 0;
+}
+
+
+static int
+md_get_algo (gcry_md_hd_t a)
+{
+ GcryDigestEntry *r = a->ctx->list;
+
+ if (r && r->next)
+ {
+ fips_signal_error ("possible usage error");
+ log_error ("WARNING: more than one algorithm in md_get_algo()\n");
+ }
+ return r ? r->spec->algo : 0;
+}
+
+
+int
+_gcry_md_get_algo (gcry_md_hd_t hd)
+{
+ return md_get_algo (hd);
+}
+
+
+/****************
+ * Return the length of the digest
+ */
+static int
+md_digest_length (int algorithm)
+{
+ gcry_md_spec_t *spec;
+
+ spec = spec_from_algo (algorithm);
+ return spec? spec->mdlen : 0;
+}
+
+
+/****************
+ * Return the length of the digest in bytes.
+ * This function will return 0 in case of errors.
+ */
+unsigned int
+_gcry_md_get_algo_dlen (int algorithm)
+{
+ return md_digest_length (algorithm);
+}
+
+
+/* Hmmm: add a mode to enumerate the OIDs
+ * to make g10/sig-check.c more portable */
+static const byte *
+md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen)
+{
+ gcry_md_spec_t *spec;
+ const byte *asnoid = NULL;
+
+ spec = spec_from_algo (algorithm);
+ if (spec)
+ {
+ if (asnlen)
+ *asnlen = spec->asnlen;
+ if (mdlen)
+ *mdlen = spec->mdlen;
+ asnoid = spec->asnoid;
+ }
+ else
+ log_bug ("no ASN.1 OID for md algo %d\n", algorithm);
+
+ return asnoid;
+}
+
+
+/****************
+ * Return information about the given cipher algorithm
+ * WHAT select the kind of information returned:
+ * GCRYCTL_TEST_ALGO:
+ * Returns 0 when the specified algorithm is available for use.
+ * buffer and nbytes must be zero.
+ * GCRYCTL_GET_ASNOID:
+ * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only
+ * the required length is returned.
+ * GCRYCTL_SELFTEST
+ * Helper for the regression tests - shall not be used by applications.
+ *
+ * Note: Because this function is in most cases used to return an
+ * integer value, we can make it easier for the caller to just look at
+ * the return value. The caller will in all cases consult the value
+ * and thereby detecting whether a error occurred or not (i.e. while checking
+ * the block size)
+ */
+gcry_err_code_t
+_gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes)
+{
+ gcry_err_code_t rc;
+
+ switch (what)
+ {
+ case GCRYCTL_TEST_ALGO:
+ if (buffer || nbytes)
+ rc = GPG_ERR_INV_ARG;
+ else
+ rc = check_digest_algo (algo);
+ break;
+
+ case GCRYCTL_GET_ASNOID:
+ /* We need to check that the algo is available because
+ md_asn_oid would otherwise raise an assertion. */
+ rc = check_digest_algo (algo);
+ if (!rc)
+ {
+ const char unsigned *asn;
+ size_t asnlen;
+
+ asn = md_asn_oid (algo, &asnlen, NULL);
+ if (buffer && (*nbytes >= asnlen))
+ {
+ memcpy (buffer, asn, asnlen);
+ *nbytes = asnlen;
+ }
+ else if (!buffer && nbytes)
+ *nbytes = asnlen;
+ else
+ {
+ if (buffer)
+ rc = GPG_ERR_TOO_SHORT;
+ else
+ rc = GPG_ERR_INV_ARG;
+ }
+ }
+ break;
+
+ case GCRYCTL_SELFTEST:
+ /* Helper function for the regression tests. */
+ rc = gpg_err_code (_gcry_md_selftest (algo, nbytes? (int)*nbytes : 0,
+ NULL));
+ break;
+
+ default:
+ rc = GPG_ERR_INV_OP;
+ break;
+ }
+
+ return rc;
+}
+
+
+static void
+md_start_debug ( gcry_md_hd_t md, const char *suffix )
+{
+ static int idx=0;
+ char buf[50];
+
+ if (fips_mode ())
+ return;
+
+ if ( md->ctx->debug )
+ {
+ log_debug("Oops: md debug already started\n");
+ return;
+ }
+ idx++;
+ snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix );
+ md->ctx->debug = fopen(buf, "w");
+ if ( !md->ctx->debug )
+ log_debug("md debug: can't open %s\n", buf );
+}
+
+
+static void
+md_stop_debug( gcry_md_hd_t md )
+{
+ if ( md->ctx->debug )
+ {
+ if ( md->bufpos )
+ md_write ( md, NULL, 0 );
+ fclose (md->ctx->debug);
+ md->ctx->debug = NULL;
+ }
+
+ { /* a kludge to pull in the __muldi3 for Solaris */
+ volatile u32 a = (u32)(uintptr_t)md;
+ volatile u64 b = 42;
+ volatile u64 c;
+ c = a * b;
+ (void)c;
+ }
+}
+
+
+
+/*
+ * Return information about the digest handle.
+ * GCRYCTL_IS_SECURE:
+ * Returns 1 when the handle works on secured memory
+ * otherwise 0 is returned. There is no error return.
+ * GCRYCTL_IS_ALGO_ENABLED:
+ * Returns 1 if the algo is enabled for that handle.
+ * The algo must be passed as the address of an int.
+ */
+gcry_err_code_t
+_gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
+{
+ gcry_err_code_t rc = 0;
+
+ switch (cmd)
+ {
+ case GCRYCTL_IS_SECURE:
+ *nbytes = h->ctx->flags.secure;
+ break;
+
+ case GCRYCTL_IS_ALGO_ENABLED:
+ {
+ GcryDigestEntry *r;
+ int algo;
+
+ if ( !buffer || !nbytes || *nbytes != sizeof (int))
+ rc = GPG_ERR_INV_ARG;
+ else
+ {
+ algo = *(int*)buffer;
+
+ *nbytes = 0;
+ for(r=h->ctx->list; r; r = r->next ) {
+ if (r->spec->algo == algo)
+ {
+ *nbytes = 1;
+ break;
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ rc = GPG_ERR_INV_OP;
+ }
+
+ return rc;
+}
+
+
+/* Explicitly initialize this module. */
+gcry_err_code_t
+_gcry_md_init (void)
+{
+ if (fips_mode())
+ {
+ /* disable algorithms that are disallowed in fips */
+ int idx;
+ gcry_md_spec_t *spec;
+
+ for (idx = 0; (spec = digest_list[idx]); idx++)
+ if (!spec->flags.fips)
+ spec->flags.disabled = 1;
+ }
+
+ return 0;
+}
+
+
+int
+_gcry_md_is_secure (gcry_md_hd_t a)
+{
+ size_t value;
+
+ if (_gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value))
+ value = 1; /* It seems to be better to assume secure memory on
+ error. */
+ return value;
+}
+
+
+int
+_gcry_md_is_enabled (gcry_md_hd_t a, int algo)
+{
+ size_t value;
+
+ value = sizeof algo;
+ if (_gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value))
+ value = 0;
+ return value;
+}
+
+
+/* Run the selftests for digest algorithm ALGO with optional reporting
+ function REPORT. */
+gpg_error_t
+_gcry_md_selftest (int algo, int extended, selftest_report_func_t report)
+{
+ gcry_err_code_t ec = 0;
+ gcry_md_spec_t *spec;
+
+ spec = spec_from_algo (algo);
+ if (spec && !spec->flags.disabled && spec->selftest)
+ ec = spec->selftest (algo, extended, report);
+ else
+ {
+ ec = (spec && spec->selftest) ? GPG_ERR_DIGEST_ALGO
+ /* */ : GPG_ERR_NOT_IMPLEMENTED;
+ if (report)
+ report ("digest", algo, "module",
+ (spec && !spec->flags.disabled)?
+ "no selftest available" :
+ spec? "algorithm disabled" : "algorithm not found");
+ }
+
+ return gpg_error (ec);
+}
diff --git a/src/fips.c b/src/fips.c
index 6c59693..14586e6 100644
--- a/src/fips.c
+++ b/src/fips.c
@@ -91,6 +91,31 @@ static void fips_new_state (enum module_states new_state);
+/* Initialize the FSM lock - this function may only
+ be called once and is intended to be run from the library
+ constructor */
+void
+_gcry_initialize_fsm_lock (void)
+{
+ gpg_error_t err;
+ /* 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 ();
+ }
+}
+
/* 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
@@ -100,7 +125,6 @@ void
_gcry_initialize_fips_mode (int force)
{
static int done;
- gpg_error_t err;
/* Make sure we are not accidentally called twice. */
if (done)
@@ -179,24 +203,6 @@ _gcry_initialize_fips_mode (int force)
/* Yes, we are in FIPS mode. */
FILE *fp;
- /* 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 ();
- }
-
-
/* If the FIPS force files exists, is readable and has a number
!= 0 on its first line, we enable the enforced fips mode. */
fp = fopen (FIPS_FORCE_FILE, "r");
@@ -359,16 +365,20 @@ _gcry_fips_is_operational (void)
{
int result;
- if (!fips_mode ())
+ lock_fsm ();
+ if (current_state == STATE_POWERON && !fips_mode ())
+ /* If we are at this point in POWERON state it means the FIPS
+ module installation was not completed. (/etc/system-fips
+ is not present.) */
result = 1;
else
{
- lock_fsm ();
- if (current_state == STATE_INIT)
+ if (current_state == STATE_INIT || current_state == STATE_SELFTEST)
{
- /* 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
+ /* If we are still in the INIT (or SELFTEST) state,
+ we need to run (or finish) 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
@@ -384,9 +394,11 @@ _gcry_fips_is_operational (void)
lock_fsm ();
}
- result = (current_state == STATE_OPERATIONAL);
- unlock_fsm ();
+ result = (current_state == STATE_OPERATIONAL) || !fips_mode ();
+ /* We always run the selftests but ignore the result
+ in non-FIPS mode. */
}
+ unlock_fsm ();
return result;
}
@@ -709,9 +721,25 @@ _gcry_fips_run_selftests (int extended)
{
enum module_states result = STATE_ERROR;
gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED;
+ int in_poweron;
- if (fips_mode ())
- fips_new_state (STATE_SELFTEST);
+ lock_fsm ();
+ in_poweron = (current_state == STATE_POWERON);
+ unlock_fsm ();
+
+ fips_new_state (STATE_SELFTEST);
+
+ /* We first check the integrity of the binary.
+ If run from the constructor we are in POWERON state,
+ we return and finish the remaining selftests before
+ real use of the library. It will be in the POWERON
+ state meanwhile. */
+ if (in_poweron)
+ if (check_binary_integrity ())
+ goto leave;
+
+ if (in_poweron)
+ return 0;
if (run_cipher_selftests (extended))
goto leave;
@@ -730,18 +758,12 @@ _gcry_fips_run_selftests (int extended)
if (run_pubkey_selftests (extended))
goto leave;
- /* Now check the integrity of the binary. We do this this after
- having checked the HMAC code. */
- if (check_binary_integrity ())
- goto leave;
-
/* All selftests passed. */
result = STATE_OPERATIONAL;
ec = 0;
leave:
- if (fips_mode ())
- fips_new_state (result);
+ fips_new_state (result);
return ec;
}
@@ -797,6 +819,7 @@ fips_new_state (enum module_states new_state)
{
case STATE_POWERON:
if (new_state == STATE_INIT
+ || new_state == STATE_SELFTEST
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR)
ok = 1;
@@ -811,6 +834,8 @@ fips_new_state (enum module_states new_state)
case STATE_SELFTEST:
if (new_state == STATE_OPERATIONAL
+ || new_state == STATE_INIT
+ || new_state == STATE_SELFTEST
|| new_state == STATE_ERROR
|| new_state == STATE_FATALERROR)
ok = 1;
diff --git a/src/fips.c.fips-ctor b/src/fips.c.fips-ctor
new file mode 100644
index 0000000..6c59693
--- /dev/null
+++ b/src/fips.c.fips-ctor
@@ -0,0 +1,894 @@
+/* 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
+#endif
+#ifdef HAVE_SYSLOG
+# include
+#endif /*HAVE_SYSLOG*/
+
+#include "g10lib.h"
+#include "cipher-proto.h"
+#include "hmac256.h"
+
+
+/* The name of the file used to force libgcrypt into fips mode. */
+#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
+
+
+/* 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()! */
+static int no_fips_mode_required;
+
+/* Flag to indicate that we are in the enforced FIPS mode. */
+static int enforced_fips_mode;
+
+/* If this flag is set, the application may no longer assume that the
+ process is running in FIPS mode. This flag is protected by the
+ FSM_LOCK. */
+static int inactive_fips_mode;
+
+/* 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))
+
+
+
+/* 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 (!no_fips_mode_required);
+ goto leave;
+ }
+
+ /* 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) )
+ {
+ gcry_assert (!no_fips_mode_required);
+ goto leave;
+ }
+
+ /* 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);
+ gcry_assert (!no_fips_mode_required);
+ goto leave;
+ }
+ 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 ();
+ }
+ }
+
+ /* Fips not not requested, set flag. */
+ no_fips_mode_required = 1;
+
+ leave:
+ if (!no_fips_mode_required)
+ {
+ /* Yes, we are in FIPS mode. */
+ FILE *fp;
+
+ /* 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 ();
+ }
+
+
+ /* If the FIPS force files exists, is readable and has a number
+ != 0 on its first line, we enable the enforced fips mode. */
+ fp = fopen (FIPS_FORCE_FILE, "r");
+ if (fp)
+ {
+ char line[256];
+
+ if (fgets (line, sizeof line, fp) && atoi (line))
+ enforced_fips_mode = 1;
+ fclose (fp);
+ }
+
+ /* 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 ();
+ }
+}
+
+
+/* This function 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. Please use the fips_mode macro
+ instead of calling this function directly. */
+int
+_gcry_fips_mode (void)
+{
+ /* No locking is required because we have the requirement that this
+ variable is only initialized once with no other threads
+ existing. */
+ return !no_fips_mode_required;
+}
+
+
+/* Return a flag telling whether we are in the enforced fips mode. */
+int
+_gcry_enforced_fips_mode (void)
+{
+ if (!_gcry_fips_mode ())
+ return 0;
+ return enforced_fips_mode;
+}
+
+/* Set a flag telling whether we are in the enforced fips mode. */
+void
+_gcry_set_enforced_fips_mode (void)
+{
+ enforced_fips_mode = 1;
+}
+
+/* If we do not want to enforce the fips mode, we can set a flag so
+ that the application may check whether it is still in fips mode.
+ TEXT will be printed as part of a syslog message. This function
+ may only be be called if in fips mode. */
+void
+_gcry_inactivate_fips_mode (const char *text)
+{
+ gcry_assert (_gcry_fips_mode ());
+
+ if (_gcry_enforced_fips_mode () )
+ {
+ /* Get us into the error state. */
+ fips_signal_error (text);
+ return;
+ }
+
+ lock_fsm ();
+ if (!inactive_fips_mode)
+ {
+ inactive_fips_mode = 1;
+ unlock_fsm ();
+#ifdef HAVE_SYSLOG
+ syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+ "%s - FIPS mode inactivated", text);
+#endif /*HAVE_SYSLOG*/
+ }
+ else
+ unlock_fsm ();
+}
+
+
+/* Return the FIPS mode inactive flag. If it is true the FIPS mode is
+ not anymore active. */
+int
+_gcry_is_fips_mode_inactive (void)
+{
+ int flag;
+
+ if (!_gcry_fips_mode ())
+ return 0;
+ lock_fsm ();
+ flag = inactive_fips_mode;
+ unlock_fsm ();
+ return flag;
+}
+
+
+
+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);
+ 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;
+}
+
+
+/* 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_3DES,
+ 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,
+ GCRY_MD_SHA256,
+ 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 all HMAC algorithms. Return 0 on success. */
+static int
+run_hmac_selftests (int extended)
+{
+ static int algos[] =
+ {
+ GCRY_MD_SHA1,
+ GCRY_MD_SHA224,
+ GCRY_MD_SHA256,
+ GCRY_MD_SHA384,
+ GCRY_MD_SHA512,
+ GCRY_MD_SHA3_224,
+ GCRY_MD_SHA3_256,
+ GCRY_MD_SHA3_384,
+ GCRY_MD_SHA3_512,
+ 0
+ };
+ int idx;
+ gpg_error_t err;
+ int anyerr = 0;
+
+ for (idx=0; algos[idx]; idx++)
+ {
+ err = _gcry_hmac_selftest (algos[idx], extended, reporter);
+ reporter ("hmac", 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_DSA,
+ 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
+static int
+get_library_path(const char *libname, const char *symbolname, char *path, size_t pathlen)
+{
+ Dl_info info;
+ void *dl, *sym;
+ int rv = -1;
+
+ dl = dlopen(libname, RTLD_LAZY);
+ if (dl == NULL) {
+ return -1;
+ }
+
+ sym = dlsym(dl, symbolname);
+
+ if (sym != NULL && dladdr(sym, &info)) {
+ strncpy(path, info.dli_fname, pathlen-1);
+ path[pathlen-1] = '\0';
+ rv = 0;
+ }
+
+ dlclose(dl);
+
+ return rv;
+}
+#endif
+
+/* Run an integrity check on the binary. Returns 0 on success. */
+static int
+check_binary_integrity (void)
+{
+#ifdef ENABLE_HMAC_BINARY_CHECK
+ gpg_error_t err;
+ char libpath[4096];
+ unsigned char digest[32];
+ int dlen;
+ char *fname = NULL;
+ const char key[] = "orboDeJITITejsirpADONivirpUkvarP";
+
+ if (get_library_path ("libgcrypt.so.20", "gcry_check_version", libpath, sizeof(libpath)))
+ err = gpg_error_from_syserror ();
+ else
+ {
+ dlen = _gcry_hmac256_file (digest, sizeof digest, libpath,
+ key, strlen (key));
+ if (dlen < 0)
+ err = gpg_error_from_syserror ();
+ else if (dlen != 32)
+ err = gpg_error (GPG_ERR_INTERNAL);
+ else
+ {
+ fname = xtrymalloc (strlen (libpath) + 1 + 5 + 1 );
+ if (!fname)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ FILE *fp;
+ char *p;
+
+ /* Prefix the basename with a dot. */
+ strcpy (fname, libpath);
+ p = strrchr (fname, '/');
+ if (p)
+ p++;
+ else
+ p = fname;
+ memmove (p+1, p, strlen (p)+1);
+ *p = '.';
+ strcat (fname, ".hmac");
+
+ /* Open the file. */
+ fp = fopen (fname, "r");
+ if (!fp)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ /* A buffer of 64 bytes plus one for a LF and one to
+ detect garbage. */
+ unsigned char buffer[64+1+1];
+ const unsigned char *s;
+ int n;
+
+ /* The HMAC files consists of lowercase hex digits
+ with an optional trailing linefeed or optional
+ with two trailing spaces. The latter format
+ allows the use of the usual sha1sum format. Fail
+ if there is any garbage. */
+ err = gpg_error (GPG_ERR_SELFTEST_FAILED);
+ n = fread (buffer, 1, sizeof buffer, fp);
+ if (n == 64
+ || (n == 65 && buffer[64] == '\n')
+ || (n == 66 && buffer[64] == ' ' && buffer[65] == ' '))
+ {
+ buffer[64] = 0;
+ for (n=0, s= buffer;
+ n < 32 && loxdigit_p (s) && loxdigit_p (s+1);
+ n++, s += 2)
+ buffer[n] = loxtoi_2 (s);
+ if ( n == 32 && !memcmp (digest, buffer, 32) )
+ err = 0;
+ }
+ fclose (fp);
+ }
+ }
+ }
+ }
+ reporter ("binary", 0, fname, err? gpg_strerror (err):NULL);
+#ifdef HAVE_SYSLOG
+ if (err)
+ syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
+ "integrity check using `%s' failed: %s",
+ fname? fname:"[?]", gpg_strerror (err));
+#endif /*HAVE_SYSLOG*/
+ xfree (fname);
+ return !!err;
+#else
+ return 0;
+#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);
+
+ if (run_cipher_selftests (extended))
+ goto leave;
+
+ if (run_digest_selftests (extended))
+ goto leave;
+
+ if (run_hmac_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;
+
+ /* Now check the integrity of the binary. We do this this after
+ having checked the HMAC code. */
+ if (check_binary_integrity ())
+ 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 961b515..77b22e1 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -422,6 +422,8 @@ gpg_err_code_t _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
/*-- fips.c --*/
+void _gcry_initialize_fsm_lock (void);
+
void _gcry_initialize_fips_mode (int force);
int _gcry_fips_mode (void);
diff --git a/src/g10lib.h.fips-ctor b/src/g10lib.h.fips-ctor
new file mode 100644
index 0000000..961b515
--- /dev/null
+++ b/src/g10lib.h.fips-ctor
@@ -0,0 +1,469 @@
+/* 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 LIKELY( expr ) __builtin_expect( !!(expr), 1 )
+#define UNLIKELY( expr ) __builtin_expect( !!(expr), 0 )
+#else
+#define LIKELY( expr ) (!!(expr))
+#define UNLIKELY( expr ) (!!(expr))
+#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 -*/
+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 --*/
+#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_ARM_NEON (1 << 15)
+#define HWF_ARM_AES (1 << 16)
+#define HWF_ARM_SHA1 (1 << 17)
+#define HWF_ARM_SHA2 (1 << 18)
+#define HWF_ARM_PMULL (1 << 19)
+
+#define HWF_INTEL_RDTSC (1 << 20)
+
+
+
+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, these
+ macros may be used instead. */
+#define wipememory2(_ptr,_set,_len) do { \
+ volatile char *_vptr=(volatile char *)(_ptr); \
+ size_t _vlen=(_len); \
+ unsigned char _vset=(_set); \
+ fast_wipememory2(_vptr,_vset,_vlen); \
+ while(_vlen) { *_vptr=(_vset); _vptr++; _vlen--; } \
+ } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+
+#define FASTWIPE_T u64
+#define FASTWIPE_MULT (U64_C(0x0101010101010101))
+
+/* Following architectures can handle unaligned accesses fast. */
+#if defined(HAVE_GCC_ATTRIBUTE_PACKED) && \
+ defined(HAVE_GCC_ATTRIBUTE_ALIGNED) && \
+ defined(HAVE_GCC_ATTRIBUTE_MAY_ALIAS) && \
+ (defined(__i386__) || defined(__x86_64__) || \
+ defined(__powerpc__) || defined(__powerpc64__) || \
+ (defined(__arm__) && defined(__ARM_FEATURE_UNALIGNED)) || \
+ defined(__aarch64__))
+#define fast_wipememory2_unaligned_head(_ptr,_set,_len) /*do nothing*/
+typedef struct fast_wipememory_s
+{
+ FASTWIPE_T a;
+} __attribute__((packed, aligned(1), may_alias)) fast_wipememory_t;
+#else
+#define fast_wipememory2_unaligned_head(_vptr,_vset,_vlen) do { \
+ while(UNLIKELY((size_t)(_vptr)&(sizeof(FASTWIPE_T)-1)) && _vlen) \
+ { *_vptr=(_vset); _vptr++; _vlen--; } \
+ } while(0)
+typedef struct fast_wipememory_s
+{
+ FASTWIPE_T a;
+} fast_wipememory_t;
+#endif
+
+/* fast_wipememory2 may leave tail bytes unhandled, in which case tail bytes
+ are handled by wipememory2. */
+#define fast_wipememory2(_vptr,_vset,_vlen) do { \
+ FASTWIPE_T _vset_long = _vset; \
+ fast_wipememory2_unaligned_head(_vptr,_vset,_vlen); \
+ if (_vlen < sizeof(FASTWIPE_T)) \
+ break; \
+ _vset_long *= FASTWIPE_MULT; \
+ do { \
+ volatile fast_wipememory_t *_vptr_long = \
+ (volatile void *)_vptr; \
+ _vptr_long->a = _vset_long; \
+ _vlen -= sizeof(FASTWIPE_T); \
+ _vptr += sizeof(FASTWIPE_T); \
+ } while (_vlen >= sizeof(FASTWIPE_T)); \
+ } while (0)
+
+
+/* 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 --*/
+
+void _gcry_initialize_fips_mode (int force);
+
+int _gcry_fips_mode (void);
+#define fips_mode() _gcry_fips_mode ()
+
+int _gcry_enforced_fips_mode (void);
+
+void _gcry_set_enforced_fips_mode (void);
+
+void _gcry_inactivate_fips_mode (const char *text);
+int _gcry_is_fips_mode_inactive (void);
+
+
+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_is_operational (void);
+#define fips_is_operational() (_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 cd3d9d9..88c8e4c 100644
--- a/src/global.c
+++ b/src/global.c
@@ -141,6 +141,29 @@ global_init (void)
}
+#ifndef FIPS_MODULE_PATH
+#define FIPS_MODULE_PATH "/etc/system-fips"
+#endif
+
+void __attribute__ ((constructor)) _gcry_global_constructor (void)
+{
+ int rv;
+
+ /* We always need the FSM lock to be functional. */
+ _gcry_initialize_fsm_lock ();
+
+ rv = access (FIPS_MODULE_PATH, F_OK);
+ if (rv < 0 && errno != ENOENT)
+ rv = 0;
+
+ if (!rv)
+ {
+ /* We run the integrity check at this point. The remaining
+ selftests are run before use of the library by application. */
+ _gcry_fips_run_selftests (0);
+ }
+}
+
/* 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
@@ -671,8 +694,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
case GCRYCTL_FIPS_MODE_P:
if (fips_mode ()
- && !_gcry_is_fips_mode_inactive ()
- && !no_secure_memory)
+ && !_gcry_is_fips_mode_inactive ())
rc = GPG_ERR_GENERAL; /* Used as TRUE value */
break;
@@ -749,9 +771,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
break;
case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
- if (!any_init_done)
+ if (fips_mode ())
{
- /* Not yet initialized at all. Set the enforced fips mode flag */
+ /* We are in FIPS mode, we can set the enforced fips mode flag. */
_gcry_set_preferred_rng_type (0);
_gcry_set_enforced_fips_mode ();
}
diff --git a/src/global.c.fips-ctor b/src/global.c.fips-ctor
new file mode 100644
index 0000000..cd3d9d9
--- /dev/null
+++ b/src/global.c.fips-ctor
@@ -0,0 +1,1343 @@
+/* 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(). */
+static int 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 (any_init_done)
+ return;
+ any_init_done = 1;
+
+ /* Tell the random module that we have seen an init call. */
+ _gcry_set_preferred_rng_type (0);
+
+ /* Get the system call clamp functions. */
+ if (!pre_syscall_func)
+ gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
+
+ /* See whether the system is in FIPS mode. This needs to come as
+ early as possible but after ATH has been initialized. */
+ _gcry_initialize_fips_mode (force_fips_mode);
+
+ /* Before we do any other initialization we need to test available
+ hardware features. */
+ _gcry_detect_hw_features ();
+
+ /* Initialize the modules - this is mainly allocating some memory and
+ creating mutexes. */
+ err = _gcry_cipher_init ();
+ if (err)
+ goto fail;
+ err = _gcry_md_init ();
+ if (err)
+ goto fail;
+ err = _gcry_mac_init ();
+ if (err)
+ goto fail;
+ err = _gcry_pk_init ();
+ if (err)
+ goto fail;
+ err = _gcry_primegen_init ();
+ if (err)
+ goto fail;
+ err = _gcry_secmem_module_init ();
+ if (err)
+ goto fail;
+ err = _gcry_mpi_init ();
+ if (err)
+ goto fail;
+
+ return;
+
+ fail:
+ BUG ();
+}
+
+
+/* This function is called by the macro fips_is_operational and makes
+ sure that the minimal initialization has been done. This is far
+ from a perfect solution and hides problems with an improper
+ initialization but at least in single-threaded mode it should work
+ reliable.
+
+ The reason we need this is that a lot of applications don't use
+ Libgcrypt properly by not running any initialization code at all.
+ They just call a Libgcrypt function and that is all what they want.
+ Now with the FIPS mode, that has the side effect of entering FIPS
+ mode (for security reasons, FIPS mode is the default if no
+ initialization has been done) and bailing out immediately because
+ the FSM is in the wrong state. If we always run the init code,
+ Libgcrypt can test for FIPS mode and at least if not in FIPS mode,
+ it will behave as before. Note that this on-the-fly initialization
+ is only done for the cryptographic functions subject to FIPS mode
+ and thus not all API calls will do such an initialization. */
+int
+_gcry_global_is_operational (void)
+{
+ if (!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_RNDLINUX
+ "linux:"
+#endif
+#if USE_RNDUNIX
+ "unix:"
+#endif
+#if USE_RNDW32
+ "w32:"
+#endif
+ "\n");
+ }
+
+ if (!what || !strcmp (what, "cpu-arch"))
+ {
+ gpgrt_fprintf (fp, "cpu-arch:"
+#if defined(HAVE_CPU_ARCH_X86)
+ "x86"
+#elif defined(HAVE_CPU_ARCH_ALPHA)
+ "alpha"
+#elif defined(HAVE_CPU_ARCH_SPARC)
+ "sparc"
+#elif defined(HAVE_CPU_ARCH_MIPS)
+ "mips"
+#elif defined(HAVE_CPU_ARCH_M68K)
+ "m68k"
+#elif defined(HAVE_CPU_ARCH_PPC)
+ "ppc"
+#elif defined(HAVE_CPU_ARCH_ARM)
+ "arm"
+#endif
+ ":\n");
+ }
+
+ if (!what || !strcmp (what, "mpi-asm"))
+ gpgrt_fprintf (fp, "mpi-asm:%s:\n", _gcry_mpi_get_hw_config ());
+
+ if (!what || !strcmp (what, "hwflist"))
+ {
+ unsigned int hwfeatures, afeature;
+
+ hwfeatures = _gcry_get_hw_features ();
+ gpgrt_fprintf (fp, "hwflist:");
+ for (i=0; (s = _gcry_enum_hw_features (i, &afeature)); i++)
+ if ((hwfeatures & afeature))
+ gpgrt_fprintf (fp, "%s:", s);
+ gpgrt_fprintf (fp, "\n");
+ }
+
+ if (!what || !strcmp (what, "fips-mode"))
+ {
+ /* We use y/n instead of 1/0 for the stupid reason that
+ * Emacsen's compile error parser would accidentally flag that
+ * line when printed during "make check" as an error. */
+ gpgrt_fprintf (fp, "fips-mode:%c:%c:\n",
+ fips_mode ()? 'y':'n',
+ _gcry_enforced_fips_mode ()? 'y':'n' );
+ }
+
+ if (!what || !strcmp (what, "rng-type"))
+ {
+ /* The currently used RNG type. */
+ unsigned int jver;
+ int active;
+
+ i = _gcry_get_rng_type (0);
+ switch (i)
+ {
+ case GCRY_RNG_TYPE_STANDARD: s = "standard"; break;
+ case GCRY_RNG_TYPE_FIPS: s = "fips"; break;
+ case GCRY_RNG_TYPE_SYSTEM: s = "system"; break;
+ default: BUG ();
+ }
+ jver = _gcry_rndjent_get_version (&active);
+ gpgrt_fprintf (fp, "rng-type:%s:%d:%u:%d:\n", s, i, jver, active);
+ }
+}
+
+
+/* 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 (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;
+}
+
+
+
+
+/* Command dispatcher function, acting as general control
+ function. */
+gcry_err_code_t
+_gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
+{
+ static int init_finished = 0;
+ gcry_err_code_t rc = 0;
+
+ switch (cmd)
+ {
+ case GCRYCTL_ENABLE_M_GUARD:
+ _gcry_private_enable_m_guard ();
+ break;
+
+ case GCRYCTL_ENABLE_QUICK_RANDOM:
+ _gcry_set_preferred_rng_type (0);
+ _gcry_enable_quick_random_gen ();
+ break;
+
+ case GCRYCTL_FAKED_RANDOM_P:
+ /* Return an error if the RNG is faked one (e.g. enabled by
+ ENABLE_QUICK_RANDOM. */
+ if (_gcry_random_is_faked ())
+ rc = GPG_ERR_GENERAL; /* Use as TRUE value. */
+ break;
+
+ case GCRYCTL_DUMP_RANDOM_STATS:
+ _gcry_random_dump_stats ();
+ break;
+
+ case GCRYCTL_DUMP_MEMORY_STATS:
+ /*m_print_stats("[fixme: prefix]");*/
+ break;
+
+ case GCRYCTL_DUMP_SECMEM_STATS:
+ _gcry_secmem_dump_stats (0);
+ break;
+
+ case GCRYCTL_DROP_PRIVS:
+ global_init ();
+ _gcry_secmem_init (0);
+ break;
+
+ case GCRYCTL_DISABLE_SECMEM:
+ global_init ();
+ no_secure_memory = 1;
+ break;
+
+ case GCRYCTL_INIT_SECMEM:
+ global_init ();
+ _gcry_secmem_init (va_arg (arg_ptr, unsigned int));
+ if ((_gcry_secmem_get_flags () & GCRY_SECMEM_FLAG_NOT_LOCKED))
+ rc = GPG_ERR_GENERAL;
+ break;
+
+ case GCRYCTL_TERM_SECMEM:
+ global_init ();
+ _gcry_secmem_term ();
+ break;
+
+ case GCRYCTL_DISABLE_SECMEM_WARN:
+ _gcry_set_preferred_rng_type (0);
+ _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
+ | GCRY_SECMEM_FLAG_NO_WARNING));
+ break;
+
+ case GCRYCTL_SUSPEND_SECMEM_WARN:
+ _gcry_set_preferred_rng_type (0);
+ _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
+ | GCRY_SECMEM_FLAG_SUSPEND_WARNING));
+ break;
+
+ case GCRYCTL_RESUME_SECMEM_WARN:
+ _gcry_set_preferred_rng_type (0);
+ _gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
+ & ~GCRY_SECMEM_FLAG_SUSPEND_WARNING));
+ break;
+
+ case 78: /* GCRYCTL_AUTO_EXPAND_SECMEM (backport from 1.9) */
+ _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 (any_init_done)
+ rc = GPG_ERR_GENERAL;
+ break;
+
+ case GCRYCTL_INITIALIZATION_FINISHED_P:
+ if (init_finished)
+ rc = GPG_ERR_GENERAL; /* Yes. */
+ break;
+
+ case GCRYCTL_INITIALIZATION_FINISHED:
+ /* This is a hook which should be used by an application after
+ all initialization has been done and right before any threads
+ are started. It is not really needed but the only way to be
+ really sure that all initialization for thread-safety has
+ been done. */
+ if (! init_finished)
+ {
+ global_init ();
+ /* Do only a basic random initialization, i.e. init the
+ mutexes. */
+ _gcry_random_initialize (0);
+ init_finished = 1;
+ /* Force us into operational state if in FIPS mode. */
+ (void)fips_is_operational ();
+ }
+ break;
+
+ case GCRYCTL_SET_THREAD_CBS:
+ /* This is now a dummy call. We used to install our own thread
+ library here. */
+ _gcry_set_preferred_rng_type (0);
+ global_init ();
+ break;
+
+ case GCRYCTL_FAST_POLL:
+ _gcry_set_preferred_rng_type (0);
+ /* We need to do make sure that the random pool is really
+ initialized so that the poll function is not a NOP. */
+ _gcry_random_initialize (1);
+
+ if ( fips_is_operational () )
+ _gcry_fast_random_poll ();
+ break;
+
+ case GCRYCTL_SET_RNDEGD_SOCKET:
+#if USE_RNDEGD
+ _gcry_set_preferred_rng_type (0);
+ rc = _gcry_rndegd_set_socket_name (va_arg (arg_ptr, const char *));
+#else
+ rc = GPG_ERR_NOT_SUPPORTED;
+#endif
+ break;
+
+ case GCRYCTL_SET_RANDOM_DAEMON_SOCKET:
+ _gcry_set_preferred_rng_type (0);
+ _gcry_set_random_daemon_socket (va_arg (arg_ptr, const char *));
+ break;
+
+ case GCRYCTL_USE_RANDOM_DAEMON:
+ /* We need to do make sure that the random pool is really
+ initialized so that the poll function is not a NOP. */
+ _gcry_set_preferred_rng_type (0);
+ _gcry_random_initialize (1);
+ _gcry_use_random_daemon (!! va_arg (arg_ptr, int));
+ break;
+
+ case GCRYCTL_CLOSE_RANDOM_DEVICE:
+ _gcry_random_close_fds ();
+ break;
+
+ /* This command dumps information pertaining to the
+ configuration of libgcrypt to the given stream. It may be
+ used before the initialization has been finished but not
+ before a gcry_version_check. See also gcry_get_config. */
+ case GCRYCTL_PRINT_CONFIG:
+ {
+ FILE *fp = va_arg (arg_ptr, FILE *);
+ char *tmpstr;
+ _gcry_set_preferred_rng_type (0);
+ tmpstr = _gcry_get_config (0, NULL);
+ if (tmpstr)
+ {
+ if (fp)
+ fputs (tmpstr, fp);
+ else
+ log_info ("%s", tmpstr);
+ xfree (tmpstr);
+ }
+ }
+ break;
+
+ case GCRYCTL_OPERATIONAL_P:
+ /* Returns true if the library is in an operational state. This
+ is always true for non-fips mode. */
+ _gcry_set_preferred_rng_type (0);
+ if (_gcry_fips_test_operational ())
+ rc = GPG_ERR_GENERAL; /* Used as TRUE value */
+ break;
+
+ case GCRYCTL_FIPS_MODE_P:
+ if (fips_mode ()
+ && !_gcry_is_fips_mode_inactive ()
+ && !no_secure_memory)
+ rc = GPG_ERR_GENERAL; /* Used as TRUE value */
+ break;
+
+ case GCRYCTL_FORCE_FIPS_MODE:
+ /* Performing this command puts the library into fips mode. If
+ the library has already been initialized into fips mode, a
+ selftest is triggered. It is not possible to put the libraty
+ into fips mode after having passed the initialization. */
+ _gcry_set_preferred_rng_type (0);
+ if (!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;
+
+#if _GCRY_GCC_VERSION >= 40600
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wswitch"
+#endif
+ 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;
+#if _GCRY_GCC_VERSION >= 40600
+# pragma GCC diagnostic pop
+#endif
+
+ case GCRYCTL_DISABLE_HWF:
+ {
+ const char *name = va_arg (arg_ptr, const char *);
+ rc = _gcry_disable_hw_feature (name);
+ }
+ break;
+
+ case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
+ if (!any_init_done)
+ {
+ /* Not yet initialized at all. Set the enforced fips mode flag */
+ _gcry_set_preferred_rng_type (0);
+ _gcry_set_enforced_fips_mode ();
+ }
+ else
+ rc = GPG_ERR_GENERAL;
+ break;
+
+ case GCRYCTL_SET_PREFERRED_RNG_TYPE:
+ /* This may be called before gcry_check_version. */
+ {
+ int i = va_arg (arg_ptr, int);
+ /* Note that we may not pass 0 to _gcry_set_preferred_rng_type. */
+ if (i > 0)
+ _gcry_set_preferred_rng_type (i);
+ }
+ break;
+
+ case GCRYCTL_GET_CURRENT_RNG_TYPE:
+ {
+ int *ip = va_arg (arg_ptr, int*);
+ if (ip)
+ *ip = _gcry_get_rng_type (!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 (!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;
+}
+
+
+
+/* Set custom allocation handlers. This is in general not useful
+ * because the libgcrypt allocation functions are guaranteed to
+ * provide proper allocation handlers which zeroize memory if needed.
+ * NOTE: All 5 functions should be set. */
+void
+_gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func,
+ gcry_handler_alloc_t new_alloc_secure_func,
+ gcry_handler_secure_check_t new_is_secure_func,
+ gcry_handler_realloc_t new_realloc_func,
+ gcry_handler_free_t new_free_func)
+{
+ global_init ();
+
+ if (fips_mode ())
+ {
+ /* We do not want to enforce the fips mode, but merely set a
+ flag so that the application may check whether it is still in
+ fips mode. */
+ _gcry_inactivate_fips_mode ("custom allocation handler");
+ }
+
+ alloc_func = new_alloc_func;
+ alloc_secure_func = new_alloc_secure_func;
+ is_secure_func = new_is_secure_func;
+ realloc_func = new_realloc_func;
+ free_func = new_free_func;
+}
+
+
+
+/****************
+ * Set an optional handler which is called in case the xmalloc functions
+ * ran out of memory. This handler may do one of these things:
+ * o free some memory and return true, so that the xmalloc function
+ * tries again.
+ * o Do whatever it like and return false, so that the xmalloc functions
+ * use the default fatal error handler.
+ * o Terminate the program and don't return.
+ *
+ * The handler function is called with 3 arguments: The opaque value set with
+ * this function, the requested memory size, and a flag with these bits
+ * currently defined:
+ * bit 0 set = secure memory has been requested.
+ */
+void
+_gcry_set_outofcore_handler (int (*f)(void*, size_t, unsigned int), void *value)
+{
+ global_init ();
+
+ if (fips_mode () )
+ {
+ log_info ("out of core handler ignored in FIPS mode\n");
+ return;
+ }
+
+ outofcore_handler = f;
+ outofcore_handler_value = value;
+}
+
+/* Return the no_secure_memory flag. */
+static int
+get_no_secure_memory (void)
+{
+ if (!no_secure_memory)
+ return 0;
+ if (_gcry_enforced_fips_mode ())
+ {
+ no_secure_memory = 0;
+ return 0;
+ }
+ return no_secure_memory;
+}
+
+
+static gcry_err_code_t
+do_malloc (size_t n, unsigned int flags, void **mem)
+{
+ gcry_err_code_t err = 0;
+ void *m;
+
+ if ((flags & GCRY_ALLOC_FLAG_SECURE) && !get_no_secure_memory ())
+ {
+ if (alloc_secure_func)
+ m = (*alloc_secure_func) (n);
+ else
+ m = _gcry_private_malloc_secure (n, !!(flags & GCRY_ALLOC_FLAG_XHINT));
+ }
+ else
+ {
+ if (alloc_func)
+ m = (*alloc_func) (n);
+ else
+ m = _gcry_private_malloc (n);
+ }
+
+ if (!m)
+ {
+ /* Make sure that ERRNO has been set in case a user supplied
+ memory handler didn't it correctly. */
+ if (!errno)
+ gpg_err_set_errno (ENOMEM);
+ err = gpg_err_code_from_errno (errno);
+ }
+ else
+ *mem = m;
+
+ return err;
+}
+
+void *
+_gcry_malloc (size_t n)
+{
+ void *mem = NULL;
+
+ do_malloc (n, 0, &mem);
+
+ return mem;
+}
+
+static void *
+_gcry_malloc_secure_core (size_t n, int xhint)
+{
+ void *mem = NULL;
+
+ do_malloc (n, (GCRY_ALLOC_FLAG_SECURE | (xhint? GCRY_ALLOC_FLAG_XHINT:0)),
+ &mem);
+
+ return mem;
+}
+
+void *
+_gcry_malloc_secure (size_t n)
+{
+ return _gcry_malloc_secure_core (n, 0);
+}
+
+int
+_gcry_is_secure (const void *a)
+{
+ if (get_no_secure_memory ())
+ return 0;
+ if (is_secure_func)
+ return is_secure_func (a) ;
+ return _gcry_private_is_secure (a);
+}
+
+void
+_gcry_check_heap( const void *a )
+{
+ (void)a;
+
+ /* FIXME: implement this*/
+#if 0
+ if( some_handler )
+ some_handler(a)
+ else
+ _gcry_private_check_heap(a)
+#endif
+}
+
+static void *
+_gcry_realloc_core (void *a, size_t n, int xhint)
+{
+ void *p;
+
+ /* To avoid problems with non-standard realloc implementations and
+ our own secmem_realloc, we divert to malloc and free here. */
+ if (!a)
+ return _gcry_malloc (n);
+ if (!n)
+ {
+ xfree (a);
+ return NULL;
+ }
+
+ if (realloc_func)
+ p = realloc_func (a, n);
+ else
+ p = _gcry_private_realloc (a, n, xhint);
+ if (!p && !errno)
+ gpg_err_set_errno (ENOMEM);
+ return p;
+}
+
+
+void *
+_gcry_realloc (void *a, size_t n)
+{
+ return _gcry_realloc_core (a, n, 0);
+}
+
+
+void
+_gcry_free (void *p)
+{
+ int save_errno;
+
+ if (!p)
+ return;
+
+ /* In case ERRNO is set we better save it so that the free machinery
+ may not accidentally change ERRNO. We restore it only if it was
+ already set to comply with the usual C semantic for ERRNO. */
+ save_errno = errno;
+ if (free_func)
+ free_func (p);
+ else
+ _gcry_private_free (p);
+
+ if (save_errno)
+ gpg_err_set_errno (save_errno);
+}
+
+void *
+_gcry_calloc (size_t n, size_t m)
+{
+ size_t bytes;
+ void *p;
+
+ bytes = n * m; /* size_t is unsigned so the behavior on overflow is
+ defined. */
+ if (m && bytes / m != n)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+
+ p = _gcry_malloc (bytes);
+ if (p)
+ memset (p, 0, bytes);
+ return p;
+}
+
+void *
+_gcry_calloc_secure (size_t n, size_t m)
+{
+ size_t bytes;
+ void *p;
+
+ bytes = n * m; /* size_t is unsigned so the behavior on overflow is
+ defined. */
+ if (m && bytes / m != n)
+ {
+ gpg_err_set_errno (ENOMEM);
+ return NULL;
+ }
+
+ p = _gcry_malloc_secure (bytes);
+ if (p)
+ memset (p, 0, bytes);
+ return p;
+}
+
+
+static char *
+_gcry_strdup_core (const char *string, int xhint)
+{
+ char *string_cp = NULL;
+ size_t string_n = 0;
+
+ string_n = strlen (string);
+
+ if (_gcry_is_secure (string))
+ string_cp = _gcry_malloc_secure_core (string_n + 1, xhint);
+ else
+ string_cp = _gcry_malloc (string_n + 1);
+
+ if (string_cp)
+ strcpy (string_cp, string);
+
+ return string_cp;
+}
+
+/* Create and return a copy of the null-terminated string STRING. If
+ * it is contained in secure memory, the copy will be contained in
+ * secure memory as well. In an out-of-memory condition, NULL is
+ * returned. */
+char *
+_gcry_strdup (const char *string)
+{
+ return _gcry_strdup_core (string, 0);
+}
+
+void *
+_gcry_xmalloc( size_t n )
+{
+ void *p;
+
+ while ( !(p = _gcry_malloc( n )) )
+ {
+ if ( fips_mode ()
+ || !outofcore_handler
+ || !outofcore_handler (outofcore_handler_value, n, 0) )
+ {
+ _gcry_fatal_error (gpg_err_code_from_errno (errno), NULL);
+ }
+ }
+ return p;
+}
+
+void *
+_gcry_xrealloc( void *a, size_t n )
+{
+ void *p;
+
+ while (!(p = _gcry_realloc_core (a, n, 1)))
+ {
+ if ( fips_mode ()
+ || !outofcore_handler
+ || !outofcore_handler (outofcore_handler_value, n,
+ _gcry_is_secure(a)? 3:2))
+ {
+ _gcry_fatal_error (gpg_err_code_from_errno (errno), NULL );
+ }
+ }
+ return p;
+}
+
+void *
+_gcry_xmalloc_secure( size_t n )
+{
+ void *p;
+
+ while (!(p = _gcry_malloc_secure_core (n, 1)))
+ {
+ if ( fips_mode ()
+ || !outofcore_handler
+ || !outofcore_handler (outofcore_handler_value, n, 1) )
+ {
+ _gcry_fatal_error (gpg_err_code_from_errno (errno),
+ _("out of core in secure memory"));
+ }
+ }
+ return p;
+}
+
+
+void *
+_gcry_xcalloc( size_t n, size_t m )
+{
+ size_t nbytes;
+ void *p;
+
+ nbytes = n * m;
+ if (m && nbytes / m != n)
+ {
+ gpg_err_set_errno (ENOMEM);
+ _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
+ }
+
+ p = _gcry_xmalloc ( nbytes );
+ memset ( p, 0, nbytes );
+ return p;
+}
+
+void *
+_gcry_xcalloc_secure( size_t n, size_t m )
+{
+ size_t nbytes;
+ void *p;
+
+ nbytes = n * m;
+ if (m && nbytes / m != n)
+ {
+ gpg_err_set_errno (ENOMEM);
+ _gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
+ }
+
+ p = _gcry_xmalloc_secure ( nbytes );
+ memset ( p, 0, nbytes );
+ return p;
+}
+
+char *
+_gcry_xstrdup (const char *string)
+{
+ char *p;
+
+ while ( !(p = _gcry_strdup_core (string, 1)) )
+ {
+ size_t n = strlen (string);
+ int is_sec = !!_gcry_is_secure (string);
+
+ if (fips_mode ()
+ || !outofcore_handler
+ || !outofcore_handler (outofcore_handler_value, n, is_sec) )
+ {
+ _gcry_fatal_error (gpg_err_code_from_errno (errno),
+ is_sec? _("out of core in secure memory"):NULL);
+ }
+ }
+
+ return p;
+}
+
+
+/* Used before blocking system calls. */
+void
+_gcry_pre_syscall (void)
+{
+ if (pre_syscall_func)
+ pre_syscall_func ();
+}
+
+
+/* Used after blocking system calls. */
+void
+_gcry_post_syscall (void)
+{
+ if (post_syscall_func)
+ post_syscall_func ();
+}
+
+
+int
+_gcry_get_debug_flag (unsigned int mask)
+{
+ if ( fips_mode () )
+ return 0;
+ return (debug_flags & mask);
+}
+
+
+
+/* It is often useful to get some feedback of long running operations.
+ This function may be used to register a handler for this.
+ The callback function CB is used as:
+
+ void cb (void *opaque, const char *what, int printchar,
+ int current, int total);
+
+ Where WHAT is a string identifying the the type of the progress
+ output, PRINTCHAR the character usually printed, CURRENT the amount
+ of progress currently done and TOTAL the expected amount of
+ progress. A value of 0 for TOTAL indicates that there is no
+ estimation available.
+
+ Defined values for WHAT:
+
+ "need_entropy" X 0 number-of-bytes-required
+ When running low on entropy
+ "primegen" '\n' 0 0
+ Prime generated
+ '!'
+ Need to refresh the prime pool
+ '<','>'
+ Number of bits adjusted
+ '^'
+ Looking for a generator
+ '.'
+ Fermat tests on 10 candidates failed
+ ':'
+ Restart with a new random value
+ '+'
+ Rabin Miller test passed
+ "pk_elg" '+','-','.','\n' 0 0
+ Only used in debugging mode.
+ "pk_dsa"
+ Only used in debugging mode.
+*/
+void
+_gcry_set_progress_handler (void (*cb)(void *,const char*,int, int, int),
+ void *cb_data)
+{
+#if USE_DSA
+ _gcry_register_pk_dsa_progress (cb, cb_data);
+#endif
+#if USE_ELGAMAL
+ _gcry_register_pk_elg_progress (cb, cb_data);
+#endif
+ _gcry_register_primegen_progress (cb, cb_data);
+ _gcry_register_random_progress (cb, cb_data);
+}
+
+
+
+/* This is a helper for the regression test suite to test Libgcrypt's locks.
+ It works using a one test lock with CMD controlling what to do:
+
+ 30111 - Allocate and init lock
+ 30112 - Take lock
+ 30113 - Release lock
+ 30114 - Destroy lock.
+
+ This function is used by tests/t-lock.c - it is not part of the
+ public API!
+ */
+static gpg_err_code_t
+external_lock_test (int cmd)
+{
+ GPGRT_LOCK_DEFINE (testlock);
+ gpg_err_code_t rc = 0;
+
+ switch (cmd)
+ {
+ case 30111: /* Init Lock. */
+ rc = gpgrt_lock_init (&testlock);
+ break;
+
+ case 30112: /* Take Lock. */
+ rc = gpgrt_lock_lock (&testlock);
+ break;
+
+ case 30113: /* Release Lock. */
+ rc = gpgrt_lock_unlock (&testlock);
+ break;
+
+ case 30114: /* Destroy Lock. */
+ rc = gpgrt_lock_destroy (&testlock);
+ break;
+
+ default:
+ rc = GPG_ERR_INV_OP;
+ break;
+ }
+
+ return rc;
+}