summaryrefslogtreecommitdiffstats
path: root/g10/call-agent.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2010-04-23 13:36:59 +0200
committerWerner Koch <wk@gnupg.org>2010-04-23 13:36:59 +0200
commit8e5010a958ded63ab6df89e1ba4d45ed9f2e572a (patch)
tree7859b79f876bc753dd2732b3d2348684bc766dbc /g10/call-agent.c
parent2010-04-23 Marcus Brinkmann <marcus@g10code.de> (diff)
downloadgnupg2-8e5010a958ded63ab6df89e1ba4d45ed9f2e572a.tar.xz
gnupg2-8e5010a958ded63ab6df89e1ba4d45ed9f2e572a.zip
Decryption and signi via agent is now implemented.
Diffstat (limited to 'g10/call-agent.c')
-rw-r--r--g10/call-agent.c128
1 files changed, 126 insertions, 2 deletions
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 7ae8fbba5..ea81c6b9e 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -50,8 +50,9 @@ static int did_early_card_test;
struct cipher_parm_s
{
+ ctrl_t ctrl;
assuan_context_t ctx;
- const char *ciphertext;
+ unsigned char *ciphertext;
size_t ciphertextlen;
};
@@ -104,7 +105,6 @@ 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
@@ -1582,3 +1582,127 @@ agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
}
+
+/* Handle a CIPHERTEXT inquiry. Note, we only send the data,
+ assuan_transact takes care of flushing and writing the END. */
+static gpg_error_t
+inq_ciphertext_cb (void *opaque, const char *line)
+{
+ struct cipher_parm_s *parm = opaque;
+ int rc;
+
+ if (!strncmp (line, "CIPHERTEXT", 10) && (line[10]==' '||!line[10]))
+ {
+ assuan_begin_confidential (parm->ctx);
+ rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
+ assuan_end_confidential (parm->ctx);
+ }
+ else
+ rc = default_inq_cb (parm->ctrl, line);
+
+ return rc;
+}
+
+
+/* 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. */
+gpg_error_t
+agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
+ gcry_sexp_t s_ciphertext,
+ unsigned char **r_buf, size_t *r_buflen)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+ membuf_t data;
+ size_t n, len;
+ char *p, *buf, *endp;
+
+ if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ *r_buf = 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;
+
+ snprintf (line, sizeof line, "SETKEY %s", keygrip);
+ 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;
+ }
+
+ init_membuf_secure (&data, 1024);
+ {
+ struct cipher_parm_s parm;
+
+ parm.ctrl = ctrl;
+ parm.ctx = agent_ctx;
+ err = make_canon_sexp (s_ciphertext, &parm.ciphertext, &parm.ciphertextlen);
+ if (err)
+ return err;
+ err = assuan_transact (agent_ctx, "PKDECRYPT",
+ membuf_data_cb, &data,
+ inq_ciphertext_cb, &parm, NULL, NULL);
+ xfree (parm.ciphertext);
+ }
+ if (err)
+ {
+ xfree (get_membuf (&data, &len));
+ return err;
+ }
+
+ put_membuf (&data, "", 1); /* Make sure it is 0 terminated. */
+ buf = get_membuf (&data, &len);
+ if (!buf)
+ return gpg_error_from_syserror ();
+ assert (len); /* (we forced Nul termination.) */
+
+ if (*buf != '(')
+ {
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_SEXP);
+ }
+
+ if (len < 13 || memcmp (buf, "(5:value", 8) ) /* "(5:valueN:D)\0" */
+ {
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_SEXP);
+ }
+ len -= 11; /* Count only the data of the second part. */
+ p = buf + 8; /* Skip leading parenthesis and the value tag. */
+
+ n = strtoul (p, &endp, 10);
+ if (!n || *endp != ':')
+ {
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_SEXP);
+ }
+ endp++;
+ if (endp-p+n > len)
+ {
+ xfree (buf);
+ return gpg_error (GPG_ERR_INV_SEXP); /* Oops: Inconsistent S-Exp. */
+ }
+
+ memmove (buf, endp, n);
+
+ *r_buflen = n;
+ *r_buf = buf;
+ return 0;
+}