mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Implement decryption for TCOS 3 cards.
This commit is contained in:
parent
990585ad7d
commit
98e1a75e20
5
TODO
5
TODO
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
192
scd/apdu.c
192
scd/apdu.c
@ -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;
|
||||
|
||||
|
10
scd/apdu.h
10
scd/apdu.h
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
@ -550,14 +552,16 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
|
||||
|
||||
*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,
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user