diff --git a/NEWS b/NEWS index 3b2016f3a..eb1bdbcf6 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,8 @@ Noteworthy changes in version 2.1.0-betaN (unreleased) * Support installation as portable application under Windows. + * Fixed GPG to decrypt using an OpenPGP card. + Noteworthy changes in version 2.1.0beta3 (2011-12-20) ----------------------------------------------------- diff --git a/agent/agent.h b/agent/agent.h index 885e7fe75..ae4e4686f 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -370,7 +370,7 @@ int agent_pksign (ctrl_t ctrl, const char *cache_nonce, /*-- pkdecrypt.c --*/ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, const unsigned char *ciphertext, size_t ciphertextlen, - membuf_t *outbuf); + membuf_t *outbuf, int *r_padding); /*-- genkey.c --*/ int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent); @@ -425,7 +425,7 @@ int divert_pksign (ctrl_t ctrl, int divert_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher, const unsigned char *shadow_info, - char **r_buf, size_t *r_len); + char **r_buf, size_t *r_len, int *r_padding); int divert_generic_cmd (ctrl_t ctrl, const char *cmdline, void *assuan_context); int divert_writekey (ctrl_t ctrl, int force, const char *serialno, @@ -459,7 +459,7 @@ int agent_card_pkdecrypt (ctrl_t ctrl, 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); + char **r_buf, size_t *r_buflen, int *r_padding); int agent_card_readcert (ctrl_t ctrl, const char *id, char **r_buf, size_t *r_buflen); int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf); diff --git a/agent/call-scd.c b/agent/call-scd.c index a334b15a1..a6c429c41 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -1,6 +1,7 @@ /* call-scd.c - fork of the scdaemon to do SC operations * Copyright (C) 2001, 2002, 2005, 2007, 2010, * 2011 Free Software Foundation, Inc. + * Copyright (C) 2013 Werner Koch * * This file is part of GnuPG. * @@ -874,14 +875,36 @@ agent_card_pksign (ctrl_t ctrl, return unlock_scd (ctrl, 0); } -/* Decipher INDATA using the current card. Note that the returned value is */ + + + +/* Check whether there is any padding info from scdaemon. */ +static gpg_error_t +padding_info_cb (void *opaque, const char *line) +{ + int *r_padding = opaque; + const char *s; + + if ((s=has_leading_keyword (line, "PADDING"))) + { + *r_padding = atoi (s); + } + + return 0; +} + + +/* Decipher INDATA using the current card. Note that the returned + value is not an s-expression but the raw data as returned by + scdaemon. The padding information is stored at R_PADDING with -1 + for not known. */ int agent_card_pkdecrypt (ctrl_t ctrl, 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) + char **r_buf, size_t *r_buflen, int *r_padding) { int rc, i; char *p, line[ASSUAN_LINELENGTH]; @@ -890,6 +913,7 @@ agent_card_pkdecrypt (ctrl_t ctrl, size_t len; *r_buf = NULL; + *r_padding = -1; /* Unknown. */ rc = start_scd (ctrl); if (rc) return rc; @@ -923,7 +947,7 @@ agent_card_pkdecrypt (ctrl_t ctrl, rc = assuan_transact (ctrl->scd_local->ctx, line, membuf_data_cb, &data, inq_needpin, &inqparm, - NULL, NULL); + padding_info_cb, r_padding); if (inqparm.any_inq_seen && (gpg_err_code(rc) == GPG_ERR_CANCELED || gpg_err_code(rc) == GPG_ERR_ASS_CANCELED)) rc = cancel_inquire (ctrl, rc); diff --git a/agent/command.c b/agent/command.c index 8e5d1803a..938778ac4 100644 --- a/agent/command.c +++ b/agent/command.c @@ -865,6 +865,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) unsigned char *value; size_t valuelen; membuf_t outbuf; + int padding; (void)line; @@ -879,12 +880,19 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) init_membuf (&outbuf, 512); rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc, - value, valuelen, &outbuf); + value, valuelen, &outbuf, &padding); xfree (value); if (rc) clear_outbuf (&outbuf); else - rc = write_and_clear_outbuf (ctx, &outbuf); + { + if (padding != -1) + rc = print_assuan_status (ctx, "PADDING", "%d", padding); + else + rc = 0; + if (!rc) + rc = write_and_clear_outbuf (ctx, &outbuf); + } xfree (ctrl->server_local->keydesc); ctrl->server_local->keydesc = NULL; return leave_cmd (ctx, rc); diff --git a/agent/divert-scd.c b/agent/divert-scd.c index f0d847389..ceef588fb 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -383,12 +383,13 @@ divert_pksign (ctrl_t ctrl, /* 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. */ + allocated buffer in R_BUF. The padding information is stored at + R_PADDING with -1 for not known. */ int divert_pkdecrypt (ctrl_t ctrl, const unsigned char *cipher, const unsigned char *shadow_info, - char **r_buf, size_t *r_len) + char **r_buf, size_t *r_len, int *r_padding) { int rc; char *kid; @@ -399,6 +400,8 @@ divert_pkdecrypt (ctrl_t ctrl, char *plaintext; size_t plaintextlen; + *r_padding = -1; + s = cipher; if (*s != '(') return gpg_error (GPG_ERR_INV_SEXP); @@ -436,7 +439,7 @@ divert_pkdecrypt (ctrl_t ctrl, rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl, ciphertext, ciphertextlen, - &plaintext, &plaintextlen); + &plaintext, &plaintextlen, r_padding); if (!rc) { *r_buf = plaintext; diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c index 7df7f1d38..9924d6dff 100644 --- a/agent/pkdecrypt.c +++ b/agent/pkdecrypt.c @@ -32,11 +32,12 @@ /* DECRYPT the stuff in ciphertext which is expected to be a S-Exp. Try to get the key from CTRL and write the decoded stuff back to - OUTFP. */ + OUTFP. The padding information is stored at R_PADDING with -1 + for not known. */ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, const unsigned char *ciphertext, size_t ciphertextlen, - membuf_t *outbuf) + membuf_t *outbuf, int *r_padding) { gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL; unsigned char *shadow_info = NULL; @@ -44,6 +45,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, char *buf = NULL; size_t len; + *r_padding = -1; + if (!ctrl->have_keygrip) { log_error ("speculative decryption not yet supported\n"); @@ -85,7 +88,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text, goto leave; } - rc = divert_pkdecrypt (ctrl, ciphertext, shadow_info, &buf, &len ); + rc = divert_pkdecrypt (ctrl, ciphertext, shadow_info, + &buf, &len, r_padding); if (rc) { log_error ("smartcard decryption failed: %s\n", gpg_strerror (rc)); diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index f832b8ebd..bfb1d9353 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -897,10 +897,15 @@ Here is an example session: C: D (b 3F444677CA))) C: END S: # session key follows + S: S PADDING 0 S: D (value 1234567890ABCDEF0) S: OK descryption successful @end example +The “PADDING” status line is only send if gpg-agent can tell what kind +of padding is used. As of now only the value 0 is used to indicate +that the padding has been removed. + @node Agent PKSIGN @subsection Signing a Hash diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index f454f1428..1a4b6d7b1 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -600,6 +600,10 @@ using the command where @var{keyid} is the hexified ID of the key to be used. +If the card is ware of the apdding format a status line with padding +information is send before the plaintext data. The key for this +status line is @code{PADDING} with the only defined value being 0 and +meaning padding has been removed. @node Scdaemon GETATTR @subsection Read an attribute's value. diff --git a/g10/call-agent.c b/g10/call-agent.c index 17290ec1a..4ce6a06ab 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1816,17 +1816,34 @@ inq_ciphertext_cb (void *opaque, const char *line) } +/* Check whether there is any padding info from the agent. */ +static gpg_error_t +padding_info_cb (void *opaque, const char *line) +{ + int *r_padding = opaque; + const char *s; + + if ((s=has_leading_keyword (line, "PADDING"))) + { + *r_padding = atoi (s); + } + + return 0; +} + + /* 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. KEYID, MAINKEYID and PUBKEY_ALGO are used to construct additional promots or status - messages. */ + messages. The padding information is stored at R_PADDING with -1 + for not known. */ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, u32 *keyid, u32 *mainkeyid, int pubkey_algo, gcry_sexp_t s_ciphertext, - unsigned char **r_buf, size_t *r_buflen) + unsigned char **r_buf, size_t *r_buflen, int *r_padding) { gpg_error_t err; char line[ASSUAN_LINELENGTH]; @@ -1841,9 +1858,12 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, dfltparm.keyinfo.mainkeyid = mainkeyid; dfltparm.keyinfo.pubkey_algo = pubkey_algo; - if (!keygrip || strlen(keygrip) != 40 || !s_ciphertext || !r_buf || !r_buflen) + if (!keygrip || strlen(keygrip) != 40 + || !s_ciphertext || !r_buf || !r_buflen || !r_padding) return gpg_error (GPG_ERR_INV_VALUE); + *r_buf = NULL; + *r_padding = -1; err = start_agent (ctrl, 0); if (err) @@ -1881,7 +1901,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, return err; err = assuan_transact (agent_ctx, "PKDECRYPT", membuf_data_cb, &data, - inq_ciphertext_cb, &parm, NULL, NULL); + inq_ciphertext_cb, &parm, + padding_info_cb, r_padding); xfree (parm.ciphertext); } if (err) diff --git a/g10/call-agent.h b/g10/call-agent.h index cce8304bc..2b944d21b 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -168,7 +168,8 @@ gpg_error_t agent_pksign (ctrl_t ctrl, const char *cache_nonce, gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc, u32 *keyid, u32 *mainkeyid, int pubkey_algo, gcry_sexp_t s_ciphertext, - unsigned char **r_buf, size_t *r_buflen); + unsigned char **r_buf, size_t *r_buflen, + int *r_padding); /* Retrieve a key encryption key. */ gpg_error_t agent_keywrap_key (ctrl_t ctrl, int forexport, diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index a328e1adc..1e7255711 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -146,7 +146,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) unsigned int n; size_t nframe; u16 csum, csum2; - int card = 0; + int padding; gcry_sexp_t s_data; char *desc; char *keygrip; @@ -203,7 +203,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) desc = gpg_format_keydesc (sk, 0, 1); err = agent_pkdecrypt (NULL, keygrip, desc, sk->keyid, sk->main_keyid, sk->pubkey_algo, - s_data, &frame, &nframe); + s_data, &frame, &nframe, &padding); xfree (desc); gcry_sexp_release (s_data); if (err) @@ -270,7 +270,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid) } else { - if (!card) + if (padding) { if (n + 7 > nframe) { diff --git a/scd/app-common.h b/scd/app-common.h index e3d23c2b4..66430b61d 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -34,6 +34,9 @@ #define APP_CHANGE_FLAG_RESET 1 #define APP_CHANGE_FLAG_NULLPIN 2 +/* Bit flags set by the decipher function into R_INFO. */ +#define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */ + struct app_local_s; /* Defined by all app-*.c. */ @@ -93,10 +96,11 @@ struct app_ctx_s { const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen); gpg_error_t (*decipher) (app_t app, const char *keyidstr, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen); + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen, + unsigned int *r_info); gpg_error_t (*writecert) (app_t app, ctrl_t ctrl, const char *certid, gpg_error_t (*pincb)(void*,const char *,char **), @@ -168,15 +172,16 @@ gpg_error_t app_sign (app_t app, const char *keyidstr, int hashalgo, const void *indata, size_t indatalen, unsigned char **outdata, size_t *outdatalen ); gpg_error_t app_auth (app_t app, const char *keyidstr, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen); + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen); gpg_error_t app_decipher (app_t app, const char *keyidstr, - gpg_error_t (*pincb)(void*, const char *, char **), - void *pincb_arg, - const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ); + gpg_error_t (*pincb)(void*, const char *, char **), + void *pincb_arg, + const void *indata, size_t indatalen, + unsigned char **outdata, size_t *outdatalen, + unsigned int *r_info); gpg_error_t app_writecert (app_t app, ctrl_t ctrl, const char *certidstr, gpg_error_t (*pincb)(void*, const char *, char **), diff --git a/scd/app-nks.c b/scd/app-nks.c index 72e726d39..c83217fd0 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -985,13 +985,16 @@ do_decipher (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ) + unsigned char **outdata, size_t *outdatalen, + unsigned int *r_info) { int rc, i; int is_sigg = 0; int fid; int kid; + (void)r_info; + if (!keyidstr || !*keyidstr || !indatalen) return gpg_error (GPG_ERR_INV_VALUE); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 011c24840..dd4a2d91e 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -3598,7 +3598,8 @@ do_decipher (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ) + unsigned char **outdata, size_t *outdatalen, + unsigned int *r_info) { int rc; unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */ @@ -3727,6 +3728,8 @@ do_decipher (app_t app, const char *keyidstr, && app->card_version == 0x0200) log_info ("NOTE: Cards with manufacturer id 5 and s/n <= 346 (0x15a)" " do not work with encryption keys > 2048 bits\n"); + + *r_info |= APP_DECIPHER_INFO_NOPAD; } return rc; diff --git a/scd/app.c b/scd/app.c index e6a663e1e..a0bb5f5ac 100644 --- a/scd/app.c +++ b/scd/app.c @@ -801,10 +801,13 @@ app_decipher (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg, const void *indata, size_t indatalen, - unsigned char **outdata, size_t *outdatalen ) + unsigned char **outdata, size_t *outdatalen, + unsigned int *r_info) { gpg_error_t err; + *r_info = 0; + if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb) return gpg_error (GPG_ERR_INV_VALUE); if (!app->ref_count) @@ -817,7 +820,8 @@ app_decipher (app_t app, const char *keyidstr, err = app->fnc.decipher (app, keyidstr, pincb, pincb_arg, indata, indatalen, - outdata, outdatalen); + outdata, outdatalen, + r_info); unlock_reader (app->slot); if (opt.verbose) log_info ("operation decipher result: %s\n", gpg_strerror (err)); diff --git a/scd/command.c b/scd/command.c index d5cc32cd9..05b50b935 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1089,6 +1089,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) unsigned char *outdata; size_t outdatalen; char *keyidstr; + unsigned int infoflags; if ( IS_LOCKED (ctrl) ) return gpg_error (GPG_ERR_LOCKED); @@ -1103,7 +1104,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) keyidstr, pin_cb, ctx, ctrl->in_data.value, ctrl->in_data.valuelen, - &outdata, &outdatalen); + &outdata, &outdatalen, &infoflags); xfree (keyidstr); if (rc) @@ -1112,6 +1113,13 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line) } else { + /* If the card driver told us that there is no padding, send a + status line. If there is a padding it is assumed that the + caller knows what padding is used. It would have been better + to always send that information but for backward + compatibility we can't do that. */ + if ((infoflags & APP_DECIPHER_INFO_NOPAD)) + send_status_direct (ctrl, "PADDING", "0"); rc = assuan_send_data (ctx, outdata, outdatalen); xfree (outdata); if (rc)