[svn] GnuPG - r5408 - in trunk: . agent g10

svn author wk cvs at cvs.gnupg.org
Tue Aug 31 17:58:42 CEST 2010


Author: wk
Date: 2010-08-31 17:58:39 +0200 (Tue, 31 Aug 2010)
New Revision: 5408

Added:
   trunk/agent/cvt-openpgp.c
   trunk/agent/cvt-openpgp.h
Modified:
   trunk/NEWS
   trunk/agent/ChangeLog
   trunk/agent/Makefile.am
   trunk/agent/agent.h
   trunk/agent/command.c
   trunk/agent/findkey.c
   trunk/agent/keyformat.txt
   trunk/agent/pksign.c
   trunk/agent/protect.c
   trunk/g10/ChangeLog
   trunk/g10/call-agent.c
   trunk/g10/call-agent.h
   trunk/g10/gpg.c
   trunk/g10/import.c
   trunk/g10/keydb.h
   trunk/g10/keyid.c
   trunk/g10/keyserver.c
   trunk/g10/main.h
   trunk/g10/misc.c
   trunk/g10/options.h
   trunk/g10/pkglue.c
Log:
Import OpenPGP keys into the agent.


[The diff below has been truncated]

Modified: trunk/agent/ChangeLog
===================================================================
--- trunk/agent/ChangeLog	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/ChangeLog	2010-08-31 15:58:39 UTC (rev 5408)
@@ -1,3 +1,18 @@
+2010-08-31  Werner Koch  <wk at g10code.com>
+
+	* pksign.c (do_encode_dsa): Fix sign problem.
+	* findkey.c (agent_is_dsa_key): Adjust to actual usage.
+
+2010-08-30  Werner Koch  <wk at g10code.com>
+
+	* protect.c (s2k_hash_passphrase): New public function.
+
+2010-08-27  Werner Koch  <wk at g10code.com>
+
+	* command.c (cmd_import_key): Support OpenPGP keys.
+	* cvt-openpgp.h, cvt-openpgp.c: New.  Some of the code is based on
+	code taken from g10/seckey-cert.c.
+
 2010-08-26  Werner Koch  <wk at g10code.com>
 
 	* command-ssh.c (open_control_file): Use estream to create the file.

Modified: trunk/g10/ChangeLog
===================================================================
--- trunk/g10/ChangeLog	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/g10/ChangeLog	2010-08-31 15:58:39 UTC (rev 5408)
@@ -1,3 +1,32 @@
+2010-08-30  Werner Koch  <wk at g10code.com>
+
+	* keyid.c (KEYID_STR_SIZE): New
+	(keystr): Use snprintf and new macro.
+	(keystr_with_sub): New.
+	(keystr_from_sk_with_sub): New.
+	(keystr_from_pk_with_sub): New.
+
+2010-08-27  Werner Koch  <wk at g10code.com>
+
+	* gpg.c (main): Change scope of CTRL to the entire function.
+
+	* import.c (import_secret_one, import, import_keys_internal)
+	(import_keys, import_keys_stream): Add arg CTRL.
+	* call-agent.c (agent_keywrap_key): New.
+	(agent_import_key, inq_import_key_parms): New.
+
+2010-08-26  Werner Koch  <wk at g10code.com>
+
+	* misc.c (openpgp_pk_algo_name): New.
+	(openpgp_md_algo_name): New.
+
+2010-08-24  Werner Koch  <wk at g10code.com>
+
+	* options.h (IMPORT_SK2PK): Remove.
+	* import.c (parse_import_options): Turn convert-sk-to-pk into a
+	dummy option.
+	(sec_to_pub_keyblock): Use modern functions.
+
 2010-08-16  Werner Koch  <wk at g10code.com>
 
 	* gpg.c (list_config, gpgconf_list): Use es_printf.

Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/NEWS	2010-08-31 15:58:39 UTC (rev 5408)
@@ -37,7 +37,11 @@
 
  * Fixed output of "gpgconf --check-options".
 
+ * GPG does not anymore use secring.gpg but delegates all secret key
+   operations to gpg-agent.  The import command moves secret keys to
+   the agent.
 
+
 Noteworthy changes in version 2.0.13 (2009-09-04)
 -------------------------------------------------
 

Modified: trunk/agent/Makefile.am
===================================================================
--- trunk/agent/Makefile.am	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/Makefile.am	2010-08-31 15:58:39 UTC (rev 5408)
@@ -46,6 +46,7 @@
 	protect.c \
 	trustlist.c \
 	divert-scd.c \
+	cvt-openpgp.c cvt-openpgp.h \
 	call-scd.c \
 	learncard.c
 

Modified: trunk/agent/agent.h
===================================================================
--- trunk/agent/agent.h	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/agent.h	2010-08-31 15:58:39 UTC (rev 5408)
@@ -171,8 +171,8 @@
   int with_qualitybar; /* Set if the quality bar should be displayed.  */
   int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
   void *check_cb_arg;  /* optional argument which might be of use in the CB */
-  const char *cb_errtext; /* used by the cb to displaye a specific error */
-  size_t max_length; /* allocated length of the buffer */
+  const char *cb_errtext; /* used by the cb to display a specific error */
+  size_t max_length;      /* allocated length of the buffer */
   char pin[1];
 };
 
@@ -306,6 +306,11 @@
                            unsigned char const **shadow_info);
 gpg_error_t parse_shadow_info (const unsigned char *shadow_info, 
                                char **r_hexsn, char **r_idstr);
+gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
+                                 int s2kmode,
+                                 const unsigned char *s2ksalt,
+                                 unsigned int s2kcount,
+                                 unsigned char *key, size_t keylen);
 
 
 /*-- trustlist.c --*/

Modified: trunk/agent/command.c
===================================================================
--- trunk/agent/command.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/command.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -37,9 +37,9 @@
 #include "agent.h"
 #include <assuan.h>
 #include "i18n.h"
+#include "cvt-openpgp.h"
 
 
-
 /* Maximum allowed size of the inquired ciphertext.  */
 #define MAXLEN_CIPHERTEXT 4096
 /* Maximum allowed size of the key parameters.  */
@@ -357,6 +357,12 @@
       const char *name = assuan_get_command_name (ctx);
       if (!name)
         name = "?";
+
+      /* Most code from common/ does not know the error source, thus
+         we fix this here.  */
+      if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
+        err = gpg_err_make (GPG_ERR_SOURCE_DEFAULT, gpg_err_code (err));
+
       if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
         log_error ("command '%s' failed: %s\n", name,
                    gpg_strerror (err));
