Overhauled the keygrip computation.
authorWerner Koch <wk@gnupg.org>
Fri, 29 Aug 2008 15:40:24 +0000 (15:40 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 29 Aug 2008 15:40:24 +0000 (15:40 +0000)
12 files changed:
TODO
cipher/ChangeLog
cipher/ecc.c
cipher/pubkey.c
cipher/rsa.c
doc/gcrypt.texi
mpi/mpicoder.c
src/ChangeLog
src/cipher-proto.h
src/fips.c
tests/ChangeLog
tests/keygrip.c

diff --git a/TODO b/TODO
index 4331027..1d61390 100644 (file)
--- a/TODO
+++ b/TODO
@@ -12,10 +12,6 @@ What's left to do                                 -*- outline -*-
   This requires the introduction of a parameter names (say) U which
   is calculated according to OpenSSL/PKCS#1 rules.
 
-* Add a warning to the manual, to check that libgcrypt actually has
-  been compiled with thread support when used by a threaded
-  application.
-
 * linker script test
   Write an autoconf test to check whether the linker supports a
   version script. 
@@ -97,5 +93,3 @@ What's left to do                                 -*- outline -*-
 ** C++ tests
   We have some code to allow using libgcrypt from C++, so we also
   should have a test case.
-
-* The prime generator always uses very-strong-random. 
index 28fdf07..a026bad 100644 (file)
@@ -1,3 +1,12 @@
+2008-08-29  Werner Koch  <wk@g10code.com>
+
+       * pubkey.c (gcry_pk_get_keygrip): Remove the special case for RSA
+       and check whether a custom computation function has been setup.
+       * rsa.c (compute_keygrip): New.
+       (_gcry_pubkey_extraspec_rsa): Setup this function.
+       * ecc.c (compute_keygrip): New.
+       (_gcry_pubkey_extraspec_ecdsa): Setup this function.
+
 2008-08-28  Werner Koch  <wk@g10code.com>
 
        * cipher.c (cipher_decrypt, cipher_encrypt): Return an error if
index c75fd4e..5d5c322 100644 (file)
@@ -1182,6 +1182,110 @@ ecc_get_nbits (int algo, gcry_mpi_t *pkey)
 }
 
 
