A whole bunch of changes to eventually support
[libgcrypt.git] / cipher / md.c
index 4872e49..2cc25b7 100644 (file)
@@ -1,5 +1,6 @@
 /* md.c  -  message digest dispatcher
- * Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2002, 2003, 2006,
+ *               2008 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -14,8 +15,7 @@
  * 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 
 #include "rmd.h"
 
-static struct {
-  const char *oidstring;
-  int algo;
-} oid_table[] = {
-  /* iso.member-body.us.rsadsi.pkcs.pkcs-1.5 (sha1WithRSAEncryption) */
-  { "1.2.840.113549.1.1.5",  GCRY_MD_SHA1 },
-  /* iso.member-body.us.rsadsi.pkcs.pkcs-1.4 (md5WithRSAEncryption) */
-  { "1.2.840.113549.1.1.4",  GCRY_MD_MD5 },
-  /* iso.member-body.us.x9-57.x9cm.3 (dsaWithSha1)*/
-  { "1.2.840.10040.4.3",     GCRY_MD_SHA1 },
-  /* from NIST's OIW  (sha1) */
-  { "1.3.14.3.2.26",         GCRY_MD_SHA1 },
-  /* rsaSignatureWithripemd160 */
-  { "1.3.36.3.3.1.2",       GCRY_MD_RMD160 },
-  /* RSADSI digestAlgorithm MD5 */
-  { "1.2.840.113549.2.5",   GCRY_MD_MD5 },
-  /* GNU.digestAlgorithm TIGER */
-  { "1.3.6.1.4.1.11591.12.2", GCRY_MD_TIGER },
-  /* iso.member-body.us.rsadsi.digestAlgorithm.md4 */
-  { "1.2.840.113549.2.4", GCRY_MD_MD4 },
-  /* from NIST OIW (sha-1WithRSAEncryption) */
-  { "1.3.14.3.2.29", GCRY_MD_SHA1 },
-  /* According to the OpenPGG draft rfc2440-bis06 */
-  { "2.16.840.1.101.3.4.2.1", GCRY_MD_SHA256 }, 
-  { "2.16.840.1.101.3.4.2.2", GCRY_MD_SHA384 }, 
-  { "2.16.840.1.101.3.4.2.3", GCRY_MD_SHA512 }, 
-  {NULL}
-};
+/* 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;
+
 
-static struct
+/* This is the list of the digest implementations included in
+   libgcrypt.  */
+static struct digest_table_entry
 {
-  gcry_digest_spec_t *digest;
-  int flags;
+  gcry_md_spec_t *digest;
+  md_extra_spec_t *extraspec;
+  unsigned int algorithm;
+  int fips_allowed;
 } digest_table[] =
   {
 #if USE_CRC    
-    { &digest_spec_crc32, 0 },
-    { &digest_spec_crc32_rfc1510, 0 },
-    { &digest_spec_crc24_rfc2440, 0 },
+    /* 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
-    { &digest_spec_md4, 0 },
+    { &_gcry_digest_spec_md4,
+      &dummy_extra_spec,                 GCRY_MD_MD4 },
 #endif
 #if USE_MD5
-    { &digest_spec_md5, 0 },
+    { &_gcry_digest_spec_md5,
+      &dummy_extra_spec,                 GCRY_MD_MD5 },
 #endif
 #if USE_RMD160
-    { &digest_spec_rmd160, 0 },
+    { &_gcry_digest_spec_rmd160,
+      &dummy_extra_spec,                 GCRY_MD_RMD160 },
 #endif
 #if USE_SHA1
-    { &digest_spec_sha1, 0 },
+    { &_gcry_digest_spec_sha1, 
+      &_gcry_digest_extraspec_sha1,      GCRY_MD_SHA1, 1 },
 #endif
 #if USE_SHA256
-    { &digest_spec_sha256, 0 },
+    { &_gcry_digest_spec_sha256,
+      &_gcry_digest_extraspec_sha256,    GCRY_MD_SHA256, 1 },
+    { &_gcry_digest_spec_sha224,
+      &_gcry_digest_extraspec_sha224,    GCRY_MD_SHA224, 1 },
 #endif
 #if USE_SHA512
-    { &digest_spec_sha512, 0 },
-    { &digest_spec_sha384, 0 },
+    { &_gcry_digest_spec_sha512,
+      &_gcry_digest_extraspec_sha512,    GCRY_MD_SHA512, 1 },
+    { &_gcry_digest_spec_sha384,
+      &_gcry_digest_extraspec_sha384,    GCRY_MD_SHA384, 1 },
 #endif
 #if USE_TIGER
-    { &digest_spec_tiger, 0 },
+    { &_gcry_digest_spec_tiger,
+      &dummy_extra_spec,                 GCRY_MD_TIGER },
+#endif
+#if USE_WHIRLPOOL
+    { &_gcry_digest_spec_whirlpool,
+      &dummy_extra_spec,                 GCRY_MD_WHIRLPOOL },
 #endif
     { NULL },
   };
 
 /* List of registered digests.  */
-static gcry_module_t *digests_registered;
+static gcry_module_t digests_registered;
 
 /* This is the lock protecting DIGESTS_REGISTERED.  */
 static ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER;
@@ -106,6 +106,33 @@ static ath_mutex_t digests_registered_lock = ATH_MUTEX_INITIALIZER;
    registered.  */
 static int default_digests_registered;
 
+typedef struct gcry_md_list
+{
+  gcry_md_spec_t *digest;
+  gcry_module_t module;
+  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. */
+  int  secure;
+  FILE  *debug;
+  int finalized;
+  GcryDigestEntry *list;
+  byte *macpads;
+  int macpads_Bsize;             /* Blocksize as used for the HMAC pads. */
+};
+
+
+#define CTX_MAGIC_NORMAL 0x11071961
+#define CTX_MAGIC_SECURE 0x16917011
+
 /* Convenient macro for registering the default digests.  */
 #define REGISTER_DEFAULT_DIGESTS                   \
   do                                               \
@@ -113,26 +140,52 @@ static int default_digests_registered;
       ath_mutex_lock (&digests_registered_lock);   \
       if (! default_digests_registered)            \
         {                                          \
-          gcry_digest_register_default ();         \
+          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 );
+
+
+
+
 /* Internal function.  Register all the ciphers included in
    CIPHER_TABLE.  Returns zero on success or an error code.  */
 static void
-gcry_digest_register_default (void)
+md_register_default (void)
 {
-  gpg_err_code_t err = 0;
+  gcry_err_code_t err = 0;
   int i;
   
-  for (i = 0; (! err) && digest_table[i].digest; i++)
-    err = _gcry_module_add (&digests_registered,
-                           digest_table[i].digest->id,
-                           (void *) digest_table[i].digest,
-                           NULL);
+  for (i = 0; !err && digest_table[i].digest; i++)
+    {
+      if ( fips_mode () && !digest_table[i].fips_allowed )
+        continue;
+
+      err = _gcry_module_add (&digests_registered,
+                              digest_table[i].algorithm,
+                              (void *) digest_table[i].digest,
+                              (void *) digest_table[i].extraspec,
+                              NULL);
+    }
 
   if (err)
     BUG ();
@@ -140,96 +193,130 @@ gcry_digest_register_default (void)
 
 /* Internal callback function.  */
 static int
-gcry_digest_lookup_func_name (void *spec, void *data)
+gcry_md_lookup_func_name (void *spec, void *data)
 {
-  gcry_digest_spec_t *digest = (gcry_digest_spec_t *) spec;
+  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)
+{
+  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;
+
+  if (oid_specs)
+    {
+      for (i = 0; oid_specs[i].oidstring && (! ret); i++)
+        if (! stricmp (oid, oid_specs[i].oidstring))
+          ret = 1;
+    }
+
+  return ret;
+}
+
 /* Internal function.  Lookup a digest entry by it's name.  */
-static gcry_module_t *
-gcry_digest_lookup_name (const char *name)
+static gcry_module_t 
+gcry_md_lookup_name (const char *name)
 {
-  gcry_module_t *digest;
+  gcry_module_t digest;
 
   digest = _gcry_module_lookup (digests_registered, (void *) name,
-                               gcry_digest_lookup_func_name);
+                               gcry_md_lookup_func_name);
 
   return digest;
 }
 
-/* Public function.  Register a provided DIGEST.  Returns zero on
-   success, in which case the chosen digest ID has been stored in
-   DIGEST, or an error code.  */
-gpg_error_t
-gcry_digest_register (gcry_digest_spec_t *digest, gcry_module_t **module)
+/* Internal function.  Lookup a cipher entry by it's oid.  */
+static gcry_module_t
+gcry_md_lookup_oid (const char *oid)
 {
-  gpg_err_code_t err = 0;
-  gcry_module_t *mod;
+  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)
+{
+  gcry_err_code_t err = 0;
+  gcry_module_t mod;
+
+  /* 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, &mod);
+                         (void *) digest, 
+                         (void *)(extraspec? extraspec : &dummy_extra_spec), 
+                          &mod);
   ath_mutex_unlock (&digests_registered_lock);
   
   if (! err)
     {
       *module = mod;
-      digest->id = mod->id;
+      *algorithm_id = mod->mod_id;
     }
 
-  return gpg_error (err);
+  return gcry_error (err);
 }
 
-/* Public function.  Unregister the digest identified by ID, which
-   must have been registered with gcry_digest_register.  */
+/* Unregister the digest identified by ID, which must have been
+   registered with gcry_digest_register.  */
 void
-gcry_digest_unregister (gcry_module_t *module)
+gcry_md_unregister (gcry_module_t module)
 {
   ath_mutex_lock (&digests_registered_lock);
   _gcry_module_release (module);
   ath_mutex_unlock (&digests_registered_lock);
 }
 
-typedef struct gcry_md_list
-{
-  gcry_digest_spec_t *digest;
-  gcry_module_t *module;
-  struct gcry_md_list *next;
-  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
+static int 
+search_oid (const char *oid, int *algorithm, gcry_md_oid_spec_t *oid_spec)
 {
-  int  magic;
-  int  secure;
-  FILE  *debug;
-  int finalized;
-  GcryDigestEntry *list;
-  byte *macpads;
-};
+  gcry_module_t module;
+  int ret = 0;
 
-#define CTX_MAGIC_NORMAL 0x11071961
-#define CTX_MAGIC_SECURE 0x16917011
+  if (oid && ((! strncmp (oid, "oid.", 4))
+             || (! strncmp (oid, "OID.", 4))))
+    oid += 4;
 
-static const char * digest_algo_to_string( int algo );
-static gpg_err_code_t check_digest_algo (int algo);
-static gpg_err_code_t md_open (gcry_md_hd_t *h, int algo, int secure, int hmac);
-static gpg_err_code_t md_enable (gcry_md_hd_t hd, int algo);
-static gpg_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, byte *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 );
+  module = gcry_md_lookup_oid (oid);
+  if (module)
+    {
+      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))
+         {
+           if (algorithm)
+             *algorithm = module->mod_id;
+           if (oid_spec)
+             *oid_spec = digest->oids[i];
+           ret = 1;
+         }
+      _gcry_module_release (module);
+    }
+
+  return ret;
+}
 
 /****************
  * Map a string to the digest algo
@@ -237,42 +324,34 @@ static void md_stop_debug( gcry_md_hd_t a );
 int
 gcry_md_map_name (const char *string)
 {
-  gcry_module_t *digest;
-  int id = 0;
+  gcry_module_t digest;
+  int ret, algorithm = 0;
 
-  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 */
-  if (digitp (string)
-      || !strncmp (string, "oid.", 4) 
-      || !strncmp (string, "OID.", 4) )
-    {
-      int i;
-      const char *s =  digitp(string)? string : (string+4);
-
-      for (i=0; oid_table[i].oidstring; i++)
-       {
-         if (!strcmp (s, oid_table[i].oidstring))
-           return oid_table[i].algo;
-       }
-    }
-
-
-  REGISTER_DEFAULT_DIGESTS;
 
   ath_mutex_lock (&digests_registered_lock);