@@ -566,8 +572,8 @@
 static const char hlp_setkeydesc[] = 
   "SETKEYDESC plus_percent_escaped_string\n"
   "\n"
-  "Set a description to be used for the next PKSIGN, PKDECRYPT or EXPORT_KEY\n"
-  "operation if this operation requires the entry of a passphrase.  If\n"
+  "Set a description to be used for the next PKSIGN, PKDECRYPT, IMPORT_KEY\n"
+  "or EXPORT_KEY operation if this operation requires a passphrase.  If\n"
   "this command is not used a default text will be used.  Note, that\n"
   "this description implictly selects the label used for the entry\n"
   "box; if the string contains the string PIN (which in general will\n"
@@ -575,8 +581,8 @@
   "\"passphrase\" is used.  The description string should not contain\n"
   "blanks unless they are percent or '+' escaped.\n"
   "\n"
-  "The description is only valid for the next PKSIGN, PKDECRYPT or\n"
-  "EXPORT_KEY operation.";
+  "The description is only valid for the next PKSIGN, PKDECRYPT,\n"
+  "IMPORT_KEY or EXPORT_KEY operation.";
 static gpg_error_t
 cmd_setkeydesc (assuan_context_t ctx, char *line)
 {
@@ -1478,6 +1484,7 @@
   unsigned char *finalkey = NULL;
   size_t finalkeylen;
   unsigned char grip[20];
+  gcry_sexp_t openpgp_sexp = NULL;
   
   (void)line;
 
@@ -1528,21 +1535,59 @@
   
   err = keygrip_from_canon_sexp (key, realkeylen, grip);
   if (err)
-    goto leave;
+    {
+      /* This might be due to an unsupported S-expression format.
+         Check whether this is openpgp-private-key and trigger that
+         import code.  */
+      if (!gcry_sexp_sscan (&openpgp_sexp, NULL, key, realkeylen))
+        {
+          const char *tag;
+          size_t taglen;
+          
+          tag = gcry_sexp_nth_data (openpgp_sexp, 0, &taglen);
+          if (tag && taglen == 19 && !memcmp (tag, "openpgp-private-key", 19))
+            ;
+          else
+            {
+              gcry_sexp_release (openpgp_sexp);
+              openpgp_sexp = NULL;
+            }
+        }
+      if (!openpgp_sexp)
+        goto leave; /* Note that ERR is still set.  */
+    }
 
-  if (!agent_key_available (grip))
+
+  if (openpgp_sexp)
     {
-      err = gpg_error (GPG_ERR_EEXIST);
-      goto leave;
+      /* In most cases the key is encrypted and thus the conversion
+         function from the OpenPGP format to our internal format will
+         ask for a passphrase.  That passphrase will be returned and
+         used to protect the key using the same code as for regular
+         key import. */
+      
+      err = convert_openpgp (ctrl, openpgp_sexp, grip,
+                             ctrl->server_local->keydesc,
+                             &key, &passphrase);
+      if (err)
+        goto leave;
+      realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
+      if (!realkeylen)
+        goto leave; /* Invalid canonical encoded S-expression.  */
     }
+  else
+    {
+      if (!agent_key_available (grip))
+        err = gpg_error (GPG_ERR_EEXIST);
+      else
+        err = agent_ask_new_passphrase 
+          (ctrl, _("Please enter the passphrase to protect the "
+                   "imported object within the GnuPG system."),
+           &passphrase);
+      if (err)
+        goto leave;
+    }
 
-  err = agent_ask_new_passphrase 
-    (ctrl, _("Please enter the passphrase to protect the "
-             "imported object within the GnuPG system."),
-     &passphrase);
-  if (err)
-    goto leave;
-
   if (passphrase)
     {
       err = agent_protect (key, passphrase, &finalkey, &finalkeylen);
@@ -1553,11 +1598,14 @@
     err = agent_write_private_key (grip, key, realkeylen, 0);
 
  leave:
+  gcry_sexp_release (openpgp_sexp);
   xfree (finalkey);
   xfree (passphrase);
   xfree (key);
   gcry_cipher_close (cipherhd);
   xfree (wrappedkey);
+  xfree (ctrl->server_local->keydesc);
+  ctrl->server_local->keydesc = NULL;
   return leave_cmd (ctx, err);
 }
 

Added: trunk/agent/cvt-openpgp.c
===================================================================
--- trunk/agent/cvt-openpgp.c	                        (rev 0)
+++ trunk/agent/cvt-openpgp.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -0,0 +1,807 @@
+/* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
+ *               2010 Free Software Foundation, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "agent.h"
+#include "i18n.h"
+#include "cvt-openpgp.h"
+
+
+/* Helper to pass data via the callback to do_unprotect. */
+struct try_do_unprotect_arg_s 
+{
+  int  is_v4;
+  int  is_protected;
+  int  pubkey_algo;
+  int  protect_algo;
+  char *iv;
+  int  ivlen;
+  int  s2k_mode;
+  int  s2k_algo;
+  byte *s2k_salt;
+  u32  s2k_count;
+  u16 desired_csum;
+  gcry_mpi_t *skey;
+  size_t skeysize;
+  int skeyidx;
+  gcry_sexp_t *r_key;
+};
+
+
+
+/* Compute the keygrip from the public key and store it at GRIP.  */
+static gpg_error_t
+get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_pkey = NULL;
+
+  switch (pubkey_algo)
+    {
+    case GCRY_PK_DSA:
+      err = 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]);
+      break;
+
+    case GCRY_PK_ELG:
+    case GCRY_PK_ELG_E:
+      err = gcry_sexp_build (&s_pkey, NULL,
+                             "(public-key(elg(p%m)(g%m)(y%m)))",
+                             pkey[0], pkey[1], pkey[2]);
+      break;
+
+    case GCRY_PK_RSA:
+    case GCRY_PK_RSA_E:
+    case GCRY_PK_RSA_S:
+      err = gcry_sexp_build (&s_pkey, NULL,
+                             "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
+      break;
+
+    default:
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      break;
+    }
+
+  if (!err && !gcry_pk_get_keygrip (s_pkey, grip))
+    err = gpg_error (GPG_ERR_INTERNAL);
+
+  gcry_sexp_release (s_pkey);
+  return err;
+}
+
+
+/* Convert a secret key given as algorithm id and an array of key
+   parameters into our s-expression based format.  */
+static gpg_error_t
+convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_skey = NULL;
+
+  *r_key = NULL;
+
+  switch (pubkey_algo)
+    {
+    case GCRY_PK_DSA:
+      err = 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]);
+      break;
+
+    case GCRY_PK_ELG:
+    case GCRY_PK_ELG_E:
+      err = 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]);
+      break;
+
+
+    case GCRY_PK_RSA:
+    case GCRY_PK_RSA_E:
+    case GCRY_PK_RSA_S:
+      err = 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]);
+
+    default:
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      break;
+    }
+
+  if (!err)
+    *r_key = s_skey;
+  return err;
+}
+
+
+
+/* Hash the passphrase and set the key. */
+static gpg_error_t
+hash_passphrase_and_set_key (const char *passphrase,
+                             gcry_cipher_hd_t hd, int protect_algo,
+                             int s2k_mode, int s2k_algo,
+                             byte *s2k_salt, u32 s2k_count)
+{
+  gpg_error_t err;
+  unsigned char *key;
+  size_t keylen;
+
+  keylen = gcry_cipher_get_algo_keylen (protect_algo);
+  if (!keylen)
+    return gpg_error (GPG_ERR_INTERNAL);
+  
+  key = xtrymalloc_secure (keylen);
+  if (!key)
+    return gpg_error_from_syserror ();
+
+  err = s2k_hash_passphrase (passphrase,
+                             s2k_algo, s2k_mode, s2k_salt, s2k_count,
+                             key, keylen);
+  if (!err)
+    err = gcry_cipher_setkey (hd, key, keylen);
+
+  xfree (key);
+  return err;
+}
+
+
+static u16
+checksum (const unsigned char *p, unsigned int n)
+{
+  u16 a;
+  
+  for (a=0; n; n-- )
+    a += *p++;
+  return a;
+}
+
+
+/* Note that this function modified SKEY.  SKEYSIZE is the allocated
+   size of the array including the NULL item; this is used for a
+   bounds check.  On success a converted key is stored at R_KEY.  */
+static int
+do_unprotect (const char *passphrase,
+              int pkt_version, int pubkey_algo, int is_protected,
+              gcry_mpi_t *skey, size_t skeysize,
+              int protect_algo, void *protect_iv, size_t protect_ivlen,
+              int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count,
+              u16 desired_csum, gcry_sexp_t *r_key)
+{
+  gpg_error_t err;
+  size_t npkey, nskey, skeylen;
+  gcry_cipher_hd_t cipher_hd = NULL;
+  u16 actual_csum;
+  size_t nbytes;
+  int i;
+  gcry_mpi_t tmpmpi;
+
+  *r_key = NULL;
+
+  /* Count the actual number of MPIs is in the array and set the
+     remainder to NULL for easier processing later on.  */
+  for (skeylen = 0; skey[skeylen]; skeylen++)
+    ;
+  for (i=skeylen; i < skeysize; i++)
+    skey[i] = NULL;
+
+  /* Check some args.  */
+  if (s2k_mode == 1001)
+    {
+      /* Stub key.  */
+      log_info (_("secret key parts are not available\n"));
+      return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
+    }
+
+  if (gcry_pk_test_algo (pubkey_algo))
+    {
+      /* The algorithm numbers are Libgcrypt numbers but fortunately
+         the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
+         numbers.  */
+      log_info (_("public key algorithm %d (%s) is not supported\n"),
+                pubkey_algo, gcry_pk_algo_name (pubkey_algo));
+      return gpg_error (GPG_ERR_PUBKEY_ALGO);
+    }
+
+  /* Get properties of the public key algorithm and do some
+     consistency checks.  Note that we need at least NPKEY+1 elements
+     in the SKEY array. */
+  if ( (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY,
+                                 NULL, &npkey))
+       || (err = gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NSKEY,
+                                    NULL, &nskey)))
+    return err;
+  if (!npkey || npkey >= nskey)
+    return gpg_error (GPG_ERR_INTERNAL);
+  if (skeylen <= npkey)
+    return gpg_error (GPG_ERR_MISSING_VALUE);
+  if (nskey+1 >= skeysize)
+    return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
+  
+  /* Check whether SKEY is at all protected.  If it is not protected
+     merely verify the checksum.  */
+  if (!is_protected)
+    {
+      unsigned char *buffer;
+
+      actual_csum = 0;
+      for (i=npkey; i < nskey; i++)
+        {
+          if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
+            return gpg_error (GPG_ERR_BAD_SECKEY);
+          
+          err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
+          if (!err)
+            {
+              buffer = (gcry_is_secure (skey[i])?
+                        xtrymalloc_secure (nbytes) : xtrymalloc (nbytes));
+              if (!buffer)
+                return gpg_error_from_syserror ();
+              err = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes,
+                                    NULL, skey[i]);
+              if (!err)
+                actual_csum += checksum (buffer, nbytes);
+              xfree (buffer);
+            }
+          if (err)
+            return err;
+        }
+      
+      if (actual_csum != desired_csum)
+        return gpg_error (GPG_ERR_CHECKSUM);
+      return 0;
+    }
+
+
+  if (gcry_cipher_test_algo (protect_algo))
+    {
+      /* The algorithm numbers are Libgcrypt numbers but fortunately
+         the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
+         numbers.  */
+      log_info (_("protection algorithm %d (%s) is not supported\n"),
+                protect_algo, gcry_cipher_algo_name (protect_algo));
+      return gpg_error (GPG_ERR_CIPHER_ALGO);
+    }
+
+  if (gcry_md_test_algo (s2k_algo))
+    {
+      log_info (_("protection hash algorithm %d (%s) is not supported\n"),
+                s2k_algo, gcry_md_algo_name (s2k_algo));
+      return gpg_error (GPG_ERR_DIGEST_ALGO);
+    }
+  
+  err = gcry_cipher_open (&cipher_hd, protect_algo,
+                          GCRY_CIPHER_MODE_CFB,
+                          (GCRY_CIPHER_SECURE
+                           | (protect_algo >= 100 ?
+                              0 : GCRY_CIPHER_ENABLE_SYNC)));
+  if (err)
+    {
+      log_error ("failed to open cipher_algo %d: %s\n",
+                 protect_algo, gpg_strerror (err));
+      return err;
+    }
+
+  err = hash_passphrase_and_set_key (passphrase, cipher_hd, protect_algo,
+                                     s2k_mode, s2k_algo, s2k_salt, s2k_count);
+  if (err)
+    {
+      gcry_cipher_close (cipher_hd);
+      return err;
+    }  
+
+  gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
+  
+  actual_csum = 0;
+  if (pkt_version >= 4)
+    {
+      int ndata;
+      unsigned int ndatabits;
+      unsigned char *p, *data;
+      u16 csum_pgp7 = 0;
+
+      if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE ))
+        {
+          gcry_cipher_close (cipher_hd);
+          return gpg_error (GPG_ERR_BAD_SECKEY);
+        }
+      p = gcry_mpi_get_opaque (skey[npkey], &ndatabits);
+      ndata = (ndatabits+7)/8;
+
+      if (ndata > 1)
+        csum_pgp7 = p[ndata-2] << 8 | p[ndata-1];
+      data = xtrymalloc_secure (ndata);
+      if (!data)
+        {
+          err = gpg_error_from_syserror ();
+          gcry_cipher_close (cipher_hd);
+          return err;
+        }
+      gcry_cipher_decrypt (cipher_hd, data, ndata, p, ndata);
+
+      p = data;
+      if (is_protected == 2)
+        {
+          /* This is the new SHA1 checksum method to detect tampering
+             with the key as used by the Klima/Rosa attack.  */
+          desired_csum = 0; 
+          actual_csum = 1;  /* Default to bad checksum.  */
+
+          if (ndata < 20) 
+            log_error ("not enough bytes for SHA-1 checksum\n");
+          else 
+            {
+              gcry_md_hd_t h;
+              
+              if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
+                BUG(); /* Algo not available. */
+              gcry_md_write (h, data, ndata - 20);
+              gcry_md_final (h);
+              if (!memcmp (gcry_md_read (h, GCRY_MD_SHA1), data+ndata-20, 20))
+                actual_csum = 0; /* Digest does match.  */
+              gcry_md_close (h);
+            }
+        }
+      else 
+        {
+          /* Old 16 bit checksum method.  */
+          if (ndata < 2)
+            {
+              log_error ("not enough bytes for checksum\n");
+              desired_csum = 0; 
+              actual_csum = 1;  /* Mark checksum bad.  */
+            }
+          else
+            {
+              desired_csum = (data[ndata-2] << 8 | data[ndata-1]);
+              actual_csum = checksum (data, ndata-2);
+              if (desired_csum != actual_csum)
+                {
+                  /* This is a PGP 7.0.0 workaround */
+                  desired_csum = csum_pgp7; /* Take the encrypted one.  */
+                }
+            }
+        }
+      
+      /* Better check it here.  Otherwise the gcry_mpi_scan would fail
+         because the length may have an arbitrary value.  */
+      if (desired_csum == actual_csum)
+        {
+          for (i=npkey; i < nskey; i++ )
+            {
+              if (gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, p, ndata, &nbytes))
+                {
+                  /* Checksum was okay, but not correctly decrypted.  */
+                  desired_csum = 0;
+                  actual_csum = 1;   /* Mark checksum bad.  */
+                  break;
+                }
+              gcry_mpi_release (skey[i]);
+              skey[i] = tmpmpi;
+              ndata -= nbytes;
+              p += nbytes;
+            }
+          skey[i] = NULL;
+          skeylen = i;
+          assert (skeylen <= skeysize);
+
+          /* Note: at this point NDATA should be 2 for a simple
+             checksum or 20 for the sha1 digest.  */
+        }
+      xfree(data);
+    }
+  else /* Packet version <= 3.  */
+    {
+      unsigned char *buffer;
+
+      for (i = npkey; i < nskey; i++)
+        {
+          unsigned char *p;
+          size_t ndata;
+          unsigned int ndatabits;
+
+          if (!skey[i] || !gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
+            {
+              gcry_cipher_close (cipher_hd);
+              return gpg_error (GPG_ERR_BAD_SECKEY);
+            }
+          p = gcry_mpi_get_opaque (skey[i], &ndatabits);
+          ndata = (ndatabits+7)/8;
+
+          if (!(ndata >= 2) || !(ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2))
+            {
+              gcry_cipher_close (cipher_hd);
+              return gpg_error (GPG_ERR_BAD_SECKEY);
+            }
+          
+          buffer = xtrymalloc_secure (ndata);
+          if (!buffer)
+            {
+              err = gpg_error_from_syserror ();
+              gcry_cipher_close (cipher_hd);
+              return err;
+            }
+              
+          gcry_cipher_sync (cipher_hd);
+          buffer[0] = p[0];
+          buffer[1] = p[1];
+          gcry_cipher_decrypt (cipher_hd, buffer+2, ndata-2, p+2, ndata-2);
+          actual_csum += checksum (buffer, ndata);
+          err = gcry_mpi_scan (&tmpmpi, GCRYMPI_FMT_PGP, buffer, ndata, &ndata);
+          xfree (buffer);
+          if (err)
+            {
+              /* Checksum was okay, but not correctly decrypted.  */
+              desired_csum = 0;
+              actual_csum = 1;   /* Mark checksum bad.  */
+              break;
+            }
+          gcry_mpi_release (skey[i]);
+          skey[i] = tmpmpi;
+        }
+    }
+  gcry_cipher_close (cipher_hd);
+
+  /* Now let's see whether we have used the correct passphrase. */
+  if (actual_csum != desired_csum)
+    return gpg_error (GPG_ERR_BAD_PASSPHRASE);
+
+  if (nskey != skeylen)
+    err = gpg_error (GPG_ERR_BAD_SECKEY);
+  else
+    err = convert_secret_key (r_key, pubkey_algo, skey);
+  if (err)
+    return err;
+
+  /* The checksum may fail, thus we also check the key itself.  */
+  err = gcry_pk_testkey (*r_key);
+  if (err)
+    {
+      gcry_sexp_release (*r_key);
+      *r_key = NULL;
+      return gpg_error (GPG_ERR_BAD_PASSPHRASE);
+    }
+
+  return 0;
+}
+
+
+/* Callback function to try the unprotection from the passpharse query
+   code.  */
+static int
+try_do_unprotect_cb (struct pin_entry_info_s *pi)
+{
+  gpg_error_t err;
+  struct try_do_unprotect_arg_s *arg = pi->check_cb_arg;
+
+  err = do_unprotect (pi->pin, arg->is_v4? 4:3,
+                      arg->pubkey_algo, arg->is_protected,
+                      arg->skey, arg->skeysize,
+                      arg->protect_algo, arg->iv, arg->ivlen,
+                      arg->s2k_mode, arg->s2k_algo,
+                      arg->s2k_salt, arg->s2k_count,
+                      arg->desired_csum, arg->r_key);
+  /* SKEY may be modified now, thus we need to re-compute SKEYIDX.  */
+  for (arg->skeyidx = 0; (arg->skeyidx < arg->skeysize
+                          && arg->skey[arg->skeyidx]); arg->skeyidx++)
+         ;
+  return err;
+}
+
+
+/* Convert an OpenPGP transfer key into our internal format.  Before
+   asking for a passphrase we check whether the key already exists in
+   our key storage.  S_PGP is the OpenPGP key in transfer format.  On
+   success R_KEY will receive a canonical encoded S-expression with
+   the unprotected key in our internal format; the caller needs to
+   release that memory.  The passphrase used to decrypt the OpenPGP
+   key will be returned at R_PASSPHRASE; the caller must release this
+   passphrase.  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_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, 
+                 unsigned char *grip, const char *prompt,
+                 unsigned char **r_key, char **r_passphrase)
+{
+  gpg_error_t err;
+  gcry_sexp_t top_list;
+  gcry_sexp_t list = NULL;
+  const char *value;
+  size_t valuelen;
+  char *string;
+  int  idx;
+  int  is_v4, is_protected;
+  int  pubkey_algo;
+  int  protect_algo = 0;
+  char iv[16];
+  int  ivlen = 0;
+  int  s2k_mode = 0;
+  int  s2k_algo = 0;
+  byte s2k_salt[8];
+  u32  s2k_count = 0;
+  size_t npkey, nskey;
+  gcry_mpi_t skey[10];  /* We support up to 9 parameters.  */
+  u16 desired_csum;
+  int skeyidx = 0;
+  gcry_sexp_t s_skey;
+  struct pin_entry_info_s *pi;
+  struct try_do_unprotect_arg_s pi_arg;
+
+  *r_key = NULL;
+  *r_passphrase = NULL;
+
+  top_list = gcry_sexp_find_token (s_pgp, "openpgp-private-key", 0);
+  if (!top_list)
+    goto bad_seckey;
+
+  list = gcry_sexp_find_token (top_list, "version", 0);
+  if (!list)
+    goto bad_seckey;
+  value = gcry_sexp_nth_data (list, 1, &valuelen);
+  if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
+    goto bad_seckey;
+  is_v4 = (value[0] == '4');
+
+  gcry_sexp_release (list);
+  list = gcry_sexp_find_token (top_list, "protection", 0);
+  if (!list)
+    goto bad_seckey;
+  value = gcry_sexp_nth_data (list, 1, &valuelen);
+  if (!value)
+    goto bad_seckey;
+  if (valuelen == 4 && !memcmp (value, "sha1", 4))
+    is_protected = 2;
+  else if (valuelen == 3 && !memcmp (value, "sum", 3))
+    is_protected = 1;
+  else if (valuelen == 4 && !memcmp (value, "none", 4))
+    is_protected = 0;
+  else
+    goto bad_seckey;
+  if (is_protected)
+    {
+      string = gcry_sexp_nth_string (list, 2);
+      if (!string)
+        goto bad_seckey;
+      protect_algo = gcry_cipher_map_name (string);
+      if (!protect_algo && !!strcmp (string, "IDEA"))
+        protect_algo = GCRY_CIPHER_IDEA;
+      xfree (string);
+      
+      value = gcry_sexp_nth_data (list, 3, &valuelen);
+      if (!value || !valuelen || valuelen > sizeof iv)
+        goto bad_seckey;
+      memcpy (iv, value, valuelen);
+      ivlen = valuelen;
+
+      string = gcry_sexp_nth_string (list, 4);
+      if (!string)
+        goto bad_seckey;
+      s2k_mode = strtol (string, NULL, 10);
+      xfree (string);
+
+      string = gcry_sexp_nth_string (list, 5);
+      if (!string)
+        goto bad_seckey;
+      s2k_algo = gcry_md_map_name (string);
+      xfree (string);
+
+      value = gcry_sexp_nth_data (list, 6, &valuelen);
+      if (!value || !valuelen || valuelen > sizeof s2k_salt)
+        goto bad_seckey;
+      memcpy (s2k_salt, value, valuelen);
+
+      string = gcry_sexp_nth_string (list, 7);
+      if (!string)
+        goto bad_seckey;
+      s2k_count = strtoul (string, NULL, 10);
+      xfree (string);
+    }
+
+  gcry_sexp_release (list);
+  list = gcry_sexp_find_token (top_list, "algo", 0);
+  if (!list)
+    goto bad_seckey;
+  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)
+      || !npkey || npkey >= nskey)
+    goto bad_seckey;
+
+  gcry_sexp_release (list);
+  list = gcry_sexp_find_token (top_list, "skey", 0);
+  if (!list)
+    goto bad_seckey;
+  for (idx=0;;)
+    {
+      int is_enc;
+
+      value = gcry_sexp_nth_data (list, ++idx, &valuelen);
+      if (!value && skeyidx >= npkey)
+        break;  /* Ready.  */
+
+      /* Check for too many parameters.  Note that depending on the
+         protection mode and version number we may see less than NSKEY
+         (but at least NPKEY+1) parameters.  */
+      if (idx >= 2*nskey)
+        goto bad_seckey;
+      if (skeyidx >= DIM (skey)-1)
+        goto bad_seckey;
+
+      if (!value || valuelen != 1 || !(value[0] == '_' || value[0] == 'e'))
+        goto bad_seckey;
+      is_enc = (value[0] == 'e');
+      value = gcry_sexp_nth_data (list, ++idx, &valuelen);
+      if (!value || !valuelen)
+        goto bad_seckey;
+      if (is_enc)
+        {
+          void *p = xtrymalloc (valuelen);
+          if (!p)
+            goto outofmem;
+          memcpy (p, value, valuelen);
+          skey[skeyidx] = gcry_mpi_set_opaque (NULL, p, valuelen*8);
+          if (!skey[skeyidx])
+            goto outofmem;
+        }
+      else
+        {
+          if (gcry_mpi_scan (skey + skeyidx, GCRYMPI_FMT_STD,
+                             value, valuelen, NULL))
+            goto bad_seckey;
+        }
+      skeyidx++;
+    }
+  skey[skeyidx++] = NULL;
+
+  gcry_sexp_release (list);
+  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;
+  gcry_sexp_release (top_list); top_list = NULL;
+
+  /* log_debug ("XXX is_v4=%d\n", is_v4); */
+  /* 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_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_debug ("XXX s2k_count=%lu\n", (unsigned long)s2k_count); */
+  /* for (idx=0; skey[idx]; idx++) */
+  /*   { */
+  /*     int is_enc = gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE); */
+  /*     log_info ("XXX skey[%d]%s:", idx, is_enc? " (enc)":""); */
+  /*     if (is_enc) */
+  /*       { */
+  /*         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"); */
+  /*   } */
+
+  err = get_keygrip (pubkey_algo, skey, grip);
+  if (err)
+    goto leave;
+
+  if (!agent_key_available (grip))
+    {
+      err = gpg_error (GPG_ERR_EEXIST);
+      goto leave;
+    }
+
+  pi = xtrycalloc_secure (1, sizeof (*pi) + 100);
+  if (!pi)
+    return gpg_error_from_syserror ();
+  pi->max_length = 100;
+  pi->min_digits = 0;  /* We want a real passphrase.  */
+  pi->max_digits = 16;
+  pi->max_tries = 3;
+  pi->check_cb = try_do_unprotect_cb;
+  pi->check_cb_arg = &pi_arg;
+  pi_arg.is_v4 = is_v4;
+  pi_arg.is_protected = is_protected;
+  pi_arg.pubkey_algo = pubkey_algo;
+  pi_arg.protect_algo = protect_algo;
+  pi_arg.iv = iv;
+  pi_arg.ivlen = ivlen;
+  pi_arg.s2k_mode = s2k_mode;
+  pi_arg.s2k_algo = s2k_algo;
+  pi_arg.s2k_salt = s2k_salt;
+  pi_arg.s2k_count = s2k_count;
+  pi_arg.desired_csum = desired_csum;
+  pi_arg.skey = skey;
+  pi_arg.skeysize = DIM (skey);
+  pi_arg.skeyidx = skeyidx;
+  pi_arg.r_key = &s_skey;
+  err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
+  skeyidx = pi_arg.skeyidx;
+  if (!err)
+    {
+      *r_passphrase = xtrystrdup (pi->pin);
+      if (!*r_passphrase)
+        err = gpg_error_from_syserror ();
+    }
+  xfree (pi);
+  if (err)
+    goto leave;
+
+  /* Save some memory and get rid of the SKEY array now.  */
+  for (idx=0; idx < skeyidx; idx++)
+    gcry_mpi_release (skey[idx]);
+  skeyidx = 0;
+
+  /* Note that the padding is not required - we use it only because
+     that function allows us to created the result in secure memory.  */
+  err = make_canon_sexp_pad (s_skey, 1, r_key, NULL);
+  gcry_sexp_release (s_skey);
+
+ leave:
+  gcry_sexp_release (list);
+  gcry_sexp_release (top_list);
+  for (idx=0; idx < skeyidx; idx++)
+    gcry_mpi_release (skey[idx]);
+  if (err)
+    {
+      xfree (*r_passphrase);
+      *r_passphrase = NULL;
+    }
+  return err;
+
+ bad_seckey:
+  err = gpg_error (GPG_ERR_BAD_SECKEY);
+  goto leave;
+  
+ outofmem:
+  err = gpg_error (GPG_ERR_ENOMEM);
+  goto leave;
+
+}
+
+
+

