gpg: First take on PKT_ENCRYPTED_AEAD.
[gnupg.git] / agent / cvt-openpgp.c
index dff6b7c..c4d0334 100644 (file)
@@ -15,7 +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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -25,8 +25,9 @@
 #include <assert.h>
 
 #include "agent.h"
-#include "i18n.h"
+#include "../common/i18n.h"
 #include "cvt-openpgp.h"
+#include "../common/host2net.h"
 
 
 /* Helper to pass data via the callback to do_unprotect. */
@@ -82,14 +83,19 @@ get_keygrip (int pubkey_algo, const char *curve, gcry_mpi_t *pkey,
     case GCRY_PK_ECC:
       if (!curve)
         err = gpg_error (GPG_ERR_BAD_SECKEY);
-      else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
-        err = gcry_sexp_build (&s_pkey, NULL,
-                               "(public-key(ecc(curve %s)(flags eddsa)(q%m)))",
-                               "Ed25519", pkey[0]);
       else
-        err = gcry_sexp_build (&s_pkey, NULL,
-                               "(public-key(ecc(curve %s)(q%m)))",
-                               curve, pkey[0]);
+        {
+          const char *format;
+
+          if (!strcmp (curve, "Ed25519"))
+            format = "(public-key(ecc(curve %s)(flags eddsa)(q%m)))";
+          else if (!strcmp (curve, "Curve25519"))
+            format = "(public-key(ecc(curve %s)(flags djb-tweak)(q%m)))";
+          else
+            format = "(public-key(ecc(curve %s)(q%m)))";
+
+          err = gcry_sexp_build (&s_pkey, NULL, format, curve, pkey[0]);
+        }
       break;
 
     default:
@@ -145,19 +151,21 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
     case GCRY_PK_ECC:
       if (!curve)
         err = gpg_error (GPG_ERR_BAD_SECKEY);
-      else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
+      else
         {
-          /* Do not store the OID as name but the real name and the
-             EdDSA flag.  */
-          err = gcry_sexp_build (&s_skey, NULL,
-                                 "(private-key(ecc(curve%s)(flags eddsa)"
-                                 "(q%m)(d%m)))",
-                                 "Ed25519", skey[0], skey[1]);
+          const char *format;
+
+          if (!strcmp (curve, "Ed25519"))
+            /* Do not store the OID as name but the real name and the
+               EdDSA flag.  */
+            format = "(private-key(ecc(curve %s)(flags eddsa)(q%m)(d%m)))";
+          else if (!strcmp (curve, "Curve25519"))
+            format = "(private-key(ecc(curve %s)(flags djb-tweak)(q%m)(d%m)))";
+          else
+            format = "(private-key(ecc(curve %s)(q%m)(d%m)))";
+
+          err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], skey[1]);
         }
-      else
-        err = gcry_sexp_build (&s_skey, NULL,
-                               "(private-key(ecc(curve%s)(q%m)(d%m)))",
-                               curve, skey[0], skey[1]);
       break;
 
     default:
@@ -215,22 +223,24 @@ convert_transfer_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey,
     case GCRY_PK_ECC:
       if (!curve)
         err = gpg_error (GPG_ERR_BAD_SECKEY);
-      else if (!strcmp (curve, openpgp_curve_to_oid ("Ed25519", NULL)))
+      else
         {
-          /* Do not store the OID as name but the real name and the
-             EdDSA flag.  */
-          err = gcry_sexp_build
-            (&s_skey, NULL,
-             "(protected-private-key(ecc(curve%s)(flags eddsa)(q%m)"
-             "(protected openpgp-native%S)))",
-             "Ed25519", skey[0], transfer_key);
+          const char *format;
+
+          if (!strcmp (curve, "Ed25519"))
+            /* Do not store the OID as name but the real name and the
+               EdDSA flag.  */
+            format = "(protected-private-key(ecc(curve %s)(flags eddsa)(q%m)"
+              "(protected openpgp-native%S)))";
+          else if (!strcmp (curve, "Curve25519"))
+            format = "(protected-private-key(ecc(curve %s)(flags djb-tweak)(q%m)"
+              "(protected openpgp-native%S)))";
+          else
+            format = "(protected-private-key(ecc(curve %s)(q%m)"
+              "(protected openpgp-native%S)))";
+
+          err = gcry_sexp_build (&s_skey, NULL, format, curve, skey[0], transfer_key);
         }
