pubkey: Move sexp parsing for gcry_pk_get_nbits to the modules.
authorWerner Koch <wk@gnupg.org>
Tue, 8 Oct 2013 18:51:39 +0000 (20:51 +0200)
committerWerner Koch <wk@gnupg.org>
Tue, 8 Oct 2013 18:51:39 +0000 (20:51 +0200)
* cipher/pubkey.c (spec_from_sexp): New.
(gcry_pk_get_nbits): Simplify.
* cipher/rsa.c (rsa_get_nbits): Take only PARMS as args and do sexp
parsing here.
* cipher/dsa.c (dsa_get_nbits): Ditto.
* cipher/elgamal.c (elg_get_nbits): Ditto.
* cipher/ecc.c (ecc_get_nbits): Ditto.
* cipher/ecc-curves.c (_gcry_ecc_fill_in_curve): Allow NULL for arg
CURVE.
--

gcry_pk_get_nbits should now also be faster for ECC because there is
no more need to copy all the parms if a curve name has been given.

Signed-off-by: Werner Koch <wk@gnupg.org>
cipher/dsa.c
cipher/ecc-curves.c
cipher/ecc.c
cipher/elgamal.c
cipher/pubkey.c
cipher/rsa.c
src/cipher-proto.h

index 136d64f..d319f73 100644 (file)
@@ -1029,12 +1029,34 @@ dsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
 }
 
 
+/* Return the number of bits for the key described by PARMS.  On error
+ * 0 is returned.  The format of PARMS starts with the algorithm name;
+ * for example:
+ *
+ *   (dsa
+ *     (p <mpi>)
+ *     (q <mpi>)
+ *     (g <mpi>)
+ *     (y <mpi>))
+ *
+ * More parameters may be given but we only need P here.
+ */
 static unsigned int
-dsa_get_nbits (int algo, gcry_mpi_t *pkey)
+dsa_get_nbits (gcry_sexp_t parms)
 {
-  (void)algo;
+  gcry_sexp_t l1;
+  gcry_mpi_t p;
+  unsigned int nbits;
+
+  l1 = gcry_sexp_find_token (parms, "p", 1);
+  if (!l1)
+    return 0; /* Parameter P not found.  */
 
-  return mpi_get_nbits (pkey[0]);
+  p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l1);
+  nbits = p? mpi_get_nbits (p) : 0;
+  gcry_mpi_release (p);
+  return nbits;
 }
 
 
index 9731deb..449a168 100644 (file)
@@ -306,7 +306,9 @@ scanval (const char *string)
 /* Generate the crypto system setup.  This function takes the NAME of
    a curve or the desired number of bits and stores at R_CURVE the
    parameters of the named curve or those of a suitable curve.  If
-   R_NBITS is not NULL, the chosen number of bits is stored there.  */
+   R_NBITS is not NULL, the chosen number of bits is stored there.
+   NULL may be given for R_CURVE, if the value is not required and for
+   example only a quick test for availability is desired.  */
 gpg_err_code_t
 _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
                          elliptic_curve_t *curve, unsigned int *r_nbits)
@@ -372,16 +374,19 @@ _gcry_ecc_fill_in_curve (unsigned int nbits, const char *name,
   if (r_nbits)
     *r_nbits = domain_parms[idx].nbits;
 
-  curve->model = domain_parms[idx].model;
-  curve->dialect = domain_parms[idx].dialect;
-  curve->p = scanval (domain_parms[idx].p);
-  curve->a = scanval (domain_parms[idx].a);
-  curve->b = scanval (domain_parms[idx].b);
-  curve->n = scanval (domain_parms[idx].n);
-  curve->G.x = scanval (domain_parms[idx].g_x);
-  curve->G.y = scanval (domain_parms[idx].g_y);
-  curve->G.z = mpi_alloc_set_ui (1);
-  curve->name = resname;
+  if (curve)
+    {
+      curve->model = domain_parms[idx].model;
+      curve->dialect = domain_parms[idx].dialect;
+      curve->p = scanval (domain_parms[idx].p);
+      curve->a = scanval (domain_parms[idx].a);
+      curve->b = scanval (domain_parms[idx].b);
+      curve->n = scanval (domain_parms[idx].n);
+      curve->G.x = scanval (domain_parms[idx].g_x);
+      curve->G.y = scanval (domain_parms[idx].g_y);
+      curve->G.z = mpi_alloc_set_ui (1);
+      curve->name = resname;
+    }
 
   return 0;
 }