Added: trunk/agent/cvt-openpgp.h
===================================================================
--- trunk/agent/cvt-openpgp.h	                        (rev 0)
+++ trunk/agent/cvt-openpgp.h	2010-08-31 15:58:39 UTC (rev 5408)
@@ -0,0 +1,27 @@
+/* cvt-openpgp.h - Convert an OpenPGP key to our internal format.
+ * Copyright (C) 2010 Free Software Foundation, Inc.
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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/>.
+ */
+#ifndef GNUPG_AGENT_CVT_OPENPGP_H
+#define GNUPG_AGENT_CVT_OPENPGP_H
+
+gpg_error_t convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, 
+                             unsigned char *grip, const char *prompt,
+                             unsigned char **r_key, char **r_passphrase);
+
+
+#endif /*GNUPG_AGENT_CVT_OPENPGP_H*/

Modified: trunk/agent/findkey.c
===================================================================
--- trunk/agent/findkey.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/findkey.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -702,7 +702,8 @@
 }
 
 
-/* Return true if S_KEY is a DSA style key.  */
+/* Return the public key algorithm number if S_KEY is a DSA style key.
+   If it is not a DSA style key, return 0.  */
 int 
 agent_is_dsa_key (gcry_sexp_t s_key)
 {
@@ -714,7 +715,12 @@
   if (key_parms_from_sexp (s_key, NULL, algoname, sizeof algoname, NULL, 0))
     return 0; /* Error - assume it is not an DSA key.  */
 
-  return (!strcmp (algoname, "dsa") || !strcmp (algoname, "ecdsa"));
+  if (!strcmp (algoname, "dsa"))
+    return GCRY_PK_DSA;
+  else if (!strcmp (algoname, "ecdsa"))
+    return GCRY_PK_ECDSA;
+  else
+    return 0;
 }
 
 

