Enhanced support for ECDSA.
authorWerner Koch <wk@gnupg.org>
Wed, 18 Apr 2007 12:59:00 +0000 (12:59 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 18 Apr 2007 12:59:00 +0000 (12:59 +0000)
Along with the latest libksba it is now possible for gpgsm to import
an ECC certificate.

12 files changed:
ChangeLog
NEWS
cipher/ChangeLog
cipher/ecc.c
cipher/pubkey.c
doc/gcrypt.texi
src/ChangeLog
src/cipher.h
src/g10lib.h
src/gcrypt.h.in
src/libgcrypt.vers
src/sexp.c

index 290df02..5c2481f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,6 @@
 2007-04-16  Werner Koch  <wk@g10code.com>
 
-       * configure.ac: Cehck for sysconf.
+       * configure.ac: Check for sysconf.
        * acinclude.m4 (GNUPG_CHECK_MLOCK): Try to use sysconf to get the
        page size and use getpagesize only then if available.
 
diff --git a/NEWS b/NEWS
index 01692ed..5d5fb55 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -49,6 +49,7 @@ Noteworthy changes in version 1.3.0 (unreleased)
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gcry_fast_random_poll  NEW
  gcry_md_debug           NEW
+ gcry_sexp_nth_string    NEW
  GCRYCTL_FAKED_RANDOM_P  NEW 
  GCRY_MD_SHA224          NEW
  GCRY_PK_USAGE_CERT      NEW
index 7d7a2e3..5538fb1 100644 (file)
@@ -1,3 +1,13 @@
+2007-04-18  Werner Koch  <wk@g10code.com>
+
+       * ecc.c (generate_curve): Implement alias mechanism.
+
+       * pubkey.c (sexp_elements_extract_ecc): New.
+       (sexp_to_key): Add special case for ecc.
+       (sexp_to_key, sexp_to_sig, sexp_to_enc, gcry_pk_genkey): Replace
+       name_terminated stuff by a call to _gcry_sexp_nth_string.
+       (gcry_pk_get_keygrip): Ditto.
+
 2007-04-16  Werner Koch  <wk@g10code.com>
 
        * ecc.c (_gcry_ecc_generate): Renamed DUMMY to CURVE and use it.
index 0012f79..d4a2187 100644 (file)
@@ -363,13 +363,28 @@ static gpg_err_code_t
 generate_curve (unsigned int nbits, const char *name, 
                 elliptic_curve_t *curve, unsigned int *r_nbits)
 {
-  int idx;
+  int idx, aliasno;
 
   if (name)
     {
+      /* First check nor native curves.  */
       for (idx = 0; domain_parms[idx].desc; idx++)
         if (!strcmp (name, domain_parms[idx].desc))
           break;
+      /* If not found consult the alias table.  */
+      if (!domain_parms[idx].desc)
+        {
+          for (aliasno = 0; curve_aliases[aliasno].name; aliasno++)
+            if (!strcmp (name, curve_aliases[aliasno].other))
+              break;
+          if (curve_aliases[aliasno].name)
+            {
+              for (idx = 0; domain_parms[idx].desc; idx++)
+                if (!strcmp (curve_aliases[aliasno].name,
+                             domain_parms[idx].desc))
+                  break;
+            }
+        }
     }
   else
     {
@@ -888,6 +903,37 @@ _gcry_ecc_generate (int algo, unsigned int nbits, const char *curve,
   return 0;
 }
 
+/* Return the parameters of the curve NAME.  */
+gcry_err_code_t
+_gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey)
+{
+  gpg_err_code_t err;
+  unsigned int nbits;
+  elliptic_curve_t E;
+  mpi_ec_t ctx;
+  gcry_mpi_t g_x, g_y;
+  
+  err = generate_curve (0, name, &E, &nbits);
+  if (err)
+    return err;
+
+  g_x = mpi_new (0);
+  g_y = mpi_new (0);
+  ctx = _gcry_mpi_ec_init (E.p, E.a);
+  if (_gcry_mpi_ec_get_affine (g_x, g_y, &E.G, ctx))
+    log_fatal ("ecc get param: Failed to get affine coordinates\n");
+  _gcry_mpi_ec_free (ctx);
+  point_free (&E.G);
+
+  pkey[0] = E.p;
+  pkey[1] = E.a;
+  pkey[2] = E.b;
+  pkey[3] = ec2os (g_x, g_y, E.p);
+  pkey[4] = E.n;
+  pkey[5] = NULL;
+
+  return 0;
+}
 
 static gcry_err_code_t
 ecc_generate (int algo, unsigned int nbits, unsigned long dummy,
@@ -1047,6 +1093,7 @@ ecc_get_nbits (int algo, gcry_mpi_t *pkey)
 static const char *ecdsa_names[] =
   {
     "ecdsa",
+    "ecc",
     NULL,
   };
 
index dd8330f..b4a6f3a 100644 (file)
@@ -1,6 +1,6 @@
 /* pubkey.c  - pubkey dispatcher
  * Copyright (C) 1998, 1999, 2000, 2002, 2003,
- *               2005 Free Software Foundation, Inc.
+ *               2005, 2007 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -781,6 +781,91 @@ sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
   return err;
 }
 
+/* Internal function used for ecc.  Note, that this function makes use
+   of its intimate knowledge about the ECC parameters from ecc.c. */
+static gcry_err_code_t
+sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
+                           gcry_mpi_t *elements)
+{
+  gcry_err_code_t err = 0;
+  int idx;
+  const char *name;
+  gcry_sexp_t list;
+
+  /* Clear the array for easir error cleanup. */
+  for (name = element_names, idx = 0; *name; name++, idx++)
+    elements[idx] = NULL;
+  assert (idx >= 6); /* We know that ECC has at least 6 elements.  */
+
+  /* Init the array with the available curve parameters. */
+  for (name = element_names, idx = 0; *name && !err; name++, idx++)
+    {
+      list = gcry_sexp_find_token (key_sexp, name, 1);
+      if (!list)
+       elements[idx] = NULL;
+      else
+       {
+         elements[idx] = gcry_sexp_nth_mpi (list, 1, GCRYMPI_FMT_USG);
+         gcry_sexp_release (list);
+         if (!elements[idx])
+            {
+              err = GPG_ERR_INV_OBJ;
+              goto leave;
+            }
+       }
+    }
+
+  /* Check whether a curve parameter has been given and then fill any
+     missing elements.  */
+  list = gcry_sexp_find_token (key_sexp, "curve", 5);
+  if (list)
+    {
+      char *curve;
+      gcry_mpi_t params[6];
+
+      for (idx = 0; idx < DIM(params); idx++)
+        params[idx] = NULL;
+
+      curve = _gcry_sexp_nth_string (list, 1);
+      if (!curve)
+        {
+          err = GPG_ERR_INV_OBJ; /* No curve name given (or out of core). */
+          goto leave;
+        }
+      err = _gcry_ecc_get_param (curve, params);
+      gcry_free (curve);
+      if (err)
+        goto leave;
+
+      for (idx = 0; idx < DIM(params); idx++)
+        {
+          if (!elements[idx])
+            elements[idx] = params[idx];
+          else
+            mpi_free (params[idx]);
+        }
+    }
+
+  /* Check that all parameters are known.  */
+  for (name = element_names, idx = 0; *name; name++, idx++)
+    if (!elements[idx])
+      {
+        err = GPG_ERR_NO_OBJ;
+        goto leave;
+      }
+  
+ leave:
+  if (err)
+    {
+      for (name = element_names, idx = 0; *name; name++, idx++)
+        if (elements[idx])
+          gcry_free (elements[idx]);
+    }
+  return err;
+}
+
+
+
 /****************
  * Convert a S-Exp with either a private or a public key to our
  * internal format. Currently we do only support the following
@@ -791,6 +876,7 @@ sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
  *    openpgp-rsa
  *    openpgp-elg
  *    openpgp-elg-sig
+ *    ecdsa
  * Provide a SE with the first element be either "private-key" or
  * or "public-key". It is followed by a list with its first element
  * be one of the above algorithm identifiers and the remaning
@@ -818,186 +904,169 @@ static gcry_err_code_t
 sexp_to_key (gcry_sexp_t sexp, int want_private, gcry_mpi_t **retarray,
              gcry_module_t *retalgo)
 {
-    gcry_sexp_t list, l2;
-    const char *name;
-    size_t n;
-    const char *elems;
-    gcry_mpi_t *array;
-    gcry_err_code_t err = GPG_ERR_NO_ERROR;
-    gcry_module_t module;
-    gcry_pk_spec_t *pubkey;
-
-    /* check that the first element is valid */
-    list = gcry_sexp_find_token( sexp, want_private? "private-key"
-                                                   :"public-key", 0 );
-    if( !list )
-       return GPG_ERR_INV_OBJ; /* Does not contain a public-
-                                   or private-key object */
-    l2 = gcry_sexp_cadr( list );
-    gcry_sexp_release ( list );
-    list = l2;
-    name = gcry_sexp_nth_data( list, 0, &n );
-    if( !name ) {
-       gcry_sexp_release ( list );
-       return GPG_ERR_INV_OBJ; /* invalid structure of object */
-    }
-
-    {
-      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;
+  gcry_err_code_t err = 0;
+  gcry_sexp_t list, l2;
+  char *name;
+  const char *elems;
+  gcry_mpi_t *array;
+  gcry_module_t module;
+  gcry_pk_spec_t *pubkey;
+  int is_ecc;
 
-      ath_mutex_lock (&pubkeys_registered_lock);
-      module = gcry_pk_lookup_name (name_terminated);
-      ath_mutex_unlock (&pubkeys_registered_lock);
+  /* Check that the first element is valid.  */
+  list = gcry_sexp_find_token (sexp, 
+                               want_private? "private-key":"public-key", 0);
+  if (!list)
+    return GPG_ERR_INV_OBJ; /* Does not contain a key object.  */
 
-      gcry_free (name_terminated);
+  l2 = gcry_sexp_cadr( list );
+  gcry_sexp_release ( list );
+  list = l2;
+  name = _gcry_sexp_nth_string (list, 0);
+  if (!name)
+    {
+      gcry_sexp_release ( list );
+      return GPG_ERR_INV_OBJ;      /* Invalid structure of object. */
     }
 
-    if (! module)
-      {
-       gcry_sexp_release (list);
-       return GPG_ERR_PUBKEY_ALGO; /* unknown algorithm */
-      }
-    else
-      pubkey = (gcry_pk_spec_t *) module->spec;
-
-    elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey;
-    array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
-    if (! array)
-      err = gpg_err_code_from_errno (errno);
-    if (! err)
-      err = sexp_elements_extract (list, elems, array);
-
-    if (list)
+  ath_mutex_lock (&pubkeys_registered_lock);
+  module = gcry_pk_lookup_name (name);
+  ath_mutex_unlock (&pubkeys_registered_lock);
+  
+  /* Fixme: We should make sure that an ECC key is always named "ecc"
+     and not "ecdsa".  "ecdsa" should be used for the signature
+     itself.  We need a function to test whether an algorithm given
+     with a key is compatible with an application of the key (signing,
+     encryption).  For RSA this is easy, but ECC is the first
+     algorithm which has many flavours. */
+  is_ecc = ( !strcmp (name, "ecdsa") || !strcmp (name, "ecc") );
+  
+  if (!module)
+    {
       gcry_sexp_release (list);
+      return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
+    }
+  else
+    pubkey = (gcry_pk_spec_t *) module->spec;
 
-    if (err)
-      {
-       if (array)
-         gcry_free (array);
-
-       ath_mutex_lock (&pubkeys_registered_lock);
-       _gcry_module_release (module);
-       ath_mutex_unlock (&pubkeys_registered_lock);
-      }
-    else
-      {
-       *retarray = array;
-       *retalgo = module;
-      }
+  elems = want_private ? pubkey->elements_skey : pubkey->elements_pkey;
+  array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
+  if (!array)
+    err = gpg_err_code_from_errno (errno);
+  if (!err)
+    {
+      if (is_ecc)
+        err = sexp_elements_extract_ecc (list, elems, array);
+      else
+        err = sexp_elements_extract (list, elems, array);
+    }
+  
+  gcry_sexp_release (list);
+  
+  if (err)
+    {
+      gcry_free (array);
 
-    return err;
+      ath_mutex_lock (&pubkeys_registered_lock);
+      _gcry_module_release (module);
+      ath_mutex_unlock (&pubkeys_registered_lock);
+    }
+  else
+    {
+      *retarray = array;
+      *retalgo = module;
+    }
+  
+  return err;
 }
 
+
 static gcry_err_code_t
 sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
             gcry_module_t *retalgo)
 {
-    gcry_sexp_t list, l2;
-    const char *name;
-    size_t n;
-    const char *elems;
-    gcry_mpi_t *array;
-    gcry_err_code_t err = GPG_ERR_NO_ERROR;
-    gcry_module_t module;
-    gcry_pk_spec_t *pubkey;
-
-    /* check that the first element is valid */
-    list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
-    if( !list )
-       return GPG_ERR_INV_OBJ; /* Does not contain a signature value object */
-    l2 = gcry_sexp_nth (list, 1);
-    if(! l2)
-      {
-       gcry_sexp_release (list);
-       return GPG_ERR_NO_OBJ; /* no cadr for the sig object */
-      }
-    name = gcry_sexp_nth_data( l2, 0, &n );
-    if( !name ) {
-       gcry_sexp_release ( list );
-       gcry_sexp_release ( l2 );
-       return GPG_ERR_INV_OBJ; /* invalid structure of object */
-    }
-    else if (n == 5 && (! memcmp (name, "flags", 5))) {
-      /* Skip flags, since they are not used but just here for the
+  gcry_err_code_t err = 0;
+  gcry_sexp_t list, l2;
+  char *name;
+  const char *elems;
+  gcry_mpi_t *array;
+  gcry_module_t module;
+  gcry_pk_spec_t *pubkey;
+  
+  /* Check that the first element is valid.  */
+  list = gcry_sexp_find_token( sexp, "sig-val" , 0 );
+  if (!list)
+    return GPG_ERR_INV_OBJ; /* Does not contain a signature value object.  */
+
+  l2 = gcry_sexp_nth (list, 1);
+  if (!l2)
+    {
+      gcry_sexp_release (list);
+      return GPG_ERR_NO_OBJ;   /* No cadr for the sig object.  */
+    }
+  name = _gcry_sexp_nth_string (l2, 0);
+  if (!name)
+    {
+      gcry_sexp_release (list);
+      gcry_sexp_release (l2);
+      return GPG_ERR_INV_OBJ;  /* Invalid structure of object.  */
+    }
+  else if (!strcmp (name, "flags")) 
+    {
+      /* Skip flags, since they are not used but here just for the
         sake of consistent S-expressions.  */
+      gcry_free (name);
       gcry_sexp_release (l2);
       l2 = gcry_sexp_nth (list, 2);
-      if (! l2)
+      if (!l2)
        {
          gcry_sexp_release (list);
          return GPG_ERR_INV_OBJ;
        }
-      name = gcry_sexp_nth_data (l2, 0, &n);
+      name = _gcry_sexp_nth_string (l2, 0);
     }
       
-    {
-      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;
-      
-      ath_mutex_lock (&pubkeys_registered_lock);
-      module = gcry_pk_lookup_name (name_terminated);
-      ath_mutex_unlock (&pubkeys_registered_lock);
+  ath_mutex_lock (&pubkeys_registered_lock);
+  module = gcry_pk_lookup_name (name);
+  ath_mutex_unlock (&pubkeys_registered_lock);
+  gcry_free (name);
+  name = NULL;
 
-      gcry_free (name_terminated);
+  if (!module)
+    {
+      gcry_sexp_release (l2);
+      gcry_sexp_release (list);
+      return GPG_ERR_PUBKEY_ALGO;  /* Unknown algorithm. */
     }
+  else
+    pubkey = (gcry_pk_spec_t *) module->spec;
 
-    if (! module)
-      {
-       gcry_sexp_release (l2);
-       gcry_sexp_release (list);
-       return GPG_ERR_PUBKEY_ALGO; /* unknown algorithm */
-      }
-    else
-      pubkey = (gcry_pk_spec_t *) module->spec;
-
-    elems = pubkey->elements_sig;
-    array = gcry_calloc (strlen (elems) + 1 , sizeof (*array));
-    if (! array)
-      err = gpg_err_code_from_errno (errno);
-
-    if (! err)
-      err = sexp_elements_extract (list, elems, array);
-
-    gcry_sexp_release (l2);
-    gcry_sexp_release (list);
+  elems = pubkey->elements_sig;
+  array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
+  if (!array)
+    err = gpg_err_code_from_errno (errno);
 
-    if (err)
-      {
-       ath_mutex_lock (&pubkeys_registered_lock);
-       _gcry_module_release (module);
-       ath_mutex_unlock (&pubkeys_registered_lock);
+  if (!err)
+    err = sexp_elements_extract (list, elems, array);
 
-       if (array)
-         gcry_free (array);
-      }
-    else
-      {
-       *retarray = array;
-       *retalgo = module;
-      }
+  gcry_sexp_release (l2);
+  gcry_sexp_release (list);
 
-    return err;
+  if (err)
+    {
+      ath_mutex_lock (&pubkeys_registered_lock);
+      _gcry_module_release (module);
+      ath_mutex_unlock (&pubkeys_registered_lock);
+      
+      gcry_free (array);
+    }
+  else
+    {
+      *retarray = array;
+      *retalgo = module;
+    }
+  
+  return err;
 }
 
 
@@ -1017,45 +1086,45 @@ static gcry_err_code_t
 sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
              int *ret_modern, int *ret_want_pkcs1, int *flags)
 {
+  gcry_err_code_t err = 0;
   gcry_sexp_t list = NULL, l2 = NULL;
   gcry_pk_spec_t *pubkey = NULL;
   gcry_module_t module = NULL;
-  const char *name;
+  char *name = NULL;
   size_t n;
   int parsed_flags = 0;
   const char *elems;
   gcry_mpi_t *array = NULL;
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
 
   *ret_want_pkcs1 = 0;
   *ret_modern = 0;
 
-  /* check that the first element is valid */
+  /* Check that the first element is valid.  */
   list = gcry_sexp_find_token (sexp, "enc-val" , 0);
-  if (! list)
+  if (!list)
     {
-      err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object */
+      err = GPG_ERR_INV_OBJ; /* Does not contain an encrypted value object */
       goto leave;
     }
 
   l2 = gcry_sexp_nth (list, 1);
-  if (! l2)
+  if (!l2)
     {
-      err = GPG_ERR_NO_OBJ; /* no cdr for the data object */
+      err = GPG_ERR_NO_OBJ; /* No cdr for the data object.  */
       goto leave;
     }
 
   /* Extract identifier of sublist.  */
-  name = gcry_sexp_nth_data (l2, 0, &n);
-  if (! name)
+  name = _gcry_sexp_nth_string (l2, 0);
+  if (!name)
     {
-      err = GPG_ERR_INV_OBJ; /* invalid structure of object */
+      err = GPG_ERR_INV_OBJ; /* Invalid structure of object.  */
       goto leave;
     }
   
-  if ((n == 5) && (! memcmp (name, "flags", 5)))
+  if (!strcmp (name, "flags"))
     {
-      /* There is a flags element - process it */
+      /* There is a flags element - process it */
       const char *s;
       int i;
       
@@ -1064,10 +1133,10 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
         {
           s = gcry_sexp_nth_data (l2, i, &n);
           if (! s)
-            ; /* not a data element - ignore */
-          else if (n == 3 && ! memcmp (s, "raw", 3))
-            ; /* just a dummy because it is the default */
-          else if (n == 5 && ! memcmp (s, "pkcs1", 5))
+            ; /* Not a data element - ignore.  */
+          else if (n == 3 && !memcmp (s, "raw", 3))
+            ; /* This is just a dummy as it is the default.  */
+          else if (n == 5 && !memcmp (s, "pkcs1", 5))
             *ret_want_pkcs1 = 1;
           else if (n == 11 && ! memcmp (s, "no-blinding", 11))
             parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
@@ -1078,20 +1147,21 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
             }
         }
       
-      /* Get the next which has the actual data */
+      /* Get the next which has the actual data. */
       gcry_sexp_release (l2);
       l2 = gcry_sexp_nth (list, 2);
-      if (! l2)
+      if (!l2)
         {
-          err = GPG_ERR_NO_OBJ; /* no cdr for the data object */
+          err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
           goto leave;
         }
 
       /* Extract sublist identifier.  */
-      name = gcry_sexp_nth_data (l2, 0, &n);
-      if (! name)
+      gcry_free (name);
+      name = _gcry_sexp_nth_string (l2, 0);
+      if (!name)
         {
-          err = GPG_ERR_INV_OBJ; /* invalid structure of object */
+          err = GPG_ERR_INV_OBJ; /* Invalid structure of object. */
           goto leave;
         }
 
@@ -1100,35 +1170,20 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
       l2 = NULL;
     }
 
-  {
-    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;
-    
-    ath_mutex_lock (&pubkeys_registered_lock);
-    module = gcry_pk_lookup_name (name_terminated);
-    ath_mutex_unlock (&pubkeys_registered_lock);
-    
-    gcry_free (name_terminated);
-    
-    if (! module)
-      {
-        err = GPG_ERR_PUBKEY_ALGO; /* unknown algorithm */
-        goto leave;
-      }
-    pubkey = (gcry_pk_spec_t *) module->spec;
-  }
+  ath_mutex_lock (&pubkeys_registered_lock);
+  module = gcry_pk_lookup_name (name);
+  ath_mutex_unlock (&pubkeys_registered_lock);
+  
+  if (!module)
+    {
+      err = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm.  */
+      goto leave;
+    }
+  pubkey = (gcry_pk_spec_t *) module->spec;
 
   elems = pubkey->elements_enc;
   array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
-  if (! array)
+  if (!array)
     {
       err = gpg_err_code_from_errno (errno);
       goto leave;
@@ -1137,18 +1192,16 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
   err = sexp_elements_extract (list, elems, array);
 
  leave:
-  if (list)
-    gcry_sexp_release (list);
-  if (l2)
-    gcry_sexp_release (l2);
+  gcry_sexp_release (list);
+  gcry_sexp_release (l2);
+  gcry_free (name);
 
   if (err)
     {
       ath_mutex_lock (&pubkeys_registered_lock);
       _gcry_module_release (module);
       ath_mutex_unlock (&pubkeys_registered_lock);
-      if (array)
-       gcry_free (array);
+      gcry_free (array);
     }
   else
     {
@@ -1820,6 +1873,9 @@ gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
   if (rc)
     goto leave;
 
+  /* Fixme: Check that the algorithm of S_SIG is compatible to the one
+     of S_PKEY.  */
+
   if (module_key->mod_id != module_sig->mod_id)
     {
       rc = GPG_ERR_CONFLICT;
@@ -1929,7 +1985,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   gcry_pk_spec_t *pubkey = NULL;
   gcry_module_t module = NULL;
   gcry_sexp_t list = NULL, l2 = NULL;
-  const char *name;
+  char *name = NULL;
   size_t n;
   gcry_err_code_t rc = GPG_ERR_NO_ERROR;
   int i;
@@ -1941,7 +1997,6 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   unsigned long use_e = 0;
   unsigned int qbits;
   gcry_mpi_t xvalue = NULL;
-  char *name_terminated;
   char *curve = NULL;
 
   REGISTER_DEFAULT_PUBKEYS;
@@ -1966,29 +2021,21 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       goto leave;
     }
 
-  name = gcry_sexp_nth_data (list, 0, &n);
-  if (! name)
-    {
-      rc = GPG_ERR_INV_OBJ; /* Algo string missing. */
-      goto leave;
-    }
-
-  name_terminated = gcry_malloc (n + 1);
-  if (!name_terminated)
+  name = _gcry_sexp_nth_string (list, 0);
+  if (!name)
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = GPG_ERR_INV_OBJ; /* Algo string missing.  */
       goto leave;
     }
-  memcpy (name_terminated, name, n);
-  name_terminated[n] = 0;
+  
   ath_mutex_lock (&pubkeys_registered_lock);
-  module = gcry_pk_lookup_name (name_terminated);
+  module = gcry_pk_lookup_name (name);
   ath_mutex_unlock (&pubkeys_registered_lock);
-  gcry_free (name_terminated);
-
-  if (! module)
+  gcry_free (name);
+  name = NULL;
+  if (!module)
     {
-      rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
+      rc = GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm.  */
       goto leave;
     }
   
@@ -2007,14 +2054,15 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   if (l2)
     {
       char buf[50];
+      const char *s;
 
-      name = gcry_sexp_nth_data (l2, 1, &n);
-      if ((! name) || (n >= DIM (buf) - 1))
+      s = gcry_sexp_nth_data (l2, 1, &n);
+      if ( !s || n >= DIM (buf) - 1 )
         {
-          rc = GPG_ERR_INV_OBJ; /* No value or value too large. */
+          rc = GPG_ERR_INV_OBJ; /* No value or value too large.  */
           goto leave;
         }
-      memcpy (buf, name, n);
+      memcpy (buf, s, n);
       buf[n] = 0;
       use_e = strtoul (buf, NULL, 0);
       gcry_sexp_release (l2);
@@ -2028,14 +2076,15 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   if (l2)
     {
       char buf[50];
+      const char *s;
 
-      name = gcry_sexp_nth_data (l2, 1, &n);
-      if ((! name) || (n >= DIM (buf) - 1))
+      s = gcry_sexp_nth_data (l2, 1, &n);
+      if (!s || n >= DIM (buf) - 1 )
         {
-          rc = GPG_ERR_INV_OBJ; /* No value or value too large. */
+          rc = GPG_ERR_INV_OBJ; /* No value or value too large.  */
           goto leave;
         }
-      memcpy (buf, name, n);
+      memcpy (buf, s, n);
       buf[n] = 0;
       qbits = (unsigned int)strtoul (buf, NULL, 0);
       gcry_sexp_release (l2);
@@ -2060,20 +2109,12 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   l2 = gcry_sexp_find_token (list, "curve", 0);
   if (l2)
     {
-      name = gcry_sexp_nth_data (l2, 1, &n);
-      if (!name || n < 1)
-        {
-          rc = GPG_ERR_INV_OBJ; /* No name or or value too large. */
-          goto leave;
-        }
-      curve = gcry_malloc (n+1);
+      curve = _gcry_sexp_nth_string (l2, 1);
       if (!curve)
         {
-          rc = gpg_err_code_from_syserror ();
+          rc = GPG_ERR_INV_OBJ; /* No curve name or value too large. */
           goto leave;
         }
-      memcpy (curve, name, n);
-      curve[n] = 0;
       gcry_sexp_release (l2);
       l2 = NULL;
     }
@@ -2092,23 +2133,18 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
     }
   if (list)
     {
-      name = gcry_sexp_nth_data (list, 1, &n);
-      if (! name)
-        {
-          rc = GPG_ERR_INV_OBJ; /* nbits without a cdr. */
-          goto leave;
-        }
-      
-      name_terminated = gcry_malloc (n + 1);
-      if (!name_terminated)
+      char buf[50];
+      const char *s;
+
+      s = gcry_sexp_nth_data (list, 1, &n);
+      if (!s || n >= DIM (buf) - 1 )
         {
-          rc = gpg_err_code_from_errno (errno);
+          rc = GPG_ERR_INV_OBJ; /* NBITS given without a cdr.  */
           goto leave;
         }
-      memcpy (name_terminated, name, n);
-      name_terminated[n] = 0;
-      nbits = (unsigned int) strtoul (name_terminated, NULL, 0);
-      gcry_free (name_terminated);
+      memcpy (buf, s, n);
+      buf[n] = 0;
+      nbits = (unsigned int)strtoul (buf, NULL, 0);
     }
   else 
     nbits = 0;
@@ -2209,6 +2245,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
   }
 
  leave:
+  gcry_free (name);
   gcry_free (curve);
   release_mpi_array (skey);
   /* Don't free SKEY itself, it is a static array. */
@@ -2286,8 +2323,8 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   gcry_sexp_t list = NULL, l2 = NULL;
   gcry_pk_spec_t *pubkey = NULL;
   gcry_module_t module = NULL;
-  const char *s, *name;
-  size_t n;
+  const char *s;
+  char *name = NULL;
   int idx;
   int is_rsa;
   const char *elems;
@@ -2311,24 +2348,16 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   list = l2;
   l2 = NULL;
 
-  name = gcry_sexp_nth_data (list, 0, &n);
-  if (! name)
+  name = _gcry_sexp_nth_string (list, 0);
+  if (!name)
     goto fail; /* Invalid structure of object. */
 
-  {
-    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);
-    module = gcry_pk_lookup_name (name_terminated);
-    ath_mutex_unlock (&pubkeys_registered_lock);
-    gcry_free (name_terminated);
-  }
+  ath_mutex_lock (&pubkeys_registered_lock);
+  module = gcry_pk_lookup_name (name);
+  ath_mutex_unlock (&pubkeys_registered_lock);
 
-  if (! module)
-    goto fail; /* unknown algorithm */
+  if (!module)
+    goto fail; /* Unknown algorithm.  */
 
   pubkey = (gcry_pk_spec_t *) module->spec;
 
@@ -2337,7 +2366,7 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   is_rsa = module->mod_id == GCRY_PK_RSA;
   elems = pubkey->elements_grip;
   if (! elems)
-    goto fail; /* no grip parameter */
+    goto fail; /* No grip parameter.  */
     
   if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
     goto fail;
@@ -2385,10 +2414,9 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   return array;
 
  fail:
-  if (l2)
-    gcry_sexp_release (l2);
-  if (md)
-    gcry_md_close (md);
+  gcry_free (name);
+  gcry_sexp_release (l2);
+  gcry_md_close (md);
   gcry_sexp_release (list);
   return NULL;
 }
index 41379d1..50e609e 100644 (file)
@@ -3634,6 +3634,15 @@ printf ("my name is %.*s\n", (int)len, name);
 @end example
 @end deftypefun
 
+@deftypefun char *gcry_sexp_nth_string (@w{gcry_sexp_t @var{list}}, @w{int @var{number}})
+
+This function is used to get and convert data from a @var{list}. The
+data is assumed to be a Nul terminated string.  The caller must
+release this returned value using @code{gcry_free}.  If there is
+no data at the given index, the index represents a list or the value
+can't be converted to a string, @code{NULL} is returned.
+@end deftypefun
+
 @deftypefun gcry_mpi_t gcry_sexp_nth_mpi (@w{gcry_sexp_t @var{list}}, @w{int @var{number}}, @w{int @var{mpifmt}})
 
 This function is used to get and convert data from a @var{list}. This
index 194a941..47e5bb2 100644 (file)
@@ -1,3 +1,12 @@
+2007-04-18  Werner Koch  <wk@g10code.com>
+
+       * gcrypt.h.in (gcry_sexp_nth_string): New.
+
+       * sexp.c (gcry_sexp_nth_data): Factored code out to ...
+       (sexp_nth_data): ... new.
+       (gcry_sexp_nth_string): New.
+       (gcry_sexp_nth_mpi): Reimplemented in terms of sexp_ntd_data.
+
 2007-04-16  Werner Koch  <wk@g10code.com>
 
        * secmem.c (init_pool): Use sysconf() if available to determine
index bd0cd74..2c505f7 100644 (file)
@@ -57,6 +57,8 @@ void _gcry_register_pk_ecc_progress (gcry_handler_progress_t cbc,
 gcry_err_code_t _gcry_ecc_generate (int algo, unsigned int nbits,
                                     const char *curve,
                                     gcry_mpi_t *skey, gcry_mpi_t **retfactors);
+gcry_err_code_t _gcry_ecc_get_param (const char *name, gcry_mpi_t *pkey);
+
 
 /*-- primegen.c --*/
 void _gcry_register_primegen_progress (gcry_handler_progress_t cb,
index db6b307..2844533 100644 (file)
@@ -243,4 +243,9 @@ gcry_err_code_t _gcry_malloc (size_t n, unsigned int flags, void **mem);
 
 #define GCRY_ALLOC_FLAG_SECURE (1 << 0)
 
+
+/*-- sexp.c --*/
+char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number);
+
+
 #endif /* G10LIB_H */
index feda73a..a95fa33 100644 (file)
@@ -472,6 +472,13 @@ gcry_sexp_t gcry_sexp_cadr (const gcry_sexp_t list);
 const char *gcry_sexp_nth_data (const gcry_sexp_t list, int number,
                                 size_t *datalen);
 
+/* This function is used to get and convert data from a LIST.  The
+   data is assumed to be a Nul terminated string.  The caller must
+   release the returned value using `gcry_free'.  If there is no data
+   at the given index, the index represents a list or the value can't
+   be converted to a string, `NULL' is returned.  */
+char *gcry_sexp_nth_string (gcry_sexp_t list, int number);
+
 /* This function is used to get and convert data from a LIST. This
    data is assumed to be an MPI stored in the format described by
    MPIFMT and returned as a standard Libgcrypt MPI.  The caller must
index 1163952..227f669 100644 (file)
@@ -82,6 +82,7 @@ GCRYPT_1.2 {
     gcry_sexp_new; gcry_sexp_nth; gcry_sexp_nth_data;
     gcry_sexp_nth_mpi; gcry_sexp_prepend; gcry_sexp_release;
     gcry_sexp_sprint; gcry_sexp_sscan; gcry_sexp_vlist;
+    gcry_sexp_nth_string;
     
     gcry_mpi_add; gcry_mpi_add_ui; gcry_mpi_addm; gcry_mpi_aprint;
     gcry_mpi_clear_bit; gcry_mpi_clear_flag; gcry_mpi_clear_highbit;
index dab2b54..e88d12c 100644 (file)
@@ -1,6 +1,6 @@
 /* sexp.c  -  S-Expression handling
  * Copyright (C) 1999, 2000, 2001, 2002, 2003,
- *               2004, 2006 Free Software Foundation, Inc.
+ *               2004, 2006, 2007 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -582,116 +582,123 @@ gcry_sexp_car( const gcry_sexp_t list )
     return gcry_sexp_nth ( list, 0 );
 }
 
-/****************
- * Get data from the car.  The returned value is valid as long as the list
- * is not modified.
- */
-const char *
-gcry_sexp_nth_data( const gcry_sexp_t list, int number, size_t *datalen )
+
+/* Helper to get data from the car.  The returned value is valid as
+   long as the list is not modified. */
+static const char *
+sexp_nth_data (const gcry_sexp_t list, int number, size_t *datalen)
 {
-    const byte *p;
-    DATALEN n;
-    int level = 0;
+  const byte *p;
+  DATALEN n;
+  int level = 0;
+  
+  *datalen = 0;
+  if ( !list ) 
+    return NULL;
 
-    *datalen = 0;
-    if ( !list ) {
-       return NULL;
-    }
-    p = list->d;
-    if ( *p == ST_OPEN )
-       p++;         /* yep, a list */
-    else if (number )
-       return NULL; /* not a list but an n > 0 element requested */
+  p = list->d;
+  if ( *p == ST_OPEN )
+    p++;            /* Yep, a list. */
+  else if (number)
+    return NULL;     /* Not a list but N > 0 requested. */
 
-    /* skip n elements */
-    while ( number > 0 ) {
-       if ( *p == ST_DATA ) {
-           memcpy ( &n, ++p, sizeof n );
-           p += sizeof n + n;
-           p--;
-           if ( !level )
-               number--;
+  /* Skip over N elements. */
+  while ( number > 0 ) 
+    {
+      if ( *p == ST_DATA ) 
+        {
+          memcpy ( &n, ++p, sizeof n );
+          p += sizeof n + n;
+          p--;
+          if ( !level )
+            number--;
        }
-       else if ( *p == ST_OPEN ) {
-           level++;
+      else if ( *p == ST_OPEN ) 
+        {
+          level++;
        }
-       else if ( *p == ST_CLOSE ) {
-           level--;
-           if ( !level )
-               number--;
+      else if ( *p == ST_CLOSE ) 
+        {
+          level--;
+          if ( !level )
+            number--;
        }
-       else if ( *p == ST_STOP ) {
-           return NULL;
+      else if ( *p == ST_STOP ) 
+        {
+          return NULL;
        }
-       p++;
+      p++;
     }
 
-
-    if ( *p == ST_DATA ) {
-       memcpy ( &n, ++p, sizeof n );
-       *datalen = n;
-       return (const char*)p + sizeof n;
+  /* If this is data, return it.  */
+  if ( *p == ST_DATA )
+    {
+      memcpy ( &n, ++p, sizeof n );
+      *datalen = n;
+      return (const char*)p + sizeof n;
     }
+  
+  return NULL;
+}
+
 
+/* Get data from the car.  The returned value is valid as long as the
+   list is not modified.  */
+const char *
+gcry_sexp_nth_data (const gcry_sexp_t list, int number, size_t *datalen )
+{
+  return sexp_nth_data (list, number, datalen);
+}
+
+
+/* Get a string from the car.  The returned value is a malloced string
+   and needs to be freed by the caller.  */
+char *
+_gcry_sexp_nth_string (const gcry_sexp_t list, int number)
+{
+  const char *s;
+  size_t n;
+  char *buf;
+
+  s = sexp_nth_data (list, number, &n);
+  if (!s || n < 1 || (n+1) < 1)
+    return NULL;
+  buf = gcry_malloc (n+1);
+  if (!buf)
     return NULL;
+  memcpy (buf, s, n);
+  buf[n] = 0;
+  return buf;
 }
 
-/****************
+/* Public version of _gcry_sexp_nth_string. */
+char *
+gcry_sexp_nth_string (const gcry_sexp_t list, int number)
+{
+  return _gcry_sexp_nth_string (list, number);
+}
+
+/*
  * Get a MPI from the car
  */
 gcry_mpi_t
 gcry_sexp_nth_mpi( gcry_sexp_t list, int number, int mpifmt )
 {
-    const byte *p;
-    DATALEN n;
-    int level = 0;
-
-    if ( !list )
-       return NULL;
-    if ( !mpifmt )
-       mpifmt = GCRYMPI_FMT_STD;
+  const char *s;
+  size_t n;
+  gcry_mpi_t a;
 
-    p = list->d;
-    if ( *p == ST_OPEN )
-       p++;         /* yep, a list */
-    else if (number )
-       return NULL; /* not a list but an n > 0 element requested */
+  if ( !mpifmt )
+    mpifmt = GCRYMPI_FMT_STD;
 
-    /* skip n elements */
-    while ( number > 0 ) {
-       if ( *p == ST_DATA ) {
-           memcpy ( &n, ++p, sizeof n );
-           p += sizeof n + n;
-           p--;
-           if ( !level )
-               number--;
-       }
-       else if ( *p == ST_OPEN ) {
-           level++;
-       }
-       else if ( *p == ST_CLOSE ) {
-           level--;
-           if ( !level )
-               number--;
-       }
-       else if ( *p == ST_STOP ) {
-           return NULL;
-       }
-       p++;
-    }
-
-    if ( *p == ST_DATA ) {
-       gcry_mpi_t a;
-       size_t nbytes;
-
-       memcpy ( &n, ++p, sizeof n );
-       p += sizeof n;
-       nbytes = n;
-       if( !gcry_mpi_scan( &a, mpifmt, p, n, &nbytes ) )
-           return a;
-    }
+  s = sexp_nth_data (list, number, &n);
+  if (!s)
+    return NULL;
 
+  if ( gcry_mpi_scan ( &a, mpifmt, s, n, NULL ) )
     return NULL;
+
+  return a;
 }