-  digest = gcry_digest_lookup_name (string);
-  if (digest)
+
+  ret = search_oid (string, &algorithm, NULL);
+  if (! ret)
     {
-      id = ((gcry_digest_spec_t *) digest->spec)->id;
-      _gcry_module_release (digest);
+      /* 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 id;
+  return algorithm;
 }
 
 
@@ -280,18 +359,18 @@ gcry_md_map_name (const char *string)
  * Map a digest algo to a string
  */
 static const char *
-digest_algo_to_string (int id)
+digest_algo_to_string (int algorithm)
 {
   const char *name = NULL;
-  gcry_module_t *digest;
+  gcry_module_t digest;
 
   REGISTER_DEFAULT_DIGESTS;
 
   ath_mutex_lock (&digests_registered_lock);
-  digest = _gcry_module_lookup_id (digests_registered, id);
+  digest = _gcry_module_lookup_id (digests_registered, algorithm);
   if (digest)
     {
-      name = ((gcry_digest_spec_t *) digest->spec)->name;
+      name = ((gcry_md_spec_t *) digest->spec)->name;
       _gcry_module_release (digest);
     }
   ath_mutex_unlock (&digests_registered_lock);
@@ -306,23 +385,23 @@ digest_algo_to_string (int id)
  * is valid.
  */
 const char *
-gcry_md_algo_name (int id)
+gcry_md_algo_name (int algorithm)
 {
-  const char *s = digest_algo_to_string (id);
+  const char *s = digest_algo_to_string (algorithm);
   return s ? s : "?";
 }
 
 
-static gpg_err_code_t
-check_digest_algo (int id)
+static gcry_err_code_t
+check_digest_algo (int algorithm)
 {
-  gpg_err_code_t rc = 0;
-  gcry_module_t *digest;
+  gcry_err_code_t rc = 0;
+  gcry_module_t digest;
 
   REGISTER_DEFAULT_DIGESTS;
 
   ath_mutex_lock (&digests_registered_lock);
-  digest = _gcry_module_lookup_id (digests_registered, id);
+  digest = _gcry_module_lookup_id (digests_registered, algorithm);
   if (digest)
     _gcry_module_release (digest);
   else
@@ -339,10 +418,10 @@ check_digest_algo (int id)
  * More algorithms may be added by md_enable(). The initial algorithm
  * may be 0.
  */
-static gpg_err_code_t
+static gcry_err_code_t
 md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
 {
-  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
   int bufsize = secure ? 512 : 1024;
   struct gcry_md_context *ctx;
   gcry_md_hd_t hd;
@@ -360,13 +439,13 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
    *     !                           ^
    *     !---------------------------!
    *
-   * We have to make sture that private is well aligned.
+   * 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 */
+  /* Allocate and set the Context pointer to the private data */
   if (secure)
     hd = gcry_malloc_secure (n + sizeof (struct gcry_md_context));
   else
@@ -378,29 +457,36 @@ md_open (gcry_md_hd_t *h, int algo, int secure, int hmac)
   if (! err)
     {
       hd->ctx = ctx = (struct gcry_md_context *) ((char *) hd + n);
-      /* setup the globally visible data (bctl in the diagram)*/
+      /* 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 */
+      /* 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->secure = secure;
 
       if (hmac)
        {
-         ctx->macpads = gcry_malloc_secure (128);
+         if ( (GCRY_MD_SHA384 == algo) || (GCRY_MD_SHA512 == algo) ) {
+           ctx->macpads_Bsize = 128;
+           ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize));
+         } else {
+           ctx->macpads_Bsize = 64;
+           ctx->macpads = gcry_malloc_secure (2*(ctx->macpads_Bsize));
+         }
          if (! ctx->macpads)
            {
-             md_close (hd);
              err = gpg_err_code_from_errno (errno);
+             md_close (hd);
            }
        }
     }
 
   if (! err)
     {
-      /* FIXME: should we really do that? */
+      /* Hmmm, should we really do that? - yes [-wk] */
       _gcry_fast_random_poll ();
 
       if (algo)
@@ -422,10 +508,10 @@ 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.  */
-gpg_error_t
+gcry_error_t
 gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
 {
-  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
   gcry_md_hd_t hd;
 
   if ((flags & ~(GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC)))
@@ -437,44 +523,44 @@ gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags)
     }
 
   *h = err? NULL : hd;
-  return gpg_error (err);
+  return gcry_error (err);
 }
 
 
 
-static gpg_err_code_t
-md_enable (gcry_md_hd_t hd, int id)
+static gcry_err_code_t
+md_enable (gcry_md_hd_t hd, int algorithm)
 {
   struct gcry_md_context *h = hd->ctx;
-  gcry_digest_spec_t *digest = NULL;
+  gcry_md_spec_t *digest = NULL;
   GcryDigestEntry *entry;
-  gcry_module_t *module;
-  gpg_err_code_t err = 0;
+  gcry_module_t module;
+  gcry_err_code_t err = 0;
 
   for (entry = h->list; entry; entry = entry->next)
-    if (entry->digest->id == id)
+    if (entry->module->mod_id == algorithm)
       return err; /* already enabled */
 
   REGISTER_DEFAULT_DIGESTS;
 
   ath_mutex_lock (&digests_registered_lock);
-  module = _gcry_module_lookup_id (digests_registered, id);
+  module = _gcry_module_lookup_id (digests_registered, algorithm);
   ath_mutex_unlock (&digests_registered_lock);
   if (! module)
     {
-      log_debug ("md_enable: algorithm %d not available\n", id);
+      log_debug ("md_enable: algorithm %d not available\n", algorithm);
       err = GPG_ERR_DIGEST_ALGO;
     }
   else
-    digest = (gcry_digest_spec_t *) module->spec;
+    digest = (gcry_md_spec_t *) module->spec;
 
   if (! err)
     {
-      size_t size = sizeof (*entry)
-       + digest->contextsize
-       - sizeof (entry->context);
+      size_t size = (sizeof (*entry)
+                     + digest->contextsize
+                     - sizeof (entry->context));
 
-      /* and allocate a new list entry */
+      /* And allocate a new list entry. */
       if (h->secure)
        entry = gcry_malloc_secure (size);
       else
@@ -487,10 +573,11 @@ md_enable (gcry_md_hd_t hd, int id)
          entry->digest = digest;
          entry->module = module;
          entry->next = h->list;
+          entry->actual_struct_size = size;
          h->list = entry;
 
-         /* and init this instance */
-         (*entry->digest->init) (&entry->context.c);
+         /* And init this instance. */
+         entry->digest->init (&entry->context.c);
        }
     }
 
@@ -508,17 +595,16 @@ md_enable (gcry_md_hd_t hd, int id)
 }
 
 
-gpg_error_t
-gcry_md_enable (gcry_md_hd_t hd, int id)
+gcry_error_t
+gcry_md_enable (gcry_md_hd_t hd, int algorithm)
 {
-  gpg_err_code_t err = md_enable (hd, id);
-  return gpg_error (err);
+  return gcry_error (md_enable (hd, algorithm));
 }
 
-static gpg_err_code_t
+static gcry_err_code_t
 md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
 {
-  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
   struct gcry_md_context *a = ahd->ctx;
   struct gcry_md_context *b;
   GcryDigestEntry *ar, *br;
@@ -540,7 +626,7 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
   if (! err)
     {
       bhd->ctx = b = (struct gcry_md_context *) ((char *) bhd + n);
-      /* no need to copy the buffer due to the write above */
+      /* No need to copy the buffer due to the write above. */
       assert (ahd->bufsize == (n - sizeof (struct gcry_md_handle) + 1));
       bhd->bufsize = ahd->bufsize;
       bhd->bufpos = 0;
@@ -550,61 +636,71 @@ md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd)
       b->debug = NULL;
       if (a->macpads)
        {
-         b->macpads = gcry_malloc_secure (128);
+         b->macpads = gcry_malloc_secure (2*(a->macpads_Bsize));
          if (! b->macpads)
            {
-             md_close (bhd);
              err = gpg_err_code_from_errno (errno);
+             md_close (bhd);
            }
          else
-           memcpy (b->macpads, a->macpads, 128);
+           memcpy (b->macpads, a->macpads, (2*(a->macpads_Bsize)));
        }
     }
 
-  /* and now copy the complete list of algorithms */
-  /* I know that the copied list is reversed, but that doesn't matter */
+  /* Copy the complete list of algorithms.  The copied list is
+     reversed, but that doesn't matter. */
+  if (!err)
+    {
+      for (ar = a->list; ar; ar = ar->next)
+        {
+          if (a->secure)
+            br = gcry_malloc_secure (sizeof *br
+                                     + ar->digest->contextsize
+                                     - sizeof(ar->context));
+          else
+            br = gcry_malloc (sizeof *br
+                              + ar->digest->contextsize
+                              - sizeof (ar->context));
+          if (!br)
+            {
+             err = gpg_err_code_from_errno (errno);
+              md_close (bhd);
+              break;
+            }
+
+          memcpy (br, ar, (sizeof (*br) + ar->digest->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);
+        }
+    }
 
-  if (! err)
-    for (ar = a->list; ar; ar = ar->next)
-      {
-       if (a->secure)
-         br = gcry_xmalloc_secure (sizeof *br
-                                   + ar->digest->contextsize
-                                   - sizeof(ar->context));
-       else
-         br = gcry_xmalloc (sizeof *br
-                            + ar->digest->contextsize
-                            - sizeof (ar->context));
-       memcpy (br, ar,
-               sizeof (*br) + ar->digest->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);
-       }
-
-  if (a->debug)
+  if (a->debug && !err)
     md_start_debug (bhd, "unknown");
 
-  if (! err)
+  if (!err)
     *b_hd = bhd;
 
   return err;
 }
 
-gpg_error_t
+gcry_error_t
 gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd)
 {
-  gpg_err_code_t err = md_copy (hd, handle);
+  gcry_err_code_t err;
+
+  err = md_copy (hd, handle);
   if (err)
     *handle = NULL;
-  return gpg_error (err);
+  return gcry_error (err);
 }
 
-/****************
+/*
  * Reset all contexts and discard any buffered stuff.  This may be used
  * instead of a md_close(); md_open().
  */
@@ -612,7 +708,9 @@ 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->finalized = 0;
 
   for (r = a->ctx->list; r; r = r->next)
@@ -621,7 +719,7 @@ gcry_md_reset (gcry_md_hd_t a)
       (*r->digest->init) (&r->context.c);
     }
   if (a->ctx->macpads)
