mpi/ec: fix when 'unsigned long' is 32-bit but limb size is 64-bit
[libgcrypt.git] / tests / pubkey.c
index 4534175..fbb7bbb 100644 (file)
@@ -26,7 +26,9 @@
 #include <string.h>
 
 
-#include "../src/gcrypt.h"
+#define PGM "pubkey"
+#include "t-common.h"
+
 
 /* Sample RSA keys, taken from basic.c.  */
 
@@ -100,21 +102,6 @@ static const char sample_public_key_1[] =
 ")\n";
 
 
-static int verbose;
-
-static void
-die (const char *format, ...)
-{
-  va_list arg_ptr ;
-
-  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
 show_sexp (const char *prefix, gcry_sexp_t a)
 {
@@ -131,6 +118,86 @@ show_sexp (const char *prefix, gcry_sexp_t a)
   gcry_free (buf);
 }
 
+/* from ../cipher/pubkey-util.c */
+static gpg_err_code_t
+_gcry_pk_util_get_nbits (gcry_sexp_t list, unsigned int *r_nbits)
+{
+  char buf[50];
+  const char *s;
+  size_t n;
+
+  *r_nbits = 0;
+
+  list = gcry_sexp_find_token (list, "nbits", 0);
+  if (!list)
+    return 0; /* No NBITS found.  */
+
+  s = gcry_sexp_nth_data (list, 1, &n);
+  if (!s || n >= DIM (buf) - 1 )
+    {
+      /* NBITS given without a cdr.  */
+      gcry_sexp_release (list);
+      return GPG_ERR_INV_OBJ;
+    }
+  memcpy (buf, s, n);
+  buf[n] = 0;
+  *r_nbits = (unsigned int)strtoul (buf, NULL, 0);
+  gcry_sexp_release (list);
+  return 0;
+}
+
+/* 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 *
+data_from_hex (const char *string, size_t *r_length)
+{
+  const char *s;
+  unsigned char *buffer;
+  size_t length;
+
+  buffer = gcry_xmalloc (strlen(string)/2+1);
+  length = 0;
+  for (s=string; *s; s +=2 )
+    {
+      if (!hexdigitp (s) || !hexdigitp (s+1))
+        die ("error parsing hex string `%s'\n", string);
+      ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+    }
+  *r_length = length;
+  return buffer;
+}
+
+
+static void
+extract_cmp_data (gcry_sexp_t sexp, const char *name, const char *expected)
+{
+  gcry_sexp_t l1;
+  const void *a;
+  size_t alen;
+  void *b;
+  size_t blen;
+
+  l1 = gcry_sexp_find_token (sexp, name, 0);
+  a = gcry_sexp_nth_data (l1, 1, &alen);
+  b = data_from_hex (expected, &blen);
+  if (!a)
+    fail ("parameter \"%s\" missing in key\n", name);
+  else if ( alen != blen || memcmp (a, b, alen) )
+    {
+      fail ("parameter \"%s\" does not match expected value\n", name);
+      if (verbose)
+        {
+          info ("expected: %s\n", expected);
+          show_sexp ("sexp: ", sexp);
+        }
+    }
+  gcry_free (b);
+  gcry_sexp_release (l1);
+}
+
 
 static void
 check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey,
@@ -144,6 +211,7 @@ check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey,
   /* Extract data from plaintext.  */
   l = gcry_sexp_find_token (plain0, "value", 0);
   x0 = gcry_sexp_nth_mpi (l, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l);
 
   /* Encrypt data.  */
   rc = gcry_pk_encrypt (&cipher, plain0, pkey);
@@ -160,7 +228,10 @@ check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey,
   if (rc)
     {
       if (decrypt_fail_code && gpg_err_code (rc) == decrypt_fail_code)
-        return; /* This is the expected failure code.  */
+       {
+         gcry_mpi_release (x0);
+         return; /* This is the expected failure code.  */
+       }
       die ("decryption failed: %s\n", gcry_strerror (rc));
     }
 
@@ -189,6 +260,8 @@ check_keys_crypt (gcry_sexp_t pkey, gcry_sexp_t skey,
   /* Compare.  */
   if (gcry_mpi_cmp (x0, x1))
     die ("data corrupted\n");
+  gcry_mpi_release (x0);
+  gcry_mpi_release (x1);
 }
 
 static void
@@ -218,6 +291,7 @@ check_keys (gcry_sexp_t pkey, gcry_sexp_t skey, unsigned int nbits_data,
 
   rc = gcry_sexp_build (&plain, NULL,
                         "(data (flags raw no-blinding) (value %m))", x);
+  gcry_mpi_release (x);
   if (rc)
     die ("converting data for encryption failed: %s\n",
         gcry_strerror (rc));
@@ -260,7 +334,7 @@ get_keys_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   int rc;
 
   rc = gcry_sexp_new (&key_spec,
-                     "(genkey (rsa (nbits 4:1024)))", 0, 1);
+                     "(genkey (rsa (nbits 4:2048)))", 0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gcry_strerror (rc));
   rc = gcry_pk_genkey (&key, key_spec);
@@ -292,7 +366,7 @@ get_keys_x931_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   int rc;
 
   rc = gcry_sexp_new (&key_spec,
-                     "(genkey (rsa (nbits 4:1024)(use-x931)))", 0, 1);
+                     "(genkey (rsa (nbits 4:2048)(use-x931)))", 0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gcry_strerror (rc));
   rc = gcry_pk_genkey (&key, key_spec);
