gpg: Install the current release signing pubkey.
[gnupg.git] / g10 / export.c
index 1eb0baa..6a921c1 100644 (file)
@@ -1,6 +1,7 @@
 /* export.c - Export keys in the OpenPGP defined format.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  *               2005, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2014  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -107,7 +108,7 @@ export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users,
                       kbnode_t *keyblock_out, unsigned int options )
 {
   int any, rc;
-  
+
   rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any);
   if (!rc && !any)
     rc = -1;
@@ -197,10 +198,10 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
   int any, rc;
   armor_filter_context_t *afx = NULL;
   compress_filter_context_t zfx;
-  
+
   memset( &zfx, 0, sizeof zfx);
-  
-  rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, &out );
+
+  rc = open_outfile (-1, NULL, 0, !!secret, &out );
   if (rc)
     return rc;
 
@@ -212,8 +213,6 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options )
           afx->what = secret? 5 : 1;
           push_armor_filter (afx, out);
         }
-      if ( opt.compress_keys )
-        push_compress_filter (out,&zfx,default_compress_algo());
     }
 
   rc = do_export_stream (ctrl, out, users, secret, NULL, options, &any );
@@ -251,7 +250,7 @@ subkey_in_list_p (subkey_list_t list, KBNODE node)
       u32 kid[2];
 
       keyid_from_pk (node->pkt->pkt.public_key, kid);
-      
+
       for (; list; list = list->next)
         if (list->kid[0] == kid[0] && list->kid[1] == kid[1])
           return 1;
@@ -293,17 +292,17 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
     case KEYDB_SEARCH_MODE_LONG_KID:
       keyid_from_pk (node->pkt->pkt.public_key, kid);
       break;
-      
+
     case KEYDB_SEARCH_MODE_FPR16:
     case KEYDB_SEARCH_MODE_FPR20:
     case KEYDB_SEARCH_MODE_FPR:
       fingerprint_from_pk (node->pkt->pkt.public_key, fpr,&fprlen);
       break;
-      
+
     default:
       break;
     }
-  
+
   switch(desc->mode)
     {
     case KEYDB_SEARCH_MODE_SHORT_KID:
@@ -338,23 +337,26 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
 /* Return a canonicalized public key algoithms.  This is used to
    compare different flavors of algorithms (e.g. ELG and ELG_E are
    considered the same).  */
-static int
-canon_pubkey_algo (int algo)
+static enum gcry_pk_algos
+canon_pk_algo (enum gcry_pk_algos algo)
 {
   switch (algo)
     {
     case GCRY_PK_RSA:
     case GCRY_PK_RSA_E:
     case GCRY_PK_RSA_S: return GCRY_PK_RSA;
-    case GCRY_PK_ELG:   
+    case GCRY_PK_ELG:
     case GCRY_PK_ELG_E: return GCRY_PK_ELG;
+    case GCRY_PK_ECC:
+    case GCRY_PK_ECDSA:
+    case GCRY_PK_ECDH: return GCRY_PK_ECC;
     default: return algo;
     }
 }
 
 
 /* Use the key transfer format given in S_PGP to create the secinfo
-   structure in PK and chnage the parameter array in PK to include the
+   structure in PK and change the parameter array in PK to include the
    secret parameters.  */
 static gpg_error_t
 transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
@@ -362,12 +364,13 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   gpg_error_t err;
   gcry_sexp_t top_list;
   gcry_sexp_t list = NULL;
+  char *curve = NULL;
   const char *value;
   size_t valuelen;
   char *string;
   int  idx;
   int  is_v4, is_protected;
-  int  pubkey_algo;
+  enum gcry_pk_algos pk_algo;
   int  protect_algo = 0;
   char iv[16];
   int  ivlen = 0;
@@ -375,12 +378,13 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   int  s2k_algo = 0;
   byte s2k_salt[8];
   u32  s2k_count = 0;
+  int  is_ecdh = 0;
   size_t npkey, nskey;
   gcry_mpi_t skey[10];  /* We support up to 9 parameters.  */
-  u16 desired_csum;
   int skeyidx = 0;
   struct seckey_info *ski;
 
+  /* gcry_log_debugsxp ("transferkey", s_pgp); */
   top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
   if (!top_list)
     goto bad_seckey;
@@ -415,7 +419,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
         goto bad_seckey;
       protect_algo = gcry_cipher_map_name (string);
       xfree (string);
-      
+
       value = gcry_sexp_nth_data (list, 3, &valuelen);
       if (!value || !valuelen || valuelen > sizeof iv)
         goto bad_seckey;
@@ -446,6 +450,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
       xfree (string);
     }
 
+  /* Parse the gcrypt PK algo and check that it is okay.  */
   gcry_sexp_release (list);
   list = gcry_sexp_find_token (top_list, "algo", 0);
   if (!list)
@@ -453,14 +458,52 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   string = gcry_sexp_nth_string (list, 1);
   if (!string)
     goto bad_seckey;
-  pubkey_algo = gcry_pk_map_name (string);
-  xfree (string);
-
-  if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
-      || gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
+  pk_algo = gcry_pk_map_name (string);
+  xfree (string); string = NULL;
+  if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
+      || gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
       || !npkey || npkey >= nskey || nskey > PUBKEY_MAX_NSKEY)
     goto bad_seckey;
 
+  /* Check that the pubkey algo matches the one from the public key.  */
+  switch (canon_pk_algo (pk_algo))
+    {
+    case GCRY_PK_RSA:
+      if (!is_RSA (pk->pubkey_algo))
+        pk_algo = 0;  /* Does not match.  */
+      break;
+    case GCRY_PK_DSA:
+      if (!is_DSA (pk->pubkey_algo))
+        pk_algo = 0;  /* Does not match.  */
+      break;
+    case GCRY_PK_ELG:
+      if (!is_ELGAMAL (pk->pubkey_algo))
+        pk_algo = 0;  /* Does not match.  */
+      break;
+    case GCRY_PK_ECC:
+      if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
+        ;
+      else if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
+        is_ecdh = 1;
+      else if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)
+        ;
+      else
+        pk_algo = 0;  /* Does not match.  */
+      /* For ECC we do not have the domain parameters thus fix our info.  */
+      npkey = 1;
+      nskey = 2;
+      break;
+    default:
+      pk_algo = 0;   /* Oops.  */
+      break;
+    }
+  if (!pk_algo)
+    {
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      goto leave;
+    }
+
+  /* Parse the key parameters.  */
   gcry_sexp_release (list);
   list = gcry_sexp_find_token (top_list, "skey", 0);
   if (!list)
@@ -507,21 +550,30 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
     }
   skey[skeyidx++] = NULL;
 
-  gcry_sexp_release (list);
-  list = gcry_sexp_find_token (top_list, "csum", 0);
+  gcry_sexp_release (list); list = NULL;
+
+  /* We have no need for the CSUM value thus we don't parse it.  */
+  /* list = gcry_sexp_find_token (top_list, "csum", 0); */
+  /* if (list) */
+  /*   { */
+  /*     string = gcry_sexp_nth_string (list, 1); */
+  /*     if (!string) */
+  /*       goto bad_seckey; */
+  /*     desired_csum = strtoul (string, NULL, 10); */
+  /*     xfree (string); */
+  /*   } */
+  /* else */
+  /*   desired_csum = 0; */
+  /* gcry_sexp_release (list); list = NULL; */
+
+  /* Get the curve name if any,  */
+  list = gcry_sexp_find_token (top_list, "curve", 0);
   if (list)
     {
-      string = gcry_sexp_nth_string (list, 1);
-      if (!string)
-        goto bad_seckey;
-      desired_csum = strtoul (string, NULL, 10);
-      xfree (string);
+      curve = gcry_sexp_nth_string (list, 1);
+      gcry_sexp_release (list); list = NULL;
     }
-  else
-    desired_csum = 0;
-
 
-  gcry_sexp_release (list); list = NULL;
   gcry_sexp_release (top_list); top_list = NULL;
 
   /* log_debug ("XXX is_v4=%d\n", is_v4); */
@@ -557,17 +609,72 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
       goto leave;
     }
 
