diff options
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r-- | g10/call-agent.c | 180 |
1 files changed, 120 insertions, 60 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c index 8906082b7..cded773c8 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1,5 +1,5 @@ /* call-agent.c - Divert GPG operations to the agent. - * Copyright (C) 2001, 2002, 2003, 2006, 2007, + * Copyright (C) 2001, 2002, 2003, 2006, 2007, * 2008, 2009 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -23,7 +23,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <unistd.h> +#include <unistd.h> #include <time.h> #include <assert.h> #ifdef HAVE_LOCALE_H @@ -48,7 +48,7 @@ static assuan_context_t agent_ctx = NULL; static int did_early_card_test; -struct cipher_parm_s +struct cipher_parm_s { assuan_context_t ctx; const char *ciphertext; @@ -69,13 +69,19 @@ struct writekey_parm_s size_t keydatalen; }; -struct genkey_parm_s +struct genkey_parm_s { assuan_context_t ctx; const char *sexp; size_t sexplen; }; +struct scd_genkey_parm_s +{ + struct agent_card_genkey_s *cgk; + char *savedbytes; /* Malloced space to save key parameter chunks. */ +}; + static gpg_error_t learn_status_cb (void *opaque, const char *line); @@ -99,7 +105,7 @@ status_sc_op_failure (int rc) write_status (STATUS_SC_OP_FAILURE); break; } -} +} @@ -162,7 +168,7 @@ start_agent (int for_card) if (!rc && is_status_enabled () && info.serialno) { char *buf; - + buf = xasprintf ("3 %s", info.serialno); write_status_text (STATUS_CARDCTRL, buf); xfree (buf); @@ -174,7 +180,7 @@ start_agent (int for_card) did_early_card_test = 1; } - + return rc; } @@ -267,7 +273,7 @@ get_serialno_cb (void *opaque, const char *line) memcpy (*serialno, line, n); (*serialno)[n] = 0; } - + return 0; } @@ -329,7 +335,7 @@ learn_status_cb (void *opaque, const char *line) { xfree (parm->serialno); parm->serialno = store_serialno (line); - parm->is_v2 = (strlen (parm->serialno) >= 16 + parm->is_v2 = (strlen (parm->serialno) >= 16 && xtoi_2 (parm->serialno+12) >= 2 ); } else if (keywordlen == 7 && !memcmp (keyword, "APPTYPE", keywordlen)) @@ -510,7 +516,7 @@ agent_learn (struct agent_card_info_s *info) /* Also try to get the key attributes. */ if (!rc) agent_scd_getattr ("KEY-ATTR", info); - + return rc; } @@ -529,7 +535,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) /* We assume that NAME does not need escaping. */ if (12 + strlen (name) > DIM(line)-1) return gpg_error (GPG_ERR_TOO_LARGE); - stpcpy (stpcpy (line, "SCD GETATTR "), name); + stpcpy (stpcpy (line, "SCD GETATTR "), name); rc = start_agent (1); if (rc) @@ -537,7 +543,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info) rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL, learn_status_cb, info); - + return rc; } @@ -562,8 +568,8 @@ agent_scd_setattr (const char *name, /* We assume that NAME does not need escaping. */ if (12 + strlen (name) > DIM(line)-1) return gpg_error (GPG_ERR_TOO_LARGE); - - p = stpcpy (stpcpy (line, "SCD SETATTR "), name); + + p = stpcpy (stpcpy (line, "SCD SETATTR "), name); *p++ = ' '; for (; valuelen; value++, valuelen--) { @@ -584,7 +590,7 @@ agent_scd_setattr (const char *name, rc = start_agent (1); if (!rc) { - rc = assuan_transact (agent_ctx, line, NULL, NULL, + rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL, NULL, NULL); } @@ -601,7 +607,7 @@ static gpg_error_t inq_writecert_parms (void *opaque, const char *line) { int rc; - struct writecert_parm_s *parm = opaque; + struct writecert_parm_s *parm = opaque; if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8])) { @@ -615,7 +621,7 @@ inq_writecert_parms (void *opaque, const char *line) /* Send a WRITECERT command to the SCdaemon. */ -int +int agent_scd_writecert (const char *certidstr, const unsigned char *certdata, size_t certdatalen) { @@ -634,7 +640,7 @@ agent_scd_writecert (const char *certidstr, parms.ctx = agent_ctx; parms.certdata = certdata; parms.certdatalen = certdatalen; - + rc = assuan_transact (agent_ctx, line, NULL, NULL, inq_writecert_parms, &parms, NULL, NULL); @@ -649,7 +655,7 @@ static gpg_error_t inq_writekey_parms (void *opaque, const char *line) { int rc; - struct writekey_parm_s *parm = opaque; + struct writekey_parm_s *parm = opaque; if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7])) { @@ -663,7 +669,7 @@ inq_writekey_parms (void *opaque, const char *line) /* Send a WRITEKEY command to the SCdaemon. */ -int +int agent_scd_writekey (int keyno, const char *serialno, const unsigned char *keydata, size_t keydatalen) { @@ -684,7 +690,7 @@ agent_scd_writekey (int keyno, const char *serialno, parms.ctx = agent_ctx; parms.keydata = keydata; parms.keydatalen = keydatalen; - + rc = assuan_transact (agent_ctx, line, NULL, NULL, inq_writekey_parms, &parms, NULL, NULL); @@ -694,14 +700,44 @@ agent_scd_writekey (int keyno, const char *serialno, +static gpg_error_t +scd_genkey_cb_append_savedbytes (struct scd_genkey_parm_s *parm, + const char *line) +{ + gpg_error_t err = 0; + char *p; + + if (!parm->savedbytes) + { + parm->savedbytes = xtrystrdup (line); + if (!parm->savedbytes) + err = gpg_error_from_syserror (); + } + else + { + p = xtrymalloc (strlen (parm->savedbytes) + strlen (line) + 1); + if (!p) + err = gpg_error_from_syserror (); + else + { + strcpy (stpcpy (p, parm->savedbytes), line); + xfree (parm->savedbytes); + parm->savedbytes = p; + } + } + + return err; +} + + /* Status callback for the SCD GENKEY command. */ static gpg_error_t scd_genkey_cb (void *opaque, const char *line) { - struct agent_card_genkey_s *parm = opaque; + struct scd_genkey_parm_s *parm = opaque; const char *keyword = line; int keywordlen; - gpg_error_t rc; + gpg_error_t rc = 0; for (keywordlen=0; *line && !spacep (line); line++, keywordlen++) ; @@ -710,7 +746,7 @@ scd_genkey_cb (void *opaque, const char *line) if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen)) { - parm->fprvalid = unhexify_fpr (line, parm->fpr); + parm->cgk->fprvalid = unhexify_fpr (line, parm->cgk->fpr); } else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen)) { @@ -722,29 +758,47 @@ scd_genkey_cb (void *opaque, const char *line) while (spacep (line)) line++; - rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL); - if (rc) - log_error ("error parsing received key data: %s\n", gpg_strerror (rc)); - else if (*name == 'n' && spacep (name+1)) - parm->n = a; - else if (*name == 'e' && spacep (name+1)) - parm->e = a; + if (*name == '-' && spacep (name+1)) + rc = scd_genkey_cb_append_savedbytes (parm, line); else { - log_info ("unknown parameter name in received key data\n"); - gcry_mpi_release (a); + if (parm->savedbytes) + { + rc = scd_genkey_cb_append_savedbytes (parm, line); + if (!rc) + rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, + parm->savedbytes, 0, NULL); + } + else + rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL); + if (rc) + log_error ("error parsing received key data: %s\n", + gpg_strerror (rc)); + else if (*name == 'n' && spacep (name+1)) + parm->cgk->n = a; + else if (*name == 'e' && spacep (name+1)) + parm->cgk->e = a; + else + { + log_info ("unknown parameter name in received key data\n"); + gcry_mpi_release (a); + rc = gpg_error (GPG_ERR_INV_PARAMETER); + } + + xfree (parm->savedbytes); + parm->savedbytes = NULL; } } else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen)) { - parm->created_at = (u32)strtoul (line, NULL, 10); + parm->cgk->created_at = (u32)strtoul (line, NULL, 10); } else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen)) { write_status_text (STATUS_PROGRESS, line); } - return 0; + return rc; } /* Send a GENKEY command to the SCdaemon. SERIALNO is not used in @@ -759,9 +813,13 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force, int rc; char line[ASSUAN_LINELENGTH]; gnupg_isotime_t tbuf; + struct scd_genkey_parm_s parms; (void)serialno; + memset (&parms, 0, sizeof parms); + parms.cgk = info; + rc = start_agent (1); if (rc) return rc; @@ -774,15 +832,17 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force, memset (info, 0, sizeof *info); snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d", *tbuf? "--timestamp=":"", tbuf, - force? "--force":"", + force? "--force":"", keyno); line[DIM(line)-1] = 0; memset (info, 0, sizeof *info); rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL, - scd_genkey_cb, info); - + scd_genkey_cb, &parms); + + xfree (parms.savedbytes); + status_sc_op_failure (rc); return rc; } @@ -800,7 +860,7 @@ select_openpgp (const char *serialno) /* Send the serialno command to initialize the connection. Without a given S/N we don't care about the data returned. If the card has already been initialized, this is a very fast command. We - request the openpgp card because that is what we expect. + request the openpgp card because that is what we expect. Note that an opt.limit_card_insert_tries of 1 means: No tries at all whereas 0 means do not limit the number of tries. Due to the @@ -816,7 +876,7 @@ select_openpgp (const char *serialno) int ask; char *want_sn; char *p; - + want_sn = xtrystrdup (serialno); if (!want_sn) return gpg_error_from_syserror (); @@ -824,14 +884,14 @@ select_openpgp (const char *serialno) if (p) *p = 0; - do + do { ask = 0; err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp", - NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, get_serialno_cb, &this_sn); if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT) - ask = 1; + ask = 1; else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED) ask = 2; else if (err) @@ -844,19 +904,19 @@ select_openpgp (const char *serialno) xfree (this_sn); this_sn = NULL; - + if (ask) { char *formatted = NULL; char *ocodeset = i18n_switchto_utf8 (); - if (!strncmp (want_sn, "D27600012401", 12) + if (!strncmp (want_sn, "D27600012401", 12) && strlen (want_sn) == 32 ) formatted = xtryasprintf ("(%.4s) %.8s", want_sn + 16, want_sn + 20); - + err = 0; - desc = xtryasprintf + desc = xtryasprintf ("%s:\n\n" " \"%s\"", ask == 1 @@ -891,7 +951,7 @@ membuf_data_cb (void *opaque, const void *buffer, size_t length) put_membuf (data, buffer, length); return 0; } - + /* Helper returning a command option to describe the used hash algorithm. See scd/command.c:cmd_pksign. */ @@ -1004,7 +1064,7 @@ agent_scd_pkdecrypt (const char *serialno, rc = select_openpgp (serialno); if (rc) return rc; - + sprintf (line, "SCD SETDATA "); p = line + strlen (line); for (i=0; i < indatalen ; i++, p += 2 ) @@ -1037,7 +1097,7 @@ agent_scd_pkdecrypt (const char *serialno, /* Send a READCERT command to the SCdaemon. */ -int +int agent_scd_readcert (const char *certidstr, void **r_buf, size_t *r_buflen) { @@ -1157,8 +1217,8 @@ agent_get_passphrase (const char *cache_id, int rc; char line[ASSUAN_LINELENGTH]; char *arg1 = NULL; - char *arg2 = NULL; - char *arg3 = NULL; + char *arg2 = NULL; + char *arg3 = NULL; char *arg4 = NULL; membuf_t data; @@ -1169,7 +1229,7 @@ agent_get_passphrase (const char *cache_id, return rc; /* Check that the gpg-agent understands the repeat option. */ - if (assuan_transact (agent_ctx, + if (assuan_transact (agent_ctx, "GETINFO cmd_has_option GET_PASSPHRASE repeat", NULL, NULL, NULL, NULL, NULL, NULL)) return gpg_error (GPG_ERR_NOT_SUPPORTED); @@ -1187,9 +1247,9 @@ agent_get_passphrase (const char *cache_id, if (!(arg4 = percent_plus_escape (desc_msg))) goto no_mem; - snprintf (line, DIM(line)-1, - "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s", - repeat, + snprintf (line, DIM(line)-1, + "GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s", + repeat, check? " --check --qualitybar":"", arg1? arg1:"X", arg2? arg2:"X", @@ -1202,13 +1262,13 @@ agent_get_passphrase (const char *cache_id, xfree (arg4); init_membuf_secure (&data, 64); - rc = assuan_transact (agent_ctx, line, + rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data, default_inq_cb, NULL, NULL, NULL); if (rc) xfree (get_membuf (&data, NULL)); - else + else { put_membuf (&data, "", 1); *r_passphrase = get_membuf (&data, NULL); @@ -1287,12 +1347,12 @@ agent_get_s2k_count (unsigned long *r_count) return err; init_membuf (&data, 32); - err = assuan_transact (agent_ctx, "GETINFO s2k_count", + err = assuan_transact (agent_ctx, "GETINFO s2k_count", membuf_data_cb, &data, NULL, NULL, NULL, NULL); if (err) xfree (get_membuf (&data, NULL)); - else + else { put_membuf (&data, "", 1); buf = get_membuf (&data, NULL); |