1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

Merge branch 'master' into key-storage-work

This commit is contained in:
Werner Koch 2013-02-12 19:17:42 +01:00
commit caddeef4a7
43 changed files with 6301 additions and 5133 deletions

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,20 +333,46 @@ get_serialno_cb (void *opaque, const char *line)
static gpg_error_t
default_inq_cb (void *opaque, const char *line)
{
(void)opaque;
gpg_error_t err = 0;
struct default_inq_parm_s *parm = opaque;
if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
{
/* There is no working server mode yet thus we use
AllowSetForegroundWindow window right here. We might want to
do this anyway in case gpg is called on the console. */
gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
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;
}
@ -515,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)
@ -532,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)
@ -544,6 +599,30 @@ agent_learn (struct agent_card_info_s *info)
return rc;
}
int
agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp)
{
int rc;
char line[ASSUAN_LINELENGTH];
snprintf (line, DIM(line)-1, "KEYTOCARD %s%s %s OPENPGP.%d %s",
force?"--force ": "", hexgrip, serialno, keyno, timestamp);
line[DIM(line)-1] = 0;
rc = start_agent (NULL, 1);
if (rc)
return rc;
rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb,
NULL, NULL, NULL);
if (rc)
return rc;
return rc;
}
/* Call the agent to retrieve a data object. This function returns
the data in the same structure as used by the learn command. It is
allowed to update such a structure using this commmand. */
@ -552,6 +631,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);
@ -565,7 +647,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;
@ -583,6 +666,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;
@ -614,8 +700,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);
@ -635,10 +722,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;
}
@ -652,6 +740,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)
@ -661,7 +752,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;
@ -683,10 +775,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;
}
@ -700,6 +792,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;
@ -711,7 +806,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;
@ -836,6 +932,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;
@ -857,9 +956,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);
@ -985,19 +1085,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));
@ -1028,6 +1134,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;
@ -1038,11 +1147,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;
}
@ -1056,16 +1168,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;
}
@ -1101,12 +1218,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,
@ -1144,7 +1265,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));
@ -1171,6 +1293,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;
@ -1178,11 +1303,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);
}
@ -1194,10 +1322,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)
@ -1206,8 +1338,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;
}
@ -1438,11 +1572,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;
}
@ -1459,15 +1593,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);
@ -1475,8 +1614,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":"",
@ -1520,11 +1658,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)
@ -1535,7 +1678,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));
@ -1564,17 +1708,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);
@ -1612,8 +1765,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
@ -1646,11 +1800,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;
}
@ -1659,9 +1814,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)
{
@ -1670,6 +1828,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);
@ -1678,6 +1843,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);
@ -1703,7 +1869,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)
@ -1772,11 +1938,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");
@ -1784,7 +1955,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));
@ -1809,10 +1981,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;
}
@ -1827,10 +1999,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)
{
@ -1842,8 +2019,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;
@ -1853,7 +2029,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;
}
@ -1875,12 +2052,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)
{
@ -1901,7 +2083,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)
{
@ -1931,14 +2113,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);
@ -1957,7 +2145,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

