Nuked almost all trailing white space.
[gnupg.git] / scd / atr.c
index bd5a226..16f26fb 100644 (file)
--- a/scd/atr.c
+++ b/scd/atr.c
@@ -5,7 +5,7 @@
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,9 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
@@ -35,7 +33,7 @@ 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 di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
                                   0, -1, -2, -4, -8, -16, -32, -64};
                                   -1, 512, 768, 1024, 1536, 2048, -1, -1 };
 static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
                                   0, -1, -2, -4, -8, -16, -32, -64};
-                                  
+
 
 /* Dump the ATR of the card at SLOT in a human readable format to
    stream FP.  */
 
 /* Dump the ATR of the card at SLOT in a human readable format to
    stream FP.  */
@@ -52,7 +50,7 @@ atr_dump (int slot, FILE *fp)
   atr = atrbuffer = apdu_get_atr (slot, &atrlen);
   if (!atr)
     return gpg_error (GPG_ERR_GENERAL);
   atr = atrbuffer = apdu_get_atr (slot, &atrlen);
   if (!atr)
     return gpg_error (GPG_ERR_GENERAL);
-  
+
   fprintf (fp, "Info on ATR of length %u at slot %d\n",
            (unsigned int)atrlen, slot);
   if (!atrlen)
   fprintf (fp, "Info on ATR of length %u at slot %d\n",
            (unsigned int)atrlen, slot);
   if (!atrlen)
@@ -61,7 +59,7 @@ atr_dump (int slot, FILE *fp)
       goto bailout;
     }
 
       goto bailout;
     }
 
-  
+
   if (*atr == 0x3b)
     fputs ("direct convention\n", fp);
   else if (*atr == 0x3f)
   if (*atr == 0x3b)
     fputs ("direct convention\n", fp);
   else if (*atr == 0x3f)
@@ -100,21 +98,21 @@ atr_dump (int slot, FILE *fp)
       else
         fprintf (fp, "%d", val);
       fputs (" D=", fp);
       else
         fprintf (fp, "%d", val);
       fputs (" D=", fp);
-      val = di_table[*atr & 0x0f]; 
+      val = di_table[*atr & 0x0f];
       if (!val)
         fputs ("[impossible value]\n", fp);
       else if (val == -1)
         fputs ("RFU\n", fp);
       else if (val < 0 )
         fprintf (fp, "1/%d\n", val);
       if (!val)
         fputs ("[impossible value]\n", fp);
       else if (val == -1)
         fputs ("RFU\n", fp);
       else if (val < 0 )
         fprintf (fp, "1/%d\n", val);
-      else 
+      else
         fprintf (fp, "%d\n", val);
         fprintf (fp, "%d\n", val);
-      
+
       if (!--atrlen)
         goto bailout;
       atr++;
     }
       if (!--atrlen)
         goto bailout;
       atr++;
     }
-     
+
   if (have_tb)
     {
       fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
   if (have_tb)
     {
       fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
@@ -251,7 +249,7 @@ atr_dump (int slot, FILE *fp)
   if (n_historical + 1 > atrlen)
     fputs ("error: ATR shorter than required for historical bytes "
            "and checksum\n", fp);
   if (n_historical + 1 > atrlen)
     fputs ("error: ATR shorter than required for historical bytes "
            "and checksum\n", fp);
-  
+
   if (n_historical)
     {
       fputs ("Historical:", fp);
   if (n_historical)
     {
       fputs ("Historical:", fp);
@@ -279,10 +277,120 @@ atr_dump (int slot, FILE *fp)
 }
 
 
 }
 
 
+/* 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)
+    {
+      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;
 
 
+  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;
+}