A lot of cleanups as well as minor API changes.
[libgcrypt.git] / cipher / pubkey.c
index d0a172b..228b0d0 100644 (file)
@@ -1,5 +1,6 @@
 /* pubkey.c  - pubkey dispatcher
- * Copyright (C) 1998,1999,2000,2002,2003 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2002, 2003,
+ *               2005 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -49,13 +50,14 @@ static struct pubkey_table_entry
 } pubkey_table[] =
   {
 #if USE_RSA
-    { &_gcry_pubkey_spec_rsa, GCRY_PK_RSA },
+    { &_gcry_pubkey_spec_rsa, GCRY_PK_RSA   },
 #endif
 #if USE_ELGAMAL
-    { &_gcry_pubkey_spec_elg, GCRY_PK_ELG },
+    { &_gcry_pubkey_spec_elg, GCRY_PK_ELG   },
+    { &_gcry_pubkey_spec_elg, GCRY_PK_ELG_E },
 #endif
 #if USE_DSA
-    { &_gcry_pubkey_spec_dsa, GCRY_PK_DSA },
+    { &_gcry_pubkey_spec_dsa, GCRY_PK_DSA   },
 #endif
     { NULL, 0 },
   };
@@ -64,7 +66,7 @@ static struct pubkey_table_entry
 static gcry_module_t pubkeys_registered;
 
 /* This is the lock protecting PUBKEYS_REGISTERED.  */
-static ath_mutex_t pubkeys_registered_lock;
+static ath_mutex_t pubkeys_registered_lock = ATH_MUTEX_INITIALIZER;;
 
 /* Flag to check wether the default pubkeys have already been
    registered.  */
@@ -91,39 +93,55 @@ static gcry_err_code_t
 dummy_generate (int algorithm, unsigned int nbits, unsigned long dummy,
                 gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
-  log_bug ("no generate() for %d\n", algorithm);
-  return GPG_ERR_PUBKEY_ALGO;
+  (void)algorithm;
+  (void)nbits;
+  (void)dummy;
+  (void)skey;
+  (void)retfactors;
+  return GPG_ERR_NOT_IMPLEMENTED;
 }
 
 static gcry_err_code_t
 dummy_check_secret_key (int algorithm, gcry_mpi_t *skey)
 {
-  log_bug ("no check_secret_key() for %d\n", algorithm);
-  return GPG_ERR_PUBKEY_ALGO;
+  (void)algorithm;
+  (void)skey;
+  return GPG_ERR_NOT_IMPLEMENTED;
 }
 
 static gcry_err_code_t
 dummy_encrypt (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
                gcry_mpi_t *pkey, int flags)
 {
-  log_bug ("no encrypt() for %d\n", algorithm);
-  return GPG_ERR_PUBKEY_ALGO;
+  (void)algorithm;
+  (void)resarr;
+  (void)data;
+  (void)pkey;
+  (void)flags;
+  return GPG_ERR_NOT_IMPLEMENTED;
 }
 
 static gcry_err_code_t
 dummy_decrypt (int algorithm, gcry_mpi_t *result, gcry_mpi_t *data,
                gcry_mpi_t *skey, int flags)
 {
-  log_bug ("no decrypt() for %d\n", algorithm);
-  return GPG_ERR_PUBKEY_ALGO;
+  (void)algorithm;
+  (void)result;
+  (void)data;
+  (void)skey;
+  (void)flags;
+  return GPG_ERR_NOT_IMPLEMENTED;
 }
 
 static gcry_err_code_t
 dummy_sign (int algorithm, gcry_mpi_t *resarr, gcry_mpi_t data,
             gcry_mpi_t *skey)
 {
-  log_bug ("no sign() for %d\n", algorithm);
-  return GPG_ERR_PUBKEY_ALGO;
+  (void)algorithm;
+  (void)resarr;
+  (void)data;
+  (void)skey;
+  return GPG_ERR_NOT_IMPLEMENTED;
 }
 
 static gcry_err_code_t