+
+/* See rsa.c for a description of this function.  */
+static gpg_err_code_t
+compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
+{
+  gpg_err_code_t ec = 0;
+  gcry_sexp_t l1;
+  static const char const names[] = "pabgnq";
+  gcry_mpi_t values[6];
+  int idx;
+
+  /* Clear the values for easier error cleanup.  */
+  for (idx=0; idx < 6; idx++)
+    values[idx] = NULL;
+    
+  /* Fill values with all available parameters.  */
+  for (idx=0; idx < 6; idx++)
+    {
+      l1 = gcry_sexp_find_token (keyparam, names+idx, 1);
+      if (l1)
+        {
+          values[idx] = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG);
+         gcry_sexp_release (l1);
+         if (!values[idx])
+            {
+              ec = GPG_ERR_INV_OBJ;
+              goto leave;
+            }
+       }
+    }
+  
+  /* Check whether a curve parameter is available and use that to fill
+     in missing values.  */
+  l1 = gcry_sexp_find_token (keyparam, "curve", 5);
+  if (l1)
+    {
+      char *curve;
+      gcry_mpi_t tmpvalues[6];
+      
+      for (idx = 0; idx < 6; idx++)
+        tmpvalues[idx] = NULL;
+
+      curve = _gcry_sexp_nth_string (l1, 1);
+      if (!curve)
+        {
+          ec = GPG_ERR_INV_OBJ; /* Name missing or out of core. */
+          goto leave;
+        }
+      ec = _gcry_ecc_get_param (curve, tmpvalues);
+      gcry_free (curve);
+      if (ec)
+        goto leave;
+
+      for (idx = 0; idx < 6; idx++)
+        {
+          if (!values[idx])
+            values[idx] = tmpvalues[idx];
+          else
+            mpi_free (tmpvalues[idx]);
+        }
+    }
+
+  /* Check that all parameters are known and normalize all MPIs (that
+     should not be required but we use an internal fucntion later and
+     thus we better make 100% sure that they are normalized). */
+  for (idx = 0; idx < 6; idx++)
+    if (!values[idx])
+      {
+        ec = GPG_ERR_NO_OBJ;
+        goto leave;
+      }
+    else
+      _gcry_mpi_normalize (values[idx]);
+      
+  /* Hash them all.  */
+  for (idx = 0; idx < 6; idx++)
+    {
+      char buf[30];
+      unsigned char *rawmpi;
+      unsigned int rawmpilen;
+      
+      rawmpi = _gcry_mpi_get_buffer (values[idx], &rawmpilen, NULL);
+      if (!rawmpi)
+        {
+          ec = gpg_err_code_from_syserror ();
+          goto leave;
+        }
+      snprintf (buf, sizeof buf, "(1:%c%u:", names[idx], rawmpilen);
+      gcry_md_write (md, buf, strlen (buf));
+      gcry_md_write (md, rawmpi, rawmpilen);
+      gcry_md_write (md, ")", 1);
+      gcry_free (rawmpi);
+    }
+
+ leave:
+  for (idx = 0; idx < 6; idx++)
+    _gcry_mpi_release (values[idx]);
+  
+  return ec;
+}
+
+
+
+
 \f
 /* 
      Self-test section.
@@ -1254,6 +1358,8 @@ gcry_pk_spec_t _gcry_pubkey_spec_ecdsa =
   };
 pk_extra_spec_t _gcry_pubkey_extraspec_ecdsa = 
   {
-    run_selftests
+    run_selftests,
+    NULL,
+    compute_keygrip
   };
 
index 8c35390..74a40cc 100644 (file)
@@ -878,7 +878,7 @@ sexp_elements_extract_ecc (gcry_sexp_t key_sexp, const char *element_names,
   const char *name;
   gcry_sexp_t list;
 
-  /* Clear the array for easir error cleanup. */
+  /* Clear the array for easier error cleanup. */
   for (name = element_names, idx = 0; *name; name++, idx++)
     elements[idx] = NULL;
   gcry_assert (idx >= 6); /* We know that ECC has at least 6 elements.  */
@@ -2432,10 +2432,10 @@ 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;
+  pk_extra_spec_t *extraspec;
   const char *s;
   char *name = NULL;
   int idx;
-  int is_rsa;
   const char *elems;
   gcry_md_hd_t md = NULL;
 
@@ -2469,53 +2469,45 @@ gcry_pk_get_keygrip (gcry_sexp_t key, unsigned char *array)
     goto fail; /* Unknown algorithm.  */
 
   pubkey = (gcry_pk_spec_t *) module->spec;
+  extraspec = module->extraspec;
 
-  /* FIXME, special handling should be implemented by the algorithms,
-     not by the libgcrypt core.  */
-  is_rsa = module->mod_id == GCRY_PK_RSA;
   elems = pubkey->elements_grip;
-  if (! elems)
+  if (!elems)
     goto fail; /* No grip parameter.  */
     
   if (gcry_md_open (&md, GCRY_MD_SHA1, 0))
     goto fail;
 