-  /* Do some sanity checks.  */
-  if (s2k_count <= 1024)
+  /* We need to change the received parameters for ECC algorithms.
+     The transfer format has the curve name and the parameters
+     separate.  We put them all into the SKEY array.  */
+  if (canon_pk_algo (pk_algo) == GCRY_PK_ECC)
     {
-      /* The count must be larger so that encode_s2k_iterations does
-         not fall into a backward compatibility mode.  */
-      err = gpg_error (GPG_ERR_INV_DATA);
-      goto leave;
+      const char *oidstr;
+
+      /* Assert that all required parameters are available.  We also
+         check that the array does not contain more parameters than
+         needed (this was used by some beta versions of 2.1.  */
+      if (!curve || !skey[0] || !skey[1] || skey[2])
+        {
+          err = gpg_error (GPG_ERR_INTERNAL);
+          goto leave;
+        }
+
+      oidstr = openpgp_curve_to_oid (curve, NULL);
+      if (!oidstr)
+        {
+          log_error ("no OID known for curve '%s'\n", curve);
+          err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+          goto leave;
+        }
+      /* Put the curve's OID into into the MPI array.  This requires
+         that we shift Q and D.  For ECDH also insert the KDF parms. */
+      if (is_ecdh)
+        {
+          skey[4] = NULL;
+          skey[3] = skey[1];
+          skey[2] = gcry_mpi_copy (pk->pkey[2]);
+        }
+      else
+        {
+          skey[3] = NULL;
+          skey[2] = skey[1];
+        }
+      skey[1] = skey[0];
+      skey[0] = NULL;
+      err = openpgp_oid_from_str (oidstr, skey + 0);
+      if (err)
+        goto leave;
+      /* Fixup the NPKEY and NSKEY to match OpenPGP reality.  */
+      npkey = 2 + is_ecdh;
+      nskey = 3 + is_ecdh;
+
+      /* for (idx=0; skey[idx]; idx++) */
+      /*   { */
+      /*     log_info ("YYY skey[%d]:", idx); */
+      /*     if (gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)) */
+      /*       { */
+      /*         void *p; */
+      /*         unsigned int nbits; */
+      /*         p = gcry_mpi_get_opaque (skey[idx], &nbits); */
+      /*         log_printhex (NULL, p, (nbits+7)/8); */
+      /*       } */
+      /*     else */
+      /*       gcry_mpi_dump (skey[idx]); */
+      /*     log_printf ("\n"); */
+      /*   } */
     }
-  if (canon_pubkey_algo (pubkey_algo) != canon_pubkey_algo (pk->pubkey_algo))
+
+  /* Do some sanity checks.  */
+  if (s2k_count > 255)
     {
-      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      /* We expect an already encoded S2K count.  */
+      err = gpg_error (GPG_ERR_INV_DATA);
       goto leave;
     }
   err = openpgp_cipher_test_algo (protect_algo);
@@ -576,12 +683,11 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   err = openpgp_md_test_algo (s2k_algo);
   if (err)
     goto leave;
-  
-  /* Check that the public key parameters match.  */
+
+  /* Check that the public key parameters match.  Note that since
+     Libgcrypt 1.5 gcry_mpi_cmp handles opaque MPI correctly.  */
   for (idx=0; idx < npkey; idx++)
-    if (gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE)
-        || gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE)
-        || gcry_mpi_cmp (pk->pkey[idx], skey[idx]))
+    if (gcry_mpi_cmp (pk->pkey[idx], skey[idx]))
       {
         err = gpg_error (GPG_ERR_BAD_PUBKEY);
         goto leave;
@@ -607,7 +713,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
       err = gpg_error_from_syserror ();
       goto leave;
     }
-  
+
   ski->is_protected = 1;
   ski->sha1chk = 1;
   ski->algo = protect_algo;
@@ -615,7 +721,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   ski->s2k.hash_algo = s2k_algo;
   assert (sizeof ski->s2k.salt == sizeof s2k_salt);
   memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt);
-  ski->s2k.count = encode_s2k_iterations (s2k_count);
+  ski->s2k.count = s2k_count;
   assert (ivlen <= sizeof ski->iv);
   memcpy (ski->iv, iv, ivlen);
   ski->ivlen = ivlen;
@@ -627,6 +733,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   /* That's it.  */
 
  leave:
+  gcry_free (curve);
   gcry_sexp_release (list);
   gcry_sexp_release (top_list);
   for (idx=0; idx < skeyidx; idx++)
@@ -636,7 +743,7 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
  bad_seckey:
   err = gpg_error (GPG_ERR_BAD_SECKEY);
   goto leave;
-  
+
  outofmem:
   err = gpg_error (GPG_ERR_ENOMEM);
   goto leave;
@@ -671,7 +778,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   init_packet (&pkt);
   kdbhd = keydb_new ();
 
-  if (!users) 
+  if (!users)
     {
       ndesc = 1;
       desc = xcalloc (ndesc, sizeof *desc);
@@ -679,13 +786,13 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
     }
   else
     {
-      for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++) 
+      for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
         ;
       desc = xmalloc ( ndesc * sizeof *desc);
-        
+
       for (ndesc=0, sl=users; sl; sl = sl->next)
         {
-          if (!(err=classify_user_id (sl->d, desc+ndesc)))
+          if (!(err=classify_user_id (sl->d, desc+ndesc, 1)))
             ndesc++;
           else
             log_error (_("key \"%s\" not found: %s\n"),
@@ -708,7 +815,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
       goto leave;
     }
 #endif
-  
+
   /* For secret key export we need to setup a decryption context.  */
   if (secret)
     {
@@ -721,7 +828,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           log_error ("error getting the KEK: %s\n", gpg_strerror (err));
           goto leave;
         }
-      
+
       /* Prepare a cipher context.  */
       err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
                               GCRY_CIPHER_MODE_AESWRAP, 0);
