Implement decryption for TCOS 3 cards.

This commit is contained in:
Werner Koch 2009-03-30 12:46:06 +00:00
parent 990585ad7d
commit 98e1a75e20
13 changed files with 277 additions and 121 deletions

5
TODO
View File

@ -23,7 +23,10 @@
** mark all unimplemented commands and options.
** Implement --default-key
** support the anyPolicy semantic
** Should we prefer nonRepudiation certs over plain signing certs?
Also: Do we need a way to allow the selection of a qualSig cert
over a plain one? The background is that the Telesec cards have 3
certs capable of signing all with the same subject name.
* sm/keydb.c
** Check file permissions

View File

@ -1,3 +1,7 @@
2009-03-27 Werner Koch <wk@g10code.com>
* learncard.c (agent_handle_learn): Add new certtype 111.
2009-03-26 Werner Koch <wk@g10code.com>
* agent.h (MAX_DIGEST_LEN): Change to 64.

View File

@ -298,10 +298,12 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
char *p;
int i;
static int certtype_list[] = {
111, /* Root CA */
101, /* trusted */
102, /* useful */
100, /* regular */
/* We don't include 110 here because gpgsm can't handle it. */
/* We don't include 110 here because gpgsm can't handle that
special root CA format. */
-1 /* end of list */
};

View File

@ -1,3 +1,16 @@
2009-03-30 Werner Koch <wk@g10code.com>
* app-nks.c (do_decipher): Make it work for TCOS 3.
* iso7816.c (iso7816_decipher): Add arg EXTENDED_MODE.
* apdu.c (apdu_send): Add arg EXTENDED_MODE and change all callers.
(apdu_send_le): Ditto.
(apdu_send_direct): Ditto, but not yet functional.
(send_le): Fix command chaining. Implement extended length option.
* ccid-driver.c (ccid_transceive): Remove restriction on apdu length.
(struct ccid_driver_s): Add field IFSC.
(ccid_get_atr): Set IFSC.
(ccid_transceive): Use negotiated IFSC and support S(IFS) command.
2009-03-26 Werner Koch <wk@g10code.com>
* command.c (cmd_pksign): Allow more hash algorithms.

View File