Modified: trunk/agent/keyformat.txt
===================================================================
--- trunk/agent/keyformat.txt	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/keyformat.txt	2010-08-31 15:58:39 UTC (rev 5408)
@@ -159,10 +159,37 @@
 More items may be added to the list.
 
 
+OpenPGP Private Key Transfer Format
+===================================
 
+This format is used to transfer keys between gpg and gpg-agent.
 
+(openpgp-private-key
+  (version V)
+  (protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT)
+  (algo PUBKEYALGO)
+  (skey CSUM c P1 c P2 c P3 ... e PN))
 
 
+* V is the packet version number (3 or 4).
+* PUBKEYALGO is a Libgcrypt algo name 
+* CSUM is the 16 bit checksum as defined by OpenPGP.
+* P1 .. PN are the parameters; the public parameters are never encrypted
+  the secrect key parameters are encrypted if the "protection" list is
+  given.  To make this more explicit each parameter is preceded by a
+  flag "_" for cleartext or "e" for encrypted text.
+* If PROTTYPE is "sha1" the new style SHA1 checksum is used if it is "sum"
+  the old 16 bit checksum is used and if it is "none" no protection at
+  all is used.
+* PROTALGO is a Libgcrypt style cipher algorithm name
+* IV is the initialization verctor.
+* S2KMODE is the value from RFC-4880.
+* S2KHASH is a a libgcrypt style hash algorithm identifier.
+* S2KSALT is the 8 byte salt
+* S2KCOUNT is the count value from RFC-4880.
+
+
+
 Notes:
 ======
 [1] I usually use the terms private and secret key exchangeable but prefer the

