Add gcry_pk_get_curve.
authorWerner Koch <wk@gnupg.org>
Tue, 1 Feb 2011 09:40:50 +0000 (10:40 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 1 Feb 2011 09:40:50 +0000 (10:40 +0100)
14 files changed:
NEWS
cipher/ChangeLog
cipher/ecc.c
cipher/pubkey.c
src/ChangeLog
src/cipher-proto.h
src/gcrypt.h.in
src/libgcrypt.def
src/libgcrypt.vers
src/visibility.c
src/visibility.h
tests/ChangeLog
tests/Makefile.am
tests/curves.c [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 48b2e06..382927e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -22,12 +22,15 @@ Noteworthy changes in version 1.5.x (unreleased)
 
  * gcry_sexp_build does now support opaque MPIs with "%m".
 
+ * New function gcry_pk_get_curve to map ECC parameters to a curve name.
+
  * Interface changes relative to the 1.4.2 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  GCRY_CIPHER_MODE_AESWRAP   NEW.
  GCRY_PK_ECDH               NEW.
  GCRY_MD_TIGER1             NEW.
  GCRY_MD_TIGER2             NEW.
+ gcry_pk_get_curve          NEW.
 
 
 Noteworthy changes in version 1.4.4 (2009-01-22)
index 0f33f7a..a32d543 100644 (file)
@@ -1,3 +1,8 @@
+2011-02-01  Werner Koch  <wk@g10code.com>
+
+       * pubkey.c (gcry_pk_get_curve): New.
+       * ecc.c (ecc_get_curve): New.
+
 2011-01-31  Werner Koch  <wk@g10code.com>
 
        * ecc.c (ecc_encrypt_raw, ecc_decrypt_raw): Do not free passed
index 8b60895..215fcfb 100644 (file)
@@ -1107,6 +1107,90 @@ ecc_get_param (const char *name, gcry_mpi_t *pkey)
 }
 
 
+/* Return the name matching the parameters in PKEY.  */
+static const char *
+ecc_get_curve (gcry_mpi_t *pkey, int iterator, unsigned int *r_nbits)
+{
+  gpg_err_code_t err;
+  elliptic_curve_t E;
+  int idx;
+  gcry_mpi_t tmp;
+  const char *result = NULL;
+
+  if (r_nbits)
+    *r_nbits = 0;
+
+  if (!pkey)
+    {
+      idx = iterator;
+      if (idx >= 0 && idx < DIM (domain_parms))
+        {
+          result = domain_parms[idx].desc;
+          if (r_nbits)
+            *r_nbits = domain_parms[idx].nbits;
+        }
+      return result;
+    }
+
+  if (!pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4])
+    return NULL;
+
+  E.p = pkey[0];
+  E.a = pkey[1];
+  E.b = pkey[2];
+  point_init (&E.G);
+  err = os2ec (&E.G, pkey[3]);
+  if (err)
+    {
+      point_free (&E.G);
+      return NULL;
+    }
+  E.n = pkey[4];
+
+  for (idx = 0; domain_parms[idx].desc; idx++)
+    {
+      tmp = scanval (domain_parms[idx].p);
+      if (!mpi_cmp (tmp, E.p))
+        {
+          mpi_free (tmp);
+          tmp = scanval (domain_parms[idx].a);
+          if (!mpi_cmp (tmp, E.a))
+            {
+              mpi_free (tmp);
+              tmp = scanval (domain_parms[idx].b);
+              if (!mpi_cmp (tmp, E.b))
+                {
+                  mpi_free (tmp);
+                  tmp = scanval (domain_parms[idx].n);
+                  if (!mpi_cmp (tmp, E.n))
+                    {
+                      mpi_free (tmp);
+                      tmp = scanval (domain_parms[idx].g_x);
+                      if (!mpi_cmp (tmp, E.G.x))
+                        {
+                          mpi_free (tmp);
+                          tmp = scanval (domain_parms[idx].g_y);
+                          if (!mpi_cmp (tmp, E.G.y))
+                            {
+                              result = domain_parms[idx].desc;
+                              if (r_nbits)
+                                *r_nbits = domain_parms[idx].nbits;
+                              break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+      mpi_free (tmp);
+    }
+
+  point_free (&E.G);
+
+  return result;
+}
+
+
 static gcry_err_code_t
 ecc_check_secret_key (int algo, gcry_mpi_t *skey)
 {
@@ -1674,5 +1758,6 @@ pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa =
     run_selftests,
     ecc_generate_ext,
     compute_keygrip,
-    ecc_get_param
+    ecc_get_param,
+    ecc_get_curve
   };
index b2de4e6..b4ac214 100644 (file)
@@ -2482,6 +2482,85 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
 }
 
 
+\f
+const char *
+gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
+{
+  gcry_mpi_t *pkey = NULL;
+  gcry_sexp_t list = NULL;
+  gcry_sexp_t l2;
+  gcry_module_t module = NULL;
+  pk_extra_spec_t *extraspec;
+  char *name = NULL;
+  const char *result = NULL;
+  int want_private = 1;
+
+  if (r_nbits)
+    *r_nbits = 0;
+
+  REGISTER_DEFAULT_PUBKEYS;
+
+  if (key)
+    {
+      iterator = 0;
+
+      /* Check that the first element is valid. */
+      list = gcry_sexp_find_token (key, "public-key", 0);
+      if (list)
+        want_private = 0;
+      if (!list)
+        list = gcry_sexp_find_token (key, "private-key", 0);
+      if (!list)
+        return NULL; /* No public- or private-key object. */
+
+      l2 = gcry_sexp_cadr (list);
+      gcry_sexp_release (list);
+      list = l2;
+      l2 = NULL;
+
+      name = _gcry_sexp_nth_string (list, 0);
+      if (!name)
+        goto leave; /* Invalid structure of object. */
+
+      /* Get the key. */
+      if (sexp_to_key (key, want_private, &pkey, &module))
+        goto leave;
+    }
+  else
+    {
+      ath_mutex_lock (&pubkeys_registered_lock);
+      module = gcry_pk_lookup_name ("ecc");
+      ath_mutex_unlock (&pubkeys_registered_lock);
+      if (!module)
+        goto leave;
+    }
+
+  extraspec = module->extraspec;
+  if (!extraspec || !extraspec->get_curve)
+    goto leave;
+
+  result = extraspec->get_curve (pkey, iterator, r_nbits);
+
+ leave:
+  if (pkey)
+    {
+      release_mpi_array (pkey);
+      gcry_free (pkey);
+    }
+  if (module)
+    {
+      ath_mutex_lock (&pubkeys_registered_lock);
+      _gcry_module_release (module);
+      ath_mutex_unlock (&pubkeys_registered_lock);
+    }
+  gcry_free (name);
+  gcry_sexp_release (list);
+  return result;
+}
+
+
+
+\f
 gcry_error_t
 gcry_pk_ctl (int cmd, void *buffer, size_t buflen)
 {
index f2fbb32..b59f1c1 100644 (file)
@@ -1,3 +1,10 @@
+2011-02-01  Werner Koch  <wk@g10code.com>
+
+       * libgcrypt.vers (gcry_pk_get_curve): Add.
+       * libgcrypt.def (gcry_pk_get_curve): Add.
+       * visibility.c (gcry_pk_get_curve): New.
+       * cipher-proto.h (pk_extra_spec): Add field GET_CURVE.
+
 2011-01-31  Werner Koch  <wk@g10code.com>
 
        * sexp.c (vsexp_sscan): Allow opaque MPIs in "%m".
index 2153236..ea7a70d 100644 (file)
@@ -1,5 +1,5 @@
 /* cipher-proto.h - Internal declarations
- *     Copyright (C) 2008 Free Software Foundation, Inc.
+ *     Copyright (C) 2008, 2011 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -53,10 +53,14 @@ typedef gcry_err_code_t (*pk_ext_generate_t)
 typedef gpg_err_code_t (*pk_comp_keygrip_t)
      (gcry_md_hd_t md, gcry_sexp_t keyparm);
 
-/* The type used to quert ECC curve parameters.  */
+/* The type used to query ECC curve parameters.  */
 typedef gcry_err_code_t (*pk_get_param_t)
      (const char *name, gcry_mpi_t *pkey);
 
+/* The type used to query an ECC curve name.  */
+typedef const char *(*pk_get_curve_t)(gcry_mpi_t *pkey, int iterator,
+                                      unsigned int *r_nbits);
+
 /* The type used to convey additional information to a cipher.  */
 typedef gpg_err_code_t (*cipher_set_extra_info_t)
      (void *c, int what, const void *buffer, size_t buflen);
@@ -82,6 +86,7 @@ typedef struct pk_extra_spec
   pk_ext_generate_t ext_generate;
   pk_comp_keygrip_t comp_keygrip;
   pk_get_param_t get_param;
+  pk_get_curve_t get_curve;
 } pk_extra_spec_t;
 
 
index 9c58b98..2509978 100644 (file)
@@ -1037,6 +1037,10 @@ unsigned int gcry_pk_get_nbits (gcry_sexp_t key) _GCRY_GCC_ATTR_PURE;
    used without contacting the author. */
 unsigned char *gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array);
 
+/* Return the name of the curve matching KEY.  */
+const char *gcry_pk_get_curve (gcry_sexp_t key, int iterator,
+                               unsigned int *r_nbits);
+
 /* Return 0 if the public key algorithm A is available for use. */
 #define gcry_pk_test_algo(a) \
             gcry_pk_algo_info( (a), GCRYCTL_TEST_ALGO, NULL, NULL )
index 8fc4d32..55ff877 100644 (file)
@@ -230,8 +230,7 @@ EXPORTS
       gcry_cipher_setkey    @188
       gcry_cipher_setiv     @189
       gcry_cipher_setctr    @190
-      
-      gcry_mpi_lshift       @191
-  
 
+      gcry_mpi_lshift       @191
 
+      gcry_pk_get_curve     @192
index ef9fcee..4670436 100644 (file)
@@ -57,6 +57,7 @@ GCRYPT_1.2 {
     gcry_pk_get_keygrip; gcry_pk_get_nbits; gcry_pk_list;
     gcry_pk_map_name; gcry_pk_register; gcry_pk_sign;
     gcry_pk_testkey; gcry_pk_unregister; gcry_pk_verify;
+    gcry_pk_get_curve;
 
     gcry_ac_data_new; gcry_ac_data_destroy; gcry_ac_data_copy;
     gcry_ac_data_length; gcry_ac_data_clear; gcry_ac_data_set;
index f187a65..fe6d9bd 100644 (file)
@@ -1,5 +1,5 @@
 /* visibility.c - Wrapper for all public functions.
- * Copyright (C) 2007, 2008  Free Software Foundation, Inc.
+ * Copyright (C) 2007, 2008, 2011  Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -737,6 +737,17 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
   return _gcry_pk_get_keygrip (key, array);
 }
 
+const char *
+gcry_pk_get_curve (gcry_sexp_t key, int iterator, unsigned int *r_nbits)
+{
+  if (!fips_is_operational ())
+    {
+      (void)fips_not_operational ();
+      return NULL;
+    }
+  return _gcry_pk_get_curve (key, iterator, r_nbits);
+}
+
 gcry_error_t
 gcry_pk_list (int *list, int *list_length)
 {
index a11e547..0b0219d 100644 (file)
 #define gcry_pk_encrypt             _gcry_pk_encrypt
 #define gcry_pk_genkey              _gcry_pk_genkey
 #define gcry_pk_get_keygrip         _gcry_pk_get_keygrip
+#define gcry_pk_get_curve           _gcry_pk_get_curve
 #define gcry_pk_get_nbits           _gcry_pk_get_nbits
 #define gcry_pk_list                _gcry_pk_list
 #define gcry_pk_map_name            _gcry_pk_map_name
@@ -358,6 +359,7 @@ void gcry_ac_os_to_mpi (gcry_mpi_t mpi, unsigned char *os, size_t os_n);
 #undef gcry_pk_encrypt            
 #undef gcry_pk_genkey             
 #undef gcry_pk_get_keygrip        
+#undef gcry_pk_get_curve
 #undef gcry_pk_get_nbits          
 #undef gcry_pk_list               
 #undef gcry_pk_map_name           
@@ -568,6 +570,7 @@ MARK_VISIBLE (gcry_pk_decrypt)
 MARK_VISIBLE (gcry_pk_encrypt)
 MARK_VISIBLE (gcry_pk_genkey)
 MARK_VISIBLE (gcry_pk_get_keygrip)
+MARK_VISIBLE (gcry_pk_get_curve)
 MARK_VISIBLE (gcry_pk_get_nbits)
 MARK_VISIBLE (gcry_pk_list)
 MARK_VISIBLE (gcry_pk_map_name)
index 64bad3e..1836d0e 100644 (file)
@@ -1,3 +1,7 @@
+2011-02-01  Werner Koch  <wk@g10code.com>
+
+       * curves.c: New.
+
 2011-01-04  Werner Koch  <wk@g10code.com>
 
        * Makefile.am (LDADD): Fix typo in last change.  Reported by
index 59cc5c4..bf26f68 100644 (file)
@@ -19,7 +19,8 @@
 ## Process this file with automake to produce Makefile.in
 
 TESTS = version t-mpi-bit prime register ac ac-schemes ac-data basic \
-        mpitests tsexp keygen pubkey hmac keygrip fips186-dsa aeswrap
+        mpitests tsexp keygen pubkey hmac keygrip fips186-dsa aeswrap \
+       curves
 
 
 # random.c uses fork() thus a test for W32 does not make any sense.
diff --git a/tests/curves.c b/tests/curves.c
new file mode 100644 (file)
index 0000000..dcf501a
--- /dev/null
@@ -0,0 +1,175 @@
+/* curves.c -  ECC curves regression tests
+ *     Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "../src/gcrypt.h"
+
+/* Number of curves defined in ../cipger/ecc.c */
+#define N_CURVES 12
+
+/* A real world sample public key.  */
+static char const sample_key_1[] =
+"(public-key\n"
+" (ecdsa\n"
+"  (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)\n"
+"  (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)\n"
+"  (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)\n"
+"  (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
+        "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)\n"
+"  (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)\n"
+"  (q #0442B927242237639A36CE9221B340DB1A9AB76DF2FE3E171277F6A4023DED146EE"
+      "86525E38CCECFF3FB8D152CC6334F70D23A525175C1BCBDDE6E023B2228770E#)\n"
+"  ))";
+static char const sample_key_1_curve[] = "NIST P-256";
+static unsigned int sample_key_1_nbits = 256;
+
+/* A made up sample public key.  */
+static char const sample_key_2[] =
+"(public-key\n"
+" (ecdh\n"
+"  (p #e95e4a5f737059dc60dfc7ad95b3d8139515620f#)\n"
+"  (a #340e7be2a280eb74e2be61bada745d97e8f7c300#)\n"
+"  (b #1e589a8595423412134faa2dbdec95c8d8675e58#)\n"
+"  (g #04bed5af16ea3f6a4f62938c4631eb5af7bdbcdbc3"
+        "1667cb477a1a8ec338f94741669c976316da6321#)\n"
+"  (n #e95e4a5f737059dc60df5991d45029409e60fc09#)\n"
+"  (q #041111111111111111111111111111111111111111"
+        "2222222222222222222222222222222222222222#)\n"
+"  ))";
+static char const sample_key_2_curve[] = "brainpoolP160r1";
+static unsigned int sample_key_2_nbits = 160;
+
+
+/* Program option flags.  */
+static int verbose;
+static int error_count;
+
+static void
+fail (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  error_count++;
+}
+
+static void
+die (const char *format, ...)
+{
+  va_list arg_ptr;
+
+  va_start (arg_ptr, format);
+  vfprintf (stderr, format, arg_ptr);
+  va_end (arg_ptr);
+  exit (1);
+}
+
+
+static void
+list_curves (void)
+{
+  int idx;
+  const char *name;
+  unsigned int nbits;
+
+  for (idx=0; (name = gcry_pk_get_curve (NULL, idx, &nbits)); idx++)
+    {
+      if (verbose)
+        printf ("%s - %u bits\n", name, nbits);
+    }
+  if (idx != N_CURVES)
+    fail ("expected %d curves but got %d\n", N_CURVES, idx);
+  if (gcry_pk_get_curve (NULL, -1, NULL))
+    fail ("curve iteration failed\n");
+}
+
+
+static void
+check_matching (void)
+{
+  gpg_error_t err;
+  gcry_sexp_t key;
+  const char *name;
+  unsigned int nbits;
+
+  err = gcry_sexp_new (&key, sample_key_1, 0, 1);
+  if (err)
+    die ("parsing s-expression string failed: %s\n", gpg_strerror (err));
+  name = gcry_pk_get_curve (key, 0, &nbits);
+  if (!name)
+    fail ("curve name not found for sample_key_1\n");
+  else if (strcmp (name, sample_key_1_curve))
+    fail ("expected curve name %s but got %s for sample_key_1\n",
+          sample_key_1_curve, name);
+  else if (nbits != sample_key_1_nbits)
+    fail ("expected curve size %u but got %u for sample_key_1\n",
+          sample_key_1_nbits, nbits);
+
+  gcry_sexp_release (key);
+
+  err = gcry_sexp_new (&key, sample_key_2, 0, 1);
+  if (err)
+    die ("parsing s-expression string failed: %s\n", gpg_strerror (err));
+  name = gcry_pk_get_curve (key, 0, &nbits);
+  if (!name)
+    fail ("curve name not found for sample_key_2\n");
+  else if (strcmp (name, sample_key_2_curve))
+    fail ("expected curve name %s but got %s for sample_key_2\n",
+          sample_key_2_curve, name);
+  else if (nbits != sample_key_2_nbits)
+    fail ("expected curve size %u but got %u for sample_key_2\n",
+          sample_key_2_nbits, nbits);
+
+  gcry_sexp_release (key);
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  int debug = 0;
+
+  if (argc > 1 && !strcmp (argv[1], "--verbose"))
+    verbose = 1;
+  else if (argc > 1 && !strcmp (argv[1], "--debug"))
+    verbose = debug = 1;
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    die ("version mismatch\n");
+  
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+  list_curves ();
+  check_matching ();
+  
+  return error_count ? 1 : 0;
+}