index eed96eb..e3d397a 100644 (file)
@@ -1836,12 +1836,56 @@ ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data,
 }
 
 
+/* Return the number of bits for the key described by PARMS.  On error
+ * 0 is returned.  The format of PARMS starts with the algorithm name;
+ * for example:
+ *
+ *   (ecc
+ *     (p <mpi>)
+ *     (a <mpi>)
+ *     (b <mpi>)
+ *     (g <mpi>)
+ *     (n <mpi>)
+ *     (q <mpi>))
+ *
+ * More parameters may be given currently P is needed.  FIXME: We
+ * need allow for a "curve" parameter.
+ */
 static unsigned int
-ecc_get_nbits (int algo, gcry_mpi_t *pkey)
+ecc_get_nbits (gcry_sexp_t parms)
 {
-  (void)algo;
+  gcry_sexp_t l1;
+  gcry_mpi_t p;
+  unsigned int nbits = 0;
+  char *curve;
+
+  l1 = gcry_sexp_find_token (parms, "p", 1);
+  if (!l1)
+    { /* Parameter P not found - check whether we have "curve".  */
+      l1 = gcry_sexp_find_token (parms, "curve", 5);
+      if (!l1)
+        return 0; /* Neither P nor CURVE found.  */
+
+      curve = _gcry_sexp_nth_string (l1, 1);
+      gcry_sexp_release (l1);
+      if (!curve)
+        return 0;  /* No curve name given (or out of core). */
 
-  return mpi_get_nbits (pkey[0]);
+      if (_gcry_ecc_fill_in_curve (0, curve, NULL, &nbits))
+        nbits = 0;
+      gcry_free (curve);
+    }
+  else
+    {
+      p = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+      gcry_sexp_release (l1);
+      if (p)
+        {
+          nbits = mpi_get_nbits (p);
+          gcry_mpi_release (p);
+        }
+    }
+  return nbits;
 }
 
 
index 3c8741a..9a74c54 100644 (file)
@@ -912,12 +912,33 @@ elg_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
 }
 
 
+/* Return the number of bits for the key described by PARMS.  On error
+ * 0 is returned.  The format of PARMS starts with the algorithm name;
+ * for example:
+ *
+ *   (dsa
+ *     (p <mpi>)
+ *     (g <mpi>)
+ *     (y <mpi>))
+ *
+ * More parameters may be given but we only need P here.
+ */
 static unsigned int
-elg_get_nbits (int algo, gcry_mpi_t *pkey)
+elg_get_nbits (gcry_sexp_t parms)
 {
-  (void)algo;
+  gcry_sexp_t l1;
+  gcry_mpi_t p;
+  unsigned int nbits;
+
+  l1 = gcry_sexp_find_token (parms, "p", 1);
+  if (!l1)
+    return 0; /* Parameter P not found.  */
 
-  return mpi_get_nbits (pkey[0]);
+  p= gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l1);
+  nbits = p? mpi_get_nbits (p) : 0;
+  gcry_mpi_release (p);
+  return nbits;
 }
 
 
index 305f53a..cb2177b 100644 (file)
@@ -109,6 +109,65 @@ spec_from_name (const char *name)
 }
 
 
