scd: Add option --dump-atr to command APDU.
authorWerner Koch <wk@gnupg.org>
Thu, 15 Dec 2011 13:47:04 +0000 (14:47 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 15 Dec 2011 14:21:02 +0000 (15:21 +0100)
* scd/atr.c: Rewrite.
* scd/Makefile.am (scdaemon_SOURCES): Add atr.c and atr.h.
* scd/command.c (cmd_apdu): Add option --dump-atr.

scd/Makefile.am
scd/atr.c
scd/atr.h
scd/command.c

index bdd457a..b42e53d 100644 (file)
@@ -37,6 +37,7 @@ card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c app-geldkarte.c
 scdaemon_SOURCES = \
        scdaemon.c scdaemon.h \
        command.c \
 scdaemon_SOURCES = \
        scdaemon.c scdaemon.h \
        command.c \
+       atr.c atr.h \
        apdu.c apdu.h \
        ccid-driver.c ccid-driver.h \
        iso7816.c iso7816.h \
        apdu.c apdu.h \
        ccid-driver.c ccid-driver.h \
        iso7816.c iso7816.h \
index 16f26fb..b8668a4 100644 (file)
--- a/scd/atr.c
+++ b/scd/atr.c
@@ -1,5 +1,5 @@
 /* atr.c - ISO 7816 ATR fucntions
 /* atr.c - ISO 7816 ATR fucntions
- *     Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <assert.h>
 
 #include <string.h>
 #include <assert.h>
 
-#include "scdaemon.h"
-#include "apdu.h"
+#include "../common/estream.h"
+#include "../common/logging.h"
 #include "atr.h"
 #include "atr.h"
-#include "dynload.h"
 
 static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
                                   -1, 512, 768, 1024, 1536, 2048, -1, -1 };
 
 static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
                                   -1, 512, 768, 1024, 1536, 2048, -1, -1 };
@@ -35,37 +34,42 @@ static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
                                   0, -1, -2, -4, -8, -16, -32, -64};
 
 
                                   0, -1, -2, -4, -8, -16, -32, -64};
 
 
-/* Dump the ATR of the card at SLOT in a human readable format to
-   stream FP.  */
-int
-atr_dump (int slot, FILE *fp)
+/* Dump the ATR in (BUFFER,BUFLEN) to a human readable format and
+   return that as a malloced buffer.  The caller must release this
+   buffer using es_free!  On error this function returns NULL and sets
+   ERRNO.  */
+char *
+atr_dump (const void *buffer, size_t buflen)
 {
 {
-  unsigned char *atrbuffer, *atr;
-  size_t atrlen;
+  const unsigned char *atr = buffer;
+  size_t atrlen = buflen;
+  estream_t fp;
   int have_ta, have_tb, have_tc, have_td;
   int n_historical;
   int idx, val;
   unsigned char chksum;
   int have_ta, have_tb, have_tc, have_td;
   int n_historical;
   int idx, val;
   unsigned char chksum;
+  char *result;
 
 
-  atr = atrbuffer = apdu_get_atr (slot, &atrlen);
-  if (!atr)
-    return gpg_error (GPG_ERR_GENERAL);
+  fp = es_fopenmem (0, "rwb");
+  if (!fp)
+    return NULL;
 
 
-  fprintf (fp, "Info on ATR of length %u at slot %d\n",
-           (unsigned int)atrlen, slot);
   if (!atrlen)
     {
   if (!atrlen)
     {
-      fprintf (fp, "error: empty ATR\n");
+      es_fprintf (fp, "error: empty ATR\n");
       goto bailout;
     }
 
       goto bailout;
     }
 
+  for (idx=0; idx < atrlen ; idx++)
+    es_fprintf (fp, "%s%02X", idx?" ":"", atr[idx]);
+  es_putc ('\n', fp);
 
   if (*atr == 0x3b)
 
   if (*atr == 0x3b)
-    fputs ("direct convention\n", fp);
+    es_fputs ("Direct convention\n", fp);
   else if (*atr == 0x3f)
   else if (*atr == 0x3f)
-    fputs ("inverse convention\n", fp);
+    es_fputs ("Inverse convention\n", fp);
   else
   else
-    fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
+    es_fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
   if (!--atrlen)
     goto bailout;
   atr++;
   if (!--atrlen)
     goto bailout;
   atr++;
@@ -79,34 +83,34 @@ atr_dump (int slot, FILE *fp)
   have_tc = !!(*atr & 0x40);
   have_td = !!(*atr & 0x80);
   n_historical = (*atr & 0x0f);
   have_tc = !!(*atr & 0x40);
   have_td = !!(*atr & 0x80);
   n_historical = (*atr & 0x0f);
-  fprintf (fp, "%d historical characters indicated\n", n_historical);
+  es_fprintf (fp, "%d historical characters indicated\n", n_historical);
 
   if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
 
   if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
-    fputs ("error: ATR shorter than indicated by format character\n", fp);
+    es_fputs ("error: ATR shorter than indicated by format character\n", fp);
   if (!--atrlen)
     goto bailout;
   atr++;
 
   if (have_ta)
     {
   if (!--atrlen)
     goto bailout;
   atr++;
 
   if (have_ta)
     {
-      fputs ("TA1: F=", fp);
+      es_fputs ("TA1: F=", fp);
       val = fi_table[(*atr >> 4) & 0x0f];
       if (!val)
       val = fi_table[(*atr >> 4) & 0x0f];
       if (!val)
-        fputs ("internal clock", fp);
+        es_fputs ("internal clock", fp);
       else if (val == -1)
       else if (val == -1)
-        fputs ("RFU", fp);
+        es_fputs ("RFU", fp);
       else
       else
-        fprintf (fp, "%d", val);
-      fputs (" D=", fp);
+        es_fprintf (fp, "%d", val);
+      es_fputs (" D=", fp);
       val = di_table[*atr & 0x0f];
       if (!val)
       val = di_table[*atr & 0x0f];
       if (!val)
-        fputs ("[impossible value]\n", fp);
+        es_fputs ("[impossible value]\n", fp);
       else if (val == -1)
       else if (val == -1)
-        fputs ("RFU\n", fp);
+        es_fputs ("RFU\n", fp);
       else if (val < 0 )
       else if (val < 0 )
-        fprintf (fp, "1/%d\n", val);
+        es_fprintf (fp, "1/%d\n", val);
       else
       else
-        fprintf (fp, "%d\n", val);
+        es_fprintf (fp, "%d\n", val);
 
       if (!--atrlen)
         goto bailout;
 
       if (!--atrlen)
         goto bailout;
@@ -115,8 +119,9 @@ atr_dump (int slot, FILE *fp)
 
   if (have_tb)
     {
 
   if (have_tb)
     {
-      fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
-               (*atr & 0x80)? " [high bit not cleared]":"");
+      es_fprintf (fp, "TB1: II=%d PI1=%d%s\n",
+                  ((*atr >> 5) & 3), (*atr & 0x1f),
+                  (*atr & 0x80)? " [high bit not cleared]":"");
       if (!--atrlen)
         goto bailout;
       atr++;
       if (!--atrlen)
         goto bailout;
       atr++;
@@ -125,9 +130,9 @@ atr_dump (int slot, FILE *fp)
   if (have_tc)
     {
       if (*atr == 255)
   if (have_tc)
     {
       if (*atr == 255)
-        fputs ("TC1: guard time shortened to 1 etu\n", fp);
+        es_fputs ("TC1: guard time shortened to 1 etu\n", fp);
       else
       else
-        fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
+        es_fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
 
       if (!--atrlen)
         goto bailout;
 
       if (!--atrlen)
         goto bailout;
@@ -140,10 +145,11 @@ atr_dump (int slot, FILE *fp)
       have_tb = !!(*atr & 0x20);
       have_tc = !!(*atr & 0x40);
       have_td = !!(*atr & 0x80);
       have_tb = !!(*atr & 0x20);
       have_tc = !!(*atr & 0x40);
       have_td = !!(*atr & 0x80);
-      fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
+      es_fprintf (fp, "TD1: protocol T%d supported\n", (*atr & 0x0f));
 
       if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
 
       if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
-        fputs ("error: ATR shorter than indicated by format character\n", fp);
+        es_fputs ("error: ATR shorter than indicated by format character\n",
+                  fp);
 
       if (!--atrlen)
         goto bailout;
 
       if (!--atrlen)
         goto bailout;
@@ -154,12 +160,12 @@ atr_dump (int slot, FILE *fp)
 
   if (have_ta)
     {
 
   if (have_ta)
     {
-      fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
-               (*atr & 0x80)? "no-":"",
-               (*atr & 0x10)? "im": "ex",
-               (*atr & 0x0f));
+      es_fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
+                  (*atr & 0x80)? "no-":"",
+                  (*atr & 0x10)? "im": "ex",
+                  (*atr & 0x0f));
       if ((*atr & 0x60))
       if ((*atr & 0x60))
-        fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
+        es_fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
       if (!--atrlen)
         goto bailout;
       atr++;
       if (!--atrlen)
         goto bailout;
       atr++;
@@ -167,7 +173,7 @@ atr_dump (int slot, FILE *fp)
 
   if (have_tb)
     {
 
   if (have_tb)
     {
-      fprintf (fp, "TB2: PI2=%d\n", *atr);
+      es_fprintf (fp, "TB2: PI2=%d\n", *atr);
       if (!--atrlen)
         goto bailout;
       atr++;
       if (!--atrlen)
         goto bailout;
       atr++;
@@ -175,7 +181,7 @@ atr_dump (int slot, FILE *fp)
 
   if (have_tc)
     {
 
   if (have_tc)
     {
-      fprintf (fp, "TC2: PWI=%d\n", *atr);
+      es_fprintf (fp, "TC2: PWI=%d\n", *atr);
       if (!--atrlen)
         goto bailout;
       atr++;
       if (!--atrlen)
         goto bailout;
       atr++;
@@ -187,10 +193,11 @@ atr_dump (int slot, FILE *fp)
       have_tb = !!(*atr & 0x20);
       have_tc = !!(*atr & 0x40);
       have_td = !!(*atr & 0x80);
       have_tb = !!(*atr & 0x20);
       have_tc = !!(*atr & 0x40);
       have_td = !!(*atr & 0x80);
-      fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
+      es_fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
 
       if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
 
       if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
-        fputs ("error: ATR shorter than indicated by format character\n", fp);
+        es_fputs ("error: ATR shorter than indicated by format character\n",
+                  fp);
 
       if (!--atrlen)
         goto bailout;
 
       if (!--atrlen)
         goto bailout;
@@ -203,7 +210,7 @@ atr_dump (int slot, FILE *fp)
     {
       if (have_ta)
         {
     {
       if (have_ta)
         {
-          fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
+          es_fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
           if (!--atrlen)
             goto bailout;
           atr++;
           if (!--atrlen)
             goto bailout;
           atr++;
@@ -211,7 +218,7 @@ atr_dump (int slot, FILE *fp)
 
       if (have_tb)
         {
 
       if (have_tb)
         {
-          fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
+          es_fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
                    idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
           if (!--atrlen)
             goto bailout;
                    idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
           if (!--atrlen)
             goto bailout;
@@ -220,7 +227,7 @@ atr_dump (int slot, FILE *fp)
 
       if (have_tc)
         {
 
       if (have_tc)
         {
-          fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
+          es_fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
           if (!--atrlen)
             goto bailout;
           atr++;
           if (!--atrlen)
             goto bailout;
           atr++;
@@ -232,11 +239,12 @@ atr_dump (int slot, FILE *fp)
           have_tb = !!(*atr & 0x20);
           have_tc = !!(*atr & 0x40);
           have_td = !!(*atr & 0x80);
           have_tb = !!(*atr & 0x20);
           have_tc = !!(*atr & 0x40);
           have_td = !!(*atr & 0x80);
-          fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
+          es_fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
 
           if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
 
           if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
-            fputs ("error: ATR shorter than indicated by format character\n",
-                   fp);
+            es_fputs ("error: "
+                      "ATR shorter than indicated by format character\n",
+                      fp);
 
           if (!--atrlen)
             goto bailout;
 
           if (!--atrlen)
             goto bailout;
@@ -247,150 +255,36 @@ atr_dump (int slot, FILE *fp)
     }
 
   if (n_historical + 1 > atrlen)
     }
 
   if (n_historical + 1 > atrlen)
-    fputs ("error: ATR shorter than required for historical bytes "
-           "and checksum\n", fp);
+    es_fputs ("error: ATR shorter than required for historical bytes "
+              "and checksum\n", fp);
 
   if (n_historical)
     {
 
   if (n_historical)
     {
-      fputs ("Historical:", fp);
+      es_fputs ("HCH:", fp);
       for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
       for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
-        fprintf (fp, " %02X", *atr);
-      putchar ('\n');
+        es_fprintf (fp, " %02X", *atr);
+      es_putc ('\n', fp);
     }
 
   if (!atrlen)
     }
 
   if (!atrlen)
-    fputs ("error: checksum missing\n", fp);
+    es_fputs ("error: checksum missing\n", fp);
   else if (*atr == chksum)
   else if (*atr == chksum)
-    fprintf (fp, "TCK: %02X (good)\n", *atr);
+    es_fprintf (fp, "TCK: %02X (good)\n", *atr);
   else
   else
-    fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
+    es_fprintf (fp, "TCK: %02X (bad; computed %02X)\n", *atr, chksum);
 
   atrlen--;
   if (atrlen)
 
   atrlen--;
   if (atrlen)
-    fprintf (fp, "error: %u bytes garbage at end of ATR\n",
-             (unsigned int)atrlen );
+    es_fprintf (fp, "error: %u bytes garbage at end of ATR\n",
+                (unsigned int)atrlen );
 
  bailout:
 
  bailout:
-  xfree (atrbuffer);
-
-  return 0;
-}
-
-
-/* Note: This code has not yet been tested!  It shall return -1 on
-   error or the number of historical bytes and store them at
-   HISTORICAL.  */
-int
-atr_get_historical (int slot, unsigned char historical[])
-{
-  int result = -1;
-  unsigned char *atrbuffer = NULL;
-  unsigned char *atr;
-  size_t atrlen;
-  int have_ta, have_tb, have_tc, have_td;
-  int n_historical;
-  int idx;
-  unsigned char chksum;
-
-  atr = atrbuffer = apdu_get_atr (slot, &atrlen);
-  if (!atr || atrlen < 2)
-    goto leave;
-  atrlen--;
-  atr++;
-
-  chksum = *atr;
-  for (idx=1; idx < atrlen-1; idx++)
-    chksum ^= atr[idx];
-
-  have_ta = !!(*atr & 0x10);
-  have_tb = !!(*atr & 0x20);
-  have_tc = !!(*atr & 0x40);
-  have_td = !!(*atr & 0x80);
-  n_historical = (*atr & 0x0f);
-
-  if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
-    goto leave; /* ATR shorter than indicated by format character.  */
-  atrlen--;
-  atr++;
-
-  if (have_ta + have_tb + have_tc >= atrlen)
-    goto leave;
-  atrlen -= have_ta + have_tb + have_tc;
-  atr    += have_ta + have_tb + have_tc;
-
-  if (have_td)
-    {
-      have_ta = !!(*atr & 0x10);
-      have_tb = !!(*atr & 0x20);
-      have_tc = !!(*atr & 0x40);
-      have_td = !!(*atr & 0x80);
-      if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
-        goto leave; /* ATR shorter than indicated by format character.  */
-      atrlen--;
-      atr++;
-    }
-  else
-    have_ta = have_tb = have_tc = have_td = 0;
-
-  if (have_ta + have_tb + have_tc >= atrlen)
-    goto leave;
-  atrlen -= have_ta + have_tb + have_tc;
-  atr    += have_ta + have_tb + have_tc;
-
-  if (have_td)
+  es_putc ('\0', fp); /* We want a string.  */
+  if (es_fclose_snatch (fp, (void**)&result, NULL))
     {
     {
-      have_ta = !!(*atr & 0x10);
-      have_tb = !!(*atr & 0x20);
-      have_tc = !!(*atr & 0x40);
-      have_td = !!(*atr & 0x80);
-      if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
-        goto leave; /* ATR shorter than indicated by format character.  */
-      atrlen--;
-      atr++;
+      log_error ("oops: es_fclose_snatch failed: %s\n", strerror (errno));
+      return NULL;
     }
     }
-  else
-    have_ta = have_tb = have_tc = have_td = 0;
-
-  for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
-    {
-      if (have_ta + have_tb + have_tc >= atrlen)
-        goto leave;
-      atrlen -= have_ta + have_tb + have_tc;
-      atr    += have_ta + have_tb + have_tc;
-
-      if (have_td)
-        {
-          have_ta = !!(*atr & 0x10);
-          have_tb = !!(*atr & 0x20);
-          have_tc = !!(*atr & 0x40);
-          have_td = !!(*atr & 0x80);
-          if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
-            goto leave; /* ATR shorter than indicated by format character.  */
-          atrlen--;
-          atr++;
-        }
-      else
-        have_ta = have_tb = have_tc = have_td = 0;
-    }
-
-  if (n_historical >= atrlen)
-    goto leave; /* ATR shorter than required for historical bytes. */
-
-  if (n_historical)
-    {
-      for (idx=0; n_historical && atrlen; n_historical--, atrlen--, atr++)
-        historical[idx] = *atr;
-    }
-
-  if (!atrlen || *atr != chksum)
-    goto leave;
-
-  /* Don't care about garbage at the end of the ATR.  */
-
-  result = n_historical;
-
- leave:
-  xfree (atrbuffer);
 
   return result;
 }
 
   return result;
 }
index 5f07522..b06a83a 100644 (file)
--- a/scd/atr.h
+++ b/scd/atr.h
@@ -20,7 +20,7 @@
 #ifndef ATR_H
 #define ATR_H
 
 #ifndef ATR_H
 #define ATR_H
 
-int atr_dump (int slot, FILE *fp);
+char *atr_dump (const void *buffer, size_t buflen);
 
 
 
 
 
 
index 0f57448..afd5ef2 100644 (file)
 #include <ksba.h>
 #include "app-common.h"
 #include "apdu.h" /* Required for apdu_*_reader (). */
 #include <ksba.h>
 #include "app-common.h"
 #include "apdu.h" /* Required for apdu_*_reader (). */
+#include "atr.h"
 #include "exechelp.h"
 #ifdef HAVE_LIBUSB
 #include "ccid-driver.h"
 #endif
 
 #include "exechelp.h"
 #ifdef HAVE_LIBUSB
 #include "ccid-driver.h"
 #endif
 
+
 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
 #define MAXLEN_PIN 100
 
 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
 #define MAXLEN_PIN 100
 
@@ -1795,7 +1797,7 @@ cmd_disconnect (assuan_context_t ctx, char *line)
 
 
 static const char hlp_apdu[] =
 
 
 static const char hlp_apdu[] =
-  "APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
+  "APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]\n"
   "\n"
   "Send an APDU to the current reader.  This command bypasses the high\n"
   "level functions and sends the data directly to the card.  HEXSTRING\n"
   "\n"
   "Send an APDU to the current reader.  This command bypasses the high\n"
   "level functions and sends the data directly to the card.  HEXSTRING\n"
@@ -1826,7 +1828,10 @@ cmd_apdu (assuan_context_t ctx, char *line)
   size_t exlen;
   int slot;
 
   size_t exlen;
   int slot;
 
-  with_atr = has_option (line, "--atr");
+  if (has_option (line, "--dump-atr"))
+    with_atr = 2;
+  else
+    with_atr = has_option (line, "--atr");
   handle_more = has_option (line, "--more");
 
   if ((s=has_option_name (line, "--exlen")))
   handle_more = has_option (line, "--more");
 
   if ((s=has_option_name (line, "--exlen")))
@@ -1861,9 +1866,32 @@ cmd_apdu (assuan_context_t ctx, char *line)
           rc = gpg_error (GPG_ERR_INV_CARD);
           goto leave;
         }
           rc = gpg_error (GPG_ERR_INV_CARD);
           goto leave;
         }
-      bin2hex (atr, atrlen, hexbuf);
+      if (with_atr == 2)
+        {
+          char *string, *p, *pend;
+
+          string = atr_dump (atr, atrlen);
+          if (string)
+            {
+              for (rc=0, p=string; !rc && (pend = strchr (p, '\n')); p = pend+1)
+                {
+                  rc = assuan_send_data (ctx, p, pend - p + 1);
+                  if (!rc)
+                    rc = assuan_send_data (ctx, NULL, 0);
+                }
+              if (!rc && *p)
+                rc = assuan_send_data (ctx, p, strlen (p));
+              es_free (string);
+              if (rc)
+                goto leave;
+            }
+        }
+      else
+        {
+          bin2hex (atr, atrlen, hexbuf);
+          send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
+        }
       xfree (atr);
       xfree (atr);
-      send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
     }
 
   apdu = hex_to_buffer (line, &apdulen);
     }
 
   apdu = hex_to_buffer (line, &apdulen);