On December 17, Mats Andersson sent in a patch for apdu chaining,
and I responded that this might cause a problem with the card-piv
driver.
I am attaching a patch that removes the restrictions for card-piv.c
and piv-tool.c. His patch to adpu.c is also included. This patch is
against svn revision 3986, two days ago.
The patch does:
adpu.c is Mats' original patch. (The rest of these changes can run
without this.)
the PIV driver no longer need to set the card max_*_size parameters
to get around emulating read_binary and write_binary. It can
now handle partial reads and writes.
The assumptions for write_binary are that the first chuck will
have idx = 0, and the last chunk will write the last byte.
The flags parameter will contain the total length.
The only write_binary operations are done when initializing
a card, and this is only done from piv-tool.c which was modified
to pass in the length and other flags.
Piv-tool continues to be a primative test tool for inializing test
cards. But it has been expanded to be able to write other objects
on test cards.
The serial number of a PIV card is obtained from the CHUID object
if present which has a FASC-N which is an ID number created by the
issuer. Normally PIV cards are issued the U.S. Federal government
But there are ways to use the same cards with a non government CA.
This is then be referred to as PIV Compatible. In this case,
the FASC-N should start with an agency code = 9999 and an RFC 4122
GUID should be present in the CHUID. If this is the case, the GUID
is used as the serial number.
Windows 7 comes with a PIV card card driver, but to get it use one of
these card the CHUID is required. (piv-tool can now write one.
For anyone interested in the difference of "PIV Card", "PIV Interoperability"
and "PIV Compatible" see:
http://www.idmanagement.gov/documents/PIV_IO_NonFed_Issuers_May2009.pdf
and also 800-73-3 draft found here:
http://csrc.nist.gov/publications/PubsSPs.html
Andreas Jellinghaus wrote:
Mats here has a fix for apdu chaining / the default
send size is too big. I don't know much about this
topic, so could you please review this change?
Regards, Andreas
---------- Weitergeleitete Nachricht ----------
Betreff: Re: [opensc-devel] OpenSC 0.11.12-rc1 release candidate available
Datum: Donnerstag 17 Dezember 2009
Von: Mats Andersson <ma...@checkpoint.com>
An: Andreas Jellinghaus <a...@dungeon.inka.de>, Martin Paljak
<mar...@paljak.pri.ee>
Hi again,
Here is the udiff. I think the patch is safe. However, by itself maybe this
patch is not worth much, it only solves half of the problem that this is now
hard-coded in opensc (I just did this for keeping copying to a minimum when I
did support for a vasco-card).
If cards support extended APDU's they don't need chaining typically (this
patch will only affect sc_transmit_apdu() when SC_APDU_FLAGS_CHAINING is set).
Anyway, as I said, it would be even more "generic" if one has a flag/option on
card-level which indicates that the card supports chaining (I think it's a
discoverable capability of the card according to iso7816, I think through ATR
inspection). Then change the code so that it will "auto-chain" if a larger
than max_send_size APDU is to be sent (i.e. when extended APDUs are supported
the max_send_size is set to the max that can be sent with extended APDUs,
hence no chaining will take place there typically).
I can have a go at such a patch if there is interest. What is the official way
to provide patches/help out with testing/development?
Cheers,
/Mats
On 12/17/09 5:34 PM, "Andreas Jellinghaus" <a...@dungeon.inka.de> wrote:
Hi Mats,
thanks for your patch, I was not aware we had a problem there.
could you resend your patch in unified diff format ("diff -u")?
that is much easier to review.
I think however the solution is not as simple as this patch -
some cards support large APDU commands ("extended" are they
called I think), so I need to check with the development
team to make sure we don't fix one and break other cards.
so this patch won't go into 0.11.12, but if we can verify
it fixes a problem and rule out breaking other cards, we
can have another 0.11.* release for it.
Regards, Andreas
Scanned by Check Point Total Security Gateway.
-------------------------------------------------------------
------------------------------------------------------------------------
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel
--
Douglas E. Engert <deeng...@anl.gov>
Argonne National Laboratory
9700 South Cass Avenue
Argonne, Illinois 60439
(630) 252-5444
--- ./src/tools/,piv-tool.c Tue Feb 2 14:30:13 2010
+++ ./src/tools/piv-tool.c Thu Feb 4 16:37:31 2010
@@ -2,7 +2,7 @@
* piv-tool.c: Tool for accessing smart cards with libopensc
*
* Copyright (C) 2001 Juha Yrjölä <juha.yrj...@iki.fi>
- * Copyright (C) 2005, Douglas E. Engert <deeng...@anl.gov>
+ * Copyright (C) 2005,2010 Douglas E. Engert <deeng...@anl.gov>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -59,11 +59,12 @@
{ "admin", 0, NULL, 'A' },
{ "usepin", 0, NULL, 'P' }, /* some beta
cards want user pin for put_data */
{ "genkey", 0, NULL, 'G' },
- { "cert", 0, NULL, 'C' },
- { "compresscert", 0, NULL, 'Z' },
+ { "object", 1, NULL, 'O' },
+ { "cert", 1, NULL, 'C' },
+ { "compresscert", 1, NULL, 'Z' },
{ "req", 0, NULL, 'R' },
- { "out", 0, NULL, 'o' },
- { "in", 0, NULL, 'o' },
+ { "out", 1, NULL, 'o' },
+ { "in", 1, NULL, 'i' },
{ "send-apdu", 1, NULL, 's' },
{ "reader", 1, NULL, 'r' },
{ "card-driver", 1, NULL, 'c' },
@@ -78,6 +79,7 @@
"authenticate using default 3des key",
"authenticate using user pin",
"Generate key <ref>:<alg> 9A:06 on card, and output pubkey",
+ "Load an object <containerID> containerID as defined in 800-73 without
leading 0x",
"Load a cert <ref> where <ref> is 9A,9B,9C or 9D",
"Load a cert that has been gziped <ref>",
"Generate a cert req",
@@ -95,6 +97,55 @@
static BIO * bp = NULL;
static RSA * newkey = NULL;
+static int load_object(const char * object_id, const char * object_file)
+{
+ FILE *fp;
+ sc_path_t path;
+ size_t derlen;
+ u8 *der = NULL;
+ u8 *body;
+ size_t bodylen;
+ int r;
+ struct stat stat_buf;
+
+ if((fp=fopen(object_file, "r"))==NULL){
+ printf("Cannot open object file, %s %s\n",
+ (object_file)?object_file:"", strerror(errno));
+ return -1;
+ }
+
+ stat(object_file, &stat_buf);
+ derlen = stat_buf.st_size;
+ der = malloc(derlen);
+ if (der == NULL) {
+ printf("file %s is too big, %lu\n",
+ object_file, (unsigned long)derlen);
+ return-1 ;
+ }
+ if (1 != fread(der, derlen, 1, fp)) {
+ printf("unable to read file %s\n",object_file);
+ return -1;
+ }
+ /* check if tag and length are valid */
+ body = (u8 *)sc_asn1_find_tag(card->ctx, der, derlen, 0x53, &bodylen);
+ if (body == NULL || derlen != body - der + bodylen) {
+ fprintf(stderr, "object tag or length not valid\n");
+ return -1;
+ }
+
+ sc_format_path(object_id, &path);
+
+ r = sc_select_file(card, &path, NULL);
+ if (r < 0) {
+ fprintf(stderr, "select file failed\n");
+ return -1;
+ }
+ /* leave 8 bits for flags, and pass in total length */
+ r = sc_write_binary(card, 0, der, derlen, derlen<<8);
+
+ return r;
+}
+
static int load_cert(const char * cert_id, const char * cert_file,
int compress)
@@ -111,7 +162,7 @@
if((fp=fopen(cert_file, "r"))==NULL){
printf("Cannot open cert file, %s %s\n",
- cert_file, strerror(errno));
+ cert_file?cert_file:"", strerror(errno));
return -1;
}
if (compress) { /* file is gziped already */
@@ -160,8 +211,9 @@
fprintf(stderr, "select file failed\n");
return -1;
}
- /* we pass compress as the flag to card-piv.c write_binary */
- r = sc_write_binary(card, 0, der, derlen, compress);
+ /* we pass length and 8 bits of flag to card-piv.c write_binary */
+ /* pass in its a cert and if needs compress */
+ r = sc_write_binary(card, 0, der, derlen, derlen<<8 | compress<1 | 1);
return r;
@@ -359,6 +411,7 @@
int do_admin_mode = 0;
int do_gen_key = 0;
int do_load_cert = 0;
+ int do_load_object = 0;
int compress_cert = 0;
int do_req = 0;
int do_print_serial = 0;
@@ -368,6 +421,7 @@
const char *out_file = NULL;
const char *in_file = NULL;
const char *cert_id = NULL;
+ const char *object_id = NULL;
const char *key_info = NULL;
const char *admin_info = NULL;
@@ -375,7 +429,7 @@
setbuf(stdout, NULL);
while (1) {
- c = getopt_long(argc, argv, "nA:G:Z:C:Ri:o:fvs:c:w", options,
&long_optind);
+ c = getopt_long(argc, argv, "nA:G:O:Z:C:Ri:o:fvs:c:w", options,
&long_optind);
if (c == -1)
break;
if (c == '?')
@@ -408,6 +462,11 @@
key_info = optarg;
action_count++;
break;
+ case 'O':
+ do_load_object = 1;
+ object_id = optarg;
+ action_count++;
+ break;
case 'Z':
compress_cert = 1;
case 'C':
@@ -491,6 +550,11 @@
}
if (do_gen_key) {
if ((err = gen_key(key_info)))
+ goto end;
+ action_count--;
+ }
+ if (do_load_object) {
+ if ((err = load_object(object_id, in_file)))
goto end;
action_count--;
}
--- ./src/libopensc/,card-piv.c Tue Feb 2 14:30:47 2010
+++ ./src/libopensc/card-piv.c Thu Feb 4 16:38:27 2010
@@ -3,7 +3,7 @@
* card-default.c: Support for cards with no driver
*
* Copyright (C) 2001, 2002 Juha Yrjölä <juha.yrj...@iki.fi>
- * Copyright (C) 2005,2006,2007 Douglas E. Engert <deeng...@anl.gov>
+ * Copyright (C) 2005,2006,2007,2008,2009,2010 Douglas E. Engert
<deeng...@anl.gov>
* Copyright (C) 2006, Identity Alliance, Thomas Harning
<thomas.harn...@identityalliance.com>
* Copyright (C) 2007, EMC, Russell Larner <rlar...@rsa.com>
*
@@ -77,11 +77,11 @@
int enumtag;
int selected_obj; /* The index into the piv_objects last selected */
int return_only_cert; /* return the cert from the object */
- int rb_state; /* first time -1, 0, in middle, 1 at eof */
- size_t max_recv_size; /* saved size, need to lie to pkcs15_read_file */
- size_t max_send_size;
+ int rwb_state; /* first time -1, 0, in middle, 1 at eof */
int key_ref; /* saved from set_security_env and */
int alg_id; /* used in decrypt, signature */
+ u8* w_buf; /* write_binary buffer */
+ size_t w_buf_len; /* length of w_buff */
piv_obj_cache_t obj_cache[PIV_OBJ_LAST_ENUM];
} piv_private_data_t;
@@ -246,7 +246,7 @@
SC_FUNC_CALLED(card->ctx,1);
sc_debug(card->ctx, "%02x %02x %02x %d : %d %d\n",
- ins, p1, p2, sendbuflen , priv->max_send_size,
priv->max_recv_size);
+ ins, p1, p2, sendbuflen , card->max_send_size,
card->max_recv_size);
rbuf = rbufinitbuf;
rbuflen = sizeof(rbufinitbuf);
@@ -272,7 +272,7 @@
if (recvbuf) {
apdu.resp = rbuf;
- apdu.le = (priv->max_recv_size <= rbuflen)? priv->max_recv_size
: rbuflen;
+ apdu.le = (card->max_recv_size <= rbuflen)? card->max_recv_size
: rbuflen;
apdu.resplen = rbuflen;
} else {
apdu.resp = rbuf;
@@ -280,16 +280,11 @@
apdu.resplen = 0;
}
- /* TODO if read_binary is fixed, this is not needed */
- card->max_recv_size = priv->max_recv_size;
-
sc_debug(card->ctx,"calling sc_transmit_apdu flags=%x le=%d,
resplen=%d, resp=%p",
apdu.flags, apdu.le, apdu.resplen, apdu.resp);
/* with new adpu.c and chaining, this actually reads the whole object */
r = sc_transmit_apdu(card, &apdu);
- /* TODO if read_binary is fixed, this is not needed */
- card->max_recv_size = 0xffff;
sc_debug(card->ctx,"DEE r=%d apdu.resplen=%d sw1=%02x sw2=%02x",
r, apdu.resplen, apdu.sw1, apdu.sw2);
@@ -911,11 +906,11 @@
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
enumtag = piv_objects[priv->selected_obj].enumtag;
- if (priv->rb_state == 1) {
+ if (priv->rwb_state == 1) {
r = 0;
}
- if (priv->rb_state == -1) {
+ if (priv->rwb_state == -1) {
r = piv_get_cached_data(card, enumtag, &rbuf, &rbuflen);
if (r >=0) {
@@ -947,7 +942,7 @@
}
}
- priv->rb_state = 0;
+ priv->rwb_state = 0;
}
if (priv->return_only_cert || piv_objects[enumtag].flags &
PIV_OBJECT_TYPE_PUBKEY) {
@@ -963,7 +958,7 @@
count = rbuflen - idx;
if (count <= 0) {
r = 0;
- priv->rb_state = 1;
+ priv->rwb_state = 1;
} else {
memcpy(buf, rbuf + idx, count);
r = count;
@@ -1011,8 +1006,9 @@
SC_FUNC_RETURN(card->ctx, 1, r);
}
+
static int piv_write_certificate(sc_card_t *card,
- unsigned idx, const u8* buf, size_t count,
+ const u8* buf, size_t count,
unsigned long flags) {
piv_private_data_t * priv = PIV_DATA(card);
int enumtag;
@@ -1023,7 +1019,7 @@
size_t taglen;
sc_debug(card->ctx,"DEE cert len=%d",count);
- taglen = put_tag_and_len(0x70, count, NULL)
+ taglen = put_tag_and_len(0x70, count, NULL)
+ put_tag_and_len(0x71, 1, NULL)
+ put_tag_and_len(0xFE, 0, NULL);
@@ -1039,7 +1035,7 @@
memcpy(p, buf, count);
p += count;
put_tag_and_len(0x71, 1, &p);
- *p++ = (flags && 1)? 0x80:0x00; /* certinfo, i.e. gziped? */
+ *p++ = (flags)? 0x80:0x00; /* certinfo, i.e. gziped? */
put_tag_and_len(0xFE,0,&p); /* LRC tag */
sc_debug(card->ctx,"DEE buf %p len %d %d", sbuf, p -sbuf, sbuflen);
@@ -1051,32 +1047,99 @@
SC_FUNC_RETURN(card->ctx, 1, r);
}
+
/*
- * We need to add the 0x53 tag and other specific tags,
+ * For certs we need to add the 0x53 tag and other specific tags,
* and call the piv_put_data
* Note: the select file will have saved the object type for us
- * Write is only used by piv-tool, so we will use flags==1
- * to indicate we are writing a compressed cert.
+ * Write is only used by piv-tool, so we will use flags:
+ * length << 8 | compress < 1 | cert
+ * to indicate we are writing a cert and if is compressed.
+ * if its not a cert its an object.
+ *
+ * Therefore when idx=0, we will get the length of the object
+ * and allocate a buffer, so we can support partial writes.
+ * When the last chuck of the data is sent, we will write it.
*/
static int piv_write_binary(sc_card_t *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
piv_private_data_t * priv = PIV_DATA(card);
+ int r;
+ int enumtag;
+
SC_FUNC_CALLED(card->ctx,1);
if (priv->selected_obj < 0)
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
- if (idx != 0)
- SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NO_CARD_SUPPORT);
+
+ enumtag = piv_objects[priv->selected_obj].enumtag;
+
+ if (priv->rwb_state == 1) /* trying to write at end */
+ SC_FUNC_RETURN(card->ctx, 1, 0);
+
+ if (priv->rwb_state == -1) {
+
+ /* if cached, remove old entry */
+ if (priv->obj_cache[enumtag].flags & PIV_OBJ_CACHE_VALID) {
+ priv->obj_cache[enumtag].flags = 0;
+ if (priv->obj_cache[enumtag].obj_data) {
+ free(priv->obj_cache[enumtag].obj_data);
+ priv->obj_cache[enumtag].obj_data = NULL;
+ priv->obj_cache[enumtag].obj_len = 0;
+ }
+ if (priv->obj_cache[enumtag].internal_obj_data) {
+
free(priv->obj_cache[enumtag].internal_obj_data);
+ priv->obj_cache[enumtag].internal_obj_data =
NULL;
+ priv->obj_cache[enumtag].internal_obj_len = 0;
+ }
+ }
+
+ if (idx != 0)
+ SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NO_CARD_SUPPORT);
+
+ priv->w_buf_len = flags>>8;
+ if (priv->w_buf_len == 0)
+ SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INTERNAL);
+
+ priv->w_buf = (u8 *)malloc(priv->w_buf_len);
+ priv-> rwb_state = 0;
+ }
+
+ /* on each pass make sure we have w_buf */
+ if (priv->w_buf == NULL)
+ SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OUT_OF_MEMORY);
+
+ if (idx + count > priv->w_buf_len)
+ SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OBJECT_NOT_VALID);
+
+ memcpy(priv->w_buf + idx, buf, count); /* copy one chunk */
+
+ /* if this was not the last chunk, return to get rest */
+ if (idx + count < priv->w_buf_len)
+ SC_FUNC_RETURN(card->ctx, 1, count);
+
+ priv-> rwb_state = 1; /* at end of object */
- if (piv_objects[priv->selected_obj].flags & PIV_OBJECT_TYPE_CERT) {
- SC_FUNC_RETURN(card->ctx, 1,
piv_write_certificate(card, idx, buf, count, flags));
+ if ( flags & 1) {
+ r = piv_write_certificate(card, priv->w_buf,
priv->w_buf_len,
+ flags & 0x02);
} else {
- sc_debug(card->ctx, "Don't know how to write object %s\n",
- piv_objects[priv->selected_obj].name);
- SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_NOT_SUPPORTED);
+ r = piv_put_data(card, enumtag, priv->w_buf, priv->w_buf_len);
+ }
+ /* if it worked, will cache it */
+ if (r >= 0 && priv->w_buf) {
+ priv->obj_cache[enumtag].flags = PIV_OBJ_CACHE_VALID;
+ priv->obj_cache[enumtag].obj_data = priv->w_buf;
+ priv->obj_cache[enumtag].obj_len = priv->w_buf_len;
+ } else {
+ if (priv->w_buf)
+ free(priv->w_buf);
}
+ priv->w_buf = NULL;
+ priv->w_buf_len = 0;
+ SC_FUNC_RETURN(card->ctx, 1, (r < 0)? r : count);
}
/*
@@ -1385,9 +1448,11 @@
static int piv_get_serial_nr_from_CHUI(sc_card_t* card, sc_serial_number_t*
serial)
{
int r;
+ int i;
+ u8 gbits;
u8 *rbuf = NULL;
- u8 *body, *fascn;
- size_t rbuflen = 0, bodylen, fascnlen;
+ u8 *body, *fascn, *guid;
+ size_t rbuflen = 0, bodylen, fascnlen, guidlen;
u8 temp[2000];
size_t templen = sizeof(temp);
@@ -1396,6 +1461,11 @@
/* ensure we've got the PIV selected, and nothing else is in process */
/* This fixes several problems due to previous incomplete APDUs during
card detection */
/* Note: We need the temp because (some?) Oberthur cards don't like
selecting an applet without response data */
+ /* 800-73-3 part1 draft, and CIO Council docs imply for PIV Compatible
card
+ * The FASC-N Agency code should be 9999 and there should be a GUID
+ * based on RFC 4122. RIf so and the GUID is not all 0's
+ * we will use the GUID as the serial number.
+ */
piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp,
&templen);
r = piv_get_cached_data(card, PIV_OBJ_CHUI, &rbuf, &rbuflen);
@@ -1406,16 +1476,35 @@
body = (u8 *)sc_asn1_find_tag(card->ctx, rbuf, rbuflen, 0x53,
&bodylen); /* Pass the outer wrapper asn1 */
if (body != NULL && bodylen != 0) {
fascn = (u8 *)sc_asn1_find_tag(card->ctx, body,
bodylen, 0x30, &fascnlen); /* Find the FASC-N data */
- if (fascn != NULL && fascnlen != 0) {
- serial->len = fascnlen < SC_MAX_SERIALNR ?
fascnlen : SC_MAX_SERIALNR;
- memcpy (serial->value, fascn, serial->len);
+ guid = (u8 *)sc_asn1_find_tag(card->ctx, body, bodylen,
0x34, &guidlen);
+
+ gbits = 0; /* if guid is valid, gbits will not be zero
*/
+ if (guid && guidlen == 16) {
+ for (i = 0; i < 16; i++) {
+ gbits = gbits | guid[i]; /* if all are
zero, gbits will be zero */
+ }
+ }
+
sc_debug(card->ctx,"fascn=%p,fascnlen=%d,guid=%p,guidlen=%d,gbits=%2.2x\n",
+ fascn, fascnlen, guid, guidlen, gbits);
+
+ if (fascn && fascnlen == 25) {
+ /* test if guid and the fascn starts with ;9999
(in ISO 4bit + partiy code) */
+ if (!(gbits && fascn[0] == 0xD4 && fascn[1] ==
0xE7
+ && fascn[2] == 0x39 &&
(fascn[3] | 0x7F) == 0xFF)) {
+ serial->len = fascnlen <
SC_MAX_SERIALNR ? fascnlen : SC_MAX_SERIALNR;
+ memcpy (serial->value, fascn,
serial->len);
+ r = SC_SUCCESS;
+ gbits = 0; /* set to skip using guid
below */
+ }
+ }
+ if (guid && gbits) {
+ serial->len = guidlen < SC_MAX_SERIALNR ?
guidlen : SC_MAX_SERIALNR;
+ memcpy (serial->value, guid, serial->len);
r = SC_SUCCESS;
}
}
}
-// if (rbuf != NULL)
-// free (rbuf);
SC_FUNC_RETURN(card->ctx, 1, r);
}
@@ -1682,7 +1771,7 @@
priv->return_only_cert = (pathlen == 4 && path[2] == 0xce && path[3] ==
0xce);
priv->selected_obj = i;
- priv->rb_state = -1;
+ priv->rwb_state = -1;
/* make it look like the file was found. */
/* We don't want to read it now unless we need the length */
@@ -1734,6 +1823,8 @@
if (priv) {
if (priv->aid_file)
sc_file_free(priv->aid_file);
+ if (priv->w_buf)
+ free(priv->w_buf);
for (i = 0; i < PIV_OBJ_LAST_ENUM - 1; i++) {
sc_debug(card->ctx,"DEE freeing #%d, %p:%d %p:%d", i,
priv->obj_cache[i].obj_data,
priv->obj_cache[i].obj_len,
@@ -1778,12 +1869,9 @@
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_OUT_OF_MEMORY);
priv->aid_file = sc_file_new();
priv->selected_obj = -1;
- priv->max_recv_size = 256;
+ /* priv->max_recv_size = 256; */
/* priv->max_recv_size = card->max_recv_size; */
- priv->max_send_size = card->max_send_size;
- /* TODO fix read_binary and write_binary (read_binary is fixed) */
- card->max_recv_size = 0xffff; /* must force pkcs15 read_binary in one
call */
- card->max_send_size = 0xffff;
+ /* priv->max_send_size = card->max_send_size; */
sc_debug(card->ctx, "Max send = %d recv = %d\n",
card->max_send_size, card->max_recv_size);
--- ./src/libopensc/,apdu.c Tue Feb 2 14:30:48 2010
+++ ./src/libopensc/apdu.c Wed Feb 3 11:21:49 2010
@@ -530,10 +530,13 @@
}
if ((apdu->flags & SC_APDU_FLAGS_CHAINING) != 0) {
- /* divide et impera: transmit APDU in chunks with Lc < 255
+ /* divide et impera: transmit APDU in chunks with Lc <=
max_send_size
* bytes using command chaining */
size_t len = apdu->datalen;
const u8 *buf = apdu->data;
+ size_t max_send_size = ((card->max_send_size > 0) ?
+ card->max_send_size :
+ card->reader->driver->max_send_size);
while (len != 0) {
size_t plen;
@@ -543,14 +546,14 @@
tapdu = *apdu;
/* clear chaining flag */
tapdu.flags &= ~SC_APDU_FLAGS_CHAINING;
- if (len > 255) {
+ if (len > max_send_size) {
/* adjust APDU case: in case of CASE 4 APDU
* the intermediate APDU are of CASE 3 */
if ((tapdu.cse & SC_APDU_SHORT_MASK) ==
SC_APDU_CASE_4_SHORT)
tapdu.cse--;
/* XXX: the chunk size must be adjusted when
* secure messaging is used */
- plen = 255;
+ plen = max_send_size;
tapdu.cla |= 0x10;
tapdu.le = 0;
/* the intermediate APDU don't expect data */
_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel