speedo: Improve speedo Makefile.
[gnupg.git] / g10 / pkglue.c
index abec77d..684ce8a 100644 (file)
@@ -1,11 +1,12 @@
 /* pkglue.c - public key operations glue code
- *     Copyright (C) 2000, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2003, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU 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
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include "gpg.h"
 #include "util.h"
 #include "pkglue.h"
+#include "main.h"
+#include "options.h"
 
-
-
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- */
-int
-pk_sign (int algo, gcry_mpi_t * data, gcry_mpi_t hash, gcry_mpi_t * skey)
+/* FIXME: Better chnage the fucntion name because mpi_ is used by
+   gcrypt macros.  */
+gcry_mpi_t
+get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
 {
-  gcry_sexp_t s_sig, s_hash, s_skey, list;
-  int rc;
-
-  /* make a sexp from skey */
-  if (algo == GCRY_PK_DSA)
-    {
-      rc = gcry_sexp_build (&s_skey, NULL,
-                           "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
-                           skey[0], skey[1], skey[2], skey[3], skey[4]);
-    }
-  else if (algo == GCRY_PK_RSA)
-    {
-      rc = gcry_sexp_build (&s_skey, NULL,
-                           "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
-                           skey[0], skey[1], skey[2], skey[3], skey[4],
-                           skey[5]);
-    }
-  else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
-    {
-      rc = gcry_sexp_build (&s_skey, NULL,
-                           "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
-                           skey[0], skey[1], skey[2], skey[3]);
-    }
-  else
-    return GPG_ERR_PUBKEY_ALGO;
-
-  if (rc)
-    BUG ();
-
-  /* put hash into a S-Exp s_hash */
-  if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
-    BUG ();
-
-  rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
-  gcry_sexp_release (s_hash);
-  gcry_sexp_release (s_skey);
-
-  if (rc)
-    ;
-  else if (algo == GCRY_PK_RSA)
-    {
-      list = gcry_sexp_find_token (s_sig, "s", 0);
-      assert (list);
-      data[0] = gcry_sexp_nth_mpi (list, 1, 0);
-      assert (data[0]);
-      gcry_sexp_release (list);
-    }
-  else
-    {
-      list = gcry_sexp_find_token (s_sig, "r", 0);
-      assert (list);
-      data[0] = gcry_sexp_nth_mpi (list, 1, 0);
-      assert (data[0]);
-      gcry_sexp_release (list);
-
-      list = gcry_sexp_find_token (s_sig, "s", 0);
-      assert (list);
-      data[1] = gcry_sexp_nth_mpi (list, 1, 0);
-      assert (data[1]);
-      gcry_sexp_release (list);
-    }
+  gcry_sexp_t list;
+  gcry_mpi_t data;
+
+  list = gcry_sexp_find_token (sexp, item, 0);
+  assert (list);
+  data = gcry_sexp_nth_mpi (list, 1, mpifmt);
+  assert (data);
+  gcry_sexp_release (list);
+  return data;
+}
 
 
-  gcry_sexp_release (s_sig);
-  return rc;
-}
 
 /****************
  * Emulate our old PK interface here - sometime in the future we might
  * change the internal design to directly fit to libgcrypt.
  */
 int
-pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
+pk_verify (pubkey_algo_t pkalgo, gcry_mpi_t hash,
+           gcry_mpi_t *data, gcry_mpi_t *pkey)
 {
   gcry_sexp_t s_sig, s_hash, s_pkey;
   int rc;
 
-  /* make a sexp from pkey */
-  if (algo == GCRY_PK_DSA)
+  /* Make a sexp from pkey.  */
+  if (pkalgo == PUBKEY_ALGO_DSA)
     {
       rc = gcry_sexp_build (&s_pkey, NULL,
                            "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
                            pkey[0], pkey[1], pkey[2], pkey[3]);
     }
-  else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
+  else if (pkalgo == PUBKEY_ALGO_ELGAMAL_E || pkalgo == PUBKEY_ALGO_ELGAMAL)
     {
       rc = gcry_sexp_build (&s_pkey, NULL,
                            "(public-key(elg(p%m)(g%m)(y%m)))",
                            pkey[0], pkey[1], pkey[2]);
     }
-  else if (algo == GCRY_PK_RSA)
+  else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
     {
       rc = gcry_sexp_build (&s_pkey, NULL,
                            "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
     }
+  else if (pkalgo == PUBKEY_ALGO_ECDSA)
+    {
+      char *curve = openpgp_oid_to_str (pkey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = gcry_sexp_build (&s_pkey, NULL,
+                                "(public-key(ecdsa(curve %s)(q%m)))",
+                                curve, pkey[1]);
+          xfree (curve);
+        }
+    }
+  else if (pkalgo == PUBKEY_ALGO_EDDSA)
+    {
+      char *curve = openpgp_oid_to_str (pkey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = gcry_sexp_build (&s_pkey, NULL,
+                                "(public-key(ecc(curve %s)"
+                                "(flags eddsa)(q%m)))",
+                                curve, pkey[1]);
+          xfree (curve);
+        }
+    }
   else
     return GPG_ERR_PUBKEY_ALGO;
 
   if (rc)
-    BUG ();
+    BUG ();  /* gcry_sexp_build should never fail.  */
 
-  /* put hash into a S-Exp s_hash */
-  if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
-    BUG ();
+  /* Put hash into a S-Exp s_hash. */
+  if (pkalgo == PUBKEY_ALGO_EDDSA)
+    {
+      if (gcry_sexp_build (&s_hash, NULL,
+                           "(data(flags eddsa)(hash-algo sha512)(value %m))",
+                           hash))
+        BUG (); /* gcry_sexp_build should never fail.  */
+    }
+  else
+    {
+      if (gcry_sexp_build (&s_hash, NULL, "%m", hash))
+        BUG (); /* gcry_sexp_build should never fail.  */
+    }
 
-  /* put data into a S-Exp s_sig */
-  if (algo == GCRY_PK_DSA)
+  /* Put data into a S-Exp s_sig. */
+  s_sig = NULL;
+  if (pkalgo == PUBKEY_ALGO_DSA)
     {
       if (!data[0] || !data[1])
         rc = gpg_error (GPG_ERR_BAD_MPI);
@@ -152,7 +135,23 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
         rc = gcry_sexp_build (&s_sig, NULL,
                               "(sig-val(dsa(r%m)(s%m)))", data[0], data[1]);
     }
-  else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
+  else if (pkalgo == PUBKEY_ALGO_ECDSA)
+    {
+      if (!data[0] || !data[1])
+        rc = gpg_error (GPG_ERR_BAD_MPI);
+      else
+        rc = gcry_sexp_build (&s_sig, NULL,
+                              "(sig-val(ecdsa(r%m)(s%m)))", data[0], data[1]);
+    }
+  else if (pkalgo == PUBKEY_ALGO_EDDSA)
+    {
+      if (!data[0] || !data[1])
+        rc = gpg_error (GPG_ERR_BAD_MPI);
+      else
+        rc = gcry_sexp_build (&s_sig, NULL,
+                              "(sig-val(eddsa(r%M)(s%M)))", data[0], data[1]);
+    }
+  else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
     {
       if (!data[0] || !data[1])
         rc = gpg_error (GPG_ERR_BAD_MPI);
@@ -160,7 +159,7 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
         rc = gcry_sexp_build (&s_sig, NULL,
                               "(sig-val(elg(r%m)(s%m)))", data[0], data[1]);
     }
-  else if (algo == GCRY_PK_RSA)
+  else if (pkalgo == PUBKEY_ALGO_RSA || pkalgo == PUBKEY_ALGO_RSA_S)
     {
       if (!data[0])
         rc = gpg_error (GPG_ERR_BAD_MPI);
@@ -170,11 +169,9 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
   else
     BUG ();
 
-  if (rc)
-    BUG ();
-
+  if (!rc)
+    rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
 
-  rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
   gcry_sexp_release (s_sig);
   gcry_sexp_release (s_hash);
   gcry_sexp_release (s_pkey);
@@ -187,162 +184,177 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t * data, gcry_mpi_t * pkey)
 /****************
  * Emulate our old PK interface here - sometime in the future we might
  * change the internal design to directly fit to libgcrypt.
+ * PK is only required to compute the fingerprint for ECDH.
  */
 int
-pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
+pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
+            PKT_public_key *pk, gcry_mpi_t *pkey)
 {
-  gcry_sexp_t s_ciph, s_data, s_pkey;
+  gcry_sexp_t s_ciph = NULL;
+  gcry_sexp_t s_data = NULL;
+  gcry_sexp_t s_pkey = NULL;
   int rc;
 
-  /* make a sexp from pkey */
-  if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
+  /* Make a sexp from pkey.  */
+  if (algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E)
     {
       rc = gcry_sexp_build (&s_pkey, NULL,
                            "(public-key(elg(p%m)(g%m)(y%m)))",
                            pkey[0], pkey[1], pkey[2]);
+      /* Put DATA into a simplified S-expression.  */
+      if (!rc)
+        rc = gcry_sexp_build (&s_data, NULL, "%m", data);
     }
-  else if (algo == GCRY_PK_RSA)
+  else if (algo == PUBKEY_ALGO_RSA || algo == PUBKEY_ALGO_RSA_E)
     {
       rc = gcry_sexp_build (&s_pkey, NULL,
                            "(public-key(rsa(n%m)(e%m)))",
                            pkey[0], pkey[1]);
+      /* Put DATA into a simplified S-expression.  */
+      if (!rc)
+        rc = gcry_sexp_build (&s_data, NULL, "%m", data);
     }
-  else
-    return GPG_ERR_PUBKEY_ALGO;
+  else if (algo == PUBKEY_ALGO_ECDH)
+    {
+      gcry_mpi_t k;
 
-  if (rc)
-    BUG ();
+      rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
+      if (!rc)
+        {
+          char *curve;
+
+          curve = openpgp_oid_to_str (pkey[0]);
+          if (!curve)
+            rc = gpg_error_from_syserror ();
+          else
+            {
+              /* Now use the ephemeral secret to compute the shared point.  */
+              rc = gcry_sexp_build (&s_pkey, NULL,
+                                    "(public-key(ecdh(curve%s)(q%m)))",
+                                    curve, pkey[1]);
+              xfree (curve);
+              /* Put K into a simplified S-expression.  */
+              if (!rc)
+                rc = gcry_sexp_build (&s_data, NULL, "%m", k);
+            }
+          gcry_mpi_release (k);
+        }
+    }
+  else
+    rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
 
-  /* put the data into a simple list */
-  if (gcry_sexp_build (&s_data, NULL, "%m", data))
-    BUG ();
+  /* Pass it to libgcrypt. */
+  if (!rc)
+    rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
 
-  /* pass it to libgcrypt */
-  rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
   gcry_sexp_release (s_data);
   gcry_sexp_release (s_pkey);
 
   if (rc)
     ;
-  else
-    { /* add better error handling or make gnupg use S-Exp directly */
-      gcry_sexp_t list = gcry_sexp_find_token (s_ciph, "a", 0);
-      assert (list);
-      resarr[0] = gcry_sexp_nth_mpi (list, 1, 0);
-      assert (resarr[0]);
-      gcry_sexp_release (list);
-
-      if (algo != GCRY_PK_RSA)
+  else if (algo == PUBKEY_ALGO_ECDH)
+    {
+      gcry_mpi_t shared, public, result;
+      byte fp[MAX_FINGERPRINT_LEN];
+      size_t fpn;
+
+      /* Get the shared point and the ephemeral public key.  */
+      shared = get_mpi_from_sexp (s_ciph, "s", GCRYMPI_FMT_USG);
+      public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
+      gcry_sexp_release (s_ciph);
+      s_ciph = NULL;
+      if (DBG_CIPHER)
         {
-          list = gcry_sexp_find_token (s_ciph, "b", 0);
-          assert (list);
-          resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
-          assert (resarr[1]);
-          gcry_sexp_release (list);
+          log_debug ("ECDH ephemeral key:");
+          gcry_mpi_dump (public);
+          log_printf ("\n");
         }
-    }
-
-  gcry_sexp_release (s_ciph);
-  return rc;
-}
-
 
-
-/****************
- * Emulate our old PK interface here - sometime in the future we might
- * change the internal design to directly fit to libgcrypt.
- */
-int
-pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
-           gcry_mpi_t * skey)
-{
-  gcry_sexp_t s_skey, s_data, s_plain;
-  int rc;
-
-  *result = NULL;
-  /* make a sexp from skey */
-  if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
-    {
-      rc = gcry_sexp_build (&s_skey, NULL,
-                           "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
-                           skey[0], skey[1], skey[2], skey[3]);
-    }
-  else if (algo == GCRY_PK_RSA)
-    {
-      rc = gcry_sexp_build (&s_skey, NULL,
-                           "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
-                           skey[0], skey[1], skey[2], skey[3], skey[4],
-                           skey[5]);
-    }
-  else
-    return GPG_ERR_PUBKEY_ALGO;
-
-  if (rc)
-    BUG ();
-
-  /* put data into a S-Exp s_data */
-  if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
-    {
-      if (!data[0] || !data[1])
-        rc = gpg_error (GPG_ERR_BAD_MPI);
+      result = NULL;
+      fingerprint_from_pk (pk, fp, &fpn);
+      if (fpn != 20)
+        rc = gpg_error (GPG_ERR_INV_LENGTH);
       else
-        rc = gcry_sexp_build (&s_data, NULL,
-                              "(enc-val(elg(a%m)(b%m)))", data[0], data[1]);
-    }
-  else if (algo == GCRY_PK_RSA)
-    {
-      if (!data[0])
-        rc = gpg_error (GPG_ERR_BAD_MPI);
+        rc = pk_ecdh_encrypt_with_shared_point (1 /*=encrypton*/, shared,
+                                                fp, data, pkey, &result);
+      gcry_mpi_release (shared);
+      if (!rc)
+        {
+          resarr[0] = public;
+          resarr[1] = result;
+        }
       else
-        rc = gcry_sexp_build (&s_data, NULL, "(enc-val(rsa(a%m)))", data[0]);
+        {
+          gcry_mpi_release (public);
+          gcry_mpi_release (result);
+        }
+    }
+  else /* Elgamal or RSA case.  */
+    { /* Fixme: Add better error handling or make gnupg use
+         S-expressions directly.  */
+      resarr[0] = get_mpi_from_sexp (s_ciph, "a", GCRYMPI_FMT_USG);
+      if (!is_RSA (algo))
+        resarr[1] = get_mpi_from_sexp (s_ciph, "b", GCRYMPI_FMT_USG);
     }
-  else
-    BUG ();
-
-  if (rc)
-    BUG ();
-
-  rc = gcry_pk_decrypt (&s_plain, s_data, s_skey);
-  gcry_sexp_release (s_skey);
-  gcry_sexp_release (s_data);
-  if (rc)
-    return rc;
-
-  *result = gcry_sexp_nth_mpi (s_plain, 0, 0);
-  gcry_sexp_release (s_plain);
-  if (!*result)
-    return -1;                 /* oops */
 
-  return 0;
+  gcry_sexp_release (s_ciph);
+  return rc;
 }
 
 
 /* Check whether SKEY is a suitable secret key. */
 int
-pk_check_secret_key (int algo, gcry_mpi_t *skey)
+pk_check_secret_key (pubkey_algo_t pkalgo, gcry_mpi_t *skey)
 {
   gcry_sexp_t s_skey;
   int rc;
 
-  if (algo == GCRY_PK_DSA)
+  if (pkalgo == PUBKEY_ALGO_DSA)
     {
       rc = gcry_sexp_build (&s_skey, NULL,
                            "(private-key(dsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
                            skey[0], skey[1], skey[2], skey[3], skey[4]);
     }
-  else if (algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E)
+  else if (pkalgo == PUBKEY_ALGO_ELGAMAL || pkalgo == PUBKEY_ALGO_ELGAMAL_E)
     {
       rc = gcry_sexp_build (&s_skey, NULL,
                            "(private-key(elg(p%m)(g%m)(y%m)(x%m)))",
                            skey[0], skey[1], skey[2], skey[3]);
     }
-  else if (algo == GCRY_PK_RSA)
+  else if (is_RSA (pkalgo))
     {
       rc = gcry_sexp_build (&s_skey, NULL,
                            "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
                            skey[0], skey[1], skey[2], skey[3], skey[4],
                            skey[5]);
     }
+  else if (pkalgo == PUBKEY_ALGO_ECDSA || pkalgo == PUBKEY_ALGO_ECDH)
+    {
+      char *curve = openpgp_oid_to_str (skey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = gcry_sexp_build (&s_skey, NULL,
+                                "(private-key(ecc(curve%s)(q%m)(d%m)))",
+                                curve, skey[1], skey[2]);
+          xfree (curve);
+        }
+    }
+  else if (pkalgo == PUBKEY_ALGO_EDDSA)
+    {
+      char *curve = openpgp_oid_to_str (skey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = gcry_sexp_build (&s_skey, NULL,
+                                "(private-key(ecc(curve %s)"
+                                "(flags eddsa)(q%m)(d%m)))",
+                                curve, skey[1], skey[2]);
+          xfree (curve);
+        }
+    }
   else
     return GPG_ERR_PUBKEY_ALGO;