@@ -737,20 +844,20 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
       kek = NULL;
     }
 
-  while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) 
+  while (!(err = keydb_search (kdbhd, desc, ndesc, &descindex)))
     {
       int skip_until_subkey = 0;
       u32 keyid[2];
       PKT_public_key *pk;
 
-      if (!users) 
+      if (!users)
         desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
 
       /* Read the keyblock. */
       release_kbnode (keyblock);
       keyblock = NULL;
       err = keydb_get_keyblock (kdbhd, &keyblock);
-      if (err) 
+      if (err)
         {
           log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
           goto leave;
@@ -762,6 +869,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           log_error ("public key packet not found in keyblock - skipped\n");
           continue;
         }
+      setup_main_keyids (keyblock);  /* gpg_format_keydesc needs it.  */
       pk = node->pkt->pkt.public_key;
       keyid_from_pk (pk, keyid);
 
@@ -802,7 +910,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
         clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
 
       /* And write it. */
-      for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) 
+      for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
         {
           if (skip_until_subkey)
             {
@@ -835,7 +943,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                      subkey and include that subkey into the output
                      too.  Need to add this subkey to a list so that
                      it won't get processed a second time.
-                   
+
                      So the first step here is to check that list and
                      skip in any case if the key is in that list.
 
@@ -843,7 +951,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                      function of GnuPG < 2.1 is not able to merge
                      secret keys and thus it is useless to output them
                      as two separate keys and have import merge them.  */
-                  if (subkey_in_list_p (subkey_list, node))  
+                  if (subkey_in_list_p (subkey_list, node))
                     skip_until_subkey = 1; /* Already processed this one. */
                   else
                     {
@@ -854,7 +962,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                             && exact_subkey_match_p (desc+j, node))
                           break;
                       if (!(j < ndesc))
-                        skip_until_subkey = 1; /* No other one matching. */ 
+                        skip_until_subkey = 1; /* No other one matching. */
                     }
                 }
 
@@ -885,7 +993,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                   && node->pkt->pkt.signature->revkey)
                 {
                   int i;
-                  
+
                   for (i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
                     if ( (node->pkt->pkt.signature->revkey[i]->class & 0x40))
                       break;
@@ -904,7 +1012,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                 or a signature on an attrib */
              while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE)
                 kbctx = kbctx->next;
+
              continue;
            }
 
@@ -913,7 +1021,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
             {
               u32 subkidbuf[2], *subkid;
               char *hexgrip, *serialno;
-              
+
               pk = node->pkt->pkt.public_key;
               if (node->pkt->pkttype == PKT_PUBLIC_KEY)
                 subkid = NULL;
@@ -930,7 +1038,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                   skip_until_subkey = 1;
                   continue;
                 }
-              
+
               err = hexkeygrip_from_pk (pk, &hexgrip);
               if (err)
                 {
@@ -970,7 +1078,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                   /* Create a key stub.  */
                   struct seckey_info *ski;
                   const char *s;
-                  
+
                   pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
                   if (!ski)
                     {
@@ -989,7 +1097,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                            ski->ivlen++, s += 2)
                         ski->iv[ski->ivlen] = xtoi_2 (s);
                     }
-                  
+
                   if ((options&EXPORT_SEXP_FORMAT))
                     err = build_sexp (out, node->pkt, &indent);
                   else
@@ -1009,8 +1117,13 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                     log_info ("key %s: asking agent for the secret parts\n",
                               keystr_with_sub (keyid, subkid));
 
-                  err = agent_export_key (ctrl, hexgrip, "Key foo", NULL,
-                                          &wrappedkey, &wrappedkeylen);
+                  {
+                    char *prompt = gpg_format_keydesc (pk,
+                                                       FORMAT_KEYDESC_EXPORT,1);
+                    err = agent_export_key (ctrl, hexgrip, prompt, NULL,
+                                            &wrappedkey, &wrappedkeylen);
+                    xfree (prompt);
+                  }
                   if (err)
                     goto unwraperror;
                   if (wrappedkeylen < 24)
@@ -1032,7 +1145,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                   realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
                   if (!realkeylen)
                     goto unwraperror; /* Invalid csexp.  */
-                  
+
                   err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
                   xfree (key);
                   key = NULL;
@@ -1119,7 +1232,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
         iobuf_put (out, ')');
       iobuf_put (out, '\n');
     }
-  if (err == -1)
+  if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
     err = 0;
 
  leave:
@@ -1252,7 +1365,7 @@ build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent)
 
 /* For some packet types we write them in a S-expression format.  This
    is still EXPERIMENTAL and subject to change.  */
-static int 
+static int
 build_sexp (iobuf_t out, PACKET *pkt, int *indent)
 {
   int rc;