-#if USE_ECC
-# ifdef __GNUC__
-#  warning needs to be fixed for ECC.
-# endif
-#endif
-
-  for (idx = 0, s = elems; *s; s++, idx++)
+  if (extraspec && extraspec->comp_keygrip)
     {
-      const char *data;
-      size_t datalen;
-
-      l2 = gcry_sexp_find_token (list, s, 1);
-      if (! l2)
-        goto fail;
-      data = gcry_sexp_nth_data (l2, 1, &datalen);
-      if (! data)
+      /* Module specific method to compute a keygrip.  */
+      if (extraspec->comp_keygrip (md, list))
         goto fail;
-      if (!is_rsa)
+    }
+  else
+    {
+      /* Generic method to compute a keygrip.  */
+      for (idx = 0, s = elems; *s; s++, idx++)
         {
+          const char *data;
+          size_t datalen;
           char buf[30];
-
-          sprintf (buf, "(1:%c%u:", *s, (unsigned int)datalen);
+          
+          l2 = gcry_sexp_find_token (list, s, 1);
+          if (! l2)
+            goto fail;
+          data = gcry_sexp_nth_data (l2, 1, &datalen);
+          if (! data)
+            goto fail;
+          
+          snprintf (buf, sizeof buf, "(1:%c%u:", *s, (unsigned int)datalen);
           gcry_md_write (md, buf, strlen (buf));
+          gcry_md_write (md, data, datalen);
+          gcry_sexp_release (l2);
+          gcry_md_write (md, ")", 1);
         }
-  
-      /* PKCS-15 says that for RSA only the modulus should be hashed -
-         however, it is not clear wether this is meant to use the raw
-         bytes (assuming this is an unsigned integer) or whether the DER
-         required 0 should be prefixed. We hash the raw bytes.  For
-         non-RSA we hash S-expressions. */
-      gcry_md_write (md, data, datalen);
-      gcry_sexp_release (l2);
-      if (!is_rsa)
-        gcry_md_write (md, ")", 1);
     }
-
+  
   if (!array)
     {
       array = gcry_malloc (20);
index 8ca8f31..9a7b94d 100644 (file)
@@ -686,6 +686,44 @@ _gcry_rsa_get_nbits (int algo, gcry_mpi_t *pkey)
 }
 
 
+/* Compute a keygrip.  MD is the hash context which we are going to
+   update.  KEYPARAM is an S-expression with the key parameters, this
+   is usually a public key but may also be a secret key.  An example
+   of such an S-expression is:
+
+      (rsa
+        (n #00B...#)
+        (e #010001#))
+        
+   PKCS-15 says that for RSA only the modulus should be hashed -
+   however, it is not clear wether this is meant to use the raw bytes
+   (assuming this is an unsigned integer) or whether the DER required
+   0 should be prefixed.  We hash the raw bytes.  */
+static gpg_err_code_t
+compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam)
+{
+  gcry_sexp_t l1;
+  const char *data;
+  size_t datalen;
+
+  l1 = gcry_sexp_find_token (keyparam, "n", 1);
+  if (!l1)
+    return GPG_ERR_NO_OBJ;
+
+  data = gcry_sexp_nth_data (l1, 1, &datalen);
+  if (!data)
+    {
+      gcry_sexp_release (l1);
+      return GPG_ERR_NO_OBJ;
+    }
+
+  gcry_md_write (md, data, datalen);
+  gcry_sexp_release (l1);
+
+  return 0;
+}
+
+
 
 \f
 /* 
@@ -761,6 +799,7 @@ gcry_pk_spec_t _gcry_pubkey_spec_rsa =
 pk_extra_spec_t _gcry_pubkey_extraspec_rsa = 
   {
     run_selftests,
-    rsa_generate
+    rsa_generate,
+    compute_keygrip
   };
 
index b3daa07..55fae68 100644 (file)
@@ -529,10 +529,10 @@ Libgcrypt into this mode:
 
 @itemize
 @item 
-If the file @file{/proc/fips140} exists and contains the string value
-@code{1}, Libgcrypt is put into FIPS mode at initialization time.
-Obviously this works only on systems with a @code{proc} file system
-(ie.e GNU/Linux).
+If the file @file{/proc/sys/crypto/fips_enabled} exists and contains a
+numeric value other than @code{0}, Libgcrypt is put into FIPS mode at
+initialization time.  Obviously this works only on systems with a
+@code{proc} file system (ie.e GNU/Linux).
 
 @item 
 If the file @file{/etc/gcrypt/fips140.force} exists, Libgcrypt is put
index 0c19941..d8f860c 100644 (file)
@@ -247,8 +247,8 @@ do_get_buffer( gcry_mpi_t a, unsigned *nbytes, int *sign, int force_secure )
 #endif
     }
 
-    /* this is sub-optimal but we need to do the shift oepration because
-     * the caller has to free the returned buffer */
+    /* This is sub-optimal but we need to do the shift operation
+       because the caller has to free the returned buffer */
     for(p=buffer; !*p && *nbytes; p++, --*nbytes )
        ;
     if( p != buffer )
