gpg: Make decryption with the OpenPGP card work.

* scd/app-common.h (APP_DECIPHER_INFO_NOPAD): New.
* scd/app-openpgp.c (do_decipher): Add arg R_INFO.
* scd/app-nks.c (do_decipher): Add arg R_INFO as a dummy.
* scd/app.c (app_decipher): Add arg R_INFO.
* scd/command.c (cmd_pkdecrypt): Print status line "PADDING".
* agent/call-scd.c (padding_info_cb): New.
(agent_card_pkdecrypt): Add arg R_PADDING.
* agent/divert-scd.c (divert_pkdecrypt): Ditto.
* agent/pkdecrypt.c (agent_pkdecrypt): Ditto.
* agent/command.c (cmd_pkdecrypt):  Print status line "PADDING".
* g10/call-agent.c (padding_info_cb): New.
(agent_pkdecrypt): Add arg R_PADDING.
* g10/pubkey-enc.c (get_it): Use padding info.
--

Decryption using a card never worked in gpg 2.1 because the
information whether the pkcs#1 padding needs to be removed was not
available.  Gpg < 2.1 too this info from the secret sub key but that
has gone in 2.1.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2013-08-26 17:29:54 +02:00
parent 04e2c83f18
commit 780ba32336
16 changed files with 134 additions and 39 deletions

2
NEWS
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 **),

View File

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

View File

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

View File

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

View File

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