+
+/* Given the s-expression SEXP with the first element be either
+ * "private-key" or "public-key" return the spec structure for it.  We
+ * look through the list to find a list beginning with "private-key"
+ * or "public-key" - the first one found is used.  If WANT_PRIVATE is
+ * set the function will only succeed if a private key has been given.
+ * On success the spec is stored at R_SPEC.  On error NULL is stored
+ * at R_SPEC and an error code returned.  If R_PARMS is not NULL and
+ * the fucntion returns success, the parameter list below
+ * "private-key" or "public-key" is stored there and the caller must
+ * call gcry_sexp_release on it.
+ */
+static gcry_err_code_t
+spec_from_sexp (gcry_sexp_t sexp, int want_private,
+                gcry_pk_spec_t **r_spec, gcry_sexp_t *r_parms)
+{
+  gcry_sexp_t list, l2;
+  char *name;
+  gcry_pk_spec_t *spec;
+
+  *r_spec = NULL;
+
+  /* Check that the first element is valid.  If we are looking for a
+     public key but a private key was supplied, we allow the use of
+     the private key anyway.  The rationale for this is that the
+     private key is a superset of the public key.  */
+  list = gcry_sexp_find_token (sexp,
+                               want_private? "private-key":"public-key", 0);
+  if (!list && !want_private)
+    list = gcry_sexp_find_token (sexp, "private-key", 0);
+  if (!list)
+    return GPG_ERR_INV_OBJ; /* Does not contain a key object.  */
+
+  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. */
+    }
+  spec = spec_from_name (name);
+  gcry_free (name);
+  if (!spec)
+    {
+      gcry_sexp_release (list);
+      return GPG_ERR_PUBKEY_ALGO; /* Unknown algorithm. */
+    }
+  *r_spec = spec;
+  if (r_parms)
+    *r_parms = list;
+  else
+    gcry_sexp_release (list);
+  return 0;
+}
+
+
+
 /* Disable the use of the algorithm ALGO.  This is not thread safe and
    should thus be called early.  */
 static void
@@ -1923,25 +1982,20 @@ unsigned int
 gcry_pk_get_nbits (gcry_sexp_t key)
 {
   gcry_pk_spec_t *spec;
-  gcry_mpi_t *keyarr = NULL;
-  unsigned int nbits = 0;
-  gcry_err_code_t rc;
-
-  /* FIXME: Parsing KEY is often too much overhead.  For example for
-     ECC we would only need to look at P and stop parsing right
-     away.  */
-
-  rc = sexp_to_key (key, 0, 0, NULL, &keyarr, &spec, NULL);
-  if (rc == GPG_ERR_INV_OBJ)
-    rc = sexp_to_key (key, 1, 0, NULL, &keyarr, &spec, NULL);
-  if (rc)
-    return 0; /* Error - 0 is a suitable indication for that. */
+  gcry_sexp_t parms;
+  unsigned int nbits;
 
-  nbits = spec->get_nbits (spec->algo, keyarr);
+  /* Parsing KEY might be considered too much overhead.  For example
+     for RSA we would only need to look at P and stop parsing right
+     away.  However, with ECC things are more complicate in that only
+     a curve name might be specified.  Thus we need to tear the sexp
+     apart. */
 
-  release_mpi_array (keyarr);
-  gcry_free (keyarr);
+  if (spec_from_sexp (key, 0, &spec, &parms))
+    return 0; /* Error - 0 is a suitable indication for that.  */
 
+  nbits = spec->get_nbits (parms);
+  gcry_sexp_release (parms);
   return nbits;
 }
 
index 55f39e4..c400718 100644 (file)
@@ -1087,12 +1087,33 @@ rsa_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey,
 }
 
 
+
+/* Return the number of bits for the key described by PARMS.  On error
+ * 0 is returned.  The format of PARMS starts with the algorithm name;
+ * for example:
+ *
+ *   (rsa
+ *     (n <mpi>)
+ *     (e <mpi>))
+ *
+ * More parameters may be given but we only need N here.
+ */
 static unsigned int
-rsa_get_nbits (int algo, gcry_mpi_t *pkey)
+rsa_get_nbits (gcry_sexp_t parms)
 {
-  (void)algo;
+  gcry_sexp_t l1;
+  gcry_mpi_t n;
+  unsigned int nbits;
 
-  return mpi_get_nbits (pkey[0]);
+  l1 = gcry_sexp_find_token (parms, "n", 1);
+  if (!l1)
+    return 0; /* Parameter N not found.  */
+
+  n = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l1);
+  nbits = n? mpi_get_nbits (n) : 0;
+  gcry_mpi_release (n);
+  return nbits;
 }
 
 
index 1011161..7a54930 100644 (file)
@@ -94,8 +94,7 @@ typedef gcry_err_code_t (*gcry_pk_verify_t) (int algo,
                                              int hashalgo);
 
 /* Type for the pk_get_nbits function.  */
-typedef unsigned (*gcry_pk_get_nbits_t) (int algo,
-                                         gcry_mpi_t *pkey);
+typedef unsigned (*gcry_pk_get_nbits_t) (gcry_sexp_t keyparms);
 
 
 /* The type used to compute the keygrip.  */