Hi!

> > Looking at your patch - I like the approach more:
> >  - removes code duplication (there's one more instance in piv-tool.c)
> >  - feels like easier to read (but verification would need attention what I
> > can't afford right now, sickathome) - has a nice debug log statement.
> > 
> > It would be nice if the patch
> >  - removed the 3rd instance of same code in piv-tool.c (and reverted r5370)
> >  - had some doxygen documentation in apdu.c and opensc.h
> >  - not really important, but probably would be good if the function had a
> > name similar to the reverse function (apdu2bytes)

Done, see the attached patch. Get well soon, btw.

> > Peter, can you verify if this works for you as well (and/or is it free of
> > the mentioned memory overrun problem) ?
> 
> Yes Frank's patch works for me too [he is right: my patch has a bug], and his 
> patch is also OK wrt to the memory overrun: Frank correctly checks length 
> before further actions (the bug was in the original code in opensc-tool.c & 
> opensc-explorer.c.
> 
> In #260 I have attached an update of Frank's patch that applies to r5378 (as 
> of today 15:00 CET DST): it backs out the changes of my patch and
> restores his version again.

Thanks! I used your version of the patch to add the changes mentioned
above.

Cheers,
Frank.
Index: src/tools/opensc-tool.c
===================================================================
--- src/tools/opensc-tool.c     (Revision 5378)
+++ src/tools/opensc-tool.c     (Arbeitskopie)
@@ -492,98 +492,24 @@
 static int send_apdu(void)
 {
        sc_apdu_t apdu;
-       u8 buf[SC_MAX_APDU_BUFFER_SIZE], sbuf[SC_MAX_APDU_BUFFER_SIZE],
-         rbuf[SC_MAX_APDU_BUFFER_SIZE], *p;
-       size_t len, len0, r;
+       u8 buf[SC_MAX_APDU_BUFFER_SIZE],
+         rbuf[SC_MAX_APDU_BUFFER_SIZE];
+       size_t len0, r;
        int c;
-       int cse = 0;
 
        for (c = 0; c < opt_apdu_count; c++) {
                len0 = sizeof(buf);
                sc_hex_to_bin(opt_apdus[c], buf, &len0);
-               if (len0 < 4) {
-                       fprintf(stderr, "APDU too short (must be at least 4 
bytes).\n");
+
+               r = sc_bytes2apdu(card->ctx, buf, len0, &apdu);
+               if (r) {
+                       fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r));
                        return 2;
                }
-               len = len0;
-               p = buf;
 
-               /* TODO: move this to apdu.c as bytes2apdu or similar. See #237 
*/
-               memset(&apdu, 0, sizeof(apdu));
-               apdu.cla = *p++;
-               apdu.ins = *p++;
-               apdu.p1 = *p++;
-               apdu.p2 = *p++;
                apdu.resp = rbuf;
                apdu.resplen = sizeof(rbuf);
-               len -= 4;
 
-               if (len == 0) {
-                       apdu.cse = SC_APDU_CASE_1;
-               }
-               else {
-                       size_t size = 0;
-
-                       if ((*p == 0) && (len >= 3)) {
-                               cse |= SC_APDU_EXT;
-                               p++;
-                               size = (*p++) << 8;
-                               size += *p++;
-                               len -= 3;
-                       }
-                       else {
-                               size = *p++;
-                               len--;
-                       }
-                       if (len == 0) {
-                               apdu.le = (size == 0) ? 256 : size;
-                               if ((apdu.le == 0) && (cse & SC_APDU_EXT))
-                                       apdu.le <<= 8;
-                               apdu.cse = SC_APDU_CASE_2_SHORT | cse;
-                       }
-                       else {
-                               apdu.lc = size;
-                               if (len < apdu.lc) {
-                                       printf("APDU too short (need %lu 
bytes)\n",
-                                               (unsigned long) apdu.lc - len);
-                                       return 1;
-                               }
-                               memcpy(sbuf, p, apdu.lc);
-                               apdu.data = sbuf;
-                               apdu.datalen = apdu.lc;
-                               len -= apdu.lc;
-                               p += apdu.lc;
-                               if (len == 0) {
-                                       apdu.cse = SC_APDU_CASE_3_SHORT | cse;
-                               }
-                               else {
-                                       apdu.le = 0;
-                                       if (cse & SC_APDU_EXT) {
-                                               if (len < 2) {
-                                                       printf("APDU too short 
(need %lu bytes)\n",
-                                                               (unsigned long) 
apdu.lc - len);
-                                                       return 1;
-                                               }
-                                               size = (*p++) << 8;
-                                               size += *p++;
-                                               len -= 2;
-                                               apdu.le = (size == 0) ? 65536 : 
size;
-                                       }
-                                       else {
-                                               size = *p++;
-                                               len--;
-                                               apdu.le = (size == 0) ? 256 : 
size;
-                                       }
-                                       apdu.cse = SC_APDU_CASE_4_SHORT | cse;
-                                       if (len) {
-                                               printf("APDU too long (%lu 
bytes extra)\n",
-                                                       (unsigned long) len);
-                                               return 1;
-                                       }
-                               }
-                       }
-               }
-
                printf("Sending: ");
                for (r = 0; r < len0; r++)
                        printf("%02X ", buf[r]);
Index: src/tools/piv-tool.c
===================================================================
--- src/tools/piv-tool.c        (Revision 5378)
+++ src/tools/piv-tool.c        (Arbeitskopie)
@@ -529,75 +529,24 @@
 static int send_apdu(void)
 {
        sc_apdu_t apdu;
-       u8 buf[SC_MAX_APDU_BUFFER_SIZE+3], sbuf[SC_MAX_APDU_BUFFER_SIZE];
-       u8 rbuf[8192], *p;
-       size_t len, len0, r;
+       u8 buf[SC_MAX_APDU_BUFFER_SIZE+3];
+       u8 rbuf[8192];
+       size_t len0, r;
        int c;
 
        for (c = 0; c < opt_apdu_count; c++) {
                len0 = sizeof(buf);
                sc_hex_to_bin(opt_apdus[c], buf, &len0);
-               if (len0 > SC_MAX_APDU_BUFFER_SIZE+2) {
-                       fprintf(stderr, "APDU too long, (must be at most %d 
bytes).\n",
-                               SC_MAX_APDU_BUFFER_SIZE+2);
-                               return 2;
-               }
-               if (len0 < 4) {
-                       fprintf(stderr, "APDU too short (must be at least 4 
bytes).\n");
+
+               r = sc_bytes2apdu(card->ctx, buf, len0, &apdu);
+               if (r) {
+                       fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r));
                        return 2;
                }
-               len = len0;
-               p = buf;
-               /* TODO: move this to apdu.c as bytes2apdu or similar. See #237 
*/
-               memset(&apdu, 0, sizeof(apdu));
-               apdu.cla = *p++;
-               apdu.ins = *p++;
-               apdu.p1 = *p++;
-               apdu.p2 = *p++;
+
                apdu.resp = rbuf;
                apdu.resplen = sizeof(rbuf);
-               len -= 4;
-               if (len > 1) {
-                       apdu.lc = *p++;
-                       len--;
-                       memcpy(sbuf, p, apdu.lc);
-                       apdu.data = sbuf;
-                       apdu.datalen = apdu.lc;
-                       if (len < apdu.lc) {
-                               fprintf(stderr, "APDU too short (need %lu 
bytes).\n",
-                                       (unsigned long) apdu.lc-len);
-                               return 2;
-                       }
-                       len -= apdu.lc;
-                       if (len) {
-                               apdu.le = *p++;
-                               if (apdu.le == 0)
-                                       apdu.le = 256;
-                               len--;
-                               apdu.cse = SC_APDU_CASE_4_SHORT;
-                       } else
-                               apdu.cse = SC_APDU_CASE_3_SHORT;
-                       if (len) {
-                               fprintf(stderr, "APDU too long (%lu bytes 
extra).\n", (unsigned long)len);
-                               return 2;
-                       }
-               } else if (len == 1) {
-                       apdu.le = *p++;
-                       if (apdu.le == 0)
-                               apdu.le = 256;
-                       len--;
-                       apdu.cse = SC_APDU_CASE_2_SHORT;
-               } else
-                       apdu.cse = SC_APDU_CASE_1;
-               printf("Sending: ");
-               for (r = 0; r < len0; r++)
-                       printf("%02X ", buf[r]);
-               printf("\n");
-               r = sc_transmit_apdu(card, &apdu);
-               if (r) {
-                       fprintf(stderr, "APDU transmit failed: %s\n", 
sc_strerror(r));
-                       return 1;
-               }
+
                printf("Received (SW1=0x%02X, SW2=0x%02X)%s\n", apdu.sw1, 
apdu.sw2,
                       apdu.resplen ? ":" : "");
                if (apdu.resplen)
