aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/ChangeLog9
-rw-r--r--agent/agent.h9
-rw-r--r--agent/call-scd.c53
-rw-r--r--agent/divert-scd.c60
-rw-r--r--agent/pkdecrypt.c45
-rw-r--r--scd/card.c100
-rw-r--r--scd/command.c35
-rw-r--r--scd/scdaemon.h6
-rw-r--r--sm/ChangeLog5
-rw-r--r--sm/base64.c5
-rw-r--r--sm/decrypt.c8
11 files changed, 305 insertions, 30 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index 94fb00241..bc0ca11ef 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,12 +1,19 @@
+2002-03-06 Werner Koch <[email protected]>
+
+ * pkdecrypt.c (agent_pkdecrypt): Changed the way the diversion is done.
+ * divert-scd.c (divert_pkdecrypt): Changed interface and
+ implemented it.
+
2002-03-05 Werner Koch <[email protected]>
* call-scd.c (inq_needpin): New.
(agent_card_pksign): Add getpin_cb args.
+ (agent_card_pkdecrypt): New.
2002-03-04 Werner Koch <[email protected]>
* pksign.c (agent_pksign): Changed how the diversion is done.
- * divert-scd.c (divert_pksign): Change interface and implemented it.
+ * divert-scd.c (divert_pksign): Changed interface and implemented it.
(encode_md_for_card): New.
* call-scd.c (agent_card_pksign): New.
diff --git a/agent/agent.h b/agent/agent.h
index 643ed60a1..2d92f94be 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -153,8 +153,8 @@ int agent_marktrusted (const char *name, const char *fpr, int flag);
/*-- divert-scd.c --*/
int divert_pksign (const unsigned char *digest, size_t digestlen, int algo,
const char *shadow_info, unsigned char **r_sig);
-int divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
- const char *shadow_info);
+int divert_pkdecrypt (const unsigned char *cipher, const char *shadow_info,
+ char **r_buf, size_t *r_len);
/*-- call-scd.c --*/
int agent_card_learn (void);
@@ -164,6 +164,11 @@ int agent_card_pksign (const char *keyid,
void *getpin_cb_arg,
const unsigned char *indata, size_t indatalen,
char **r_buf, size_t *r_buflen);
+int agent_card_pkdecrypt (const char *keyid,
+ int (*getpin_cb)(void *, const char *, char*,size_t),
+ void *getpin_cb_arg,
+ const unsigned char *indata, size_t indatalen,
+ char **r_buf, size_t *r_buflen);
#endif /*AGENT_H*/
diff --git a/agent/call-scd.c b/agent/call-scd.c
index 6cf53fdfd..dd8853f22 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -403,3 +403,56 @@ agent_card_pksign (const char *keyid,
return 0;
}
+/* Decipher INDATA using the current card. Note that the returned value is */
+int
+agent_card_pkdecrypt (const char *keyid,
+ int (*getpin_cb)(void *, const char *, char*, size_t),
+ void *getpin_cb_arg,
+ const unsigned char *indata, size_t indatalen,
+ char **r_buf, size_t *r_buflen)
+{
+ int rc, i;
+ char *p, line[ASSUAN_LINELENGTH];
+ struct membuf data;
+ struct inq_needpin_s inqparm;
+ size_t len;
+
+ *r_buf = NULL;
+ rc = start_scd ();
+ if (rc)
+ return rc;
+
+ /* FIXME: use secure memory where appropriate */
+ if (indatalen*2 + 50 > DIM(line))
+ return seterr (General_Error);
+
+ sprintf (line, "SETDATA ");
+ p = line + strlen (line);
+ for (i=0; i < indatalen ; i++, p += 2 )
+ sprintf (p, "%02X", indata[i]);
+ rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ return map_assuan_err (rc);
+
+ init_membuf (&data, 1024);
+ inqparm.ctx = scd_ctx;
+ inqparm.getpin_cb = getpin_cb;
+ inqparm.getpin_cb_arg = getpin_cb_arg;
+ snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
+ line[DIM(line)-1] = 0;
+ rc = assuan_transact (scd_ctx, line,
+ membuf_data_cb, &data,
+ inq_needpin, &inqparm,
+ NULL, NULL);
+ if (rc)
+ {
+ xfree (get_membuf (&data, &len));
+ return map_assuan_err (rc);
+ }
+ *r_buf = get_membuf (&data, r_buflen);
+ if (!*r_buf)
+ return GNUPG_Out_Of_Core;
+
+ return 0;
+}
+
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index d938d2618..33fd5ce26 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -258,21 +258,65 @@ divert_pksign (const unsigned char *digest, size_t digestlen, int algo,
}
-int
-divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
- const char *shadow_info)
+/* Decrypt the the value given asn an S-expression in CIPHER using the
+ key identified by SHADOW_INFO and return the plaintext in an
+ allocated buffer in R_BUF. */
+int
+divert_pkdecrypt (const unsigned char *cipher, const char *shadow_info,
+ char **r_buf, size_t *r_len)
{
int rc;
char *kid;
+ const unsigned char *s;
+ size_t n;
+ const unsigned char *ciphertext;
+ size_t ciphertextlen;
+ char *plaintext;
+ size_t plaintextlen;
+
+ s = cipher;
+ if (*s != '(')
+ return GNUPG_Invalid_Sexp;
+ s++;
+ n = snext (&s);
+ if (!n)
+ return GNUPG_Invalid_Sexp;
+ if (!smatch (&s, n, "enc-val"))
+ return GNUPG_Unknown_Sexp;
+ if (*s != '(')
+ return GNUPG_Unknown_Sexp;
+ s++;
+ n = snext (&s);
+ if (!n)
+ return GNUPG_Invalid_Sexp;
+ if (!smatch (&s, n, "rsa"))
+ return GNUPG_Unsupported_Algorithm;
+ if (*s != '(')
+ return GNUPG_Unknown_Sexp;
+ s++;
+ n = snext (&s);
+ if (!n)
+ return GNUPG_Invalid_Sexp;
+ if (!smatch (&s, n, "a"))
+ return GNUPG_Unknown_Sexp;
+ n = snext (&s);
+ if (!n)
+ return GNUPG_Unknown_Sexp;
+ ciphertext = s;
+ ciphertextlen = n;
rc = ask_for_card (shadow_info, &kid);
if (rc)
return rc;
-
+ rc = agent_card_pkdecrypt (kid, getpin_cb, NULL,
+ ciphertext, ciphertextlen,
+ &plaintext, &plaintextlen);
+ if (!rc)
+ {
+ *r_buf = plaintext;
+ *r_len = plaintextlen;
+ }
xfree (kid);
- return GNUPG_Not_Implemented;
+ return rc;
}
-
-
-
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
index 33663a9f7..9a32e76d7 100644
--- a/agent/pkdecrypt.c
+++ b/agent/pkdecrypt.c
@@ -71,14 +71,27 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
rc = seterr (No_Secret_Key);
goto leave;
}
+
if (!s_skey)
{ /* divert operation to the smartcard */
- rc = divert_pkdecrypt (&s_plain, s_cipher, shadow_info);
+
+ if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
+ {
+ rc = GNUPG_Invalid_Sexp;
+ goto leave;
+ }
+
+ rc = divert_pkdecrypt (ciphertext, shadow_info, &buf, &len );
if (rc)
{
log_error ("smartcard decryption failed: %s\n", gnupg_strerror (rc));
goto leave;
}
+ /* FIXME: don't use buffering and change the protocol to return
+ a complete S-expression and not just a part. */
+ fprintf (outfp, "%u:", (unsigned int)len);
+ fwrite (buf, 1, len, outfp);
+ putc (0, outfp);
}
else
{ /* no smartcard, but a private key */
@@ -95,23 +108,23 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
rc = map_gcry_err (rc);
goto leave;
}
+
+ if (DBG_CRYPTO)
+ {
+ log_debug ("plain: ");
+ gcry_sexp_dump (s_plain);
+ }
+ len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
+ assert (len);
+ buf = xmalloc (len);
+ len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
+ assert (len);
+ /* FIXME: we must make sure that no buffering takes place or we are
+ in full control of the buffer memory (easy to do) - should go
+ into assuan. */
+ fwrite (buf, 1, len, outfp);
}
- if (DBG_CRYPTO)
- {
- log_debug ("plain: ");
- gcry_sexp_dump (s_plain);
- }
- len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- buf = xmalloc (len);
- len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
- assert (len);
-
- /* FIXME: we must make sure that no buffering takes place or we are
- in full control of the buffer memory (easy to do) - should go
- into assuan. */
- fwrite (buf, 1, len, outfp);
leave:
gcry_sexp_release (s_skey);
diff --git a/scd/card.c b/scd/card.c
index 281c81013..e7640ffcb 100644
--- a/scd/card.c
+++ b/scd/card.c
@@ -541,3 +541,103 @@ leave:
}
+/* Create the signature and return the allocated result in OUTDATA.
+ If a PIN is required the PINCB will be used to ask for the PIN; it
+ should return the PIN in an allocated buffer and put it into PIN. */
+int
+card_decipher (CARD card, const char *keyidstr,
+ int (pincb)(void*, const char *, char **),
+ void *pincb_arg,
+ const void *indata, size_t indatalen,
+ void **outdata, size_t *outdatalen )
+{
+ struct sc_pkcs15_id keyid;
+ struct sc_pkcs15_prkey_info *key;
+ struct sc_pkcs15_pin_info *pin;
+ struct sc_pkcs15_object *keyobj, *pinobj;
+ char *pinvalue;
+ int rc;
+ unsigned char *outbuf = NULL;
+ size_t outbuflen;
+
+ if (!card || !card->p15card || !indata || !indatalen
+ || !outdata || !outdatalen || !pincb)
+ return GNUPG_Invalid_Value;
+
+ rc = idstr_to_id (keyidstr, &keyid);
+ if (rc)
+ return rc;
+
+ rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &keyobj);
+ if (rc < 0)
+ {
+ log_error ("private key not found: %s\n", sc_strerror(rc));
+ rc = GNUPG_No_Secret_Key;
+ goto leave;
+ }
+ rc = 0;
+ key = keyobj->data;
+
+ rc = sc_pkcs15_find_pin_by_auth_id (card->p15card,
+ &keyobj->auth_id, &pinobj);
+ if (rc)
+ {
+ log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc));
+ rc = GNUPG_Bad_PIN_Method;
+ goto leave;
+ }
+ pin = pinobj->data;
+
+ /* Fixme: pack this into a verification loop */
+ /* Fixme: we might want to pass pin->min_length and
+ pin->stored_length */
+ rc = pincb (pincb_arg, pinobj->label, &pinvalue);
+ if (rc)
+ {
+ log_info ("PIN callback returned error: %s\n", gnupg_strerror (rc));
+ goto leave;
+ }
+
+ rc = sc_pkcs15_verify_pin (card->p15card, pin,
+ pinvalue, strlen (pinvalue));
+ xfree (pinvalue);
+ if (rc)
+ {
+ log_info ("PIN verification failed: %s\n", sc_strerror (rc));
+ rc = GNUPG_Bad_PIN;
+ goto leave;
+ }
+
+ outbuflen = indatalen < 256? 256 : indatalen;
+ outbuf = xtrymalloc (outbuflen);
+ if (!outbuf)
+ return GNUPG_Out_Of_Core;
+
+ /* OpenSC does not yet support decryption for cryptflex cards */
+/* rc = sc_pkcs15_decipher (card->p15card, key, */
+/* indata, indatalen, */
+/* outbuf, outbuflen); */
+ rc = sc_pkcs15_compute_signature (card->p15card, key,
+ 0,
+ indata, indatalen,
+ outbuf, outbuflen );
+ if (rc < 0)
+ {
+ log_error ("failed to decipger the data: %s\n", sc_strerror (rc));
+ rc = GNUPG_Card_Error;
+ }
+ else
+ {
+ *outdatalen = rc;
+ *outdata = outbuf;
+ outbuf = NULL;
+ rc = 0;
+ }
+
+
+leave:
+ xfree (outbuf);
+ return rc;
+}
+
+
diff --git a/scd/command.c b/scd/command.c
index a171de3df..30191dd95 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -400,6 +400,40 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
return map_to_assuan_status (rc);
}
+/* PKDECRYPT <hexified_id>
+
+ */
+static int
+cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
+{
+ CTRL ctrl = assuan_get_pointer (ctx);
+ int rc;
+ void *outdata;
+ size_t outdatalen;
+
+ if ((rc = open_card (ctrl)))
+ return rc;
+
+ rc = card_decipher (ctrl->card_ctx,
+ line,
+ pin_cb, ctx,
+ ctrl->in_data.value, ctrl->in_data.valuelen,
+ &outdata, &outdatalen);
+ if (rc)
+ {
+ log_error ("card_create_signature failed: %s\n", gnupg_strerror (rc));
+ }
+ else
+ {
+ rc = assuan_send_data (ctx, outdata, outdatalen);
+ xfree (outdata);
+ if (rc)
+ return rc; /* that is already an assuan error code */
+ }
+
+ return map_to_assuan_status (rc);
+}
+
@@ -417,6 +451,7 @@ register_commands (ASSUAN_CONTEXT ctx)
{ "READCERT", 0, cmd_readcert },
{ "SETDATA", 0, cmd_setdata },
{ "PKSIGN", 0, cmd_pksign },
+ { "PKDECRYPT", 0,cmd_pkdecrypt },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index 8a5506d32..bd604b41c 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -92,7 +92,11 @@ int card_create_signature (CARD card,
void *pincb_arg,
const void *indata, size_t indatalen,
void **outdata, size_t *outdatalen );
-
+int card_decipher (CARD card, const char *keyidstr,
+ int (pincb)(void*, const char *, char **),
+ void *pincb_arg,
+ const void *indata, size_t indatalen,
+ void **outdata, size_t *outdatalen);
#endif /*SCDAEMON_H*/
diff --git a/sm/ChangeLog b/sm/ChangeLog
index 846388f81..e47057eb7 100644
--- a/sm/ChangeLog
+++ b/sm/ChangeLog
@@ -1,3 +1,8 @@
+2002-03-06 Werner Koch <[email protected]>
+
+ * base64.c (base64_reader_cb): Use case insensitive compare of the
+ Content-Type string to detect plain base-64.
+
2002-03-05 Werner Koch <[email protected]>
* gpgsm.c, gpgsm.h: Add local_user.
diff --git a/sm/base64.c b/sm/base64.c
index bf1aea179..e7a1ae9ae 100644
--- a/sm/base64.c
+++ b/sm/base64.c
@@ -224,8 +224,9 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
parm->linelen = parm->readpos = 0;
}
else if ( parm->have_lf && parm->line_counter == 1
- && !strncmp (parm->line, "Content-Type:", 13))
- { /* Might be a S/MIME body */
+ && parm->linelen >= 13
+ && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
+ { /* might be a S/MIME body */
parm->might_be_smime = 1;
parm->linelen = parm->readpos = 0;
goto next;
diff --git a/sm/decrypt.c b/sm/decrypt.c
index d16bb59e4..382ec0975 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -79,6 +79,14 @@ prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
goto leave;
}
+ /* FIXME: Actually the leading zero is required but due to the way
+ we encode the output in libgcrypt as an MPI we are not able to
+ encode that leading zero. However, when using a Smartcard we are
+ doing it the rightway and therefore we have skip the zero. This
+ should be fixed in gpg-agent of course. */
+ if (!seskey[n])
+ n++;
+
if (seskey[n] != 2 ) /* wrong block type version */
{
rc = seterr (Invalid_Session_Key);