Decryption using a Cryptoflex card does now work.

This commit is contained in:
Werner Koch 2002-03-06 09:01:12 +00:00
parent 914e77c133
commit 303b4bd636
11 changed files with 305 additions and 30 deletions

View File

@ -1,12 +1,19 @@
2002-03-06 Werner Koch <wk@gnupg.org>
* 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 <wk@gnupg.org>
* call-scd.c (inq_needpin): New.
(agent_card_pksign): Add getpin_cb args.
(agent_card_pkdecrypt): New.
2002-03-04 Werner Koch <wk@gnupg.org>
* 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.

View File

@ -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*/

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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 }

View File

@ -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*/

View File

@ -1,3 +1,8 @@
2002-03-06 Werner Koch <wk@gnupg.org>
* base64.c (base64_reader_cb): Use case insensitive compare of the
Content-Type string to detect plain base-64.
2002-03-05 Werner Koch <wk@gnupg.org>
* gpgsm.c, gpgsm.h: Add local_user.

View File

@ -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;

View File

@ -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);