@@ -131,14 +149,20 @@ dummy_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
               gcry_mpi_t *pkey,
              int (*cmp) (void *, gcry_mpi_t), void *opaquev)
 {
-  log_bug ("no verify() for %d\n", algorithm);
-  return GPG_ERR_PUBKEY_ALGO;
+  (void)algorithm;
+  (void)hash;
+  (void)data;
+  (void)pkey;
+  (void)cmp;
+  (void)opaquev;
+  return GPG_ERR_NOT_IMPLEMENTED;
 }
 
 static unsigned
 dummy_get_nbits (int algorithm, gcry_mpi_t *pkey)
 {
-  log_bug ("no get_nbits() for %d\n", algorithm);
+  (void)algorithm;
+  (void)pkey;
   return 0;
 }
 
@@ -179,7 +203,7 @@ gcry_pk_lookup_func_name (void *spec, void *data)
 {
   gcry_pk_spec_t *pubkey = (gcry_pk_spec_t *) spec;
   char *name = (char *) data;
-  char **aliases = pubkey->aliases;
+  const char **aliases = pubkey->aliases;
   int ret = stricmp (name, pubkey->name);
 
   while (ret && *aliases)
@@ -272,14 +296,14 @@ gcry_pk_map_name (const char *string)
 }
 
 
-/****************
- * Map a pubkey algo to a string
- */
+/* Map the public key algorithm whose ID is contained in ALGORITHM to
+   a string representation of the algorithm name.  For unknown
  algorithm IDs this functions returns "?". */
 const char *
 gcry_pk_algo_name (int algorithm)
 {
-  const char *name = NULL;
   gcry_module_t pubkey;
+  const char *name;
 
   REGISTER_DEFAULT_PUBKEYS;
 
@@ -290,6 +314,8 @@ gcry_pk_algo_name (int algorithm)
       name = ((gcry_pk_spec_t *) pubkey->spec)->name;
       _gcry_module_release (pubkey);
     }
+  else
+    name = "?";
   ath_mutex_unlock (&pubkeys_registered_lock);
 
   return name;
@@ -470,7 +496,8 @@ pubkey_get_nenc (int algorithm)
 
 
 static gcry_err_code_t
-pubkey_generate (int algorithm, unsigned int nbits, unsigned long use_e,
+pubkey_generate (int algorithm, unsigned int nbits, unsigned int qbits,
+                 unsigned long use_e,
                  gcry_mpi_t *skey, gcry_mpi_t **retfactors)
 {
   gcry_err_code_t err = GPG_ERR_PUBKEY_ALGO;
@@ -482,8 +509,13 @@ pubkey_generate (int algorithm, unsigned int nbits, unsigned long use_e,
   pubkey = _gcry_module_lookup_id (pubkeys_registered, algorithm);
   if (pubkey)
     {
-      err = ((gcry_pk_spec_t *) pubkey->spec)->generate 
-        (algorithm, nbits, use_e, skey, retfactors);
+      /* Hack to pass QBITS to the DSA generation.  */
+      if (qbits && pubkey->spec == &_gcry_pubkey_spec_dsa)
+        err = _gcry_dsa_generate2
+          (algorithm, nbits, qbits, 0, skey, retfactors);
+      else
+        err = ((gcry_pk_spec_t *) pubkey->spec)->generate 
+          (algorithm, nbits, use_e, skey, retfactors);
       _gcry_module_release (pubkey);
     }
   ath_mutex_unlock (&pubkeys_registered_lock);
@@ -789,7 +821,15 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray,
     }
 
     {
-      char *name_terminated = gcry_xmalloc (n + 1);
+      char *name_terminated;
+
+      name_terminated = gcry_malloc (n + 1);
+      if (!name_terminated)
+        {
+          err = gpg_err_code_from_errno (errno);
+          gcry_sexp_release (list);
+          return err;
+        }
       memcpy (name_terminated, name, n);
       name_terminated[n] = 0;
 
@@ -879,7 +919,17 @@ sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
     }
       
     {
-      char *name_terminated = gcry_xmalloc (n + 1);
+      char *name_terminated;
+
+      name_terminated = gcry_malloc (n + 1);
+      if (!name_terminated)
+        {
+          err = gcry_err_code_from_errno (errno);
+         gcry_sexp_release (l2);
+         gcry_sexp_release (list);
+          return err;
+        }
+          
       memcpy (name_terminated, name, n);
       name_terminated[n] = 0;
       
@@ -1029,7 +1079,14 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
     }
 
   {
-    char *name_terminated = gcry_xmalloc (n + 1);
+    char *name_terminated;
+
+    name_terminated = gcry_malloc (n + 1);
+    if (!name_terminated)
+      {
+        err = gcry_err_code_from_errno (errno);
+        goto leave;
+      }
     memcpy (name_terminated, name, n);
     name_terminated[n] = 0;
     
@@ -1243,15 +1300,16 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
           static struct { const char *name; int algo; } hashnames[] = 
           { { "sha1",   GCRY_MD_SHA1 },
             { "md5",    GCRY_MD_MD5 },
-            { "rmd160", GCRY_MD_RMD160 },
             { "sha256", GCRY_MD_SHA256 },
+            { "ripemd160", GCRY_MD_RMD160 },
+            { "rmd160", GCRY_MD_RMD160 },
             { "sha384", GCRY_MD_SHA384 },
             { "sha512", GCRY_MD_SHA512 },
             { "md2",    GCRY_MD_MD2 },
             { "md4",    GCRY_MD_MD4 },
             { "tiger",  GCRY_MD_TIGER },
             { "haval",  GCRY_MD_HAVAL },
-            { NULL }
+            { NULL, 0 }
           };
           int algo;
           byte asn[100];
@@ -1394,7 +1452,12 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
     goto leave;
 
   /* Now we can encrypt DATA to CIPH. */
-  ciph = gcry_xcalloc (strlen (algo_elems) + 1, sizeof (*ciph));
+  ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph));
+  if (!ciph)
+    {
+      rc = gpg_err_code_from_errno (errno);
+      goto leave;
+    }
   rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags);
   mpi_free (data);
   data = NULL;
