From bfbd80feb95fba36292cd9dab43016f17b1e6972 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 1 Oct 2010 20:33:53 +0000 Subject: [PATCH] Exporting secret keys via gpg-agent is now basically supported. A couple of forward ported changes. Doc updates. --- NEWS | 8 +- README.maint | 1 + agent/ChangeLog | 44 +++ agent/agent.h | 10 +- agent/call-pinentry.c | 38 +- agent/command-ssh.c | 4 +- agent/command.c | 151 ++++++-- agent/cvt-openpgp.c | 273 +++++++++++++- agent/cvt-openpgp.h | 12 +- agent/divert-scd.c | 6 +- agent/findkey.c | 62 +++- agent/genkey.c | 14 +- agent/gpg-agent.c | 28 +- agent/keyformat.txt | 114 +++++- agent/pkdecrypt.c | 4 +- agent/pksign.c | 4 +- agent/protect.c | 27 +- agent/t-protect.c | 8 + common/ChangeLog | 14 + common/http.c | 3 + common/logging.c | 3 + common/sexp-parse.h | 2 +- common/status.c | 1 + common/util.h | 6 + configure.ac | 2 +- dirmngr/ChangeLog | 4 + dirmngr/validate.c | 2 +- doc/ChangeLog | 4 + doc/DETAILS | 3 +- doc/Makefile.am | 4 +- doc/debugging.texi | 2 +- doc/gpg-agent.texi | 16 +- doc/gpg.texi | 32 +- doc/gpgsm.texi | 11 +- g10/ChangeLog | 64 ++++ g10/build-packet.c | 12 +- g10/call-agent.c | 142 +++++++- g10/call-agent.h | 10 + g10/card-util.c | 10 +- g10/compress.c | 4 +- g10/decrypt-data.c | 4 +- g10/decrypt.c | 12 +- g10/encrypt.c | 10 +- g10/export.c | 745 +++++++++++++++++++++++++++++++-------- g10/free-packet.c | 2 +- g10/getkey.c | 16 +- g10/gpg.c | 78 ++-- g10/gpgv.c | 14 +- g10/import.c | 46 +-- g10/keydb.h | 9 +- g10/keyedit.c | 20 +- g10/keygen.c | 2 +- g10/keyid.c | 14 +- g10/keylist.c | 14 +- g10/keyserver-internal.h | 33 +- g10/keyserver.c | 112 +++--- g10/main.h | 35 +- g10/mainproc.c | 41 ++- g10/options.h | 2 - g10/packet.h | 13 +- g10/parse-packet.c | 2 +- g10/photoid.c | 2 +- g10/pkclist.c | 16 +- g10/server.c | 6 +- g10/sign.c | 5 +- g10/verify.c | 16 +- scd/ccid-driver.c | 13 +- sm/ChangeLog | 10 + sm/call-agent.c | 3 +- sm/certchain.c | 6 +- sm/gpgsm.c | 2 +- sm/import.c | 14 +- 72 files changed, 1930 insertions(+), 546 deletions(-) diff --git a/NEWS b/NEWS index 676ab68d8..b456fa845 100644 --- a/NEWS +++ b/NEWS @@ -30,8 +30,8 @@ Noteworthy changes in version 2.1.x (under development) by default. * Dirmngr is now a part of this package. Dirmngr is now also - expected to run as a system service and the configuraion - directories are changed to the gnupg name space. + expected to run as a system service and the configuration + directories are changed to the GnuPG name space. * Given sufficient permissions Dirmngr is started automagically. @@ -43,6 +43,10 @@ Noteworthy changes in version 2.1.x (under development) * The OpenPGP import command is now able to merge secret keys. + * Removed options: + --export-options: export-secret-subkey-passwd + --simple-sk-checksum + Noteworthy changes in version 2.0.13 (2009-09-04) ------------------------------------------------- diff --git a/README.maint b/README.maint index 9ef7a61ea..ac3e05965 100644 --- a/README.maint +++ b/README.maint @@ -23,6 +23,7 @@ Release process: (Mainly config.guess and config.sub). * [1.4 only] Update gpg.texi and gpgv.texi from the trunk: make -C doc update-source-from-gnupg-2 + * [1.4 and 2.0] Copy needed texinfo files from trunk. * Run "make -C po update-po". * Write NEWS entries and set the release date in NEWS. * In configure.ac set "my_issvn" to "no". diff --git a/agent/ChangeLog b/agent/ChangeLog index db77fe014..16871b20f 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,47 @@ +2010-09-30 Werner Koch + + * gpg-agent.c (agent_exit): Run cleanup. + (cleanup): Run only once. + + * call-pinentry.c (close_button_status_cb): New. + (agent_askpin): Add arg R_CANCEL_ALL. Change all callers. + * genkey.c (agent_ask_new_passphrase): Ditto. + * findkey.c (unprotect): Return GPG_ERR_FULLY_CANCELED if needed. + + * command.c (cmd_export_key): Add support for OpenPGP keys. + * findkey.c (unprotect): Add optional arg R_PASSPHRASE. + (agent_key_from_file): Ditto. Change all callers. + + * findkey.c (unprotect): Do not put the passphrase into the cache + if it has been changed. + + * cvt-openpgp.c (convert_to_openpgp, apply_protection) + (key_from_sexp): New. + +2010-09-29 Werner Koch + + * cvt-openpgp.c (convert_openpgp): Rename to convert_from_openpgp. + + * command.c (has_option): Stop at "--". + (has_option_name, option_value): Ditto. + (skip_options): Skip initial spaces. + +2010-09-24 Werner Koch + + * gpg-agent.c (main, reread_configuration): Always test whether + the default configuration file has been created in the meantime. + Fixes bug#1285. + +2010-09-17 Werner Koch + + * command.c (cmd_havekey): Allow testing of several keygrips. + +2010-09-15 Werner Koch + + * protect.c (calculate_mic): Take care of shared secret format. + + * agent.h (PROTECTED_SHARED_SECRET): New. + 2010-09-02 Werner Koch * cache.c (new_data): Change arg and callers to use a string and diff --git a/agent/agent.h b/agent/agent.h index 6c2e7c65e..517df1351 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -182,7 +182,8 @@ enum PRIVATE_KEY_UNKNOWN = 0, PRIVATE_KEY_CLEAR = 1, PRIVATE_KEY_PROTECTED = 2, - PRIVATE_KEY_SHADOWED = 3 + PRIVATE_KEY_SHADOWED = 3, + PROTECTED_SHARED_SECRET = 4 }; @@ -233,7 +234,8 @@ gpg_error_t agent_key_from_file (ctrl_t ctrl, unsigned char **shadow_info, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, - gcry_sexp_t *result); + gcry_sexp_t *result, + char **r_passphrase); gpg_error_t agent_public_key_from_file (ctrl_t ctrl, const unsigned char *grip, gcry_sexp_t *result); @@ -251,7 +253,7 @@ int pinentry_active_p (ctrl_t ctrl, int waitseconds); int agent_askpin (ctrl_t ctrl, const char *desc_text, const char *prompt_text, const char *inital_errtext, - struct pin_entry_info_s *pininfo); + struct pin_entry_info_s *pininfo, int *r_cancelall); int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, const char *errtext, int with_qualitybar); @@ -289,7 +291,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, /*-- genkey.c --*/ int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent); gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, - char **r_passphrase); + char **r_passphrase, int *r_cancelall); int agent_genkey (ctrl_t ctrl, const char *cache_nonce, const char *keyparam, size_t keyparmlen, membuf_t *outbuf); int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey); diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 6ab845a0c..4436b4f48 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -696,6 +696,29 @@ setup_qualitybar (void) } +/* Check the button_info line for a close action. */ +static gpg_error_t +close_button_status_cb (void *opaque, const char *line) +{ + int *flag = opaque; + const char *keyword = line; + int keywordlen; + + for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) + ; + while (spacep (line)) + line++; + if (keywordlen == 11 && !memcmp (keyword, "BUTTON_INFO", keywordlen)) + { + if ( !strcmp (line, "close") ) + *flag = 1; + } + + return 0; +} + + + /* Call the Entry and ask for the PIN. We do check for a valid PIN number here and repeat it as long as we have invalid formed @@ -704,7 +727,7 @@ int agent_askpin (ctrl_t ctrl, const char *desc_text, const char *prompt_text, const char *initial_errtext, - struct pin_entry_info_s *pininfo) + struct pin_entry_info_s *pininfo, int *r_cancel_all) { int rc; char line[ASSUAN_LINELENGTH]; @@ -712,6 +735,10 @@ agent_askpin (ctrl_t ctrl, const char *errtext = NULL; int is_pin = 0; int saveflag; + int close_button; + + if (r_cancel_all) + *r_cancel_all = 0; if (opt.batch) return 0; /* fixme: we should return BAD PIN */ @@ -791,8 +818,10 @@ agent_askpin (ctrl_t ctrl, saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); assuan_begin_confidential (entry_ctx); + close_button = 0; rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, - inq_quality, entry_ctx, NULL, NULL); + inq_quality, entry_ctx, + close_button_status_cb, &close_button); assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); /* Most pinentries out in the wild return the old Assuan error code for canceled which gets translated to an assuan Cancel error and @@ -801,6 +830,11 @@ agent_askpin (ctrl_t ctrl, && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); + /* Set a flag in case the window close button was clicked to + cancel the operation. */ + if (close_button && r_cancel_all && gpg_err_code (rc) == GPG_ERR_CANCELED) + *r_cancel_all = 1; + if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) errtext = is_pin? _("PIN too long") : _("Passphrase too long"); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index ec1c73e6a..3829d4836 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2425,7 +2425,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) pi2->check_cb_arg = pi->pin; next_try: - err = agent_askpin (ctrl, description, NULL, initial_errtext, pi); + err = agent_askpin (ctrl, description, NULL, initial_errtext, pi, NULL); initial_errtext = NULL; if (err) goto out; @@ -2433,7 +2433,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) /* Unless the passphrase is empty, ask to confirm it. */ if (pi->pin && *pi->pin) { - err = agent_askpin (ctrl, description2, NULL, NULL, pi2); + err = agent_askpin (ctrl, description2, NULL, NULL, pi2, NULL); if (err == -1) { /* The re-entered one did not match and the user did not hit cancel. */ diff --git a/agent/command.c b/agent/command.c index a8827e5de..e8af3ecf6 100644 --- a/agent/command.c +++ b/agent/command.c @@ -169,6 +169,23 @@ reset_notify (assuan_context_t ctx, char *line) } +/* Skip over options. + Blanks after the options are also removed. */ +static char * +skip_options (const char *line) +{ + while (spacep (line)) + line++; + while ( *line == '-' && line[1] == '-' ) + { + while (*line && !spacep (line)) + line++; + while (spacep (line)) + line++; + } + return (char*)line; +} + /* Check whether the option NAME appears in LINE */ static int has_option (const char *line, const char *name) @@ -177,6 +194,8 @@ has_option (const char *line, const char *name) int n = strlen (name); s = strstr (line, name); + if (s && s >= skip_options (line)) + return 0; return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); } @@ -190,6 +209,8 @@ has_option_name (const char *line, const char *name) int n = strlen (name); s = strstr (line, name); + if (s && s >= skip_options (line)) + return 0; return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n) || s[n] == '=')); } @@ -203,6 +224,8 @@ option_value (const char *line, const char *name) int n = strlen (name); s = strstr (line, name); + if (s && s >= skip_options (line)) + return NULL; if (s && (s == line || spacep (s-1)) && s[n] && (spacep (s+n) || s[n] == '=')) { @@ -215,23 +238,6 @@ option_value (const char *line, const char *name) } -/* Skip over options. It is assumed that leading spaces have been - removed (this is the case for lines passed to a handler from - assuan). Blanks after the options are also removed. */ -static char * -skip_options (char *line) -{ - while ( *line == '-' && line[1] == '-' ) - { - while (*line && !spacep (line)) - line++; - while (spacep (line)) - line++; - } - return line; -} - - /* Replace all '+' by a blank. */ static void plus_to_blank (char *s) @@ -530,23 +536,35 @@ cmd_marktrusted (assuan_context_t ctx, char *line) static const char hlp_havekey[] = - "HAVEKEY \n" + "HAVEKEY \n" "\n" - "Return success when the secret key is available."; + "Return success if at least one of the secret keys with the given\n" + "keygrips is available."; static gpg_error_t cmd_havekey (assuan_context_t ctx, char *line) { - int rc; + gpg_error_t err; unsigned char buf[20]; - rc = parse_keygrip (ctx, line, buf); - if (rc) - return rc; + do + { + err = parse_keygrip (ctx, line, buf); + if (err) + return err; + + if (!agent_key_available (buf)) + return 0; /* Found. */ - if (agent_key_available (buf)) - return gpg_error (GPG_ERR_NO_SECKEY); - - return 0; + while (*line && *line != ' ' && *line != '\t') + line++; + while (*line == ' ' || *line == '\t') + line++; + } + while (*line); + + /* No leave_cmd() here because errors are expected and would clutter + the log. */ + return gpg_error (GPG_ERR_NO_SECKEY); } @@ -1316,9 +1334,14 @@ cmd_passwd (assuan_context_t ctx, char *line) ctrl->in_passwd++; rc = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip, &shadow_info, CACHE_MODE_IGNORE, NULL, - &s_skey); + &s_skey, NULL); if (rc) - ; + { + /* Not all users of gpg-agent know about fully cancled; thus we + map it back. */ + if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); + } else if (!s_skey) { log_error ("changing a smartcard PIN is not yet supported\n"); @@ -1590,9 +1613,9 @@ cmd_import_key (assuan_context_t ctx, char *line) 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, cache_nonce, - &key, &passphrase); + err = convert_from_openpgp (ctrl, openpgp_sexp, grip, + ctrl->server_local->keydesc, cache_nonce, + &key, &passphrase); if (err) goto leave; realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); @@ -1620,7 +1643,7 @@ cmd_import_key (assuan_context_t ctx, char *line) err = agent_ask_new_passphrase (ctrl, _("Please enter the passphrase to protect the " "imported object within the GnuPG system."), - &passphrase); + &passphrase, NULL); if (err) goto leave; } @@ -1650,7 +1673,7 @@ cmd_import_key (assuan_context_t ctx, char *line) static const char hlp_export_key[] = - "EXPORT_KEY \n" + "EXPORT_KEY [--cache-nonce=] [--openpgp] \n" "\n" "Export a secret key from the key store. The key will be encrypted\n" "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n" @@ -1668,6 +1691,26 @@ cmd_export_key (assuan_context_t ctx, char *line) gcry_cipher_hd_t cipherhd = NULL; unsigned char *wrappedkey = NULL; size_t wrappedkeylen; + int openpgp; + char *cache_nonce; + char *passphrase = NULL; + + openpgp = has_option (line, "--openpgp"); + cache_nonce = option_value (line, "--cache-nonce"); + if (cache_nonce) + { + for (; *line && !spacep (line); line++) + ; + if (*line) + *line++ = '\0'; + cache_nonce = xtrystrdup (cache_nonce); + if (!cache_nonce) + { + err = gpg_error_from_syserror (); + goto leave; + } + } + line = skip_options (line); if (!ctrl->server_local->export_key) { @@ -1685,8 +1728,11 @@ cmd_export_key (assuan_context_t ctx, char *line) goto leave; } + /* Get the key from the file. With the openpgp flag we also ask for + the passphrase so that we can use it to re-encrypt it. */ err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip, - NULL, CACHE_MODE_IGNORE, NULL, &s_skey); + NULL, CACHE_MODE_IGNORE, NULL, &s_skey, + openpgp ? &passphrase : NULL); if (err) goto leave; if (!s_skey) @@ -1697,8 +1743,33 @@ cmd_export_key (assuan_context_t ctx, char *line) err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); goto leave; } - - err = make_canon_sexp_pad (s_skey, 1, &key, &keylen); + + if (openpgp) + { + /* The openpgp option changes the key format into the OpenPGP + key transfer format. The result is already a padded + canonical S-expression. */ + if (!passphrase) + { + int fully_canceled; + err = agent_ask_new_passphrase + (ctrl, _("This key (or subkey) is not protected with a passphrase." + " Please enter a new passphrase to export it."), + &passphrase, &fully_canceled); + if (err) + { + if (fully_canceled) + err = gpg_error (GPG_ERR_FULLY_CANCELED); + goto leave; + } + } + err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen); + } + else + { + /* Convert into a canonical S-expression and wrap that. */ + err = make_canon_sexp_pad (s_skey, 1, &key, &keylen); + } if (err) goto leave; gcry_sexp_release (s_skey); @@ -1735,12 +1806,18 @@ cmd_export_key (assuan_context_t ctx, char *line) leave: + xfree (passphrase); xfree (wrappedkey); gcry_cipher_close (cipherhd); xfree (key); gcry_sexp_release (s_skey); xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; + + /* Not all users of gpg-agent know about fully cancled; thus we map + it back unless we know that it is okay. */ + if (!openpgp && gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) + err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED); return leave_cmd (ctx, err); } diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c index fee93e27d..8105ae6f6 100644 --- a/agent/cvt-openpgp.c +++ b/agent/cvt-openpgp.c @@ -525,10 +525,10 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi) 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, - const char *cache_nonce, - unsigned char **r_key, char **r_passphrase) +convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, + unsigned char *grip, const char *prompt, + const char *cache_nonce, + unsigned char **r_key, char **r_passphrase) { gpg_error_t err; gcry_sexp_t top_list; @@ -779,7 +779,7 @@ convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, err = try_do_unprotect_cb (pi); } if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE) - err = agent_askpin (ctrl, prompt, NULL, NULL, pi); + err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL); skeyidx = pi_arg.skeyidx; if (!err) { @@ -824,4 +824,267 @@ convert_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, } + +static gpg_error_t +key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array) +{ + gpg_error_t err = 0; + gcry_sexp_t l2; + int idx; + + for (idx=0; *elems; elems++, idx++) + { + l2 = gcry_sexp_find_token (sexp, elems, 1); + if (!l2) + { + err = gpg_error (GPG_ERR_NO_OBJ); /* Required parameter not found. */ + goto leave; + } + array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l2); + if (!array[idx]) + { + err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid. */ + goto leave; + } + } + + leave: + if (err) + { + int i; + + for (i=0; i < idx; i++) + { + gcry_mpi_release (array[i]); + array[i] = NULL; + } + } + return err; +} + + +/* Given an ARRAY of mpis with the key parameters, protect the secret + parameters in that array and replace them by one opaque encoded + mpi. NPKEY is the number of public key parameters and NSKEY is + the number of secret key parameters (including the public ones). + On success the array will have NPKEY+1 elements. */ +static gpg_error_t +apply_protection (gcry_mpi_t *array, int npkey, int nskey, + const char *passphrase, + int protect_algo, void *protect_iv, size_t protect_ivlen, + int s2k_mode, int s2k_algo, byte *s2k_salt, u32 s2k_count) +{ + gpg_error_t err; + int i, j; + gcry_cipher_hd_t cipherhd; + unsigned char *bufarr[10]; + size_t narr[10]; + unsigned int nbits[10]; + int ndata; + unsigned char *p, *data; + + assert (npkey < nskey); + assert (nskey < DIM (bufarr)); + + /* Collect only the secret key parameters into BUFARR et al and + compute the required size of the data buffer. */ + ndata = 20; /* Space for the SHA-1 checksum. */ + for (i = npkey, j = 0; i < nskey; i++, j++ ) + { + err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufarr+j, narr+j, array[i]); + if (err) + { + err = gpg_error_from_syserror (); + for (i = 0; i < j; i++) + xfree (bufarr[i]); + return err; + } + nbits[j] = gcry_mpi_get_nbits (array[i]); + ndata += 2 + narr[j]; + } + + /* Allocate data buffer and stuff it with the secret key parameters. */ + data = xtrymalloc_secure (ndata); + if (!data) + { + err = gpg_error_from_syserror (); + for (i = 0; i < (nskey-npkey); i++ ) + xfree (bufarr[i]); + return err; + } + p = data; + for (i = 0; i < (nskey-npkey); i++ ) + { + *p++ = nbits[i] >> 8 ; + *p++ = nbits[i]; + memcpy (p, bufarr[i], narr[i]); + p += narr[i]; + xfree (bufarr[i]); + bufarr[i] = NULL; + } + assert (p == data + ndata - 20); + + /* Append a hash of the secret key parameters. */ + gcry_md_hash_buffer (GCRY_MD_SHA1, p, data, ndata - 20); + + /* Encrypt it. */ + err = gcry_cipher_open (&cipherhd, protect_algo, + GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_SECURE); + if (!err) + err = hash_passphrase_and_set_key (passphrase, cipherhd, protect_algo, + s2k_mode, s2k_algo, s2k_salt, s2k_count); + if (!err) + err = gcry_cipher_setiv (cipherhd, protect_iv, protect_ivlen); + if (!err) + err = gcry_cipher_encrypt (cipherhd, data, ndata, NULL, 0); + gcry_cipher_close (cipherhd); + if (err) + { + xfree (data); + return err; + } + + /* Replace the secret key parameters in the array by one opaque value. */ + for (i = npkey; i < nskey; i++ ) + { + gcry_mpi_release (array[i]); + array[i] = NULL; + } + array[npkey] = gcry_mpi_set_opaque (NULL, data, ndata*8); + return 0; +} + + +/* Convert our key S_KEY into an OpenPGP key transfer format. On + success a canonical encoded S-expression is stored at R_TRANSFERKEY + and its length at R_TRANSFERKEYLEN; this S-expression is also + padded to a multiple of 64 bits. */ +gpg_error_t +convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase, + unsigned char **r_transferkey, size_t *r_transferkeylen) +{ + gpg_error_t err; + gcry_sexp_t list, l2; + char *name; + int algo; + const char *algoname; + const char *elems; + int npkey, nskey; + gcry_mpi_t array[10]; + char protect_iv[16]; + char salt[8]; + unsigned long s2k_count; + int i, j; + + (void)ctrl; + + *r_transferkey = NULL; + + for (i=0; i < DIM (array); i++) + array[i] = NULL; + + list = gcry_sexp_find_token (s_key, "private-key", 0); + if (!list) + return gpg_error (GPG_ERR_NO_OBJ); /* Does not contain a key object. */ + l2 = gcry_sexp_cadr (list); + gcry_sexp_release (list); + list = l2; + name = gcry_sexp_nth_string (list, 0); + if (!name) + { + gcry_sexp_release (list); + return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */ + } + + algo = gcry_pk_map_name (name); + xfree (name); + + switch (algo) + { + case GCRY_PK_RSA: algoname = "rsa"; npkey = 2; elems = "nedpqu"; break; + case GCRY_PK_ELG: algoname = "elg"; npkey = 3; elems = "pgyx"; break; + case GCRY_PK_ELG_E: algoname = "elg"; npkey = 3; elems = "pgyx"; break; + case GCRY_PK_DSA: algoname = "dsa"; npkey = 4; elems = "pqgyx"; break; + case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break; + default: algoname = ""; npkey = 0; elems = NULL; break; + } + assert (!elems || strlen (elems) < DIM (array) ); + nskey = elems? strlen (elems) : 0; + + if (!elems) + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + else + err = key_from_sexp (list, elems, array); + gcry_sexp_release (list); + if (err) + return err; + + gcry_create_nonce (protect_iv, sizeof protect_iv); + gcry_create_nonce (salt, sizeof salt); + s2k_count = get_standard_s2k_count (); + err = apply_protection (array, npkey, nskey, passphrase, + GCRY_CIPHER_AES, protect_iv, sizeof protect_iv, + 3, GCRY_MD_SHA1, salt, s2k_count); + /* Turn it into the transfer key S-expression. Note that we always + return a protected key. */ + if (!err) + { + char countbuf[35]; + membuf_t mbuf; + void *format_args_buf_ptr[1]; + int format_args_buf_int[1]; + void *format_args[10+2]; + size_t n; + gcry_sexp_t tmpkey, tmpsexp; + + snprintf (countbuf, sizeof countbuf, "%lu", s2k_count); + + init_membuf (&mbuf, 50); + put_membuf_str (&mbuf, "(skey"); + for (i=j=0; i < npkey; i++) + { + put_membuf_str (&mbuf, " _ %m"); + format_args[j++] = array + i; + } + put_membuf_str (&mbuf, " e %b"); + format_args_buf_ptr[0] = gcry_mpi_get_opaque (array[npkey], &n); + format_args_buf_int[0] = (n+7)/8; + format_args[j++] = format_args_buf_int; + format_args[j++] = format_args_buf_ptr; + put_membuf_str (&mbuf, ")\n"); + put_membuf (&mbuf, "", 1); + + tmpkey = NULL; + { + char *format = get_membuf (&mbuf, NULL); + if (!format) + err = gpg_error_from_syserror (); + else + err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args); + xfree (format); + } + if (!err) + err = gcry_sexp_build (&tmpsexp, NULL, + "(openpgp-private-key\n" + " (version 1:4)\n" + " (algo %s)\n" + " %S\n" + " (protection sha1 aes %b 1:3 sha1 %b %s))\n", + algoname, + tmpkey, + (int)sizeof protect_iv, protect_iv, + (int)sizeof salt, salt, + countbuf); + gcry_sexp_release (tmpkey); + if (!err) + err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen); + gcry_sexp_release (tmpsexp); + } + + for (i=0; i < DIM (array); i++) + gcry_mpi_release (array[i]); + + return err; +} diff --git a/agent/cvt-openpgp.h b/agent/cvt-openpgp.h index 8dafbc454..db06a3f6a 100644 --- a/agent/cvt-openpgp.h +++ b/agent/cvt-openpgp.h @@ -19,10 +19,14 @@ #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, - const char *cache_nonce, - unsigned char **r_key, char **r_passphrase); +gpg_error_t convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, + unsigned char *grip, const char *prompt, + const char *cache_nonce, + unsigned char **r_key, char **r_passphrase); +gpg_error_t convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, + const char *passphrase, + unsigned char **r_transferkey, + size_t *r_transferkeylen); #endif /*GNUPG_AGENT_CVT_OPENPGP_H*/ diff --git a/agent/divert-scd.c b/agent/divert-scd.c index bf07d0785..0986f3bd3 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -266,7 +266,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) if (any_flags) { - rc = agent_askpin (ctrl, info, prompt, again_text, pi); + rc = agent_askpin (ctrl, info, prompt, again_text, pi, NULL); again_text = NULL; if (!rc && newpin) { @@ -288,7 +288,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) is_puk? _("Repeat this PUK"): _("Repeat this PIN")), - prompt, NULL, pi2); + prompt, NULL, pi2, NULL); if (!rc && strcmp (pi->pin, pi2->pin)) { again_text = (resetcode? @@ -312,7 +312,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) info? info:"", info? "')":"") < 0) desc = NULL; - rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi); + rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi, NULL); xfree (desc); } diff --git a/agent/findkey.c b/agent/findkey.c index 02aea24e5..63b24a5d5 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -104,7 +104,7 @@ agent_write_private_key (const unsigned char *grip, } -/* Callback function to try the unprotection from the passpharse query +/* Callback function to try the unprotection from the passphrase query code. */ static int try_unprotect_cb (struct pin_entry_info_s *pi) @@ -273,11 +273,16 @@ modify_description (const char *in, const char *comment, char **result) should be the hex encoded keygrip of that key to be used with the caching mechanism. DESC_TEXT may be set to override the default description used for the pinentry. If LOOKUP_TTL is given this - function is used to lookup the default ttl. */ + function is used to lookup the default ttl. If R_PASSPHRASE is not + NULL, the function succeeded and the key was protected the used + passphrase (entered or from the cache) is stored there; if not NULL + will be stored. The caller needs to free the returned + passphrase. */ static int unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, unsigned char **keybuf, const unsigned char *grip, - cache_mode_t cache_mode, lookup_ttl_t lookup_ttl) + cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, + char **r_passphrase) { struct pin_entry_info_s *pi; struct try_unprotect_arg_s arg; @@ -285,6 +290,10 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, unsigned char *result; size_t resultlen; char hexgrip[40+1]; + int fully_canceled; + + if (r_passphrase) + *r_passphrase = NULL; bin2hex (grip, 20, hexgrip); @@ -297,13 +306,17 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, if (pw) { rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen); - xfree (pw); if (!rc) { + if (r_passphrase) + *r_passphrase = pw; + else + xfree (pw); xfree (*keybuf); *keybuf = result; return 0; } + xfree (pw); } } @@ -318,13 +331,17 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, if (pw) { rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen); - xfree (pw); if (!rc) { + if (r_passphrase) + *r_passphrase = pw; + else + xfree (pw); xfree (*keybuf); *keybuf = result; return 0; } + xfree (pw); rc = 0; } @@ -366,7 +383,9 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, arg.change_required = 0; pi->check_cb_arg = &arg; - rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi); + rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, &fully_canceled); + if (gpg_err_code (rc) == GPG_ERR_CANCELED && fully_canceled) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED); if (!rc) { assert (arg.unprotected_key); @@ -400,8 +419,13 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, return rc; } } - agent_put_cache (hexgrip, cache_mode, pi->pin, - lookup_ttl? lookup_ttl (hexgrip) : 0); + else + { + agent_put_cache (hexgrip, cache_mode, pi->pin, + lookup_ttl? lookup_ttl (hexgrip) : 0); + if (r_passphrase && *pi->pin) + *r_passphrase = xtrystrdup (pi->pin); + } xfree (*keybuf); *keybuf = arg.unprotected_key; } @@ -501,13 +525,17 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result) not simply pass the TTL value because the value is only needed if an unprotect action was needed and looking up the TTL may have some overhead (e.g. scanning the sshcontrol file). If a CACHE_NONCE is - given that cache item is first tried to get a passphrase. */ + given that cache item is first tried to get a passphrase. If + R_PASSPHRASE is not NULL, the function succeeded and the key was + protected the used passphrase (entered or from the cache) is stored + there; if not NULL will be stored. The caller needs to free the + returned passphrase. */ gpg_error_t agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, const char *desc_text, const unsigned char *grip, unsigned char **shadow_info, cache_mode_t cache_mode, lookup_ttl_t lookup_ttl, - gcry_sexp_t *result) + gcry_sexp_t *result, char **r_passphrase) { int rc; unsigned char *buf; @@ -518,6 +546,8 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, *result = NULL; if (shadow_info) *shadow_info = NULL; + if (r_passphrase) + *r_passphrase = NULL; rc = read_key_file (grip, &s_skey); if (rc) @@ -579,7 +609,7 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, if (!rc) { rc = unprotect (ctrl, cache_nonce, desc_text_final, &buf, grip, - cache_mode, lookup_ttl); + cache_mode, lookup_ttl, r_passphrase); if (rc) log_error ("failed to unprotect the secret key: %s\n", gpg_strerror (rc)); @@ -626,6 +656,11 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, if (rc || got_shadow_info) { xfree (buf); + if (r_passphrase) + { + xfree (*r_passphrase); + *r_passphrase = NULL; + } return rc; } @@ -637,6 +672,11 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce, { log_error ("failed to build S-Exp (off=%u): %s\n", (unsigned int)erroff, gpg_strerror (rc)); + if (r_passphrase) + { + xfree (*r_passphrase); + *r_passphrase = NULL; + } return rc; } diff --git a/agent/genkey.c b/agent/genkey.c index 0a35643e5..c26785204 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -290,10 +290,12 @@ reenter_compare_cb (struct pin_entry_info_s *pi) function returns 0 and store the passphrase at R_PASSPHRASE; if the user opted not to use a passphrase NULL will be stored there. The user needs to free the returned string. In case of an error and - error code is returned and NULL stored at R_PASSPHRASE. */ + error code is returned and NULL stored at R_PASSPHRASE. If + R_CANCEL_ALL is not NULL and the user canceled by directly closing + the window true will be stored at this address. */ gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, - char **r_passphrase) + char **r_passphrase, int *r_cancel_all) { gpg_error_t err; const char *text1 = prompt; @@ -314,7 +316,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, pi2->check_cb_arg = pi->pin; next_try: - err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); + err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, r_cancel_all); initial_errtext = NULL; if (!err) { @@ -327,7 +329,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, /* Unless the passphrase is empty, ask to confirm it. */ if (pi->pin && *pi->pin) { - err = agent_askpin (ctrl, text2, NULL, NULL, pi2); + err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL); if (err == -1) { /* The re-entered one did not match and the user did not hit cancel. */ @@ -379,7 +381,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, rc = agent_ask_new_passphrase (ctrl, _("Please enter the passphrase to%0A" "to protect your new key"), - &passphrase); + &passphrase, NULL); if (rc) return rc; @@ -471,7 +473,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey) rc = agent_ask_new_passphrase (ctrl, _("Please enter the new passphrase"), - &passphrase); + &passphrase, NULL); if (!rc) { rc = store_key (s_skey, passphrase, 1); diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index 0e64939f5..a0e018ea3 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -440,6 +440,11 @@ remove_socket (char *name) static void cleanup (void) { + static int done; + + if (done) + return; + done = 1; deinitialize_module_cache (); remove_socket (socket_name); remove_socket (socket_name_ssh); @@ -724,6 +729,12 @@ main (int argc, char **argv ) if( parse_debug ) log_info (_("NOTE: no default option file `%s'\n"), configname ); + /* Save the default conf file name so that + reread_configuration is able to test whether the + config file has been created in the meantime. */ + xfree (config_filename); + config_filename = configname; + configname = NULL; } else { @@ -811,10 +822,15 @@ main (int argc, char **argv ) fclose( configfp ); configfp = NULL; /* Keep a copy of the name so that it can be read on SIGHUP. */ - config_filename = configname; + if (config_filename != configname) + { + xfree (config_filename); + config_filename = configname; + } configname = NULL; goto next_pass; } + xfree (configname); configname = NULL; if (log_get_errorcount(0)) @@ -1262,6 +1278,12 @@ void agent_exit (int rc) { /*FIXME: update_random_seed_file();*/ + + /* We run our cleanup handler because that may close cipher contexts + stored in secure memory and thus this needs to be done before we + explicitly terminate secure memory. */ + cleanup (); + #if 1 /* at this time a bit annoying */ if (opt.debug & DBG_MEMSTAT_VALUE) @@ -1337,8 +1359,8 @@ reread_configuration (void) fp = fopen (config_filename, "r"); if (!fp) { - log_error (_("option file `%s': %s\n"), - config_filename, strerror(errno) ); + log_info (_("option file `%s': %s\n"), + config_filename, strerror(errno) ); return; } diff --git a/agent/keyformat.txt b/agent/keyformat.txt index 841e5840f..da93f0c50 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -14,7 +14,8 @@ the ~/.gnupg home directory. This directory is named and should have permissions 700. The secret keys are stored in files with a name matching the -hexadecimal representation of the keygrip[2]. +hexadecimal representation of the keygrip[2] and suffixed with ".key". + Unprotected Private Key Format ============================== @@ -166,21 +167,23 @@ 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)) + (skey _ P1 _ P2 _ P3 ... e PN) + (csum n) + (protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT)) * 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. +* CSUM is the depreciated 16 bit checksum as defined by OpenPGP. This + is an optional element. * 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. + the old 16 bit checksum (above) 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. @@ -189,6 +192,105 @@ This format is used to transfer keys between gpg and gpg-agent. * S2KCOUNT is the count value from RFC-4880. +Persistent Passphrase Format +============================ + +To allow persistent storage of cached passphrases we use a scheme +similar to the private-key storage format. This is a master +passphrase format where each file may protect several secrets under +one master passphrase. It is possible to have several of those files +each protected by a dedicated master passphrase. Clear text keywords +allow to list the available protected passphrases. + +The name of the files with these protected secrets have this form: +pw-.dat. STRING may be an arbitrary string, as a default name +for the passphrase storage the name "pw-default.dat" is suggested. + + +(protected-shared-secret + ((desc descriptive_text) + (key [key_1] (keyword_1 keyword_2 keyword_n)) + (key [key_2] (keyword_21 keyword_22 keyword_2n)) + (key [key_n] (keyword_n1 keyword_n2 keyword_nn)) + (protected mode (parms) encrypted_octet_string) + (protected-at ) + ) +) + +After decryption the encrypted_octet_string yields this S-expression: + +( + ( + (value key_1 value_1) + (value key_2 value_2) + (value key_n value_n) + ) + (hash sha1 #...[hashvalue]...#) +) + +The "descriptive_text" is displayed with the prompt to enter the +unprotection passphrase. + +KEY_1 to KEY_N are unique identifiers for the shared secret, for +example an URI. In case this information should be kept confidential +as well, they may not appear in the unprotected part; however they are +mandatory in the encrypted_octet_string. The list of keywords is +optional. The oder of the "key" lists and the order of the "value" +lists mut match, that is the first "key"-list is associated with the +first "value" list in the encrypted_octet_string. + +The protection mode etc. is indentical to the protection mode as +decribed for the private key format. + +list of the secret key parameters. The protected-at expression is +optional; the isotimestamp is 15 bytes long (e.g. "19610711T172000"). + +The "hash" in the encrypted_octet_string is calculated on the +concatenation of the key list and value lists: i.e it is required to +hash the concatenation of all these lists, including the +parenthesis and (if used) the protected-at list. + +Example: + +(protected-shared-secret + ((desc "List of system passphrases") + (key "uid-1002" ("Knuth" "Donald Ervin Knuth")) + (key "uid-1001" ("Dijkstra" "Edsgar Wybe Dijkstra")) + (key) + (protected mode (parms) encrypted_octet_string) + (protected-at "20100915T111722") + ) +) + +with "encrypted_octet_string" decoding to: + +( + ( + (value 4:1002 "signal flags at the lock") + (value 4:1001 "taocp") + (value 1:0 "premature optimization is the root of all evil") + ) + (hash sha1 #0102030405060708091011121314151617181920#) +) + +To compute the hash this S-expression (in canoncical format) was +hashed: + + ((desc "List of system passphrases") + (key "uid-1002" ("Knuth" "Donald Ervin Knuth")) + (key "uid-1001" ("Dijkstra" "Edsgar Wybe Dijkstra")) + (key) + (value 4:1002 "signal flags at the lock") + (value 4:1001 "taocp") + (value 1:0 "premature optimization is the root of all evil") + (protected-at "20100915T111722") + ) + + + + + + Notes: ====== diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 11d297fbf..11d0cc375 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -66,7 +66,9 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, } rc = agent_key_from_file (ctrl, NULL, desc_text, ctrl->keygrip, &shadow_info, - CACHE_MODE_NORMAL, NULL, &s_skey); + CACHE_MODE_NORMAL, NULL, &s_skey, NULL); + if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) { if (gpg_err_code (rc) == GPG_ERR_ENOENT) diff --git a/agent/pksign.c b/agent/pksign.c index d31a687ce..12f4420be 100644 --- a/agent/pksign.c +++ b/agent/pksign.c @@ -255,7 +255,9 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce, rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip, &shadow_info, cache_mode, lookup_ttl, - &s_skey); + &s_skey, NULL); + if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED) + rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); if (rc) { log_error ("failed to read the secret key\n"); diff --git a/agent/protect.c b/agent/protect.c index 3a983e2bd..795d06231 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -191,14 +191,16 @@ get_standard_s2k_count (void) -/* Calculate the MIC for a private key S-Exp. SHA1HASH should point to - a 20 byte buffer. This function is suitable for any algorithms. */ +/* Calculate the MIC for a private key or shared secret S-expression. + SHA1HASH should point to a 20 byte buffer. This function is + suitable for all algorithms. */ static int calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash) { const unsigned char *hash_begin, *hash_end; const unsigned char *s; size_t n; + int is_shared_secret; s = plainkey; if (*s != '(') @@ -207,16 +209,23 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash) n = snext (&s); if (!n) return gpg_error (GPG_ERR_INV_SEXP); - if (!smatch (&s, n, "private-key")) + if (smatch (&s, n, "private-key")) + is_shared_secret = 0; + else if (smatch (&s, n, "shared-secret")) + is_shared_secret = 1; + else return gpg_error (GPG_ERR_UNKNOWN_SEXP); if (*s != '(') return gpg_error (GPG_ERR_UNKNOWN_SEXP); hash_begin = s; - s++; - n = snext (&s); - if (!n) - return gpg_error (GPG_ERR_INV_SEXP); - s += n; /* skip over the algorithm name */ + if (!is_shared_secret) + { + s++; + n = snext (&s); + if (!n) + return gpg_error (GPG_ERR_INV_SEXP); + s += n; /* Skip the algorithm name. */ + } while (*s == '(') { @@ -955,7 +964,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase, xfree (final); return rc; } - /* Now remove tha part which is included in the MIC but should not + /* Now remove the part which is included in the MIC but should not go into the final thing. */ if (cutlen) { diff --git a/agent/t-protect.c b/agent/t-protect.c index 0e29cafe2..7b80bcbbb 100644 --- a/agent/t-protect.c +++ b/agent/t-protect.c @@ -289,6 +289,13 @@ test_agent_get_shadow_info (void) } +static void +test_agent_protect_shared_secret (void) +{ + +} + + int @@ -305,6 +312,7 @@ main (int argc, char **argv) test_make_shadow_info (); test_agent_shadow_key (); test_agent_get_shadow_info (); + test_agent_protect_shared_secret (); return 0; } diff --git a/common/ChangeLog b/common/ChangeLog index 0c8698bab..b7e33baf1 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,17 @@ +2010-09-30 Werner Koch + + * util.h (GPG_ERR_FULLY_CANCELED): Add replacement. + +2010-09-17 Werner Koch + + * http.c (INADDR_NONE): Provide fallback. + * logging.c (INADDR_NONE): Ditto. + +2010-09-16 Werner Koch + + * util.h: Add GPG_ERR_MISSING_ISSUER_CERT. + * status.c (get_inv_recpsgnr_code): Ditto. + 2010-09-13 Werner Koch * homedir.c (gnupg_bindir) [W32CE]: Change to bin/. diff --git a/common/http.c b/common/http.c index 1e3e89790..1d84051a2 100644 --- a/common/http.c +++ b/common/http.c @@ -114,6 +114,9 @@ struct srventry #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif +#ifndef INADDR_NONE /* Slowaris is missing that. */ +#define INADDR_NONE ((unsigned long)(-1)) +#endif /*INADDR_NONE*/ #define HTTP_PROXY_ENV "http_proxy" #define MAX_LINELEN 20000 /* Max. length of a HTTP header line. */ diff --git a/common/logging.c b/common/logging.c index 4c2d61b1e..5a61c609c 100644 --- a/common/logging.c +++ b/common/logging.c @@ -68,6 +68,9 @@ #ifndef EAFNOSUPPORT # define EAFNOSUPPORT EINVAL #endif +#ifndef INADDR_NONE /* Slowaris is missing that. */ +#define INADDR_NONE ((unsigned long)(-1)) +#endif /*INADDR_NONE*/ #ifdef HAVE_W32_SYSTEM #define sock_close(a) closesocket(a) diff --git a/common/sexp-parse.h b/common/sexp-parse.h index b3213a6fe..5ec7c7f71 100644 --- a/common/sexp-parse.h +++ b/common/sexp-parse.h @@ -82,7 +82,7 @@ sskip (unsigned char const **buf, int *depth) /* Check whether the the string at the address BUF points to matches the token. Return true on match and update BUF to point behind the - token. Return false and dont update tha buffer if it does not + token. Return false and do not update the buffer if it does not match. */ static inline int smatch (unsigned char const **buf, size_t buflen, const char *token) diff --git a/common/status.c b/common/status.c index e9f84bfd1..7b9f4a3ae 100644 --- a/common/status.c +++ b/common/status.c @@ -58,6 +58,7 @@ get_inv_recpsgnr_code (gpg_error_t err) case GPG_ERR_NOT_TRUSTED: errstr = "10"; break; case GPG_ERR_MISSING_CERT: errstr = "11"; break; + case GPG_ERR_MISSING_ISSUER_CERT: errstr = "12"; break; default: errstr = "0"; break; } diff --git a/common/util.h b/common/util.h index 341df2531..286cf50a2 100644 --- a/common/util.h +++ b/common/util.h @@ -33,6 +33,12 @@ #ifndef GPG_ERR_NOT_INITIALIZED #define GPG_ERR_NOT_INITIALIZED 184 #endif +#ifndef GPG_ERR_MISSING_ISSUER_CERT +#define GPG_ERR_MISSING_ISSUER_CERT 185 +#endif +#ifndef GPG_ERR_FULLY_CANCELED +#define GPG_ERR_FULLY_CANCELED 198 +#endif /* Hash function used with libksba. */ diff --git a/configure.ac b/configure.ac index 17ca28052..5e2d7ca4d 100644 --- a/configure.ac +++ b/configure.ac @@ -396,7 +396,7 @@ AH_BOTTOM([ # define GNUPG_DEFAULT_HOMEDIR "/gnupg" # endif #elif defined(__VMS) -#define GNUPG_DEFAULT_HOMEDIR "/SYS\$LOGIN/gnupg" +#define GNUPG_DEFAULT_HOMEDIR "/SYS$LOGIN/gnupg" #else #define GNUPG_DEFAULT_HOMEDIR "~/.gnupg" #endif diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog index 3afd1372a..ffe9bbd24 100644 --- a/dirmngr/ChangeLog +++ b/dirmngr/ChangeLog @@ -1,3 +1,7 @@ +2010-09-16 Werner Koch + + * validate.c (validate_cert_chain): Use GPG_ERR_MISSING_ISSUER_CERT. + 2010-08-13 Werner Koch * Makefile.am (dirmngr_SOURCES): Add w32-ldap-help.h. diff --git a/dirmngr/validate.c b/dirmngr/validate.c index 538779842..de7443e11 100644 --- a/dirmngr/validate.c +++ b/dirmngr/validate.c @@ -623,7 +623,7 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime, log_error (_("issuer certificate not found: %s\n"), gpg_strerror (err)); /* Use a better understandable error code. */ - err = gpg_error (GPG_ERR_MISSING_CERT); + err = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); goto leave; } diff --git a/doc/ChangeLog b/doc/ChangeLog index e27d9a9b6..efa1939e2 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2010-09-28 Werner Koch + + * Makefile.am (AM_MAKEINFOFLAGS): Add define gpgtwoone. + 2010-09-28 David Shaw * gpg.texi (OpenPGP Options): Clarify that --force-v3-sigs diff --git a/doc/DETAILS b/doc/DETAILS index a67e90e53..93dedbea0 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -586,7 +586,8 @@ more arguments in future versions. 8 := "Policy mismatch" 9 := "Not a secret key" 10 := "Key not trusted" - 11 := "Missing certificate" (e.g. intermediate or root cert.) + 11 := "Missing certificate" + 12 := "Missing issuer certificate" Note that for historical reasons the INV_RECP status is also used for gpgsm's SIGNER command where it relates to signer's diff --git a/doc/Makefile.am b/doc/Makefile.am index 74e389c98..26c6e9e5e 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -57,9 +57,9 @@ gnupg_TEXINFOS = \ DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips -AM_MAKEINFOFLAGS = -I $(srcdir) --css-include=$(srcdir)/texi.css +AM_MAKEINFOFLAGS = -I $(srcdir) --css-include=$(srcdir)/texi.css -D gpgtwoone -YAT2M_OPTIONS = -I $(srcdir) \ +YAT2M_OPTIONS = -I $(srcdir) -D gpgtwoone \ --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard" myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \ diff --git a/doc/debugging.texi b/doc/debugging.texi index df71009d6..26383c06b 100644 --- a/doc/debugging.texi +++ b/doc/debugging.texi @@ -194,7 +194,7 @@ or other purposes and don't have a corresponding certificate. @item A root certificate does not verify A common problem is that the root certificate misses the required -basicConstrains attribute and thus @command{gpgsm} rejects this +basicConstraints attribute and thus @command{gpgsm} rejects this certificate. An error message indicating ``no value'' is a sign for such a certificate. You may use the @code{relax} flag in @file{trustlist.txt} to accept the certificate anyway. Note that the diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index dff2d1d97..41f2efc8b 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -317,8 +317,12 @@ should in general not be used to avoid X-sniffing attacks. @item --log-file @var{file} @opindex log-file -Append all logging output to @var{file}. This is very helpful in -seeing what the agent actually does. +Append all logging output to @var{file}. This is very helpful in seeing +what the agent actually does. If neither a log file nor a log file +descriptor has been set on a Windows platform, the Registry entry +@var{HKCU\Software\GNU\GnuPG:DefaultLogFile}, if set, is used to specify +the logging output. + @anchor{option --allow-mark-trusted} @item --allow-mark-trusted @@ -1148,11 +1152,13 @@ This can be used to see whether a secret key is available. It does not return any information on whether the key is somehow protected. @example - HAVEKEY @var{keygrip} + HAVEKEY @var{keygrips} @end example -The Agent answers either with OK or @code{No_Secret_Key} (208). The -caller may want to check for other error codes as well. +The agent answers either with OK or @code{No_Secret_Key} (208). The +caller may want to check for other error codes as well. More than one +keygrip may be given. In this case the command returns success if at +least one of the keygrips corresponds to an available secret key. @node Agent LEARN diff --git a/doc/gpg.texi b/doc/gpg.texi index d35818e58..cf0cfb135 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -3,6 +3,11 @@ @c This is part of the GnuPG manual. @c For copying conditions, see the file gnupg.texi. +@c Note that we use this texinfo file for all versions of GnuPG: 1.4.x, +@c 2.0 and 2.1. The macro "gpgone" controls parts which are only valid +@c for GnuPG 1.4, the macro "gpgtwoone" controls parts which are only +@c valid for GnupG 2.1 and later. + @node Invoking GPG @chapter Invoking GPG @cindex GPG command options @@ -68,18 +73,19 @@ implementation. @ifset gpgone This is the standalone version of @command{gpg}. For desktop use you -should consider using @command{gpg2}. +should consider using @command{gpg2} @footnote{On some platforms gpg2 is +installed under the name @command{gpg}}. @end ifset @ifclear gpgone In contrast to the standalone version @command{gpg}, which is more -suited for server and embedded platforms, this version is installed -under the name @command{gpg2} and more targeted to the desktop as it -requires several other modules to be installed. The standalone version -will be kept maintained and it is possible to install both versions on -the same system. If you need to use different configuration files, you -should make use of something like @file{gpg.conf-2} instead of just -@file{gpg.conf}. +suited for server and embedded platforms, this version is commonly +installed under the name @command{gpg2} and more targeted to the desktop +as it requires several other modules to be installed. The standalone +version will be kept maintained and it is possible to install both +versions on the same system. If you need to use different configuration +files, you should make use of something like @file{gpg.conf-2} instead +of just @file{gpg.conf}. @end ifclear @manpause @@ -415,8 +421,10 @@ normally not very useful and a security risk. The second form of the command has the special property to render the secret part of the primary key useless; this is a GNU extension to OpenPGP and other implementations can not be expected to successfully import such a key. +@ifclear gpgtwoone See the option @option{--simple-sk-checksum} if you want to import such an exported key with an older OpenPGP implementation. +@end ifclear @item --import @itemx --fast-import @@ -1550,6 +1558,7 @@ key signer (defaults to 3) @item --max-cert-depth @code{n} Maximum depth of a certification chain (default is 5). +@ifclear gpgtwoone @item --simple-sk-checksum Secret keys are integrity protected by using a SHA-1 checksum. This method is part of the upcoming enhanced OpenPGP specification but @@ -1560,6 +1569,7 @@ a security risk. Note that using this option only takes effect when the secret key is encrypted - the simplest way to make this happen is to change the passphrase on the key (even changing it to the same value is acceptable). +@end ifclear @item --no-sig-cache Do not cache the verification status of key signatures. @@ -1884,11 +1894,17 @@ program that does not accept attribute user IDs. Defaults to yes. Include designated revoker information that was marked as "sensitive". Defaults to no. +@c Since GnuPG 2.1 gpg-agent manages the secret key and thus the +@c export-reset-subkey-passwd hack is not anymore justified. Such use +@c cases need to be implemented using a specialized secret key export +@c tool. +@ifclear gpgtwoone @item export-reset-subkey-passwd When using the @option{--export-secret-subkeys} command, this option resets the passphrases for all exported subkeys to empty. This is useful when the exported subkey is to be used on an unattended machine where a passphrase doesn't necessarily make sense. Defaults to no. +@end ifclear @item export-clean Compact (remove all signatures from) user IDs on the key being diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi index b354ece90..93b625162 100644 --- a/doc/gpgsm.texi +++ b/doc/gpgsm.texi @@ -31,7 +31,7 @@ @command{gpgsm} is a tool similar to @command{gpg} to provide digital encryption and signing services on X.509 certificates and the CMS protocol. It is mainly used as a backend for S/MIME mail processing. -@command{gpgsm} includes a full features certificate management and +@command{gpgsm} includes a full featured certificate management and complies with all rules defined for the German Sphinx project. @manpause @@ -286,7 +286,7 @@ smartcard is not yet supported. @node GPGSM Options @section Option Summary -@command{GPGSM} comes features a bunch of options to control the exact behaviour +@command{GPGSM} features a bunch of options to control the exact behaviour and to change the default configuration. @menu @@ -566,10 +566,9 @@ certificate. @item --include-certs @var{n} @opindex include-certs Using @var{n} of -2 includes all certificate except for the root cert, --1 includes all certs, 0 does not include any certs, 1 includes only -the signers cert (this is the default) and all other positive -values include up to @var{n} certificates starting with the signer cert. -The default is -2. +-1 includes all certs, 0 does not include any certs, 1 includes only the +signers cert and all other positive values include up to @var{n} +certificates starting with the signer cert. The default is -2. @item --cipher-algo @var{oid} @opindex cipher-algo diff --git a/g10/ChangeLog b/g10/ChangeLog index 554c12b11..17f3e3269 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,67 @@ +2010-10-01 Werner Koch + + * export.c (do_export_stream): Rewrite to take the secret keys + from the agent. + (canon_pubkey_algo, transfer_format_to_openpgp): New. + +2010-09-29 Werner Koch + + * keygen.c (key_from_sexp): Fix memory leak in the error case. + + * call-agent.c (agent_export_key): New. + +2010-09-29 Werner Koch + + * build-packet.c (build_packet): Fix up the pkttype. + + * keyid.c (keystr_with_sub): Make SUB_KID optional. + (keystr_from_pk_with_sub): Ditto. + + * call-agent.c (agent_scd_pksign): Add missing space. + + * mainproc.c (struct mainproc_context): Add field CTRL. + (proc_packets): Add arg CTRL. Change all callers. + (proc_signature_packets, proc_signature_packets_by_fd) + (proc_encryption_packets): Add arg CTRL. Change all callers. + * compress.c (handle_compressed): Ditto. + * getkey.c (get_pubkey_byname): Ditto. + * keyserver.c (keyserver_spawn, keyserver_work): Ditto. + (show_prompt, keyserver_export, keyserver_import) + (keyserver_import_fprint, keyserver_import_keyid) + (keyserver_refresh, keyserver_search, keyserver_fetch) + (keyserver_import_name, keyserver_search_prompt) + (keyserver_import_pka, keyserver_import_cert): Ditto. + callers. + * verify.c (verify_signatures, verify_files): Ditto. + * sign.c (sign_file): Ditto. + * encrypt.c (encrypt_crypt, encrypt_crypt_files): Ditto. + * pkclist.c (find_and_check_key, build_pk_list): Ditto. + * keylist.c (locate_one, public_key_list, secret_key_list): Ditto. + * card-util.c (fetch_url, card_edit): Ditto. + * import.c (check_prefs, import_one, revocation_present): Ditto. + * keyedit.c (menu_addrevoker, keyedit_menu): Ditto. + * decrypt-data.c (decrypt_data): Ditto. + * decrypt.c (decrypt_message, decrypt_messages) + (decrypt_message_fd): Ditto. + * gpgv.c (main): Add CTRL structure. + +2010-09-28 Werner Koch + + * options.h (struct opt): Remove SIMPLE_SK_CHECKSUM. + + * export.c (parse_export_options): Remove option + export-resert-subkey-passwd. + (do_export_stream, do_export, export_pubkeys) + (export_pubkeys_stream, export_seckeys, export_secsubkeys): Add + arg CTRL. Change all callers. + + * call-agent.c (hash_algo_option): New. + (agent_scd_pksign): Use it. + +2010-09-17 Werner Koch + + * call-agent.c (agent_probe_any_secret_key): New. + 2010-09-28 David Shaw * options.skel: Make the example for force-v3-sigs match diff --git a/g10/build-packet.c b/g10/build-packet.c index 354afece7..83d6c7a73 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -26,10 +26,10 @@ #include #include "gpg.h" +#include "util.h" #include "packet.h" #include "status.h" #include "iobuf.h" -#include "util.h" #include "cipher.h" #include "i18n.h" #include "options.h" @@ -71,8 +71,16 @@ build_packet( IOBUF out, PACKET *pkt ) log_debug("build_packet() type=%d\n", pkt->pkttype ); assert( pkt->pkt.generic ); - switch( (pkttype = pkt->pkttype) ) + switch ((pkttype = pkt->pkttype)) { + case PKT_PUBLIC_KEY: + if (pkt->pkt.public_key->seckey_info) + pkttype = PKT_SECRET_KEY; + break; + case PKT_PUBLIC_SUBKEY: + if (pkt->pkt.public_key->seckey_info) + pkttype = PKT_SECRET_SUBKEY; + break; case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break; case PKT_ENCRYPTED: case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break; diff --git a/g10/call-agent.c b/g10/call-agent.c index 90fa40e1d..bdf4c9589 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -901,7 +901,27 @@ membuf_data_cb (void *opaque, const void *buffer, size_t length) put_membuf (data, buffer, length); return 0; } - + + +/* Helper returning a command option to describe the used hash + algorithm. See scd/command.c:cmd_pksign. */ +static const char * +hash_algo_option (int algo) +{ + switch (algo) + { + case GCRY_MD_RMD160: return "--hash=rmd160"; + case GCRY_MD_SHA1 : return "--hash=sha1"; + case GCRY_MD_SHA224: return "--hash=sha224"; + case GCRY_MD_SHA256: return "--hash=sha256"; + case GCRY_MD_SHA384: return "--hash=sha384"; + case GCRY_MD_SHA512: return "--hash=sha512"; + case GCRY_MD_MD5 : return "--hash=md5"; + default: return ""; + } +} + + /* Send a sign command to the scdaemon via gpg-agent's pass thru mechanism. */ int @@ -942,14 +962,11 @@ agent_scd_pksign (const char *serialno, int hashalgo, return rc; init_membuf (&data, 1024); -#if 0 - if (!hashalgo) /* Temporary test hack. */ - snprintf (line, DIM(line)-1, "SCD PKAUTH %s", serialno); - else -#endif - snprintf (line, DIM(line)-1, "SCD PKSIGN %s%s", - hashalgo == GCRY_MD_RMD160? "--hash=rmd160 " : "", - serialno); + /* if (!hashalgo) /\* Temporary test hack. *\/ */ + /* snprintf (line, DIM(line)-1, "SCD PKAUTH %s", serialno); */ + /* else */ + snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", + hash_algo_option (hashalgo), serialno); line[DIM(line)-1] = 0; rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data, default_inq_cb, NULL, NULL, NULL); @@ -1325,6 +1342,57 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk) return err; } +/* Ask the agent whether a secret key is availabale for any of the + keys (primary or sub) in KEYBLOCK. Returns 0 if available. */ +gpg_error_t +agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock) +{ + gpg_error_t err; + char line[ASSUAN_LINELENGTH]; + char *p; + kbnode_t kbctx, node; + int nkeys; + unsigned char grip[20]; + + err = start_agent (ctrl, 0); + if (err) + return err; + + err = gpg_error (GPG_ERR_NO_SECKEY); /* Just in case no key was + found in KEYBLOCK. */ + p = stpcpy (line, "HAVEKEY"); + for (kbctx=NULL, nkeys=0; (node = walk_kbnode (keyblock, &kbctx, 0)); ) + if (node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY + || node->pkt->pkttype == PKT_SECRET_KEY + || node->pkt->pkttype == PKT_SECRET_SUBKEY) + { + if (nkeys && ((p - line) + 41) > (ASSUAN_LINELENGTH - 2)) + { + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (err != gpg_err_code (GPG_ERR_NO_SECKEY)) + break; /* Seckey available or unexpected error - ready. */ + p = stpcpy (line, "HAVEKEY"); + nkeys = 0; + } + + err = keygrip_from_pk (node->pkt->pkt.public_key, grip); + if (err) + return err; + *p++ = ' '; + bin2hex (grip, 20, p); + p += 40; + nkeys++; + } + + if (!err && nkeys) + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + + return err; +} + static gpg_error_t @@ -1393,7 +1461,8 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno) } -/* Status callback for agent_import_key and agent_genkey. */ +/* Status callback for agent_import_key, agent_export_key and + agent_genkey. */ static gpg_error_t cache_nonce_status_cb (void *opaque, const char *line) { @@ -1849,3 +1918,56 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, } + +/* Receive a secret key from the agent. HEXKEYGRIP is the hexified + keygrip, DESC a prompt to be displayed with the agent's passphrase + question (needs to be plus+percent escaped). On success the key is + stored as a canonical S-expression at R_RESULT and R_RESULTLEN. */ +gpg_error_t +agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, + char **cache_nonce_addr, + unsigned char **r_result, size_t *r_resultlen) +{ + gpg_error_t err; + membuf_t data; + size_t len; + unsigned char *buf; + char line[ASSUAN_LINELENGTH]; + + *r_result = NULL; + + err = start_agent (ctrl, 0); + if (err) + return err; + + if (desc) + { + snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc); + err = assuan_transact (agent_ctx, line, + NULL, NULL, NULL, NULL, NULL, NULL); + if (err) + return err; + } + + snprintf (line, DIM(line)-1, "EXPORT_KEY --openpgp %s%s %s", + cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"", + cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"", + hexkeygrip); + + init_membuf_secure (&data, 1024); + err = assuan_transact (agent_ctx, line, + membuf_data_cb, &data, + default_inq_cb, ctrl, + cache_nonce_status_cb, cache_nonce_addr); + if (err) + { + xfree (get_membuf (&data, &len)); + return err; + } + buf = get_membuf (&data, &len); + if (!buf) + return gpg_error_from_syserror (); + *r_result = buf; + *r_resultlen = len; + return 0; +} diff --git a/g10/call-agent.h b/g10/call-agent.h index f33f15d6a..5496e596e 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -144,6 +144,11 @@ gpg_error_t agent_get_s2k_count (unsigned long *r_count); 0 if the secret key is available. */ gpg_error_t agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk); +/* Ask the agent whether a secret key is availabale for any of the + keys (primary or sub) in KEYBLOCK. Returns 0 if available. */ +gpg_error_t agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock); + + /* Return infos about the secret key with HEXKEYGRIP. */ gpg_error_t agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno); @@ -174,6 +179,11 @@ gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, const void *key, size_t keylen); +/* Receive a key from the agent. */ +gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip, + const char *desc, char **cache_nonce_addr, + unsigned char **r_result, size_t *r_resultlen); + #endif /*GNUPG_G10_CALL_AGENT_H*/ diff --git a/g10/card-util.c b/g10/card-util.c index 1dd7a9219..1abcde894 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -721,7 +721,7 @@ change_url (void) /* Fetch the key from the URL given on the card or try to get it from the default keyserver. */ static int -fetch_url(void) +fetch_url (ctrl_t ctrl) { int rc; struct agent_card_info_s info; @@ -751,13 +751,13 @@ fetch_url(void) event, the fpr/keyid is not meaningful for straight HTTP fetches, but using it allows the card to point to HKP and LDAP servers as well. */ - rc=keyserver_import_fprint(info.fpr1,20,spec); + rc = keyserver_import_fprint (ctrl, info.fpr1, 20, spec); free_keyserver_spec(spec); } } else if (info.fpr1valid) { - rc = keyserver_import_fprint (info.fpr1, 20, opt.keyserver); + rc = keyserver_import_fprint (ctrl, info.fpr1, 20, opt.keyserver); } } @@ -1765,7 +1765,7 @@ card_edit_completion(const char *text, int start, int end) /* Menu to edit all user changeable values on an OpenPGP card. Only Key creation is not handled here. */ void -card_edit (strlist_t commands) +card_edit (ctrl_t ctrl, strlist_t commands) { enum cmdids cmd = cmdNOP; int have_commands = !!commands; @@ -1924,7 +1924,7 @@ card_edit (strlist_t commands) break; case cmdFETCH: - fetch_url(); + fetch_url (ctrl); break; case cmdLOGIN: diff --git a/g10/compress.c b/g10/compress.c index db9fedb64..5dd3591df 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -300,7 +300,7 @@ release_context (compress_filter_context_t *ctx) * Handle a compressed packet */ int -handle_compressed( void *procctx, PKT_compressed *cd, +handle_compressed (ctrl_t ctrl, void *procctx, PKT_compressed *cd, int (*callback)(IOBUF, void *), void *passthru ) { compress_filter_context_t *cfx; @@ -315,7 +315,7 @@ handle_compressed( void *procctx, PKT_compressed *cd, if( callback ) rc = callback(cd->buf, passthru ); else - rc = proc_packets(procctx, cd->buf); + rc = proc_packets (ctrl,procctx, cd->buf); cd->buf = NULL; return rc; } diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c index c9da9be97..3779f6a92 100644 --- a/g10/decrypt-data.c +++ b/g10/decrypt-data.c @@ -74,7 +74,7 @@ release_dfx_context (decode_filter_ctx_t dfx) * Decrypt the data, specified by ED with the key DEK. */ int -decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) +decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { decode_filter_ctx_t dfx; byte *p; @@ -191,7 +191,7 @@ decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) else iobuf_push_filter ( ed->buf, decode_filter, dfx ); - proc_packets ( procctx, ed->buf ); + proc_packets (ctrl, procctx, ed->buf ); ed->buf = NULL; if (dfx->eof_seen > 1 ) rc = gpg_error (GPG_ERR_INV_PACKET); diff --git a/g10/decrypt.c b/g10/decrypt.c index 210e1feec..595b2879e 100644 --- a/g10/decrypt.c +++ b/g10/decrypt.c @@ -43,7 +43,7 @@ * rejects files which don't begin with an encrypted message. */ int -decrypt_message (const char *filename) +decrypt_message (ctrl_t ctrl, const char *filename) { IOBUF fp; armor_filter_context_t *afx = NULL; @@ -86,7 +86,7 @@ decrypt_message (const char *filename) no_out = 1; opt.outfile = "-"; } - rc = proc_encryption_packets ( NULL, fp ); + rc = proc_encryption_packets (ctrl, NULL, fp ); if (no_out) opt.outfile = NULL; @@ -100,7 +100,7 @@ decrypt_message (const char *filename) /* Same as decrypt_message but takes a file descriptor for input and output. */ gpg_error_t -decrypt_message_fd (int input_fd, int output_fd) +decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd) { gpg_error_t err; IOBUF fp; @@ -158,7 +158,7 @@ decrypt_message_fd (int input_fd, int output_fd) } } - err = proc_encryption_packets ( NULL, fp ); + err = proc_encryption_packets (ctrl, NULL, fp ); iobuf_close (fp); fclose (opt.outfp); @@ -170,7 +170,7 @@ decrypt_message_fd (int input_fd, int output_fd) void -decrypt_messages (int nfiles, char *files[]) +decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]) { IOBUF fp; armor_filter_context_t *afx = NULL; @@ -251,7 +251,7 @@ decrypt_messages (int nfiles, char *files[]) push_armor_filter ( afx, fp ); } } - rc = proc_packets(NULL, fp); + rc = proc_packets (ctrl,NULL, fp); iobuf_close(fp); if (rc) log_error("%s: decryption failed: %s\n", print_fname_stdin(filename), diff --git a/g10/encrypt.c b/g10/encrypt.c index 881fecfc1..55f9b27fb 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -461,7 +461,7 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek, * PROVIDED_PKS; if not the function builds a list of keys on its own. */ int -encrypt_crypt (int filefd, const char *filename, +encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, strlist_t remusr, int use_symkey, pk_list_t provided_keys, int outputfd) { @@ -503,7 +503,7 @@ encrypt_crypt (int filefd, const char *filename, pk_list = provided_keys; else { - if ((rc = build_pk_list (remusr, &pk_list, PUBKEY_USAGE_ENC))) + if ((rc = build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC))) { release_progress_context (pfx); return rc; @@ -939,7 +939,7 @@ write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out) void -encrypt_crypt_files (int nfiles, char **files, strlist_t remusr) +encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr) { int rc = 0; @@ -963,7 +963,7 @@ encrypt_crypt_files (int nfiles, char **files, strlist_t remusr) } line[strlen(line)-1] = '\0'; print_file_status(STATUS_FILE_START, line, 2); - rc = encrypt_crypt (-1, line, remusr, 0, NULL, -1); + rc = encrypt_crypt (ctrl, -1, line, remusr, 0, NULL, -1); if (rc) log_error ("encryption of `%s' failed: %s\n", print_fname_stdin(line), g10_errstr(rc) ); @@ -975,7 +975,7 @@ encrypt_crypt_files (int nfiles, char **files, strlist_t remusr) while (nfiles--) { print_file_status(STATUS_FILE_START, *files, 2); - if ( (rc = encrypt_crypt (-1, *files, remusr, 0, NULL, -1)) ) + if ( (rc = encrypt_crypt (ctrl, -1, *files, remusr, 0, NULL, -1)) ) log_error("encryption of `%s' failed: %s\n", print_fname_stdin(*files), g10_errstr(rc) ); write_status( STATUS_FILE_DONE ); diff --git a/g10/export.c b/g10/export.c index bea798e47..91c6a73d7 100644 --- a/g10/export.c +++ b/g10/export.c @@ -1,6 +1,6 @@ -/* export.c +/* export.c - Export keys in the OpenPGP defined format. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, - * 2005 Free Software Foundation, Inc. + * 2005, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -34,7 +34,7 @@ #include "main.h" #include "i18n.h" #include "trustdb.h" - +#include "call-agent.h" /* An object to keep track of subkeys. */ struct subkey_list_s @@ -45,10 +45,12 @@ struct subkey_list_s typedef struct subkey_list_s *subkey_list_t; -static int do_export( strlist_t users, int secret, unsigned int options ); -static int do_export_stream( IOBUF out, strlist_t users, int secret, - KBNODE *keyblock_out, unsigned int options, - int *any ); +static int do_export (ctrl_t ctrl, + strlist_t users, int secret, unsigned int options ); +static int do_export_stream (ctrl_t ctrl, iobuf_t out, + strlist_t users, int secret, + kbnode_t *keyblock_out, unsigned int options, + int *any); static int build_sexp (iobuf_t out, PACKET *pkt, int *indent); @@ -63,8 +65,6 @@ parse_export_options(char *str,unsigned int *options,int noisy) N_("export attribute user IDs (generally photo IDs)")}, {"export-sensitive-revkeys",EXPORT_SENSITIVE_REVKEYS,NULL, N_("export revocation keys marked as \"sensitive\"")}, - {"export-reset-subkey-passwd",EXPORT_RESET_SUBKEY_PASSWD,NULL, - N_("remove the passphrase from exported subkeys")}, {"export-clean",EXPORT_CLEAN,NULL, N_("remove unusable parts from key during export")}, {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL, @@ -93,9 +93,9 @@ parse_export_options(char *str,unsigned int *options,int noisy) * options are defined in main.h. * If USERS is NULL, the complete ring will be exported. */ int -export_pubkeys( strlist_t users, unsigned int options ) +export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options ) { - return do_export( users, 0, options ); + return do_export (ctrl, users, 0, options ); } /**************** @@ -103,35 +103,41 @@ export_pubkeys( strlist_t users, unsigned int options ) * been exported */ int -export_pubkeys_stream( IOBUF out, strlist_t users, - KBNODE *keyblock_out, unsigned int options ) +export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, + kbnode_t *keyblock_out, unsigned int options ) { - int any, rc; - - rc = do_export_stream( out, users, 0, keyblock_out, options, &any ); - if( !rc && !any ) - rc = -1; - return rc; + int any, rc; + + rc = do_export_stream (ctrl, out, users, 0, keyblock_out, options, &any); + if (!rc && !any) + rc = -1; + return rc; } int -export_seckeys( strlist_t users ) +export_seckeys (ctrl_t ctrl, strlist_t users ) { /* Use only relevant options for the secret key. */ unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT); - return do_export( users, 1, options ); + return do_export (ctrl, users, 1, options); } int -export_secsubkeys( strlist_t users ) +export_secsubkeys (ctrl_t ctrl, strlist_t users ) { /* Use only relevant options for the secret key. */ unsigned int options = (opt.export_options & EXPORT_SEXP_FORMAT); - return do_export( users, 2, options ); + return do_export (ctrl, users, 2, options); } + +/* Export the keys identified by the list of strings in USERS. If + Secret is false public keys will be exported. With secret true + secret keys will be exported; in this case 1 means the entire + secret keyblock and 2 only the subkeys. OPTIONS are the export + options to apply. */ static int -do_export( strlist_t users, int secret, unsigned int options ) +do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options ) { IOBUF out = NULL; int any, rc; @@ -156,7 +162,7 @@ do_export( strlist_t users, int secret, unsigned int options ) push_compress_filter (out,&zfx,default_compress_algo()); } - rc = do_export_stream ( out, users, secret, NULL, options, &any ); + rc = do_export_stream (ctrl, out, users, secret, NULL, options, &any ); if ( rc || !any ) iobuf_cancel (out); @@ -275,11 +281,324 @@ exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node) } -/* If keyblock_out is non-NULL, AND the exit code is zero, then it - contains a pointer to the first keyblock found and exported. No - other keyblocks are exported. The caller must free it. */ +/* Return a canonicalized public key algoithms. This is used to + compare different flavors of algorithms (e.g. ELG and ELG_E are + considered the same). */ static int -do_export_stream (iobuf_t out, strlist_t users, int secret, +canon_pubkey_algo (int algo) +{ + switch (algo) + { + case GCRY_PK_RSA: + case GCRY_PK_RSA_E: + case GCRY_PK_RSA_S: return GCRY_PK_RSA; + case GCRY_PK_ELG: + case GCRY_PK_ELG_E: return GCRY_PK_ELG; + default: return algo; + } +} + + +/* Use the key transfer format given in S_PGP to create the secinfo + structure in PK and chnage the parameter array in PK to include the + secret parameters. */ +static gpg_error_t +transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk) +{ + gpg_error_t err; + gcry_sexp_t top_list; + gcry_sexp_t list = NULL; + 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; + struct seckey_info *ski; + + 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); + 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 || nskey > PUBKEY_MAX_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"); */ + /* } */ + + if (!is_v4 || is_protected != 2 ) + { + /* We only support the v4 format and a SHA-1 checksum. */ + err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + goto leave; + } + + /* Do some sanity checks. */ + if (s2k_count <= 1024) + { + /* The count must be larger so that encode_s2k_iterations does + not fall into a backward compatibility mode. */ + err = gpg_error (GPG_ERR_INV_DATA); + goto leave; + } + if (canon_pubkey_algo (pubkey_algo) != canon_pubkey_algo (pk->pubkey_algo)) + { + err = gpg_error (GPG_ERR_PUBKEY_ALGO); + goto leave; + } + err = openpgp_cipher_test_algo (protect_algo); + if (err) + goto leave; + err = openpgp_md_test_algo (s2k_algo); + if (err) + goto leave; + + /* Check that the public key parameters match. */ + for (idx=0; idx < npkey; idx++) + if (gcry_mpi_get_flag (pk->pkey[idx], GCRYMPI_FLAG_OPAQUE) + || gcry_mpi_get_flag (skey[idx], GCRYMPI_FLAG_OPAQUE) + || gcry_mpi_cmp (pk->pkey[idx], skey[idx])) + { + err = gpg_error (GPG_ERR_BAD_PUBKEY); + goto leave; + } + + /* Check that the first secret key parameter in SKEY is encrypted + and that there are no more secret key parameters. The latter is + guaranteed by the v4 packet format. */ + if (!gcry_mpi_get_flag (skey[npkey], GCRYMPI_FLAG_OPAQUE)) + goto bad_seckey; + if (npkey+1 < DIM (skey) && skey[npkey+1]) + goto bad_seckey; + + /* Check that the secret key parameters in PK are all set to NULL. */ + for (idx=npkey; idx < nskey; idx++) + if (pk->pkey[idx]) + goto bad_seckey; + + /* Now build the protection info. */ + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); + if (!ski) + { + err = gpg_error_from_syserror (); + goto leave; + } + + ski->is_protected = 1; + ski->sha1chk = 1; + ski->algo = protect_algo; + ski->s2k.mode = s2k_mode; + ski->s2k.hash_algo = s2k_algo; + assert (sizeof ski->s2k.salt == sizeof s2k_salt); + memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt); + ski->s2k.count = encode_s2k_iterations (s2k_count); + assert (ivlen <= sizeof ski->iv); + memcpy (ski->iv, iv, ivlen); + ski->ivlen = ivlen; + + /* Store the protected secret key parameter. */ + pk->pkey[npkey] = skey[npkey]; + skey[npkey] = NULL; + + /* That's it. */ + + leave: + gcry_sexp_release (list); + gcry_sexp_release (top_list); + for (idx=0; idx < skeyidx; idx++) + gcry_mpi_release (skey[idx]); + return err; + + bad_seckey: + err = gpg_error (GPG_ERR_BAD_SECKEY); + goto leave; + + outofmem: + err = gpg_error (GPG_ERR_ENOMEM); + goto leave; +} + +/* Export the keys identified by the list of strings in USERS to the + stream OUT. If Secret is false public keys will be exported. With + secret true secret keys will be exported; in this case 1 means the + entire secret keyblock and 2 only the subkeys. OPTIONS are the + export options to apply. If KEYBLOCK_OUT is not NULL, AND the exit + code is zero, a pointer to the first keyblock found and exported + will be stored at this address; no other keyblocks are exported in + this case. The caller must free it the returned keyblock. If any + key has been exported true is stored at ANY. */ +static int +do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret, kbnode_t *keyblock_out, unsigned int options, int *any) { gpg_error_t err = 0; @@ -292,6 +611,7 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, KEYDB_HANDLE kdbhd; strlist_t sl; int indent = 0; + gcry_cipher_hd_t cipherhd = NULL; *any = 0; init_packet (&pkt); @@ -330,21 +650,51 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, if (secret) { log_error (_("exporting secret keys not allowed\n")); - err = G10ERR_GENERAL; + err = gpg_error (GPG_ERR_NOT_SUPPORTED); goto leave; } #endif + + /* For secret key export we need to setup a decryption context. */ + if (secret) + { + void *kek = NULL; + size_t keklen; + + err = agent_keywrap_key (ctrl, 1, &kek, &keklen); + if (err) + { + log_error ("error getting the KEK: %s\n", gpg_strerror (err)); + goto leave; + } + + /* Prepare a cipher context. */ + err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128, + GCRY_CIPHER_MODE_AESWRAP, 0); + if (!err) + err = gcry_cipher_setkey (cipherhd, kek, keklen); + if (err) + { + log_error ("error setting up an encryption context: %s\n", + gpg_strerror (err)); + goto leave; + } + xfree (kek); + kek = NULL; + } while (!(err = keydb_search2 (kdbhd, desc, ndesc, &descindex))) { - int sha1_warned = 0; int skip_until_subkey = 0; u32 keyid[2]; + PKT_public_key *pk; if (!users) desc[0].mode = KEYDB_SEARCH_MODE_NEXT; /* Read the keyblock. */ + release_kbnode (keyblock); + keyblock = NULL; err = keydb_get_keyblock (kdbhd, &keyblock); if (err) { @@ -352,60 +702,57 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, goto leave; } - if ((node=find_kbnode(keyblock, PKT_SECRET_KEY))) + node = find_kbnode (keyblock, PKT_PUBLIC_KEY); + if (!node) { - PKT_public_key *pk = node->pkt->pkt.public_key; + log_error ("public key packet not found in keyblock - skipped\n"); + continue; + } + pk = node->pkt->pkt.public_key; + keyid_from_pk (pk, keyid); - keyid_from_pk (pk, keyid); + /* If a secret key export is required we need to check whether + we have a secret key at all and if so create the seckey_info + structure. */ + if (secret) + { + if (agent_probe_any_secret_key (ctrl, keyblock)) + continue; /* No secret key (neither primary nor subkey). */ - /* We can't apply GNU mode 1001 on an unprotected key. */ - if( secret == 2 - && pk->seckey_info && !pk->seckey_info->is_protected ) + /* No v3 keys with GNU mode 1001. */ + if (secret == 2 && pk->version == 3) { - log_info (_("key %s: not protected - skipped\n"), + log_info (_("key %s: PGP 2.x style key - skipped\n"), keystr (keyid)); continue; } - /* No v3 keys with GNU mode 1001. */ - if( secret == 2 && pk->version == 3 ) + /* The agent does not yet allow to export v3 packets. It is + actually questionable whether we should allow them at + all. */ + if (pk->version == 3) { - log_info(_("key %s: PGP 2.x style key - skipped\n"), - keystr (keyid)); + log_info ("key %s: PGP 2.x style key (v3) export " + "not yet supported - skipped\n", keystr (keyid)); continue; } + } - /* It does not make sense to export a key with a primary - key on card using a non-key stub. We simply skip those - keys when used with --export-secret-subkeys. */ - if (secret == 2 - && pk->seckey_info && pk->seckey_info->is_protected - && pk->seckey_info->s2k.mode == 1002 ) - { - log_info(_("key %s: key material on-card - skipped\n"), - keystr (keyid)); - continue; - } - } - else - { - /* It's a public key export, so do the cleaning if - requested. Note that both export-clean and - export-minimal only apply to UID sigs (0x10, 0x11, 0x12, - and 0x13). A designated revocation is never stripped, - even with export-minimal set. */ - if ( (options & EXPORT_CLEAN) ) - clean_key (keyblock, opt.verbose, options&EXPORT_MINIMAL, - NULL, NULL); - } + /* Always do the cleaning on the public key part if requested. + Note that we don't yet set this option if we are exporting + secret keys. Note that both export-clean and export-minimal + only apply to UID sigs (0x10, 0x11, 0x12, and 0x13). A + designated revocation is never stripped, even with + export-minimal set. */ + if ((options & EXPORT_CLEAN)) + clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL); /* And write it. */ for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); ) { if (skip_until_subkey) { - if (node->pkt->pkttype==PKT_PUBLIC_SUBKEY - || node->pkt->pkttype==PKT_SECRET_SUBKEY) + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) skip_until_subkey = 0; else continue; @@ -425,8 +772,7 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, (plus the primary key, if the user didn't specifically request it). */ if (desc[descindex].exact - && (node->pkt->pkttype == PKT_PUBLIC_SUBKEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY)) + && node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if (!exact_subkey_match_p (desc+descindex, node)) { @@ -440,9 +786,9 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, skip in any case if the key is in that list. We need this whole mess because the import - function is not able to merge secret keys and - thus it is useless to output them as two separate - keys and have import merge them. */ + function of GnuPG < 2.1 is not able to merge + secret keys and thus it is useless to output them + as two separate keys and have import merge them. */ if (subkey_in_list_p (subkey_list, node)) skip_until_subkey = 1; /* Already processed this one. */ else @@ -508,88 +854,181 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, continue; } - if (secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY) + if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)) { - /* We don't want to export the secret parts of the - * primary key, this is done by temporary switching to - * GNU protection mode 1001. */ - int save_mode = node->pkt->pkt.public_key->seckey_info->s2k.mode; - node->pkt->pkt.public_key->seckey_info->s2k.mode = 1001; - if ((options&EXPORT_SEXP_FORMAT)) - err = build_sexp (out, node->pkt, &indent); + u32 subkidbuf[2], *subkid; + char *hexgrip, *serialno; + + pk = node->pkt->pkt.public_key; + if (node->pkt->pkttype == PKT_PUBLIC_KEY) + subkid = NULL; else - err = build_packet (out, node->pkt); - node->pkt->pkt.public_key->seckey_info->s2k.mode = save_mode; - } - else if (secret == 2 && node->pkt->pkttype == PKT_SECRET_SUBKEY - && (opt.export_options&EXPORT_RESET_SUBKEY_PASSWD)) - { - /* If the subkey is protected reset the passphrase to - export an unprotected subkey. This feature is useful - in cases of a subkey copied to an unattended machine - where a passphrase is not required. */ - err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); - goto leave; -#warning We need to implement this - /* PKT_secret_key *sk_save, *sk; */ + { + keyid_from_pk (pk, subkidbuf); + subkid = subkidbuf; + } - /* sk_save = node->pkt->pkt.secret_key; */ - /* sk = copy_secret_key (NULL, sk_save); */ - /* node->pkt->pkt.secret_key = sk; */ + if (pk->seckey_info) + { + log_error ("key %s: oops: seckey_info already set" + " - skipped\n", keystr_with_sub (keyid, subkid)); + skip_until_subkey = 1; + continue; + } + + err = hexkeygrip_from_pk (pk, &hexgrip); + if (err) + { + log_error ("key %s: error computing keygrip: %s" + " - skipped\n", keystr_with_sub (keyid, subkid), + gpg_strerror (err)); + skip_until_subkey = 1; + err = 0; + continue; + } - /* log_info (_("about to export an unprotected subkey\n")); */ - /* switch (is_secret_key_protected (sk)) */ - /* { */ - /* case -1: */ - /* err = gpg_error (GPG_ERR_PUBKEY_ALGO); */ - /* break; */ - /* case 0: */ - /* break; */ - /* default: */ - /* if (sk->protect.s2k.mode == 1001) */ - /* ; /\* No secret parts. *\/ */ - /* else if( sk->protect.s2k.mode == 1002 ) */ - /* ; /\* Card key stub. *\/ */ - /* else */ - /* { */ - /* /\* err = check_secret_key( sk, 0 ); *\/ */ - /* } */ - /* break; */ - /* } */ - /* if (err) */ - /* { */ - /* node->pkt->pkt.secret_key = sk_save; */ - /* free_secret_key (sk); */ - /* log_error (_("failed to unprotect the subkey: %s\n"), */ - /* g10_errstr (rc)); */ - /* goto leave; */ - /* } */ + if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY) + { + /* We are asked not to export the secret parts of + the primary key. Make up an error code to create + the stub. */ + err = GPG_ERR_NOT_FOUND; + serialno = NULL; + } + else + err = agent_get_keyinfo (ctrl, hexgrip, &serialno); - /* if ((options&EXPORT_SEXP_FORMAT)) */ - /* err = build_sexp (out, node->pkt, &indent); */ - /* else */ - /* err = build_packet (out, node->pkt); */ + if ((!err && serialno) + && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY) + { + /* It does not make sense to export a key with its + primary key on card using a non-key stub. Thus + we skip those keys when used with + --export-secret-subkeys. */ + log_info (_("key %s: key material on-card - skipped\n"), + keystr_with_sub (keyid, subkid)); + skip_until_subkey = 1; + } + else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND + || (!err && serialno)) + { + /* Create a key stub. */ + struct seckey_info *ski; + const char *s; + + pk->seckey_info = ski = xtrycalloc (1, sizeof *ski); + if (!ski) + { + err = gpg_error_from_syserror (); + xfree (hexgrip); + goto leave; + } - /* node->pkt->pkt.secret_key = sk_save; */ - /* free_secret_key (sk); */ + ski->is_protected = 1; + if (err) + ski->s2k.mode = 1001; /* GNU dummy (no secret key). */ + else + { + ski->s2k.mode = 1002; /* GNU-divert-to-card. */ + for (s=serialno; sizeof (ski->ivlen) && *s && s[1]; + ski->ivlen++, s += 2) + ski->iv[ski->ivlen] = xtoi_2 (s); + } + + if ((options&EXPORT_SEXP_FORMAT)) + err = build_sexp (out, node->pkt, &indent); + else + err = build_packet (out, node->pkt); + } + else if (!err) + { + /* FIXME: Move this spaghetti code into a separate + function. */ + unsigned char *wrappedkey = NULL; + size_t wrappedkeylen; + unsigned char *key = NULL; + size_t keylen, realkeylen; + gcry_sexp_t s_skey; + + if (opt.verbose) + log_info ("key %s: asking agent for the secret parts\n", + keystr_with_sub (keyid, subkid)); + + err = agent_export_key (ctrl, hexgrip, "Key foo", NULL, + &wrappedkey, &wrappedkeylen); + if (err) + goto unwraperror; + if (wrappedkeylen < 24) + { + err = gpg_error (GPG_ERR_INV_LENGTH); + goto unwraperror; + } + keylen = wrappedkeylen - 8; + key = xtrymalloc_secure (keylen); + if (!key) + { + err = gpg_error_from_syserror (); + goto unwraperror; + } + err = gcry_cipher_decrypt (cipherhd, key, keylen, + wrappedkey, wrappedkeylen); + if (err) + goto unwraperror; + realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err); + if (!realkeylen) + goto unwraperror; /* Invalid csexp. */ + + err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen); + xfree (key); + key = NULL; + if (err) + goto unwraperror; + err = transfer_format_to_openpgp (s_skey, pk); + gcry_sexp_release (s_skey); + if (err) + goto unwraperror; + + if ((options&EXPORT_SEXP_FORMAT)) + err = build_sexp (out, node->pkt, &indent); + else + err = build_packet (out, node->pkt); + goto unwraperror_leave; + + unwraperror: + xfree (wrappedkey); + xfree (key); + if (err) + { + log_error ("key %s: error receiving key from agent:" + " %s%s\n", + keystr_with_sub (keyid, subkid), + gpg_strerror (err), + gpg_err_code (err) == GPG_ERR_FULLY_CANCELED? + "":_(" - skipped")); + if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) + goto leave; + skip_until_subkey = 1; + err = 0; + } + unwraperror_leave: + ; + } + else + { + log_error ("key %s: error getting keyinfo from agent: %s" + " - skipped\n", keystr_with_sub (keyid, subkid), + gpg_strerror (err)); + skip_until_subkey = 1; + err = 0; + } + + xfree (pk->seckey_info); + pk->seckey_info = NULL; + xfree (hexgrip); } else { - /* Warn the user if the secret key or any of the secret - subkeys are protected with SHA1 and we have - simple_sk_checksum set. */ - if (!sha1_warned && opt.simple_sk_checksum && - (node->pkt->pkttype == PKT_SECRET_KEY - || node->pkt->pkttype == PKT_SECRET_SUBKEY) - && node->pkt->pkt.public_key->seckey_info->sha1chk) - { - /* I hope this warning doesn't confuse people. */ - log_info(_("WARNING: secret key %s does not have a " - "simple SK checksum\n"), keystr (keyid)); - - sha1_warned = 1; - } - if ((options&EXPORT_SEXP_FORMAT)) err = build_sexp (out, node->pkt, &indent); else @@ -602,6 +1041,9 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, node->pkt->pkttype, gpg_strerror (err)); goto leave; } + + if (!skip_until_subkey) + *any = 1; } if ((options&EXPORT_SEXP_FORMAT) && indent) @@ -611,10 +1053,9 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, iobuf_put (out, '\n'); } - ++*any; - if(keyblock_out) + if (keyblock_out) { - *keyblock_out=keyblock; + *keyblock_out = keyblock; break; } } @@ -624,10 +1065,11 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, iobuf_put (out, ')'); iobuf_put (out, '\n'); } - if( err == -1 ) + if (err == -1) err = 0; leave: + gcry_cipher_close (cipherhd); release_subkey_list (subkey_list); xfree(desc); keydb_release (kdbhd); @@ -672,6 +1114,10 @@ do_export_stream (iobuf_t out, strlist_t users, int secret, static int build_sexp_seckey (iobuf_t out, PACKET *pkt, int *indent) { + (void)out; + (void)pkt; + (void)indent; + /* FIXME: Not yet implemented. */ return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* PKT_secret_key *sk = pkt->pkt.secret_key; */ @@ -759,4 +1205,3 @@ build_sexp (iobuf_t out, PACKET *pkt, int *indent) } return rc; } - diff --git a/g10/free-packet.c b/g10/free-packet.c index 47d89eed5..5c4a0fcb5 100644 --- a/g10/free-packet.c +++ b/g10/free-packet.c @@ -25,9 +25,9 @@ #include #include "gpg.h" +#include "util.h" #include "packet.h" #include "../common/iobuf.h" -#include "util.h" #include "cipher.h" #include "options.h" diff --git a/g10/getkey.c b/g10/getkey.c index 401e66879..8d983487b 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -676,7 +676,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist, to import the key via the online mechanisms defined by --auto-key-locate. */ int -get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk, +get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk, const char *name, KBNODE * ret_keyblock, KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl) { @@ -770,21 +770,21 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk, case AKL_CERT: mechanism = "DNS CERT"; glo_ctrl.in_auto_key_retrieve++; - rc = keyserver_import_cert (name, &fpr, &fpr_len); + rc = keyserver_import_cert (ctrl, name, &fpr, &fpr_len); glo_ctrl.in_auto_key_retrieve--; break; case AKL_PKA: mechanism = "PKA"; glo_ctrl.in_auto_key_retrieve++; - rc = keyserver_import_pka (name, &fpr, &fpr_len); + rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len); glo_ctrl.in_auto_key_retrieve--; break; case AKL_LDAP: mechanism = "LDAP"; glo_ctrl.in_auto_key_retrieve++; - rc = keyserver_import_ldap (name, &fpr, &fpr_len); + rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len); glo_ctrl.in_auto_key_retrieve--; break; @@ -797,9 +797,8 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk, { mechanism = opt.keyserver->uri; glo_ctrl.in_auto_key_retrieve++; - rc = - keyserver_import_name (name, &fpr, &fpr_len, - opt.keyserver); + rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len, + opt.keyserver); glo_ctrl.in_auto_key_retrieve--; } else @@ -816,7 +815,8 @@ get_pubkey_byname (GETKEY_CTX * retctx, PKT_public_key * pk, mechanism = akl->spec->uri; keyserver = keyserver_match (akl->spec); glo_ctrl.in_auto_key_retrieve++; - rc = keyserver_import_name (name, &fpr, &fpr_len, keyserver); + rc = keyserver_import_name (ctrl, + name, &fpr, &fpr_len, keyserver); glo_ctrl.in_auto_key_retrieve--; } break; diff --git a/g10/gpg.c b/g10/gpg.c index b0383627e..f553c6e16 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -37,9 +37,9 @@ #define INCLUDED_BY_MAIN_MODULE 1 #include "gpg.h" #include -#include "packet.h" #include "../common/iobuf.h" #include "util.h" +#include "packet.h" #include "main.h" #include "options.h" #include "keydb.h" @@ -273,7 +273,6 @@ enum cmd_and_opt_values oS2KDigest, oS2KCipher, oS2KCount, - oSimpleSKChecksum, oDisplayCharset, oNotDashEscaped, oEscapeFrom, @@ -565,7 +564,6 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oS2KDigest, "s2k-digest-algo", "@"), ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"), ARGPARSE_s_i (oS2KCount, "s2k-count", "@"), - ARGPARSE_s_n (oSimpleSKChecksum, "simple-sk-checksum", "@"), ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"), ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"), ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"), @@ -2504,7 +2502,6 @@ main (int argc, char **argv) else opt.s2k_count = 0; /* Auto-calibrate when needed. */ break; - case oSimpleSKChecksum: opt.simple_sk_checksum = 1; break; case oNoEncryptTo: opt.no_encrypt_to = 1; break; case oEncryptTo: /* store the recipient in the second list */ sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); @@ -2966,8 +2963,8 @@ main (int argc, char **argv) } } - - if( configfp ) { + if (configfp) + { fclose( configfp ); configfp = NULL; /* Remember the first config file name. */ @@ -2977,10 +2974,10 @@ main (int argc, char **argv) xfree(configname); configname = NULL; goto next_pass; - } - xfree( configname ); configname = NULL; - if( log_get_errorcount(0) ) - g10_exit(2); + } + xfree(configname); configname = NULL; + if (log_get_errorcount (0)) + g10_exit(2); /* The command --gpgconf-list is pretty simple and may be called directly after the option parsing. */ @@ -3405,7 +3402,7 @@ main (int argc, char **argv) if(fname && utf8_strings) opt.flags.utf8_filename=1; - ctrl = xtrycalloc (1, sizeof *ctrl); + ctrl = xcalloc (1, sizeof *ctrl); gpg_init_default_ctrl (ctrl); switch( cmd ) { @@ -3463,12 +3460,12 @@ main (int argc, char **argv) case aEncr: /* encrypt the given file */ if(multifile) - encrypt_crypt_files(argc, argv, remusr); + encrypt_crypt_files (ctrl, argc, argv, remusr); else { if( argc > 1 ) wrong_args(_("--encrypt [filename]")); - if( (rc = encrypt_crypt (-1, fname, remusr, 0, NULL, -1)) ) + if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) ) log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); } @@ -3489,7 +3486,7 @@ main (int argc, char **argv) " while in %s mode\n"),compliance_option_string()); else { - if( (rc = encrypt_crypt (-1, fname, remusr, 1, NULL, -1)) ) + if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) ) log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); } @@ -3509,7 +3506,7 @@ main (int argc, char **argv) strcpy(sl->d, fname); } } - if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) ) + if( (rc = sign_file (ctrl, sl, detached_sig, locusr, 0, NULL, NULL)) ) log_error("signing failed: %s\n", g10_errstr(rc) ); free_strlist(sl); break; @@ -3523,7 +3520,7 @@ main (int argc, char **argv) } else sl = NULL; - if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) ) + if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 1, remusr, NULL))) log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); free_strlist(sl); @@ -3547,7 +3544,8 @@ main (int argc, char **argv) } else sl = NULL; - if( (rc = sign_file(sl, detached_sig, locusr, 2, remusr, NULL)) ) + if ((rc = sign_file (ctrl, sl, detached_sig, locusr, + 2, remusr, NULL))) log_error("%s: symmetric+sign+encrypt failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) ); free_strlist(sl); @@ -3572,26 +3570,26 @@ main (int argc, char **argv) break; case aVerify: - if(multifile) + if (multifile) { - if( (rc = verify_files( argc, argv ) )) + if ((rc = verify_files (ctrl, argc, argv))) log_error("verify files failed: %s\n", g10_errstr(rc) ); } else { - if( (rc = verify_signatures( argc, argv ) )) + if ((rc = verify_signatures (ctrl, argc, argv))) log_error("verify signatures failed: %s\n", g10_errstr(rc) ); } break; case aDecrypt: - if(multifile) - decrypt_messages(argc, argv); + if (multifile) + decrypt_messages (ctrl, argc, argv); else { if( argc > 1 ) wrong_args(_("--decrypt [filename]")); - if( (rc = decrypt_message( fname ) )) + if( (rc = decrypt_message (ctrl, fname) )) log_error("decrypt_message failed: %s\n", g10_errstr(rc) ); } break; @@ -3616,7 +3614,7 @@ main (int argc, char **argv) append_to_strlist( &sl, "save" ); username = make_username( fname ); - keyedit_menu (username, locusr, sl, 0, 0 ); + keyedit_menu (ctrl, username, locusr, sl, 0, 0 ); xfree(username); free_strlist(sl); break; @@ -3629,11 +3627,11 @@ main (int argc, char **argv) sl = NULL; for( argc--, argv++ ; argc; argc--, argv++ ) append_to_strlist( &sl, *argv ); - keyedit_menu( username, locusr, sl, 0, 1 ); + keyedit_menu (ctrl, username, locusr, sl, 0, 1 ); free_strlist(sl); } else - keyedit_menu(username, locusr, NULL, 0, 1 ); + keyedit_menu (ctrl, username, locusr, NULL, 0, 1 ); xfree(username); break; @@ -3669,21 +3667,21 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list( sl, 0 ); + public_key_list (ctrl, sl, 0); free_strlist(sl); break; case aListSecretKeys: sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); - secret_key_list( sl ); + secret_key_list (ctrl, sl); free_strlist(sl); break; case aLocateKeys: sl = NULL; for (; argc; argc--, argv++) add_to_strlist2( &sl, *argv, utf8_strings ); - public_key_list (sl, 1); + public_key_list (ctrl, sl, 1); free_strlist (sl); break; @@ -3718,11 +3716,11 @@ main (int argc, char **argv) for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); if( cmd == aSendKeys ) - rc=keyserver_export( sl ); + rc = keyserver_export (ctrl, sl ); else if( cmd == aRecvKeys ) - rc=keyserver_import( sl ); + rc = keyserver_import (ctrl, sl ); else - rc=export_pubkeys( sl, opt.export_options ); + rc = export_pubkeys (ctrl, sl, opt.export_options); if(rc) { if(cmd==aSendKeys) @@ -3739,7 +3737,7 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); - rc=keyserver_search( sl ); + rc = keyserver_search (ctrl, sl); if(rc) log_error(_("keyserver search failed: %s\n"),g10_errstr(rc)); free_strlist(sl); @@ -3749,7 +3747,7 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); - rc=keyserver_refresh(sl); + rc = keyserver_refresh (ctrl, sl); if(rc) log_error(_("keyserver refresh failed: %s\n"),g10_errstr(rc)); free_strlist(sl); @@ -3759,7 +3757,7 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); - rc=keyserver_fetch(sl); + rc = keyserver_fetch (ctrl, sl); if(rc) log_error("key fetch failed: %s\n",g10_errstr(rc)); free_strlist(sl); @@ -3769,7 +3767,7 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); - export_seckeys( sl ); + export_seckeys (ctrl, sl); free_strlist(sl); break; @@ -3777,7 +3775,7 @@ main (int argc, char **argv) sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); - export_secsubkeys( sl ); + export_secsubkeys (ctrl, sl); free_strlist(sl); break; @@ -3987,11 +3985,11 @@ main (int argc, char **argv) sl = NULL; for (argc--, argv++ ; argc; argc--, argv++) append_to_strlist (&sl, *argv); - card_edit (sl); + card_edit (ctrl, sl); free_strlist (sl); } else - card_edit (NULL); + card_edit (ctrl, NULL); break; case aChangePIN: @@ -4045,7 +4043,7 @@ main (int argc, char **argv) set_packet_list_mode(1); opt.list_packets=1; } - rc = proc_packets(NULL, a ); + rc = proc_packets (ctrl, NULL, a ); if( rc ) log_error("processing message failed: %s\n", g10_errstr(rc) ); iobuf_close(a); diff --git a/g10/gpgv.c b/g10/gpgv.c index b56b1c046..b342d2481 100644 --- a/g10/gpgv.c +++ b/g10/gpgv.c @@ -35,9 +35,9 @@ #define INCLUDED_BY_MAIN_MODULE 1 #include "gpg.h" +#include "util.h" #include "packet.h" #include "iobuf.h" -#include "util.h" #include "main.h" #include "options.h" #include "keydb.h" @@ -140,8 +140,9 @@ main( int argc, char **argv ) ARGPARSE_ARGS pargs; int rc=0; strlist_t sl; - strlist_t nrings=NULL; + strlist_t nrings = NULL; unsigned configlineno; + ctrl_t ctrl; set_strusage (my_strusage); log_set_prefix ("gpgv", 1); @@ -201,10 +202,14 @@ main( int argc, char **argv ) keydb_add_resource (sl->d, 8); FREE_STRLIST (nrings); + + ctrl = xcalloc (1, sizeof *ctrl); - if ( (rc = verify_signatures( argc, argv ) )) + if ((rc = verify_signatures (ctrl, argc, argv))) log_error("verify signatures failed: %s\n", g10_errstr(rc) ); + xfree (ctrl); + /* cleanup */ g10_exit (0); return 8; /*NOTREACHED*/ @@ -377,8 +382,9 @@ get_override_session_key (DEK *dek, const char *string) /* Stub: */ int -decrypt_data (void *procctx, PKT_encrypted *ed, DEK *dek) +decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek) { + (void)ctrl; (void)procctx; (void)ed; (void)dek; diff --git a/g10/import.c b/g10/import.c index e3e7824a2..605c3b8ab 100644 --- a/g10/import.c +++ b/g10/import.c @@ -64,10 +64,11 @@ 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 void revocation_present (ctrl_t ctrl, kbnode_t keyblock); +static int import_one (ctrl_t ctrl, + 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 (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, @@ -265,7 +266,8 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats, while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) { if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY ) - rc = import_one( fname, keyblock, stats, fpr, fpr_len, options, 0); + rc = import_one (ctrl, fname, keyblock, + stats, fpr, fpr_len, options, 0); else if( keyblock->pkt->pkttype == PKT_SECRET_KEY ) rc = import_secret_one (ctrl, fname, keyblock, stats, options); else if( keyblock->pkt->pkttype == PKT_SIGNATURE @@ -614,9 +616,9 @@ check_prefs_warning(PKT_public_key *pk) } static void -check_prefs(KBNODE keyblock) +check_prefs (ctrl_t ctrl, kbnode_t keyblock) { - KBNODE node; + kbnode_t node; PKT_public_key *pk; int problem=0; @@ -711,7 +713,7 @@ check_prefs(KBNODE keyblock) append_to_strlist(&sl,"updpref"); append_to_strlist(&sl,"save"); - keyedit_menu( username, locusr, sl, 1, 1 ); + keyedit_menu (ctrl, username, locusr, sl, 1, 1 ); free_strlist(sl); free_strlist(locusr); } @@ -728,7 +730,8 @@ check_prefs(KBNODE keyblock) * which called gpg. */ static int -import_one( const char *fname, KBNODE keyblock, struct stats_s *stats, +import_one (ctrl_t ctrl, + const char *fname, KBNODE keyblock, struct stats_s *stats, unsigned char **fpr,size_t *fpr_len,unsigned int options, int from_sk ) { @@ -1060,15 +1063,15 @@ import_one( const char *fname, KBNODE keyblock, struct stats_s *stats, if (mod_key) { - revocation_present (keyblock_orig); + revocation_present (ctrl, keyblock_orig); if (!from_sk && have_secret_key_with_kid (keyid)) - check_prefs (keyblock_orig); + check_prefs (ctrl, keyblock_orig); } else if (new_key) { - revocation_present (keyblock); + revocation_present (ctrl, keyblock); if (!from_sk && have_secret_key_with_kid (keyid)) - check_prefs (keyblock); + check_prefs (ctrl, keyblock); } release_kbnode( keyblock_orig ); @@ -1425,7 +1428,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, keystr_from_pk (pk)); else { - import_one (fname, pub_keyblock, stats, + import_one (ctrl, fname, pub_keyblock, stats, NULL, NULL, opt.import_options, 1); /* Fixme: We should check for an invalid keyblock and cancel the secret key import in this case. */ @@ -1448,7 +1451,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock, keystr_from_pk (pk)); if (is_status_enabled ()) print_import_ok (pk, 1|16); - check_prefs (node); + check_prefs (ctrl, node); } release_kbnode (node); } @@ -2051,10 +2054,10 @@ collapse_uids( KBNODE *keyblock ) present. This may be called without the benefit of merge_xxxx so you can't rely on pk->revkey and friends. */ static void -revocation_present(KBNODE keyblock) +revocation_present (ctrl_t ctrl, kbnode_t keyblock) { - KBNODE onode,inode; - PKT_public_key *pk=keyblock->pkt->pkt.public_key; + kbnode_t onode, inode; + PKT_public_key *pk = keyblock->pkt->pkt.public_key; for(onode=keyblock->next;onode;onode=onode->next) { @@ -2106,9 +2109,10 @@ revocation_present(KBNODE keyblock) log_info(_("WARNING: key %s may be revoked:" " fetching revocation key %s\n"), tempkeystr,keystr(keyid)); - keyserver_import_fprint(sig->revkey[idx]->fpr, - MAX_FINGERPRINT_LEN, - opt.keyserver); + keyserver_import_fprint (ctrl, + sig->revkey[idx]->fpr, + MAX_FINGERPRINT_LEN, + opt.keyserver); /* Do we have it now? */ rc=get_pubkey_byfprint_fast (NULL, diff --git a/g10/keydb.h b/g10/keydb.h index 63f42a572..eab59e0a5 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -157,8 +157,10 @@ void show_revocation_reason( PKT_public_key *pk, int mode ); int check_signatures_trust( PKT_signature *sig ); void release_pk_list (PK_LIST pk_list); -int build_pk_list (strlist_t rcpts, PK_LIST *ret_pk_list, unsigned use); -gpg_error_t find_and_check_key (const char *name, unsigned int use, +int build_pk_list (ctrl_t ctrl, + strlist_t rcpts, PK_LIST *ret_pk_list, unsigned use); +gpg_error_t find_and_check_key (ctrl_t ctrl, + const char *name, unsigned int use, int mark_hidden, pk_list_t *pk_list_addr); int algo_available( preftype_t preftype, int algo, @@ -204,7 +206,8 @@ void getkey_disable_caches(void); int get_pubkey( PKT_public_key *pk, u32 *keyid ); int get_pubkey_fast ( PKT_public_key *pk, u32 *keyid ); KBNODE get_pubkeyblock( u32 *keyid ); -int get_pubkey_byname (GETKEY_CTX *rx, PKT_public_key *pk, const char *name, +int get_pubkey_byname (ctrl_t ctrl, + GETKEY_CTX *rx, PKT_public_key *pk, const char *name, KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd, int include_unusable, int no_akl ); int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk, diff --git a/g10/keyedit.c b/g10/keyedit.c index 86dacfff5..d1cacaf39 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -60,7 +60,7 @@ static void menu_deluid (KBNODE pub_keyblock); static int menu_delsig (KBNODE pub_keyblock); static int menu_clean (KBNODE keyblock, int self_only); static void menu_delkey (KBNODE pub_keyblock); -static int menu_addrevoker (KBNODE pub_keyblock, int sensitive); +static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive); static int menu_expire (KBNODE pub_keyblock); static int menu_backsign (KBNODE pub_keyblock); static int menu_set_primary_uid (KBNODE pub_keyblock); @@ -1586,7 +1586,7 @@ keyedit_completion (const char *text, int start, int end) /* Main function of the menu driven key editor. */ void -keyedit_menu (const char *username, strlist_t locusr, +keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check) { enum cmdids cmd = 0; @@ -1599,7 +1599,6 @@ keyedit_menu (const char *username, strlist_t locusr, int modified = 0; int toggle; int have_commands = !!commands; - ctrl_t ctrl = NULL; /* Dummy for now. */ if (opt.command_fd != -1) ; @@ -1623,7 +1622,7 @@ keyedit_menu (const char *username, strlist_t locusr, #endif /* Get the public key */ - err = get_pubkey_byname (NULL, NULL, username, &keyblock, &kdbhd, 1, 1); + err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1); if (err) goto leave; if (fix_keyblock (keyblock)) @@ -2095,7 +2094,7 @@ keyedit_menu (const char *username, strlist_t locusr, if (ascii_strcasecmp (arg_string, "sensitive") == 0) sensitive = 1; - if (menu_addrevoker (keyblock, sensitive)) + if (menu_addrevoker (ctrl, keyblock, sensitive)) { redisplay = 1; modified = 1; @@ -2886,9 +2885,10 @@ show_key_with_all_names (KBNODE keyblock, int only_marked, int with_revoker, if (pk->is_revoked) { char *user = get_user_id_string_native (pk->revoked.keyid); - const char *algo = gcry_pk_algo_name (pk->revoked.algo); - tty_printf (_("This key was revoked on %s by %s key %s\n"), - revokestr_from_pk (pk), algo ? algo : "?", user); + tty_printf (_("The following key was revoked on" + " %s by %s key %s\n"), + revokestr_from_pk (pk), + gcry_pk_algo_name (pk->revoked.algo), user); xfree (user); } @@ -3444,7 +3444,7 @@ menu_delkey (KBNODE pub_keyblock) * the keyblock. Returns true if there is a new revoker. */ static int -menu_addrevoker (KBNODE pub_keyblock, int sensitive) +menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) { PKT_public_key *pk = NULL; PKT_public_key *revoker_pk = NULL; @@ -3508,7 +3508,7 @@ menu_addrevoker (KBNODE pub_keyblock, int sensitive) primary keys only, but some casual testing shows that PGP and GnuPG both can handle a designated revocation from a subkey. */ revoker_pk->req_usage = PUBKEY_USAGE_CERT; - rc = get_pubkey_byname (NULL, revoker_pk, answer, NULL, NULL, 1, 1); + rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 1); if (rc) { log_error (_("key \"%s\" not found: %s\n"), answer, diff --git a/g10/keygen.c b/g10/keygen.c index 33a5a217c..00ad26ecb 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1123,7 +1123,7 @@ key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, { for (i=0; ikeyid, sub_pk->keyid); + return keystr_with_sub (main_pk->keyid, sub_pk? sub_pk->keyid:NULL); } diff --git a/g10/keylist.c b/g10/keylist.c index 2d3574a6d..254513a76 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -43,7 +43,7 @@ static void list_all (int); static void list_one (strlist_t names, int secret); -static void locate_one (strlist_t names); +static void locate_one (ctrl_t ctrl, strlist_t names); static void print_card_serialno (PKT_public_key *sk); struct sig_stats @@ -61,7 +61,7 @@ static estream_t attrib_fp; With LOCATE_MODE set the locate algorithm is used to find a key. */ void -public_key_list (strlist_t list, int locate_mode) +public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode) { if (opt.with_colons) { @@ -107,7 +107,7 @@ public_key_list (strlist_t list, int locate_mode) check_trustdb_stale (); if (locate_mode) - locate_one (list); + locate_one (ctrl, list); else if (!list) list_all (0); else @@ -116,8 +116,10 @@ public_key_list (strlist_t list, int locate_mode) void -secret_key_list (strlist_t list) +secret_key_list (ctrl_t ctrl, strlist_t list) { + (void)ctrl; + check_trustdb_stale (); if (!list) @@ -533,7 +535,7 @@ list_one (strlist_t names, int secret) static void -locate_one (strlist_t names) +locate_one (ctrl_t ctrl, strlist_t names) { int rc = 0; strlist_t sl; @@ -545,7 +547,7 @@ locate_one (strlist_t names) for (sl = names; sl; sl = sl->next) { - rc = get_pubkey_byname (&ctx, NULL, sl->d, &keyblock, NULL, 1, 0); + rc = get_pubkey_byname (ctrl, &ctx, NULL, sl->d, &keyblock, NULL, 1, 0); if (rc) { if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY) diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h index 9f05c1880..cbf3c04a8 100644 --- a/g10/keyserver-internal.h +++ b/g10/keyserver-internal.h @@ -33,20 +33,23 @@ struct keyserver_spec *parse_keyserver_uri(const char *string, const char *configname, unsigned int configlineno); struct keyserver_spec *parse_preferred_keyserver(PKT_signature *sig); -int keyserver_export(strlist_t users); -int keyserver_import(strlist_t users); -int keyserver_import_fprint(const byte *fprint,size_t fprint_len, - struct keyserver_spec *keyserver); -int keyserver_import_keyid(u32 *keyid,struct keyserver_spec *keyserver); -int keyserver_refresh(strlist_t users); -int keyserver_search(strlist_t tokens); -int keyserver_fetch(strlist_t urilist); -int keyserver_import_cert(const char *name, - unsigned char **fpr,size_t *fpr_len); -int keyserver_import_pka(const char *name,unsigned char **fpr,size_t *fpr_len); -int keyserver_import_name(const char *name,unsigned char **fpr,size_t *fpr_len, - struct keyserver_spec *keyserver); -int keyserver_import_ldap(const char *name, - unsigned char **fpr,size_t *fpr_len); +int keyserver_export (ctrl_t ctrl, strlist_t users); +int keyserver_import (ctrl_t ctrl, strlist_t users); +int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, + struct keyserver_spec *keyserver); +int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid, + struct keyserver_spec *keyserver); +int keyserver_refresh (ctrl_t ctrl, strlist_t users); +int keyserver_search (ctrl_t ctrl, strlist_t tokens); +int keyserver_fetch (ctrl_t ctrl, strlist_t urilist); +int keyserver_import_cert (ctrl_t ctrl, const char *name, + unsigned char **fpr,size_t *fpr_len); +int keyserver_import_pka (ctrl_t ctrl, + const char *name,unsigned char **fpr,size_t *fpr_len); +int keyserver_import_name (ctrl_t ctrl, + const char *name,unsigned char **fpr,size_t *fpr_len, + struct keyserver_spec *keyserver); +int keyserver_import_ldap (ctrl_t ctrl, const char *name, + unsigned char **fpr,size_t *fpr_len); #endif /* !_KEYSERVER_INTERNAL_H_ */ diff --git a/g10/keyserver.c b/g10/keyserver.c index 39c3d69d9..730c52fb9 100644 --- a/g10/keyserver.c +++ b/g10/keyserver.c @@ -89,10 +89,10 @@ static struct parse_options keyserver_opts[]= {NULL,0,NULL,NULL} }; -static int keyserver_work(enum ks_action action,strlist_t list, - KEYDB_SEARCH_DESC *desc,int count, - unsigned char **fpr,size_t *fpr_len, - struct keyserver_spec *keyserver); +static int keyserver_work (ctrl_t ctrl, enum ks_action action,strlist_t list, + KEYDB_SEARCH_DESC *desc,int count, + unsigned char **fpr,size_t *fpr_len, + struct keyserver_spec *keyserver); /* Reasonable guess */ #define DEFAULT_MAX_CERT_SIZE 16384 @@ -732,7 +732,8 @@ parse_keyrec(char *keystring) (cosmetics, really) and to better take advantage of the keyservers that can do multiple fetches in one go (LDAP). */ static int -show_prompt(KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search) +show_prompt (ctrl_t ctrl, + KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search) { char *answer; @@ -765,8 +766,8 @@ show_prompt(KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search) while((num=strsep(&split," ,"))!=NULL) if(atoi(num)>=1 && atoi(num)<=numdesc) - keyserver_work(KS_GET,NULL,&desc[atoi(num)-1],1, - NULL,NULL,opt.keyserver); + keyserver_work (ctrl, KS_GET,NULL,&desc[atoi(num)-1],1, + NULL,NULL,opt.keyserver); xfree(answer); return 1; @@ -779,7 +780,7 @@ show_prompt(KEYDB_SEARCH_DESC *desc,int numdesc,int count,const char *search) small, it will grow safely. If negative it disables the "Key x-y of z" messages. searchstr should be UTF-8 (rather than native). */ static void -keyserver_search_prompt(IOBUF buffer,const char *searchstr) +keyserver_search_prompt (ctrl_t ctrl, IOBUF buffer,const char *searchstr) { int i=0,validcount=0,started=0,header=0,count=1; unsigned int maxlen,buflen,numlines=0; @@ -872,7 +873,7 @@ keyserver_search_prompt(IOBUF buffer,const char *searchstr) for(;;) { - if(show_prompt(desc,i,validcount?count:0,localstr)) + if (show_prompt (ctrl, desc, i, validcount?count:0, localstr)) break; validcount=0; } @@ -901,7 +902,7 @@ keyserver_search_prompt(IOBUF buffer,const char *searchstr) /* screen_lines - 1 for the prompt. */ if(numlines+keyrec->lines>opt.screen_lines-1) { - if(show_prompt(desc,i,validcount?count:0,localstr)) + if (show_prompt (ctrl, desc, i, validcount?count:0, localstr)) break; else numlines=0; @@ -977,9 +978,10 @@ direct_uri_map(const char *scheme,unsigned int is_direct) #define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\"" static int -keyserver_spawn(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, - int count,int *prog,unsigned char **fpr,size_t *fpr_len, - struct keyserver_spec *keyserver) +keyserver_spawn (ctrl_t ctrl, + enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, + int count,int *prog,unsigned char **fpr,size_t *fpr_len, + struct keyserver_spec *keyserver) { int ret=0,i,gotversion=0,outofband=0; strlist_t temp; @@ -1243,8 +1245,8 @@ keyserver_spawn(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, /* TODO: Remove Comment: lines from keys exported this way? */ - if(export_pubkeys_stream(buffer,temp,&block, - opt.keyserver_options.export_options)==-1) + if(export_pubkeys_stream (ctrl, buffer,temp,&block, + opt.keyserver_options.export_options)==-1) iobuf_close(buffer); else { @@ -1510,7 +1512,7 @@ keyserver_spawn(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, break; case KS_SEARCH: - keyserver_search_prompt(spawn->fromchild,searchstr); + keyserver_search_prompt (ctrl, spawn->fromchild,searchstr); break; default: @@ -1529,9 +1531,10 @@ keyserver_spawn(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, } static int -keyserver_work(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, - int count,unsigned char **fpr,size_t *fpr_len, - struct keyserver_spec *keyserver) +keyserver_work (ctrl_t ctrl, + enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, + int count,unsigned char **fpr,size_t *fpr_len, + struct keyserver_spec *keyserver) { int rc=0,ret=0; @@ -1549,7 +1552,8 @@ keyserver_work(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, #else /* Spawn a handler */ - rc=keyserver_spawn(action,list,desc,count,&ret,fpr,fpr_len,keyserver); + rc = keyserver_spawn (ctrl, action, list, desc, count, + &ret, fpr, fpr_len, keyserver); if(ret) { switch(ret) @@ -1599,7 +1603,7 @@ keyserver_work(enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc, } int -keyserver_export(strlist_t users) +keyserver_export (ctrl_t ctrl, strlist_t users) { gpg_error_t err; strlist_t sl=NULL; @@ -1624,7 +1628,7 @@ keyserver_export(strlist_t users) if(sl) { - rc=keyserver_work(KS_SEND,sl,NULL,0,NULL,NULL,opt.keyserver); + rc = keyserver_work (ctrl, KS_SEND,sl,NULL,0,NULL,NULL,opt.keyserver); free_strlist(sl); } @@ -1632,7 +1636,7 @@ keyserver_export(strlist_t users) } int -keyserver_import(strlist_t users) +keyserver_import (ctrl_t ctrl, strlist_t users) { gpg_error_t err; KEYDB_SEARCH_DESC *desc; @@ -1663,7 +1667,8 @@ keyserver_import(strlist_t users) } if(count>0) - rc=keyserver_work(KS_GET,NULL,desc,count,NULL,NULL,opt.keyserver); + rc=keyserver_work (ctrl, KS_GET, NULL, desc, count, + NULL, NULL, opt.keyserver); xfree(desc); @@ -1671,8 +1676,8 @@ keyserver_import(strlist_t users) } int -keyserver_import_fprint(const byte *fprint,size_t fprint_len, - struct keyserver_spec *keyserver) +keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len, + struct keyserver_spec *keyserver) { KEYDB_SEARCH_DESC desc; @@ -1689,11 +1694,12 @@ keyserver_import_fprint(const byte *fprint,size_t fprint_len, /* TODO: Warn here if the fingerprint we got doesn't match the one we asked for? */ - return keyserver_work(KS_GET,NULL,&desc,1,NULL,NULL,keyserver); + return keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, keyserver); } int -keyserver_import_keyid(u32 *keyid,struct keyserver_spec *keyserver) +keyserver_import_keyid (ctrl_t ctrl, + u32 *keyid,struct keyserver_spec *keyserver) { KEYDB_SEARCH_DESC desc; @@ -1703,7 +1709,7 @@ keyserver_import_keyid(u32 *keyid,struct keyserver_spec *keyserver) desc.u.kid[0]=keyid[0]; desc.u.kid[1]=keyid[1]; - return keyserver_work(KS_GET,NULL,&desc,1,NULL,NULL,keyserver); + return keyserver_work (ctrl, KS_GET,NULL,&desc,1,NULL,NULL,keyserver); } /* code mostly stolen from do_export_stream */ @@ -1865,7 +1871,7 @@ keyidlist(strlist_t users,KEYDB_SEARCH_DESC **klist,int *count,int fakev3) usernames to refresh only part of the keyring. */ int -keyserver_refresh(strlist_t users) +keyserver_refresh (ctrl_t ctrl, strlist_t users) { int rc,count,numdesc,fakev3=0; KEYDB_SEARCH_DESC *desc; @@ -1908,7 +1914,8 @@ keyserver_refresh(strlist_t users) Note that a preferred keyserver without a scheme:// will be interpreted as hkp:// */ - rc=keyserver_work(KS_GET,NULL,&desc[i],1,NULL,NULL,keyserver); + rc = keyserver_work (ctrl, KS_GET, NULL, &desc[i], 1, + NULL, NULL, keyserver); if(rc) log_info(_("WARNING: unable to refresh key %s" " via %s: %s\n"),keystr_from_desc(&desc[i]), @@ -1938,7 +1945,8 @@ keyserver_refresh(strlist_t users) count,opt.keyserver->uri); } - rc=keyserver_work(KS_GET,NULL,desc,numdesc,NULL,NULL,opt.keyserver); + rc=keyserver_work (ctrl, KS_GET, NULL, desc, numdesc, + NULL, NULL, opt.keyserver); } xfree(desc); @@ -1954,16 +1962,16 @@ keyserver_refresh(strlist_t users) } int -keyserver_search(strlist_t tokens) +keyserver_search (ctrl_t ctrl, strlist_t tokens) { - if(tokens) - return keyserver_work(KS_SEARCH,tokens,NULL,0,NULL,NULL,opt.keyserver); - else - return 0; + if (tokens) + return keyserver_work (ctrl, KS_SEARCH, tokens, NULL, 0, + NULL, NULL, opt.keyserver); + return 0; } int -keyserver_fetch(strlist_t urilist) +keyserver_fetch (ctrl_t ctrl, strlist_t urilist) { KEYDB_SEARCH_DESC desc; strlist_t sl; @@ -1988,7 +1996,7 @@ keyserver_fetch(strlist_t urilist) { int rc; - rc=keyserver_work(KS_GET,NULL,&desc,1,NULL,NULL,spec); + rc = keyserver_work (ctrl, KS_GET, NULL, &desc, 1, NULL, NULL, spec); if(rc) log_info (_("WARNING: unable to fetch URI %s: %s\n"), sl->d,g10_errstr(rc)); @@ -2011,7 +2019,8 @@ keyserver_fetch(strlist_t urilist) /* Import key in a CERT or pointed to by a CERT */ int -keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len) +keyserver_import_cert (ctrl_t ctrl, + const char *name,unsigned char **fpr,size_t *fpr_len) { char *domain,*look,*url; IOBUF key; @@ -2058,7 +2067,7 @@ keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len) spec=parse_keyserver_uri(url,1,NULL,0); if(spec) { - rc=keyserver_import_fprint(*fpr,*fpr_len,spec); + rc = keyserver_import_fprint (ctrl, *fpr,*fpr_len,spec); free_keyserver_spec(spec); } } @@ -2067,7 +2076,7 @@ keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len) /* If only a fingerprint is provided, try and fetch it from our --keyserver */ - rc=keyserver_import_fprint(*fpr,*fpr_len,opt.keyserver); + rc = keyserver_import_fprint (ctrl, *fpr,*fpr_len,opt.keyserver); } else log_info(_("no keyserver known (use option --keyserver)\n")); @@ -2087,7 +2096,8 @@ keyserver_import_cert(const char *name,unsigned char **fpr,size_t *fpr_len) /* Import key pointed to by a PKA record. Return the requested fingerprint in fpr. */ int -keyserver_import_pka(const char *name,unsigned char **fpr,size_t *fpr_len) +keyserver_import_pka (ctrl_t ctrl, + const char *name,unsigned char **fpr,size_t *fpr_len) { char *uri; int rc = G10ERR_NO_PUBKEY; @@ -2103,7 +2113,7 @@ keyserver_import_pka(const char *name,unsigned char **fpr,size_t *fpr_len) spec = parse_keyserver_uri (uri, 1, NULL, 0); if (spec) { - rc = keyserver_import_fprint (*fpr, 20, spec); + rc = keyserver_import_fprint (ctrl, *fpr, 20, spec); free_keyserver_spec (spec); } xfree (uri); @@ -2120,15 +2130,17 @@ keyserver_import_pka(const char *name,unsigned char **fpr,size_t *fpr_len) /* Import all keys that match name */ int -keyserver_import_name(const char *name,unsigned char **fpr,size_t *fpr_len, - struct keyserver_spec *keyserver) +keyserver_import_name (ctrl_t ctrl, const char *name, + unsigned char **fpr, size_t *fpr_len, + struct keyserver_spec *keyserver) { strlist_t list=NULL; int rc; append_to_strlist(&list,name); - rc=keyserver_work(KS_GETNAME,list,NULL,0,fpr,fpr_len,keyserver); + rc = keyserver_work (ctrl, KS_GETNAME, list, NULL, + 0, fpr, fpr_len, keyserver); free_strlist(list); @@ -2137,7 +2149,8 @@ keyserver_import_name(const char *name,unsigned char **fpr,size_t *fpr_len, /* Import a key by name using LDAP */ int -keyserver_import_ldap(const char *name,unsigned char **fpr,size_t *fpr_len) +keyserver_import_ldap (ctrl_t ctrl, + const char *name,unsigned char **fpr,size_t *fpr_len) { char *domain; struct keyserver_spec *keyserver; @@ -2200,7 +2213,8 @@ keyserver_import_ldap(const char *name,unsigned char **fpr,size_t *fpr_len) append_to_strlist(&list,name); - rc=keyserver_work(KS_GETNAME,list,NULL,0,fpr,fpr_len,keyserver); + rc = keyserver_work (ctrl, KS_GETNAME, list, NULL, + 0, fpr, fpr_len, keyserver); free_strlist(list); diff --git a/g10/main.h b/g10/main.h index ba8afbafa..3804effd3 100644 --- a/g10/main.h +++ b/g10/main.h @@ -192,10 +192,11 @@ void display_online_help( const char *keyword ); int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); int encrypt_symmetric (const char *filename ); int encrypt_store (const char *filename ); -int encrypt_crypt (int filefd, const char *filename, +int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, strlist_t remusr, int use_symkey, pk_list_t provided_keys, int outputfd); -void encrypt_crypt_files (int nfiles, char **files, strlist_t remusr); +void encrypt_crypt_files (ctrl_t ctrl, + int nfiles, char **files, strlist_t remusr); int encrypt_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); @@ -203,7 +204,7 @@ int encrypt_filter (void *opaque, int control, /*-- sign.c --*/ int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce); -int sign_file( strlist_t filenames, int detached, strlist_t locusr, +int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int do_encrypt, strlist_t remusr, const char *outfile ); int clearsign_file( const char *fname, strlist_t locusr, const char *outfile ); int sign_symencrypt_file (const char *fname, strlist_t locusr); @@ -221,7 +222,7 @@ int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk, int delete_keys( strlist_t names, int secret, int allow_both ); /*-- keyedit.c --*/ -void keyedit_menu( const char *username, strlist_t locusr, +void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check ); void keyedit_passwd (const char *username); void show_basic_key_info (KBNODE keyblock); @@ -280,11 +281,11 @@ int collapse_uids( KBNODE *keyblock ); /*-- export.c --*/ int parse_export_options(char *str,unsigned int *options,int noisy); -int export_pubkeys( strlist_t users, unsigned int options ); -int export_pubkeys_stream( iobuf_t out, strlist_t users, - KBNODE *keyblock_out, unsigned int options ); -int export_seckeys( strlist_t users ); -int export_secsubkeys( strlist_t users ); +int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options ); +int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, + kbnode_t *keyblock_out, unsigned int options ); +int export_seckeys (ctrl_t ctrl, strlist_t users); +int export_secsubkeys (ctrl_t ctrl, strlist_t users); /* dearmor.c --*/ int dearmor_file( const char *fname ); @@ -300,8 +301,8 @@ struct revocation_reason_info * void release_revocation_reason_info( struct revocation_reason_info *reason ); /*-- keylist.c --*/ -void public_key_list( strlist_t list, int locate_mode ); -void secret_key_list( strlist_t list ); +void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode ); +void secret_key_list (ctrl_t ctrl, strlist_t list ); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque ); @@ -318,14 +319,14 @@ void print_card_key_info (estream_t fp, KBNODE keyblock); /*-- verify.c --*/ void print_file_status( int status, const char *name, int what ); -int verify_signatures( int nfiles, char **files ); -int verify_files( int nfiles, char **files ); +int verify_signatures (ctrl_t ctrl, int nfiles, char **files ); +int verify_files (ctrl_t ctrl, int nfiles, char **files ); int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp); /*-- decrypt.c --*/ -int decrypt_message( const char *filename ); -gpg_error_t decrypt_message_fd (int input_fd, int output_fd); -void decrypt_messages(int nfiles, char *files[]); +int decrypt_message (ctrl_t ctrl, const char *filename ); +gpg_error_t decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd); +void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]); /*-- plaintext.c --*/ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, @@ -346,7 +347,7 @@ int gpg_server (ctrl_t); /*-- card-util.c --*/ void change_pin (int no, int allow_admin); void card_status (estream_t fp, char *serialno, size_t serialnobuflen); -void card_edit (strlist_t commands); +void card_edit (ctrl_t ctrl, strlist_t commands); int card_generate_subkey (KBNODE pub_keyblock, KBNODE sec_keyblock); int card_store_subkey (KBNODE node, int use); #endif diff --git a/g10/mainproc.c b/g10/mainproc.c index 02ffae92e..c2c7aba01 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -26,10 +26,10 @@ #include #include "gpg.h" +#include "util.h" #include "packet.h" #include "iobuf.h" #include "options.h" -#include "util.h" #include "cipher.h" #include "keydb.h" #include "filter.h" @@ -56,6 +56,7 @@ struct kidlist_item { typedef struct mainproc_context *CTX; struct mainproc_context { + ctrl_t ctrl; struct mainproc_context *anchor; /* May be useful in the future. */ PKT_public_key *last_pubkey; PKT_user_id *last_user_id; @@ -563,8 +564,8 @@ proc_encrypted( CTX c, PACKET *pkt ) } else if( !c->dek ) result = G10ERR_NO_SECKEY; - if( !result ) - result = decrypt_data( c, pkt->pkt.encrypted, c->dek ); + if (!result) + result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek ); if( result == -1 ) ; @@ -757,18 +758,19 @@ proc_compressed_cb( IOBUF a, void *info ) { if ( ((CTX)info)->signed_data.used && ((CTX)info)->signed_data.data_fd != -1) - return proc_signature_packets_by_fd (info, a, + return proc_signature_packets_by_fd (((CTX)info)->ctrl, info, a, ((CTX)info)->signed_data.data_fd); else - return proc_signature_packets (info, a, + return proc_signature_packets (((CTX)info)->ctrl, info, a, ((CTX)info)->signed_data.data_names, ((CTX)info)->sigfilename ); } static int -proc_encrypt_cb( IOBUF a, void *info ) +proc_encrypt_cb (IOBUF a, void *info ) { - return proc_encryption_packets( info, a ); + CTX c = info; + return proc_encryption_packets (c->ctrl, info, a ); } static void @@ -781,11 +783,11 @@ proc_compressed( CTX c, PACKET *pkt ) if( !zd->algorithm ) rc=G10ERR_COMPR_ALGO; else if( c->sigs_only ) - rc = handle_compressed( c, zd, proc_compressed_cb, c ); + rc = handle_compressed (c->ctrl, c, zd, proc_compressed_cb, c ); else if( c->encrypt_only ) - rc = handle_compressed( c, zd, proc_encrypt_cb, c ); + rc = handle_compressed (c->ctrl, c, zd, proc_encrypt_cb, c ); else - rc = handle_compressed( c, zd, NULL, NULL ); + rc = handle_compressed (c->ctrl, c, zd, NULL, NULL ); if( rc ) log_error("uncompressing failed: %s\n", g10_errstr(rc)); free_packet(pkt); @@ -1174,11 +1176,12 @@ list_node( CTX c, KBNODE node ) int -proc_packets( void *anchor, IOBUF a ) +proc_packets (ctrl_t ctrl, void *anchor, IOBUF a ) { int rc; CTX c = xmalloc_clear( sizeof *c ); + c->ctrl = ctrl; c->anchor = anchor; rc = do_proc_packets( c, a ); xfree( c ); @@ -1188,12 +1191,13 @@ proc_packets( void *anchor, IOBUF a ) int -proc_signature_packets( void *anchor, IOBUF a, +proc_signature_packets (ctrl_t ctrl, void *anchor, IOBUF a, strlist_t signedfiles, const char *sigfilename ) { CTX c = xmalloc_clear( sizeof *c ); int rc; + c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; @@ -1228,7 +1232,8 @@ proc_signature_packets( void *anchor, IOBUF a, int -proc_signature_packets_by_fd (void *anchor, IOBUF a, int signed_data_fd ) +proc_signature_packets_by_fd (ctrl_t ctrl, + void *anchor, IOBUF a, int signed_data_fd ) { int rc; CTX c; @@ -1237,6 +1242,7 @@ proc_signature_packets_by_fd (void *anchor, IOBUF a, int signed_data_fd ) if (!c) return gpg_error_from_syserror (); + c->ctrl = ctrl; c->anchor = anchor; c->sigs_only = 1; @@ -1269,11 +1275,12 @@ proc_signature_packets_by_fd (void *anchor, IOBUF a, int signed_data_fd ) int -proc_encryption_packets( void *anchor, IOBUF a ) +proc_encryption_packets (ctrl_t ctrl, void *anchor, IOBUF a ) { CTX c = xmalloc_clear( sizeof *c ); int rc; + c->ctrl = ctrl; c->anchor = anchor; c->encrypt_only = 1; rc = do_proc_packets( c, a ); @@ -1652,7 +1659,7 @@ check_sig_and_print( CTX c, KBNODE node ) int res; glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_keyid(sig->keyid,spec); + res = keyserver_import_keyid (c->ctrl, sig->keyid,spec); glo_ctrl.in_auto_key_retrieve--; if(!res) rc=do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); @@ -1684,7 +1691,7 @@ check_sig_and_print( CTX c, KBNODE node ) if (spec) { glo_ctrl.in_auto_key_retrieve++; - res = keyserver_import_keyid (sig->keyid, spec); + res = keyserver_import_keyid (c->ctrl, sig->keyid, spec); glo_ctrl.in_auto_key_retrieve--; free_keyserver_spec (spec); if (!res) @@ -1702,7 +1709,7 @@ check_sig_and_print( CTX c, KBNODE node ) int res; glo_ctrl.in_auto_key_retrieve++; - res=keyserver_import_keyid ( sig->keyid, opt.keyserver ); + res=keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); glo_ctrl.in_auto_key_retrieve--; if(!res) rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey ); diff --git a/g10/options.h b/g10/options.h index cee248f25..968393257 100644 --- a/g10/options.h +++ b/g10/options.h @@ -124,8 +124,6 @@ struct int s2k_cipher_algo; unsigned char s2k_count; /* This is the encoded form, not the raw count */ - int simple_sk_checksum; /* create the deprecated rfc2440 secret key - protection */ int not_dash_escaped; int escape_from; int lock_once; diff --git a/g10/packet.h b/g10/packet.h index 02674a039..643cc5beb 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -370,11 +370,12 @@ struct notation /*-- mainproc.c --*/ void reset_literals_seen(void); -int proc_packets( void *ctx, iobuf_t a ); -int proc_signature_packets( void *ctx, iobuf_t a, +int proc_packets (ctrl_t ctrl, void *ctx, iobuf_t a ); +int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a, strlist_t signedfiles, const char *sigfile ); -int proc_signature_packets_by_fd ( void *anchor, IOBUF a, int signed_data_fd ); -int proc_encryption_packets( void *ctx, iobuf_t a ); +int proc_signature_packets_by_fd (ctrl_t ctrl, + void *anchor, IOBUF a, int signed_data_fd ); +int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); /*-- parse-packet.c --*/ @@ -475,11 +476,11 @@ gpg_error_t get_session_key (PKT_pubkey_enc *k, DEK *dek); gpg_error_t get_override_session_key (DEK *dek, const char *string); /*-- compress.c --*/ -int handle_compressed( void *ctx, PKT_compressed *cd, +int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd, int (*callback)(iobuf_t, void *), void *passthru ); /*-- encr-data.c --*/ -int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek ); +int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, diff --git a/g10/parse-packet.c b/g10/parse-packet.c index c83524016..89d6f5958 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -25,9 +25,9 @@ #include #include "gpg.h" +#include "util.h" #include "packet.h" #include "iobuf.h" -#include "util.h" #include "cipher.h" #include "filter.h" #include "photoid.h" diff --git a/g10/photoid.c b/g10/photoid.c index 3be42d2fc..2d56d80b6 100644 --- a/g10/photoid.c +++ b/g10/photoid.c @@ -29,11 +29,11 @@ #endif #include "gpg.h" +#include "util.h" #include "packet.h" #include "status.h" #include "exec.h" #include "keydb.h" -#include "util.h" #include "i18n.h" #include "iobuf.h" #include "options.h" diff --git a/g10/pkclist.c b/g10/pkclist.c index cffabd0b4..f76c18648 100644 --- a/g10/pkclist.c +++ b/g10/pkclist.c @@ -778,7 +778,7 @@ expand_group(strlist_t input) of the key. USE the requested usage and a set MARK_HIDDEN will mark the key in the updated list as a hidden recipient. */ gpg_error_t -find_and_check_key (const char *name, unsigned int use, +find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use, int mark_hidden, pk_list_t *pk_list_addr) { int rc; @@ -793,7 +793,7 @@ find_and_check_key (const char *name, unsigned int use, return gpg_error_from_syserror (); pk->req_usage = use; - rc = get_pubkey_byname (NULL, pk, name, NULL, NULL, 0, 0); + rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0); if (rc) { /* Key not found or other error. */ @@ -883,7 +883,8 @@ find_and_check_key (const char *name, unsigned int use, not changed. */ int -build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) +build_pk_list (ctrl_t ctrl, + strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) { PK_LIST pk_list = NULL; PKT_public_key *pk=NULL; @@ -929,7 +930,8 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) /* We explicitly allow encrypt-to to an disabled key; thus we pass 1for the second last argument and 1 as the last argument to disable AKL. */ - if ( (rc = get_pubkey_byname (NULL, pk, rov->d, NULL, NULL, 1, 1)) ) + if ( (rc = get_pubkey_byname (ctrl, + NULL, pk, rov->d, NULL, NULL, 1, 1)) ) { free_public_key ( pk ); pk = NULL; log_error (_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) ); @@ -1066,7 +1068,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) free_public_key (pk); pk = xmalloc_clear( sizeof *pk ); pk->req_usage = use; - rc = get_pubkey_byname (NULL, pk, answer, NULL, NULL, 0, 0 ); + rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 ); if (rc) tty_printf(_("No such user ID.\n")); else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) ) @@ -1140,7 +1142,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) /* The default recipient is allowed to be disabled; thus pass 1 as second last argument. We also don't want an AKL. */ - rc = get_pubkey_byname (NULL, pk, def_rec, NULL, NULL, 1, 1); + rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1); if (rc) log_error(_("unknown default recipient \"%s\"\n"), def_rec ); else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo, use)) ) @@ -1178,7 +1180,7 @@ build_pk_list( strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use ) if ( (remusr->flags & 1) ) continue; /* encrypt-to keys are already handled. */ - rc = find_and_check_key (remusr->d, use, !!(remusr->flags&2), + rc = find_and_check_key (ctrl, remusr->d, use, !!(remusr->flags&2), &pk_list); if (rc) goto fail; diff --git a/g10/server.c b/g10/server.c index f67a34677..1c534f1e5 100644 --- a/g10/server.c +++ b/g10/server.c @@ -231,7 +231,7 @@ cmd_recipient (assuan_context_t ctx, char *line) remusr = rcpts; */ - err = find_and_check_key (line, PUBKEY_USAGE_ENC, hidden, + err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden, &ctrl->server_local->recplist); if (err) @@ -324,7 +324,7 @@ cmd_encrypt (assuan_context_t ctx, char *line) /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/ - err = encrypt_crypt (inp_fd, NULL, NULL, 0, + err = encrypt_crypt (ctrl, inp_fd, NULL, NULL, 0, ctrl->server_local->recplist, out_fd); @@ -368,7 +368,7 @@ cmd_decrypt (assuan_context_t ctx, char *line) return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL); glo_ctrl.lasterr = 0; - err = decrypt_message_fd (inp_fd, out_fd); + err = decrypt_message_fd (ctrl, inp_fd, out_fd); if (!err) err = glo_ctrl.lasterr; diff --git a/g10/sign.c b/g10/sign.c index eeb4549ca..cf7efe5dc 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -762,7 +762,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash, * uncompressed, non-armored and in binary mode. */ int -sign_file( strlist_t filenames, int detached, strlist_t locusr, +sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int encryptflag, strlist_t remusr, const char *outfile ) { const char *fname; @@ -822,7 +822,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr, compliance_failure(); } - if(encryptflag && (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC ))) + if (encryptflag + && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC))) goto leave; /* prepare iobufs */ diff --git a/g10/verify.c b/g10/verify.c index 4dab20717..0810223d0 100644 --- a/g10/verify.c +++ b/g10/verify.c @@ -50,7 +50,7 @@ */ int -verify_signatures( int nfiles, char **files ) +verify_signatures (ctrl_t ctrl, int nfiles, char **files ) { IOBUF fp; armor_filter_context_t *afx = NULL; @@ -110,7 +110,7 @@ verify_signatures( int nfiles, char **files ) sl = NULL; for(i=nfiles-1 ; i > 0 ; i-- ) add_to_strlist( &sl, files[i] ); - rc = proc_signature_packets( NULL, fp, sl, sigfile ); + rc = proc_signature_packets (ctrl, NULL, fp, sl, sigfile ); free_strlist(sl); iobuf_close(fp); if( (afx && afx->no_openpgp_data && rc == -1) || rc == G10ERR_NO_DATA ) { @@ -139,7 +139,7 @@ print_file_status( int status, const char *name, int what ) static int -verify_one_file( const char *name ) +verify_one_file (ctrl_t ctrl, const char *name ) { IOBUF fp; armor_filter_context_t *afx = NULL; @@ -172,7 +172,7 @@ verify_one_file( const char *name ) } } - rc = proc_signature_packets( NULL, fp, NULL, name ); + rc = proc_signature_packets (ctrl, NULL, fp, NULL, name ); iobuf_close(fp); write_status( STATUS_FILE_DONE ); @@ -190,7 +190,7 @@ verify_one_file( const char *name ) * Note: This function can not handle detached signatures. */ int -verify_files( int nfiles, char **files ) +verify_files (ctrl_t ctrl, int nfiles, char **files ) { int i; @@ -208,13 +208,13 @@ verify_files( int nfiles, char **files ) * also no script languages available. We don't strip any * spaces, so that we can process nearly all filenames */ line[strlen(line)-1] = 0; - verify_one_file( line ); + verify_one_file (ctrl, line ); } } else { /* take filenames from the array */ for(i=0; i < nfiles; i++ ) - verify_one_file( files[i] ); + verify_one_file (ctrl, files[i] ); } return 0; } @@ -262,7 +262,7 @@ gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp) push_armor_filter (afx, fp); } - rc = proc_signature_packets_by_fd (NULL, fp, data_fd); + rc = proc_signature_packets_by_fd (ctrl, NULL, fp, data_fd); if ( afx && afx->no_openpgp_data && (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) ) diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 8c362d73c..b71ff6aef 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -918,12 +918,13 @@ parse_ccid_descriptor (ccid_driver_t handle, DEBUGOUT_1 (" bMaxCCIDBusySlots %5u\n", buf[53]); - if (buf[0] > 54) { - DEBUGOUT (" junk "); - for (i=54; i < buf[0]-54; i++) - DEBUGOUT_CONT_1 (" %02X", buf[i]); - DEBUGOUT_LF (); - } + if (buf[0] > 54) + { + DEBUGOUT (" junk "); + for (i=54; i < buf[0]-54; i++) + DEBUGOUT_CONT_1 (" %02X", buf[i]); + DEBUGOUT_LF (); + } if (!have_t1 || !(have_tpdu || handle->apdu_level) || !have_auto_conf) { diff --git a/sm/ChangeLog b/sm/ChangeLog index 82a1f998b..9a68f8d43 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,13 @@ +2010-09-16 Werner Koch + + * certchain.c (gpgsm_walk_cert_chain): Use GPG_ERR_MISSING_ISSUER_CERT. + (do_validate_chain): Ditto. + (gpgsm_basic_cert_check): Ditto. + * call-agent.c (learn_cb): Take care of new + GPG_ERR_MISSING_ISSUER_CERT. + * import.c (check_and_store): Ditto. + (check_and_store): Ditto. + 2010-08-16 Werner Koch * gpgsm.c (main) : Use es_printf. diff --git a/sm/call-agent.c b/sm/call-agent.c index 3bfa9f049..81d486bd2 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -887,7 +887,8 @@ learn_cb (void *opaque, const void *buffer, size_t length) because we can assume that the --learn-card command has been used on purpose. */ rc = gpgsm_basic_cert_check (parm->ctrl, cert); - if (rc && gpg_err_code (rc) != GPG_ERR_MISSING_CERT) + if (rc && gpg_err_code (rc) != GPG_ERR_MISSING_CERT + && gpg_err_code (rc) != GPG_ERR_MISSING_ISSUER_CERT) log_error ("invalid certificate: %s\n", gpg_strerror (rc)); else { diff --git a/sm/certchain.c b/sm/certchain.c index bbb8bbe8d..40ab6a4b5 100644 --- a/sm/certchain.c +++ b/sm/certchain.c @@ -789,7 +789,7 @@ gpgsm_walk_cert_chain (ctrl_t ctrl, ksba_cert_t start, ksba_cert_t *r_next) print an error here. */ if (rc != -1 && opt.verbose > 1) log_error ("failed to find issuer's certificate: rc=%d\n", rc); - rc = gpg_error (GPG_ERR_MISSING_CERT); + rc = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); goto leave; } @@ -1496,7 +1496,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, } else log_error ("failed to find issuer's certificate: rc=%d\n", rc); - rc = gpg_error (GPG_ERR_MISSING_CERT); + rc = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); goto leave; } @@ -1897,7 +1897,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert) } else log_error ("failed to find issuer's certificate: rc=%d\n", rc); - rc = gpg_error (GPG_ERR_MISSING_CERT); + rc = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); goto leave; } diff --git a/sm/gpgsm.c b/sm/gpgsm.c index cc8c5404e..226704a98 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -287,7 +287,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_s (oAuditLog, "audit-log", N_("|FILE|write an audit log to FILE")), - ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", ""), + ARGPARSE_s_s (oHtmlAuditLog, "html-audit-log", "@"), ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")), ARGPARSE_s_n (oBatch, "batch", N_("batch mode: never ask")), ARGPARSE_s_n (oAnswerYes, "yes", N_("assume yes on most questions")), diff --git a/sm/import.c b/sm/import.c index 69a64f1c8..c70e4e916 100644 --- a/sm/import.c +++ b/sm/import.c @@ -194,7 +194,8 @@ check_and_store (ctrl_t ctrl, struct stats_s *stats, if (!rc && ctrl->with_validation) rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL); if (!rc || (!ctrl->with_validation - && gpg_err_code (rc) == GPG_ERR_MISSING_CERT) ) + && (gpg_err_code (rc) == GPG_ERR_MISSING_CERT + || gpg_err_code (rc) == GPG_ERR_MISSING_ISSUER_CERT))) { int existed; @@ -253,9 +254,14 @@ check_and_store (ctrl_t ctrl, struct stats_s *stats, log_error (_("basic certificate checks failed - not imported\n")); if (stats) stats->not_imported++; - print_import_problem (ctrl, cert, - gpg_err_code (rc) == GPG_ERR_MISSING_CERT? 2 : - gpg_err_code (rc) == GPG_ERR_BAD_CERT? 1 : 0); + /* We keep the test for GPG_ERR_MISSING_CERT only in case + GPG_ERR_MISSING_CERT has been used instead of the newer + GPG_ERR_MISSING_ISSUER_CERT. */ + print_import_problem + (ctrl, cert, + gpg_err_code (rc) == GPG_ERR_MISSING_ISSUER_CERT? 2 : + gpg_err_code (rc) == GPG_ERR_MISSING_CERT? 2 : + gpg_err_code (rc) == GPG_ERR_BAD_CERT? 1 : 0); } }