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 + + * learncard.c (agent_handle_learn): Add new certtype 111. + 2009-03-26 Werner Koch * 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 + + * 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 * 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) + 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; 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);