[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