-    md_write (a, a->ctx->macpads, 64); /* inner pad */
+    md_write (a, a->ctx->macpads, a->ctx->macpads_Bsize); /* inner pad */
 }
 
 static void
@@ -639,20 +737,29 @@ md_close (gcry_md_hd_t a)
       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);
     }
-  gcry_free(a->ctx->macpads);
+
+  if (a->ctx->macpads)
+    {
+      wipememory (a->ctx->macpads, 2*(a->ctx->macpads_Bsize));
+      gcry_free(a->ctx->macpads);
+    }
+
+  wipememory (a, a->ctx->actual_handle_size);
   gcry_free(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, byte *inbuf, size_t inlen)
+md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen)
 {
   GcryDigestEntry *r;
   
@@ -676,7 +783,7 @@ md_write (gcry_md_hd_t a, byte *inbuf, size_t inlen)
 void
 gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen)
 {
-  md_write (hd, (unsigned char *) inbuf, inlen);
+  md_write (hd, inbuf, inlen);
 }
 
 static void
@@ -697,25 +804,27 @@ md_final (gcry_md_hd_t a)
 
   if (a->ctx->macpads)
     {
-      /* finish the hmac */
+      /* Finish the hmac. */
       int algo = md_get_algo (a);
       byte *p = md_read (a, algo);
       size_t dlen = md_digest_length (algo);
       gcry_md_hd_t om;
-      gpg_err_code_t err = md_open (&om, algo, a->ctx->secure, 0);
+      gcry_err_code_t err = md_open (&om, algo, a->ctx->secure, 0);
 
       if (err)
        _gcry_fatal_error (err, NULL);
-      md_write (om, a->ctx->macpads+64, 64);
+      md_write (om, 
+                (a->ctx->macpads)+(a->ctx->macpads_Bsize), 
+                a->ctx->macpads_Bsize);
       md_write (om, p, dlen);
       md_final (om);
-      /* replace our digest with the mac (they have the same size) */
+      /* Replace our digest with the mac (they have the same size). */
       memcpy (p, md_read (om, algo), dlen);
       md_close (om);
     }
 }
 