Index: src/tools/opensc-explorer.c
===================================================================
--- src/tools/opensc-explorer.c (Revision 5378)
+++ src/tools/opensc-explorer.c (Arbeitskopie)
@@ -1298,11 +1298,8 @@
 {
        sc_apdu_t apdu;
        u8 buf[SC_MAX_APDU_BUFFER_SIZE];
-       u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
-       u8 *p;
        size_t len, len0, r, ii;
-       int cse = 0;
 
        if (argc < 1) {
                puts("Usage: apdu [apdu:hex:codes:...]");
@@ -1315,86 +1312,12 @@
                len += len0;
        }
 
-       if (len < 4) {
-               puts("APDU too short (must be at least 4 bytes)");
-               return 1;
+       r = sc_bytes2apdu(card->ctx, buf, len, &apdu);
+       if (r) {
+               fprintf(stderr, "Invalid APDU: %s\n", sc_strerror(r));
+               return 2;
        }
-       len0 = len;
 
-       /* TODO: move this to apdu.c as bytes2apdu or similar. See #237 */
-       memset(&apdu, 0, sizeof(apdu));
-       p = buf;
-       apdu.cla = *p++;
-       apdu.ins = *p++;
-       apdu.p1 = *p++;
-       apdu.p2 = *p++;
-       len -= 4;
-
-       if (len == 0) {
-               apdu.cse = SC_APDU_CASE_1;
-       }
-       else {
-               size_t size = 0;
-
-               if ((*p == 0) && (len >= 3)) {
-                       cse |= SC_APDU_EXT;
-                       p++;
-                       size = (*p++) << 8;
-                       size += *p++;
-                       len -= 3;
-               }
-               else {
-                       size = *p++;
-                       len--;
-               }
-               if (len == 0) {
-                       apdu.le = (size == 0) ? 256 : size;
-                       if ((apdu.le == 0) && (cse & SC_APDU_EXT))
-                               apdu.le <<= 8;
-                       apdu.cse = SC_APDU_CASE_2_SHORT | cse;
-               }
-               else {
-                       apdu.lc = size;
-                       if (len < apdu.lc) {
-                               printf("APDU too short (need %lu bytes)\n",
-                                       (unsigned long) apdu.lc - len);
-                               return 1;
-                       }
-                       memcpy(sbuf, p, apdu.lc);
-                       apdu.data = sbuf;
-                       apdu.datalen = apdu.lc;
-                       len -= apdu.lc;
-                       p += apdu.lc;
-                       if (len == 0) {
-                               apdu.cse = SC_APDU_CASE_3_SHORT | cse;
-                       }
-                       else {
-                               apdu.le = 0;
-                               if (cse & SC_APDU_EXT) {
-                                       if (len < 2) {
-                                               printf("APDU too short (need 
%lu bytes)\n",
-                                                       (unsigned long) apdu.lc 
- len);
-                                               return 1;
-                                       }
-                                       size = (*p++) << 8;
-                                       size += *p++;
-                                       len -= 2;
-                                       apdu.le = (size == 0) ? 65536 : size;
-                               }
-                               else {
-                                       size = *p++;
-                                       len--;
-                                       apdu.le = (size == 0) ? 256 : size;
-                               }
-                               apdu.cse = SC_APDU_CASE_4_SHORT | cse;
-                               if (len) {
-                                       printf("APDU too long (%lu bytes 
extra)\n",
-                                               (unsigned long) len);
-                                       return 1;
-                               }
-                       }
-               }
-       }
        apdu.resp = rbuf;
        apdu.resplen = sizeof(rbuf);
 
