[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-310-ga329b6a

by Werner Koch cvs at cvs.gnupg.org
Wed Oct 16 16:23:13 CEST 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  a329b6abf00c990faf1986f9fbad7b4d71c13bcb (commit)
      from  45aa6131e93fac89d46733b3436d960f35fb99b2 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a329b6abf00c990faf1986f9fbad7b4d71c13bcb
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Oct 16 16:20:56 2013 +0200

    sexp: Add function gcry_sexp_extract_param.
    
    * src/gcrypt.h.in (_GCRY_GCC_ATTR_SENTINEL): New.
    (gcry_sexp_extract_param): New.
    * src/visibility.c (gcry_sexp_extract_param): New.
    * src/visibility.h (gcry_sexp_extract_param): Add hack to detect
    internal use.
    * cipher/pubkey-util.c (_gcry_pk_util_extract_mpis): Move and split
    into ...
    * src/sexp.c (_gcry_sexp_vextract_param)
    (_gcry_sexp_extract_param): this.  Change all callers.  Add support for buffer
    descriptors and a path option/
    
    * tests/tsexp.c (die, hex2buffer, hex2mpi, hex2mpiopa): New.
    (cmp_mpihex, cmp_bufhex): New.
    (check_extract_param): New.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index ab326eb..d60e067 100644
--- a/NEWS
+++ b/NEWS
@@ -35,13 +35,13 @@ Noteworthy changes in version 1.6.0 (unreleased)
 
  * Added a scatter gather hash convenience function.
 
- * Added several MPI helper functions.
+ * Added several MPI amd SEXP helper functions.
 
  * Added support for negative numbers to gcry_mpi_print,
    gcry_mpi_aprint and gcry_mpi_scan.
 
  * The algorithm ids GCRY_PK_ECDSA and GCRY_PK_ECDH are now
-   deprecated.  Use GCRY_PK_ECC instead.
+   deprecated.  Use GCRY_PK_ECC if you need an algorithm id.
 
  * Interface changes relative to the 1.5.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -108,6 +108,7 @@ Noteworthy changes in version 1.6.0 (unreleased)
  GCRYCTL_DISABLE_PRIV_DROP       NEW.
  GCRY_CIPHER_SALSA20             NEW.
  gcry_sexp_nth_buffer            NEW.
+ gcry_sexp_extract_param         NEW.
  GCRY_CIPHER_SALSA20R12          NEW.
  GCRY_CIPHER_GOST28147           NEW.
  GCRY_MD_GOSTR3411_94            NEW.
diff --git a/cipher/dsa.c b/cipher/dsa.c
index e43bdf4..45ad97a 100644
--- a/cipher/dsa.c
+++ b/cipher/dsa.c
@@ -956,9 +956,9 @@ dsa_check_secret_key (gcry_sexp_t keyparms)
   gcry_err_code_t rc;
   DSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL};
 
-  rc = _gcry_pk_util_extract_mpis (keyparms, "pqgyx",
-                                   &sk.p, &sk.q, &sk.g, &sk.y, &sk.x,
-                                   NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx",
+                                 &sk.p, &sk.q, &sk.g, &sk.y, &sk.x,
+                                 NULL);
   if (rc)
     goto leave;
 
@@ -998,8 +998,8 @@ dsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     log_mpidump ("dsa_sign   data", data);
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "pqgyx",
-                                   &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pqgyx",
+                                 &sk.p, &sk.q, &sk.g, &sk.y, &sk.x, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1065,7 +1065,7 @@ dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   rc = _gcry_pk_util_preparse_sigval (s_sig, dsa_names, &l1, NULL);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1075,8 +1075,8 @@ dsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (s_keyparms, "pqgy",
-                                   &pk.p, &pk.q, &pk.g, &pk.y, NULL);
+  rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pqgy",
+                                 &pk.p, &pk.q, &pk.g, &pk.y, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
diff --git a/cipher/ecc-curves.c b/cipher/ecc-curves.c
index 53433a2..2cdb9b4 100644
--- a/cipher/ecc-curves.c
+++ b/cipher/ecc-curves.c
@@ -436,9 +436,9 @@ _gcry_ecc_get_curve (gcry_sexp_t keyparms, int iterator, unsigned int *r_nbits)
   /*
    * Extract the curve parameters..
    */
-  if (_gcry_pk_util_extract_mpis (keyparms, "-pabgn",
-                                  &E.p, &E.a, &E.b, &mpi_g, &E.n,
-                                  NULL))
+  if (_gcry_sexp_extract_param (keyparms, NULL, "-pabgn",
+                                &E.p, &E.a, &E.b, &mpi_g, &E.n,
+                                NULL))
     goto leave;
   if (mpi_g)
     {
diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c
index d89971f..fa0bded 100644
--- a/cipher/ecc-misc.c
+++ b/cipher/ecc-misc.c
@@ -55,6 +55,7 @@ _gcry_ecc_curve_copy (elliptic_curve_t E)
 
   R.model = E.model;
   R.dialect = E.dialect;
+  R.name = E.name;
   R.p = mpi_copy (E.p);
   R.a = mpi_copy (E.a);
   R.b = mpi_copy (E.b);
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 3b75fea..1323d00 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -1435,9 +1435,9 @@ ecc_check_secret_key (gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d",
-                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
-                                   &mpi_q, &sk.d, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d",
+                                 &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                                 &mpi_q, &sk.d, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1552,9 +1552,9 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d",
-                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
-                                   &mpi_q, &sk.d, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?/q?+d",
+                                 &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                                 &mpi_q, &sk.d, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1686,9 +1686,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   rc = _gcry_pk_util_preparse_sigval (s_sig, ecc_names, &l1, &sigflags);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1,
-                                   (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
-                                   &sig_r, &sig_s, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL,
+                                 (sigflags & PUBKEY_FLAG_EDDSA)? "/rs":"rs",
+                                 &sig_r, &sig_s, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1706,9 +1706,9 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (s_keyparms, "-p?a?b?g?n?/q?",
-                                   &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
-                                   &mpi_q, NULL);
+  rc = _gcry_sexp_extract_param (s_keyparms, NULL, "-p?a?b?g?n?/q?",
+                                 &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+                                 &mpi_q, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -1890,9 +1890,9 @@ ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+q",
-                                   &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
-                                   &mpi_q, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+q",
+                                 &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+                                 &mpi_q, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
@@ -2044,7 +2044,7 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL, "e", &data_e, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -2058,9 +2058,9 @@ ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   /*
    * Extract the key.
    */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d",
-                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
-                                   &sk.d, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "-p?a?b?g?n?+d",
+                                 &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                                 &sk.d, NULL);
   if (rc)
     goto leave;
   if (mpi_g)
diff --git a/cipher/elgamal.c b/cipher/elgamal.c
index 691e122..432ba6f 100644
--- a/cipher/elgamal.c
+++ b/cipher/elgamal.c
@@ -735,9 +735,9 @@ elg_check_secret_key (gcry_sexp_t keyparms)
   gcry_err_code_t rc;
   ELG_secret_key sk = {NULL, NULL, NULL, NULL};
 
-  rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx",
-                                   &sk.p, &sk.g, &sk.y, &sk.x,
-                                   NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx",
+                                 &sk.p, &sk.g, &sk.y, &sk.x,
+                                 NULL);
   if (rc)
     goto leave;
 
@@ -781,7 +781,8 @@ elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "pgy", &pk.p, &pk.g, &pk.y, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pgy",
+                                 &pk.p, &pk.g, &pk.y, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -831,7 +832,7 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   rc = _gcry_pk_util_preparse_encval (s_data, elg_names, &l1, &ctx);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "ab", &data_a, &data_b, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL, "ab", &data_a, &data_b, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -846,9 +847,9 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx",
-                                   &sk.p, &sk.g, &sk.y, &sk.x,
-                                   NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx",
+                                 &sk.p, &sk.g, &sk.y, &sk.x,
+                                 NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -940,8 +941,8 @@ elg_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "pgyx",
-                                   &sk.p, &sk.g, &sk.y, &sk.x, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "pgyx",
+                                 &sk.p, &sk.g, &sk.y, &sk.x, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1008,7 +1009,7 @@ elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
   rc = _gcry_pk_util_preparse_sigval (s_sig, elg_names, &l1, NULL);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "rs", &sig_r, &sig_s, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL, "rs", &sig_r, &sig_s, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1018,8 +1019,8 @@ elg_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (s_keyparms, "pgy",
-                                   &pk.p, &pk.g, &pk.y, NULL);
+  rc = _gcry_sexp_extract_param (s_keyparms, NULL, "pgy",
+                                 &pk.p, &pk.g, &pk.y, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h
index cb2721d..db1399d 100644
--- a/cipher/pubkey-internal.h
+++ b/cipher/pubkey-internal.h
@@ -28,9 +28,6 @@ gpg_err_code_t _gcry_pk_util_get_nbits (gcry_sexp_t list,
                                         unsigned int *r_nbits);
 gpg_err_code_t _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list,
                                             unsigned long *r_e);
-gpg_err_code_t _gcry_pk_util_extract_mpis (gcry_sexp_t sexp,
-                                           const char *list, ...)
-                                           GCC_ATTR_SENTINEL(0);
 gpg_err_code_t _gcry_pk_util_preparse_sigval (gcry_sexp_t s_sig,
                                               const char **algo_names,
                                               gcry_sexp_t *r_parms,
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index caf715e..0b90054 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -273,119 +273,6 @@ _gcry_pk_util_get_rsa_use_e (gcry_sexp_t list, unsigned long *r_e)
 }
 
 
-/* Extract MPIs from an s-expression using a list of one letter
- * parameters.  The names of these parameters are given by the string
- * LIST.  Some special characters may be given to control the
- * conversion:
- *
- *    + :: Switch to unsigned integer format (default).
- *    - :: Switch to standard signed format.
- *    / :: Switch to opaque format.
- *    ? :: The previous parameter is optional.
- *
- * For each parameter name a pointer to an MPI variable is expected
- * and finally a NULL is expected.  Example:
- *
- *   _gcry_pk_util_extract_mpis (key, "n/x+ed", &mpi_n, &mpi_x, &mpi_e, NULL)
- *
- * This stores the parameter "N" from KEY as an unsigned MPI into
- * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the
- * parameter "E" again as an unsigned MPI into MPI_E.
- *
- * The function returns NULL on success.  On error an error code is
- * returned and the passed MPIs are either unchanged or set to NULL.
- */
-gpg_err_code_t
-_gcry_pk_util_extract_mpis (gcry_sexp_t sexp, const char *list, ...)
-{
-  va_list arg_ptr;
-  const char *s;
-  gcry_mpi_t *array[10];
-  int idx;
-  gcry_sexp_t l1;
-  enum gcry_mpi_format mpifmt = GCRYMPI_FMT_USG;
-
-  /* First copy all the args into an array.  This is required so that
-     we are able to release already allocated MPIs if later an error
-     was found.  */
-  va_start (arg_ptr, list) ;
-  for (s=list, idx=0; *s && idx < DIM (array); s++)
-    {
-      if (*s == '+' || *s == '-' || *s == '/' || *s == '?')
-        ;
-      else
-        {
-          array[idx] = va_arg (arg_ptr, gcry_mpi_t *);
-          if (!array[idx])
-            {
-              va_end (arg_ptr);
-              return GPG_ERR_INTERNAL; /* NULL pointer given.  */
-            }
-          idx++;
-        }
-    }
-  if (*s)
-    {
-      va_end (arg_ptr);
-      return GPG_ERR_INTERNAL;  /* Too many list elements.  */
-    }
-  if (va_arg (arg_ptr, gcry_mpi_t *))
-    {
-      va_end (arg_ptr);
-      return GPG_ERR_INTERNAL;  /* Not enough list elemends.  */
-    }
-  va_end (arg_ptr);
-
-  /* Now extract all parameters.  */
-  for (s=list, idx=0; *s; s++)
-    {
-      if (*s == '+')
-        mpifmt = GCRYMPI_FMT_USG;
-      else if (*s == '-')
-        mpifmt = GCRYMPI_FMT_STD;
-      else if (*s == '/')
-        mpifmt = GCRYMPI_FMT_HEX; /* Used to indicate opaque.  */
-      else if (*s == '?')
-        ; /* Only used via lookahead.  */
-      else
-        {
-          l1 = gcry_sexp_find_token (sexp, s, 1);
-          if (!l1 && s[1] == '?')
-            *array[idx] = NULL;       /* Optional element not found.  */
-          else if (!l1)
-            {
-              while (idx--)
-                {
-                  gcry_mpi_release (*array[idx]);
-                  *array[idx] = NULL;
-                }
-              return GPG_ERR_NO_OBJ;  /* List element not found.  */
-            }
-          else
-            {
-              if (mpifmt == GCRYMPI_FMT_HEX)
-                *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1);
-              else
-                *array[idx] = gcry_sexp_nth_mpi (l1, 1, mpifmt);
-              gcry_sexp_release (l1);
-              if (!*array[idx])
-                {
-                  while (idx--)
-                    {
-                      gcry_mpi_release (*array[idx]);
-                      *array[idx] = NULL;
-                    }
-                  return GPG_ERR_INV_OBJ;  /* Conversion failed.  */
-                }
-            }
-          idx++;
-        }
-    }
-
-  return 0;
-}
-
-
 /* Parse a "sig-val" s-expression and store the inner parameter list at
    R_PARMS.  ALGO_NAMES is used to verify that the algorithm in
    "sig-val" is valid.  Returns 0 on success and stores a new list at
diff --git a/cipher/rsa.c b/cipher/rsa.c
index d4d2a0a..fed52a1 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -855,9 +855,9 @@ rsa_check_secret_key (gcry_sexp_t keyparms)
   RSA_secret_key sk = {NULL, NULL, NULL, NULL, NULL, NULL};
 
   /* To check the key we need the optional parameters. */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "nedpqu",
-                                   &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
-                                   NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "nedpqu",
+                                 &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+                                 NULL);
   if (rc)
     goto leave;
 