@@ -362,8 +436,8 @@ get_dsa_key_new (gcry_sexp_t *pkey, gcry_sexp_t *skey, int transient_key)
 
   rc = gcry_sexp_new (&key_spec,
                       transient_key
-                      ? "(genkey (dsa (nbits 4:1024)(transient-key)))"
-                      : "(genkey (dsa (nbits 4:1024)))",
+                      ? "(genkey (dsa (nbits 4:2048)(transient-key)))"
+                      : "(genkey (dsa (nbits 4:2048)))",
                       0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gcry_strerror (rc));
@@ -396,7 +470,7 @@ get_dsa_key_fips186_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   int rc;
 
   rc = gcry_sexp_new
-    (&key_spec, "(genkey (dsa (nbits 4:1024)(use-fips186)))",  0, 1);
+    (&key_spec, "(genkey (dsa (nbits 4:2048)(use-fips186)))",  0, 1);
   if (rc)
     die ("error creating S-expression: %s\n", gcry_strerror (rc));
   rc = gcry_pk_genkey (&key, key_spec);
@@ -463,6 +537,7 @@ get_dsa_key_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   *skey = sec_key;
 }
 
+#if 0
 static void
 get_dsa_key_fips186_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
 {
@@ -504,7 +579,7 @@ get_dsa_key_fips186_with_domain_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
   *pkey = pub_key;
   *skey = sec_key;
 }
-
+#endif /*0*/
 
 static void
 get_dsa_key_fips186_with_seed_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
@@ -516,7 +591,7 @@ get_dsa_key_fips186_with_seed_new (gcry_sexp_t *pkey, gcry_sexp_t *skey)
     (&key_spec,
      "(genkey"
      "  (dsa"
-     "    (nbits 4:1024)"
+     "    (nbits 4:2048)"
      "    (use-fips186)"
      "    (transient-key)"
      "    (derive-parms"
@@ -628,12 +703,14 @@ check_run (void)
   gcry_sexp_release (pkey);
   gcry_sexp_release (skey);
 
+  /* We need new test vectors for get_dsa_key_fips186_with_domain_new.  */
   if (verbose)
-    fprintf (stderr, "Generating DSA key with given domain (FIPS 186).\n");
-  get_dsa_key_fips186_with_domain_new (&pkey, &skey);
-  /* Fixme:  Add a check function for DSA keys.  */
-  gcry_sexp_release (pkey);
-  gcry_sexp_release (skey);
+    fprintf (stderr, "Generating DSA key with given domain (FIPS 186)"
+             " - skipped.\n");
+  /* get_dsa_key_fips186_with_domain_new (&pkey, &skey); */
+  /* /\* Fixme:  Add a check function for DSA keys.  *\/ */
+  /* gcry_sexp_release (pkey); */
+  /* gcry_sexp_release (skey); */
 
   if (verbose)
     fprintf (stderr, "Generating DSA key with given seed (FIPS 186).\n");
@@ -809,8 +886,8 @@ check_x931_derived_key (int what)
     }
   };
   gpg_error_t err;
-  gcry_sexp_t key_spec, key, pub_key, sec_key;
-  gcry_mpi_t d_expected, d_have;
+  gcry_sexp_t key_spec = NULL, key = NULL, pub_key = NULL, sec_key = NULL;
+  gcry_mpi_t d_expected = NULL, d_have = NULL;
 
   if (what < 0 && what >= sizeof testtable)
     die ("invalid WHAT value\n");
@@ -819,10 +896,25 @@ check_x931_derived_key (int what)
   if (err)
     die ("error creating S-expression [%d]: %s\n", what, gpg_strerror (err));
 
