diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/call-agent.c | 294 | ||||
-rw-r--r-- | g10/call-agent.h | 6 | ||||
-rw-r--r-- | g10/card-util.c | 242 | ||||
-rw-r--r-- | g10/gpg.c | 14 | ||||
-rw-r--r-- | g10/keydb.h | 3 | ||||
-rw-r--r-- | g10/main.h | 2 | ||||
-rw-r--r-- | g10/options.h | 1 | ||||
-rw-r--r-- | g10/passphrase.c | 70 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 4 | ||||
-rw-r--r-- | g10/server.c | 36 | ||||
-rw-r--r-- | g10/sign.c | 3 |
11 files changed, 443 insertions, 232 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c index 55637e463..85a3f2842 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,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; } diff --git a/g10/call-agent.h b/g10/call-agent.h index 43de14fe3..ab1d41a53 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -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); diff --git a/g10/card-util.c b/g10/card-util.c index 83586858e..75208cc86 100644 --- a/g10/card-util.c +++ b/g10/card-util.c @@ -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; */ - - -/* assert (node->pkt->pkttype == PKT_SECRET_KEY */ -/* || node->pkt->pkttype == PKT_SECRET_SUBKEY); */ -/* sk = node->pkt->pkt.secret_key; */ - -/* 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; */ -/* } */ - -/* show_card_key_info (&info); */ - -/* nbits = nbits_from_sk (sk); */ - -/* 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))); */ - -/* 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")); */ - -/* 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 (replace_existing_key_p (&info, keyno)) */ -/* 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; */ -/* } */ - -/* #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; *\/ */ -/* /\* } *\/ */ - -/* /\* 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; + 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); + + pk = node->pkt->pkt.public_key; + + 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; + } + + nbits = nbits_from_pk (pk); + + 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; + } + + 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")); + + 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")); + } + + if ((rc = replace_existing_key_p (&info, keyno)) < 0) + goto leave; + + err = hexkeygrip_from_pk (pk, &hexgrip); + if (err) + goto leave; + + epoch2isotime (timebuf, (time_t)pk->timestamp); + agent_keytocard (hexgrip, keyno, rc, info.serialno, timebuf); + + if (rc) + log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc)); + else + okay = 1; + xfree (hexgrip); + + leave: + agent_release_card_info (&info); + return okay; } @@ -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; diff --git a/g10/keydb.h b/g10/keydb.h index fb36c81eb..39e7826a9 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/main.h b/g10/main.h index d25265aa7..15d3b7627 100644 --- a/g10/main.h +++ b/g10/main.h @@ -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 --*/ diff --git a/g10/options.h b/g10/options.h index d4824bcf1..d44d7a14b 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 a69536e1d..a328e1adc 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -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) diff --git a/g10/server.c b/g10/server.c index d8871d059..da9c28df4 100644 --- a/g10/server.c +++ b/g10/server.c @@ -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); +} diff --git a/g10/sign.c b/g10/sign.c index 6ff7df6a9..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); @@ -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(); |