@@ -902,7 +902,7 @@ rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -969,7 +969,7 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   rc = _gcry_pk_util_preparse_encval (s_data, rsa_names, &l1, &ctx);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "a", &data, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL, "a", &data, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -981,9 +981,9 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?",
-                                   &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
-                                   NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "nedp?q?u?",
+                                 &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+                                 NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1125,9 +1125,9 @@ rsa_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
     }
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "nedp?q?u?",
-                                   &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
-                                   NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "nedp?q?u?",
+                                 &sk.n, &sk.e, &sk.d, &sk.p, &sk.q, &sk.u,
+                                 NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
@@ -1213,14 +1213,14 @@ rsa_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
   rc = _gcry_pk_util_preparse_sigval (s_sig, rsa_names, &l1, NULL);
   if (rc)
     goto leave;
-  rc = _gcry_pk_util_extract_mpis (l1, "s", &sig, NULL);
+  rc = _gcry_sexp_extract_param (l1, NULL, "s", &sig, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
     log_printmpi ("rsa_verify  sig", sig);
 
   /* Extract the key.  */
-  rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL);
+  rc = _gcry_sexp_extract_param (keyparms, NULL, "ne", &pk.n, &pk.e, NULL);
   if (rc)
     goto leave;
   if (DBG_CIPHER)
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 79d4d74..473c484 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -3748,6 +3748,66 @@ this function to parse results of a public key function, you most
 likely want to use @code{GCRYMPI_FMT_USG}.
 @end deftypefun
 
+ at deftypefun gpg_error_t gcry_sexp_extract_param ( @
+  @w{gcry_sexp_t @var{sexp}}, @
+  @w{const char *@var{path}}, @
+  @w{const char *@var{list}}, ...)
+
+Extract parameters from an S-expression using a list of single letter
+parameter names.  The names of these parameters are specified in
+LIST.  Some special characters may be given to control the
+conversion:
+
+ at table @samp
+ at item +
+Switch to unsigned integer format (GCRYMPI_FMT_USG).  This is the
+default mode.
+ at item -
+Switch to standard signed format (GCRYMPI_FMT_STD).
+ at item /
+Switch to opaque MPI format.  The resulting MPIs may not be used for
+computations; see @code{gcry_mpi_get_opaque} for details.
+ at item &
+Switch to buffer descriptor mode.  See below for details.
+ at item ?
+If immediately following a parameter letter, that parameter is
+considered optional.
+ at end table
+
+Unless in buffer descriptor mode for each parameter name a pointer to
+an @code{gcry_mpi_t} variable is expected finally followed by a @code{NULL}.
+For example
+ at example
+  _gcry_sexp_extract_param (key, NULL, "n/x+ed",
+                            &mpi_n, &mpi_x, &mpi_e, NULL)
+ at end example
+
+stores the parameter 'n' from @var{key} as an unsigned MPI into
+ at var{mpi_n}, the parameter 'x' as an opaque MPI into @var{mpi_x}, and
+the parameter 'e' again as an unsigned MPI into @var{mpi_e}.
+
+ at var{path} is an optional string used to locate a token.  The
+exclamation mark separated tokens are used via
+ at code{gcry_sexp_find_token} to find a start point inside the
+S-expression.
+
+In buffer descriptor mode a pointer to a @code{gcry_buffer_t}
+descriptor is expected instead of a pointer to an MPI.  The caller may
+use two different operation modes here: If the @var{data} field of the
+provided descriptor is @code{NULL}, the function allocates a new
+buffer and stores it at @var{data}; the other fields are set
+accordingly with @var{off} set to 0.  If @var{data} is not
+ at code{NULL}, the function assumes that the @var{data}, @var{size}, and
+ at var{off} fields specify a buffer where to but the value of the
+respective parameter; on return the @var{len} field receives the
+number of bytes copied to that buffer; in case the buffer is too
+small, the function immediately returns with an error code (and
+ at var{len} is set to 0).
+
+The function returns NULL on success.  On error an error code is
+returned and the passed MPIs are either unchanged or set to NULL.
+ at end deftypefun
+
 
 @c **********************************************************
 @c *******************  MPIs ******** ***********************
diff --git a/src/g10lib.h b/src/g10lib.h
index c1ba2f7..3b09448 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -75,13 +75,6 @@
 #define GCC_ATTR_UNUSED
 #endif
 
-#if __GNUC__ >= 4
-# define GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a)))
-#else
-# define GCC_ATTR_SENTINEL(a)
-#endif
-
-
 /* Gettext macros.  */
 
 #define _(a)  _gcry_gettext(a)
@@ -382,6 +375,12 @@ gcry_err_code_t _gcry_sexp_vbuild (gcry_sexp_t *retsexp, size_t *erroff,
                                    const char *format, va_list arg_ptr);
 gcry_mpi_t _gcry_sexp_nth_opaque_mpi (gcry_sexp_t list, int number);
 char *_gcry_sexp_nth_string (const gcry_sexp_t list, int number);
+gpg_err_code_t _gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
+                                          const char *list, va_list arg_ptr);
+gpg_err_code_t _gcry_sexp_extract_param (gcry_sexp_t sexp,
+                                         const char *path,
+                                         const char *list,
+                                         ...) _GCRY_GCC_ATTR_SENTINEL(0);
 
 
 /*-- fips.c --*/
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 8646f43..64cc0e4 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -102,6 +102,10 @@ extern "C" {
 
 #define _GCRY_GCC_ATTR_PRINTF(f,a)  __attribute__ ((format (printf,f,a)))
 
+#if _GCRT_GCC_VERSION >= 40000
+#define _GCRY_GCC_ATTR_SENTINEL(a) __attribute__ ((sentinel(a)))
+#endif
+
 #endif /*__GNUC__*/
 
 #ifndef _GCRY_GCC_ATTR_DEPRECATED
@@ -114,7 +118,10 @@ extern "C" {
 #define _GCRY_GCC_ATTR_MALLOC
 #endif
 #ifndef _GCRY_GCC_ATTR_PRINTF
-#define _GCRY_GCC_ATTR_PRINTF
+#define _GCRY_GCC_ATTR_PRINTF(f,a)
+#endif
+#ifndef _GCRY_GCC_ATTR_SENTINEL
+#define _GCRY_GCC_ATTR_SENTINEL(a)
 #endif
 
 /* Make up an attribute to mark functions and types as deprecated but
@@ -459,6 +466,12 @@ char *gcry_sexp_nth_string (gcry_sexp_t list, int number);
    value can't be converted to an MPI, `NULL' is returned.  */
 gcry_mpi_t gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt);
 
+/* Convenience fucntion to extract parameters from an S-expression
+ * using a list of single letter parameters.  */
+gpg_error_t gcry_sexp_extract_param (gcry_sexp_t sexp,
+                                     const char *path,
+                                     const char *list,
+                                     ...) _GCRY_GCC_ATTR_SENTINEL(0);
 
 
 /*******************************************
diff --git a/src/libgcrypt.def b/src/libgcrypt.def
index 7efb3b9..ec0c1e3 100644
--- a/src/libgcrypt.def
+++ b/src/libgcrypt.def
@@ -253,5 +253,8 @@ EXPORTS
       gcry_log_debugpnt         @223
       gcry_log_debugsxp         @224
 
+      gcry_sexp_extract_param   @225
+
+
 
 ;; end of file with public symbols for Windows.
diff --git a/src/libgcrypt.vers b/src/libgcrypt.vers
index b1669fd..be72aad 100644
--- a/src/libgcrypt.vers
+++ b/src/libgcrypt.vers
@@ -76,7 +76,7 @@ GCRYPT_1.6 {
     gcry_sexp_new; gcry_sexp_nth; gcry_sexp_nth_buffer; 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_sexp_nth_string; gcry_sexp_extract_param;
 
     gcry_mpi_is_neg; gcry_mpi_neg; gcry_mpi_abs;
     gcry_mpi_add; gcry_mpi_add_ui; gcry_mpi_addm; gcry_mpi_aprint;
diff --git a/src/sexp.c b/src/sexp.c
index 6a2a9be..6e4ff27 100644
--- a/src/sexp.c
+++ b/src/sexp.c
@@ -2117,3 +2117,238 @@ gcry_sexp_canon_len (const unsigned char *buffer, size_t length,
 	}
     }
 }
+
+
+/* Extract MPIs from an s-expression using a list of one letter
+ * parameters.  The names of these parameters are given by the string
+ * LIST.  Some special characters may be given to control the
+ * conversion:
+ *
+ *    + :: Switch to unsigned integer format (default).
+ *    - :: Switch to standard signed format.
+ *    / :: Switch to opaque format.
+ *    & :: Switch to buffer descriptor mode - see below.
+ *    ? :: The previous parameter is optional.
+ *
+ * Unless in gcry_buffer_t mode for each parameter name a pointer to
+ * an MPI variable is expected and finally a NULL is expected.
+ * Example:
+ *
+ *   _gcry_sexp_extract_param (key, NULL, "n/x+ed",
+ *                             &mpi_n, &mpi_x, &mpi_e, NULL)
+ *
+ * This stores the parameter "N" from KEY as an unsigned MPI into
+ * MPI_N, the parameter "X" as an opaque MPI into MPI_X, and the
+ * parameter "E" again as an unsigned MPI into MPI_E.
+ *
+ * If in buffer descriptor mode a pointer to gcry_buffer_t descriptor
+ * is expected instead of a pointer to an MPI.  The caller may use two
+ * different operation modes: If the DATA field of the provided buffer
+ * descriptor is NULL, the function allocates a new buffer and stores
+ * it at DATA; the other fields are set accordingly with OFF being 0.
+ * If DATA is not NULL, the function assumes that DATA, SIZE, and OFF
+ * describe a buffer where to but the data; on return the LEN field
+ * receives the number of bytes copied to that buffer; if the buffer
+ * is too small, the function immediately returns with an error code
+ * (and LEN set to 0).
+ *
+ * PATH is an optional string used to locate a token.  The exclamation
+ * mark separated tokens are used to via gcry_sexp_find_token to find
+ * a start point inside SEXP.
+ *
+ * The function returns NULL on success.  On error an error code is
+ * returned and the passed MPIs are either unchanged or set to NULL.
+ */
+gpg_err_code_t
+_gcry_sexp_vextract_param (gcry_sexp_t sexp, const char *path,
+                           const char *list, va_list arg_ptr)
+{
+  gpg_err_code_t rc;
+  const char *s;
+  gcry_mpi_t *array[20];
+  char arrayisdesc[20];
+  int idx;
+  gcry_sexp_t l1;
+  int mode = '+'; /* Default to GCRYMPI_FMT_USG.  */
+  gcry_sexp_t freethis = NULL;
+
+  memset (arrayisdesc, 0, sizeof arrayisdesc);
+
+  /* First copy all the args into an array.  This is required so that
+     we are able to release already allocated MPIs if later an error
+     was found.  */
+  for (s=list, idx=0; *s && idx < DIM (array); s++)
+    {
+      if (*s == '&' || *s == '+' || *s == '-' || *s == '/' || *s == '?' )
+        ;
+      else
+        {
+          array[idx] = va_arg (arg_ptr, gcry_mpi_t *);
+          if (!array[idx])
+            return GPG_ERR_MISSING_VALUE; /* NULL pointer given.  */
+          idx++;
+        }
+    }
+  if (*s)
+    return GPG_ERR_LIMIT_REACHED;  /* Too many list elements.  */
+  if (va_arg (arg_ptr, gcry_mpi_t *))
+    return GPG_ERR_INV_ARG;  /* Not enough list elemends.  */
+
+  /* Drill down.  */
+  while (path && *path)
+    {
+      size_t n;
+
+      s = strchr (path, '!');
+      if (s == path)
+        {
+          rc = GPG_ERR_NOT_FOUND;
+          goto cleanup;
+        }
+      n = s? s - path : 0;
+      l1 = gcry_sexp_find_token (sexp, path, n);
+      if (!l1)
+        {
+          rc = GPG_ERR_NOT_FOUND;
+          goto cleanup;
+        }
+      sexp = l1; l1 = NULL;
+      gcry_sexp_release (freethis);
+      freethis = sexp;
+      if (n)
+        path += n + 1;
+      else
+        path = NULL;
+    }
+
+
+  /* Now extract all parameters.  */
+  for (s=list, idx=0; *s; s++)
+    {
+      if (*s == '&' || *s == '+' || *s == '-' || *s == '/')
+        mode = *s;
+      else if (*s == '?')
+        ; /* Only used via lookahead.  */
+      else
+        {
+          l1 = gcry_sexp_find_token (sexp, s, 1);
+          if (!l1 && s[1] == '?')
+            {
+              /* Optional element not found.  */
+              if (mode == '&')
+                {
+                  gcry_buffer_t *spec = (gcry_buffer_t*)array[idx];
+                  if (!spec->data)
+                    {
+                      spec->size = 0;
+                      spec->off = 0;
+                    }
+                  spec->len = 0;
+                }
+              else
+                *array[idx] = NULL;
+            }
+          else if (!l1)
+            {
+              rc = GPG_ERR_NO_OBJ;  /* List element not found.  */
+              goto cleanup;
+            }
+           else
+            {
+              if (mode == '&')
+                {
+                  gcry_buffer_t *spec = (gcry_buffer_t*)array[idx];
+
+                  if (spec->data)
+                    {
+                      const char *pbuf;
+                      size_t nbuf;
+
+                      pbuf = gcry_sexp_nth_data (l1, 1, &nbuf);
+                      if (!pbuf || !nbuf)
+                        {
+                          rc = GPG_ERR_INV_OBJ;
+                          goto cleanup;
+                        }
+                      if (spec->off + nbuf > spec->size)
+                        {
+                          rc = GPG_ERR_BUFFER_TOO_SHORT;
+                          goto cleanup;
+                        }
+                      memcpy ((char*)spec->data + spec->off, pbuf, nbuf);
+                      spec->len = nbuf;
+                      arrayisdesc[idx] = 1;
+                    }
+                  else
+                    {
+                      spec->data = gcry_sexp_nth_buffer (l1, 1, &spec->size);
+                      if (!spec->data)
+                        {
+                          rc = GPG_ERR_INV_OBJ; /* Or out of core.  */
+                          goto cleanup;
+                        }
+                      spec->len = spec->size;
+                      spec->off = 0;
+                      arrayisdesc[idx] = 2;
+                    }
+                }
+              else if (mode == '/')
+                *array[idx] = _gcry_sexp_nth_opaque_mpi (l1, 1);
+              else if (mode == '-')
+                *array[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_STD);
+              else
+                *array[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+              gcry_sexp_release (l1); l1 = NULL;
+              if (!*array[idx])
+                {
+                  rc = GPG_ERR_INV_OBJ;  /* Conversion failed.  */
+                  goto cleanup;
+                }
+            }
+          idx++;
+        }
+    }
+
+  gcry_sexp_release (freethis);
+  return 0;
+
+ cleanup:
+  gcry_sexp_release (freethis);
+  gcry_sexp_release (l1);
+  while (idx--)
+    {
+      if (!arrayisdesc[idx])
+        {
+          gcry_mpi_release (*array[idx]);
+          *array[idx] = NULL;
+        }
+      else if (!arrayisdesc[idx] == 1)
+        {
+          /* Caller provided buffer.  */
+          gcry_buffer_t *spec = (gcry_buffer_t*)array[idx];
+          spec->len = 0;
+        }
+      else
+        {
+          /* We might have allocated a buffer.  */
+          gcry_buffer_t *spec = (gcry_buffer_t*)array[idx];
+          gcry_free (spec->data);
+          spec->data = NULL;
+          spec->size = spec->off = spec->len = 0;
+        }
+     }
+  return rc;
+}
+
+gpg_error_t
+_gcry_sexp_extract_param (gcry_sexp_t sexp, const char *path,
+                          const char *list, ...)
+{
+  gcry_err_code_t rc;
+  va_list arg_ptr;
+
+  va_start (arg_ptr, list);
+  rc = _gcry_sexp_vextract_param (sexp, path, list, arg_ptr);
+  va_end (arg_ptr);
+  return gpg_error (rc);
+}
diff --git a/src/visibility.c b/src/visibility.c
index 6e3c755..848925e 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -250,6 +250,21 @@ gcry_sexp_nth_mpi (gcry_sexp_t list, int number, int mpifmt)
   return _gcry_sexp_nth_mpi (list, number, mpifmt);
 }
 
+gpg_error_t
+gcry_sexp_extract_param (gcry_sexp_t sexp, const char *path,
+                         const char *list, ...)
+{
+  gcry_err_code_t rc;
+  va_list arg_ptr;
+
+  va_start (arg_ptr, list);
+  rc = _gcry_sexp_vextract_param (sexp, path, list, arg_ptr);
+  va_end (arg_ptr);
+  return gpg_error (rc);
+}
+
+
+
 gcry_mpi_t
 gcry_mpi_new (unsigned int nbits)
 {
diff --git a/src/visibility.h b/src/visibility.h
index cd2a60f..1c8f047 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -537,6 +537,7 @@ MARK_VISIBLE (gcry_sexp_release)
 MARK_VISIBLE (gcry_sexp_sprint)
 MARK_VISIBLE (gcry_sexp_sscan)
 MARK_VISIBLE (gcry_sexp_vlist)
+MARK_VISIBLEX(gcry_sexp_extract_param)
 
 MARK_VISIBLEX(gcry_mpi_abs)
 MARK_VISIBLE (gcry_mpi_add)
@@ -615,6 +616,16 @@ MARK_VISIBLEX(_gcry_mpi_get_const)
 
 
 #undef MARK_VISIBLE
-#endif /*_GCRY_INCLUDED_BY_VISIBILITY_C*/
+#else /*!_GCRY_INCLUDED_BY_VISIBILITY_C*/
+
+/* To avoid accidental use of the public functions inside Libgcrypt,
+   we redefine them to catch such errors.  The usual difference
+   between a public and an internal version is that the internal
+   version use gpg_err_code_t and the public version gpg_error_t.  */
+
+#define gcry_sexp_extract_param _gcry_USE_THE_UNDERSCORED_FUNCTION
+
+
+#endif /*!_GCRY_INCLUDED_BY_VISIBILITY_C*/
 
 #endif /*GCRY_VISIBILITY_H*/
diff --git a/tests/tsexp.c b/tests/tsexp.c
index 7c4f7c8..8a6b912 100644
--- a/tests/tsexp.c
+++ b/tests/tsexp.c
@@ -25,14 +25,48 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <assert.h>
 #include "../src/gcrypt-int.h"
 
 #define PGMNAME "tsexp"
 
+#ifndef DIM
+# define DIM(v)		     (sizeof(v)/sizeof((v)[0]))
+#endif
+#define my_isascii(c) (!((c) & 0x80))
+#define digitp(p)     (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a)  (digitp (a)                     \
+                       || (*(a) >= 'A' && *(a) <= 'F')  \
+                       || (*(a) >= 'a' && *(a) <= 'f'))
+#define xtoi_1(p)     (*(p) <= '9'? (*(p)- '0'): \
+                       *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)     ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+#define xmalloc(a)    gcry_xmalloc ((a))
+#define xcalloc(a,b)  gcry_xcalloc ((a),(b))
+#define xstrdup(a)    gcry_xstrdup ((a))
+#define xfree(a)      gcry_free ((a))
+#define pass()        do { ; } while (0)
+
+
 static int verbose;
 static int error_count;
 
 static void