@ -81,6 +81,10 @@ int agent_learn (struct agent_card_info_s *info);
/* Update INFO with the attribute NAME. */
int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
/* Send the KEYTOCARD command. */
int agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp);
/* Send a SETATTR command to the SCdaemon. */
int agent_scd_setattr (const char *name,
const unsigned char *value, size_t valuelen,
@ -155,12 +159,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

@ -1264,6 +1264,7 @@ replace_existing_key_p (struct agent_card_info_s *info, int keyno)
if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_key",
_("Replace existing key? (y/N) ")))
return -1;
return 1;
}
return 0;
}
@ -1484,7 +1485,7 @@ card_generate_subkey (KBNODE pub_keyblock)
tty_printf(_("Invalid selection.\n"));
}
if (replace_existing_key_p (&info, keyno))
if (replace_existing_key_p (&info, keyno) < 0)
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
@ -1531,152 +1532,99 @@ card_generate_subkey (KBNODE pub_keyblock)
int
card_store_subkey (KBNODE node, int use)
{
log_info ("FIXME: card_store_subkey has not yet been implemented\n");
/* struct agent_card_info_s info; */
/* int okay = 0; */
/* int rc; */
/* int keyno, i; */
/* PKT_secret_key *copied_sk = NULL; */
/* PKT_secret_key *sk; */
/* size_t n; */
/* const char *s; */
/* int allow_keyno[3]; */
/* unsigned int nbits; */
struct agent_card_info_s info;
int okay = 0;
unsigned int nbits;
int allow_keyno[3];
int keyno;
PKT_public_key *pk;
gpg_error_t err;
char *hexgrip;
int rc;
gnupg_isotime_t timebuf;
assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
/* assert (node->pkt->pkttype == PKT_SECRET_KEY */
/* || node->pkt->pkttype == PKT_SECRET_SUBKEY); */
/* sk = node->pkt->pkt.secret_key; */
pk = node->pkt->pkt.public_key;
/* if (get_info_for_key_operation (&info)) */
/* return 0; */
if (get_info_for_key_operation (&info))
return 0;
/* if (!info.extcap.ki) */
/* { */
/* tty_printf ("The card does not support the import of keys\n"); */
/* tty_printf ("\n"); */
/* goto leave; */
/* } */
if (!info.extcap.ki)
{
tty_printf ("The card does not support the import of keys\n");
tty_printf ("\n");
goto leave;
}
/* show_card_key_info (&info); */
nbits = nbits_from_pk (pk);
/* nbits = nbits_from_sk (sk); */
if (!is_RSA (pk->pubkey_algo) || (!info.is_v2 && nbits != 1024) )
{
tty_printf ("You may only store a 1024 bit RSA key on the card\n");
tty_printf ("\n");
goto leave;
}
/* if (!is_RSA (sk->pubkey_algo) || (!info.is_v2 && nbits != 1024) ) */
/* { */
/* tty_printf ("You may only store a 1024 bit RSA key on the card\n"); */
/* tty_printf ("\n"); */
/* goto leave; */
/* } */
allow_keyno[0] = (!use || (use & (PUBKEY_USAGE_SIG)));
allow_keyno[1] = (!use || (use & (PUBKEY_USAGE_ENC)));
allow_keyno[2] = (!use || (use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH)));
/* allow_keyno[0] = (!use || (use & (PUBKEY_USAGE_SIG))); */
/* allow_keyno[1] = (!use || (use & (PUBKEY_USAGE_ENC))); */
/* allow_keyno[2] = (!use || (use & (PUBKEY_USAGE_SIG|PUBKEY_USAGE_AUTH))); */
tty_printf (_("Please select where to store the key:\n"));
/* tty_printf (_("Please select where to store the key:\n")); */
if (allow_keyno[0])
tty_printf (_(" (1) Signature key\n"));
if (allow_keyno[1])
tty_printf (_(" (2) Encryption key\n"));
if (allow_keyno[2])
tty_printf (_(" (3) Authentication key\n"));
/* if (allow_keyno[0]) */
/* tty_printf (_(" (1) Signature key\n")); */
/* if (allow_keyno[1]) */
/* tty_printf (_(" (2) Encryption key\n")); */
/* if (allow_keyno[2]) */
/* tty_printf (_(" (3) Authentication key\n")); */
for (;;)
{
char *answer = cpr_get ("cardedit.genkeys.storekeytype",
_("Your selection? "));
cpr_kill_prompt();
if (*answer == CONTROL_D || !*answer)
{
xfree (answer);
goto leave;
}
keyno = *answer? atoi(answer): 0;
xfree(answer);
if (keyno >= 1 && keyno <= 3 && allow_keyno[keyno-1])
{
if (info.is_v2 && !info.extcap.aac
&& info.key_attr[keyno-1].nbits != nbits)
{
tty_printf ("Key does not match the card's capability.\n");
}
else
break; /* Okay. */
}
else
tty_printf(_("Invalid selection.\n"));
}
/* for (;;) */
/* { */
/* char *answer = cpr_get ("cardedit.genkeys.storekeytype", */
/* _("Your selection? ")); */
/* cpr_kill_prompt(); */
/* if (*answer == CONTROL_D || !*answer) */
/* { */
/* xfree (answer); */
/* goto leave; */
/* } */
/* keyno = *answer? atoi(answer): 0; */
/* xfree(answer); */
/* if (keyno >= 1 && keyno <= 3 && allow_keyno[keyno-1]) */
/* { */
/* if (info.is_v2 && !info.extcap.aac */
/* && info.key_attr[keyno-1].nbits != nbits) */
/* { */
/* tty_printf ("Key does not match the card's capability.\n"); */
/* } */
/* else */
/* break; /\* Okay. *\/ */
/* } */
/* else */
/* tty_printf(_("Invalid selection.\n")); */
/* } */
if ((rc = replace_existing_key_p (&info, keyno)) < 0)
goto leave;
/* if (replace_existing_key_p (&info, keyno)) */
/* goto leave; */
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
goto leave;
/* /\* Unprotect key. *\/ */
/* switch (is_secret_key_protected (sk) ) */
/* { */
/* case 0: /\* Not protected. *\/ */
/* break; */
/* case -1: */
/* log_error (_("unknown key protection algorithm\n")); */
/* goto leave; */
/* default: */
/* if (sk->protect.s2k.mode == 1001) */
/* { */
/* log_error (_("secret parts of key are not available\n")); */
/* goto leave; */
/* } */
/* if (sk->protect.s2k.mode == 1002) */
/* { */
/* log_error (_("secret key already stored on a card\n")); */
/* goto leave; */
/* } */
/* /\* We better copy the key before we unprotect it. *\/ */
/* copied_sk = sk = copy_secret_key (NULL, sk); */
/* rc = 0/\*check_secret_key (sk, 0)*\/; */
/* if (rc) */
/* goto leave; */
/* } */
epoch2isotime (timebuf, (time_t)pk->timestamp);
agent_keytocard (hexgrip, keyno, rc, info.serialno, timebuf);
/* #warning code save_unprotected_key_to_card */
/* /\* rc = save_unprotected_key_to_card (sk, keyno); *\/ */
/* /\* if (rc) *\/ */
/* /\* { *\/ */
/* /\* log_error (_("error writing key to card: %s\n"), gpg_strerror (rc)); *\/ */
/* /\* goto leave; *\/ */
/* /\* } *\/ */
if (rc)
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
else
okay = 1;
xfree (hexgrip);
/* /\* Get back to the maybe protected original secret key. *\/ */
/* if (copied_sk) */
/* { */
/* free_secret_key (copied_sk); */
/* copied_sk = NULL; */
/* } */
/* sk = node->pkt->pkt.secret_key; */
/* /\* Get rid of the secret key parameters and store the serial numer. *\/ */
/* n = pubkey_get_nskey (sk->pubkey_algo); */
/* for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++) */
/* { */
/* gcry_mpi_release (sk->skey[i]); */
/* sk->skey[i] = NULL; */
/* } */
/* i = pubkey_get_npkey (sk->pubkey_algo); */
/* sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8); */
/* sk->is_protected = 1; */
/* sk->protect.s2k.mode = 1002; */
/* s = info.serialno; */
/* for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1]; */
/* sk->protect.ivlen++, s += 2) */
/* sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s); */
/* okay = 1; */
/* leave: */
/* if (copied_sk) */
/* free_secret_key (copied_sk); */
/* agent_release_card_info (&info); */
/* return okay; */
return -1;
leave:
agent_release_card_info (&info);
return okay;
}

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", "@"),
@ -2594,7 +2597,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

