/* md.c - message digest dispatcher
* Copyright (C) 1998, 1999, 2002, 2003, 2006,
* 2008 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* it under the terms of the GNU Lesser general Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* Libgcrypt is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "ath.h"
#include "rmd.h"
/* A dummy extraspec so that we do not need to tests the extraspec
field from the module specification against NULL and instead
directly test the respective fields of extraspecs. */
/* This is the list of the digest implementations included in
libgcrypt. */
static struct digest_table_entry
{
unsigned int algorithm;
int fips_allowed;
} digest_table[] =
{
#if USE_CRC
/* We allow the CRC algorithms even in FIPS mode because they are
actually no cryptographic primitives. */
#endif
#if USE_MD4
#endif
#if USE_MD5
#endif
#if USE_RMD160
#endif
#if USE_SHA1
#endif
#if USE_SHA256
#endif
#if USE_SHA512
#endif
#if USE_TIGER
#endif
#if USE_WHIRLPOOL
#endif
{ NULL },
};
/* List of registered digests. */
/* This is the lock protecting DIGESTS_REGISTERED. */
/* Flag to check wether the default ciphers have already been
registered. */
static int default_digests_registered;
typedef struct gcry_md_list
{
/* 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;
int secure;
int finalized;
};
/* Convenient macro for registering the default digests. */
#define REGISTER_DEFAULT_DIGESTS \
do \
{ \
if (! default_digests_registered) \
{ \
md_register_default (); \
default_digests_registered = 1; \
} \
} \
while (0)
static const char * digest_algo_to_string( int algo );
static void md_close (gcry_md_hd_t a);
static void md_final(gcry_md_hd_t a);
static int md_get_algo( gcry_md_hd_t a );
static int md_digest_length( int algo );
static void md_stop_debug ( gcry_md_hd_t a );
/* Internal function. Register all the ciphers included in
CIPHER_TABLE. Returns zero on success or an error code. */
static void
md_register_default (void)
{
int i;
{
if ( fips_mode ())
{
if (!digest_table[i].fips_allowed)
continue;
&& _gcry_enforced_fips_mode () )
continue; /* Do not register in enforced fips mode. */
}
(void *) digest_table[i].digest,
(void *) digest_table[i].extraspec,
NULL);
}
if (err)
BUG ();
}
/* Internal callback function. */
static int
{
}
/* Internal callback function. Used via _gcry_module_lookup. */
static int
{
int ret = 0, i;
if (oid_specs)
{
ret = 1;
}
return ret;
}
/* Internal function. Lookup a digest entry by it's name. */
static gcry_module_t
{
return digest;
}
/* Internal function. Lookup a cipher entry by it's oid. */
static gcry_module_t
{
return digest;
}
/* Register a new digest module whose specification can be found in
DIGEST. On success, a new algorithm ID is stored in ALGORITHM_ID
and a pointer representhing this module is stored in MODULE. */
unsigned int *algorithm_id,
{
/* We do not support module loading in fips mode. */
if (fips_mode ())
return gpg_error (GPG_ERR_NOT_SUPPORTED);
(void *) digest,
&mod);
if (! err)
{
}
return gcry_error (err);
}
/* Unregister the digest identified by ID, which must have been
registered with gcry_digest_register. */
void
{
}
static int
{
int ret = 0;
oid += 4;
if (module)
{
int i;
{
if (algorithm)
if (oid_spec)
ret = 1;
}
}
return ret;
}
/****************
* Map a string to the digest algo
*/
int
{
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 */
if (! ret)
{
/* Not found, search a matching digest name. */
if (digest)
{
}
}
return algorithm;
}
/****************
* Map a digest algo to a string
*/
static const char *
{
if (digest)
{
}
return name;
}
/****************
* 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 *
{
const char *s = digest_algo_to_string (algorithm);
return s ? s : "?";
}
static gcry_err_code_t
{
if (digest)
else
return rc;
}
/****************
* 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
{
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)
else
if (! hd)
if (! err)
{
/* Setup the globally visible data (bctl in the diagram).*/
/* Initialize the private data. */
if (hmac)
{
switch (algo)
{
case GCRY_MD_SHA384:
case GCRY_MD_SHA512:
break;
default:
break;
}
{
}
}
}
if (! err)
{
/* Hmmm, should we really do that? - yes [-wk] */
if (algo)
{
if (err)
}
}
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. */
{
else
{
(flags & GCRY_MD_FLAG_HMAC));
}
return gcry_error (err);
}
static gcry_err_code_t
{
return err; /* already enabled */
if (! module)
{
}
else
{
_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. */
}
}
if (!err)
{
/* And allocate a new list entry. */
if (h->secure)
else
if (! entry)
else
{
/* And init this instance. */
}
}
if (err)
{
if (module)
{
}
}
return err;
}
{
}
static gcry_err_code_t
{
struct gcry_md_context *b;
size_t n;
if (a->secure)
else
if (! bhd)
if (! err)
{
/* No need to copy the buffer due to the write above. */
memcpy (b, a, sizeof *a);
if (a->macpads)
{
if (! b->macpads)
{
}
else
}
}
/* Copy the complete list of algorithms. The copied list is
reversed, but that doesn't matter. */
if (!err)
{
{
if (a->secure)
else
if (!br)
{
break;
}
/* Add a reference to the module. */
}
}
if (!err)
return err;
}
{
if (err)
return gcry_error (err);
}
/*
* Reset all contexts and discard any buffered stuff. This may be used
* instead of a md_close(); md_open().
*/
void
{
GcryDigestEntry *r;
/* Note: We allow this even in fips non operational mode. */
{
}
}
static void
{
if (! a)
return;
md_stop_debug (a);
{
_gcry_module_release (r->module);
wipememory (r, r->actual_struct_size);
gcry_free (r);
}
{
}
gcry_free(a);
}
void
{
/* Note: We allow this even in fips non operational mode. */
}
static void
{
GcryDigestEntry *r;
{
BUG();
BUG();
}
{
if (a->bufpos)
}
a->bufpos = 0;
}
void
{
}
static void
{
GcryDigestEntry *r;
return;
if (a->bufpos)
{
/* Finish the hmac. */
if (err)
a->ctx->macpads_Bsize);
/* Replace our digest with the mac (they have the same size). */
}
}
static gcry_err_code_t
{
int i;
if (!algo)
return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */
{
if (!helpkey)
return gpg_err_code_from_errno (errno);
}
{
ipad[i] ^= 0x36;
opad[i] ^= 0x5c;
}
return GPG_ERR_NO_ERROR;
}
{
switch (cmd)
{
case GCRYCTL_FINALIZE:
break;
case GCRYCTL_SET_KEY:
break;
case GCRYCTL_START_DUMP:
break;
case GCRYCTL_STOP_DUMP:
md_stop_debug ( hd );
break;
default:
rc = GPG_ERR_INV_OP;
}
return gcry_error (rc);
}
{
else
{
if (! rc)
gcry_md_reset (hd);
}
return gcry_error (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
{
if (suffix)
else
md_stop_debug (hd);
}
/****************
* if ALGO is null get the digest for the used algo (which should be only one)
*/
static byte *
{
if (! algo)
{
/* return the first algorithm */
if (r && r->next)
log_debug ("more than one algorithm in md_read(0)\n");
}
else
{
}
BUG();
return NULL;
}
/*
* Read out the complete digest, this function implictly finalizes
* the hash.
*/
byte *
{
/* 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. */
}
/*
* Read out an intermediate digest. Not yet functional.
*/
{
(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
{
if (algo == GCRY_MD_SHA1)
else
{
/* For the others we do not have a fast function, so we use the
normal functions. */
gcry_md_hd_t h;
{
_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. */
}
}
if (err)
log_bug ("gcry_md_open failed for algo %d: %s",
md_final (h);
md_close (h);
}
}
static int
{
if (r && r->next)
{
fips_signal_error ("possible usage error");
log_error ("WARNING: more than one algorithm in md_get_algo()\n");
}
}
int
{
return md_get_algo (hd);
}
/****************
* Return the length of the digest
*/
static int
{
int mdlen = 0;
if (digest)
{
}
return mdlen;
}
/****************
* Return the length of the digest in bytes.
* This function will return 0 in case of errors.
*/
unsigned int
{
return md_digest_length (algorithm);
}
/* Hmmm: add a mode to enumerate the OIDs
* to make g10/sig-check.c more portable */
static const byte *
{
if (digest)
{
if (asnlen)
if (mdlen)
}
else
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.
*
* 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 occured or not (i.e. while checking
* the block size)
*/
{
switch (what)
{
case GCRYCTL_TEST_ALGO:
else
break;
case GCRYCTL_GET_ASNOID:
/* We need to check that the algo is available because
md_asn_oid would otherwise raise an assertion. */
if (!err)
{
const char unsigned *asn;
{
}
else
{
if (buffer)
else
}
}
break;
default:
}
return gcry_error (err);
}
static void
{
static int idx=0;
if (fips_mode ())
return;
{
log_debug("Oops: md debug already started\n");
return;
}
idx++;
}
static void
{
{
}
#ifdef HAVE_U64_TYPEDEF
{ /* a kludge to pull in the __muldi3 for Solaris */
volatile u64 b = 42;
volatile u64 c;
c = a * b;
}
#endif
}
/*
* 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.
*/
{
switch (cmd)
{
case GCRYCTL_IS_SECURE:
break;
case GCRYCTL_IS_ALGO_ENABLED:
{
GcryDigestEntry *r;
int algo;
else
{
*nbytes = 0;
{
*nbytes = 1;
break;
}
}
}
break;
}
default:
}
return gcry_error (err);
}
/* Explicitly initialize this module. */
_gcry_md_init (void)
{
return err;
}
int
{
error. */
return value;
}
int
{
value = 0;
return value;
}
/* Get a list consisting of the IDs of the loaded message digest
modules. If LIST is zero, write the number of loaded message
digest modules to LIST_LENGTH and return. If LIST is non-zero, the
first *LIST_LENGTH algorithm IDs are stored in LIST, which must be
of according size. In case there are less message digest modules
than *LIST_LENGTH, *LIST_LENGTH is updated to the correct
number. */
{
return err;
}
/* Run the selftests for digest algorithm ALGO with optional reporting
function REPORT. */
{
else
{
if (report)
"no selftest available" :
}
if (module)
{
}
}