+die (const char *format, ...)
+{
+  va_list arg_ptr ;
+
+  fflush (stdout);
+  fprintf (stderr, "%s: ", PGMNAME);
+  va_start( arg_ptr, format ) ;
+  vfprintf (stderr, format, arg_ptr );
+  va_end(arg_ptr);
+  if (*format && format[strlen(format)-1] != '\n')
+    putc ('\n', stderr);
+  exit (1);
+}
+
+static void
 info (const char *format, ...)
 {
   va_list arg_ptr;
@@ -42,6 +76,8 @@ info (const char *format, ...)
       va_start( arg_ptr, format ) ;
       vfprintf (stderr, format, arg_ptr );
       va_end(arg_ptr);
+      if (*format && format[strlen(format)-1] != '\n')
+        putc ('\n', stderr);
     }
 }
 
@@ -54,10 +90,110 @@ fail ( const char *format, ... )
     va_start( arg_ptr, format ) ;
     vfprintf (stderr, format, arg_ptr );
     va_end(arg_ptr);
+    if (*format && format[strlen(format)-1] != '\n')
+      putc ('\n', stderr);
     error_count++;
 }
 
 
+
+/* Convert STRING consisting of hex characters into its binary
+   representation and return it as an allocated buffer. The valid
+   length of the buffer is returned at R_LENGTH.  The string is
+   delimited by end of string.  The function returns NULL on
+   error.  */
+static void *
+hex2buffer (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = xmalloc (strlen(string)/2+1);
+  length = 0;
+  for (s=string; *s; s +=2 )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        return NULL;           /* Invalid hex digits. */
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+static gcry_mpi_t
+hex2mpi (const char *string)
+{
+  gpg_error_t err;
+  gcry_mpi_t val;
+
+  err = gcry_mpi_scan (&val, GCRYMPI_FMT_HEX, string, 0, NULL);
+  if (err)
+    die ("hex2mpi '%s' failed: %s\n", string, gpg_strerror (err));
+  return val;
+}
+
+static gcry_mpi_t
+hex2mpiopa (const char *string)
+{
+  char *buffer;
+  size_t buflen;
+  gcry_mpi_t val;
+
+  buffer = hex2buffer (string, &buflen);
+  if (!buffer)
+    die ("hex2mpiopa '%s' failed: parser error\n", string);
+  val = gcry_mpi_set_opaque (NULL, buffer, buflen*8);
+  if (!buffer)
+    die ("hex2mpiopa '%s' failed: set_opaque error%s\n", string);
+  return val;
+}
+
+
+/* Compare A to B, where B is given as a hex string.  */
+static int
+cmp_mpihex (gcry_mpi_t a, const char *b)
+{
+  gcry_mpi_t bval;
+  int res;
+
+  if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    bval = hex2mpiopa (b);
+  else
+    bval = hex2mpi (b);
+  res = gcry_mpi_cmp (a, bval);
+  gcry_mpi_release (bval);
+  return res;
+}
+
+/* Compare A to B, where A is a buffer and B a hex string.  */
+static int
+cmp_bufhex (const void *a, size_t alen, const char *b)
+{
+  void *bbuf;
+  size_t blen;
+  int res;
+
+  if (!a && !b)
+    return 0;
+  if (a && !b)
+    return 1;
+  if (!a && b)
+    return -1;
+
+  bbuf = hex2buffer (b, &blen);
+  if (!bbuf)
+    die ("cmp_bufhex: error converting hex string\n");
+  if (alen != blen)
+    return alen < blen? -1 : 1;
+  res = memcmp (a, bbuf, alen);
+  xfree (bbuf);
+  return res;
+}
+
+
+
 /* fixme: we need better tests */
 static void
 basic (void)
@@ -195,7 +331,7 @@ basic (void)
               fail ("no car for `%s'\n", token);
               continue;
             }
-          info ("car=`%.*s'\n", (int)n, p);
+          /* info ("car=`%.*s'\n", (int)n, p); */
 
           s2 = gcry_sexp_cdr (s1);
           if (!s2)
@@ -230,7 +366,7 @@ basic (void)
                   fail("no car for `%s'\n", parm );
                   continue;
                 }
-              info ("car=`%.*s'\n", (int)n, p);
+              /* info ("car=`%.*s'\n", (int)n, p); */
               p = gcry_sexp_nth_data (s2, 1, &n);
               if (!p)
                 {
@@ -238,7 +374,7 @@ basic (void)
                   fail("no cdr for `%s'\n", parm );
                   continue;
                 }
-              info ("cdr=`%.*s'\n", (int)n, p);
+              /* info ("cdr=`%.*s'\n", (int)n, p); */
 
               a = gcry_sexp_nth_mpi (s2, 0, GCRYMPI_FMT_USG);
               gcry_sexp_release (s2);
@@ -457,6 +593,379 @@ check_sscan (void)
 }
 
 
+static void
+check_extract_param (void)
+{
+  /* This sample data is a real key but with some parameters of the
+     public key modified.  */
+  static char sample1[] =
+    "(key-data"
+    " (public-key"
+    "  (ecc"
+    "   (curve Ed25519)"
+    "   (p #6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)"
+    "   (a #EF#)"
+    "   (b #C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)"
+    "   (g #14"
+    "       216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"
+    "       6666666666666666666666666666666666666666666666666666666666666658#)"
+    "   (n #0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)"
+    "   (q #20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)"
+    "))"
+    " (private-key"
+    "  (ecc"
+    "   (curve Ed25519)"
+    "   (p #7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED#)"
+    "   (a #FF#)"
+    "   (b #D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6#)"
+    "   (g #04"
+    "       216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"
+    "       6666666666666666666666666666666666666666666666666666666666666658#)"
+    "   (n #1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED#)"
+    "   (q #30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62#)"
+    "   (d #56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276#)"
+    ")))";
+
+  static char sample1_p[] =
+    "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED";
+  static char sample1_px[] =
+    "6FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED";
+  static char sample1_a[] = "FF";
+  static char sample1_ax[] = "EF";
+  static char sample1_b[] =
+    "D2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6";
+  static char sample1_bx[] =
+    "C2036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978B6";
+  static char sample1_g[] =
+    "04"
+    "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"
+    "6666666666666666666666666666666666666666666666666666666666666658";
+  static char sample1_gx[] =
+    "14"
+    "216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A"
+    "6666666666666666666666666666666666666666666666666666666666666658";
+  static char sample1_n[] =
+    "1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED";
+  static char sample1_nx[] =
+    "0000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED";
+  static char sample1_q[] =
+    "30B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62";
+  static char sample1_qx[] =
+    "20B37806015CA06B3AEB9423EE84A41D7F31AA65F4148553755206D679F8BF62";
+  static char sample1_d[] =
+    "56BEA284A22F443A7AEA8CEFA24DA5055CDF1D490C94D8C568FE0802C9169276";
+
+  static struct {
+    const char *sexp_str;
+    const char *path;
+    const char *list;
+    int nparam;
+    gpg_err_code_t expected_err;
+    const char *exp_p;
+    const char *exp_a;
+    const char *exp_b;
+    const char *exp_g;
+    const char *exp_n;
+    const char *exp_q;
+    const char *exp_d;
+  } tests[] = {
+    {
+      sample1,
+      NULL,
+      "pabgnqd", 6,
+      GPG_ERR_MISSING_VALUE,
+    },
+    {
+      sample1,
+      NULL,
+      "pabgnq", 7,
+      GPG_ERR_INV_ARG
+    },
+    {
+      sample1,
+      NULL,
+      "pabgnqd", 7,
+      0,
+      sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx,
+      sample1_qx, sample1_d
+    },
+    {
+      sample1,
+      NULL,
+      "abg", 3,
+      0,
+      sample1_ax, sample1_bx, sample1_gx
+    },
+    {
+      sample1,
+      NULL,
+      "x?abg", 4,
+      0,
+      NULL, sample1_ax, sample1_bx, sample1_gx
+    },
+    {
+      sample1,
+      NULL,
+      "p?abg", 4,
+      GPG_ERR_USER_1,
+      NULL, sample1_ax, sample1_bx, sample1_gx
+    },
+    {
+      sample1,
+      NULL,
+      "pax?gnqd", 7,
+      0,
+      sample1_px, sample1_ax, NULL, sample1_gx, sample1_nx,
+      sample1_qx, sample1_d
+    },
+    {
+      sample1,
+      "public-key",
+      "pabgnqd", 7,
+      GPG_ERR_NO_OBJ,  /* d is not in public key.  */
+      sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx,
+      sample1_qx, sample1_d
+    },
+    {
+      sample1,
+      "private-key",
+      "pabgnqd", 7,
+      0,
+      sample1_p, sample1_a, sample1_b, sample1_g, sample1_n,
+      sample1_q, sample1_d
+    },
+    {
+      sample1,
+      "public-key!ecc",
+      "pabgnq", 6,
+      0,
+      sample1_px, sample1_ax, sample1_bx, sample1_gx, sample1_nx,
+      sample1_qx
+    },
+    {
+      sample1,
+      "public-key!ecc!foo",
+      "pabgnq", 6,
+      GPG_ERR_NOT_FOUND
+    },
+    {
+      sample1,
+      "public-key!!ecc",
+      "pabgnq", 6,
+      GPG_ERR_NOT_FOUND
+    },
+    {
+      sample1,
+      "private-key",
+      "pa/bgnqd", 7,
+      0,
+      sample1_p, sample1_a, sample1_b, sample1_g, sample1_n,
+      sample1_q, sample1_d
+    },
+    {
+      sample1,
+      "private-key",
+      "p-a+bgnqd", 7,
+      0,
+      sample1_p, "-01", sample1_b, sample1_g, sample1_n,
+      sample1_q, sample1_d
+    },
+    {NULL}
+  };
+  int idx, i;
+  const char *paramstr;
+  int paramidx;
+  gpg_error_t err;
+  gcry_sexp_t sxp;
+  gcry_mpi_t mpis[7];
+  gcry_buffer_t ioarray[7];
+  char iobuffer[200];
+
+  info ("checking gcry_sexp_extract_param\n");
+  for (idx=0; tests[idx].sexp_str; idx++)
+    {
+      err = gcry_sexp_new (&sxp, tests[idx].sexp_str, 0, 1);
+      if (err)
+        die ("converting string to sexp failed: %s", gpg_strerror (err));
+
+      memset (mpis, 0, sizeof mpis);
+      switch (tests[idx].nparam)
+        {
+        case 0:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         NULL);
+          break;
+        case 1:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, NULL);
+          break;
+        case 2:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, mpis+1, NULL);
+          break;
+        case 3:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, mpis+1, mpis+2, NULL);
+          break;
+        case 4:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, mpis+1, mpis+2, mpis+3, NULL);
+          break;
+        case 5:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, mpis+1, mpis+2, mpis+3, mpis+4,
+                                         NULL);
+          break;
+        case 6:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, mpis+1, mpis+2, mpis+3, mpis+4,
+                                         mpis+5, NULL);
+          break;
+        case 7:
+          err = gcry_sexp_extract_param (sxp, tests[idx].path, tests[idx].list,
+                                         mpis+0, mpis+1, mpis+2, mpis+3, mpis+4,
+                                         mpis+5, mpis+6, NULL);
+          break;
+        default:
+          die ("test %d: internal error", idx);
+        }
+
+      if (tests[idx].expected_err
+          && tests[idx].expected_err != GPG_ERR_USER_1)
+        {
+          if (tests[idx].expected_err != gpg_err_code (err))
+            fail ("gcry_sexp_extract_param test %d failed: "
+                  "expected error '%s' - got '%s'", idx,
+                  gpg_strerror (tests[idx].expected_err),gpg_strerror (err));
+
+        }
+      else if (err)
+        {
+          fail ("gcry_sexp_extract_param test %d failed: %s",
+                idx, gpg_strerror (err));
+        }
+      else /* No error - check the extracted values.  */
+        {
+          for (paramidx=0; paramidx < DIM (mpis); paramidx++)
+            {
+              switch (paramidx)
+                {
+                case 0: paramstr = tests[idx].exp_p; break;
+                case 1: paramstr = tests[idx].exp_a; break;
+                case 2: paramstr = tests[idx].exp_b; break;
+                case 3: paramstr = tests[idx].exp_g; break;
+                case 4: paramstr = tests[idx].exp_n; break;
+                case 5: paramstr = tests[idx].exp_q; break;
+                case 6: paramstr = tests[idx].exp_d; break;
+                default:
+                  die ("test %d: internal error: bad param %d",
+                       idx, paramidx);
+                }
+
+              if (tests[idx].expected_err == GPG_ERR_USER_1
+                  && mpis[paramidx] && !paramstr && paramidx == 0)
+                ; /* Okay  Special case error for param 0.  */
+              else if (!mpis[paramidx] && !paramstr)
+                ; /* Okay.  */
+              else if (!mpis[paramidx] && paramstr)
+                fail ("test %d: value for param %d expected but not returned",
+                      idx, paramidx);
+              else if (mpis[paramidx] && !paramstr)
+                fail ("test %d: value for param %d not expected",
+                      idx, paramidx);
+              else if (cmp_mpihex (mpis[paramidx], paramstr))
+                {
+                  fail ("test %d: param %d mismatch", idx, paramidx);
+                  gcry_log_debug    ("expected: %s\n", paramstr);
+                  gcry_log_debugmpi ("     got", mpis[paramidx]);
+                }
+              else if (tests[idx].expected_err && paramidx == 0)
+                fail ("test %d: param %d: expected error '%s' - got 'Success'",
+                      idx, paramidx, gpg_strerror (tests[idx].expected_err));
+            }
+
+        }
+
+      for (i=0; i < DIM (mpis); i++)
+        gcry_mpi_release (mpis[i]);
+      gcry_sexp_release (sxp);
+    }
+
+  info ("checking gcry_sexp_extract_param/desc\n");
+
+  memset (ioarray, 0, sizeof ioarray);
+
+  err = gcry_sexp_new (&sxp, sample1, 0, 1);
+  if (err)
+    die ("converting string to sexp failed: %s", gpg_strerror (err));
+
+  ioarray[1].size = sizeof iobuffer;
+  ioarray[1].data = iobuffer;
+  ioarray[1].off  = 0;
+  ioarray[2].size = sizeof iobuffer;
+  ioarray[2].data = iobuffer;
+  ioarray[2].off  = 50;
+  assert (ioarray[2].off < sizeof iobuffer);
+  err = gcry_sexp_extract_param (sxp, "key-data!private-key", "&pab",
+                                 ioarray+0, ioarray+1, ioarray+2, NULL);
+  if (err)
+    fail ("gcry_sexp_extract_param with desc failed: %s", gpg_strerror (err));
+  else
+    {
+      if (!ioarray[0].data)
+        fail ("gcry_sexp_extract_param/desc failed: no P");
+      else if (ioarray[0].size != 32)
+        fail ("gcry_sexp_extract_param/desc failed: P has wrong size");
+      else if (ioarray[0].len != 32)
+        fail ("gcry_sexp_extract_param/desc failed: P has wrong length");
+      else if (ioarray[0].off)
+        fail ("gcry_sexp_extract_param/desc failed: P has OFF set");
+      else if (cmp_bufhex (ioarray[0].data, ioarray[0].len, sample1_p))
+        {
+          fail ("gcry_sexp_extract_param/desc failed: P mismatch");
+          gcry_log_debug    ("expected: %s\n", sample1_p);
+          gcry_log_debughex ("     got", ioarray[0].data, ioarray[0].len);
+        }
+
+      if (!ioarray[1].data)
+        fail ("gcry_sexp_extract_param/desc failed: A buffer lost");
+      else if (ioarray[1].size != sizeof iobuffer)
+        fail ("gcry_sexp_extract_param/desc failed: A size changed");
+      else if (ioarray[1].off != 0)
+        fail ("gcry_sexp_extract_param/desc failed: A off changed");
+      else if (ioarray[1].len != 1)
+        fail ("gcry_sexp_extract_param/desc failed: A has wrong length");
+      else if (cmp_bufhex (ioarray[1].data + ioarray[1].off, ioarray[1].len,
+                           sample1_a))
+        {
+          fail ("gcry_sexp_extract_param/desc failed: A mismatch");
+          gcry_log_debug    ("expected: %s\n", sample1_a);
+          gcry_log_debughex ("     got",
+                             ioarray[1].data + ioarray[1].off, ioarray[1].len);
+        }
+
+      if (!ioarray[2].data)
+        fail ("gcry_sexp_extract_param/desc failed: B buffer lost");
+      else if (ioarray[2].size != sizeof iobuffer)
+        fail ("gcry_sexp_extract_param/desc failed: B size changed");
+      else if (ioarray[2].off != 50)
+        fail ("gcry_sexp_extract_param/desc failed: B off changed");
+      else if (ioarray[2].len != 32)
+        fail ("gcry_sexp_extract_param/desc failed: B has wrong length");
+      else if (cmp_bufhex (ioarray[2].data + ioarray[2].off, ioarray[2].len,
+                           sample1_b))
+        {
+          fail ("gcry_sexp_extract_param/desc failed: B mismatch");
+          gcry_log_debug    ("expected: %s\n", sample1_b);
+          gcry_log_debughex ("     got",
+                             ioarray[2].data + ioarray[2].off, ioarray[2].len);
+        }
+
+      xfree (ioarray[0].data);
+    }
+
+  gcry_sexp_release (sxp);
+}
 
 
 int
