More support for Netkey cards.

Small changes to teh CCID driver.
Support 2048 bit OpenPGP cards.
This commit is contained in:
Werner Koch 2009-05-08 15:07:45 +00:00
parent 03aae15a56
commit eeca39ae50
9 changed files with 375 additions and 99 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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");
@ -1156,9 +1238,40 @@ switch_application (app_t app, int enable_sigg)
err = iso7816_select_application (app->slot, aid_sigg, sizeof aid_sigg, 0);
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->sigg_active = enable_sigg;
{
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;

View File

@ -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
{
memset (fixbuf, 0, fixuplen);
memcpy (fixbuf+fixuplen, indata, indatalen);
rc = iso7816_decipher (app->slot, 0,
fixbuf, fixuplen+indatalen, -1,
outdata, outdatalen);
xfree (fixbuf);
}
return gpg_error_from_syserror ();
memset (fixbuf, 0, fixuplen);
memcpy (fixbuf+fixuplen, indata, indatalen);
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
rc = iso7816_decipher (app->slot, 0,
indata, indatalen, 0,
outdata, outdatalen);
exmode = 0;
rc = iso7816_decipher (app->slot, exmode,
indata, indatalen, padind,
outdata, outdatalen);
xfree (fixbuf);
}
return rc;
}

View File

@ -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,34 +1978,36 @@ abort_cmd (ccid_driver_t handle)
}
/* Now send the abort command to the bulk out pipe using the same
SEQNO and SLOT. */
msg[0] = PC_to_RDR_Abort;
msg[5] = 0; /* slot */
msg[6] = seqno;
msg[7] = 0; /* RFU */
msg[8] = 0; /* RFU */
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,
(char*)msg, msglen,
5000 /* ms timeout */);
if (rc == msglen)
rc = 0;
else if (rc == -1)
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. */
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;
msg[7] = 0; /* RFU */
msg[8] = 0; /* RFU */
msg[9] = 0; /* RFU */
msglen = 10;
set_msg_len (msg, 0);
rc = usb_bulk_write (handle->idev,
handle->ep_bulk_out,
(char*)msg, msglen,
5000 /* ms timeout */);
if (rc == msglen)
rc = 0;
else if (rc == -1)
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;
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;
@ -2448,11 +2472,11 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
extended APDU exchange level is not yet supported. */
if (apdulen > 261)
return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
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"

View File

@ -605,10 +605,15 @@ 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,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen)
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,
0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
datalen, (const char*)data, result, resultlen);
sw = apdu_send_le (slot, extended_mode,
0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
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,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen)
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);
}

View File

@ -103,12 +103,14 @@ 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,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_read_public_key (int slot,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen);
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, 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);