1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-18 14:17:03 +01:00

Updated card stuff to support T=0 cards.

This commit is contained in:
Werner Koch 2005-09-07 17:05:42 +00:00
parent 9a2a2904cc
commit b4b9f891e2
9 changed files with 394 additions and 459 deletions

2
README
View File

@ -307,7 +307,7 @@
certify that they know the owner of the keys they sign. If you then certify that they know the owner of the keys they sign. If you then
trust all the introducers to have correctly signed other keys, you trust all the introducers to have correctly signed other keys, you
can be be sure that the other key really belongs to the one who can be be sure that the other key really belongs to the one who
claims to own it.. claims to own it.
There are 2 steps to validate a key: There are 2 steps to validate a key:
1. First check that there is a complete chain 1. First check that there is a complete chain

View File

@ -782,7 +782,7 @@ The format of this file is as follows:
Handle: <string> Handle: <string>
This is an optional parameter only used with the status lines This is an optional parameter only used with the status lines
KEY_CREATED and KEY_NOT_CREATED. STRING may be up to 100 KEY_CREATED and KEY_NOT_CREATED. STRING may be up to 100
characters and should not contauin spaces. It is useful for characters and should not contain spaces. It is useful for
batch key generation to associate a key parameter block with a batch key generation to associate a key parameter block with a
status line. status line.

View File

@ -1,5 +1,20 @@
2005-09-07 Werner Koch <wk@g10code.com> 2005-09-07 Werner Koch <wk@g10code.com>
* cardglue.h (GPG_ERR_TOO_LARGE): New.
* apdu.c, apdu.h, iso7816.c, iso7816.h
* ccid-driver.c, ccid-driver.h: Updated from GnuPG 1.9 source.
Changes are:
* iso7816.c (iso7816_select_path): New.
* iso7816.c (iso7816_read_binary): Use Le=0 when reading all
data. Handle 6C00 error and take 6B00 as indication for EOF.
* apdu.h (SW_EXACT_LENGTH_P): New.
* apdu.c (new_reader_slot, reset_pcsc_reader, pcsc_get_status)
(open_pcsc_reader): Set new reader state IS_T0.
(apdu_send_le): When doing T=0 make sure not to send Lc and Le.
Problem reported by Carl Meijer.
(apdu_send_direct): Initialize RESULTLEN.
* misc.c (parse_options): Allow meta option "help" to list all * misc.c (parse_options): Allow meta option "help" to list all
options and to exit the program. options and to exit the program.

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,7 @@ enum {
SW_RECORD_NOT_FOUND = 0x6a83, SW_RECORD_NOT_FOUND = 0x6a83,
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_INS_NOT_SUP = 0x6d00, SW_INS_NOT_SUP = 0x6d00,
SW_CLA_NOT_SUP = 0x6e00, SW_CLA_NOT_SUP = 0x6e00,
SW_SUCCESS = 0x9000, SW_SUCCESS = 0x9000,
@ -66,6 +67,8 @@ enum {
}; };
#define SW_EXACT_LENGTH_P(a) (((a)&~0xff) == SW_EXACT_LENGTH)
/* Note , that apdu_open_reader returns no status word but -1 on error. */ /* Note , that apdu_open_reader returns no status word but -1 on error. */
int apdu_open_reader (const char *portstr); int apdu_open_reader (const char *portstr);

View File

@ -112,6 +112,7 @@ typedef struct ctrl_ctx_s *ctrl_t;
#define GPG_ERR_UNKNOWN_SEXP G10ERR_INV_ARG #define GPG_ERR_UNKNOWN_SEXP G10ERR_INV_ARG
#define GPG_ERR_DUP_VALUE G10ERR_INV_ARG #define GPG_ERR_DUP_VALUE G10ERR_INV_ARG
#define GPG_ERR_BAD_SECKEY G10ERR_BAD_SECKEY #define GPG_ERR_BAD_SECKEY G10ERR_BAD_SECKEY
#define GPG_ERR_TOO_LARGE G10ERR_GENERAL
#define GPG_ERR_EBUSY G10ERR_GENERAL #define GPG_ERR_EBUSY G10ERR_GENERAL
#define GPG_ERR_ENOENT G10ERR_OPEN_FILE #define GPG_ERR_ENOENT G10ERR_OPEN_FILE

View File