@@ -1410,7 +1473,12 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
     void **arg_list;
     
     /* Build the string.  */
-    string = p = gcry_xmalloc (needed);
+    string = p = gcry_malloc (needed);
+    if (!string)
+      {
+        rc = gpg_err_code_from_errno (errno);
+        goto leave;
+      }
     p = stpcpy ( p, "(enc-val(" );
     p = stpcpy ( p, algo_name );
     for (i=0; algo_elems[i]; i++ )
@@ -1612,7 +1680,12 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
   if (rc)
     goto leave;
 
-  result = gcry_xcalloc (strlen (algo_elems) + 1, sizeof (*result));
+  result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result));
+  if (!result)
+    {
+      rc = gpg_err_code_from_errno (errno);
+      goto leave;
+    }
   rc = pubkey_sign (module->mod_id, result, hash, skey);
   if (rc)
     goto leave;
@@ -1628,7 +1701,12 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
     needed += 10 * nelem;
 
     /* Build the string. */
-    string = p = gcry_xmalloc (needed);
+    string = p = gcry_malloc (needed);
+    if (!string)
+      {
+        rc = gpg_err_code_from_errno (errno);
+        goto leave;
+      }
     p = stpcpy (p, "(sig-val(");
     p = stpcpy (p, algo_name);
     for (i = 0; algo_elems[i]; i++)
@@ -1819,6 +1897,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   gcry_mpi_t skey[10], *factors = NULL;
   unsigned int nbits = 0;
   unsigned long use_e = 0;
+  unsigned int qbits;
   char *name_terminated;
 
   REGISTER_DEFAULT_PUBKEYS;
@@ -1850,7 +1929,12 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       goto leave;
     }
 
-  name_terminated = gcry_xmalloc (n + 1);
+  name_terminated = gcry_malloc (n + 1);
+  if (!name_terminated)
+    {
+      rc = gpg_err_code_from_errno (errno);
+      goto leave;
+    }
   memcpy (name_terminated, name, n);
   name_terminated[n] = 0;
   ath_mutex_lock (&pubkeys_registered_lock);
@@ -1893,6 +1977,28 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   else
     use_e = 65537; /* Not given, use the value generated by old versions. */
 