Index: src/libopensc/libopensc.exports
===================================================================
--- src/libopensc/libopensc.exports     (Revision 5378)
+++ src/libopensc/libopensc.exports     (Arbeitskopie)
@@ -95,6 +95,7 @@
 sc_file_set_type_attr
 sc_file_valid
 sc_format_apdu
+sc_bytes2apdu
 sc_format_asn1_entry
 sc_format_oid
 sc_format_path
Index: src/libopensc/apdu.c
===================================================================
--- src/libopensc/apdu.c        (Revision 5378)
+++ src/libopensc/apdu.c        (Arbeitskopie)
@@ -606,3 +606,116 @@
 
        return r;
 }
+
+int sc_bytes2apdu(sc_context_t *ctx, const u8 *buf, size_t len, sc_apdu_t 
*apdu)
+{
+    const u8 *p;
+    size_t len0;
+
+    if (!buf || !apdu)
+        return SC_ERROR_INVALID_ARGUMENTS;
+
+    len0 = len;
+    if (len < 4) {
+        sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "APDU too short (must be at least 
4 bytes)");
+        return SC_ERROR_INVALID_DATA;
+    }
+
+    memset(apdu, 0, sizeof *apdu);
+    p = buf;
+    apdu->cla = *p++;
+    apdu->ins = *p++;
+    apdu->p1 = *p++;
+    apdu->p2 = *p++;
+    len -= 4;
+    if (!len) {
+        apdu->cse = SC_APDU_CASE_1;
+    } else {
+        if (*p == 0 && len >= 3) {
+            /* ...must be an extended APDU */
+            p++;
+            if (len == 3) {
+                apdu->le = (*p++)<<8;
+                apdu->le += *p++;
+                if (apdu->le == 0)
+                    apdu->le = 0xffff+1;
+                len -= 3;
+                apdu->cse = SC_APDU_CASE_2_EXT;
+            } else {
+                /* len > 3 */
+                apdu->lc = (*p++)<<8;
+                apdu->lc += *p++;
+                len -= 3;
+                if (len < apdu->lc) {
+                    sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "APDU too short (need 
%lu more bytes)\n",
+                            (unsigned long) apdu->lc - len);
+                    return SC_ERROR_INVALID_DATA;
+                }
+                apdu->data = p;
+                apdu->datalen = apdu->lc;
+                len -= apdu->lc;
+                p += apdu->lc;
+                if (!len) {
+                    apdu->cse = SC_APDU_CASE_3_EXT;
+                } else {
+                    /* at this point the apdu has a Lc, so Le is on 2 bytes */
+                    if (len < 2) {
+                        sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "APDU too short 
(need 2 more bytes)\n");
+                        return SC_ERROR_INVALID_DATA;
+                    }
+                    apdu->le = (*p++)<<8;
+                    apdu->le += *p++;
+                    if (apdu->le == 0)
+                        apdu->le = 0xffff+1;
+                    len -= 2;
+                    apdu->cse = SC_APDU_CASE_4_EXT;
+                }
+            }
+        } else {
+            /* ...must be a short APDU */
+            if (len == 1) {
+                apdu->le = *p++;
+                if (apdu->le == 0)
+                    apdu->le = 0xff+1;
+                len--;
+                apdu->cse = SC_APDU_CASE_2_SHORT;
+            } else {
+                apdu->lc = *p++;
+                len--;
+                if (len < apdu->lc) {
+                    sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "APDU too short (need 
%lu more bytes)\n",
+                            (unsigned long) apdu->lc - len);
+                    return SC_ERROR_INVALID_DATA;
+                }
+                apdu->data = p;
+                apdu->datalen = apdu->lc;
+                len -= apdu->lc;
+                p += apdu->lc;
+                if (!len) {
+                    apdu->cse = SC_APDU_CASE_3_SHORT;
+                } else {
+                    apdu->le = *p++;
+                    if (apdu->le == 0)
+                        apdu->le = 0xff+1;
+                    len--;
+                    apdu->cse = SC_APDU_CASE_4_SHORT;
+
+                }
+            }
+        }
+        if (len) {
+            sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "APDU too long (%lu bytes 
extra)\n",
+                    (unsigned long) len);
+            return SC_ERROR_INVALID_DATA;
+        }
+    }
+
+    apdu->flags = SC_APDU_FLAGS_NO_GET_RESP|SC_APDU_FLAGS_NO_RETRY_WL;
+
+    sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Case %d %s APDU, %lu bytes:\tins=%02x 
p1=%02x p2=%02x lc=%04x le=%04x",
+            apdu->cse & SC_APDU_SHORT_MASK,
+            (apdu->cse & SC_APDU_EXT) != 0 ? "extended" : "short",
+            (unsigned long) len0, apdu->ins, apdu->p1, apdu->p2, apdu->lc, 
apdu->le);
+
+    return SC_SUCCESS;
+}
Index: src/libopensc/opensc.h
===================================================================
--- src/libopensc/opensc.h      (Revision 5378)
+++ src/libopensc/opensc.h      (Arbeitskopie)
@@ -654,6 +654,20 @@
 void sc_format_apdu(sc_card_t *card, sc_apdu_t *apdu, int cse, int ins,
                    int p1, int p2);
 
+/** Transforms an APDU from binary to its @c sc_apdu_t representation
+ *  @param  ctx     sc_context_t object (used for logging)
+ *  @param  buf     APDU to be encoded as an @c sc_apdu_t object
+ *  @param  len     length of @a buf
+ *  @param  apdu    @c sc_apdu_t object to initialize
+ *  @return SC_SUCCESS on success and an error code otherwise
+ *  @note On successful initialization apdu->data will point to @a buf with an
+ *  appropriate offset. Only free() @a buf, when apdu->data is not needed any
+ *  longer.
+ *  @note On successful initialization @a apdu->resp and apdu->resplen will be
+ *  0. You should modify both if you are expecting data in the response APDU.
+ */
+int sc_bytes2apdu(sc_context_t *ctx, const u8 *buf, size_t len, sc_apdu_t 
*apdu);
+
 int sc_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2);
 
 /********************************************************************/

Attachment: pgpQDoTJPcFoJ.pgp
Description: PGP signature

_______________________________________________
opensc-devel mailing list
opensc-devel@lists.opensc-project.org
http://www.opensc-project.org/mailman/listinfo/opensc-devel

Reply via email to