@ -556,7 +556,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
all in a 2 bute Unicode encoding using little endian. */ all in a 2 bute Unicode encoding using little endian. */
rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
(USB_DT_STRING << 8), 0, (USB_DT_STRING << 8), 0,
buf, sizeof buf, 1000 /* ms timeout */); (char*)buf, sizeof buf, 1000 /* ms timeout */);
if (rc < 4) if (rc < 4)
langid = 0x0409; /* English. */ langid = 0x0409; /* English. */
else else
@ -564,7 +564,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
(USB_DT_STRING << 8) + idx, langid, (USB_DT_STRING << 8) + idx, langid,
buf, sizeof buf, 1000 /* ms timeout */); (char*)buf, sizeof buf, 1000 /* ms timeout */);
if (rc < 2 || buf[1] != USB_DT_STRING) if (rc < 2 || buf[1] != USB_DT_STRING)
return NULL; /* Error or not a string. */ return NULL; /* Error or not a string. */
len = buf[0]; len = buf[0];
@ -1156,7 +1156,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
rc = usb_bulk_write (handle->idev, rc = usb_bulk_write (handle->idev,
handle->ep_bulk_out, handle->ep_bulk_out,
msg, msglen, (char*)msg, msglen,
1000 /* ms timeout */); 1000 /* ms timeout */);
if (rc == msglen) if (rc == msglen)
return 0; return 0;
@ -1189,7 +1189,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
retry: retry:
rc = usb_bulk_read (handle->idev, rc = usb_bulk_read (handle->idev,
handle->ep_bulk_in, handle->ep_bulk_in,
buffer, length, (char*)buffer, length,
timeout); timeout);
if (rc < 0) if (rc < 0)
{ {
@ -1301,7 +1301,7 @@ ccid_poll (ccid_driver_t handle)
rc = usb_bulk_read (handle->idev, rc = usb_bulk_read (handle->idev,
handle->ep_intr, handle->ep_intr,
msg, sizeof msg, (char*)msg, sizeof msg,
0 /* ms timeout */ ); 0 /* ms timeout */ );
if (rc < 0 && errno == ETIMEDOUT) if (rc < 0 && errno == ETIMEDOUT)
return 0; return 0;
@ -1445,7 +1445,7 @@ ccid_get_atr (ccid_driver_t handle,
{ {
tried_iso = 1; tried_iso = 1;
/* Try switching to ISO mode. */ /* Try switching to ISO mode. */
if (!send_escape_cmd (handle, "\xF1\x01", 2)) if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2))
goto again; goto again;
} }
else if (CCID_COMMAND_FAILED (msg)) else if (CCID_COMMAND_FAILED (msg))
@ -2027,7 +2027,7 @@ ccid_transceive_secure (ccid_driver_t handle,
if (handle->id_vendor == VENDOR_SCM) if (handle->id_vendor == VENDOR_SCM)
{ {
DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n"); DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
rc = send_escape_cmd (handle, "\x80\x02\x00", 3); rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3);
if (rc) if (rc)
return rc; return rc;
} }

View File

@ -78,6 +78,7 @@ map_sw (int sw)
case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break; case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break;
case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break; case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break;
case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break; case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break;
case SW_EXACT_LENGTH: ec = GPG_ERR_INV_VALUE; break;
case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break; case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break;
case SW_CLA_NOT_SUP: ec = GPG_ERR_CARD; break; case SW_CLA_NOT_SUP: ec = GPG_ERR_CARD; break;
case SW_SUCCESS: ec = 0; break; case SW_SUCCESS: ec = 0; break;
@ -154,7 +155,7 @@ iso7816_select_file (int slot, int tag, int is_dir,
p0 = (tag == 0x3F00)? 0: is_dir? 1:2; p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
p1 = 0x0c; /* No FC return. */ p1 = 0x0c; /* No FC return. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
p0, p1, 2, tagbuf ); p0, p1, 2, (char*)tagbuf );
return map_sw (sw); return map_sw (sw);
} }
@ -162,6 +163,39 @@ iso7816_select_file (int slot, int tag, int is_dir,
} }
/* Do a select file command with a direct path. */
gpg_error_t
iso7816_select_path (int slot, const unsigned short *path, size_t pathlen,
unsigned char **result, size_t *resultlen)
{
int sw, p0, p1;
unsigned char buffer[100];
int buflen;
if (result || resultlen)
{
*result = NULL;
*resultlen = 0;
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
if (pathlen/2 >= sizeof buffer)
return gpg_error (GPG_ERR_TOO_LARGE);
for (buflen = 0; pathlen; pathlen--, path++)
{
buffer[buflen++] = (*path >> 8);
buffer[buflen++] = *path;
}
p0 = 0x08;
p1 = 0x0c; /* No FC return. */
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
p0, p1, buflen, (char*)buffer );
return map_sw (sw);
}
/* This is a private command currently only working for TCOS cards. */ /* This is a private command currently only working for TCOS cards. */
gpg_error_t gpg_error_t
iso7816_list_directory (int slot, int list_dirs, iso7816_list_directory (int slot, int list_dirs,
@ -286,7 +320,7 @@ iso7816_put_data (int slot, int tag,
sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA, sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
((tag >> 8) & 0xff), (tag & 0xff), ((tag >> 8) & 0xff), (tag & 0xff),
datalen, data); datalen, (const char*)data);
return map_sw (sw); return map_sw (sw);
} }
@ -300,10 +334,11 @@ iso7816_manage_security_env (int slot, int p1, int p2,
{ {
int sw; int sw;
if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen) if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 )
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, datalen, data); sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2,
data? datalen : -1, (const char*)data);
return map_sw (sw); return map_sw (sw);
} }
@ -323,7 +358,7 @@ 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, data, sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data,
result, resultlen); result, resultlen);
if (sw != SW_SUCCESS) if (sw != SW_SUCCESS)
{ {
@ -364,13 +399,15 @@ 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, datalen+1, buf, sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
datalen+1, (char*)buf,
result, resultlen); result, resultlen);
xfree (buf); xfree (buf);
} }
else else
{ {
sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen, data, sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
datalen, (const char *)data,
result, resultlen); result, resultlen);
} }
if (sw != SW_SUCCESS) if (sw != SW_SUCCESS)
@ -399,7 +436,7 @@ iso7816_internal_authenticate (int slot,
*resultlen = 0; *resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0, sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
datalen, data, result, resultlen); datalen, (const char*)data, result, resultlen);
if (sw != SW_SUCCESS) if (sw != SW_SUCCESS)
{ {
/* Make sure that pending buffers are released. */ /* Make sure that pending buffers are released. */
@ -426,7 +463,7 @@ do_generate_keypair (int slot, int readonly,
*resultlen = 0; *resultlen = 0;
sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0, sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
datalen, data, result, resultlen); datalen, (const char*)data, result, resultlen);
if (sw != SW_SUCCESS) if (sw != SW_SUCCESS)
{ {
/* Make sure that pending buffers are released. */ /* Make sure that pending buffers are released. */
@ -522,8 +559,10 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
{ {
buffer = NULL; buffer = NULL;
bufferlen = 0; bufferlen = 0;
/* Fixme: Either the ccid driver or the TCOS cards have problems /* Note, that we to set N to 254 due to problems either with the
with an Le of 0. */ ccid driver or some TCOS cards. It actually should be 0
which is the official ISO value to read a variable length
object. */
if (read_all || nmax > 254) if (read_all || nmax > 254)
n = 254; n = 254;
else else
@ -531,6 +570,21 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY, sw = apdu_send_le (slot, 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) )
{
n = (sw & 0x00ff);
sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
n, &buffer, &bufferlen);
}
if (*result && sw == SW_BAD_P0_P1)
{
/* Bad Parameter means that the offset is outside of the
EF. When reading all data we take this as an indication
for EOF. */
break;
}
if (sw != SW_SUCCESS && sw != SW_EOF_REACHED) if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
{ {
@ -606,7 +660,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
buffer = NULL; buffer = NULL;
bufferlen = 0; bufferlen = 0;
/* Fixme: Either the ccid driver of the TCOS cards have problems /* Fixme: Either the ccid driver or the TCOS cards have problems
with an Le of 0. */ with an Le of 0. */
sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD, sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
recno, recno,

View File

@ -34,6 +34,9 @@ gpg_error_t iso7816_select_application (int slot,
const char *aid, size_t aidlen); const char *aid, size_t aidlen);
gpg_error_t iso7816_select_file (int slot, int tag, int is_dir, gpg_error_t iso7816_select_file (int slot, int tag, int is_dir,
unsigned char **result, size_t *resultlen); unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_select_path (int slot,
const unsigned short *path, size_t pathlen,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_list_directory (int slot, int list_dirs, gpg_error_t iso7816_list_directory (int slot, int list_dirs,
unsigned char **result, size_t *resultlen); unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_verify (int slot, gpg_error_t iso7816_verify (int slot,