diff options
Diffstat (limited to 'plugins/MirOTR/Libgcrypt/cipher/md.c')
-rw-r--r-- | plugins/MirOTR/Libgcrypt/cipher/md.c | 889 |
1 files changed, 384 insertions, 505 deletions
diff --git a/plugins/MirOTR/Libgcrypt/cipher/md.c b/plugins/MirOTR/Libgcrypt/cipher/md.c index da07783d92..008ef5b230 100644 --- a/plugins/MirOTR/Libgcrypt/cipher/md.c +++ b/plugins/MirOTR/Libgcrypt/cipher/md.c @@ -1,6 +1,7 @@ /* 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. * @@ -30,103 +31,75 @@ #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. */ -static md_extra_spec_t dummy_extra_spec; - /* This is the list of the digest implementations included in libgcrypt. */ -static struct digest_table_entry -{ - gcry_md_spec_t *digest; - md_extra_spec_t *extraspec; - unsigned int algorithm; - int fips_allowed; -} digest_table[] = +static gcry_md_spec_t *digest_list[] = { -#if USE_CRC - /* We allow the CRC algorithms even in FIPS mode because they are - actually no cryptographic primitives. */ - { &_gcry_digest_spec_crc32, - &dummy_extra_spec, GCRY_MD_CRC32, 1 }, - { &_gcry_digest_spec_crc32_rfc1510, - &dummy_extra_spec, GCRY_MD_CRC32_RFC1510, 1 }, - { &_gcry_digest_spec_crc24_rfc2440, - &dummy_extra_spec, GCRY_MD_CRC24_RFC2440, 1 }, -#endif -#if USE_MD4 - { &_gcry_digest_spec_md4, - &dummy_extra_spec, GCRY_MD_MD4 }, -#endif -#if USE_MD5 - { &_gcry_digest_spec_md5, - &dummy_extra_spec, GCRY_MD_MD5, 1 }, -#endif -#if USE_RMD160 - { &_gcry_digest_spec_rmd160, - &dummy_extra_spec, GCRY_MD_RMD160 }, +#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, - &_gcry_digest_extraspec_sha1, GCRY_MD_SHA1, 1 }, + &_gcry_digest_spec_sha1, #endif #if USE_SHA256 - { &_gcry_digest_spec_sha256, - &_gcry_digest_extraspec_sha256, GCRY_MD_SHA256, 1 }, - { &_gcry_digest_spec_sha224, - &_gcry_digest_extraspec_sha224, GCRY_MD_SHA224, 1 }, + &_gcry_digest_spec_sha256, + &_gcry_digest_spec_sha224, #endif #if USE_SHA512 - { &_gcry_digest_spec_sha512, - &_gcry_digest_extraspec_sha512, GCRY_MD_SHA512, 1 }, - { &_gcry_digest_spec_sha384, - &_gcry_digest_extraspec_sha384, GCRY_MD_SHA384, 1 }, + &_gcry_digest_spec_sha512, + &_gcry_digest_spec_sha384, #endif -#if USE_TIGER - { &_gcry_digest_spec_tiger, - &dummy_extra_spec, GCRY_MD_TIGER }, - { &_gcry_digest_spec_tiger1, - &dummy_extra_spec, GCRY_MD_TIGER1 }, - { &_gcry_digest_spec_tiger2, - &dummy_extra_spec, GCRY_MD_TIGER2 }, +#ifdef USE_GOST_R_3411_94 + &_gcry_digest_spec_gost3411_94, +#endif +#ifdef USE_GOST_R_3411_12 + &_gcry_digest_spec_stribog_256, + &_gcry_digest_spec_stribog_512, #endif #if USE_WHIRLPOOL - { &_gcry_digest_spec_whirlpool, - &dummy_extra_spec, GCRY_MD_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 - { NULL }, +#if USE_MD4 + &_gcry_digest_spec_md4, +#endif + NULL }; -/* List of registered digests. */ -static gcry_module_t digests_registered; - -/* This is the lock protecting DIGESTS_REGISTERED. */ -static ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER; - -/* Flag to check wether the default ciphers have already been - registered. */ -static int default_digests_registered; typedef struct gcry_md_list { - gcry_md_spec_t *digest; - gcry_module_t module; + 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 +/* 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. */ - int secure; FILE *debug; - int finalized; + struct { + unsigned int secure: 1; + unsigned int finalized:1; + unsigned int bugemu1:1; + } flags; GcryDigestEntry *list; byte *macpads; int macpads_Bsize; /* Blocksize as used for the HMAC pads. */ @@ -136,301 +109,175 @@ struct gcry_md_context #define CTX_MAGIC_NORMAL 0x11071961 #define CTX_MAGIC_SECURE 0x16917011 -/* Convenient macro for registering the default digests. */ -#define REGISTER_DEFAULT_DIGESTS \ - do \ - { \ - ath_mutex_lock (&digests_registered_lock); \ - if (! default_digests_registered) \ - { \ - md_register_default (); \ - default_digests_registered = 1; \ - } \ - ath_mutex_unlock (&digests_registered_lock); \ - } \ - while (0) - - -static const char * digest_algo_to_string( int algo ); -static gcry_err_code_t check_digest_algo (int algo); -static gcry_err_code_t md_open (gcry_md_hd_t *h, int algo, - int secure, int hmac); static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); -static gcry_err_code_t md_copy (gcry_md_hd_t a, gcry_md_hd_t *b); 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 void md_final(gcry_md_hd_t a); 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 const byte *md_asn_oid( int algo, size_t *asnlen, size_t *mdlen ); 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; +} -/* Internal function. Register all the ciphers included in - CIPHER_TABLE. Returns zero on success or an error code. */ -static void -md_register_default (void) +/* 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) { - gcry_err_code_t err = 0; - int i; - - for (i = 0; !err && digest_table[i].digest; i++) - { - if ( fips_mode ()) - { - if (!digest_table[i].fips_allowed) - continue; - if (digest_table[i].algorithm == GCRY_MD_MD5 - && _gcry_enforced_fips_mode () ) - continue; /* Do not register in enforced fips mode. */ - } + int idx; + gcry_md_spec_t *spec; - err = _gcry_module_add (&digests_registered, - digest_table[i].algorithm, - (void *) digest_table[i].digest, - (void *) digest_table[i].extraspec, - NULL); - } + algo = map_algo (algo); - if (err) - BUG (); + for (idx = 0; (spec = digest_list[idx]); idx++) + if (algo == spec->algo) + return spec; + return NULL; } -/* Internal callback function. */ -static int -gcry_md_lookup_func_name (void *spec, void *data) -{ - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *name = (char *) data; - return (!_stricmp (digest->name, name)); -} - -/* Internal callback function. Used via _gcry_module_lookup. */ -static int -gcry_md_lookup_func_oid (void *spec, void *data) +/* Lookup a hash's spec by its name. */ +static gcry_md_spec_t * +spec_from_name (const char *name) { - gcry_md_spec_t *digest = (gcry_md_spec_t *) spec; - char *oid = (char *) data; - gcry_md_oid_spec_t *oid_specs = digest->oids; - int ret = 0, i; + gcry_md_spec_t *spec; + int idx; - if (oid_specs) + for (idx=0; (spec = digest_list[idx]); idx++) { - for (i = 0; oid_specs[i].oidstring && (! ret); i++) - if (!_stricmp (oid, oid_specs[i].oidstring)) - ret = 1; + if (!stricmp (name, spec->name)) + return spec; } - return ret; -} - -/* Internal function. Lookup a digest entry by it's name. */ -static gcry_module_t -gcry_md_lookup_name (const char *name) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) name, - gcry_md_lookup_func_name); - - return digest; + return NULL; } -/* Internal function. Lookup a cipher entry by it's oid. */ -static gcry_module_t -gcry_md_lookup_oid (const char *oid) -{ - gcry_module_t digest; - - digest = _gcry_module_lookup (digests_registered, (void *) oid, - gcry_md_lookup_func_oid); - - 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. */ -gcry_error_t -_gcry_md_register (gcry_md_spec_t *digest, - md_extra_spec_t *extraspec, - unsigned int *algorithm_id, - gcry_module_t *module) +/* Lookup a hash's spec by its OID. */ +static gcry_md_spec_t * +spec_from_oid (const char *oid) { - gcry_err_code_t err = 0; - gcry_module_t mod; + gcry_md_spec_t *spec; + gcry_md_oid_spec_t *oid_specs; + int idx, j; - /* We do not support module loading in fips mode. */ - if (fips_mode ()) - return gpg_error (GPG_ERR_NOT_SUPPORTED); - - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_add (&digests_registered, 0, - (void *) digest, - (void *)(extraspec? extraspec : &dummy_extra_spec), - &mod); - ath_mutex_unlock (&digests_registered_lock); - - if (! err) + for (idx=0; (spec = digest_list[idx]); idx++) { - *module = mod; - *algorithm_id = mod->mod_id; + 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 gcry_error (err); -} - -/* Unregister the digest identified by ID, which must have been - registered with gcry_digest_register. */ -void -gcry_md_unregister (gcry_module_t module) -{ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); + return NULL; } -static int -search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec) +static gcry_md_spec_t * +search_oid (const char *oid, gcry_md_oid_spec_t *oid_spec) { - gcry_module_t module; - int ret = 0; + gcry_md_spec_t *spec; + int i; if (oid && ((! strncmp (oid, "oid.", 4)) || (! strncmp (oid, "OID.", 4)))) oid += 4; - module = gcry_md_lookup_oid (oid); - if (module) + spec = spec_from_oid (oid); + if (spec && spec->oids) { - gcry_md_spec_t *digest = module->spec; - int i; - - for (i = 0; digest->oids[i].oidstring && !ret; i++) - if (!_stricmp (oid, digest->oids[i].oidstring)) + for (i = 0; spec->oids[i].oidstring; i++) + if (!stricmp (oid, spec->oids[i].oidstring)) { - if (algorithm) - *algorithm = module->mod_id; if (oid_spec) - *oid_spec = digest->oids[i]; - ret = 1; + *oid_spec = spec->oids[i]; + return spec; } - _gcry_module_release (module); } - return ret; + return NULL; } + /**************** * Map a string to the digest algo */ int -gcry_md_map_name (const char *string) +_gcry_md_map_name (const char *string) { - gcry_module_t digest; - int ret, algorithm = 0; + gcry_md_spec_t *spec; - if (! string) + if (!string) return 0; - REGISTER_DEFAULT_DIGESTS; - /* 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; - ath_mutex_lock (&digests_registered_lock); + /* Not found, search a matching digest name. */ + spec = spec_from_name (string); + if (spec) + return spec->algo; - ret = search_oid (string, &algorithm, NULL); - if (! ret) - { - /* Not found, search a matching digest name. */ - digest = gcry_md_lookup_name (string); - if (digest) - { - algorithm = digest->mod_id; - _gcry_module_release (digest); - } - } - ath_mutex_unlock (&digests_registered_lock); - - return algorithm; + return 0; } /**************** - * Map a digest algo to a string - */ -static const char * -digest_algo_to_string (int algorithm) -{ - const char *name = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - name = ((gcry_md_spec_t *) digest->spec)->name; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - 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 * -gcry_md_algo_name (int algorithm) +_gcry_md_algo_name (int algorithm) { - const char *s = digest_algo_to_string (algorithm); - return s ? s : "?"; + 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_err_code_t rc = 0; - gcry_module_t digest; + gcry_md_spec_t *spec; - REGISTER_DEFAULT_DIGESTS; + spec = spec_from_algo (algorithm); + if (spec && !spec->flags.disabled) + return 0; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - _gcry_module_release (digest); - else - rc = GPG_ERR_DIGEST_ALGO; - ath_mutex_unlock (&digests_registered_lock); + return GPG_ERR_DIGEST_ALGO; - 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 -md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) +md_open (gcry_md_hd_t *h, int algo, unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + 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; @@ -456,9 +303,9 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) /* Allocate and set the Context pointer to the private data */ if (secure) - hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); + hd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); else - hd = gcry_malloc (n + sizeof (struct gcry_md_context)); + hd = xtrymalloc (n + sizeof (struct gcry_md_context)); if (! hd) err = gpg_err_code_from_errno (errno); @@ -474,7 +321,8 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) 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->secure = secure; + ctx->flags.secure = secure; + ctx->flags.bugemu1 = !!(flags & GCRY_MD_FLAG_BUGEMU1); if (hmac) { @@ -484,11 +332,14 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) case GCRY_MD_SHA512: ctx->macpads_Bsize = 128; break; + case GCRY_MD_GOSTR3411_94: + ctx->macpads_Bsize = 32; + break; default: ctx->macpads_Bsize = 64; break; } - ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize)); + ctx->macpads = xtrymalloc_secure (2*(ctx->macpads_Bsize)); if (!ctx->macpads) { err = gpg_err_code_from_errno (errno); @@ -521,22 +372,21 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac) 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_error_t -gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) +gcry_err_code_t +_gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; gcry_md_hd_t hd; - if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC))) - err = GPG_ERR_INV_ARG; + if ((flags & ~(GCRY_MD_FLAG_SECURE + | GCRY_MD_FLAG_HMAC + | GCRY_MD_FLAG_BUGEMU1))) + rc = GPG_ERR_INV_ARG; else - { - err = md_open (&hd, algo, (flags & GCRY_MD_FLAG_SECURE), - (flags & GCRY_MD_FLAG_HMAC)); - } + rc = md_open (&hd, algo, flags); - *h = err? NULL : hd; - return gcry_error (err); + *h = rc? NULL : hd; + return rc; } @@ -545,29 +395,22 @@ 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 *digest = NULL; + gcry_md_spec_t *spec; GcryDigestEntry *entry; - gcry_module_t module; gcry_err_code_t err = 0; for (entry = h->list; entry; entry = entry->next) - if (entry->module->mod_id == algorithm) - return err; /* already enabled */ - - REGISTER_DEFAULT_DIGESTS; + if (entry->spec->algo == algorithm) + return 0; /* Already enabled */ - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algorithm); - ath_mutex_unlock (&digests_registered_lock); - if (! module) + spec = spec_from_algo (algorithm); + if (!spec) { log_debug ("md_enable: algorithm %d not available\n", algorithm); err = GPG_ERR_DIGEST_ALGO; } - else - digest = (gcry_md_spec_t *) module->spec; - + if (!err && algorithm == GCRY_MD_MD5 && fips_mode ()) { _gcry_inactivate_fips_mode ("MD5 used"); @@ -578,41 +421,31 @@ md_enable (gcry_md_hd_t hd, int algorithm) err = GPG_ERR_DIGEST_ALGO; } } - + if (!err) { size_t size = (sizeof (*entry) - + digest->contextsize + + spec->contextsize - sizeof (entry->context)); /* And allocate a new list entry. */ - if (h->secure) - entry = gcry_malloc_secure (size); + if (h->flags.secure) + entry = xtrymalloc_secure (size); else - entry = gcry_malloc (size); + entry = xtrymalloc (size); if (! entry) err = gpg_err_code_from_errno (errno); else { - entry->digest = digest; - entry->module = module; + entry->spec = spec; entry->next = h->list; entry->actual_struct_size = size; h->list = entry; /* And init this instance. */ - entry->digest->init (&entry->context.c); - } - } - - if (err) - { - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); + entry->spec->init (&entry->context.c, + h->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); } } @@ -620,30 +453,31 @@ md_enable (gcry_md_hd_t hd, int algorithm) } -gcry_error_t -gcry_md_enable (gcry_md_hd_t hd, int algorithm) +gcry_err_code_t +_gcry_md_enable (gcry_md_hd_t hd, int algorithm) { - return gcry_error (md_enable (hd, 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 = GPG_ERR_NO_ERROR; + 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->secure) - bhd = gcry_malloc_secure (n + sizeof (struct gcry_md_context)); + if (a->flags.secure) + bhd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); else - bhd = gcry_malloc (n + sizeof (struct gcry_md_context)); + bhd = xtrymalloc (n + sizeof (struct gcry_md_context)); if (! bhd) err = gpg_err_code_from_errno (errno); @@ -661,7 +495,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) b->debug = NULL; if (a->macpads) { - b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize)); + b->macpads = xtrymalloc_secure (2*(a->macpads_Bsize)); if (! b->macpads) { err = gpg_err_code_from_errno (errno); @@ -678,14 +512,14 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) { for (ar = a->list; ar; ar = ar->next) { - if (a->secure) - br = gcry_malloc_secure (sizeof *br - + ar->digest->contextsize - - sizeof(ar->context)); + if (a->flags.secure) + br = xtrymalloc_secure (sizeof *br + + ar->spec->contextsize + - sizeof(ar->context)); else - br = gcry_malloc (sizeof *br - + ar->digest->contextsize - - sizeof (ar->context)); + br = xtrymalloc (sizeof *br + + ar->spec->contextsize + - sizeof (ar->context)); if (!br) { err = gpg_err_code_from_errno (errno); @@ -693,15 +527,10 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) break; } - memcpy (br, ar, (sizeof (*br) + ar->digest->contextsize + memcpy (br, ar, (sizeof (*br) + ar->spec->contextsize - sizeof (ar->context))); br->next = b->list; b->list = br; - - /* Add a reference to the module. */ - ath_mutex_lock (&digests_registered_lock); - _gcry_module_use (br->module); - ath_mutex_unlock (&digests_registered_lock); } } @@ -714,39 +543,43 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) return err; } -gcry_error_t -gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) + +gcry_err_code_t +_gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) { - gcry_err_code_t err; + gcry_err_code_t rc; - err = md_copy (hd, handle); - if (err) + rc = md_copy (hd, handle); + if (rc) *handle = NULL; - return gcry_error (err); + 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) +_gcry_md_reset (gcry_md_hd_t a) { GcryDigestEntry *r; /* Note: We allow this even in fips non operational mode. */ - a->bufpos = a->ctx->finalized = 0; + a->bufpos = a->ctx->flags.finalized = 0; for (r = a->ctx->list; r; r = r->next) { - memset (r->context.c, 0, r->digest->contextsize); - (*r->digest->init) (&r->context.c); + memset (r->context.c, 0, r->spec->contextsize); + (*r->spec->init) (&r->context.c, + a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); } if (a->ctx->macpads) md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */ } + static void md_close (gcry_md_hd_t a) { @@ -759,35 +592,34 @@ md_close (gcry_md_hd_t a) for (r = a->ctx->list; r; r = r2) { r2 = r->next; - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (r->module); - ath_mutex_unlock (&digests_registered_lock); wipememory (r, r->actual_struct_size); - gcry_free (r); + xfree (r); } if (a->ctx->macpads) { wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize)); - gcry_free(a->ctx->macpads); + xfree(a->ctx->macpads); } wipememory (a, a->ctx->actual_handle_size); - gcry_free(a); + xfree(a); } + void -gcry_md_close (gcry_md_hd_t hd) +_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) @@ -799,33 +631,35 @@ md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) for (r = a->ctx->list; r; r = r->next) { if (a->bufpos) - (*r->digest->write) (&r->context.c, a->buf, a->bufpos); - (*r->digest->write) (&r->context.c, inbuf, inlen); + (*r->spec->write) (&r->context.c, a->buf, a->bufpos); + (*r->spec->write) (&r->context.c, inbuf, inlen); } a->bufpos = 0; } + void -gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) +_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->finalized) + if (a->ctx->flags.finalized) return; if (a->bufpos) md_write (a, NULL, 0); for (r = a->ctx->list; r; r = r->next) - (*r->digest->final) (&r->context.c); + (*r->spec->final) (&r->context.c); - a->ctx->finalized = 1; + a->ctx->flags.finalized = 1; if (a->ctx->macpads) { @@ -834,12 +668,15 @@ md_final (gcry_md_hd_t a) byte *p = md_read (a, algo); size_t dlen = md_digest_length (algo); gcry_md_hd_t om; - gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0); + gcry_err_code_t err; + err = md_open (&om, algo, + ((a->ctx->flags.secure? GCRY_MD_FLAG_SECURE:0) + | (a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0))); if (err) _gcry_fatal_error (err, NULL); - md_write (om, - (a->ctx->macpads)+(a->ctx->macpads_Bsize), + md_write (om, + (a->ctx->macpads)+(a->ctx->macpads_Bsize), a->ctx->macpads_Bsize); md_write (om, p, dlen); md_final (om); @@ -849,6 +686,7 @@ md_final (gcry_md_hd_t a) } } + static gcry_err_code_t prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) { @@ -860,12 +698,12 @@ prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) if (!algo) return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ - if ( keylen > hd->ctx->macpads_Bsize ) + if ( keylen > hd->ctx->macpads_Bsize ) { - helpkey = gcry_malloc_secure (md_digest_length (algo)); + helpkey = xtrymalloc_secure (md_digest_length (algo)); if (!helpkey) return gpg_err_code_from_errno (errno); - gcry_md_hash_buffer (algo, helpkey, key, keylen); + _gcry_md_hash_buffer (algo, helpkey, key, keylen); key = helpkey; keylen = md_digest_length (algo); gcry_assert ( keylen <= hd->ctx->macpads_Bsize ); @@ -876,29 +714,29 @@ prepare_macpads (gcry_md_hd_t hd, const unsigned char *key, size_t keylen) opad = (hd->ctx->macpads)+(hd->ctx->macpads_Bsize); memcpy ( ipad, key, keylen ); memcpy ( opad, key, keylen ); - for (i=0; i < hd->ctx->macpads_Bsize; i++ ) + for (i=0; i < hd->ctx->macpads_Bsize; i++ ) { ipad[i] ^= 0x36; opad[i] ^= 0x5c; } - gcry_free (helpkey); + xfree (helpkey); - return GPG_ERR_NO_ERROR; + return 0; } -gcry_error_t -gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) + +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_SET_KEY: - rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen)); - break; case GCRYCTL_START_DUMP: md_start_debug (hd, buffer); break; @@ -908,31 +746,33 @@ gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) default: rc = GPG_ERR_INV_OP; } - return gcry_error (rc); + return rc; } -gcry_error_t -gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) + +gcry_err_code_t +_gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) { - gcry_err_code_t rc = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; if (!hd->ctx->macpads) rc = GPG_ERR_CONFLICT; else { rc = prepare_macpads (hd, key, keylen); - if (! rc) - gcry_md_reset (hd); + if (!rc) + _gcry_md_reset (hd); } - return gcry_error (rc); + 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) +_gcry_md_debug (gcry_md_hd_t hd, const char *suffix) { if (suffix) md_start_debug (hd, suffix); @@ -941,9 +781,9 @@ gcry_md_debug (gcry_md_hd_t hd, const char *suffix) } - /**************** - * if ALGO is null get the digest for the used algo (which should be only one) + * 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 ) @@ -952,35 +792,36 @@ md_read( gcry_md_hd_t a, int algo ) if (! algo) { - /* Return the first algorithm. */ + /* Return the first algorithm */ if (r) { if (r->next) log_debug ("more than one algorithm in md_read(0)\n"); - return r->digest->read( &r->context.c ); + return r->spec->read (&r->context.c); } } else { for (r = a->ctx->list; r; r = r->next) - if (r->module->mod_id == algo) - return r->digest->read (&r->context.c); + if (r->spec->algo == algo) + return r->spec->read (&r->context.c); } BUG(); return NULL; } + /* * Read out the complete digest, this function implictly finalizes * the hash. */ byte * -gcry_md_read (gcry_md_hd_t hd, int algo) +_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); + _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); return md_read (hd, algo); } @@ -989,7 +830,7 @@ gcry_md_read (gcry_md_hd_t hd, int algo) * 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) +_gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) { (void)hd; (void)algo; @@ -1009,8 +850,8 @@ gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) * 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) +_gcry_md_hash_buffer (int algo, void *digest, + const void *buffer, size_t length) { if (algo == GCRY_MD_SHA1) _gcry_sha1_hash_buffer (digest, buffer, length); @@ -1034,7 +875,7 @@ gcry_md_hash_buffer (int algo, void *digest, } } - err = md_open (&h, algo, 0, 0); + err = md_open (&h, algo, 0); if (err) log_bug ("gcry_md_open failed for algo %d: %s", algo, gpg_strerror (gcry_error(err))); @@ -1045,6 +886,83 @@ gcry_md_hash_buffer (int algo, void *digest, } } + +/* 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 (algo == GCRY_MD_SHA1 && !hmac) + _gcry_sha1_hash_buffers (digest, iov, iovcnt); + 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; + + 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 (); + } + } + + 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), md_digest_length (algo)); + md_close (h); + } + + return 0; +} + + static int md_get_algo (gcry_md_hd_t a) { @@ -1055,11 +973,12 @@ md_get_algo (gcry_md_hd_t a) fips_signal_error ("possible usage error"); log_error ("WARNING: more than one algorithm in md_get_algo()\n"); } - return r ? r->module->mod_id : 0; + return r ? r->spec->algo : 0; } + int -gcry_md_get_algo (gcry_md_hd_t hd) +_gcry_md_get_algo (gcry_md_hd_t hd) { return md_get_algo (hd); } @@ -1071,29 +990,19 @@ gcry_md_get_algo (gcry_md_hd_t hd) static int md_digest_length (int algorithm) { - gcry_module_t digest; - int mdlen = 0; - - REGISTER_DEFAULT_DIGESTS; + gcry_md_spec_t *spec; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) - { - mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - _gcry_module_release (digest); - } - ath_mutex_unlock (&digests_registered_lock); - - return mdlen; + 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) +_gcry_md_get_algo_dlen (int algorithm) { return md_digest_length (algorithm); } @@ -1104,31 +1013,25 @@ gcry_md_get_algo_dlen (int algorithm) static const byte * md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) { + gcry_md_spec_t *spec; const byte *asnoid = NULL; - gcry_module_t digest; - - REGISTER_DEFAULT_DIGESTS; - ath_mutex_lock (&digests_registered_lock); - digest = _gcry_module_lookup_id (digests_registered, algorithm); - if (digest) + spec = spec_from_algo (algorithm); + if (spec) { if (asnlen) - *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen; + *asnlen = spec->asnlen; if (mdlen) - *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen; - asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid; - _gcry_module_release (digest); + *mdlen = spec->mdlen; + asnoid = spec->asnoid; } else log_bug ("no ASN.1 OID for md algo %d\n", algorithm); - ath_mutex_unlock (&digests_registered_lock); return asnoid; } - /**************** * Return information about the given cipher algorithm * WHAT select the kind of information returned: @@ -1138,59 +1041,68 @@ md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) * 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 occured or not (i.e. while checking + * and thereby detecting whether a error occurred or not (i.e. while checking * the block size) */ -gcry_error_t -gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc; switch (what) { case GCRYCTL_TEST_ALGO: if (buffer || nbytes) - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; else - err = check_digest_algo (algo); + 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. */ - err = check_digest_algo (algo); - if (!err) + 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; - } + { + memcpy (buffer, asn, asnlen); + *nbytes = asnlen; + } else if (!buffer && nbytes) *nbytes = asnlen; else { if (buffer) - err = GPG_ERR_TOO_SHORT; + rc = GPG_ERR_TOO_SHORT; else - err = GPG_ERR_INV_ARG; + rc = GPG_ERR_INV_ARG; } } break; - default: - err = GPG_ERR_INV_OP; + 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 gcry_error (err); + return rc; } @@ -1202,7 +1114,7 @@ md_start_debug ( gcry_md_hd_t md, const char *suffix ) if (fips_mode ()) return; - + if ( md->ctx->debug ) { log_debug("Oops: md debug already started\n"); @@ -1215,6 +1127,7 @@ md_start_debug ( gcry_md_hd_t md, const char *suffix ) log_debug("md debug: can't open %s\n", buf ); } + static void md_stop_debug( gcry_md_hd_t md ) { @@ -1232,6 +1145,7 @@ md_stop_debug( gcry_md_hd_t md ) volatile u64 b = 42; volatile u64 c; c = a * b; + (void)c; } #endif } @@ -1247,15 +1161,15 @@ md_stop_debug( gcry_md_hd_t md ) * Returns 1 if the algo is enabled for that handle. * The algo must be passed as the address of an int. */ -gcry_error_t -gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) +gcry_err_code_t +_gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; + gcry_err_code_t rc = 0; switch (cmd) { case GCRYCTL_IS_SECURE: - *nbytes = h->ctx->secure; + *nbytes = h->ctx->flags.secure; break; case GCRYCTL_IS_ALGO_ENABLED: @@ -1263,15 +1177,15 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) GcryDigestEntry *r; int algo; - if ( !buffer || (nbytes && (*nbytes != sizeof (int)))) - err = GPG_ERR_INV_ARG; + 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->module->mod_id == algo) + if (r->spec->algo == algo) { *nbytes = 1; break; @@ -1282,10 +1196,10 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) } default: - err = GPG_ERR_INV_OP; + rc = GPG_ERR_INV_OP; } - return gcry_error (err); + return rc; } @@ -1293,20 +1207,16 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) gcry_err_code_t _gcry_md_init (void) { - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - REGISTER_DEFAULT_DIGESTS; - - return err; + return 0; } int -gcry_md_is_secure (gcry_md_hd_t a) +_gcry_md_is_secure (gcry_md_hd_t a) { size_t value; - if (gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &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; @@ -1314,69 +1224,38 @@ gcry_md_is_secure (gcry_md_hd_t a) int -gcry_md_is_enabled (gcry_md_hd_t a, int algo) +_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)) + if (_gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) 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. */ -gcry_error_t -gcry_md_list (int *list, int *list_length) -{ - gcry_err_code_t err = GPG_ERR_NO_ERROR; - - ath_mutex_lock (&digests_registered_lock); - err = _gcry_module_list (digests_registered, list, list_length); - ath_mutex_unlock (&digests_registered_lock); - - return err; -} - /* 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_module_t module = NULL; - cipher_extra_spec_t *extraspec = NULL; gcry_err_code_t ec = 0; + gcry_md_spec_t *spec; - REGISTER_DEFAULT_DIGESTS; - - ath_mutex_lock (&digests_registered_lock); - module = _gcry_module_lookup_id (digests_registered, algo); - if (module && !(module->flags & FLAG_MODULE_DISABLED)) - extraspec = module->extraspec; - ath_mutex_unlock (&digests_registered_lock); - if (extraspec && extraspec->selftest) - ec = extraspec->selftest (algo, extended, report); + spec = spec_from_algo (algo); + if (spec && !spec->flags.disabled && spec->selftest) + ec = spec->selftest (algo, extended, report); else { - ec = GPG_ERR_DIGEST_ALGO; + ec = (spec && spec->selftest) ? GPG_ERR_DIGEST_ALGO + /* */ : GPG_ERR_NOT_IMPLEMENTED; if (report) - report ("digest", algo, "module", - module && !(module->flags & FLAG_MODULE_DISABLED)? + report ("digest", algo, "module", + (spec && !spec->flags.disabled)? "no selftest available" : - module? "algorithm disabled" : "algorithm not found"); + spec? "algorithm disabled" : "algorithm not found"); } - if (module) - { - ath_mutex_lock (&digests_registered_lock); - _gcry_module_release (module); - ath_mutex_unlock (&digests_registered_lock); - } return gpg_error (ec); } |