index d72ef54..be3cc2e 100644 (file)
@@ -1,3 +1,11 @@
+2008-08-29  Werner Koch  <wk@g10code.com>
+
+       * fips.c (_gcry_initialize_fips_mode): Changed /proc file to test
+       for FIPS mode.
+
+       * cipher-proto.h (pk_compute_keygrip_t): New.
+       (pk_extra_spec): Add field comp_keygrip.
+
 2008-08-28  Werner Koch  <wk@g10code.com>
 
        * hwfeatures.c (_gcry_detect_hw_features): Disable hardware
index 4ca76b5..39a9101 100644 (file)
@@ -48,6 +48,10 @@ typedef gcry_err_code_t (*pk_ext_generate_t)
       gcry_mpi_t *skey,
       gcry_mpi_t **retfactors);
 
+/* The type is used to compute the keygrip.  */
+typedef gpg_err_code_t (*pk_comp_keygrip_t)
+     (gcry_md_hd_t md, gcry_sexp_t keyparm);
+
 
 /* Extra module specification structures.  These are used for internal
    modules which provide more functions than available through the
@@ -66,6 +70,7 @@ typedef struct pk_extra_spec
 {
   selftest_func_t selftest;
   pk_ext_generate_t ext_generate;
+  pk_comp_keygrip_t comp_keygrip;
 } pk_extra_spec_t;
 
 
index c9f29bd..04b34d8 100644 (file)
@@ -115,13 +115,14 @@ _gcry_initialize_fips_mode (int force)
   {
     FILE *fp;
     int saved_errno;
+    static const char const procfname[] = "/proc/sys/crypto/fips_enabled";
 
-    fp = fopen ("/proc/fips140", "r");
+    fp = fopen (procfname, "r");
     if (fp)
       {
         char line[256];
         
-        if (fgets (line, sizeof line, fp) && atoi (line) == 1)
+        if (fgets (line, sizeof line, fp) && atoi (line))
           {
             /* System is in fips mode.  */
             fclose (fp);
@@ -136,7 +137,7 @@ _gcry_initialize_fips_mode (int force)
         /* Problem reading the fips file despite that we have the proc
            file system.  We better stop right away. */
         log_info ("FATAL: error reading `%s' in libgcrypt: %s\n",
-                  "/proc/fips140", strerror (saved_errno));
+                  procfname, strerror (saved_errno));
         abort ();
       }
   }
index c08d544..7d91d09 100644 (file)
@@ -1,3 +1,7 @@
+2008-08-29  Werner Koch  <wk@g10code.com>
+
+       * keygrip.c: Update to also check ECDSA.
+
 2008-08-28  Werner Koch  <wk@g10code.com>
 
        * rsa-16k.key: New sample key.
index 351139f..e1908ba 100644 (file)
@@ -45,15 +45,29 @@ die (const char *format, ...)
   exit (1);
 }
 