-      else
-        err = gcry_sexp_build
-          (&s_skey, NULL,
-           "(protected-private-key(ecc(curve%s)(q%m)"
-           "(protected openpgp-native%S)))",
-           curve, skey[0], transfer_key);
       break;
 
     default:
@@ -487,7 +497,7 @@ do_unprotect (const char *passphrase,
       ndata = (ndatabits+7)/8;
 
       if (ndata > 1)
-        csum_pgp7 = p[ndata-2] << 8 | p[ndata-1];
+        csum_pgp7 = buf16_to_u16 (p+ndata-2);
       data = xtrymalloc_secure (ndata);
       if (!data)
         {
@@ -531,7 +541,7 @@ do_unprotect (const char *passphrase,
             }
           else
             {
-              desired_csum = (data[ndata-2] << 8 | data[ndata-1]);
+              desired_csum = buf16_to_u16 (data+ndata-2);
               actual_csum = checksum (data, ndata-2);
               if (desired_csum != actual_csum)
                 {
@@ -586,7 +596,7 @@ do_unprotect (const char *passphrase,
           p = gcry_mpi_get_opaque (skey[i], &ndatabits);
           ndata = (ndatabits+7)/8;
 
-          if (!(ndata >= 2) || !(ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2))
+          if (!(ndata >= 2) || !(ndata == (buf16_to_ushort (p) + 7)/8 + 2))
             {
               gcry_cipher_close (cipher_hd);
               return gpg_error (GPG_ERR_BAD_SECKEY);
@@ -647,7 +657,7 @@ do_unprotect (const char *passphrase,
 
 /* Callback function to try the unprotection from the passphrase query
    code.  */
-static int
+static gpg_error_t
 try_do_unprotect_cb (struct pin_entry_info_s *pi)
 {
   gpg_error_t err;
@@ -675,7 +685,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi)
    silently decrypt the key; CACHE_NONCE and R_PASSPHRASE must both be
    NULL in this mode.  */
 static gpg_error_t
-convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
+convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
                            unsigned char *grip, const char *prompt,
                            const char *cache_nonce, const char *passphrase,
                            unsigned char **r_key, char **r_passphrase)
@@ -828,15 +838,13 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       value = gcry_sexp_nth_data (list, ++idx, &valuelen);
       if (!value || !valuelen)
         goto bad_seckey;
-      if (is_enc || curve)
+      if (is_enc)
         {
-          /* Encrypted parameters and ECC parameters need or can be
-             stored as opaque.  */
+          /* Encrypted parameters need to be stored as opaque.  */
           skey[skeyidx] = gcry_mpi_set_opaque_copy (NULL, value, valuelen*8);
           if (!skey[skeyidx])
             goto outofmem;
-          if (is_enc)
-            gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1);
+          gcry_mpi_set_flag (skey[skeyidx], GCRYMPI_FLAG_USER1);
         }
       else
         {
@@ -870,11 +878,11 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
   log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
   log_debug ("XXX is_protected=%d\n", is_protected);
   log_debug ("XXX protect_algo=%d\n", protect_algo);
-  log_printhex ("XXX iv", iv, ivlen);
+  log_printhex (iv, ivlen, "XXX iv");
   log_debug ("XXX ivlen=%d\n", ivlen);
   log_debug ("XXX s2k_mode=%d\n", s2k_mode);
   log_debug ("XXX s2k_algo=%d\n", s2k_algo);
-  log_printhex ("XXX s2k_salt", s2k_salt, sizeof s2k_salt);
+  log_printhex (s2k_salt, sizeof s2k_salt, "XXX s2k_salt");
   log_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count);
   log_debug ("XXX curve='%s'\n", curve);
   for (idx=0; skey[idx]; idx++)
@@ -886,7 +894,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
   if (err)
     goto leave;
 
-  if (!from_native && !agent_key_available (grip))
+  if (!dontcare_exist && !from_native && !agent_key_available (grip))
     {
       err = gpg_error (GPG_ERR_EEXIST);
       goto leave;
@@ -908,10 +916,10 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
       struct pin_entry_info_s *pi;
       struct try_do_unprotect_arg_s pi_arg;
 
-      pi = xtrycalloc_secure (1, sizeof (*pi) + 100);
+      pi = xtrycalloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
       if (!pi)
         return gpg_error_from_syserror ();
-      pi->max_length = 100;
+      pi->max_length = MAX_PASSPHRASE_LEN + 1;
       pi->min_digits = 0;  /* We want a real passphrase.  */
       pi->max_digits = 16;
       pi->max_tries = 3;
@@ -960,7 +968,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
           err = try_do_unprotect_cb (pi);
         }
       if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE && !from_native)
-        err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
+        err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL, 0);
       skeyidx = pi_arg.skeyidx;
       if (!err && r_passphrase && is_protected)
         {
@@ -1020,12 +1028,12 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp,
    the key.  The keygrip will be stored at the 20 byte buffer pointed
    to by GRIP.  On error NULL is stored at all return arguments.  */
 gpg_error_t
-convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
+convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
                       unsigned char *grip, const char *prompt,
                       const char *cache_nonce,
                       unsigned char **r_key, char **r_passphrase)
 {
-  return convert_from_openpgp_main (ctrl, s_pgp, grip, prompt,
+  return convert_from_openpgp_main (ctrl, s_pgp, dontcare_exist, grip, prompt,
                                     cache_nonce, NULL,
                                     r_key, r_passphrase);
 }
@@ -1044,20 +1052,32 @@ convert_from_openpgp_native (ctrl_t ctrl,
   if (!passphrase)
     return gpg_error (GPG_ERR_INTERNAL);
 
-  err = convert_from_openpgp_main (ctrl, s_pgp, grip, NULL,
+  err = convert_from_openpgp_main (ctrl, s_pgp, 0, grip, NULL,
                                    NULL, passphrase,
                                    r_key, NULL);
 
   /* On success try to re-write the key.  */
   if (!err)
     {
-      unsigned char *protectedkey = NULL;
-      size_t protectedkeylen;
-
-      if (!agent_protect (*r_key, passphrase, &protectedkey, &protectedkeylen,
-                          ctrl->s2k_count))
-        agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
-      xfree (protectedkey);
+      if (*passphrase)
+        {
+          unsigned char *protectedkey = NULL;
+          size_t protectedkeylen;
+
+          if (!agent_protect (*r_key, passphrase,
+                              &protectedkey, &protectedkeylen,
+                              ctrl->s2k_count, -1))
+            agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
+          xfree (protectedkey);
+        }
+      else
+        {
+          /* Empty passphrase: write key without protection.  */
+          agent_write_private_key (grip,
+                                   *r_key,
+                                   gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
+                                   1);
+        }
     }
 
   return err;
@@ -1092,36 +1112,14 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey,
   ndata = 20; /* Space for the SHA-1 checksum.  */
   for (i = npkey, j = 0; i < nskey; i++, j++ )
     {
-      if (gcry_mpi_get_flag (array[i], GCRYMPI_FLAG_OPAQUE))
-        {
-          const void *s;
-          unsigned int n;
-
-          s = gcry_mpi_get_opaque (array[i], &n);
-          nbits[j] = n;
-          n = (n+7)/8;
-          narr[j] = n;
-          bufarr[j] = gcry_is_secure (s)? xtrymalloc_secure (n):xtrymalloc (n);
-          if (!bufarr[j])
-            {
-              err = gpg_error_from_syserror ();
-              for (i = 0; i < j; i++)
-                xfree (bufarr[i]);
-              return err;
-            }
-          memcpy (bufarr[j], s, n);
-        }
-      else
+      err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]);
+      if (err)
         {
-          err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]);
-          if (err)
-            {
-              for (i = 0; i < j; i++)
-                xfree (bufarr[i]);
-              return err;
-            }
-          nbits[j] = gcry_mpi_get_nbits (array[i]);
+          for (i = 0; i < j; i++)
+            xfree (bufarr[i]);
+          return err;
         }
+      nbits[j] = gcry_mpi_get_nbits (array[i]);
       ndata += 2 + narr[j];
     }
 
@@ -1187,13 +1185,15 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey,
  * R_NSKEY is pointer to number of private key data.
  * R_ELEMS is static string which is no need to free by caller.
  * ARRAY contains public and private key data.
+ * ARRAYSIZE is the allocated size of the array for cross-checking.
  * R_CURVE is pointer to S-Expression of the curve (can be NULL).
  * R_FLAGS is pointer to S-Expression of the flags (can be NULL).
  */
 gpg_error_t
 extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
                      const char **r_algoname, int *r_npkey, int *r_nskey,
-                     const char **r_elems, gcry_mpi_t *array,
+                     const char **r_elems,
+                     gcry_mpi_t *array, int arraysize,
                      gcry_sexp_t *r_curve, gcry_sexp_t *r_flags)
 {
   gpg_error_t err;
@@ -1204,6 +1204,9 @@ extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
   gcry_sexp_t curve = NULL;
   gcry_sexp_t flags = NULL;
 
+  *r_curve = NULL;
+  *r_flags = NULL;
+
   if (!req_private_key_data)
     {
       list = gcry_sexp_find_token (s_key, "shadowed-private-key", 0 );
@@ -1231,6 +1234,9 @@ extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
       return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
     }
 
+  if (arraysize < 7)
+    BUG ();
+
   /* Map NAME to a name as used by Libgcrypt.  We do not use the
      Libgcrypt function here because we need a lowercase name and
      require special treatment for some algorithms.  */
@@ -1265,56 +1271,16 @@ extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
                                      array+0, array+1, array+2, array+3,
                                      array+4, NULL);
     }
