gpg: Add pinentry-mode feature.

* g10/gpg.c: Include shareddefs.h.
(main): Add option --pinentry-mode.
* g10/options.h (struct opt): Add field pinentry_mode.
* g10/passphrase.c: Include shareddefs.h.
(have_static_passphrase): Take care of loopback pinentry_mode.
(read_passphrase_from_fd): Ditto.
(get_static_passphrase): New.
(passphrase_to_dek_ext): Factor some code out to ...
(emit_status_need_passphrase): new.
* g10/call-agent.c (start_agent): Send the pinentry mode.
(default_inq_cb): Take care of the PASSPHRASE inquiry.  Return a
proper error code.
(agent_pksign): Add args keyid, mainkeyid and pubkey_algo.
(agent_pkdecrypt): Ditto.
* g10/pubkey-enc.c (get_it): Pass new args.
* g10/sign.c (do_sign): Pass new args.

* g10/call-agent.c (struct default_inq_parm_s): New.  Change all
similar structs to reference this one.  Change all users and inquire
callback to use this struct, instead of NULL or some undefined but not
used structs.  This change will help to eventually get rid of global
variables.
--

This new features allows to use gpg without a Pinentry.  As a
prerequisite the agent must be configured to allow the loopback
pinentry mode (option --allow-loopback-pinentry).  For example

  gpg2 --pinentry-mode=loopback FILE.gpg

may be used to decrypt FILE.gpg while entering the passphrase on the
tty.  If batch is used, --passphrase et al. may be used, if
--command-fd is used, the passphrase may be provided by another
process.  Note that there are no try-again prompts in case of a bad
passphrase.
This commit is contained in:
Werner Koch 2013-02-07 20:37:58 +01:00
parent 84de484bc3
commit 21feecd48f
10 changed files with 301 additions and 81 deletions

2
NEWS
View File

@ -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)
-----------------------------------------------------

View File

@ -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.

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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. */

View File

@ -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)

View File

@ -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);