Modified: trunk/agent/pksign.c
===================================================================
--- trunk/agent/pksign.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/pksign.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -164,10 +164,22 @@
   if (mdlen > qbits/8)
     mdlen = qbits/8;
             
-  /* Create the S-expression.  */
-  err = gcry_sexp_build (&hash, NULL,
-                        "(data (flags raw) (value %b))",
-                        (int)mdlen, md);
+  /* Create the S-expression.  We need to convert to an MPI first
+     because we want an unsigned integer.  Using %b directly is not
+     possible because libgcrypt assumes an mpi and uses
+     GCRYMPI_FMT_STD for parsing and thus possible yielding a negative
+     value.  */
+  {
+    gcry_mpi_t mpi;
+      
+    err = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, md, mdlen, NULL);
+    if (!err)
+      {
+        err = gcry_sexp_build (&hash, NULL,
+                               "(data (flags raw) (value %m))", mpi);
+        gcry_mpi_release (mpi);
+      }
+  }
   if (!err)
     *r_hash = hash;
   return err;   
@@ -304,8 +316,10 @@
 
       if (DBG_CRYPTO)
         {
-          log_debug ("skey: ");
+          log_debug ("skey:\n");
           gcry_sexp_dump (s_skey);
+          log_debug ("hash:\n");
+          gcry_sexp_dump (s_hash);
         }
 
       /* sign */