-  else if (!strcmp (name, "ecc"))
+  else if (!strcmp (name, "ecc") || !strcmp (name, "ecdsa"))
     {
       algoname = "ecc";
-      format = "/qd?";
+      format = "qd?";
       npkey = 1;
       nskey = 2;
       curve = gcry_sexp_find_token (list, "curve", 0);
       flags = gcry_sexp_find_token (list, "flags", 0);
       err = gcry_sexp_extract_param (list, NULL, format,
                                      array+0, array+1, NULL);
-      if (flags)
-        {
-          gcry_sexp_t param = gcry_sexp_find_token (flags, "param", 0);
-          if (param)
-            {
-              gcry_sexp_release (param);
-              array[6] = array[0];
-              array[7] = array[1];
-              err = gcry_sexp_extract_param (list, NULL, "pabgnh?",
-                                             array+0, array+1, array+2, array+3,
-                                             array+4, array+5, NULL);
-              if (array[5] == NULL)
-                {
-                  array[5] = GCRYMPI_CONST_ONE;
-                  npkey += 6;
-                  nskey += 6;
-                }
-              format = "pabgnhqd?";
-            }
-        }
-    }
-  else if (!strcmp (name, "ecdsa"))
-    {
-      algoname = "ecdsa";
-      format = "pabgnqd?";
-      npkey = 6;
-      nskey = 7;
-      err = gcry_sexp_extract_param (list, NULL, format,
-                                     array+0, array+1, array+2, array+3,
-                                     array+4, array+5, array+6, NULL);
-    }
-  else if (!strcmp (name, "ecdh"))
-    {
-      algoname = "ecdh";
-      format = "pabgnqd?";
-      npkey = 6;
-      nskey= 7;
-      err = gcry_sexp_extract_param (list, NULL, format,
-                                     array+0, array+1, array+2, array+3,
-                                     array+4, array+5, array+6, NULL);
     }
   else
     {
@@ -1332,12 +1298,7 @@ extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
     {
       *r_algoname = algoname;
       if (r_elems)
-        {
-          if (format[0] == '/') /* It is opaque data qualifier, skip it.  */
-            *r_elems = format+1;
-          else
-            *r_elems = format;
-        }
+        *r_elems = format;
       *r_npkey = npkey;
       if (r_nskey)
         *r_nskey = nskey;
@@ -1375,7 +1336,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
     array[i] = NULL;
 
   err = extract_private_key (s_key, 1, &algoname, &npkey, &nskey, NULL,
-                             array, &curve, &flags);
+                             array, DIM (array), &curve, &flags);
   if (err)
     return err;