-static gpg_err_code_t
+static gcry_err_code_t
 prepare_macpads( gcry_md_hd_t hd, const byte *key, size_t keylen)
 {
   int i;
@@ -723,37 +832,39 @@ prepare_macpads( gcry_md_hd_t hd, const byte *key, size_t keylen)
   byte *helpkey = NULL;
   byte *ipad, *opad;
 
-  if( !algo )
+  if ( !algo )
     return GPG_ERR_DIGEST_ALGO; /* i.e. no algo enabled */
 
-  if( keylen > 64 ) {
-    helpkey = gcry_malloc_secure( md_digest_length( algo ) );
-    if( !helpkey )
-      return gpg_err_code_from_errno (errno);
-    gcry_md_hash_buffer( algo, helpkey, key, keylen );
-    key = helpkey;
-    keylen = md_digest_length( algo );
-    assert( keylen <= 64 );
-  }
+  if ( keylen > 64 ) 
+    {
+      helpkey = gcry_malloc_secure ( md_digest_length( algo ) );
+      if ( !helpkey )
+        return gpg_err_code_from_errno (errno);
+      gcry_md_hash_buffer ( algo, helpkey, key, keylen );
+      key = helpkey;
+      keylen = md_digest_length( algo );
+      assert ( keylen <= 64 );
+    }
 
-  memset( hd->ctx->macpads, 0, 128 );
+  memset ( hd->ctx->macpads, 0, 2*(hd->ctx->macpads_Bsize) );
   ipad = hd->ctx->macpads;
-  opad = hd->ctx->macpads+64;
-  memcpy( ipad, key, keylen );
-  memcpy( opad, key, keylen );
-  for(i=0; i < 64; i++ ) {
-    ipad[i] ^= 0x36;
-    opad[i] ^= 0x5c;
-  }
+  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++ ) 
+    {
+      ipad[i] ^= 0x36;
+      opad[i] ^= 0x5c;
+    }
   gcry_free( helpkey );
 
   return GPG_ERR_NO_ERROR;
 }
 
