aboutsummaryrefslogtreecommitdiffstats
path: root/g10/call-agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r--g10/call-agent.c180
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);