@@ -472,6 +981,7 @@ main (int argc, char **argv)
   canon_len ();
   back_and_forth ();
   check_sscan ();
+  check_extract_param ();
 
   return error_count? 1:0;
 }

-----------------------------------------------------------------------

Summary of changes:
 NEWS                     |    5 +-
 cipher/dsa.c             |   16 +-
 cipher/ecc-curves.c      |    6 +-
 cipher/ecc-misc.c        |    1 +
 cipher/ecc.c             |   38 ++--
 cipher/elgamal.c         |   27 +--
 cipher/pubkey-internal.h |    3 -
 cipher/pubkey-util.c     |  113 ----------
 cipher/rsa.c             |   26 +--
 doc/gcrypt.texi          |   60 ++++++
 src/g10lib.h             |   13 +-
 src/gcrypt.h.in          |   15 +-
 src/libgcrypt.def        |    3 +
 src/libgcrypt.vers       |    2 +-
 src/sexp.c               |  235 +++++++++++++++++++++
 src/visibility.c         |   15 ++
 src/visibility.h         |   13 +-
 tests/tsexp.c            |  516 +++++++++++++++++++++++++++++++++++++++++++++-
 18 files changed, 920 insertions(+), 187 deletions(-)


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org


_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits




More information about the Gcrypt-devel mailing list