-gpg_error_t
-gcry_md_ctl (gcry_md_hd_t hd, int cmd, byte *buffer, size_t buflen)
+gcry_error_t
+gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen)
 {
-  gpg_err_code_t rc = 0;
+  gcry_err_code_t rc = 0;
   
   switch (cmd)
     {
@@ -761,26 +872,26 @@ gcry_md_ctl (gcry_md_hd_t hd, int cmd, byte *buffer, size_t buflen)
       md_final (hd);
       break;
     case GCRYCTL_SET_KEY:
-      rc = gpg_err_code (gcry_md_setkey (hd, buffer, buflen));
+      rc = gcry_err_code (gcry_md_setkey (hd, buffer, buflen));
       break;
     case GCRYCTL_START_DUMP:
       md_start_debug (hd, buffer);
       break;
     case GCRYCTL_STOP_DUMP:
-      md_stop_debug( hd );
+      md_stop_debug ( hd );
       break;
     default:
       rc = GPG_ERR_INV_OP;
     }
-  return gpg_error (rc);
+  return gcry_error (rc);
 }
 
-gpg_error_t
+gcry_error_t
 gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
 {
-  gpg_err_code_t rc = GPG_ERR_NO_ERROR;
+  gcry_err_code_t rc = GPG_ERR_NO_ERROR;
 
-  if (! hd->ctx->macpads)
+  if (!hd->ctx->macpads)
     rc = GPG_ERR_CONFLICT;
   else
     {
@@ -789,9 +900,22 @@ gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen)
        gcry_md_reset (hd);
     }
 
