summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO5
-rw-r--r--agent/ChangeLog4
-rw-r--r--agent/learncard.c4
-rw-r--r--scd/ChangeLog13
-rw-r--r--scd/apdu.c192
-rw-r--r--scd/apdu.h10
-rw-r--r--scd/app-help.c3
-rw-r--r--scd/app-nks.c61
-rw-r--r--scd/app-openpgp.c6
-rw-r--r--scd/ccid-driver.c50
-rw-r--r--scd/command.c11
-rw-r--r--scd/iso7816.c37
-rw-r--r--scd/iso7816.h2
13 files changed, 277 insertions, 121 deletions
diff --git a/TODO b/TODO
index 78068358b..45e221bda 100644
--- a/TODO
+++ b/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
diff --git a/agent/ChangeLog b/agent/ChangeLog
index c55199135..10390da3f 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -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.
diff --git a/agent/learncard.c b/agent/learncard.c
index 3db33ee76..b5b5bd77d 100644
--- a/agent/learncard.c
+++ b/agent/learncard.c
@@ -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 */
};
diff --git a/scd/ChangeLog b/scd/ChangeLog
index f6de2599d..efd46fea9 100644
--- a/scd/ChangeLog
+++ b/scd/ChangeLog
@@ -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.
diff --git a/scd/apdu.c b/scd/apdu.c
index b12b7e951..d63157ce7 100644
--- a/scd/apdu.c
+++ b/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)
- {
- apdu[apdulen] |= 0x10;
- assert (use_chaining < 256);
- lc_chunk = use_chaining;
- lc -= use_chaining;
- }
- else
+ if (use_extended_length)
{
use_chaining = 0;
- lc_chunk = lc;
+ 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);
+ }
}
- apdulen++;
- apdu[apdulen++] = ins;
- apdu[apdulen++] = p0;
- apdu[apdulen++] = p1;
- if (lc_chunk != -1)
+ else
{
- 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;
+ 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). */
}
- 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;
diff --git a/scd/apdu.h b/scd/apdu.h
index 007bda767..2a932df38 100644
--- a/scd/apdu.h
+++ b/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);
diff --git a/scd/app-help.c b/scd/app-help.c
index 7b9ce992d..83b34c64e 100644
--- a/scd/app-help.c
+++ b/scd/app-help.c
@@ -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;
}
diff --git a/scd/app-nks.c b/scd/app-nks.c
index d2ba9789d..4656b238f 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -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;
}
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index ce09a51f5..2c89e8c3c 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -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;
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 854aca1b5..c159b5cd1 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -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;
diff --git a/scd/command.c b/scd/command.c
index 07aed176a..71081b26f 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -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));
diff --git a/scd/iso7816.c b/scd/iso7816.c
index ecb6dc1bd..d12f918a8 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -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,
diff --git a/scd/iso7816.h b/scd/iso7816.h
index 6c0485d0c..44e50d784 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -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);