+  /* Handle the optional qbits element. */
+  l2 = gcry_sexp_find_token (list, "qbits", 0);
+  if (l2)
+    {
+      char buf[50];
+
+      name = gcry_sexp_nth_data (l2, 1, &n);
+      if ((! name) || (n >= DIM (buf) - 1))
+        {
+          rc = GPG_ERR_INV_OBJ; /* No value or value too large. */
+          goto leave;
+        }
+      memcpy (buf, name, n);
+      buf[n] = 0;
+      qbits = (unsigned int)strtoul (buf, NULL, 0);
+      gcry_sexp_release (l2);
+      l2 = NULL;
+    }
+  else
+    qbits = 0;
+
+  /* Now parse the required nbits element. */
   l2 = gcry_sexp_find_token (list, "nbits", 0);
   gcry_sexp_release (list);
   list = l2;
@@ -1911,13 +2017,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       goto leave;
     }
   
-  name_terminated = gcry_xmalloc (n + 1);
+  name_terminated = gcry_malloc (n + 1);
+  if (!name_terminated)
+    {
+      rc = gpg_err_code_from_errno (errno);
+      goto leave;
+    }
   memcpy (name_terminated, name, n);
   name_terminated[n] = 0;
   nbits = (unsigned int) strtoul (name_terminated, NULL, 0);
   gcry_free (name_terminated);
 
-  rc = pubkey_generate (module->mod_id, nbits, use_e, skey, &factors);
+  rc = pubkey_generate (module->mod_id, nbits, qbits, use_e, skey, &factors);
   if (rc)
     goto leave;
 
@@ -1938,7 +2049,12 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
 
     /* Build the string. */
     nelem = 0;
-    string = p = gcry_xmalloc (needed);
+    string = p = gcry_malloc (needed);
+    if (!string)
+      {
+        rc = gpg_err_code_from_errno (errno);
+        goto leave;
+      }
     p = stpcpy (p, "(key-data");
     p = stpcpy (p, "(public-key(");
     p = stpcpy (p, algo_name);
@@ -2092,6 +2208,8 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   if (! list)
     list = gcry_sexp_find_token (key, "protected-private-key", 0);
   if (! list)
+    list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
+  if (! list)
     return NULL; /* No public- or private-key object. */
 
   l2 = gcry_sexp_cadr (list);
@@ -2104,7 +2222,9 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
     goto fail; /* Invalid structure of object. */
 
   {
-    char *name_terminated = gcry_xmalloc (n + 1);
+    char *name_terminated = gcry_malloc (n + 1);
+    if (!name_terminated)
+      goto fail;
     memcpy (name_terminated, name, n);
     name_terminated[n] = 0;
     ath_mutex_lock (&pubkeys_registered_lock);
@@ -2260,6 +2380,8 @@ gcry_pk_algo_info (int algorithm, int what, void *buffer, size_t *nbytes)
 
        /* FIXME? */
        *nbytes = use;
+
+       break;
       }
 
     case GCRYCTL_GET_ALGO_NPKEY:
@@ -2355,3 +2477,64 @@ gcry_pk_list (int *list, int *list_length)
 
   return err;
 }
+
+gcry_err_code_t
+_gcry_pk_get_elements (int algo, char **enc, char **sig)
+{
+  gcry_module_t pubkey;
+  gcry_pk_spec_t *spec;
+  gcry_err_code_t err;
+  char *enc_cp;
+  char *sig_cp;
+
+  REGISTER_DEFAULT_PUBKEYS;
+
+  enc_cp = NULL;
+  sig_cp = NULL;
+  spec = NULL;
+
+  pubkey = _gcry_module_lookup_id (pubkeys_registered, algo);
+  if (! pubkey)
+    {
+      err = GPG_ERR_INTERNAL;
+      goto out;
+    }
+  spec = pubkey->spec;
+
+  if (enc)
+    {
+      enc_cp = strdup (spec->elements_enc);
+      if (! enc_cp)
+       {
+         err = gpg_err_code_from_errno (errno);
+         goto out;
+       }
+    }
+  
+  if (sig)
+    {
+      sig_cp = strdup (spec->elements_sig);
+      if (! sig_cp)
+       {
+         err = gpg_err_code_from_errno (errno);
+         goto out;
+       }
+    }
+
+  if (enc)
+    *enc = enc_cp;
+  if (sig)
+    *sig = sig_cp;
+  err = 0;
+
+ out:
+
+  _gcry_module_release (pubkey);
+  if (err)
+    {
+      free (enc_cp);
+      free (sig_cp);
+    }
+
+  return err;
+}