diff --git a/NEWS b/NEWS index a8352ca53..b81759ceb 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ Noteworthy changes in version 2.1.0beta4 (unreleased) * The hash algorithm is now printed for sig records in key listings. + * New option --pinentry-mode for GPG. + Noteworthy changes in version 2.1.0beta3 (2011-12-20) ----------------------------------------------------- diff --git a/doc/gpg.texi b/doc/gpg.texi index d67900042..cf647e19b 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -2611,6 +2611,26 @@ Note that this passphrase is only used if the option @option{--batch} has also been given. This is different from @command{gpg}. @end ifclear +@ifset gpgtwoone +@item --pinentry-mode @code{mode} +@opindex pinentry-mode +Set the pinentry mode to @code{mode}. Allowed values for @code{mode} +are: +@table @asis + @item default + Use the default of the agent, which is @code{ask}. + @item ask + Force the use of the Pinentry. + @item cancel + Emulate use of Pinentry's cancel button. + @item error + Return a Pinentry error (``No Pinentry''). + @item loopback + Redirect Pinentry queries to the caller. Note that in contrast to + Pinentry the user is not prompted again if he enters a bad password. +@end table +@end ifset + @item --command-fd @code{n} @opindex command-fd This is a replacement for the deprecated shared-memory IPC mode. diff --git a/g10/call-agent.c b/g10/call-agent.c index a4d1dbb13..ed141dadc 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1,6 +1,6 @@ /* call-agent.c - Divert GPG operations to the agent. * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009, - * 2010, 2011 Free Software Foundation, Inc. + * 2010, 2011, 2013 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -40,47 +40,60 @@ #include "sysutils.h" #include "call-agent.h" #include "status.h" +#include "../common/shareddefs.h" #ifndef DBG_ASSUAN # define DBG_ASSUAN 1 #endif +#define CONTROL_D ('D' - 'A' + 1) + + static assuan_context_t agent_ctx = NULL; static int did_early_card_test; -struct cipher_parm_s +struct default_inq_parm_s { ctrl_t ctrl; assuan_context_t ctx; + struct { + u32 *keyid; + u32 *mainkeyid; + int pubkey_algo; + } keyinfo; +}; + +struct cipher_parm_s +{ + struct default_inq_parm_s *dflt; + assuan_context_t ctx; unsigned char *ciphertext; size_t ciphertextlen; }; struct writecert_parm_s { - assuan_context_t ctx; + struct default_inq_parm_s *dflt; const unsigned char *certdata; size_t certdatalen; }; struct writekey_parm_s { - assuan_context_t ctx; + struct default_inq_parm_s *dflt; const unsigned char *keydata; size_t keydatalen; }; struct genkey_parm_s { - ctrl_t ctrl; - assuan_context_t ctx; + struct default_inq_parm_s *dflt; const char *keyparms; }; struct import_key_parm_s { - ctrl_t ctrl; - assuan_context_t ctx; + struct default_inq_parm_s *dflt; const void *key; size_t keylen; }; @@ -161,6 +174,19 @@ start_agent (ctrl_t ctrl, int for_card) here used to indirectly enable GPG_ERR_FULLY_CANCELED. */ assuan_transact (agent_ctx, "OPTION agent-awareness=2.1.0", NULL, NULL, NULL, NULL, NULL, NULL); + /* Pass on the pinentry mode. */ + if (opt.pinentry_mode) + { + char *tmp = xasprintf ("OPTION pinentry-mode=%s", + str_pinentry_mode (opt.pinentry_mode)); + rc = assuan_transact (agent_ctx, tmp, + NULL, NULL, NULL, NULL, NULL, NULL); + xfree (tmp); + if (rc) + log_error ("setting pinentry mode '%s' failed: %s\n", + str_pinentry_mode (opt.pinentry_mode), + gpg_strerror (rc)); + } } } @@ -307,21 +333,46 @@ get_serialno_cb (void *opaque, const char *line) static gpg_error_t default_inq_cb (void *opaque, const char *line) { - gpg_error_t err; - ctrl_t ctrl = opaque; + gpg_error_t err = 0; + struct default_inq_parm_s *parm = opaque; if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17])) { - err = gpg_proxy_pinentry_notify (ctrl, line); + err = gpg_proxy_pinentry_notify (parm->ctrl, line); if (err) log_error (_("failed to proxy %s inquiry to client\n"), "PINENTRY_LAUNCHED"); /* We do not pass errors to avoid breaking other code. */ } + else if (!strncmp (line, "PASSPHRASE", 10) && (line[10]==' '||!line[10]) + && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK) + { + if (have_static_passphrase ()) + { + const char *s = get_static_passphrase (); + err = assuan_send_data (parm->ctx, s, strlen (s)); + } + else + { + char *pw; + + if (parm->keyinfo.keyid) + emit_status_need_passphrase (parm->keyinfo.keyid, + parm->keyinfo.mainkeyid, + parm->keyinfo.pubkey_algo); + pw = cpr_get_hidden ("passphrase.enter", _("Enter passphrase: ")); + cpr_kill_prompt (); + if (*pw == CONTROL_D && !pw[1]) + err = gpg_error (GPG_ERR_CANCELED); + else + err = assuan_send_data (parm->ctx, pw, strlen (pw)); + xfree (pw); + } + } else log_debug ("ignoring gpg-agent inquiry '%s'\n", line); - return 0; + return err; } @@ -516,6 +567,9 @@ int agent_learn (struct agent_card_info_s *info) { int rc; + struct default_inq_parm_s parm; + + memset (&parm, 0, sizeof parm); rc = start_agent (NULL, 1); if (rc) @@ -533,10 +587,10 @@ agent_learn (struct agent_card_info_s *info) if (rc) return rc; - + parm.ctx = agent_ctx; memset (info, 0, sizeof *info); rc = assuan_transact (agent_ctx, "SCD LEARN --force", - dummy_data_cb, NULL, default_inq_cb, NULL, + dummy_data_cb, NULL, default_inq_cb, &parm, learn_status_cb, info); /* Also try to get the key attributes. */ if (!rc) @@ -553,6 +607,9 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) { int rc; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s parm; + + memset (&parm, 0, sizeof parm); if (!*name) return gpg_error (GPG_ERR_INV_VALUE); @@ -566,7 +623,8 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) if (rc) return rc; - rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL, + parm.ctx = agent_ctx; + rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm, learn_status_cb, info); return rc; @@ -584,6 +642,9 @@ agent_scd_setattr (const char *name, int rc; char line[ASSUAN_LINELENGTH]; char *p; + struct default_inq_parm_s parm; + + memset (&parm, 0, sizeof parm); (void)serialno; @@ -615,8 +676,9 @@ agent_scd_setattr (const char *name, rc = start_agent (NULL, 1); if (!rc) { + parm.ctx = agent_ctx; rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, NULL, NULL, NULL); + default_inq_cb, &parm, NULL, NULL); } status_sc_op_failure (rc); @@ -636,10 +698,11 @@ inq_writecert_parms (void *opaque, const char *line) if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8])) { - rc = assuan_send_data (parm->ctx, parm->certdata, parm->certdatalen); + rc = assuan_send_data (parm->dflt->ctx, + parm->certdata, parm->certdatalen); } else - rc = default_inq_cb (opaque, line); + rc = default_inq_cb (parm->dflt, line); return rc; } @@ -653,6 +716,9 @@ agent_scd_writecert (const char *certidstr, int rc; char line[ASSUAN_LINELENGTH]; struct writecert_parm_s parms; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); rc = start_agent (NULL, 1); if (rc) @@ -662,7 +728,8 @@ agent_scd_writecert (const char *certidstr, snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr); line[DIM(line)-1] = 0; - parms.ctx = agent_ctx; + dfltparm.ctx = agent_ctx; + parms.dflt = &dfltparm; parms.certdata = certdata; parms.certdatalen = certdatalen; @@ -684,10 +751,10 @@ inq_writekey_parms (void *opaque, const char *line) if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) { - rc = assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen); + rc = assuan_send_data (parm->dflt->ctx, parm->keydata, parm->keydatalen); } else - rc = default_inq_cb (opaque, line); + rc = default_inq_cb (parm->dflt, line); return rc; } @@ -701,6 +768,9 @@ agent_scd_writekey (int keyno, const char *serialno, int rc; char line[ASSUAN_LINELENGTH]; struct writekey_parm_s parms; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); (void)serialno; @@ -712,7 +782,8 @@ agent_scd_writekey (int keyno, const char *serialno, snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno); line[DIM(line)-1] = 0; - parms.ctx = agent_ctx; + dfltparm.ctx = agent_ctx; + parms.dflt = &dfltparm; parms.keydata = keydata; parms.keydatalen = keydatalen; @@ -837,6 +908,9 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force, char line[ASSUAN_LINELENGTH]; gnupg_isotime_t tbuf; struct scd_genkey_parm_s parms; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); (void)serialno; @@ -858,9 +932,10 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force, keyno); line[DIM(line)-1] = 0; + dfltparm.ctx = agent_ctx; memset (info, 0, sizeof *info); rc = assuan_transact (agent_ctx, line, - NULL, NULL, default_inq_cb, NULL, + NULL, NULL, default_inq_cb, &dfltparm, scd_genkey_cb, &parms); xfree (parms.savedbytes); @@ -986,19 +1061,25 @@ agent_scd_readcert (const char *certidstr, char line[ASSUAN_LINELENGTH]; membuf_t data; size_t len; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); *r_buf = NULL; rc = start_agent (NULL, 1); if (rc) return rc; + dfltparm.ctx = agent_ctx; + init_membuf (&data, 2048); snprintf (line, DIM(line)-1, "SCD READCERT %s", certidstr); line[DIM(line)-1] = 0; rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data, - default_inq_cb, NULL, NULL, NULL); + default_inq_cb, &dfltparm, + NULL, NULL); if (rc) { xfree (get_membuf (&data, &len)); @@ -1029,6 +1110,9 @@ agent_scd_change_pin (int chvno, const char *serialno) int rc; char line[ASSUAN_LINELENGTH]; const char *reset = ""; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); (void)serialno; @@ -1039,11 +1123,14 @@ agent_scd_change_pin (int chvno, const char *serialno) rc = start_agent (NULL, 1); if (rc) return rc; + dfltparm.ctx = agent_ctx; snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno); line[DIM(line)-1] = 0; - rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, + NULL, NULL, + default_inq_cb, &dfltparm, + NULL, NULL); status_sc_op_failure (rc); return rc; } @@ -1057,16 +1144,21 @@ agent_scd_checkpin (const char *serialno) { int rc; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); rc = start_agent (NULL, 1); if (rc) return rc; + dfltparm.ctx = agent_ctx; snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno); line[DIM(line)-1] = 0; rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, NULL, NULL, NULL); + default_inq_cb, &dfltparm, + NULL, NULL); status_sc_op_failure (rc); return rc; } @@ -1102,12 +1194,16 @@ agent_get_passphrase (const char *cache_id, char *arg3 = NULL; char *arg4 = NULL; membuf_t data; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); *r_passphrase = NULL; rc = start_agent (NULL, 0); if (rc) return rc; + dfltparm.ctx = agent_ctx; /* Check that the gpg-agent understands the repeat option. */ if (assuan_transact (agent_ctx, @@ -1145,7 +1241,8 @@ agent_get_passphrase (const char *cache_id, init_membuf_secure (&data, 64); rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data, - default_inq_cb, NULL, NULL, NULL); + default_inq_cb, &dfltparm, + NULL, NULL); if (rc) xfree (get_membuf (&data, NULL)); @@ -1172,6 +1269,9 @@ agent_clear_passphrase (const char *cache_id) { int rc; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); if (!cache_id || !*cache_id) return 0; @@ -1179,11 +1279,14 @@ agent_clear_passphrase (const char *cache_id) rc = start_agent (NULL, 0); if (rc) return rc; + dfltparm.ctx = agent_ctx; snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id); line[DIM(line)-1] = 0; - return assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, NULL, NULL, NULL); + return assuan_transact (agent_ctx, line, + NULL, NULL, + default_inq_cb, &dfltparm, + NULL, NULL); } @@ -1195,10 +1298,14 @@ gpg_agent_get_confirmation (const char *desc) int rc; char *tmp; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); rc = start_agent (NULL, 0); if (rc) return rc; + dfltparm.ctx = agent_ctx; tmp = percent_plus_escape (desc); if (!tmp) @@ -1207,8 +1314,10 @@ gpg_agent_get_confirmation (const char *desc) line[DIM(line)-1] = 0; xfree (tmp); - rc = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, NULL, NULL, NULL); + rc = assuan_transact (agent_ctx, line, + NULL, NULL, + default_inq_cb, &dfltparm, + NULL, NULL); return rc; } @@ -1439,11 +1548,11 @@ inq_genkey_parms (void *opaque, const char *line) if (!strncmp (line, "KEYPARAM", 8) && (line[8]==' '||!line[8])) { - err = assuan_send_data (parm->ctx, + err = assuan_send_data (parm->dflt->ctx, parm->keyparms, strlen (parm->keyparms)); } else - err = default_inq_cb (parm->ctrl, line); + err = default_inq_cb (parm->dflt, line); return err; } @@ -1460,15 +1569,20 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, gpg_error_t err; struct genkey_parm_s gk_parm; struct cache_nonce_parm_s cn_parm; + struct default_inq_parm_s dfltparm; membuf_t data; size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; + *r_pubkey = NULL; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; err = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); @@ -1476,8 +1590,7 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, return err; init_membuf (&data, 1024); - gk_parm.ctrl = ctrl; - gk_parm.ctx = agent_ctx; + gk_parm.dflt = &dfltparm; gk_parm.keyparms = keyparms; snprintf (line, sizeof line, "GENKEY%s%s%s", no_protection? " --no-protection":"", @@ -1521,11 +1634,16 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; *r_pubkey = NULL; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; err = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL); if (err) @@ -1536,7 +1654,8 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, init_membuf (&data, 1024); err = assuan_transact (agent_ctx, line, membuf_data_cb, &data, - default_inq_cb, NULL, NULL, NULL); + default_inq_cb, &dfltparm, + NULL, NULL); if (err) { xfree (get_membuf (&data, &len)); @@ -1565,17 +1684,26 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *keygrip, const char *desc, + u32 *keyid, u32 *mainkeyid, int pubkey_algo, unsigned char *digest, size_t digestlen, int digestalgo, gcry_sexp_t *r_sigval) { gpg_error_t err; char line[ASSUAN_LINELENGTH]; membuf_t data; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; + dfltparm.keyinfo.keyid = keyid; + dfltparm.keyinfo.mainkeyid = mainkeyid; + dfltparm.keyinfo.pubkey_algo = pubkey_algo; *r_sigval = NULL; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; if (digestlen*2 + 50 > DIM(line)) return gpg_error (GPG_ERR_GENERAL); @@ -1613,8 +1741,9 @@ agent_pksign (ctrl_t ctrl, const char *cache_nonce, cache_nonce? " -- ":"", cache_nonce? cache_nonce:""); err = assuan_transact (agent_ctx, line, - membuf_data_cb, &data, default_inq_cb, ctrl, - NULL, NULL); + membuf_data_cb, &data, + default_inq_cb, &dfltparm, + NULL, NULL); if (err) xfree (get_membuf (&data, NULL)); else @@ -1647,11 +1776,12 @@ inq_ciphertext_cb (void *opaque, const char *line) if (!strncmp (line, "CIPHERTEXT", 10) && (line[10]==' '||!line[10])) { assuan_begin_confidential (parm->ctx); - rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen); + rc = assuan_send_data (parm->dflt->ctx, + parm->ciphertext, parm->ciphertextlen); assuan_end_confidential (parm->ctx); } else - rc = default_inq_cb (parm->ctrl, line); + rc = default_inq_cb (parm->dflt, line); return rc; } @@ -1660,9 +1790,12 @@ inq_ciphertext_cb (void *opaque, const char *line) /* Call the agent to do a decrypt operation using the key identified by the hex string KEYGRIP and the input data S_CIPHERTEXT. On the success the decoded value is stored verbatim at R_BUF and its - length at R_BUF; the callers needs to release it. */ + length at R_BUF; the callers needs to release it. KEYID, MAINKEYID + and PUBKEY_ALGO are used to construct additional promots or status + messages. */ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, + u32 *keyid, u32 *mainkeyid, int pubkey_algo, gcry_sexp_t s_ciphertext, unsigned char **r_buf, size_t *r_buflen) { @@ -1671,6 +1804,13 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, membuf_t data; size_t n, len; char *p, *buf, *endp; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; + dfltparm.keyinfo.keyid = keyid; + dfltparm.keyinfo.mainkeyid = mainkeyid; + dfltparm.keyinfo.pubkey_algo = pubkey_algo; if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen) return gpg_error (GPG_ERR_INV_VALUE); @@ -1679,6 +1819,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; err = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); @@ -1704,7 +1845,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, { struct cipher_parm_s parm; - parm.ctrl = ctrl; + parm.dflt = &dfltparm; parm.ctx = agent_ctx; err = make_canon_sexp (s_ciphertext, &parm.ciphertext, &parm.ciphertextlen); if (err) @@ -1773,11 +1914,16 @@ agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen) size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; *r_kek = NULL; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s", forexport? "--export":"--import"); @@ -1785,7 +1931,8 @@ agent_keywrap_key (ctrl_t ctrl, int forexport, void **r_kek, size_t *r_keklen) init_membuf_secure (&data, 64); err = assuan_transact (agent_ctx, line, membuf_data_cb, &data, - default_inq_cb, ctrl, NULL, NULL); + default_inq_cb, &dfltparm, + NULL, NULL); if (err) { xfree (get_membuf (&data, &len)); @@ -1810,10 +1957,10 @@ inq_import_key_parms (void *opaque, const char *line) if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) { - err = assuan_send_data (parm->ctx, parm->key, parm->keylen); + err = assuan_send_data (parm->dflt->ctx, parm->key, parm->keylen); } else - err = default_inq_cb (parm->ctrl, line); + err = default_inq_cb (parm->dflt, line); return err; } @@ -1828,10 +1975,15 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, struct import_key_parm_s parm; struct cache_nonce_parm_s cn_parm; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; if (desc) { @@ -1843,8 +1995,7 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, return err; } - parm.ctrl = ctrl; - parm.ctx = agent_ctx; + parm.dflt = &dfltparm; parm.key = key; parm.keylen = keylen; @@ -1854,7 +2005,8 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr, cn_parm.cache_nonce_addr = cache_nonce_addr; cn_parm.passwd_nonce_addr = NULL; err = assuan_transact (agent_ctx, line, - NULL, NULL, inq_import_key_parms, &parm, + NULL, NULL, + inq_import_key_parms, &parm, cache_nonce_status_cb, &cn_parm); return err; } @@ -1876,12 +2028,17 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, size_t len; unsigned char *buf; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; *r_result = NULL; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; if (desc) { @@ -1902,7 +2059,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, cn_parm.passwd_nonce_addr = NULL; err = assuan_transact (agent_ctx, line, membuf_data_cb, &data, - default_inq_cb, ctrl, + default_inq_cb, &dfltparm, cache_nonce_status_cb, &cn_parm); if (err) { @@ -1932,14 +2089,20 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, gpg_error_t err; struct cache_nonce_parm_s cn_parm; char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s dfltparm; + + memset (&dfltparm, 0, sizeof dfltparm); + dfltparm.ctrl = ctrl; err = start_agent (ctrl, 0); if (err) return err; + dfltparm.ctx = agent_ctx; if (!hexkeygrip || strlen (hexkeygrip) != 40) return gpg_error (GPG_ERR_INV_VALUE); + if (desc) { snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc); @@ -1958,7 +2121,7 @@ agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, cn_parm.cache_nonce_addr = cache_nonce_addr; cn_parm.passwd_nonce_addr = passwd_nonce_addr; err = assuan_transact (agent_ctx, line, NULL, NULL, - default_inq_cb, ctrl, + default_inq_cb, &dfltparm, cache_nonce_status_cb, &cn_parm); return err; } diff --git a/g10/call-agent.h b/g10/call-agent.h index 43de14fe3..de05d7afc 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -155,12 +155,14 @@ gpg_error_t agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, /* Create a signature. */ gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce, const char *hexkeygrip, const char *desc, + u32 *keyid, u32 *mainkeyid, int pubkey_algo, unsigned char *digest, size_t digestlen, int digestalgo, gcry_sexp_t *r_sigval); /* Decrypt a ciphertext. */ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, + u32 *keyid, u32 *mainkeyid, int pubkey_algo, gcry_sexp_t s_ciphertext, unsigned char **r_buf, size_t *r_buflen); diff --git a/g10/gpg.c b/g10/gpg.c index b614a94a0..9adc21abc 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -56,6 +56,7 @@ #include "asshelp.h" #include "call-dirmngr.h" #include "../common/init.h" +#include "../common/shareddefs.h" #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__) #define MY_O_BINARY O_BINARY @@ -217,6 +218,7 @@ enum cmd_and_opt_values oPassphraseFD, oPassphraseFile, oPassphraseRepeat, + oPinentryMode, oCommandFD, oCommandFile, oQuickRandom, @@ -611,6 +613,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), + ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), ARGPARSE_s_i (oCommandFD, "command-fd", "@"), ARGPARSE_s_s (oCommandFile, "command-file", "@"), ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"), @@ -2593,7 +2596,16 @@ main (int argc, char **argv) case oPassphraseFile: pwfd = open_info_file (pargs.r.ret_str, 0, 1); break; - case oPassphraseRepeat: opt.passphrase_repeat=pargs.r.ret_int; break; + case oPassphraseRepeat: + opt.passphrase_repeat = pargs.r.ret_int; + break; + + case oPinentryMode: + opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str); + if (opt.pinentry_mode == -1) + log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); + break; + case oCommandFD: opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); break; diff --git a/g10/keydb.h b/g10/keydb.h index 22c2b673e..fd80c2525 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -181,6 +181,7 @@ unsigned char encode_s2k_iterations (int iterations); assuan_context_t agent_open (int try, const char *orig_codeset); void agent_close (assuan_context_t ctx); int have_static_passphrase(void); +const char *get_static_passphrase (void); void set_passphrase_from_string(const char *pass); void read_passphrase_from_fd( int fd ); void passphrase_clear_cache ( u32 *keyid, const char *cacheid, int algo ); @@ -196,6 +197,8 @@ void set_next_passphrase( const char *s ); char *get_last_passphrase(void); void next_to_last_passphrase(void); +void emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo); + char *gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped); diff --git a/g10/options.h b/g10/options.h index e67d0ce04..223b11510 100644 --- a/g10/options.h +++ b/g10/options.h @@ -242,6 +242,7 @@ struct } *auto_key_locate; int passphrase_repeat; + int pinentry_mode; } opt; /* CTRL is used to keep some global variables we currently can't diff --git a/g10/passphrase.c b/g10/passphrase.c index cc5655505..d872e36ae 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -43,7 +43,7 @@ #include "i18n.h" #include "status.h" #include "call-agent.h" - +#include "../common/shareddefs.h" static char *fd_passwd = NULL; static char *next_pw = NULL; @@ -104,9 +104,21 @@ encode_s2k_iterations (int iterations) int have_static_passphrase() { - return !!fd_passwd && opt.batch; + return (!!fd_passwd + && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK)); } +/* Return a static passphrase. The returned value is only valid as + long as no other passphrase related function is called. NULL may + be returned if no passphrase has been set; better use + have_static_passphrase first. */ +const char * +get_static_passphrase (void) +{ + return fd_passwd; +} + + /**************** * Set the passphrase to be used for the next query and only for the next * one. @@ -156,7 +168,7 @@ read_passphrase_from_fd( int fd ) int i, len; char *pw; - if ( !opt.batch ) + if ( !opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK) { /* Not used but we have to do a dummy read, so that it won't end up at the begin of the message if the quite usual trick to prepend the passphtrase to the message is used. */ @@ -187,7 +199,7 @@ read_passphrase_from_fd( int fd ) break; } pw[i] = 0; - if (!opt.batch) + if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK) tty_printf("\b\b\b \n" ); xfree ( fd_passwd ); @@ -458,30 +470,9 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo, if ( keyid ) { - u32 used_kid[2]; - char *us; - - if ( keyid[2] && keyid[3] ) - { - used_kid[0] = keyid[2]; - used_kid[1] = keyid[3]; - } - else - { - used_kid[0] = keyid[0]; - used_kid[1] = keyid[1]; - } - - us = get_long_user_id_string ( keyid ); - write_status_text ( STATUS_USERID_HINT, us ); - xfree(us); - - snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0", - (ulong)keyid[0], (ulong)keyid[1], - (ulong)used_kid[0], (ulong)used_kid[1], - pubkey_algo ); - - write_status_text ( STATUS_NEED_PASSPHRASE, buf ); + emit_status_need_passphrase (keyid, + keyid[2] && keyid[3]? keyid+2:NULL, + pubkey_algo); } else { @@ -614,6 +605,29 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo, } +/* Emit the USERID_HINT and the NEED_PASSPHRASE status messages. + MAINKEYID may be NULL. */ +void +emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo) +{ + char buf[50]; + char *us; + + us = get_long_user_id_string (keyid); + write_status_text (STATUS_USERID_HINT, us); + xfree (us); + + snprintf (buf, sizeof buf -1, "%08lX%08lX %08lX%08lX %d 0", + (ulong)keyid[0], + (ulong)keyid[1], + (ulong)(mainkeyid? mainkeyid[0]:keyid[0]), + (ulong)(mainkeyid? mainkeyid[1]:keyid[1]), + pubkey_algo); + + write_status_text (STATUS_NEED_PASSPHRASE, buf); +} + + /* Return an allocated utf-8 string describing the key PK. If ESCAPED is true spaces and control characters are percent or plus escaped. MODE 0 is for the common prompt, MODE 1 for the import prompt. */ diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 254e81091..a98a7238b 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -193,7 +193,9 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) /* Decrypt. */ desc = gpg_format_keydesc (sk, 0, 1); - err = agent_pkdecrypt (NULL, keygrip, desc, s_data, &frame, &nframe); + err = agent_pkdecrypt (NULL, keygrip, + desc, sk->keyid, sk->main_keyid, sk->pubkey_algo, + s_data, &frame, &nframe); xfree (desc); gcry_sexp_release (s_data); if (err) diff --git a/g10/sign.c b/g10/sign.c index 501f1ff25..8944067d7 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -272,6 +272,7 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig, desc = gpg_format_keydesc (pksk, 0, 1); err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc, + pksk->keyid, pksk->main_keyid, pksk->pubkey_algo, dp, gcry_md_get_algo_dlen (mdalgo), mdalgo, &s_sigval); xfree (desc);