@@ -319,7 +333,7 @@
 
       if (DBG_CRYPTO)
         {
-          log_debug ("result: ");
+          log_debug ("result:\n");
           gcry_sexp_dump (s_sig);
         }
     }

Modified: trunk/agent/protect.c
===================================================================
--- trunk/agent/protect.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/agent/protect.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -73,6 +73,8 @@
                  const unsigned char *s2ksalt, unsigned long s2kcount,
                  unsigned char *key, size_t keylen);
 
+
+
 /* Get the process time and store it in DATA.  */
 static void
 calibrate_get_time (struct calibrate_time_s *data)
@@ -1076,6 +1078,19 @@
 }
 
 
+gpg_error_t
+s2k_hash_passphrase (const char *passphrase, int hashalgo,
+                     int s2kmode,
+                     const unsigned char *s2ksalt,
+                     unsigned int s2kcount,
+                     unsigned char *key, size_t keylen)
+{
+  return hash_passphrase (passphrase, hashalgo, s2kmode, s2ksalt, 
+                          (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6),
+                          key, keylen);
+}
+
+
 
 
 /* Create an canonical encoded S-expression with the shadow info from

Modified: trunk/g10/call-agent.c
===================================================================
--- trunk/g10/call-agent.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/g10/call-agent.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -77,6 +77,13 @@
   const char *keyparms;
 };
 
+struct import_key_parm_s
+{
+  ctrl_t ctrl;
+  assuan_context_t ctx;
+  const void *key;
+  size_t keylen;
+};
 
 
 static gpg_error_t learn_status_cb (void *opaque, const char *line);
@@ -1706,3 +1713,97 @@
   *r_buf = buf;
   return 0;
 }
+
+
+
+/* Retrieve a key encryption key from the agent.  With FOREXPORT true
+   the key shall be used for export, with false for import.  On success
+   the new key is stored at R_KEY and its length at R_KEKLEN.  */
+gpg_error_t
+agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen)
+{
+  gpg_error_t err;
+  membuf_t data;
+  size_t len;
+  unsigned char *buf;
+  char line[ASSUAN_LINELENGTH];
+
+  *r_kek = NULL;
+  err = start_agent (ctrl, 0);
+  if (err)
+    return err;
+
+  snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
+            forexport? "--export":"--import");
+
+  init_membuf_secure (&data, 64);
+  err = assuan_transact (agent_ctx, line,
+                         membuf_data_cb, &data, 
+                         default_inq_cb, ctrl, NULL, NULL);
+  if (err)
+    {
+      xfree (get_membuf (&data, &len));
+      return err;
+    }
+  buf = get_membuf (&data, &len);
+  if (!buf)
+    return gpg_error_from_syserror ();
+  *r_kek = buf;
+  *r_keklen = len;
+  return 0;
+}
+
+
+
+/* Handle the inquiry for an IMPORT_KEY command.  */
+static gpg_error_t
+inq_import_key_parms (void *opaque, const char *line)
+{
+  struct import_key_parm_s *parm = opaque; 
+  gpg_error_t err;
+
+  if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
+    {
+      err = assuan_send_data (parm->ctx, parm->key, parm->keylen);
+    }
+  else
+    err = default_inq_cb (parm->ctrl, line);
+
+  return err; 
+}
+
+
+/* Call the agent to import a key into the agent.  */
+gpg_error_t
+agent_import_key (ctrl_t ctrl, const char *desc, const void *key, size_t keylen)
+{
+  gpg_error_t err;
+  struct import_key_parm_s parm;
+
+  err = start_agent (ctrl, 0);
+  if (err)
+    return err;
+
+  if (desc)
+    {
+      char line[ASSUAN_LINELENGTH];
+
+      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+      line[DIM(line)-1] = 0;
+      err = assuan_transact (agent_ctx, line,
+                            NULL, NULL, NULL, NULL, NULL, NULL);
+      if (err)
+        return err;
+    }
+
+  parm.ctrl   = ctrl;
+  parm.ctx    = agent_ctx;
+  parm.key    = key;
+  parm.keylen = keylen;
+
+  err = assuan_transact (agent_ctx, "IMPORT_KEY",
+                         NULL, NULL, inq_import_key_parms, &parm, NULL, NULL);
+  return err;
+}
+
+