-  return gpg_error (rc);
+  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
+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)
@@ -805,113 +929,74 @@ md_read( gcry_md_hd_t a, int algo )
     {
       /* return the first algorithm */
       if (r && r->next)
-       log_debug("more than algorithm in md_read(0)\n");
-      return (*r->digest->read)( &r->context.c );
+       log_debug ("more than one algorithm in md_read(0)\n");
+      return r->digest->read( &r->context.c );
     }
   else
     {
       for (r = a->ctx->list; r; r = r->next)
-       if (r->digest->id == algo)
-         return (*r->digest->read) (&r->context.c);
+       if (r->module->mod_id == algo)
+         return r->digest->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)
 {
+  /* 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);
 }
 
-/****************
- * This function combines md_final and md_read but keeps the context
- * intact.  This function can be used to calculate intermediate
- * digests.  The digest is copied into buffer and the digestlength is
- * returned.  If buffer is NULL only the needed size for buffer is returned.
- * buflen gives the max size of buffer. If the buffer is too shourt to
- * hold the complete digest, the buffer is filled with as many bytes are
- * possible and this value is returned.
- */
-#if 0
-static int
-md_digest( gcry_md_hd_t a, int algo, byte *buffer, int buflen )
-{
-  struct md_digest_list_s *r = NULL;
-  char *context;
-  char *digest;
-
-  if( a->bufpos )
-    md_write( a, NULL, 0 );
 
-  if( !algo ) {  /* return digest for the first algorithm */
-    if( (r=a->ctx->list) && r->next )
-      log_debug("more than algorithm in md_digest(0)\n");
-  }
-  else {
-    for(r=a->ctx->list; r; r = r->next )
-      if( r->algo == algo )
-       break;
-  }
-  if( !r )
-    BUG();
-
-  if( !buffer )
-    return r->mdlen;
-
-  /* I don't want to change the interface, so I simply work on a copy
-   * of the context (extra overhead - should be fixed)*/
-  context = a->ctx->secure ? gcry_xmalloc_secure( r->contextsize )
-    : gcry_xmalloc( r->contextsize );
-  memcpy( context, r->context.c, r->contextsize );
-  (*r->digest->final)( context );
-  digest = (*r->digest->read)( context );
-
-  if( buflen > r->mdlen )
-    buflen = r->mdlen;
-  memcpy( buffer, digest, buflen );
-
-  gcry_free(context);
-  return buflen;
-}
-#endif
-
-/****************
- * Read out an intermediate digest.
+/*
+ * Read out an intermediate digest.  Not yet functional.
  */
-gpg_err_code_t
+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 supported
- * algorithm is RIPE-MD. 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.
- */
+/*
+ * 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)
+gcry_md_hash_buffer (int algo, void *digest,
+                     const void *buffer, size_t length)
 {
-  if (algo == GCRY_MD_RMD160)
+  if (algo == GCRY_MD_SHA1)
+    _gcry_sha1_hash_buffer (digest, buffer, length);
+  else if (algo == GCRY_MD_RMD160 && !fips_mode () )
     _gcry_rmd160_hash_buffer (digest, buffer, length);
   else
     {
-      /* for the others we do not have a fast function, so we use the
-        normal functions to do it */
+      /* 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 = md_open (&h, algo, 0, 0);
-      if(! err)
-       /* FIXME?  */
-       BUG(); /* algo not available */
+      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));
@@ -925,8 +1010,11 @@ md_get_algo (gcry_md_hd_t a)
   GcryDigestEntry *r = a->ctx->list;
 
   if (r && r->next)