@ -353,6 +353,8 @@ void unblock_all_signals(void);
/*-- server.c --*/
int gpg_server (ctrl_t);
gpg_error_t gpg_proxy_pinentry_notify (ctrl_t ctrl,
const unsigned char *line);
#ifdef ENABLE_CARD_SUPPORT
/*-- card-util.c --*/

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

@ -201,7 +201,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

@ -50,6 +50,9 @@ struct server_local_s
/* List of prepared recipients. */
pk_list_t recplist;
/* Set if pinentry notifications should be passed back to the
client. */
int allow_pinentry_notify;
};
@ -105,9 +108,8 @@ has_option (const char *line, const char *name)
static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value)
{
/* ctrl_t ctrl = assuan_get_pointer (ctx); */
ctrl_t ctrl = assuan_get_pointer (ctx);
(void)ctx;
(void)value;
/* Fixme: Implement the tty and locale args. */
@ -136,6 +138,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
{
/* This is for now a dummy option. */
}
else if (!strcmp (key, "allow-pinentry-notify"))
{
ctrl->server_local->allow_pinentry_notify = 1;
}
else
return gpg_error (GPG_ERR_UNKNOWN_OPTION);
@ -768,3 +774,29 @@ gpg_server (ctrl_t ctrl)
assuan_release (ctx);
return rc;
}
/* Helper to notify the client about Pinentry events. Because that
might disturb some older clients, this is only done when enabled
via an option. If it is not enabled we tell Windows to allow
setting the foreground window right here. Returns an gpg error
code. */
gpg_error_t
gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
{
if (!ctrl || !ctrl->server_local
|| !ctrl->server_local->allow_pinentry_notify)
{
gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
/* Client might be interested in that event - send as status line. */
if (!strncmp (line, "PINENTRY_LAUNCHED", 17)
&& (line[17]==' '||!line[17]))
{
for (line += 17; *line && spacep (line); line++)
;
write_status_text (STATUS_PINENTRY_LAUNCHED, line);
}
return 0;
}
return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
}

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);
@ -1604,6 +1605,8 @@ update_keysig_packet( PKT_signature **ret_sig,
/* create a new signature packet */
sig = copy_signature (NULL, orig_sig);
sig->digest_algo=digest_algo;
/* We need to create a new timestamp so that new sig expiration
calculations are done correctly... */
sig->timestamp=make_timestamp();