+  {
+    unsigned nbits;
+    err = _gcry_pk_util_get_nbits(key_spec, &nbits);
+    if (err)
+      die ("nbits not found\n");
+    if (gcry_fips_mode_active() && nbits < 2048)
+      {
+        info("RSA key test with %d bits skipped in fips mode\n", nbits);
+        goto leave;
+      }
+  }
+
   err = gcry_pk_genkey (&key, key_spec);
   gcry_sexp_release (key_spec);
   if (err)
-    die ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err));
+    {
+      fail ("error generating RSA key [%d]: %s\n", what, gpg_strerror (err));
+      goto leave;
+    }
 
   pub_key = gcry_sexp_find_token (key, "public-key", 0);
   if (!pub_key)
@@ -848,6 +940,7 @@ check_x931_derived_key (int what)
       show_sexp (NULL, sec_key);
       die ("parameter d does match expected value [%d]\n", what);
     }
+leave:
   gcry_mpi_release (d_expected);
   gcry_mpi_release (d_have);
 
@@ -886,9 +979,23 @@ check_ecc_sample_key (void)
     "(data (flags raw)\n"
     " (value #00112233445566778899AABBCCDDEEFF"
     /* */    "000102030405060708090A0B0C0D0E0F#))";
+  static const char hash2_string[] =
+    "(data (flags raw)\n"
+    " (hash sha1 #00112233445566778899AABBCCDDEEFF"
+    /* */    "000102030405060708090A0B0C0D0E0F"
+    /* */    "000102030405060708090A0B0C0D0E0F"
+    /* */    "00112233445566778899AABBCCDDEEFF#))";
+  /* hash2, but longer than curve length, so it will be truncated */
+  static const char hash3_string[] =
+    "(data (flags raw)\n"
+    " (hash sha1 #00112233445566778899AABBCCDDEEFF"
+    /* */    "000102030405060708090A0B0C0D0E0F"
+    /* */    "000102030405060708090A0B0C0D0E0F"
+    /* */    "00112233445566778899AABBCCDDEEFF"
+    /* */    "000102030405060708090A0B0C0D0E0F#))";
 
   gpg_error_t err;
-  gcry_sexp_t key, hash, sig;
+  gcry_sexp_t key, hash, hash2, hash3, sig, sig2;
 
   if (verbose)
     fprintf (stderr, "Checking sample ECC key.\n");
@@ -896,6 +1003,12 @@ check_ecc_sample_key (void)
   if ((err = gcry_sexp_new (&hash, hash_string, 0, 1)))
     die ("line %d: %s", __LINE__, gpg_strerror (err));
 