Modified: trunk/g10/call-agent.h
===================================================================
--- trunk/g10/call-agent.h	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/g10/call-agent.h	2010-08-31 15:58:39 UTC (rev 5408)
@@ -163,6 +163,14 @@
                              gcry_sexp_t s_ciphertext,
                              unsigned char **r_buf, size_t *r_buflen);
 
+/* Retrieve a key encryption key.  */
+gpg_error_t agent_keywrap_key (ctrl_t ctrl, int forexport,
+                               void **r_kek, size_t *r_keklen);
 
+/* Send a key to the agent.  */
+gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc,
+                              const void *key, size_t keylen);
+
+
 #endif /*GNUPG_G10_CALL_AGENT_H*/
 

Modified: trunk/g10/gpg.c
===================================================================
--- trunk/g10/gpg.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/g10/gpg.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -1925,6 +1925,7 @@
     int any_explicit_recipient = 0;
     int require_secmem=0,got_secmem=0;
     struct assuan_malloc_hooks malloc_hooks;
+    ctrl_t ctrl;
 
 #ifdef __riscos__
     opt.lock_once = 1;
@@ -1984,23 +1985,24 @@
     opt.pgp2_workarounds = 1;
     opt.escape_from = 1;
     opt.flags.require_cross_cert = 1;