@ -414,6 +414,7 @@ apdu_strerror (int rc)
case SW_FILE_NOT_FOUND : return "file not found";
case SW_RECORD_NOT_FOUND:return "record not found";
case SW_REF_NOT_FOUND : return "reference not found";
case SW_BAD_LC : return "bad Lc";
case SW_BAD_P0_P1 : return "bad P0 or P1";
case SW_INS_NOT_SUP : return "instruction not supported";
case SW_CLA_NOT_SUP : return "class not supported";
@ -2806,14 +2807,18 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
/* Core APDU tranceiver function. Parameters are described at
apdu_send_le with the exception of PININFO which indicates keypad
related operations if not NULL. If EXTENDED_MODE is not NULL
related operations if not NULL. If EXTENDED_MODE is not 0
command chaining or extended length will be used according to these
values:
n < 0 := Use command chaining with the data part limited to -n
in each chunk. If -1 is used a default value is used.
n == 0 := No extended mode or command chaining.
n == 1 := Use extended length for input and output without a
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,
@ -2825,12 +2830,16 @@ send_le (int slot, int class, int ins, int p0, int p1,
unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
the driver. */
size_t resultlen;
unsigned char apdu[5+256+1];
unsigned char short_apdu_buffer[5+256+1];
unsigned char *apdu_buffer = NULL;
size_t apdu_buffer_size;
unsigned char *apdu;
size_t apdulen;
int sw;
long rc; /* We need a long here due to PC/SC. */
int did_exact_length_hack = 0;
int use_chaining = 0;
int use_extended_length = 0;
int lc_chunk;
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
@ -2847,7 +2856,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
if (!extended_mode)
return SW_WRONG_LENGTH; /* No way to send such an APDU. */
else if (extended_mode > 0)
return SW_HOST_NOT_SUPPORTED; /* FIXME. */
use_extended_length = 1;
else if (extended_mode < 0)
{
/* Send APDU using chaining mode. */
@ -2861,51 +2870,99 @@ send_le (int slot, int class, int ins, int p0, int p1,
else
return SW_HOST_INV_VALUE;
}
else if (lc == -1 && extended_mode > 0)
use_extended_length = 1;
if (le != -1 && (le > 256 || le < 0))
return SW_WRONG_LENGTH;
if ((!data && lc != -1) || (data && lc == -1))
return SW_HOST_INV_VALUE;
if (use_extended_length)
{
if (reader_table[slot].is_t0)
return SW_HOST_NOT_SUPPORTED;
/* 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);
if (!apdu_buffer)
return SW_HOST_OUT_OF_CORE;
apdu = apdu_buffer;
}
else
{
apdu_buffer_size = sizeof short_apdu_buffer;
apdu = short_apdu_buffer;
}
if ((sw = lock_slot (slot)))
return sw;
do
{
apdulen = 0;
apdu[apdulen] = class;
if (use_chaining && lc > 255)
if (use_extended_length)
{
apdu[apdulen] |= 0x10;
assert (use_chaining < 256);
lc_chunk = use_chaining;
lc -= use_chaining;
use_chaining = 0;
apdulen = 0;
apdu[apdulen++] = class;
apdu[apdulen++] = ins;
apdu[apdulen++] = p0;
apdu[apdulen++] = p1;
apdu[apdulen++] = 0; /* Z byte: Extended length marker. */
if (lc >= 0)
{
apdu[apdulen++] = ((lc >> 8) & 0xff);
apdu[apdulen++] = (lc & 0xff);
memcpy (apdu+apdulen, data, lc);
data += lc;
apdulen += lc;
}
if (le != -1)
{
apdu[apdulen++] = ((le >> 8) & 0xff);
apdu[apdulen++] = (le & 0xff);
}
}
else
{
use_chaining = 0;
lc_chunk = lc;
apdulen = 0;
apdu[apdulen] = class;
if (use_chaining && lc > 255)
{
apdu[apdulen] |= 0x10;
assert (use_chaining < 256);
lc_chunk = use_chaining;
lc -= use_chaining;
}
else
{
use_chaining = 0;
lc_chunk = lc;
}
apdulen++;
apdu[apdulen++] = ins;
apdu[apdulen++] = p0;
apdu[apdulen++] = p1;
if (lc_chunk != -1)
{
apdu[apdulen++] = lc_chunk;
memcpy (apdu+apdulen, data, lc_chunk);
data += lc_chunk;
apdulen += lc_chunk;
/* T=0 does not allow the use of Lc together with Le;
thus disable Le in this case. */
if (reader_table[slot].is_t0)
le = -1;
}
if (le != -1 && !use_chaining)
apdu[apdulen++] = le; /* Truncation is okay (0 means 256). */
}
apdulen++;
apdu[apdulen++] = ins;
apdu[apdulen++] = p0;
apdu[apdulen++] = p1;
if (lc_chunk != -1)
{
apdu[apdulen++] = lc_chunk;
memcpy (apdu+apdulen, data, lc_chunk);
data += lc_chunk;
apdulen += lc_chunk;
/* T=0 does not allow the use of Lc together with Le; thus
disable Le in this case. */
if (reader_table[slot].is_t0)
le = -1;
}
if (le != -1)
apdu[apdulen++] = le; /* Truncation is okay because 0 means 256. */
/* As safeguard don't pass any garbage from the stack to the driver. */
assert (sizeof (apdu) >= apdulen);
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
exact_length_hack:
/* 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;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
if (rc || resultlen < 2)
@ -2916,7 +2973,8 @@ send_le (int slot, int class, int ins, int p0, int p1,
return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
}
sw = (result[resultlen-2] << 8) | result[resultlen-1];
if (!did_exact_length_hack && SW_EXACT_LENGTH_P (sw))
if (!use_extended_length
&& !did_exact_length_hack && SW_EXACT_LENGTH_P (sw))
{
apdu[apdulen-1] = (sw & 0x00ff);
did_exact_length_hack = 1;
@ -2925,6 +2983,13 @@ send_le (int slot, int class, int ins, int p0, int p1,
}
while (use_chaining && sw == SW_SUCCESS);
if (apdu_buffer)
{
xfree (apdu_buffer);
apdu_buffer = NULL;
apdu_buffer_size = 0;
}
/* Store away the returned data but strip the statusword. */
resultlen -= 2;
if (DBG_CARD_IO)
@ -2976,13 +3041,16 @@ send_le (int slot, int class, int ins, int p0, int p1,
if (DBG_CARD_IO)
log_debug ("apdu_send_simple(%d): %d more bytes available\n",
slot, len);
apdu_buffer_size = sizeof short_apdu_buffer;
apdu = short_apdu_buffer;
apdulen = 0;
apdu[apdulen++] = class;
apdu[apdulen++] = 0xC0;
apdu[apdulen++] = 0;
apdu[apdulen++] = 0;
apdu[apdulen++] = len;
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
assert (apdulen <= apdu_buffer_size);
memset (apdu+apdulen, 0, apdu_buffer_size - apdulen);
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
if (rc || resultlen < 2)
@ -3052,47 +3120,52 @@ send_le (int slot, int class, int ins, int p0, int p1,
/* Send an APDU to the card in SLOT. The APDU is created from all
given parameters: CLASS, INS, P0, P1, LC, DATA, LE. A value of -1
for LC won't sent this field and the data field; in this case DATA
must also be passed as NULL. The return value is the status word
or -1 for an invalid SLOT or other non card related error. If
RETBUF is not NULL, it will receive an allocated buffer with the
returned data. The length of that data will be put into
*RETBUFLEN. The caller is reponsible for releasing the buffer even
in case of errors. */
must also be passed as NULL. If EXTENDED_MODE is not 0 command
chaining or extended length will be used; see send_le for details.
The return value is the status word or -1 for an invalid SLOT or
other non card related error. If RETBUF is not NULL, it will
receive an allocated buffer with the returned data. The length of
that data will be put into *RETBUFLEN. The caller is reponsible
for releasing the buffer even in case of errors. */
int
apdu_send_le(int slot, int class, int ins, int p0, int p1,
apdu_send_le(int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen)
{
return send_le (slot, class, ins, p0, p1,
lc, data, le,
retbuf, retbuflen,
NULL, 0);
NULL, extended_mode);
}
/* Send an APDU to the card in SLOT. The APDU is created from all
given parameters: CLASS, INS, P0, P1, LC, DATA. A value of -1 for
LC won't sent this field and the data field; in this case DATA must
also be passed as NULL. The return value is the status word or -1
for an invalid SLOT or other non card related error. If RETBUF is
not NULL, it will receive an allocated buffer with the returned
data. The length of that data will be put into *RETBUFLEN. The
caller is reponsible for releasing the buffer even in case of
errors. */
also be passed as NULL. If EXTENDED_MODE is not 0 command chaining
or extended length will be used; see send_le for details. The
return value is the status word or -1 for an invalid SLOT or other
non card related error. If RETBUF is not NULL, it will receive an
allocated buffer with the returned data. The length of that data
will be put into *RETBUFLEN. The caller is reponsible for
releasing the buffer even in case of errors. */
int
apdu_send (int slot, int class, int ins, int p0, int p1,
apdu_send (int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
{
return send_le (slot, class, ins, p0, p1, lc, data, 256,
retbuf, retbuflen, NULL, 0);
retbuf, retbuflen, NULL, extended_mode);
}
/* Send an APDU to the card in SLOT. The APDU is created from all
given parameters: CLASS, INS, P0, P1, LC, DATA. A value of -1 for
LC won't sent this field and the data field; in this case DATA must
also be passed as NULL. The return value is the status word or -1
for an invalid SLOT or other non card related error. No data will be
returned. */
also be passed as NULL. If EXTENDED_MODE is not 0 command chaining
or extended length will be used; see send_le for details. The
return value is the status word or -1 for an invalid SLOT or other
non card related error. No data will be returned. */
int
apdu_send_simple (int slot, int extended_mode,
int class, int ins, int p0, int p1,
@ -3126,11 +3199,13 @@ apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
and returns with an APDU including the status word. With
HANDLE_MORE set to true this function will handle the MORE DATA
status and return all APDUs concatenated with one status word at
the end. The function does not return a regular status word but 0
on success. If the slot is locked, the function returns
immediately with an error. */
the end. If EXTENDED_MODE is not 0 command chaining or extended
length will be used; see send_le for details. The function does
not return a regular status word but 0 on success. If the slot is
locked, the function returns immediately with an error. */
int
apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
apdu_send_direct (int slot, int extended_mode,
const unsigned char *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **retbuf, size_t *retbuflen)
{
@ -3147,6 +3222,9 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
if (extended_mode)
return SW_HOST_NOT_SUPPORTED; /* FIXME. */
if ((sw = trylock_slot (slot)))
return sw;

View File

@ -41,6 +41,7 @@ enum {
SW_NOT_SUPPORTED = 0x6a81,
SW_FILE_NOT_FOUND = 0x6a82,
SW_RECORD_NOT_FOUND = 0x6a83,
SW_BAD_LC = 0x6a87, /* Lc does not match command or p1/p2. */
SW_REF_NOT_FOUND = 0x6a88,
SW_BAD_P0_P1 = 0x6b00,
SW_EXACT_LENGTH = 0x6c00,
@ -117,13 +118,14 @@ int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int apdu_send (int slot, int extended_mode,
int class, int ins, int p0, int p1, int lc, const char *data,
unsigned char **retbuf, size_t *retbuflen);
int apdu_send_le (int slot, int class, int ins, int p0, int p1,
int apdu_send_le (int slot, int extended_mode,
int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen);
int apdu_send_direct (int slot,
int apdu_send_direct (int slot, int extended_mode,
const unsigned char *apdudata, size_t apdudatalen,
int handle_more,
unsigned char **retbuf, size_t *retbuflen);

View File

@ -121,8 +121,7 @@ app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff)
if ( !(class == CLASS_UNIVERSAL && constructed
&& (tag == TAG_SEQUENCE || tag == TAG_SET)))
{
log_info ("contents of FID 0x%04X does not look like a certificate\n",
fid);
log_info ("data at FID 0x%04X does not look like a certificate\n", fid);
return 0;
}

View File

@ -22,8 +22,11 @@
- We are now targeting TCOS 3 cards and it may happen that there is
a regression towards TCOS 2 cards. Please report.
- The TKS3 AUT key is not used by our authentication command but
accessible via the decrypt command.
- The TKS3 AUT key is not used. It seems that it is only useful for
the internal authentication command and not accessible by other
applications. The key itself is in the encryption class but the
corresponding certificate has only the digitalSignature
capability.
- If required, we automagically switch between the NKS application
and the SigG application. This avoids to use the DINSIG
@ -70,9 +73,7 @@ static struct
unsigned char kid; /* Corresponding key references. */
} filelist[] = {
{ 0, 0x4531, 0, 0, 0xC000, 1, 0, 0x80 }, /* EF_PK.NKS.SIG */
{ 1, 0x4531, 3, 0, 0x0000, 1, 1, 0x84 }, /* EF_PK.CH.SIG */
{ 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */
{ 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */
{ 0, 0x4331, 0, 100 },
{ 0, 0x4332, 0, 100 },
{ 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
@ -80,11 +81,15 @@ static struct
{ 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
{ 0, 0x43B1, 0, 100 },
{ 0, 0x43B2, 0, 100 },
{ 0, 0x4571, 3, 0, 0xc500, 0, 0, 0x82 }, /* EF_PK.NKS.AUT */
{ 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */
/* The authentication key is not used. */
/* { 0, 0x4571, 3, 0, 0xC500, 0, 0, 0x82 }, /\* EF_PK.NKS.AUT *\/ */
/* { 0, 0xC500, 3, 101 }, /\* EF_C.NKS.AUT *\/ */
{ 0, 0x45B2, 3, 0, 0xC201, 0, 1, 0x83 }, /* EF_PK.NKS.ENC1024 */
{ 0, 0xC201, 3, 101 }, /* EF_C.NKS.ENC1024 */
/* { 1, 0xB000, 3, ... */
{ 1, 0x4531, 3, 0, 0xC000, 1, 1, 0x84 }, /* EF_PK.CH.SIG */
{ 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */
{ 1, 0xC008, 3, 101 }, /* EF_C.CA.SIG */
{ 1, 0xC00E, 3, 111 }, /* EF_C.RCA.SIG */
{ 0, 0 }
};
@ -249,7 +254,7 @@ get_chv_status (app_t app, int sigg, int pwid)
command[2] = 0x00;
command[3] = pwid;
if (apdu_send_direct (app->slot, command, 4, 0, &result, &resultlen))
if (apdu_send_direct (app->slot, 0, command, 4, 0, &result, &resultlen))
rc = -1; /* Error. */
else if (resultlen < 2)
rc = -1; /* Error. */
@ -808,13 +813,10 @@ do_decipher (app_t app, const char *keyidstr,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen )
{
static const unsigned char mse_parm[] = {
0x80, 1, 0x10, /* Select algorithm RSA. */
0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
};
int rc, i;
int is_sigg = 0;
int fid;
int kid;
if (!keyidstr || !*keyidstr || !indatalen)
return gpg_error (GPG_ERR_INV_VALUE);
@ -847,15 +849,40 @@ do_decipher (app_t app, const char *keyidstr,
return gpg_error (GPG_ERR_NOT_FOUND);
if (!filelist[i].isenckey)
return gpg_error (GPG_ERR_INV_ID);
kid = filelist[i].kid;
if (app->app_local->nks_version > 2)
{
unsigned char mse[6];
mse[0] = 0x80; /* Algorithm reference. */
mse[1] = 1;
mse[2] = 0x0a; /* RSA no padding. (0x1A is pkcs#1.5 padding.) */
mse[3] = 0x84; /* Private key reference. */
mse[4] = 1;
mse[5] = kid;
rc = iso7816_manage_security_env (app->slot, 0x41, 0xB8,
mse, sizeof mse);
}
else
{
static const unsigned char mse[] =
{
0x80, 1, 0x10, /* Select algorithm RSA. */
0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
};
rc = iso7816_manage_security_env (app->slot, 0xC1, 0xB8,
mse, sizeof mse);
}
/* Do the TCOS specific MSE. */
rc = iso7816_manage_security_env (app->slot,
0xC1, 0xB8,
mse_parm, sizeof mse_parm);
if (!rc)
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
/* Note that we need to use extended length APDUs for TCOS 3 cards.
Command chaining does not work. */
if (!rc)
rc = iso7816_decipher (app->slot, indata, indatalen, 0x81,
rc = iso7816_decipher (app->slot, app->app_local->nks_version > 2? 1:0,
indata, indatalen, 0x81,
outdata, outdatalen);
return rc;
}

View File

@ -3066,14 +3066,16 @@ do_decipher (app_t app, const char *keyidstr,
{
memset (fixbuf, 0, fixuplen);
memcpy (fixbuf+fixuplen, indata, indatalen);
rc = iso7816_decipher (app->slot, fixbuf, fixuplen+indatalen, -1,
rc = iso7816_decipher (app->slot, 0,
fixbuf, fixuplen+indatalen, -1,
outdata, outdatalen);
xfree (fixbuf);
}
}
else
rc = iso7816_decipher (app->slot, indata, indatalen, 0,
rc = iso7816_decipher (app->slot, 0,
indata, indatalen, 0,
outdata, outdatalen);
}
return rc;

View File

@ -243,6 +243,7 @@ struct ccid_driver_s
int auto_ifsd;
int max_ifsd;
int ifsd;
int ifsc;
int powered_off;
int has_pinpad;
int apdu_level; /* Reader supports short APDU level exchange. */
@ -1840,7 +1841,6 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
*nread = msglen = rc;
}
if (msglen < 10)
{
DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
@ -1880,7 +1880,6 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
return CCID_DRIVER_ERR_INV_VALUE;
}
if (debug_level && (!no_debug || debug_level >= 3))
{
switch (buffer[0])
@ -2326,6 +2325,11 @@ ccid_get_atr (ccid_driver_t handle,
if (rc)
DEBUGOUT ("SetParameters failed (ignored)\n");
if (!rc && msglen > 15 && msg[15] >= 16 && msg[15] <= 254 )
handle->ifsc = msg[15];
else
handle->ifsc = 128; /* Something went wrong, assume 128 bytes. */
handle->t1_ns = 0;
handle->t1_nr = 0;
@ -2582,22 +2586,15 @@ ccid_transceive (ccid_driver_t handle,
assert (apdulen);
/* Construct an I-Block. */
/* Fixme: I am not sure whether limiting the length to 259
as per CCID spec is required. The code blow chops the
APDU anyway into 128 byte blocks. Needs to be addressed
when supporting extended length APDUs. */
if (apdulen > 259)
return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
tpdu = msg+10;
/* NAD: DAD=1, SAD=0 */
tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
if (apdulen > 128 /* fixme: replace by ifsc */)
if (apdulen > handle->ifsc )
{
apdulen = 128;
apdu_buf += 128;
apdu_buflen -= 128;
apdulen = handle->ifsc;
apdu_buf += handle->ifsc;
apdu_buflen -= handle->ifsc;
tpdu[1] |= (1 << 5); /* Set more bit. */
}
tpdu[2] = apdulen;
@ -2752,8 +2749,31 @@ ccid_transceive (ccid_driver_t handle,
DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n",
(tpdu[1] & 0x20)? "response": "request",
(tpdu[1] & 0x1f));
if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
{ /* Wait time extension request. */
if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 1 && tpdu[2] == 1)
{
/* Information field size request. */
unsigned char ifsc = tpdu[3];
if (ifsc < 16 || ifsc > 254)
return CCID_DRIVER_ERR_CARD_IO_ERROR;
msg = send_buffer;
tpdu = msg+10;
/* NAD: DAD=1, SAD=0 */
tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
tpdu[1] = (0xc0 | 0x20 | 1); /* S-block response */
tpdu[2] = 1;
tpdu[3] = ifsc;
tpdulen = 4;
edc = compute_edc (tpdu, tpdulen, use_crc);
if (use_crc)
tpdu[tpdulen++] = (edc >> 8);
tpdu[tpdulen++] = edc;
DEBUGOUT_1 ("T=1 requesting an ifsc=%d\n", ifsc);
}
else if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
{
/* Wait time extension request. */
unsigned char bwi = tpdu[3];
msg = send_buffer;
tpdu = msg+10;

View File

@ -596,7 +596,8 @@ cmd_serialno (assuan_context_t ctx, char *line)
100 := Regular X.509 cert
101 := Trusted X.509 cert
102 := Useful X.509 cert
110 := Root CA cert (e.g. DINSIG)
110 := Root CA cert in a special format (e.g. DINSIG)
111 := Root CA cert as standard X509 cert.
For certain cards, more information will be returned:
@ -963,7 +964,7 @@ cmd_pksign (assuan_context_t ctx, char *line)
xfree (keyidstr);
if (rc)
{
log_error ("card_sign failed: %s\n", gpg_strerror (rc));
log_error ("app_sign failed: %s\n", gpg_strerror (rc));
}
else
{
@ -1013,7 +1014,7 @@ cmd_pkauth (assuan_context_t ctx, char *line)
xfree (keyidstr);
if (rc)
{
log_error ("app_auth_sign failed: %s\n", gpg_strerror (rc));
log_error ("app_auth failed: %s\n", gpg_strerror (rc));
}
else
{
@ -1057,7 +1058,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
xfree (keyidstr);
if (rc)
{
log_error ("card_create_signature failed: %s\n", gpg_strerror (rc));
log_error ("app_decipher failed: %s\n", gpg_strerror (rc));
}
else
{
@ -1821,7 +1822,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
unsigned char *result = NULL;
size_t resultlen;
rc = apdu_send_direct (ctrl->reader_slot, apdu, apdulen, handle_more,
rc = apdu_send_direct (ctrl->reader_slot, 0, apdu, apdulen, handle_more,
&result, &resultlen);
if (rc)
log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));

View File

@ -213,7 +213,7 @@ iso7816_list_directory (int slot, int list_dirs,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL,
sw = apdu_send (slot, 0, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL,
result, resultlen);
if (sw != SW_SUCCESS)
{
@ -244,7 +244,7 @@ iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
*result = NULL;
*resultlen = 0;
sw = apdu_send_direct (slot, apdudata, apdudatalen, handle_more,
sw = apdu_send_direct (slot, 0, apdudata, apdudatalen, handle_more,
result, resultlen);
if (!sw)
{
@ -430,7 +430,7 @@ iso7816_get_data (int slot, int tag,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_GET_DATA,
sw = apdu_send (slot, 0, 0x00, CMD_GET_DATA,
((tag >> 8) & 0xff), (tag & 0xff), -1, NULL,
result, resultlen);
if (sw != SW_SUCCESS)
@ -462,7 +462,7 @@ iso7816_put_data (int slot, int extended_mode, int tag,
return map_sw (sw);
}
/* Same as iso7816_put_data but uses an odd instrcution byte. */
/* Same as iso7816_put_data but uses an odd instruction byte. */
gpg_error_t
iso7816_put_data_odd (int slot, int extended_mode, int tag,
const unsigned char *data, size_t datalen)
@ -509,7 +509,8 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data,
sw = apdu_send (slot, 0,
0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data,
result, resultlen);
if (sw != SW_SUCCESS)
{
@ -530,7 +531,8 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
and the plaintext is available in a newly allocated buffer stored
at RESULT with its length stored at RESULTLEN. */
gpg_error_t
iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
iso7816_decipher (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int padind, unsigned char **result, size_t *resultlen)
{
int sw;
@ -547,17 +549,19 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
buf = xtrymalloc (datalen + 1);
if (!buf)
return gpg_error (gpg_err_code_from_errno (errno));
*buf = padind; /* Padding indicator. */
memcpy (buf+1, data, datalen);
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
sw = apdu_send (slot, extended_mode,
0x00, CMD_PSO, 0x80, 0x86,
datalen+1, (char*)buf,
result, resultlen);
xfree (buf);
}
else
{
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
sw = apdu_send (slot, extended_mode,
0x00, CMD_PSO, 0x80, 0x86,
datalen, (const char *)data,
result, resultlen);
}
@ -586,7 +590,7 @@ iso7816_internal_authenticate (int slot,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
sw = apdu_send (slot, 0, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
datalen, (const char*)data, result, resultlen);
if (sw != SW_SUCCESS)
{
@ -613,7 +617,8 @@ do_generate_keypair (int slot, int readonly,
*result = NULL;
*resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
sw = apdu_send (slot, 0,
0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
datalen, (const char*)data, result, resultlen);
if (sw != SW_SUCCESS)
{
@ -661,8 +666,8 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer)
{
result = NULL;
n = length > 254? 254 : length;
sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
n,
sw = apdu_send_le (slot, 0,
0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL, n,
&result, &resultlen);
if (sw != SW_SUCCESS)
{
@ -711,13 +716,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
buffer = NULL;
bufferlen = 0;
n = read_all? 0 : nmax;
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
if ( SW_EXACT_LENGTH_P(sw) )
{
n = (sw & 0x00ff);
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
}
@ -804,7 +809,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
buffer = NULL;
bufferlen = 0;
sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_RECORD,
recno,
short_ef? short_ef : 0x04,
-1, NULL,

View File

@ -96,7 +96,7 @@ gpg_error_t iso7816_manage_security_env (int slot, int p1, int p2,
gpg_error_t iso7816_compute_ds (int slot,
const unsigned char *data, size_t datalen,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_decipher (int slot,
gpg_error_t iso7816_decipher (int slot, int extended_mode,
const unsigned char *data, size_t datalen,
int padind,
unsigned char **result, size_t *resultlen);