+static void
+print_hex (const char *text, const void *buf, size_t n)
+{
+  const unsigned char *p = buf;
+
+  fputs (text, stdout);
+  for (; n; n--, p++)
+    printf ("%02X", *p);
+  putchar ('\n');
+}
+
+
 \f
 
 static struct
 {
+  int algo;
   const char *key;
   const unsigned char grip[20];
 } key_grips[] =
   {
     {
+      GCRY_PK_RSA,
       "(private-key"
       " (rsa"
       "  (n #00B6B509596A9ECABC939212F891E656A626BA07DA8521A9CAD4C08E640C04052FBB87F424EF1A0275A48A9299AC9DB69ABE3D0124E6C756B1F7DFB9B842D6251AEA6EE85390495CADA73D671537FCE5850A932F32BAB60AB1AC1F852C1F83C625E7A7D70CDA9EF16D5C8E47739D77DF59261ABE8454807FF441E143FBD37F8545#)"
@@ -65,6 +79,7 @@ static struct
       "\x32\xCF\xFA\x85\xB1\x79\x1F\xBB\x26\x14\xE9\x1A\xFD\xF3\xAF\xE3\x32\x08\x2E\x25"
     },
     {
+      GCRY_PK_DSA,
       " (public-key"
       " (dsa"
       "  (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)"
@@ -75,6 +90,7 @@ static struct
       
     },
     {
+      GCRY_PK_DSA,
       "(private-key"
       " (dsa"
       "  (p #0084E4C626E16005770BD9509ABF7354492E85B8C0060EFAAAEC617F725B592FAA59DF5460575F41022776A9718CE62EDD542AB73C7720869EBDBC834D174ADCD7136827DF51E2613545A25CA573BC502A61B809000B6E35F5EB7FD6F18C35678C23EA1C3638FB9CFDBA2800EE1B62F41A4479DE824F2834666FBF8DC5B53C2617#)"
@@ -83,7 +99,40 @@ static struct
       "  (y #3D5DD14AFA2BF24A791E285B90232213D0E3BA74AB1109E768AED19639A322F84BB7D959E2BA92EF73DE4C7F381AA9F4053CFA3CD4527EF9043E304E5B95ED0A3A5A9D590AA641C13DB2B6E32B9B964A6A2C730DD3EA7C8E13F7A140AFF1A91CE375E9B9B960384779DC4EA180FA1F827C52288F366C0770A220F50D6D8FD6F6#)"
       "  (x #0087F9E91BFBCC1163DE71ED86D557708E32F8ADDE#)))",
       "\x04\xA3\x4F\xA0\x2B\x03\x94\xD7\x32\xAD\xD5\x9B\x50\xAF\xDB\x5D\x57\x22\xA6\x10"
+    },
+    {   
+      GCRY_PK_ECDSA,
+      "(public-key"
+      " (ecdsa"
+      " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)"
+      " (a #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC#)"
+      " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)"
+      " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)"
+      " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)"
+      " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))",
+      "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6"
+    },
+    {   
+      GCRY_PK_ECDSA,
+      "(public-key"
+      " (ecdsa"
+      " (p #00FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF#)"
+      " (curve \"NIST P-256\")"
+      " (b #5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B#)"
+      " (g #046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5#)"
+      " (n #00FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551#)"
+      " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))",
+      "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6"
+    },
+    {   
+      GCRY_PK_ECDSA,
+      "(public-key"
+      " (ecdsa"
+      " (curve secp256r1)"
+      " (q #04C8A4CEC2E9A9BC8E173531A67B0840DF345C32E261ADD780E6D83D56EFADFD5DE872F8B854819B59543CE0B7F822330464FBC4E6324DADDCD9D059554F63B344#)))",
+      "\xE6\xDF\x94\x2D\xBD\x8C\x77\x05\xA3\xDD\x41\x6E\xFC\x04\x01\xDB\x31\x0E\x99\xB6"
     }
+
   };
 
 static void
@@ -97,12 +146,27 @@ check (void)
 
   for (i = 0; i < (sizeof (key_grips) / sizeof (*key_grips)); i++)
     {
+      if (gcry_pk_test_algo (key_grips[i].algo))
+        {
+          if (verbose)
+            fprintf (stderr, "algo %d not available; test skipped\n", 
+                     key_grips[i].algo);
+          continue;
+        }
       err = gcry_sexp_sscan (&sexp, NULL, key_grips[i].key,
                             strlen (key_grips[i].key));
-      assert (! err);
+      if (err)
+        die ("scanning data %d failed: %s\n", i, gpg_strerror (err));
       ret = gcry_pk_get_keygrip (sexp, buf);
-      assert (ret);
-      assert (! memcmp (key_grips[i].grip, buf, sizeof (buf)));
+      if (!ret)
+        die ("gcry_pk_get_keygrip failed for %d\n", i);
+        
+      if ( memcmp (key_grips[i].grip, buf, sizeof (buf)) )
+        {
+          print_hex ("keygrip: ", buf, sizeof buf);
+          die ("keygrip for %d does not match\n", i); 
+        }
+
       gcry_sexp_release (sexp);
     }
 }