-    opt.import_options=IMPORT_SK2PK;
-    opt.export_options=EXPORT_ATTRIBUTES;
-    opt.keyserver_options.import_options=IMPORT_REPAIR_PKS_SUBKEY_BUG;
-    opt.keyserver_options.export_options=EXPORT_ATTRIBUTES;
-    opt.keyserver_options.options=
-      KEYSERVER_HONOR_KEYSERVER_URL|KEYSERVER_HONOR_PKA_RECORD;
-    opt.verify_options=
-      VERIFY_SHOW_POLICY_URLS|VERIFY_SHOW_STD_NOTATIONS|VERIFY_SHOW_KEYSERVER_URLS;
-    opt.trust_model=TM_AUTO;
-    opt.mangle_dos_filenames=0;
-    opt.min_cert_level=2;
-    set_screen_dimensions();
-    opt.keyid_format=KF_SHORT;
-    opt.def_sig_expire="0";
-    opt.def_cert_expire="0";
-    set_homedir ( default_homedir () );
-    opt.passphrase_repeat=1;
+    opt.import_options = 0;
+    opt.export_options = EXPORT_ATTRIBUTES;
+    opt.keyserver_options.import_options = IMPORT_REPAIR_PKS_SUBKEY_BUG;
+    opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
+    opt.keyserver_options.options = (KEYSERVER_HONOR_KEYSERVER_URL
+                                     | KEYSERVER_HONOR_PKA_RECORD );
+    opt.verify_options = (VERIFY_SHOW_POLICY_URLS
+                          | VERIFY_SHOW_STD_NOTATIONS
+                          | VERIFY_SHOW_KEYSERVER_URLS);
+    opt.trust_model = TM_AUTO;
+    opt.mangle_dos_filenames = 0;
+    opt.min_cert_level = 2;
+    set_screen_dimensions ();
+    opt.keyid_format = KF_SHORT;
+    opt.def_sig_expire = "0";
+    opt.def_cert_expire = "0";
+    set_homedir (default_homedir ());
+    opt.passphrase_repeat = 1;
 
     /* Check whether we have a config file on the command line.  */
     orig_argc = argc;
@@ -3403,6 +3405,9 @@
     if(fname && utf8_strings)
       opt.flags.utf8_filename=1;
 
+    ctrl = xtrycalloc (1, sizeof *ctrl);
+    gpg_init_default_ctrl (ctrl);
+
     switch( cmd ) {
       case aPrimegen:
       case aPrintMD:
@@ -3438,13 +3443,7 @@
     switch( cmd )
       {
       case aServer:
-        {
-          ctrl_t ctrl = xtrycalloc (1, sizeof *ctrl);
-          gpg_init_default_ctrl (ctrl);
-          gpg_server (ctrl);
-          gpg_deinit_default_ctrl (ctrl);
-          xfree (ctrl);
-        }
+        gpg_server (ctrl);
         break;
 
       case aStore: /* only store the file */
@@ -3704,7 +3703,7 @@
       case aFastImport:
         opt.import_options |= IMPORT_FAST;
       case aImport:
-	import_keys( argc? argv:NULL, argc, NULL, opt.import_options );
+	import_keys (ctrl, argc? argv:NULL, argc, NULL, opt.import_options);
 	break;
 
 	/* TODO: There are a number of command that use this same
@@ -4055,6 +4054,8 @@
       }
 
     /* cleanup */
+    gpg_deinit_default_ctrl (ctrl);
+    xfree (ctrl);
     release_armor_context (afx);
     FREE_STRLIST(remusr);
     FREE_STRLIST(locusr);

Modified: trunk/g10/import.c
===================================================================
--- trunk/g10/import.c	2010-08-31 08:42:38 UTC (rev 5407)
+++ trunk/g10/import.c	2010-08-31 15:58:39 UTC (rev 5408)
@@ -1,6 +1,6 @@
 /* import.c - import a key into our key storage.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- *               2007 Free Software Foundation, Inc.
+ *               2007, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -37,6 +37,8 @@
 #include "ttyio.h"
 #include "status.h"
 #include "keyserver-internal.h"
+#include "call-agent.h"
+#include "../common/membuf.h"
 
 struct stats_s {
     ulong count;
@@ -58,14 +60,15 @@
 };
 
 
-static int import( IOBUF inp, const char* fname,struct stats_s *stats,
-		   unsigned char **fpr,size_t *fpr_len,unsigned int options );
+static int import (ctrl_t ctrl,
+                   IOBUF inp, const char* fname, struct stats_s *stats,
+		   unsigned char **fpr, size_t *fpr_len, unsigned int options);
 static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
 static void revocation_present(KBNODE keyblock);
 static int import_one(const char *fname, KBNODE keyblock,struct stats_s *stats,
 		      unsigned char **fpr,size_t *fpr_len,
 		      unsigned int options,int from_sk);
-static int import_secret_one( const char *fname, KBNODE keyblock,
+static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
                               struct stats_s *stats, unsigned int options);
 static int import_revoke_cert( const char *fname, KBNODE node,
                                struct stats_s *stats);
@@ -96,8 +99,6 @@
        N_("repair damage from the pks keyserver during import")},
       {"fast-import",IMPORT_FAST,NULL,
        N_("do not update the trustdb after import")},
-      {"convert-sk-to-pk",IMPORT_SK2PK,NULL,
-       N_("create a public key when importing a secret key")},
       {"merge-only",IMPORT_MERGE_ONLY,NULL,
        N_("only accept updates to existing keys")},
       {"import-clean",IMPORT_CLEAN,NULL,
@@ -111,6 +112,7 @@
       {"import-unusable-sigs",0,NULL,NULL},
       {"import-clean-sigs",0,NULL,NULL},
       {"import-clean-uids",0,NULL,NULL},
+      {"convert-sk-to-pk",0, NULL,NULL},
       {NULL,0,NULL,NULL}
     };
 




More information about the Gnupg-commits mailing list