+  if ((err = gcry_sexp_new (&hash2, hash2_string, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+
+  if ((err = gcry_sexp_new (&hash3, hash3_string, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+
   if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1)))
     die ("line %d: %s", __LINE__, gpg_strerror (err));
 
@@ -909,6 +1022,28 @@ check_ecc_sample_key (void)
   if ((err = gcry_pk_verify (sig, hash, key)))
     die ("gcry_pk_verify failed: %s", gpg_strerror (err));
 
+  /* Verify hash truncation */
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+
+  if ((err = gcry_pk_sign (&sig2, hash2, key)))
+    die ("gcry_pk_sign failed: %s", gpg_strerror (err));
+
+  gcry_sexp_release (sig);
+  if ((err = gcry_pk_sign (&sig, hash3, key)))
+    die ("gcry_pk_sign failed: %s", gpg_strerror (err));
+
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+
+  if ((err = gcry_pk_verify (sig, hash2, key)))
+    die ("gcry_pk_verify failed: %s", gpg_strerror (err));
+
+  if ((err = gcry_pk_verify (sig2, hash3, key)))
+    die ("gcry_pk_verify failed: %s", gpg_strerror (err));
+
   /* Now try signing without the Q parameter.  */
 
   gcry_sexp_release (key);
@@ -927,6 +1062,105 @@ check_ecc_sample_key (void)
     die ("gcry_pk_verify signed without Q failed: %s", gpg_strerror (err));
 
   gcry_sexp_release (sig);
+  gcry_sexp_release (sig2);
+  gcry_sexp_release (key);
+  gcry_sexp_release (hash);
+  gcry_sexp_release (hash2);
+  gcry_sexp_release (hash3);
+}
+
+
+static void
+check_ed25519ecdsa_sample_key (void)
+{
+  static const char ecc_private_key[] =
+    "(private-key\n"
+    " (ecc\n"
+    "  (curve \"Ed25519\")\n"
+    "  (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321"
+    "        156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)"
+    "  (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)"
+    "))";
+  static const char ecc_private_key_wo_q[] =
+    "(private-key\n"
+    " (ecc\n"
+    "  (curve \"Ed25519\")\n"
+    "  (d #09A0C38E0F1699073541447C19DA12E3A07A7BFDB0C186E4AC5BCE6F23D55252#)"
+    "))";
+  static const char ecc_public_key[] =
+    "(public-key\n"
+    " (ecc\n"
+    "  (curve \"Ed25519\")\n"
+    "  (q #044C056555BE4084BB3D8D8895FDF7C2893DFE0256251923053010977D12658321"
+    "        156D1ADDC07987713A418783658B476358D48D582DB53233D9DED3C1C2577B04#)"
+    "))";
+  static const char ecc_public_key_comp[] =
+    "(public-key\n"
+    " (ecc\n"
+    "  (curve \"Ed25519\")\n"
+    "  (q #047b57c2c1d3ded93332b52d588dd45863478b658387413a718779c0dd1a6d95#)"
+    "))";
+  static const char hash_string[] =
+    "(data (flags rfc6979)\n"
+    " (hash sha256 #00112233445566778899AABBCCDDEEFF"
+    /* */          "000102030405060708090A0B0C0D0E0F#))";
+
+  gpg_error_t err;
+  gcry_sexp_t key, hash, sig;
+
+  if (verbose)
+    fprintf (stderr, "Checking sample Ed25519/ECDSA key.\n");
+
+  /* Sign.  */
+  if ((err = gcry_sexp_new (&hash, hash_string, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  if ((err = gcry_sexp_new (&key, ecc_private_key, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  if ((err = gcry_pk_sign (&sig, hash, key)))
+    die ("gcry_pk_sign failed: %s", gpg_strerror (err));
+
+  /* Verify.  */
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  if ((err = gcry_pk_verify (sig, hash, key)))
+    die ("gcry_pk_verify failed: %s", gpg_strerror (err));
+
+  /* Verify again using a compressed public key.  */
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  if ((err = gcry_pk_verify (sig, hash, key)))
+    die ("gcry_pk_verify failed (comp): %s", gpg_strerror (err));
+
+  /* Sign without a Q parameter.  */
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_private_key_wo_q, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  gcry_sexp_release (sig);
+  if ((err = gcry_pk_sign (&sig, hash, key)))
+    die ("gcry_pk_sign w/o Q failed: %s", gpg_strerror (err));
+
+  /* Verify.  */
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_public_key, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  if ((err = gcry_pk_verify (sig, hash, key)))
+    die ("gcry_pk_verify signed w/o Q failed: %s", gpg_strerror (err));
+
+  /* Verify again using a compressed public key.  */
+  gcry_sexp_release (key);
+  if ((err = gcry_sexp_new (&key, ecc_public_key_comp, 0, 1)))
+    die ("line %d: %s", __LINE__, gpg_strerror (err));
+  if ((err = gcry_pk_verify (sig, hash, key)))
+    die ("gcry_pk_verify signed w/o Q failed (comp): %s", gpg_strerror (err));
+
+  extract_cmp_data (sig, "r", ("a63123a783ef29b8276e08987daca4"
+                               "655d0179e22199bf63691fd88eb64e15"));
+  extract_cmp_data (sig, "s", ("0d9b45c696ab90b96b08812b485df185"
+                               "623ddaf5d02fa65ca5056cb6bd0f16f1"));
+
+  gcry_sexp_release (sig);
   gcry_sexp_release (key);
   gcry_sexp_release (hash);
 }
@@ -935,7 +1169,6 @@ check_ecc_sample_key (void)
 int
 main (int argc, char **argv)
 {
-  int debug = 0;
   int i;
 
   if (argc > 1 && !strcmp (argv[1], "--verbose"))
@@ -946,14 +1179,14 @@ main (int argc, char **argv)
       debug = 1;
     }
 
-  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
-  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
-    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
+    xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
   /* No valuable keys are create, so we can speed up our RNG. */
-  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+  xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
   for (i=0; i < 2; i++)
     check_run ();
@@ -962,6 +1195,8 @@ main (int argc, char **argv)
     check_x931_derived_key (i);
 
   check_ecc_sample_key ();
+  if (!gcry_fips_mode_active ())
+    check_ed25519ecdsa_sample_key ();
 
-  return 0;
+  return !!error_count;
 }