-    log_error("WARNING: more than algorithm in md_get_algo()\n");
-  return r ? r->digest->id : 0;
+    {
+      fips_signal_error ("possible usage error");
+      log_error ("WARNING: more than algorithm in md_get_algo()\n");
+    }
+  return r ? r->module->mod_id : 0;
 }
 
 int
@@ -940,18 +1028,18 @@ gcry_md_get_algo (gcry_md_hd_t hd)
  * Return the length of the digest
  */
 static int
-md_digest_length (int id)
+md_digest_length (int algorithm)
 {
-  gcry_module_t *digest;
+  gcry_module_t digest;
   int mdlen = 0;
 
   REGISTER_DEFAULT_DIGESTS;
 
   ath_mutex_lock (&digests_registered_lock);
-  digest = _gcry_module_lookup_id (digests_registered, id);
+  digest = _gcry_module_lookup_id (digests_registered, algorithm);
   if (digest)
     {
-      mdlen = ((gcry_digest_spec_t *) digest->spec)->mdlen;
+      mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen;
       _gcry_module_release (digest);
     }
   ath_mutex_unlock (&digests_registered_lock);
@@ -964,35 +1052,35 @@ md_digest_length (int id)
  * This function will return 0 in case of errors.
  */
 unsigned int
-gcry_md_get_algo_dlen (int id)
+gcry_md_get_algo_dlen (int algorithm)
 {
-  return md_digest_length (id);
+  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 id, size_t *asnlen, size_t *mdlen)
+md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen)
 {
   const byte *asnoid = NULL;
-  gcry_module_t *digest;
+  gcry_module_t digest;
 
   REGISTER_DEFAULT_DIGESTS;
 
   ath_mutex_lock (&digests_registered_lock);
-  digest = _gcry_module_lookup_id (digests_registered, id);
+  digest = _gcry_module_lookup_id (digests_registered, algorithm);
   if (digest)
     {
       if (asnlen)
-       *asnlen = ((gcry_digest_spec_t *) digest->spec)->asnlen;
+       *asnlen = ((gcry_md_spec_t *) digest->spec)->asnlen;
       if (mdlen)
-       *mdlen = ((gcry_digest_spec_t *) digest->spec)->mdlen;
-      asnoid = ((gcry_digest_spec_t *) digest->spec)->asnoid;
+       *mdlen = ((gcry_md_spec_t *) digest->spec)->mdlen;
+      asnoid = ((gcry_md_spec_t *) digest->spec)->asnoid;
       _gcry_module_release (digest);
     }
   else
-    log_bug ("no asn for md algo %d\n", id);
+    log_bug ("no ASN.1 OID for md algo %d\n", algorithm);
   ath_mutex_unlock (&digests_registered_lock);
 
   return asnoid;
@@ -1016,10 +1104,10 @@ md_asn_oid (int id, size_t *asnlen, size_t *mdlen)
  * and thereby detecting whether a error occured or not (i.e. while checking
  * the block size)
  */
-gpg_error_t
+gcry_error_t
 gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes)
 {
-  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
 
   switch (what)
     {
@@ -1031,60 +1119,72 @@ gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes)
       break;
 
     case GCRYCTL_GET_ASNOID:
-      {
-       size_t asnlen;
-       const char *asn = md_asn_oid (algo, &asnlen, NULL);
-       if (buffer && (*nbytes >= asnlen))
+      /* 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)
+        {
+          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)
-             err = GPG_ERR_TOO_SHORT;
-           else
-             err = GPG_ERR_INV_ARG;
-         }
-       break;
-      }
+          else if (!buffer && nbytes)
+            *nbytes = asnlen;
+          else
+            {
+              if (buffer)
+                err = GPG_ERR_TOO_SHORT;
+              else
+                err = GPG_ERR_INV_ARG;
+            }
+        }
+      break;
 
   default:
     err = GPG_ERR_INV_OP;
   }
 
-  return gpg_error (err);
+  return gcry_error (err);
 }
 
 
 static void
-md_start_debug( gcry_md_hd_t md, const char *suffix )
+md_start_debug ( gcry_md_hd_t md, const char *suffix )
 {
   static int idx=0;
-  char buf[25];
+  char buf[50];
 
-  if( md->ctx->debug ) {
-    log_debug("Oops: md debug already started\n");
+  if (fips_mode ())
     return;
-  }
+  
+  if ( md->ctx->debug )
+    {
+      log_debug("Oops: md debug already started\n");
+      return;
+    }
   idx++;
-  sprintf(buf, "dbgmd-%05d.%.10s", idx, suffix );
+  snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix );
   md->ctx->debug = fopen(buf, "w");
-  if( !md->ctx->debug )
+  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;
-  }
+  if ( md->ctx->debug )
+    {
+      if ( md->bufpos )
+        md_write ( md, NULL, 0 );
+      fclose (md->ctx->debug);
+      md->ctx->debug = NULL;
+    }
+
 #ifdef HAVE_U64_TYPEDEF
   {  /* a kludge to pull in the __muldi3 for Solaris */
     volatile u32 a = (u32)(ulong)md;
@@ -1097,19 +1197,19 @@ md_stop_debug( gcry_md_hd_t md )
 
 
 
-/****************
+/*
  * 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 enanled for that handle.
+ *     Returns 1 if the algo is enabled for that handle.
  *     The algo must be passed as the address of an int.
  */
-gpg_error_t
+gcry_error_t
 gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
 {
-  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
 
   switch (cmd)
     {
@@ -1122,7 +1222,7 @@ 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))))
+       if ( !buffer || (nbytes && (*nbytes != sizeof (int))))
          err = GPG_ERR_INV_ARG;
        else
          {
@@ -1130,7 +1230,7 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
            
            *nbytes = 0;
            for(r=h->ctx->list; r; r = r->next ) {
-             if (r->digest->id == algo)
+             if (r->module->mod_id == algo)
                {
                  *nbytes = 1;
                  break;
@@ -1144,13 +1244,15 @@ gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes)
     err = GPG_ERR_INV_OP;
   }
 
-  return gpg_error (err);
+  return gcry_error (err);
 }
 
-gpg_err_code_t
+
+/* Explicitly initialize this module.  */
+gcry_err_code_t
 _gcry_md_init (void)
 {
-  gpg_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t err = GPG_ERR_NO_ERROR;
 
   REGISTER_DEFAULT_DIGESTS;
 
@@ -1175,7 +1277,65 @@ 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;
 }
+
+/* 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, selftest_report_func_t report)
+{
+  gcry_module_t module = NULL;
+  cipher_extra_spec_t *extraspec = NULL;
+  gcry_err_code_t ec = 0;
+
+  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, report);
+  else
+    {
+      ec = GPG_ERR_DIGEST_ALGO;
+      if (report)
+        report ("digest", algo, "module", 
+                module && !(module->flags & FLAG_MODULE_DISABLED)?
+                "no selftest available" :
+                module? "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);
+}