summaryrefslogtreecommitdiffstats
path: root/g10/call-agent.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2010-04-20 19:57:50 +0200
committerWerner Koch <wk@gnupg.org>2010-04-20 19:57:50 +0200
commit21b0a955be63dc69625194ece8557e79b6ad60c2 (patch)
tree97de4727b46f1f2b5dac30142e5a408c898d48fc /g10/call-agent.c
parentAdd missing file. (diff)
downloadgnupg2-21b0a955be63dc69625194ece8557e79b6ad60c2.tar.xz
gnupg2-21b0a955be63dc69625194ece8557e79b6ad60c2.zip
Generating an OpenPGP key cia gpg-agent basically works.
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r--g10/call-agent.c333
1 files changed, 312 insertions, 21 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 260cd48a9..9379fcb52 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 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009,
+ * 2010 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -69,14 +69,15 @@ struct writekey_parm_s
size_t keydatalen;
};
-struct genkey_parm_s
+struct genkey_parm_s
{
+ ctrl_t ctrl;
assuan_context_t ctx;
- const char *sexp;
- size_t sexplen;
+ const char *keyparms;
};
+
static gpg_error_t learn_status_cb (void *opaque, const char *line);
@@ -107,10 +108,12 @@ status_sc_op_failure (int rc)
/* Try to connect to the agent via socket or fork it off and work by
pipes. Handle the server's initial greeting */
static int
-start_agent (int for_card)
+start_agent (ctrl_t ctrl, int for_card)
{
int rc;
+ (void)ctrl; /* Not yet used. */
+
/* Fixme: We need a context for each thread or serialize the access
to the agent. */
if (agent_ctx)
@@ -486,7 +489,7 @@ agent_learn (struct agent_card_info_s *info)
{
int rc;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -531,7 +534,7 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
return gpg_error (GPG_ERR_TOO_LARGE);
stpcpy (stpcpy (line, "SCD GETATTR "), name);
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -581,7 +584,7 @@ agent_scd_setattr (const char *name,
}
*p = 0;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (!rc)
{
rc = assuan_transact (agent_ctx, line, NULL, NULL,
@@ -623,7 +626,7 @@ agent_scd_writecert (const char *certidstr,
char line[ASSUAN_LINELENGTH];
struct writecert_parm_s parms;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -673,7 +676,7 @@ agent_scd_writekey (int keyno, const char *serialno,
(void)serialno;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -762,7 +765,7 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
(void)serialno;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -909,7 +912,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
*r_buf = NULL;
*r_buflen = 0;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT
|| gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
rc = 0; /* We check later. */
@@ -972,7 +975,7 @@ agent_scd_pkdecrypt (const char *serialno,
size_t len;
*r_buf = NULL;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT
|| gpg_err_code (rc) == GPG_ERR_NOT_SUPPORTED)
rc = 0; /* We check later. */
@@ -1029,7 +1032,7 @@ agent_scd_readcert (const char *certidstr,
size_t len;
*r_buf = NULL;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -1077,7 +1080,7 @@ agent_scd_change_pin (int chvno, const char *serialno)
reset = "--reset";
chvno %= 100;
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -1099,7 +1102,7 @@ agent_scd_checkpin (const char *serialno)
int rc;
char line[ASSUAN_LINELENGTH];
- rc = start_agent (1);
+ rc = start_agent (NULL, 1);
if (rc)
return rc;
@@ -1146,7 +1149,7 @@ agent_get_passphrase (const char *cache_id,
*r_passphrase = NULL;
- rc = start_agent (0);
+ rc = start_agent (NULL, 0);
if (rc)
return rc;
@@ -1217,7 +1220,7 @@ agent_clear_passphrase (const char *cache_id)
if (!cache_id || !*cache_id)
return 0;
- rc = start_agent (0);
+ rc = start_agent (NULL, 0);
if (rc)
return rc;
@@ -1237,7 +1240,7 @@ gpg_agent_get_confirmation (const char *desc)
char *tmp;
char line[ASSUAN_LINELENGTH];
- rc = start_agent (0);
+ rc = start_agent (NULL, 0);
if (rc)
return rc;
@@ -1264,7 +1267,7 @@ agent_get_s2k_count (unsigned long *r_count)
*r_count = 0;
- err = start_agent (0);
+ err = start_agent (NULL, 0);
if (err)
return err;
@@ -1289,3 +1292,291 @@ agent_get_s2k_count (unsigned long *r_count)
return err;
}
+
+
+/* Ask the agent whether a secret key with the given keygrip is
+ known. */
+gpg_error_t
+agent_havekey (ctrl_t ctrl, const char *hexkeygrip)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+
+ err = start_agent (ctrl, 0);
+ if (err)
+ return err;
+
+ if (!hexkeygrip || strlen (hexkeygrip) != 40)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
+ line[DIM(line)-1] = 0;
+
+ err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ return err;
+}
+
+
+
+static gpg_error_t
+keyinfo_status_cb (void *opaque, const char *line)
+{
+ char **serialno = opaque;
+ const char *s, *s2;
+
+ if (!strncmp (line, "KEYINFO ", 8) && !*serialno)
+ {
+ s = strchr (line+8, ' ');
+ if (s && s[1] == 'T' && s[2] == ' ' && s[3])
+ {
+ s += 3;
+ s2 = strchr (s, ' ');
+ if ( s2 > s )
+ {
+ *serialno = xtrymalloc ((s2 - s)+1);
+ if (*serialno)
+ {
+ memcpy (*serialno, s, s2 - s);
+ (*serialno)[s2 - s] = 0;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* Return the serial number for a secret key. If the returned serial
+ number is NULL, the key is not stored on a smartcard. Caller needs
+ to free R_SERIALNO. */
+gpg_error_t
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+ char *serialno = NULL;
+
+ *r_serialno = NULL;
+
+ err = start_agent (ctrl, 0);
+ if (err)
+ return err;
+
+ if (!hexkeygrip || strlen (hexkeygrip) != 40)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
+ line[DIM(line)-1] = 0;
+
+ err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
+ keyinfo_status_cb, &serialno);
+ if (!err && serialno)
+ {
+ /* Sanity check for bad characters. */
+ if (strpbrk (serialno, ":\n\r"))
+ err = GPG_ERR_INV_VALUE;
+ }
+ if (err)
+ xfree (serialno);
+ else
+ *r_serialno = serialno;
+ return err;
+}
+
+
+
+/* Handle a KEYPARMS inquiry. Note, we only send the data,
+ assuan_transact takes care of flushing and writing the end */
+static gpg_error_t
+inq_genkey_parms (void *opaque, const char *line)
+{
+ struct genkey_parm_s *parm = opaque;
+ gpg_error_t err;
+
+ if (!strncmp (line, "KEYPARAM", 8) && (line[8]==' '||!line[8]))
+ {
+ err = assuan_send_data (parm->ctx,
+ parm->keyparms, strlen (parm->keyparms));
+ }
+ else
+ err = default_inq_cb (parm->ctrl, line);
+
+ return err;
+}
+
+
+/* Call the agent to generate a new key. KEYPARMS is the usual
+ S-expression giving the parameters of the key. gpg-agent passes it
+ gcry_pk_genkey. */
+gpg_error_t
+agent_genkey (ctrl_t ctrl, const char *keyparms, gcry_sexp_t *r_pubkey)
+{
+ gpg_error_t err;
+ struct genkey_parm_s gk_parm;
+ membuf_t data;
+ size_t len;
+ unsigned char *buf;
+
+ *r_pubkey = NULL;
+ err = start_agent (ctrl, 0);
+ if (err)
+ return err;
+
+ err = assuan_transact (agent_ctx, "RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ return err;
+
+ init_membuf (&data, 1024);
+ gk_parm.ctrl = ctrl;
+ gk_parm.ctx = agent_ctx;
+ gk_parm.keyparms = keyparms;
+ err = assuan_transact (agent_ctx, "GENKEY",
+ membuf_data_cb, &data,
+ inq_genkey_parms, &gk_parm, NULL, NULL);
+ if (err)
+ {
+ xfree (get_membuf (&data, &len));
+ return err;
+ }
+
+ buf = get_membuf (&data, &len);
+ if (!buf)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = gcry_sexp_sscan (r_pubkey, NULL, buf, len);
+ xfree (buf);
+ }
+ return err;
+}
+
+
+
+
+/* FIXME: Call the agent to read the public key part for a given keygrip. If
+ FROMCARD is true, the key is directly read from the current
+ smartcard. In this case HEXKEYGRIP should be the keyID
+ (e.g. OPENPGP.3). */
+/* int */
+/* agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip, */
+/* ksba_sexp_t *r_pubkey) */
+/* { */
+/* int rc; */
+/* membuf_t data; */
+/* size_t len; */
+/* unsigned char *buf; */
+/* char line[ASSUAN_LINELENGTH]; */
+
+/* *r_pubkey = NULL; */
+/* rc = start_agent (ctrl); */
+/* if (rc) */
+/* return rc; */
+
+/* rc = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL); */
+/* if (rc) */
+/* return rc; */
+
+/* snprintf (line, DIM(line)-1, "%sREADKEY %s", */
+/* fromcard? "SCD ":"", hexkeygrip); */
+/* line[DIM(line)-1] = 0; */
+
+/* init_membuf (&data, 1024); */
+/* rc = assuan_transact (agent_ctx, line, */
+/* membuf_data_cb, &data, */
+/* default_inq_cb, ctrl, NULL, NULL); */
+/* if (rc) */
+/* { */
+/* xfree (get_membuf (&data, &len)); */
+/* return rc; */
+/* } */
+/* buf = get_membuf (&data, &len); */
+/* if (!buf) */
+/* return gpg_error (GPG_ERR_ENOMEM); */
+/* if (!gcry_sexp_canon_len (buf, len, NULL, NULL)) */
+/* { */
+/* xfree (buf); */
+/* return gpg_error (GPG_ERR_INV_SEXP); */
+/* } */
+/* *r_pubkey = buf; */
+/* return 0; */
+/* } */
+
+
+
+/* Call the agent to do a sign operation using the key identified by
+ the hex string KEYGRIP. DESC is a description of the key to be
+ displayed if the agent needs to ask for the PIN. DIGEST and
+ DIGESTLEN is the hash value to sign and DIGESTALGO the algorithm id
+ used to compute the digest. */
+gpg_error_t
+agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
+ unsigned char *digest, size_t digestlen, int digestalgo,
+ gcry_sexp_t *r_sigval)
+{
+ gpg_error_t err;
+ int i;
+ char *p, line[ASSUAN_LINELENGTH];
+ membuf_t data;
+
+ *r_sigval = NULL;
+ err = start_agent (ctrl, 0);
+ if (err)
+ return err;
+
+ if (digestlen*2 + 50 > DIM(line))
+ return gpg_error (GPG_ERR_GENERAL);
+
+ err = assuan_transact (agent_ctx, "RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ return err;
+
+ snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
+ line[DIM(line)-1] = 0;
+ err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ return err;
+
+ if (desc)
+ {
+ snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+ line[DIM(line)-1] = 0;
+ err = assuan_transact (agent_ctx, line,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ return err;
+ }
+
+ snprintf (line, sizeof line, "SETHASH %d ", digestalgo);
+ p = line + strlen (line);
+ for (i=0; i < digestlen ; i++, p += 2 )
+ sprintf (p, "%02X", digest[i]);
+ err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ return err;
+
+ init_membuf (&data, 1024);
+ err = assuan_transact (agent_ctx, "PKSIGN",
+ membuf_data_cb, &data, default_inq_cb, ctrl,
+ NULL, NULL);
+ if (err)
+ xfree (get_membuf (&data, NULL));
+ else
+ {
+ unsigned char *buf;
+ size_t len;
+
+ buf = get_membuf (&data, &len);
+ if (!buf)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = gcry_sexp_sscan (r_sigval, NULL, buf, len);
+ xfree (buf);
+ }
+ }
+ return err;
+}
+
+