mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
More support for Netkey cards.
Small changes to teh CCID driver. Support 2048 bit OpenPGP cards.
This commit is contained in:
parent
03aae15a56
commit
eeca39ae50
@ -1,3 +1,26 @@
|
||||
2009-05-08 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-openpgp.c (do_genkey): Allow larger key sizes.
|
||||
(do_decipher): Ditto.
|
||||
* iso7816.c (do_generate_keypair): Add arg EXTENDED_MODE an LE.
|
||||
(iso7816_generate_keypair, iso7816_read_public_key): Ditto.
|
||||
Changed all callers.
|
||||
* apdu.c (send_le): Implement extended length return values.
|
||||
|
||||
* ccid-driver.c (bulk_in): Retry on EAGAIN.
|
||||
(abort_cmd): Change seqno handling.
|
||||
|
||||
2009-04-28 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-help.c (app_help_count_bits): New.
|
||||
|
||||
* app-nks.c (switch_application): Detect mass signature cards.
|
||||
Take care of new NEED_APP_SELECT flag.
|
||||
(do_sign): Don't allow mass signature cards.
|
||||
(all_zero_p): New.
|
||||
(do_readkey): New.
|
||||
(app_select_nks): Register do_readkey.
|
||||
|
||||
2009-04-01 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-openpgp.c (do_setattr, do_writekey): Prepare for extended
|
||||
|
55
scd/apdu.c
55
scd/apdu.c
@ -2817,8 +2817,6 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
|
||||
length limit.
|
||||
n > 1 := Use extended length with up to N bytes.
|
||||
|
||||
FIXME: We don't support extended length return values larger
|
||||
than 256 bytes due to a static buffer.
|
||||
*/
|
||||
static int
|
||||
send_le (int slot, int class, int ins, int p0, int p1,
|
||||
@ -2826,9 +2824,12 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
unsigned char **retbuf, size_t *retbuflen,
|
||||
struct pininfo_s *pininfo, int extended_mode)
|
||||
{
|
||||
#define RESULTLEN 258
|
||||
unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
|
||||
the driver. */
|
||||
#define SHORT_RESULT_BUFFER_SIZE 258
|
||||
/* We allocate 8 extra bytes as a safety margin towards a driver bug. */
|
||||
unsigned char short_result_buffer[SHORT_RESULT_BUFFER_SIZE+10];
|
||||
unsigned char *result_buffer = NULL;
|
||||
size_t result_buffer_size;
|
||||
unsigned char *result;
|
||||
size_t resultlen;
|
||||
unsigned char short_apdu_buffer[5+256+1];
|
||||
unsigned char *apdu_buffer = NULL;
|
||||
@ -2873,8 +2874,22 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
else if (lc == -1 && extended_mode > 0)
|
||||
use_extended_length = 1;
|
||||
|
||||
if (le != -1 && (le > 256 || le < 0))
|
||||
return SW_WRONG_LENGTH;
|
||||
if (le != -1 && (le > (extended_mode > 0? 255:256) || le < 0))
|
||||
{
|
||||
/* Expected Data does not fit into an APDU. What we do now
|
||||
depends on the EXTENDED_MODE parameter. Note that a check
|
||||
for command chaining does not make sense because we are
|
||||
looking at Le. */
|
||||
if (!extended_mode)
|
||||
return SW_WRONG_LENGTH; /* No way to send such an APDU. */
|
||||
else if (use_extended_length)
|
||||
; /* We are already using extended length. */
|
||||
else if (extended_mode > 0)
|
||||
use_extended_length = 1;
|
||||
else
|
||||
return SW_HOST_INV_VALUE;
|
||||
}
|
||||
|
||||
if ((!data && lc != -1) || (data && lc == -1))
|
||||
return SW_HOST_INV_VALUE;
|
||||
|
||||
@ -2885,7 +2900,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
|
||||
/* Space for: cls/ins/p1/p2+Z+2_byte_Lc+Lc+2_byte_Le. */
|
||||
apdu_buffer_size = 4 + 1 + (lc >= 0? (2+lc):0) + 2;
|
||||
apdu_buffer = xtrymalloc (apdu_buffer_size);
|
||||
apdu_buffer = xtrymalloc (apdu_buffer_size + 10);
|
||||
if (!apdu_buffer)
|
||||
return SW_HOST_OUT_OF_CORE;
|
||||
apdu = apdu_buffer;
|
||||
@ -2896,6 +2911,24 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
apdu = short_apdu_buffer;
|
||||
}
|
||||
|
||||
if (use_extended_length && (le > 256 || le < 0))
|
||||
{
|
||||
result_buffer_size = le < 0? 4096 : le;
|
||||
result_buffer = xtrymalloc (result_buffer_size + 10);
|
||||
if (!result_buffer)
|
||||
{
|
||||
xfree (apdu_buffer);
|
||||
return SW_HOST_OUT_OF_CORE;
|
||||
}
|
||||
result = result_buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
result_buffer_size = SHORT_RESULT_BUFFER_SIZE;
|
||||
result = short_result_buffer;
|
||||
}
|
||||
#undef SHORT_RESULT_BUFFER_SIZE
|
||||
|
||||
if ((sw = lock_slot (slot)))
|
||||
return sw;
|
||||
|
||||
@ -2963,7 +2996,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
/* As a safeguard don't pass any garbage to the driver. */
|
||||
assert (apdulen <= apdu_buffer_size);
|
||||
memset (apdu+apdulen, 0, apdu_buffer_size - apdulen);
|
||||
resultlen = RESULTLEN;
|
||||
resultlen = result_buffer_size;
|
||||
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
|
||||
if (rc || resultlen < 2)
|
||||
{
|
||||
@ -3051,7 +3084,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
apdu[apdulen++] = len;
|
||||
assert (apdulen <= apdu_buffer_size);
|
||||
memset (apdu+apdulen, 0, apdu_buffer_size - apdulen);
|
||||
resultlen = RESULTLEN;
|
||||
resultlen = result_buffer_size;
|
||||
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
|
||||
if (rc || resultlen < 2)
|
||||
{
|
||||
@ -3114,7 +3147,6 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
||||
log_printhex (" dump: ", *retbuf, *retbuflen);
|
||||
|
||||
return sw;
|
||||
#undef RESULTLEN
|
||||
}
|
||||
|
||||
/* Send an APDU to the card in SLOT. The APDU is created from all
|
||||
@ -3210,6 +3242,7 @@ apdu_send_direct (int slot, int extended_mode,
|
||||
unsigned char **retbuf, size_t *retbuflen)
|
||||
{
|
||||
#define RESULTLEN 258
|
||||
/* FIXME: Implement dynamic result buffer and extended Le. */
|
||||
unsigned char apdu[5+256+1];
|
||||
size_t apdulen;
|
||||
unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
|
||||
|
@ -135,6 +135,7 @@ gpg_error_t app_openpgp_storekey (app_t app, int keyno,
|
||||
void *pincb_arg);
|
||||
#else
|
||||
/*-- app-help.c --*/
|
||||
unsigned int app_help_count_bits (const unsigned char *a, size_t len);
|
||||
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
|
||||
size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* app-help.c - Application helper functions
|
||||
* Copyright (C) 2004 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2004, 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -28,6 +28,30 @@
|
||||
#include "iso7816.h"
|
||||
#include "tlv.h"
|
||||
|
||||
|
||||
/* Count the number of bits, assuming the A represents an unsigned big
|
||||
integer of length LEN bytes. If A is NULL a length of 0 is
|
||||
returned. */
|
||||
unsigned int
|
||||
app_help_count_bits (const unsigned char *a, size_t len)
|
||||
{
|
||||
unsigned int n = len * 8;
|
||||
int i;
|
||||
|
||||
if (!a)
|
||||
return 0;
|
||||
|
||||
for (; len && !*a; len--, a++, n -=8)
|
||||
;
|
||||
if (len)
|
||||
{
|
||||
for (i=7; i && !(*a & (1<<i)); i--)
|
||||
n--;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* Return the KEYGRIP for the certificate CERT as an hex encoded
|
||||
string in the user provided buffer HEXKEYGRIP which must be of at
|
||||
least 41 bytes. */
|
||||
|
121
scd/app-nks.c
121
scd/app-nks.c
@ -100,6 +100,11 @@ struct app_local_s {
|
||||
int nks_version; /* NKS version. */
|
||||
|
||||
int sigg_active; /* True if switched to the SigG application. */
|
||||
int sigg_msig_checked;/* True if we checked for a mass signature card. */
|
||||
int sigg_is_msig; /* True if this is a mass signature card. */
|
||||
|
||||
int need_app_select; /* Need to re-select the application. */
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -120,6 +125,18 @@ do_deinit (app_t app)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
all_zero_p (void *buffer, size_t length)
|
||||
{
|
||||
char *p;
|
||||
|
||||
for (p=buffer; length; length--, p++)
|
||||
if (*p)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Read the file with FID, assume it contains a public key and return
|
||||
its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
|
||||
static gpg_error_t
|
||||
@ -590,6 +607,65 @@ do_readcert (app_t app, const char *certid,
|
||||
}
|
||||
|
||||
|
||||
/* Handle the READKEY command. On success a canonical encoded
|
||||
S-expression with the public key will get stored at PK and its
|
||||
length at PKLEN; the caller must release that buffer. On error PK
|
||||
and PKLEN are not changed and an error code is returned. As of now
|
||||
this function is only useful for the internal authentication key.
|
||||
Other keys are automagically retrieved via by means of the
|
||||
certificate parsing code in commands.c:cmd_readkey. For internal
|
||||
use PK and PKLEN may be NULL to just check for an existing key. */
|
||||
static gpg_error_t
|
||||
do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
unsigned char *buffer[2];
|
||||
size_t buflen[2];
|
||||
unsigned short path[1] = { 0x4500 };
|
||||
|
||||
/* We use a generic name to retrieve PK.AUT.IFD-SPK. */
|
||||
if (!strcmp (keyid, "$IFDAUTHKEY") && app->app_local->nks_version >= 3)
|
||||
;
|
||||
else /* Return the error code expected by cmd_readkey. */
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||
|
||||
/* Access the KEYD file which is always in the master directory. */
|
||||
err = iso7816_select_path (app->slot, path, DIM (path), NULL, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
/* Due to the above select we need to re-select our application. */
|
||||
app->app_local->need_app_select = 1;
|
||||
/* Get the two records. */
|
||||
err = iso7816_read_record (app->slot, 5, 1, 0, &buffer[0], &buflen[0]);
|
||||
if (err)
|
||||
return err;
|
||||
if (all_zero_p (buffer[0], buflen[0]))
|
||||
{
|
||||
xfree (buffer[0]);
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
}
|
||||
err = iso7816_read_record (app->slot, 6, 1, 0, &buffer[1], &buflen[1]);
|
||||
if (err)
|
||||
{
|
||||
xfree (buffer[0]);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (pk && pklen)
|
||||
{
|
||||
*pk = make_canon_sexp_from_rsa_pk (buffer[0], buflen[0],
|
||||
buffer[1], buflen[1],
|
||||
pklen);
|
||||
if (!*pk)
|
||||
err = gpg_error_from_syserror ();
|
||||
}
|
||||
|
||||
xfree (buffer[0]);
|
||||
xfree (buffer[1]);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
basic_pin_checks (const char *pinvalue, int minlen, int maxlen)
|
||||
{
|
||||
@ -673,7 +749,6 @@ verify_pin (app_t app, int pwid, const char *desc,
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
that callback should return the PIN in an allocated buffer and
|
||||
@ -723,6 +798,12 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (is_sigg && app->app_local->sigg_is_msig)
|
||||
{
|
||||
log_info ("mass signature cards are not allowed\n");
|
||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
|
||||
|| !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
|
||||
|| keyidstr[4])
|
||||
@ -1147,8 +1228,9 @@ switch_application (app_t app, int enable_sigg)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
if ((app->app_local->sigg_active && enable_sigg)
|
||||
|| (!app->app_local->sigg_active && !enable_sigg) )
|
||||
if (((app->app_local->sigg_active && enable_sigg)
|
||||
|| (!app->app_local->sigg_active && !enable_sigg))
|
||||
&& !app->app_local->need_app_select)
|
||||
return 0; /* Already switched. */
|
||||
|
||||
log_info ("app-nks: switching to %s\n", enable_sigg? "SigG":"NKS");
|
||||
@ -1157,8 +1239,39 @@ switch_application (app_t app, int enable_sigg)
|
||||
else
|
||||
err = iso7816_select_application (app->slot, aid_nks, sizeof aid_nks, 0);
|
||||
|
||||
if (!err && enable_sigg && app->app_local->nks_version >= 3
|
||||
&& !app->app_local->sigg_msig_checked)
|
||||
{
|
||||
/* Check whether this card is a mass signature card. */
|
||||
unsigned char *buffer;
|
||||
size_t buflen;
|
||||
const unsigned char *tmpl;
|
||||
size_t tmpllen;
|
||||
|
||||
app->app_local->sigg_msig_checked = 1;
|
||||
app->app_local->sigg_is_msig = 1;
|
||||
err = iso7816_select_file (app->slot, 0x5349, 0, NULL, NULL);
|
||||
if (!err)
|
||||
err = iso7816_read_record (app->slot, 1, 1, 0, &buffer, &buflen);
|
||||
if (!err)
|
||||
{
|
||||
tmpl = find_tlv (buffer, buflen, 0x7a, &tmpllen);
|
||||
if (tmpl && tmpllen == 12
|
||||
&& !memcmp (tmpl,
|
||||
"\x93\x02\x00\x01\xA4\x06\x83\x01\x81\x83\x01\x83",
|
||||
12))
|
||||
app->app_local->sigg_is_msig = 0;
|
||||
xfree (buffer);
|
||||
}
|
||||
if (app->app_local->sigg_is_msig)
|
||||
log_info ("This is a mass signature card\n");
|
||||
}
|
||||
|
||||
if (!err)
|
||||
{
|
||||
app->app_local->need_app_select = 0;
|
||||
app->app_local->sigg_active = enable_sigg;
|
||||
}
|
||||
else
|
||||
log_error ("app-nks: error switching to %s: %s\n",
|
||||
enable_sigg? "SigG":"NKS", gpg_strerror (err));
|
||||
@ -1193,8 +1306,10 @@ app_select_nks (app_t app)
|
||||
app->fnc.deinit = do_deinit;
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.readcert = do_readcert;
|
||||
app->fnc.readkey = do_readkey;
|
||||
app->fnc.getattr = do_getattr;
|
||||
app->fnc.setattr = NULL;
|
||||
app->fnc.writekey = NULL;
|
||||
app->fnc.genkey = NULL;
|
||||
app->fnc.sign = do_sign;
|
||||
app->fnc.auth = NULL;
|
||||
|
@ -1095,9 +1095,9 @@ get_public_key (app_t app, int keyno)
|
||||
{
|
||||
/* We may simply read the public key out of these cards. */
|
||||
err = iso7816_read_public_key
|
||||
(app->slot, (const unsigned char*)(keyno == 0? "\xB6" :
|
||||
keyno == 1? "\xB8" : "\xA4"),
|
||||
2,
|
||||
(app->slot, 0, (const unsigned char*)(keyno == 0? "\xB6" :
|
||||
keyno == 1? "\xB8" : "\xA4"), 2,
|
||||
0,
|
||||
&buffer, &buflen);
|
||||
if (err)
|
||||
{
|
||||
@ -2530,6 +2530,9 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
int keyno = atoi (keynostr);
|
||||
int force = (flags & 1);
|
||||
time_t start_at;
|
||||
int exmode;
|
||||
int le_value;
|
||||
unsigned int keybits;
|
||||
|
||||
if (keyno < 1 || keyno > 3)
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
@ -2550,22 +2553,44 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Because we send the key parameter back via status lines we need
|
||||
to put a limit on the max. allowed keysize. 2048 bit will
|
||||
already lead to a 527 byte long status line and thus a 4096 bit
|
||||
key would exceed the Assuan line length limit. */
|
||||
keybits = app->app_local->keyattr[keyno].n_bits;
|
||||
if (keybits > 3072)
|
||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||
|
||||
/* Prepare for key generation by verifying the Admin PIN. */
|
||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
#if 1
|
||||
/* Test whether we will need extended length mode. (1900 is an
|
||||
arbitrary length which for sure fits into a short apdu.) */
|
||||
if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
|
||||
{
|
||||
exmode = 1; /* Use extended length w/o a limit. */
|
||||
le_value = app->app_local->extcap.max_rsp_data;
|
||||
/* No need to check le_value because it comes from a 16 bit
|
||||
value and thus can't create an overflow on a 32 bit
|
||||
system. */
|
||||
}
|
||||
else
|
||||
{
|
||||
exmode = 0;
|
||||
le_value = 256; /* Use legacy value. */
|
||||
}
|
||||
|
||||
log_info (_("please wait while key is being generated ...\n"));
|
||||
start_at = time (NULL);
|
||||
rc = iso7816_generate_keypair
|
||||
#else
|
||||
# warning key generation temporary replaced by reading an existing key.
|
||||
rc = iso7816_read_public_key
|
||||
#endif
|
||||
(app->slot, (const unsigned char*)(keyno == 0? "\xB6" :
|
||||
keyno == 1? "\xB8" : "\xA4"),
|
||||
2,
|
||||
/* # warning key generation temporary replaced by reading an existing key. */
|
||||
/* rc = iso7816_read_public_key */
|
||||
(app->slot, exmode,
|
||||
(const unsigned char*)(keyno == 0? "\xB6" :
|
||||
keyno == 1? "\xB8" : "\xA4"), 2,
|
||||
le_value,
|
||||
&buffer, &buflen);
|
||||
if (rc)
|
||||
{
|
||||
@ -2575,6 +2600,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
}
|
||||
log_info (_("key generation completed (%d seconds)\n"),
|
||||
(int)(time (NULL) - start_at));
|
||||
|
||||
keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
|
||||
if (!keydata)
|
||||
{
|
||||
@ -2590,7 +2616,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
log_error (_("response does not contain the RSA modulus\n"));
|
||||
goto leave;
|
||||
}
|
||||
/* log_printhex ("RSA n:", m, mlen); */
|
||||
/* log_printhex ("RSA n:", m, mlen); */
|
||||
send_key_data (ctrl, "n", m, mlen);
|
||||
|
||||
e = find_tlv (keydata, keydatalen, 0x0082, &elen);
|
||||
@ -2600,7 +2626,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
||||
log_error (_("response does not contain the RSA public exponent\n"));
|
||||
goto leave;
|
||||
}
|
||||
/* log_printhex ("RSA e:", e, elen); */
|
||||
/* log_printhex ("RSA e:", e, elen); */
|
||||
send_key_data (ctrl, "e", e, elen);
|
||||
|
||||
created_at = createtime? createtime : gnupg_get_time ();
|
||||
@ -2995,6 +3021,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
const char *s;
|
||||
int n;
|
||||
const char *fpr = NULL;
|
||||
int exmode;
|
||||
|
||||
if (!keyidstr || !*keyidstr || !indatalen)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
@ -3030,7 +3057,7 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
the card. This is allows for a meaningful error message in case
|
||||
the key on the card has been replaced but the shadow information
|
||||
known to gpg was not updated. If there is no fingerprint, the
|
||||
decryption will won't produce the right plaintext anyway. */
|
||||
decryption won't produce the right plaintext anyway. */
|
||||
rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -3039,6 +3066,8 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
if (!rc)
|
||||
{
|
||||
size_t fixuplen;
|
||||
unsigned char *fixbuf = NULL;
|
||||
int padind = 0;
|
||||
|
||||
/* We might encounter a couple of leading zeroes in the
|
||||
cryptogram. Due to internal use of MPIs thease leading
|
||||
@ -3049,39 +3078,46 @@ do_decipher (app_t app, const char *keyidstr,
|
||||
probability anyway broken. */
|
||||
if (indatalen >= (128-16) && indatalen < 128) /* 1024 bit key. */
|
||||
fixuplen = 128 - indatalen;
|
||||
else if (indatalen >= (256-16) && indatalen < 256) /* 2048 bit key. */
|
||||
fixuplen = 256 - indatalen;
|
||||
else if (indatalen >= (192-16) && indatalen < 192) /* 1536 bit key. */
|
||||
fixuplen = 192 - indatalen;
|
||||
else if (indatalen >= (256-16) && indatalen < 256) /* 2048 bit key. */
|
||||
fixuplen = 256 - indatalen;
|
||||
else if (indatalen >= (384-16) && indatalen < 384) /* 3072 bit key. */
|
||||
fixuplen = 384 - indatalen;
|
||||
else
|
||||
fixuplen = 0;
|
||||
|
||||
if (fixuplen)
|
||||
{
|
||||
unsigned char *fixbuf;
|
||||
|
||||
/* While we have to prepend stuff anyway, we can also
|
||||
include the padding byte here so that iso1816_decipher
|
||||
does not need to do yet another data mangling. */
|
||||
does not need to do another data mangling. */
|
||||
fixuplen++;
|
||||
|
||||
fixbuf = xtrymalloc (fixuplen + indatalen);
|
||||
if (!fixbuf)
|
||||
rc = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
memset (fixbuf, 0, fixuplen);
|
||||
memcpy (fixbuf+fixuplen, indata, indatalen);
|
||||
rc = iso7816_decipher (app->slot, 0,
|
||||
fixbuf, fixuplen+indatalen, -1,
|
||||
indata = fixbuf;
|
||||
indatalen = fixuplen + indatalen;
|
||||
padind = -1; /* Already padded. */
|
||||
}
|
||||
|
||||
if (app->app_local->cardcap.ext_lc_le && indatalen > 254 )
|
||||
exmode = 1; /* Extended length w/o a limit. */
|
||||
else if (app->app_local->cardcap.cmd_chaining && indatalen > 254)
|
||||
exmode = -254; /* Command chaining with max. 254 bytes. */
|
||||
else
|
||||
exmode = 0;
|
||||
|
||||
rc = iso7816_decipher (app->slot, exmode,
|
||||
indata, indatalen, padind,
|
||||
outdata, outdatalen);
|
||||
xfree (fixbuf);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
rc = iso7816_decipher (app->slot, 0,
|
||||
indata, indatalen, 0,
|
||||
outdata, outdatalen);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,11 @@
|
||||
#endif /* This source not used by scdaemon. */
|
||||
|
||||
|
||||
#ifndef EAGAIN
|
||||
#define EAGAIN EWOULDBLOCK
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
enum {
|
||||
RDR_to_PC_NotifySlotChange= 0x50,
|
||||
@ -1811,6 +1816,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||
{
|
||||
int rc;
|
||||
size_t msglen;
|
||||
int eagain_retries = 0;
|
||||
|
||||
/* Fixme: The next line for the current Valgrind without support
|
||||
for USB IOCTLs. */
|
||||
@ -1824,7 +1830,13 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||
timeout);
|
||||
if (rc < 0)
|
||||
{
|
||||
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
||||
rc = errno;
|
||||
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (rc));
|
||||
if (rc == EAGAIN && eagain_retries++ < 5)
|
||||
{
|
||||
gnupg_sleep (1);
|
||||
goto retry;
|
||||
}
|
||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||
}
|
||||
*nread = msglen = rc;
|
||||
@ -1834,12 +1846,19 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||
rc = read (handle->dev_fd, buffer, length);
|
||||
if (rc < 0)
|
||||
{
|
||||
rc = errno;
|
||||
DEBUGOUT_2 ("read from %d failed: %s\n",
|
||||
handle->dev_fd, strerror (errno));
|
||||
handle->dev_fd, strerror (rc));
|
||||
if (rc == EAGAIN && eagain_retries++ < 5)
|
||||
{
|
||||
gnupg_sleep (1);
|
||||
goto retry;
|
||||
}
|
||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||
}
|
||||
*nread = msglen = rc;
|
||||
}
|
||||
eagain_retries = 0;
|
||||
|
||||
if (msglen < 10)
|
||||
{
|
||||
@ -1942,6 +1961,7 @@ abort_cmd (ccid_driver_t handle)
|
||||
/* Send the abort command to the control pipe. Note that we don't
|
||||
need to keep track of sent abort commands because there should
|
||||
never be another thread using the same slot concurrently. */
|
||||
handle->seqno--; /* Restore the last one sent. */
|
||||
seqno = (handle->seqno & 0xff);
|
||||
rc = usb_control_msg (handle->idev,
|
||||
0x21,/* bmRequestType: host-to-device,
|
||||
@ -1958,7 +1978,12 @@ abort_cmd (ccid_driver_t handle)
|
||||
}
|
||||
|
||||
/* Now send the abort command to the bulk out pipe using the same
|
||||
SEQNO and SLOT. */
|
||||
SEQNO and SLOT. Do this in a loop to so that all seqno are
|
||||
tried. */
|
||||
seqno--; /* Adjust for next increment. */
|
||||
do
|
||||
{
|
||||
seqno++;
|
||||
msg[0] = PC_to_RDR_Abort;
|
||||
msg[5] = 0; /* slot */
|
||||
msg[6] = seqno;
|
||||
@ -1967,7 +1992,6 @@ abort_cmd (ccid_driver_t handle)
|
||||
msg[9] = 0; /* RFU */
|
||||
msglen = 10;
|
||||
set_msg_len (msg, 0);
|
||||
handle->seqno++; /* Bumb up for the next use. */
|
||||
|
||||
rc = usb_bulk_write (handle->idev,
|
||||
handle->ep_bulk_out,
|
||||
@ -1976,16 +2000,14 @@ abort_cmd (ccid_driver_t handle)
|
||||
if (rc == msglen)
|
||||
rc = 0;
|
||||
else if (rc == -1)
|
||||
DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n", strerror (errno));
|
||||
DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n",
|
||||
strerror (errno));
|
||||
else
|
||||
DEBUGOUT_1 ("usb_bulk_write failed in abort_cmd: %d\n", rc);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Wait for the expected response. */
|
||||
do
|
||||
{
|
||||
rc = usb_bulk_read (handle->idev,
|
||||
handle->ep_bulk_in,
|
||||
(char*)msg, sizeof msg,
|
||||
@ -2017,6 +2039,7 @@ abort_cmd (ccid_driver_t handle)
|
||||
}
|
||||
while (msg[0] != RDR_to_PC_SlotStatus && msg[5] != 0 && msg[6] != seqno);
|
||||
|
||||
handle->seqno = seqno;
|
||||
DEBUGOUT ("sending abort sequence succeeded\n");
|
||||
|
||||
return 0;
|
||||
@ -2430,12 +2453,13 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
|
||||
size_t *nresp)
|
||||
{
|
||||
int rc;
|
||||
unsigned char send_buffer[10+261], recv_buffer[10+261];
|
||||
unsigned char send_buffer[10+261+300], recv_buffer[10+261+300];
|
||||
const unsigned char *apdu;
|
||||
size_t apdulen;
|
||||
unsigned char *msg;
|
||||
size_t msglen;
|
||||
unsigned char seqno;
|
||||
int bwi = 4;
|
||||
|
||||
msg = send_buffer;
|
||||
|
||||
@ -2452,7 +2476,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
|
||||
msg[0] = PC_to_RDR_XfrBlock;
|
||||
msg[5] = 0; /* slot */
|
||||
msg[6] = seqno = handle->seqno++;
|
||||
msg[7] = 4; /* bBWI */
|
||||
msg[7] = bwi; /* bBWI */
|
||||
msg[8] = 0; /* RFU */
|
||||
msg[9] = 0; /* RFU */
|
||||
memcpy (msg+10, apdu, apdulen);
|
||||
@ -3274,6 +3298,13 @@ main (int argc, char **argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static coid
|
||||
gnupg_sleep (int seconds)
|
||||
{
|
||||
sleep (seconds);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
|
||||
|
@ -605,9 +605,14 @@ iso7816_internal_authenticate (int slot,
|
||||
}
|
||||
|
||||
|
||||
/* LE is the expected return length. This is usually 0 except if
|
||||
extended length mode is used and more than 256 byte will be
|
||||
returned. In that case a value of -1 uses a large default
|
||||
(e.g. 4096 bytes), a value larger 256 used that value. */
|
||||
static gpg_error_t
|
||||
do_generate_keypair (int slot, int readonly,
|
||||
do_generate_keypair (int slot, int extended_mode, int readonly,
|
||||
const unsigned char *data, size_t datalen,
|
||||
int le,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
int sw;
|
||||
@ -617,9 +622,11 @@ do_generate_keypair (int slot, int readonly,
|
||||
*result = NULL;
|
||||
*resultlen = 0;
|
||||
|
||||
sw = apdu_send (slot, 0,
|
||||
sw = apdu_send_le (slot, extended_mode,
|
||||
0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
|
||||
datalen, (const char*)data, result, resultlen);
|
||||
datalen, (const char*)data,
|
||||
le >= 0 && le < 256? 256:le,
|
||||
result, resultlen);
|
||||
if (sw != SW_SUCCESS)
|
||||
{
|
||||
/* Make sure that pending buffers are released. */
|
||||
@ -634,20 +641,24 @@ do_generate_keypair (int slot, int readonly,
|
||||
|
||||
|
||||
gpg_error_t
|
||||
iso7816_generate_keypair (int slot,
|
||||
iso7816_generate_keypair (int slot, int extended_mode,
|
||||
const unsigned char *data, size_t datalen,
|
||||
int le,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
return do_generate_keypair (slot, 0, data, datalen, result, resultlen);
|
||||
return do_generate_keypair (slot, extended_mode, 0,
|
||||
data, datalen, le, result, resultlen);
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
iso7816_read_public_key (int slot,
|
||||
iso7816_read_public_key (int slot, int extended_mode,
|
||||
const unsigned char *data, size_t datalen,
|
||||
int le,
|
||||
unsigned char **result, size_t *resultlen)
|
||||
{
|
||||
return do_generate_keypair (slot, 1, data, datalen, result, resultlen);
|
||||
return do_generate_keypair (slot, extended_mode, 1,
|
||||
data, datalen, le, result, resultlen);
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,11 +103,13 @@ gpg_error_t iso7816_decipher (int slot, int extended_mode,
|
||||
gpg_error_t iso7816_internal_authenticate (int slot,
|
||||
const unsigned char *data, size_t datalen,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_generate_keypair (int slot,
|
||||
gpg_error_t iso7816_generate_keypair (int slot, int extended_mode,
|
||||
const unsigned char *data, size_t datalen,
|
||||
int le,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_read_public_key (int slot,
|
||||
gpg_error_t iso7816_read_public_key (int slot, int extended_mode,
|
||||
const unsigned char *data, size_t datalen,
|
||||
int le,
|
||||
unsigned char **result, size_t *resultlen);
|
||||
gpg_error_t iso7816_get_challenge (int slot,
|
||||
int length, unsigned char *buffer);
|
||||
|
Loading…
x
Reference in New Issue
Block a user