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.
|
** mark all unimplemented commands and options.
|
||||||
** Implement --default-key
|
** Implement --default-key
|
||||||
** support the anyPolicy semantic
|
** 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
|
* sm/keydb.c
|
||||||
** Check file permissions
|
** 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>
|
2009-03-26 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* agent.h (MAX_DIGEST_LEN): Change to 64.
|
* agent.h (MAX_DIGEST_LEN): Change to 64.
|
||||||
|
@ -298,10 +298,12 @@ agent_handle_learn (ctrl_t ctrl, void *assuan_context)
|
|||||||
char *p;
|
char *p;
|
||||||
int i;
|
int i;
|
||||||
static int certtype_list[] = {
|
static int certtype_list[] = {
|
||||||
|
111, /* Root CA */
|
||||||
101, /* trusted */
|
101, /* trusted */
|
||||||
102, /* useful */
|
102, /* useful */
|
||||||
100, /* regular */
|
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 /* 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>
|
2009-03-26 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* command.c (cmd_pksign): Allow more hash algorithms.
|
* 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_FILE_NOT_FOUND : return "file not found";
|
||||||
case SW_RECORD_NOT_FOUND:return "record not found";
|
case SW_RECORD_NOT_FOUND:return "record not found";
|
||||||
case SW_REF_NOT_FOUND : return "reference 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_BAD_P0_P1 : return "bad P0 or P1";
|
||||||
case SW_INS_NOT_SUP : return "instruction not supported";
|
case SW_INS_NOT_SUP : return "instruction not supported";
|
||||||
case SW_CLA_NOT_SUP : return "class 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
|
/* Core APDU tranceiver function. Parameters are described at
|
||||||
apdu_send_le with the exception of PININFO which indicates keypad
|
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
|
command chaining or extended length will be used according to these
|
||||||
values:
|
values:
|
||||||
n < 0 := Use command chaining with the data part limited to -n
|
n < 0 := Use command chaining with the data part limited to -n
|
||||||
in each chunk. If -1 is used a default value is used.
|
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
|
n == 1 := Use extended length for input and output without a
|
||||||
length limit.
|
length limit.
|
||||||
n > 1 := Use extended length with up to N bytes.
|
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
|
static int
|
||||||
send_le (int slot, int class, int ins, int p0, int p1,
|
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
|
unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
|
||||||
the driver. */
|
the driver. */
|
||||||
size_t resultlen;
|
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;
|
size_t apdulen;
|
||||||
int sw;
|
int sw;
|
||||||
long rc; /* We need a long here due to PC/SC. */
|
long rc; /* We need a long here due to PC/SC. */
|
||||||
int did_exact_length_hack = 0;
|
int did_exact_length_hack = 0;
|
||||||
int use_chaining = 0;
|
int use_chaining = 0;
|
||||||
|
int use_extended_length = 0;
|
||||||
int lc_chunk;
|
int lc_chunk;
|
||||||
|
|
||||||
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
|
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)
|
if (!extended_mode)
|
||||||
return SW_WRONG_LENGTH; /* No way to send such an APDU. */
|
return SW_WRONG_LENGTH; /* No way to send such an APDU. */
|
||||||
else if (extended_mode > 0)
|
else if (extended_mode > 0)
|
||||||
return SW_HOST_NOT_SUPPORTED; /* FIXME. */
|
use_extended_length = 1;
|
||||||
else if (extended_mode < 0)
|
else if (extended_mode < 0)
|
||||||
{
|
{
|
||||||
/* Send APDU using chaining mode. */
|
/* Send APDU using chaining mode. */
|
||||||
@ -2861,51 +2870,99 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
|||||||
else
|
else
|
||||||
return SW_HOST_INV_VALUE;
|
return SW_HOST_INV_VALUE;
|
||||||
}
|
}
|
||||||
|
else if (lc == -1 && extended_mode > 0)
|
||||||
|
use_extended_length = 1;
|
||||||
|
|
||||||
if (le != -1 && (le > 256 || le < 0))
|
if (le != -1 && (le > 256 || le < 0))
|
||||||
return SW_WRONG_LENGTH;
|
return SW_WRONG_LENGTH;
|
||||||
if ((!data && lc != -1) || (data && lc == -1))
|
if ((!data && lc != -1) || (data && lc == -1))
|
||||||
return SW_HOST_INV_VALUE;
|
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)))
|
if ((sw = lock_slot (slot)))
|
||||||
return sw;
|
return sw;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
apdulen = 0;
|
if (use_extended_length)
|
||||||
apdu[apdulen] = class;
|
|
||||||
if (use_chaining && lc > 255)
|
|
||||||
{
|
{
|
||||||
apdu[apdulen] |= 0x10;
|
use_chaining = 0;
|
||||||
assert (use_chaining < 256);
|
apdulen = 0;
|
||||||
lc_chunk = use_chaining;
|
apdu[apdulen++] = class;
|
||||||
lc -= use_chaining;
|
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
|
else
|
||||||
{
|
{
|
||||||
use_chaining = 0;
|
apdulen = 0;
|
||||||
lc_chunk = lc;
|
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:
|
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;
|
resultlen = RESULTLEN;
|
||||||
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
|
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
|
||||||
if (rc || resultlen < 2)
|
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;
|
return rc? rc : SW_HOST_INCOMPLETE_CARD_RESPONSE;
|
||||||
}
|
}
|
||||||
sw = (result[resultlen-2] << 8) | result[resultlen-1];
|
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);
|
apdu[apdulen-1] = (sw & 0x00ff);
|
||||||
did_exact_length_hack = 1;
|
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);
|
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. */
|
/* Store away the returned data but strip the statusword. */
|
||||||
resultlen -= 2;
|
resultlen -= 2;
|
||||||
if (DBG_CARD_IO)
|
if (DBG_CARD_IO)
|
||||||
@ -2976,13 +3041,16 @@ send_le (int slot, int class, int ins, int p0, int p1,
|
|||||||
if (DBG_CARD_IO)
|
if (DBG_CARD_IO)
|
||||||
log_debug ("apdu_send_simple(%d): %d more bytes available\n",
|
log_debug ("apdu_send_simple(%d): %d more bytes available\n",
|
||||||
slot, len);
|
slot, len);
|
||||||
|
apdu_buffer_size = sizeof short_apdu_buffer;
|
||||||
|
apdu = short_apdu_buffer;
|
||||||
apdulen = 0;
|
apdulen = 0;
|
||||||
apdu[apdulen++] = class;
|
apdu[apdulen++] = class;
|
||||||
apdu[apdulen++] = 0xC0;
|
apdu[apdulen++] = 0xC0;
|
||||||
apdu[apdulen++] = 0;
|
apdu[apdulen++] = 0;
|
||||||
apdu[apdulen++] = 0;
|
apdu[apdulen++] = 0;
|
||||||
apdu[apdulen++] = len;
|
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;
|
resultlen = RESULTLEN;
|
||||||
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
|
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
|
||||||
if (rc || resultlen < 2)
|
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
|
/* 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
|
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
|
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
|
must also be passed as NULL. If EXTENDED_MODE is not 0 command
|
||||||
or -1 for an invalid SLOT or other non card related error. If
|
chaining or extended length will be used; see send_le for details.
|
||||||
RETBUF is not NULL, it will receive an allocated buffer with the
|
The return value is the status word or -1 for an invalid SLOT or
|
||||||
returned data. The length of that data will be put into
|
other non card related error. If RETBUF is not NULL, it will
|
||||||
*RETBUFLEN. The caller is reponsible for releasing the buffer even
|
receive an allocated buffer with the returned data. The length of
|
||||||
in case of errors. */
|
that data will be put into *RETBUFLEN. The caller is reponsible
|
||||||
|
for releasing the buffer even in case of errors. */
|
||||||
int
|
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,
|
int lc, const char *data, int le,
|
||||||
unsigned char **retbuf, size_t *retbuflen)
|
unsigned char **retbuf, size_t *retbuflen)
|
||||||
{
|
{
|
||||||
return send_le (slot, class, ins, p0, p1,
|
return send_le (slot, class, ins, p0, p1,
|
||||||
lc, data, le,
|
lc, data, le,
|
||||||
retbuf, retbuflen,
|
retbuf, retbuflen,
|
||||||
NULL, 0);
|
NULL, extended_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send an APDU to the card in SLOT. The APDU is created from all
|
/* 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
|
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
|
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
|
also be passed as NULL. If EXTENDED_MODE is not 0 command chaining
|
||||||
for an invalid SLOT or other non card related error. If RETBUF is
|
or extended length will be used; see send_le for details. The
|
||||||
not NULL, it will receive an allocated buffer with the returned
|
return value is the status word or -1 for an invalid SLOT or other
|
||||||
data. The length of that data will be put into *RETBUFLEN. The
|
non card related error. If RETBUF is not NULL, it will receive an
|
||||||
caller is reponsible for releasing the buffer even in case of
|
allocated buffer with the returned data. The length of that data
|
||||||
errors. */
|
will be put into *RETBUFLEN. The caller is reponsible for
|
||||||
|
releasing the buffer even in case of errors. */
|
||||||
int
|
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)
|
int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
|
||||||
{
|
{
|
||||||
return send_le (slot, class, ins, p0, p1, lc, data, 256,
|
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
|
/* 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
|
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
|
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
|
also be passed as NULL. If EXTENDED_MODE is not 0 command chaining
|
||||||
for an invalid SLOT or other non card related error. No data will be
|
or extended length will be used; see send_le for details. The
|
||||||
returned. */
|
return value is the status word or -1 for an invalid SLOT or other
|
||||||
|
non card related error. No data will be returned. */
|
||||||
int
|
int
|
||||||
apdu_send_simple (int slot, int extended_mode,
|
apdu_send_simple (int slot, int extended_mode,
|
||||||
int class, int ins, int p0, int p1,
|
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
|
and returns with an APDU including the status word. With
|
||||||
HANDLE_MORE set to true this function will handle the MORE DATA
|
HANDLE_MORE set to true this function will handle the MORE DATA
|
||||||
status and return all APDUs concatenated with one status word at
|
status and return all APDUs concatenated with one status word at
|
||||||
the end. The function does not return a regular status word but 0
|
the end. If EXTENDED_MODE is not 0 command chaining or extended
|
||||||
on success. If the slot is locked, the function returns
|
length will be used; see send_le for details. The function does
|
||||||
immediately with an error. */
|
not return a regular status word but 0 on success. If the slot is
|
||||||
|
locked, the function returns immediately with an error. */
|
||||||
int
|
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,
|
int handle_more,
|
||||||
unsigned char **retbuf, size_t *retbuflen)
|
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 )
|
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
|
||||||
return SW_HOST_NO_DRIVER;
|
return SW_HOST_NO_DRIVER;
|
||||||
|
|
||||||
|
if (extended_mode)
|
||||||
|
return SW_HOST_NOT_SUPPORTED; /* FIXME. */
|
||||||
|
|
||||||
if ((sw = trylock_slot (slot)))
|
if ((sw = trylock_slot (slot)))
|
||||||
return sw;
|
return sw;
|
||||||
|
|
||||||
|
10
scd/apdu.h
10
scd/apdu.h
@ -41,6 +41,7 @@ enum {
|
|||||||
SW_NOT_SUPPORTED = 0x6a81,
|
SW_NOT_SUPPORTED = 0x6a81,
|
||||||
SW_FILE_NOT_FOUND = 0x6a82,
|
SW_FILE_NOT_FOUND = 0x6a82,
|
||||||
SW_RECORD_NOT_FOUND = 0x6a83,
|
SW_RECORD_NOT_FOUND = 0x6a83,
|
||||||
|
SW_BAD_LC = 0x6a87, /* Lc does not match command or p1/p2. */
|
||||||
SW_REF_NOT_FOUND = 0x6a88,
|
SW_REF_NOT_FOUND = 0x6a88,
|
||||||
SW_BAD_P0_P1 = 0x6b00,
|
SW_BAD_P0_P1 = 0x6b00,
|
||||||
SW_EXACT_LENGTH = 0x6c00,
|
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 lc, const char *data,
|
||||||
int pin_mode,
|
int pin_mode,
|
||||||
int pinlen_min, int pinlen_max, int pin_padlen);
|
int pinlen_min, int pinlen_max, int pin_padlen);
|
||||||
int apdu_send (int slot, int class, int ins, int p0, int p1,
|
int apdu_send (int slot, int extended_mode,
|
||||||
int lc, const char *data,
|
int class, int ins, int p0, int p1, int lc, const char *data,
|
||||||
unsigned char **retbuf, size_t *retbuflen);
|
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,
|
int lc, const char *data, int le,
|
||||||
unsigned char **retbuf, size_t *retbuflen);
|
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,
|
const unsigned char *apdudata, size_t apdudatalen,
|
||||||
int handle_more,
|
int handle_more,
|
||||||
unsigned char **retbuf, size_t *retbuflen);
|
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
|
if ( !(class == CLASS_UNIVERSAL && constructed
|
||||||
&& (tag == TAG_SEQUENCE || tag == TAG_SET)))
|
&& (tag == TAG_SEQUENCE || tag == TAG_SET)))
|
||||||
{
|
{
|
||||||
log_info ("contents of FID 0x%04X does not look like a certificate\n",
|
log_info ("data at FID 0x%04X does not look like a certificate\n", fid);
|
||||||
fid);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,8 +22,11 @@
|
|||||||
- We are now targeting TCOS 3 cards and it may happen that there is
|
- We are now targeting TCOS 3 cards and it may happen that there is
|
||||||
a regression towards TCOS 2 cards. Please report.
|
a regression towards TCOS 2 cards. Please report.
|
||||||
|
|
||||||
- The TKS3 AUT key is not used by our authentication command but
|
- The TKS3 AUT key is not used. It seems that it is only useful for
|
||||||
accessible via the decrypt command.
|
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
|
- If required, we automagically switch between the NKS application
|
||||||
and the SigG application. This avoids to use the DINSIG
|
and the SigG application. This avoids to use the DINSIG
|
||||||
@ -70,9 +73,7 @@ static struct
|
|||||||
unsigned char kid; /* Corresponding key references. */
|
unsigned char kid; /* Corresponding key references. */
|
||||||
} filelist[] = {
|
} filelist[] = {
|
||||||
{ 0, 0x4531, 0, 0, 0xC000, 1, 0, 0x80 }, /* EF_PK.NKS.SIG */
|
{ 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 */
|
{ 0, 0xC000, 0, 101 }, /* EF_C.NKS.SIG */
|
||||||
{ 1, 0xC000, 0, 101 }, /* EF_C.CH.SIG */
|
|
||||||
{ 0, 0x4331, 0, 100 },
|
{ 0, 0x4331, 0, 100 },
|
||||||
{ 0, 0x4332, 0, 100 },
|
{ 0, 0x4332, 0, 100 },
|
||||||
{ 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
|
{ 0, 0xB000, 0, 110 }, /* EF_PK.RCA.NKS */
|
||||||
@ -80,11 +81,15 @@ static struct
|
|||||||
{ 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
|
{ 0, 0xC200, 0, 101 }, /* EF_C.NKS.ENC */
|
||||||
{ 0, 0x43B1, 0, 100 },
|
{ 0, 0x43B1, 0, 100 },
|
||||||
{ 0, 0x43B2, 0, 100 },
|
{ 0, 0x43B2, 0, 100 },
|
||||||
{ 0, 0x4571, 3, 0, 0xc500, 0, 0, 0x82 }, /* EF_PK.NKS.AUT */
|
/* The authentication key is not used. */
|
||||||
{ 0, 0xC500, 3, 101 }, /* EF_C.NKS.AUT */
|
/* { 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, 0x45B2, 3, 0, 0xC201, 0, 1, 0x83 }, /* EF_PK.NKS.ENC1024 */
|
||||||
{ 0, 0xC201, 3, 101 }, /* EF_C.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 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -249,7 +254,7 @@ get_chv_status (app_t app, int sigg, int pwid)
|
|||||||
command[2] = 0x00;
|
command[2] = 0x00;
|
||||||
command[3] = pwid;
|
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. */
|
rc = -1; /* Error. */
|
||||||
else if (resultlen < 2)
|
else if (resultlen < 2)
|
||||||
rc = -1; /* Error. */
|
rc = -1; /* Error. */
|
||||||
@ -808,13 +813,10 @@ do_decipher (app_t app, const char *keyidstr,
|
|||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen )
|
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 rc, i;
|
||||||
int is_sigg = 0;
|
int is_sigg = 0;
|
||||||
int fid;
|
int fid;
|
||||||
|
int kid;
|
||||||
|
|
||||||
if (!keyidstr || !*keyidstr || !indatalen)
|
if (!keyidstr || !*keyidstr || !indatalen)
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
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);
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
if (!filelist[i].isenckey)
|
if (!filelist[i].isenckey)
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
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)
|
if (!rc)
|
||||||
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
|
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)
|
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);
|
outdata, outdatalen);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -3066,14 +3066,16 @@ do_decipher (app_t app, const char *keyidstr,
|
|||||||
{
|
{
|
||||||
memset (fixbuf, 0, fixuplen);
|
memset (fixbuf, 0, fixuplen);
|
||||||
memcpy (fixbuf+fixuplen, indata, indatalen);
|
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);
|
outdata, outdatalen);
|
||||||
xfree (fixbuf);
|
xfree (fixbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rc = iso7816_decipher (app->slot, indata, indatalen, 0,
|
rc = iso7816_decipher (app->slot, 0,
|
||||||
|
indata, indatalen, 0,
|
||||||
outdata, outdatalen);
|
outdata, outdatalen);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -243,6 +243,7 @@ struct ccid_driver_s
|
|||||||
int auto_ifsd;
|
int auto_ifsd;
|
||||||
int max_ifsd;
|
int max_ifsd;
|
||||||
int ifsd;
|
int ifsd;
|
||||||
|
int ifsc;
|
||||||
int powered_off;
|
int powered_off;
|
||||||
int has_pinpad;
|
int has_pinpad;
|
||||||
int apdu_level; /* Reader supports short APDU level exchange. */
|
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;
|
*nread = msglen = rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (msglen < 10)
|
if (msglen < 10)
|
||||||
{
|
{
|
||||||
DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
|
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;
|
return CCID_DRIVER_ERR_INV_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (debug_level && (!no_debug || debug_level >= 3))
|
if (debug_level && (!no_debug || debug_level >= 3))
|
||||||
{
|
{
|
||||||
switch (buffer[0])
|
switch (buffer[0])
|
||||||
@ -2326,6 +2325,11 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
if (rc)
|
if (rc)
|
||||||
DEBUGOUT ("SetParameters failed (ignored)\n");
|
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_ns = 0;
|
||||||
handle->t1_nr = 0;
|
handle->t1_nr = 0;
|
||||||
|
|
||||||
@ -2582,22 +2586,15 @@ ccid_transceive (ccid_driver_t handle,
|
|||||||
assert (apdulen);
|
assert (apdulen);
|
||||||
|
|
||||||
/* Construct an I-Block. */
|
/* 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;
|
tpdu = msg+10;
|
||||||
/* NAD: DAD=1, SAD=0 */
|
/* NAD: DAD=1, SAD=0 */
|
||||||
tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
|
tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
|
||||||
tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
|
tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
|
||||||
if (apdulen > 128 /* fixme: replace by ifsc */)
|
if (apdulen > handle->ifsc )
|
||||||
{
|
{
|
||||||
apdulen = 128;
|
apdulen = handle->ifsc;
|
||||||
apdu_buf += 128;
|
apdu_buf += handle->ifsc;
|
||||||
apdu_buflen -= 128;
|
apdu_buflen -= handle->ifsc;
|
||||||
tpdu[1] |= (1 << 5); /* Set more bit. */
|
tpdu[1] |= (1 << 5); /* Set more bit. */
|
||||||
}
|
}
|
||||||
tpdu[2] = apdulen;
|
tpdu[2] = apdulen;
|
||||||
@ -2752,8 +2749,31 @@ ccid_transceive (ccid_driver_t handle,
|
|||||||
DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n",
|
DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n",
|
||||||
(tpdu[1] & 0x20)? "response": "request",
|
(tpdu[1] & 0x20)? "response": "request",
|
||||||
(tpdu[1] & 0x1f));
|
(tpdu[1] & 0x1f));
|
||||||
if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
|
if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 1 && tpdu[2] == 1)
|
||||||
{ /* Wait time extension request. */
|
{
|
||||||
|
/* 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];
|
unsigned char bwi = tpdu[3];
|
||||||
msg = send_buffer;
|
msg = send_buffer;
|
||||||
tpdu = msg+10;
|
tpdu = msg+10;
|
||||||
|
@ -596,7 +596,8 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
|||||||
100 := Regular X.509 cert
|
100 := Regular X.509 cert
|
||||||
101 := Trusted X.509 cert
|
101 := Trusted X.509 cert
|
||||||
102 := Useful 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:
|
For certain cards, more information will be returned:
|
||||||
|
|
||||||
@ -963,7 +964,7 @@ cmd_pksign (assuan_context_t ctx, char *line)
|
|||||||
xfree (keyidstr);
|
xfree (keyidstr);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("card_sign failed: %s\n", gpg_strerror (rc));
|
log_error ("app_sign failed: %s\n", gpg_strerror (rc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1013,7 +1014,7 @@ cmd_pkauth (assuan_context_t ctx, char *line)
|
|||||||
xfree (keyidstr);
|
xfree (keyidstr);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("app_auth_sign failed: %s\n", gpg_strerror (rc));
|
log_error ("app_auth failed: %s\n", gpg_strerror (rc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1057,7 +1058,7 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
|
|||||||
xfree (keyidstr);
|
xfree (keyidstr);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("card_create_signature failed: %s\n", gpg_strerror (rc));
|
log_error ("app_decipher failed: %s\n", gpg_strerror (rc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1821,7 +1822,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
|
|||||||
unsigned char *result = NULL;
|
unsigned char *result = NULL;
|
||||||
size_t resultlen;
|
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);
|
&result, &resultlen);
|
||||||
if (rc)
|
if (rc)
|
||||||
log_error ("apdu_send_direct failed: %s\n", gpg_strerror (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;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*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);
|
result, resultlen);
|
||||||
if (sw != SW_SUCCESS)
|
if (sw != SW_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -244,7 +244,7 @@ iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
|
|||||||
*result = NULL;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*resultlen = 0;
|
||||||
|
|
||||||
sw = apdu_send_direct (slot, apdudata, apdudatalen, handle_more,
|
sw = apdu_send_direct (slot, 0, apdudata, apdudatalen, handle_more,
|
||||||
result, resultlen);
|
result, resultlen);
|
||||||
if (!sw)
|
if (!sw)
|
||||||
{
|
{
|
||||||
@ -430,7 +430,7 @@ iso7816_get_data (int slot, int tag,
|
|||||||
*result = NULL;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*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,
|
((tag >> 8) & 0xff), (tag & 0xff), -1, NULL,
|
||||||
result, resultlen);
|
result, resultlen);
|
||||||
if (sw != SW_SUCCESS)
|
if (sw != SW_SUCCESS)
|
||||||
@ -462,7 +462,7 @@ iso7816_put_data (int slot, int extended_mode, int tag,
|
|||||||
return map_sw (sw);
|
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
|
gpg_error_t
|
||||||
iso7816_put_data_odd (int slot, int extended_mode, int tag,
|
iso7816_put_data_odd (int slot, int extended_mode, int tag,
|
||||||
const unsigned char *data, size_t datalen)
|
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;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*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);
|
result, resultlen);
|
||||||
if (sw != SW_SUCCESS)
|
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
|
and the plaintext is available in a newly allocated buffer stored
|
||||||
at RESULT with its length stored at RESULTLEN. */
|
at RESULT with its length stored at RESULTLEN. */
|
||||||
gpg_error_t
|
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 padind, unsigned char **result, size_t *resultlen)
|
||||||
{
|
{
|
||||||
int sw;
|
int sw;
|
||||||
@ -550,14 +552,16 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
|
|||||||
|
|
||||||
*buf = padind; /* Padding indicator. */
|
*buf = padind; /* Padding indicator. */
|
||||||
memcpy (buf+1, data, datalen);
|
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,
|
datalen+1, (char*)buf,
|
||||||
result, resultlen);
|
result, resultlen);
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
}
|
}
|
||||||
else
|
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,
|
datalen, (const char *)data,
|
||||||
result, resultlen);
|
result, resultlen);
|
||||||
}
|
}
|
||||||
@ -586,7 +590,7 @@ iso7816_internal_authenticate (int slot,
|
|||||||
*result = NULL;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*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);
|
datalen, (const char*)data, result, resultlen);
|
||||||
if (sw != SW_SUCCESS)
|
if (sw != SW_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -613,7 +617,8 @@ do_generate_keypair (int slot, int readonly,
|
|||||||
*result = NULL;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*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);
|
datalen, (const char*)data, result, resultlen);
|
||||||
if (sw != SW_SUCCESS)
|
if (sw != SW_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -661,8 +666,8 @@ iso7816_get_challenge (int slot, int length, unsigned char *buffer)
|
|||||||
{
|
{
|
||||||
result = NULL;
|
result = NULL;
|
||||||
n = length > 254? 254 : length;
|
n = length > 254? 254 : length;
|
||||||
sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
|
sw = apdu_send_le (slot, 0,
|
||||||
n,
|
0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL, n,
|
||||||
&result, &resultlen);
|
&result, &resultlen);
|
||||||
if (sw != SW_SUCCESS)
|
if (sw != SW_SUCCESS)
|
||||||
{
|
{
|
||||||
@ -711,13 +716,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
|
|||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
bufferlen = 0;
|
bufferlen = 0;
|
||||||
n = read_all? 0 : nmax;
|
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,
|
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
|
||||||
n, &buffer, &bufferlen);
|
n, &buffer, &bufferlen);
|
||||||
if ( SW_EXACT_LENGTH_P(sw) )
|
if ( SW_EXACT_LENGTH_P(sw) )
|
||||||
{
|
{
|
||||||
n = (sw & 0x00ff);
|
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,
|
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
|
||||||
n, &buffer, &bufferlen);
|
n, &buffer, &bufferlen);
|
||||||
}
|
}
|
||||||
@ -804,7 +809,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
|
|||||||
|
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
bufferlen = 0;
|
bufferlen = 0;
|
||||||
sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
|
sw = apdu_send_le (slot, 0, 0x00, CMD_READ_RECORD,
|
||||||
recno,
|
recno,
|
||||||
short_ef? short_ef : 0x04,
|
short_ef? short_ef : 0x04,
|
||||||
-1, NULL,
|
-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,
|
gpg_error_t iso7816_compute_ds (int slot,
|
||||||
const unsigned char *data, size_t datalen,
|
const unsigned char *data, size_t datalen,
|
||||||
unsigned char **result, size_t *resultlen);
|
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,
|
const unsigned char *data, size_t datalen,
|
||||||
int padind,
|
int padind,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user