2N/A/* md.c - message digest dispatcher
2N/A * Copyright (C) 1998, 1999, 2002, 2003, 2006,
2N/A * 2008 Free Software Foundation, Inc.
2N/A *
2N/A * This file is part of Libgcrypt.
2N/A *
2N/A * Libgcrypt is free software; you can redistribute it and/or modify
2N/A * it under the terms of the GNU Lesser general Public License as
2N/A * published by the Free Software Foundation; either version 2.1 of
2N/A * the License, or (at your option) any later version.
2N/A *
2N/A * Libgcrypt is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU Lesser General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU Lesser General Public
2N/A * License along with this program; if not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A#include <config.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <errno.h>
2N/A
2N/A#include "g10lib.h"
2N/A#include "cipher.h"
2N/A#include "ath.h"
2N/A
2N/A#include "rmd.h"
2N/A
2N/A/* A dummy extraspec so that we do not need to tests the extraspec
2N/A field from the module specification against NULL and instead
2N/A directly test the respective fields of extraspecs. */
2N/Astatic md_extra_spec_t dummy_extra_spec;
2N/A
2N/A
2N/A/* This is the list of the digest implementations included in
2N/A libgcrypt. */
2N/Astatic struct digest_table_entry
2N/A{
2N/A gcry_md_spec_t *digest;
2N/A md_extra_spec_t *extraspec;
2N/A unsigned int algorithm;
2N/A int fips_allowed;
2N/A} digest_table[] =
2N/A {
2N/A#if USE_CRC
2N/A /* We allow the CRC algorithms even in FIPS mode because they are
2N/A actually no cryptographic primitives. */
2N/A { &_gcry_digest_spec_crc32,
2N/A &dummy_extra_spec, GCRY_MD_CRC32, 1 },
2N/A { &_gcry_digest_spec_crc32_rfc1510,
2N/A &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 },
2N/A { &_gcry_digest_spec_crc24_rfc2440,
2N/A &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 },
2N/A#endif
2N/A#if USE_MD4
2N/A { &_gcry_digest_spec_md4,
2N/A &dummy_extra_spec, GCRY_MD_MD4 },
2N/A#endif
2N/A#if USE_MD5
2N/A { &_gcry_digest_spec_md5,
2N/A &dummy_extra_spec, GCRY_MD_MD5, 1 },
2N/A#endif
2N/A#if USE_RMD160
2N/A { &_gcry_digest_spec_rmd160,
2N/A &dummy_extra_spec, GCRY_MD_RMD160 },
2N/A#endif
2N/A#if USE_SHA1
2N/A { &_gcry_digest_spec_sha1,
2N/A &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 },
2N/A#endif
2N/A#if USE_SHA256
2N/A { &_gcry_digest_spec_sha256,
2N/A &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 },
2N/A { &_gcry_digest_spec_sha224,
2N/A &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 },
2N/A#endif
2N/A#if USE_SHA512
2N/A { &_gcry_digest_spec_sha512,
2N/A &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 },
2N/A { &_gcry_digest_spec_sha384,
2N/A &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 },
2N/A#endif
2N/A#if USE_TIGER
2N/A { &_gcry_digest_spec_tiger,
2N/A &dummy_extra_spec, GCRY_MD_TIGER },
2N/A#endif
2N/A#if USE_WHIRLPOOL
2N/A { &_gcry_digest_spec_whirlpool,
2N/A &dummy_extra_spec, GCRY_MD_WHIRLPOOL },
2N/A#endif
2N/A { NULL },
2N/A };
2N/A
2N/A/* List of registered digests. */
2N/Astatic gcry_module_t digests_registered;
2N/A
2N/A/* This is the lock protecting DIGESTS_REGISTERED. */
2N/Astatic ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER;
2N/A
2N/A/* Flag to check wether the default ciphers have already been
2N/A registered. */
2N/Astatic int default_digests_registered;
2N/A
2N/Atypedef struct gcry_md_list
2N/A{
2N/A gcry_md_spec_t *digest;
2N/A gcry_module_t module;
2N/A struct gcry_md_list *next;
2N/A size_t actual_struct_size; /* Allocated size of this structure. */
2N/A PROPERLY_ALIGNED_TYPE context;
2N/A} GcryDigestEntry;
2N/A
2N/A/* this structure is put right after the gcry_md_hd_t buffer, so that
2N/A * only one memory block is needed. */
2N/Astruct gcry_md_context
2N/A{
2N/A int magic;
2N/A size_t actual_handle_size; /* Allocated size of this handle. */
2N/A int secure;
2N/A FILE *debug;
2N/A int finalized;
2N/A GcryDigestEntry *list;
2N/A byte *macpads;
2N/A int macpads_Bsize; /* Blocksize as used for the HMAC pads. */
2N/A};
2N/A
2N/A
2N/A#define CTX_MAGIC_NORMAL 0x11071961
2N/A#define CTX_MAGIC_SECURE 0x16917011
2N/A
2N/A/* Convenient macro for registering the default digests. */
2N/A#define REGISTER_DEFAULT_DIGESTS \
2N/A do \
2N/A { \
2N/A ath_mutex_lock (&digests_registered_lock); \
2N/A if (! default_digests_registered) \
2N/A { \
2N/A md_register_default (); \
2N/A default_digests_registered = 1; \
2N/A } \
2N/A ath_mutex_unlock (&digests_registered_lock); \
2N/A } \
2N/A while (0)
2N/A
2N/A
2N/Astatic const char * digest_algo_to_string( int algo );
2N/Astatic gcry_err_code_t check_digest_algo (int algo);
2N/Astatic gcry_err_code_t md_open (gcry_md_hd_t *h, int algo,
2N/A int secure, int hmac);
2N/Astatic gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo);
2N/Astatic gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b);
2N/Astatic void md_close (gcry_md_hd_t a);
2N/Astatic void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen);
2N/Astatic void md_final(gcry_md_hd_t a);
2N/Astatic byte *md_read( gcry_md_hd_t a, int algo );
2N/Astatic int md_get_algo( gcry_md_hd_t a );
2N/Astatic int md_digest_length( int algo );
2N/Astatic const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen );
2N/Astatic void md_start_debug ( gcry_md_hd_t a, const char *suffix );
2N/Astatic void md_stop_debug ( gcry_md_hd_t a );
2N/A
2N/A
2N/A
2N/A
2N/A/* Internal function. Register all the ciphers included in
2N/A CIPHER_TABLE. Returns zero on success or an error code. */
2N/Astatic void
2N/Amd_register_default (void)
2N/A{
2N/A gcry_err_code_t err = 0;
2N/A int i;
2N/A
2N/A for (i = 0; !err && digest_table[i].digest; i++)
2N/A {
2N/A if ( fips_mode ())
2N/A {
2N/A if (!digest_table[i].fips_allowed)
2N/A continue;
2N/A if (digest_table[i].algorithm == GCRY_MD_MD5
2N/A && _gcry_enforced_fips_mode () )
2N/A continue; /* Do not register in enforced fips mode. */
2N/A }
2N/A
2N/A err = _gcry_module_add (&digests_registered,
2N/A digest_table[i].algorithm,
2N/A (void *) digest_table[i].digest,
2N/A (void *) digest_table[i].extraspec,
2N/A NULL);
2N/A }
2N/A
2N/A if (err)
2N/A BUG ();
2N/A}
2N/A
2N/A/* Internal callback function. */
2N/Astatic int
2N/Agcry_md_lookup_func_name (void *spec, void *data)
2N/A{
2N/A gcry_md_spec_t *digest = (gcry_md_spec_t *) spec;
2N/A char *name = (char *) data;
2N/A
2N/A return (! stricmp (digest->name, name));
2N/A}
2N/A
2N/A/* Internal callback function. Used via _gcry_module_lookup. */
2N/Astatic int
2N/Agcry_md_lookup_func_oid (void *spec, void *data)
2N/A{
2N/A gcry_md_spec_t *digest = (gcry_md_spec_t *) spec;
2N/A char *oid = (char *) data;
2N/A gcry_md_oid_spec_t *oid_specs = digest->oids;
2N/A int ret = 0, i;
2N/A
2N/A if (oid_specs)
2N/A {
2N/A for (i = 0; oid_specs[i].oidstring && (! ret); i++)
2N/A if (! stricmp (oid, oid_specs[i].oidstring))
2N/A ret = 1;
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/* Internal function. Lookup a digest entry by it's name. */
2N/Astatic gcry_module_t
2N/Agcry_md_lookup_name (const char *name)
2N/A{
2N/A gcry_module_t digest;
2N/A
2N/A digest = _gcry_module_lookup (digests_registered, (void *) name,
2N/A gcry_md_lookup_func_name);
2N/A
2N/A return digest;
2N/A}
2N/A
2N/A/* Internal function. Lookup a cipher entry by it's oid. */
2N/Astatic gcry_module_t
2N/Agcry_md_lookup_oid (const char *oid)
2N/A{
2N/A gcry_module_t digest;
2N/A
2N/A digest = _gcry_module_lookup (digests_registered, (void *) oid,
2N/A gcry_md_lookup_func_oid);
2N/A
2N/A return digest;
2N/A}
2N/A
2N/A/* Register a new digest module whose specification can be found in
2N/A DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID
2N/A and a pointer representhing this module is stored in MODULE. */
2N/Agcry_error_t
2N/A_gcry_md_register (gcry_md_spec_t *digest,
2N/A md_extra_spec_t *extraspec,
2N/A unsigned int *algorithm_id,
2N/A gcry_module_t *module)
2N/A{
2N/A gcry_err_code_t err = 0;
2N/A gcry_module_t mod;
2N/A
2N/A /* We do not support module loading in fips mode. */
2N/A if (fips_mode ())
2N/A return gpg_error (GPG_ERR_NOT_SUPPORTED);
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A err = _gcry_module_add (&digests_registered, 0,
2N/A (void *) digest,
2N/A (void *)(extraspec? extraspec : &dummy_extra_spec),
2N/A &mod);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A if (! err)
2N/A {
2N/A *module = mod;
2N/A *algorithm_id = mod->mod_id;
2N/A }
2N/A
2N/A return gcry_error (err);
2N/A}
2N/A
2N/A/* Unregister the digest identified by ID, which must have been
2N/A registered with gcry_digest_register. */
2N/Avoid
2N/Agcry_md_unregister (gcry_module_t module)
2N/A{
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A _gcry_module_release (module);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A}
2N/A
2N/A
2N/Astatic int
2N/Asearch_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec)
2N/A{
2N/A gcry_module_t module;
2N/A int ret = 0;
2N/A
2N/A if (oid && ((! strncmp (oid, "oid.", 4))
2N/A || (! strncmp (oid, "OID.", 4))))
2N/A oid += 4;
2N/A
2N/A module = gcry_md_lookup_oid (oid);
2N/A if (module)
2N/A {
2N/A gcry_md_spec_t *digest = module->spec;
2N/A int i;
2N/A
2N/A for (i = 0; digest->oids[i].oidstring && !ret; i++)
2N/A if (! stricmp (oid, digest->oids[i].oidstring))
2N/A {
2N/A if (algorithm)
2N/A *algorithm = module->mod_id;
2N/A if (oid_spec)
2N/A *oid_spec = digest->oids[i];
2N/A ret = 1;
2N/A }
2N/A _gcry_module_release (module);
2N/A }
2N/A
2N/A return ret;
2N/A}
2N/A
2N/A/****************
2N/A * Map a string to the digest algo
2N/A */
2N/Aint
2N/Agcry_md_map_name (const char *string)
2N/A{
2N/A gcry_module_t digest;
2N/A int ret, algorithm = 0;
2N/A
2N/A if (! string)
2N/A return 0;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A /* If the string starts with a digit (optionally prefixed with
2N/A either "OID." or "oid."), we first look into our table of ASN.1
2N/A object identifiers to figure out the algorithm */
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A
2N/A ret = search_oid (string, &algorithm, NULL);
2N/A if (! ret)
2N/A {
2N/A /* Not found, search a matching digest name. */
2N/A digest = gcry_md_lookup_name (string);
2N/A if (digest)
2N/A {
2N/A algorithm = digest->mod_id;
2N/A _gcry_module_release (digest);
2N/A }
2N/A }
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A return algorithm;
2N/A}
2N/A
2N/A
2N/A/****************
2N/A * Map a digest algo to a string
2N/A */
2N/Astatic const char *
2N/Adigest_algo_to_string (int algorithm)
2N/A{
2N/A const char *name = NULL;
2N/A gcry_module_t digest;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A digest = _gcry_module_lookup_id (digests_registered, algorithm);
2N/A if (digest)
2N/A {
2N/A name = ((gcry_md_spec_t *) digest->spec)->name;
2N/A _gcry_module_release (digest);
2N/A }
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A return name;
2N/A}
2N/A
2N/A/****************
2N/A * This function simply returns the name of the algorithm or some constant
2N/A * string when there is no algo. It will never return NULL.
2N/A * Use the macro gcry_md_test_algo() to check whether the algorithm
2N/A * is valid.
2N/A */
2N/Aconst char *
2N/Agcry_md_algo_name (int algorithm)
2N/A{
2N/A const char *s = digest_algo_to_string (algorithm);
2N/A return s ? s : "?";
2N/A}
2N/A
2N/A
2N/Astatic gcry_err_code_t
2N/Acheck_digest_algo (int algorithm)
2N/A{
2N/A gcry_err_code_t rc = 0;
2N/A gcry_module_t digest;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A digest = _gcry_module_lookup_id (digests_registered, algorithm);
2N/A if (digest)
2N/A _gcry_module_release (digest);
2N/A else
2N/A rc = GPG_ERR_DIGEST_ALGO;
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A return rc;
2N/A}
2N/A
2N/A
2N/A
2N/A/****************
2N/A * Open a message digest handle for use with algorithm ALGO.
2N/A * More algorithms may be added by md_enable(). The initial algorithm
2N/A * may be 0.
2N/A */
2N/Astatic gcry_err_code_t
2N/Amd_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A int bufsize = secure ? 512 : 1024;
2N/A struct gcry_md_context *ctx;
2N/A gcry_md_hd_t hd;
2N/A size_t n;
2N/A
2N/A /* Allocate a memory area to hold the caller visible buffer with it's
2N/A * control information and the data required by this module. Set the
2N/A * context pointer at the beginning to this area.
2N/A * We have to use this strange scheme because we want to hide the
2N/A * internal data but have a variable sized buffer.
2N/A *
2N/A * +---+------+---........------+-------------+
2N/A * !ctx! bctl ! buffer ! private !
2N/A * +---+------+---........------+-------------+
2N/A * ! ^
2N/A * !---------------------------!
2N/A *
2N/A * We have to make sure that private is well aligned.
2N/A */
2N/A n = sizeof (struct gcry_md_handle) + bufsize;
2N/A n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1)
2N/A / sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE);
2N/A
2N/A /* Allocate and set the Context pointer to the private data */
2N/A if (secure)
2N/A hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context));
2N/A else
2N/A hd = gcry_malloc (n + sizeof (struct gcry_md_context));
2N/A
2N/A if (! hd)
2N/A err = gpg_err_code_from_errno (errno);
2N/A
2N/A if (! err)
2N/A {
2N/A hd->ctx = ctx = (struct gcry_md_context *) ((char *) hd + n);
2N/A /* Setup the globally visible data (bctl in the diagram).*/
2N/A hd->bufsize = n - sizeof (struct gcry_md_handle) + 1;
2N/A hd->bufpos = 0;
2N/A
2N/A /* Initialize the private data. */
2N/A memset (hd->ctx, 0, sizeof *hd->ctx);
2N/A ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL;
2N/A ctx->actual_handle_size = n + sizeof (struct gcry_md_context);
2N/A ctx->secure = secure;
2N/A
2N/A if (hmac)
2N/A {
2N/A switch (algo)
2N/A {
2N/A case GCRY_MD_SHA384:
2N/A case GCRY_MD_SHA512:
2N/A ctx->macpads_Bsize = 128;
2N/A break;
2N/A default:
2N/A ctx->macpads_Bsize = 64;
2N/A break;
2N/A }
2N/A ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize));
2N/A if (!ctx->macpads)
2N/A {
2N/A err = gpg_err_code_from_errno (errno);
2N/A md_close (hd);
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (! err)
2N/A {
2N/A /* Hmmm, should we really do that? - yes [-wk] */
2N/A _gcry_fast_random_poll ();
2N/A
2N/A if (algo)
2N/A {
2N/A err = md_enable (hd, algo);
2N/A if (err)
2N/A md_close (hd);
2N/A }
2N/A }
2N/A
2N/A if (! err)
2N/A *h = hd;
2N/A
2N/A return err;
2N/A}
2N/A
2N/A/* Create a message digest object for algorithm ALGO. FLAGS may be
2N/A given as an bitwise OR of the gcry_md_flags values. ALGO may be
2N/A given as 0 if the algorithms to be used are later set using
2N/A gcry_md_enable. H is guaranteed to be a valid handle or NULL on
2N/A error. */
2N/Agcry_error_t
2N/Agcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A gcry_md_hd_t hd;
2N/A
2N/A if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)))
2N/A err = GPG_ERR_INV_ARG;
2N/A else
2N/A {
2N/A err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE),
2N/A (flags & GCRY_MD_FLAG_HMAC));
2N/A }
2N/A
2N/A *h = err? NULL : hd;
2N/A return gcry_error (err);
2N/A}
2N/A
2N/A
2N/A
2N/Astatic gcry_err_code_t
2N/Amd_enable (gcry_md_hd_t hd, int algorithm)
2N/A{
2N/A struct gcry_md_context *h = hd->ctx;
2N/A gcry_md_spec_t *digest = NULL;
2N/A GcryDigestEntry *entry;
2N/A gcry_module_t module;
2N/A gcry_err_code_t err = 0;
2N/A
2N/A for (entry = h->list; entry; entry = entry->next)
2N/A if (entry->module->mod_id == algorithm)
2N/A return err; /* already enabled */
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A module = _gcry_module_lookup_id (digests_registered, algorithm);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A if (! module)
2N/A {
2N/A log_debug ("md_enable: algorithm %d not available\n", algorithm);
2N/A err = GPG_ERR_DIGEST_ALGO;
2N/A }
2N/A else
2N/A digest = (gcry_md_spec_t *) module->spec;
2N/A
2N/A
2N/A if (!err && algorithm == GCRY_MD_MD5 && fips_mode ())
2N/A {
2N/A _gcry_inactivate_fips_mode ("MD5 used");
2N/A if (_gcry_enforced_fips_mode () )
2N/A {
2N/A /* We should never get to here because we do not register
2N/A MD5 in enforced fips mode. But better throw an error. */
2N/A err = GPG_ERR_DIGEST_ALGO;
2N/A }
2N/A }
2N/A
2N/A if (!err)
2N/A {
2N/A size_t size = (sizeof (*entry)
2N/A + digest->contextsize
2N/A - sizeof (entry->context));
2N/A
2N/A /* And allocate a new list entry. */
2N/A if (h->secure)
2N/A entry = gcry_malloc_secure (size);
2N/A else
2N/A entry = gcry_malloc (size);
2N/A
2N/A if (! entry)
2N/A err = gpg_err_code_from_errno (errno);
2N/A else
2N/A {
2N/A entry->digest = digest;
2N/A entry->module = module;
2N/A entry->next = h->list;
2N/A entry->actual_struct_size = size;
2N/A h->list = entry;
2N/A
2N/A /* And init this instance. */
2N/A entry->digest->init (&entry->context.c);
2N/A }
2N/A }
2N/A
2N/A if (err)
2N/A {
2N/A if (module)
2N/A {
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A _gcry_module_release (module);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A }
2N/A }
2N/A
2N/A return err;
2N/A}
2N/A
2N/A
2N/Agcry_error_t
2N/Agcry_md_enable (gcry_md_hd_t hd, int algorithm)
2N/A{
2N/A return gcry_error (md_enable (hd, algorithm));
2N/A}
2N/A
2N/Astatic gcry_err_code_t
2N/Amd_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A struct gcry_md_context *a = ahd->ctx;
2N/A struct gcry_md_context *b;
2N/A GcryDigestEntry *ar, *br;
2N/A gcry_md_hd_t bhd;
2N/A size_t n;
2N/A
2N/A if (ahd->bufpos)
2N/A md_write (ahd, NULL, 0);
2N/A
2N/A n = (char *) ahd->ctx - (char *) ahd;
2N/A if (a->secure)
2N/A bhd = gcry_malloc_secure (n + sizeof (struct gcry_md_context));
2N/A else
2N/A bhd = gcry_malloc (n + sizeof (struct gcry_md_context));
2N/A
2N/A if (! bhd)
2N/A err = gpg_err_code_from_errno (errno);
2N/A
2N/A if (! err)
2N/A {
2N/A bhd->ctx = b = (struct gcry_md_context *) ((char *) bhd + n);
2N/A /* No need to copy the buffer due to the write above. */
2N/A gcry_assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1));
2N/A bhd->bufsize = ahd->bufsize;
2N/A bhd->bufpos = 0;
2N/A gcry_assert (! ahd->bufpos);
2N/A memcpy (b, a, sizeof *a);
2N/A b->list = NULL;
2N/A b->debug = NULL;
2N/A if (a->macpads)
2N/A {
2N/A b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize));
2N/A if (! b->macpads)
2N/A {
2N/A err = gpg_err_code_from_errno (errno);
2N/A md_close (bhd);
2N/A }
2N/A else
2N/A memcpy (b->macpads, a->macpads, (2*(a->macpads_Bsize)));
2N/A }
2N/A }
2N/A
2N/A /* Copy the complete list of algorithms. The copied list is
2N/A reversed, but that doesn't matter. */
2N/A if (!err)
2N/A {
2N/A for (ar = a->list; ar; ar = ar->next)
2N/A {
2N/A if (a->secure)
2N/A br = gcry_malloc_secure (sizeof *br
2N/A + ar->digest->contextsize
2N/A - sizeof(ar->context));
2N/A else
2N/A br = gcry_malloc (sizeof *br
2N/A + ar->digest->contextsize
2N/A - sizeof (ar->context));
2N/A if (!br)
2N/A {
2N/A err = gpg_err_code_from_errno (errno);
2N/A md_close (bhd);
2N/A break;
2N/A }
2N/A
2N/A memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize
2N/A - sizeof (ar->context)));
2N/A br->next = b->list;
2N/A b->list = br;
2N/A
2N/A /* Add a reference to the module. */
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A _gcry_module_use (br->module);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A }
2N/A }
2N/A
2N/A if (a->debug && !err)
2N/A md_start_debug (bhd, "unknown");
2N/A
2N/A if (!err)
2N/A *b_hd = bhd;
2N/A
2N/A return err;
2N/A}
2N/A
2N/Agcry_error_t
2N/Agcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd)
2N/A{
2N/A gcry_err_code_t err;
2N/A
2N/A err = md_copy (hd, handle);
2N/A if (err)
2N/A *handle = NULL;
2N/A return gcry_error (err);
2N/A}
2N/A
2N/A/*
2N/A * Reset all contexts and discard any buffered stuff. This may be used
2N/A * instead of a md_close(); md_open().
2N/A */
2N/Avoid
2N/Agcry_md_reset (gcry_md_hd_t a)
2N/A{
2N/A GcryDigestEntry *r;
2N/A
2N/A /* Note: We allow this even in fips non operational mode. */
2N/A
2N/A a->bufpos = a->ctx->finalized = 0;
2N/A
2N/A for (r = a->ctx->list; r; r = r->next)
2N/A {
2N/A memset (r->context.c, 0, r->digest->contextsize);
2N/A (*r->digest->init) (&r->context.c);
2N/A }
2N/A if (a->ctx->macpads)
2N/A md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */
2N/A}
2N/A
2N/Astatic void
2N/Amd_close (gcry_md_hd_t a)
2N/A{
2N/A GcryDigestEntry *r, *r2;
2N/A
2N/A if (! a)
2N/A return;
2N/A if (a->ctx->debug)
2N/A md_stop_debug (a);
2N/A for (r = a->ctx->list; r; r = r2)
2N/A {
2N/A r2 = r->next;
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A _gcry_module_release (r->module);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A wipememory (r, r->actual_struct_size);
2N/A gcry_free (r);
2N/A }
2N/A
2N/A if (a->ctx->macpads)
2N/A {
2N/A wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize));
2N/A gcry_free(a->ctx->macpads);
2N/A }
2N/A
2N/A wipememory (a, a->ctx->actual_handle_size);
2N/A gcry_free(a);
2N/A}
2N/A
2N/Avoid
2N/Agcry_md_close (gcry_md_hd_t hd)
2N/A{
2N/A /* Note: We allow this even in fips non operational mode. */
2N/A md_close (hd);
2N/A}
2N/A
2N/Astatic void
2N/Amd_write (gcry_md_hd_t a, const void *inbuf, size_t inlen)
2N/A{
2N/A GcryDigestEntry *r;
2N/A
2N/A if (a->ctx->debug)
2N/A {
2N/A if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1)
2N/A BUG();
2N/A if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1)
2N/A BUG();
2N/A }
2N/A
2N/A for (r = a->ctx->list; r; r = r->next)
2N/A {
2N/A if (a->bufpos)
2N/A (*r->digest->write) (&r->context.c, a->buf, a->bufpos);
2N/A (*r->digest->write) (&r->context.c, inbuf, inlen);
2N/A }
2N/A a->bufpos = 0;
2N/A}
2N/A
2N/Avoid
2N/Agcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen)
2N/A{
2N/A md_write (hd, inbuf, inlen);
2N/A}
2N/A
2N/Astatic void
2N/Amd_final (gcry_md_hd_t a)
2N/A{
2N/A GcryDigestEntry *r;
2N/A
2N/A if (a->ctx->finalized)
2N/A return;
2N/A
2N/A if (a->bufpos)
2N/A md_write (a, NULL, 0);
2N/A
2N/A for (r = a->ctx->list; r; r = r->next)
2N/A (*r->digest->final) (&r->context.c);
2N/A
2N/A a->ctx->finalized = 1;
2N/A
2N/A if (a->ctx->macpads)
2N/A {
2N/A /* Finish the hmac. */
2N/A int algo = md_get_algo (a);
2N/A byte *p = md_read (a, algo);
2N/A size_t dlen = md_digest_length (algo);
2N/A gcry_md_hd_t om;
2N/A gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0);
2N/A
2N/A if (err)
2N/A _gcry_fatal_error (err, NULL);
2N/A md_write (om,
2N/A (a->ctx->macpads)+(a->ctx->macpads_Bsize),
2N/A a->ctx->macpads_Bsize);
2N/A md_write (om, p, dlen);
2N/A md_final (om);
2N/A /* Replace our digest with the mac (they have the same size). */
2N/A memcpy (p, md_read (om, algo), dlen);
2N/A md_close (om);
2N/A }
2N/A}
2N/A
2N/Astatic gcry_err_code_t
2N/Aprepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen)
2N/A{
2N/A int i;
2N/A int algo = md_get_algo (hd);
2N/A unsigned char *helpkey = NULL;
2N/A unsigned char *ipad, *opad;
2N/A
2N/A if (!algo)
2N/A return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */
2N/A
2N/A if ( keylen > hd->ctx->macpads_Bsize )
2N/A {
2N/A helpkey = gcry_malloc_secure (md_digest_length (algo));
2N/A if (!helpkey)
2N/A return gpg_err_code_from_errno (errno);
2N/A gcry_md_hash_buffer (algo, helpkey, key, keylen);
2N/A key = helpkey;
2N/A keylen = md_digest_length (algo);
2N/A gcry_assert ( keylen <= hd->ctx->macpads_Bsize );
2N/A }
2N/A
2N/A memset ( hd->ctx->macpads, 0, 2*(hd->ctx->macpads_Bsize) );
2N/A ipad = hd->ctx->macpads;
2N/A opad = (hd->ctx->macpads)+(hd->ctx->macpads_Bsize);
2N/A memcpy ( ipad, key, keylen );
2N/A memcpy ( opad, key, keylen );
2N/A for (i=0; i < hd->ctx->macpads_Bsize; i++ )
2N/A {
2N/A ipad[i] ^= 0x36;
2N/A opad[i] ^= 0x5c;
2N/A }
2N/A gcry_free (helpkey);
2N/A
2N/A return GPG_ERR_NO_ERROR;
2N/A}
2N/A
2N/Agcry_error_t
2N/Agcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
2N/A{
2N/A gcry_err_code_t rc = 0;
2N/A
2N/A switch (cmd)
2N/A {
2N/A case GCRYCTL_FINALIZE:
2N/A md_final (hd);
2N/A break;
2N/A case GCRYCTL_SET_KEY:
2N/A rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen));
2N/A break;
2N/A case GCRYCTL_START_DUMP:
2N/A md_start_debug (hd, buffer);
2N/A break;
2N/A case GCRYCTL_STOP_DUMP:
2N/A md_stop_debug ( hd );
2N/A break;
2N/A default:
2N/A rc = GPG_ERR_INV_OP;
2N/A }
2N/A return gcry_error (rc);
2N/A}
2N/A
2N/Agcry_error_t
2N/Agcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
2N/A{
2N/A gcry_err_code_t rc = GPG_ERR_NO_ERROR;
2N/A
2N/A if (!hd->ctx->macpads)
2N/A rc = GPG_ERR_CONFLICT;
2N/A else
2N/A {
2N/A rc = prepare_macpads (hd, key, keylen);
2N/A if (! rc)
2N/A gcry_md_reset (hd);
2N/A }
2N/A
2N/A return gcry_error (rc);
2N/A}
2N/A
2N/A/* The new debug interface. If SUFFIX is a string it creates an debug
2N/A file for the context HD. IF suffix is NULL, the file is closed and
2N/A debugging is stopped. */
2N/Avoid
2N/Agcry_md_debug (gcry_md_hd_t hd, const char *suffix)
2N/A{
2N/A if (suffix)
2N/A md_start_debug (hd, suffix);
2N/A else
2N/A md_stop_debug (hd);
2N/A}
2N/A
2N/A
2N/A
2N/A/****************
2N/A * if ALGO is null get the digest for the used algo (which should be only one)
2N/A */
2N/Astatic byte *
2N/Amd_read( gcry_md_hd_t a, int algo )
2N/A{
2N/A GcryDigestEntry *r = a->ctx->list;
2N/A
2N/A if (! algo)
2N/A {
2N/A /* return the first algorithm */
2N/A if (r && r->next)
2N/A log_debug ("more than one algorithm in md_read(0)\n");
2N/A return r->digest->read( &r->context.c );
2N/A }
2N/A else
2N/A {
2N/A for (r = a->ctx->list; r; r = r->next)
2N/A if (r->module->mod_id == algo)
2N/A return r->digest->read (&r->context.c);
2N/A }
2N/A BUG();
2N/A return NULL;
2N/A}
2N/A
2N/A/*
2N/A * Read out the complete digest, this function implictly finalizes
2N/A * the hash.
2N/A */
2N/Abyte *
2N/Agcry_md_read (gcry_md_hd_t hd, int algo)
2N/A{
2N/A /* This function is expected to always return a digest, thus we
2N/A can't return an error which we actually should do in
2N/A non-operational state. */
2N/A gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0);
2N/A return md_read (hd, algo);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Read out an intermediate digest. Not yet functional.
2N/A */
2N/Agcry_err_code_t
2N/Agcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen)
2N/A{
2N/A (void)hd;
2N/A (void)algo;
2N/A (void)buffer;
2N/A (void)buflen;
2N/A
2N/A /*md_digest ... */
2N/A fips_signal_error ("unimplemented function called");
2N/A return GPG_ERR_INTERNAL;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Shortcut function to hash a buffer with a given algo. The only
2N/A * guaranteed supported algorithms are RIPE-MD160 and SHA-1. The
2N/A * supplied digest buffer must be large enough to store the resulting
2N/A * hash. No error is returned, the function will abort on an invalid
2N/A * algo. DISABLED_ALGOS are ignored here. */
2N/Avoid
2N/Agcry_md_hash_buffer (int algo, void *digest,
2N/A const void *buffer, size_t length)
2N/A{
2N/A if (algo == GCRY_MD_SHA1)
2N/A _gcry_sha1_hash_buffer (digest, buffer, length);
2N/A else if (algo == GCRY_MD_RMD160 && !fips_mode () )
2N/A _gcry_rmd160_hash_buffer (digest, buffer, length);
2N/A else
2N/A {
2N/A /* For the others we do not have a fast function, so we use the
2N/A normal functions. */
2N/A gcry_md_hd_t h;
2N/A gpg_err_code_t err;
2N/A
2N/A if (algo == GCRY_MD_MD5 && fips_mode ())
2N/A {
2N/A _gcry_inactivate_fips_mode ("MD5 used");
2N/A if (_gcry_enforced_fips_mode () )
2N/A {
2N/A /* We should never get to here because we do not register
2N/A MD5 in enforced fips mode. */
2N/A _gcry_fips_noreturn ();
2N/A }
2N/A }
2N/A
2N/A err = md_open (&h, algo, 0, 0);
2N/A if (err)
2N/A log_bug ("gcry_md_open failed for algo %d: %s",
2N/A algo, gpg_strerror (gcry_error(err)));
2N/A md_write (h, (byte *) buffer, length);
2N/A md_final (h);
2N/A memcpy (digest, md_read (h, algo), md_digest_length (algo));
2N/A md_close (h);
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Amd_get_algo (gcry_md_hd_t a)
2N/A{
2N/A GcryDigestEntry *r = a->ctx->list;
2N/A
2N/A if (r && r->next)
2N/A {
2N/A fips_signal_error ("possible usage error");
2N/A log_error ("WARNING: more than one algorithm in md_get_algo()\n");
2N/A }
2N/A return r ? r->module->mod_id : 0;
2N/A}
2N/A
2N/Aint
2N/Agcry_md_get_algo (gcry_md_hd_t hd)
2N/A{
2N/A return md_get_algo (hd);
2N/A}
2N/A
2N/A
2N/A/****************
2N/A * Return the length of the digest
2N/A */
2N/Astatic int
2N/Amd_digest_length (int algorithm)
2N/A{
2N/A gcry_module_t digest;
2N/A int mdlen = 0;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A digest = _gcry_module_lookup_id (digests_registered, algorithm);
2N/A if (digest)
2N/A {
2N/A mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen;
2N/A _gcry_module_release (digest);
2N/A }
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A return mdlen;
2N/A}
2N/A
2N/A/****************
2N/A * Return the length of the digest in bytes.
2N/A * This function will return 0 in case of errors.
2N/A */
2N/Aunsigned int
2N/Agcry_md_get_algo_dlen (int algorithm)
2N/A{
2N/A return md_digest_length (algorithm);
2N/A}
2N/A
2N/A
2N/A/* Hmmm: add a mode to enumerate the OIDs
2N/A * to make g10/sig-check.c more portable */
2N/Astatic const byte *
2N/Amd_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen)
2N/A{
2N/A const byte *asnoid = NULL;
2N/A gcry_module_t digest;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A digest = _gcry_module_lookup_id (digests_registered, algorithm);
2N/A if (digest)
2N/A {
2N/A if (asnlen)
2N/A *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen;
2N/A if (mdlen)
2N/A *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen;
2N/A asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid;
2N/A _gcry_module_release (digest);
2N/A }
2N/A else
2N/A log_bug ("no ASN.1 OID for md algo %d\n", algorithm);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A return asnoid;
2N/A}
2N/A
2N/A
2N/A
2N/A/****************
2N/A * Return information about the given cipher algorithm
2N/A * WHAT select the kind of information returned:
2N/A * GCRYCTL_TEST_ALGO:
2N/A * Returns 0 when the specified algorithm is available for use.
2N/A * buffer and nbytes must be zero.
2N/A * GCRYCTL_GET_ASNOID:
2N/A * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only
2N/A * the required length is returned.
2N/A *
2N/A * Note: Because this function is in most cases used to return an
2N/A * integer value, we can make it easier for the caller to just look at
2N/A * the return value. The caller will in all cases consult the value
2N/A * and thereby detecting whether a error occured or not (i.e. while checking
2N/A * the block size)
2N/A */
2N/Agcry_error_t
2N/Agcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A
2N/A switch (what)
2N/A {
2N/A case GCRYCTL_TEST_ALGO:
2N/A if (buffer || nbytes)
2N/A err = GPG_ERR_INV_ARG;
2N/A else
2N/A err = check_digest_algo (algo);
2N/A break;
2N/A
2N/A case GCRYCTL_GET_ASNOID:
2N/A /* We need to check that the algo is available because
2N/A md_asn_oid would otherwise raise an assertion. */
2N/A err = check_digest_algo (algo);
2N/A if (!err)
2N/A {
2N/A const char unsigned *asn;
2N/A size_t asnlen;
2N/A
2N/A asn = md_asn_oid (algo, &asnlen, NULL);
2N/A if (buffer && (*nbytes >= asnlen))
2N/A {
2N/A memcpy (buffer, asn, asnlen);
2N/A *nbytes = asnlen;
2N/A }
2N/A else if (!buffer && nbytes)
2N/A *nbytes = asnlen;
2N/A else
2N/A {
2N/A if (buffer)
2N/A err = GPG_ERR_TOO_SHORT;
2N/A else
2N/A err = GPG_ERR_INV_ARG;
2N/A }
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A err = GPG_ERR_INV_OP;
2N/A }
2N/A
2N/A return gcry_error (err);
2N/A}
2N/A
2N/A
2N/Astatic void
2N/Amd_start_debug ( gcry_md_hd_t md, const char *suffix )
2N/A{
2N/A static int idx=0;
2N/A char buf[50];
2N/A
2N/A if (fips_mode ())
2N/A return;
2N/A
2N/A if ( md->ctx->debug )
2N/A {
2N/A log_debug("Oops: md debug already started\n");
2N/A return;
2N/A }
2N/A idx++;
2N/A snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix );
2N/A md->ctx->debug = fopen(buf, "w");
2N/A if ( !md->ctx->debug )
2N/A log_debug("md debug: can't open %s\n", buf );
2N/A}
2N/A
2N/Astatic void
2N/Amd_stop_debug( gcry_md_hd_t md )
2N/A{
2N/A if ( md->ctx->debug )
2N/A {
2N/A if ( md->bufpos )
2N/A md_write ( md, NULL, 0 );
2N/A fclose (md->ctx->debug);
2N/A md->ctx->debug = NULL;
2N/A }
2N/A
2N/A#ifdef HAVE_U64_TYPEDEF
2N/A { /* a kludge to pull in the __muldi3 for Solaris */
2N/A volatile u32 a = (u32)(ulong)md;
2N/A volatile u64 b = 42;
2N/A volatile u64 c;
2N/A c = a * b;
2N/A }
2N/A#endif
2N/A}
2N/A
2N/A
2N/A
2N/A/*
2N/A * Return information about the digest handle.
2N/A * GCRYCTL_IS_SECURE:
2N/A * Returns 1 when the handle works on secured memory
2N/A * otherwise 0 is returned. There is no error return.
2N/A * GCRYCTL_IS_ALGO_ENABLED:
2N/A * Returns 1 if the algo is enabled for that handle.
2N/A * The algo must be passed as the address of an int.
2N/A */
2N/Agcry_error_t
2N/Agcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A
2N/A switch (cmd)
2N/A {
2N/A case GCRYCTL_IS_SECURE:
2N/A *nbytes = h->ctx->secure;
2N/A break;
2N/A
2N/A case GCRYCTL_IS_ALGO_ENABLED:
2N/A {
2N/A GcryDigestEntry *r;
2N/A int algo;
2N/A
2N/A if ( !buffer || (nbytes && (*nbytes != sizeof (int))))
2N/A err = GPG_ERR_INV_ARG;
2N/A else
2N/A {
2N/A algo = *(int*)buffer;
2N/A
2N/A *nbytes = 0;
2N/A for(r=h->ctx->list; r; r = r->next ) {
2N/A if (r->module->mod_id == algo)
2N/A {
2N/A *nbytes = 1;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A break;
2N/A }
2N/A
2N/A default:
2N/A err = GPG_ERR_INV_OP;
2N/A }
2N/A
2N/A return gcry_error (err);
2N/A}
2N/A
2N/A
2N/A/* Explicitly initialize this module. */
2N/Agcry_err_code_t
2N/A_gcry_md_init (void)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A return err;
2N/A}
2N/A
2N/A
2N/Aint
2N/Agcry_md_is_secure (gcry_md_hd_t a)
2N/A{
2N/A size_t value;
2N/A
2N/A if (gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value))
2N/A value = 1; /* It seems to be better to assume secure memory on
2N/A error. */
2N/A return value;
2N/A}
2N/A
2N/A
2N/Aint
2N/Agcry_md_is_enabled (gcry_md_hd_t a, int algo)
2N/A{
2N/A size_t value;
2N/A
2N/A value = sizeof algo;
2N/A if (gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value))
2N/A value = 0;
2N/A return value;
2N/A}
2N/A
2N/A/* Get a list consisting of the IDs of the loaded message digest
2N/A modules. If LIST is zero, write the number of loaded message
2N/A digest modules to LIST_LENGTH and return. If LIST is non-zero, the
2N/A first *LIST_LENGTH algorithm IDs are stored in LIST, which must be
2N/A of according size. In case there are less message digest modules
2N/A than *LIST_LENGTH, *LIST_LENGTH is updated to the correct
2N/A number. */
2N/Agcry_error_t
2N/Agcry_md_list (int *list, int *list_length)
2N/A{
2N/A gcry_err_code_t err = GPG_ERR_NO_ERROR;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A err = _gcry_module_list (digests_registered, list, list_length);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A
2N/A return err;
2N/A}
2N/A
2N/A
2N/A/* Run the selftests for digest algorithm ALGO with optional reporting
2N/A function REPORT. */
2N/Agpg_error_t
2N/A_gcry_md_selftest (int algo, int extended, selftest_report_func_t report)
2N/A{
2N/A gcry_module_t module = NULL;
2N/A cipher_extra_spec_t *extraspec = NULL;
2N/A gcry_err_code_t ec = 0;
2N/A
2N/A REGISTER_DEFAULT_DIGESTS;
2N/A
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A module = _gcry_module_lookup_id (digests_registered, algo);
2N/A if (module && !(module->flags & FLAG_MODULE_DISABLED))
2N/A extraspec = module->extraspec;
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A if (extraspec && extraspec->selftest)
2N/A ec = extraspec->selftest (algo, extended, report);
2N/A else
2N/A {
2N/A ec = GPG_ERR_DIGEST_ALGO;
2N/A if (report)
2N/A report ("digest", algo, "module",
2N/A module && !(module->flags & FLAG_MODULE_DISABLED)?
2N/A "no selftest available" :
2N/A module? "algorithm disabled" : "algorithm not found");
2N/A }
2N/A
2N/A if (module)
2N/A {
2N/A ath_mutex_lock (&digests_registered_lock);
2N/A _gcry_module_release (module);
2N/A ath_mutex_unlock (&digests_registered_lock);
2N/A }
2N/A return gpg_error (ec);
2N/A}