*** empty log message ***
authorWerner Koch <wk@gnupg.org>
Tue, 16 Mar 2004 10:49:37 +0000 (10:49 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 16 Mar 2004 10:49:37 +0000 (10:49 +0000)
14 files changed:
scd/ChangeLog
scd/apdu.c
scd/app-nks.c
scd/app-openpgp.c
scd/app.c
scd/card-dinsig.c
scd/card-p15.c
scd/card.c
scd/ccid-driver.c
scd/command.c
scd/iso7816.c
scd/iso7816.h
scd/sc-investigate.c
scd/scdaemon.h

index 66ceebd..a9296cb 100644 (file)
@@ -1,3 +1,17 @@
+2004-03-11  Werner Koch  <wk@gnupg.org>
+
+       * scdaemon.h (out_of_core): Removed.  Replaced callers by standard
+       gpg_error function.
+
+       * apdu.c, iso7816.c, ccid-driver.c [GNUPG_SCD_MAIN_HEADER]: Allow
+       to include a header defined by the compiler.  This helps us to
+       reuse the source in other software.
+
+2004-03-10  Werner Koch  <wk@gnupg.org>
+
+       * iso7816.c (iso7816_read_record): New arg SHORT_EF.  Changed all
+       callers.
+
 2004-02-18  Werner Koch  <wk@gnupg.org>
 
        * sc-investigate.c (main): Setup the used character set.
index e5295f5..7843fd5 100644 (file)
@@ -28,7 +28,9 @@
 # include <opensc/opensc.h>
 #endif
 
-#if GNUPG_MAJOR_VERSION == 1
+#if defined(GNUPG_SCD_MAIN_HEADER)
+#include GNUPG_SCD_MAIN_HEADER
+#elif GNUPG_MAJOR_VERSION == 1
 /* This is used with GnuPG version < 1.9.  The code has been source
    copied from the current GnuPG >= 1.9  and is maintained over
    there. */
index 2ceb537..a4b6e3a 100644 (file)
@@ -130,10 +130,10 @@ keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
   err = iso7816_select_file (slot, fid, 0, NULL, NULL);
   if (err)
     return err;
-  err = iso7816_read_record (slot, 1, 1, &buffer[0], &buflen[0]);
+  err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]);
   if (err)
     return err;
-  err = iso7816_read_record (slot, 2, 1, &buffer[1], &buflen[1]);
+  err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]);
   if (err)
     {
       xfree (buffer[0]);
index 021d6a5..7782b8e 100644 (file)
@@ -245,7 +245,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
   n = 6 + 2 + mlen + 2 + elen;
   p = buffer = xtrymalloc (3 + n);
   if (!buffer)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
   
   *p++ = 0x99;     /* ctb */
   *p++ = n >> 8;   /* 2 byte length header */
index 6ac1827..d395fe5 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -47,7 +47,7 @@ select_application (ctrl_t ctrl, int slot, const char *name)
   app = xtrycalloc (1, sizeof *app);
   if (!app)
     {
-      rc = out_of_core ();
+      rc = gpg_error (gpg_err_code_from_errno (errno));
       log_info ("error allocating context: %s\n", gpg_strerror (rc));
       return NULL;
     }
index bb070d5..df09bfb 100644 (file)
@@ -141,7 +141,7 @@ dinsig_enum_keypairs (CARD card, int idx,
     {
       *keyid = xtrymalloc (17);
       if (!*keyid)
-        return out_of_core ();
+        return gpg_error (gpg_err_code_from_errno (errno));
       if (!idx)
         strcpy (*keyid, "DINSIG-DF01.C000");
       else
@@ -193,7 +193,7 @@ dinsig_read_cert (CARD card, const char *certidstr,
   buf = xtrymalloc (file->size);
   if (!buf)
     {
-      gpg_error_t tmperr = out_of_core ();
+      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
       sc_file_free (file);
       return tmperr;
     }
index 239e750..ae3ef14 100644 (file)
@@ -53,7 +53,7 @@ init_private_data (CARD card)
 
   priv = xtrycalloc (1, sizeof *priv);
   if (!priv)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
 
   /* OpenSC (0.7.0) is a bit strange in that the get_objects functions
      tries to be a bit too clever and implicitly does an enumeration
@@ -179,7 +179,7 @@ p15_enum_keypairs (CARD card, int idx,
 
       *keyid = p = xtrymalloc (9+pinfo->id.len*2+1);
       if (!*keyid)
-        return out_of_core ();
+        return gpg_error (gpg_err_code_from_errno (errno));
       p = stpcpy (p, "P15-5015.");
       for (i=0; i < pinfo->id.len; i++, p += 2)
         sprintf (p, "%02X", pinfo->id.value[i]);
@@ -217,7 +217,7 @@ p15_enum_certs (CARD card, int idx, char **certid, int *type)
 
       *certid = p = xtrymalloc (9+cinfo->id.len*2+1);
       if (!*certid)
-        return out_of_core ();
+        return gpg_error (gpg_err_code_from_errno (errno));
       p = stpcpy (p, "P15-5015.");
       for (i=0; i < cinfo->id.len; i++, p += 2)
         sprintf (p, "%02X", cinfo->id.value[i]);
@@ -304,7 +304,7 @@ p15_read_cert (CARD card, const char *certidstr,
   *cert = xtrymalloc (certder->data_len);
   if (!*cert)
     {
-      gpg_error_t tmperr = out_of_core ();
+      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
       sc_pkcs15_free_certificate (certder);
       return tmperr;
     }
@@ -400,7 +400,7 @@ p15_sign (CARD card, const char *keyidstr, int hashalgo,
   outbuflen = 1024; 
   outbuf = xtrymalloc (outbuflen);
   if (!outbuf)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
   
   rc = sc_pkcs15_compute_signature (card->p15card, keyobj,
                                     cryptflags,
@@ -462,7 +462,7 @@ p15_decipher (CARD card, const char *keyidstr,
   outbuflen = indatalen < 256? 256 : indatalen; 
   outbuf = xtrymalloc (outbuflen);
   if (!outbuf)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
 
   rc = sc_pkcs15_decipher (card->p15card, keyobj, 
                            0,
index 53c89f3..8366dcb 100644 (file)
@@ -108,7 +108,7 @@ card_open (CARD *rcard)
 
   card = xtrycalloc (1, sizeof *card);
   if (!card)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
   card->reader = 0;
   
   rc = sc_establish_context (&card->ctx, "scdaemon");
@@ -275,7 +275,7 @@ find_iccsn (const unsigned char *buffer, size_t length, char **serial)
 
   *serial = p = xtrymalloc (2*n+1);
   if (!*serial)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
   for (; n; n--, p += 2, s++)
     sprintf (p, "%02X", *s);
   *p = 0;
@@ -389,7 +389,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
       *serial = NULL;
       p = xtrymalloc (strlen (efser) + 7);
       if (!p)
-          rc = out_of_core ();
+          rc = gpg_error (gpg_err_code_from_errno (errno));
       else
         {
           strcpy (p, "FF0100");
@@ -405,7 +405,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
         {
           xfree (*serial);
           *serial = NULL;
-          rc = out_of_core ();
+          rc = gpg_error (gpg_err_code_from_errno (errno));
         }
       else
         {
index ca56201..b398e3c 100644 (file)
 #define DRVNAME "ccid-driver: "
 
 
-#ifdef GNUPG_MAJOR_VERSION  /* This source is used within GnuPG. */
+/* Depending on how this source is used we either define our error
+   output to go to stderr or to the jnlib based logging functions.  We
+   use the latter when GNUPG_MAJOR_VERSION is defines or when both,
+   GNUPG_SCD_MAIN_HEADER and HAVE_JNLIB_LOGGING are defined.
+*/
+#if defined(GNUPG_MAJOR_VERSION) \
+    || (defined(GNUPG_SCD_MAIN_HEADER) && defined(HAVE_JNLIB_LOGGING))
 
-# if GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */
+#if defined(GNUPG_SCD_MAIN_HEADER)
+#  include GNUPG_SCD_MAIN_HEADER
+#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */
 #  include "options.h"
 #  include "util.h"
 #  include "memory.h"
 #  include "cardglue.h"
 # else /* This is the modularized GnuPG 1.9 or later. */
 #  include "scdaemon.h"
-# endif
+#endif
 
 /* Disable all debugging output for now. */
 #undef DBG_CARD_IO
index d148ddb..4746e11 100644 (file)
@@ -351,7 +351,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
 
           buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
           if (!buf)
-            rc = out_of_core ();
+            rc = gpg_error (gpg_err_code_from_errno (errno));
           else
             {
               sprintf (buf, "%d %s", certtype, certid);
@@ -389,7 +389,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
 
           buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
           if (!buf)
-            rc = out_of_core ();
+            rc = gpg_error (gpg_err_code_from_errno (errno));
           else
             {
               int i;
@@ -577,7 +577,7 @@ pin_cb (void *opaque, const char *info, char **retstr)
 
   rc = asprintf (&command, "NEEDPIN %s", info);
   if (rc < 0)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
 
   /* FIXME: Write an inquire function which returns the result in
      secure memory */
index 1ee9b55..d7d3c12 100644 (file)
@@ -24,7 +24,9 @@
 #include <stdlib.h>
 #include <string.h>
 
-#if GNUPG_MAJOR_VERSION == 1
+#if defined(GNUPG_SCD_MAIN_HEADER)
+#include GNUPG_SCD_MAIN_HEADER
+#elif GNUPG_MAJOR_VERSION == 1
 /* This is used with GnuPG version < 1.9.  The code has been source
    copied from the current GnuPG >= 1.9  and is maintained over
    there. */
@@ -200,7 +202,7 @@ iso7816_change_reference_data (int slot, int chvno,
 
   buf = xtrymalloc (oldchvlen + newchvlen);
   if (!buf)
-    return out_of_core ();
+    return gpg_error (gpg_err_code_from_errno (errno));
   if (oldchvlen)
     memcpy (buf, oldchv, oldchvlen);
   memcpy (buf+oldchvlen, newchv, newchvlen);
@@ -341,7 +343,8 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
       /* We need to prepend the padding indicator. */
       buf = xtrymalloc (datalen + 1);
       if (!buf)
-        return out_of_core ();
+        return gpg_error (gpg_err_code_from_errno (errno));
+
       *buf = padind; /* Padding indicator. */
       memcpy (buf+1, data, datalen);
       sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf,
@@ -550,11 +553,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax,
 
 /* Perform a READ RECORD command. RECNO gives the record number to
    read with 0 indicating the current record.  RECCOUNT must be 1 (not
-   all cards support reading of more than one record).  The result is
-   stored in a newly allocated buffer at the address passed by RESULT.
-   Returns the length of this data at the address of RESULTLEN. */
+   all cards support reading of more than one record).  SHORT_EF
+   should be 0 to read the current EF or contain a short EF. The
+   result is stored in a newly allocated buffer at the address passed
+   by RESULT.  Returns the length of this data at the address of
+   RESULTLEN. */
 gpg_error_t
-iso7816_read_record (int slot, int recno, int reccount,
+iso7816_read_record (int slot, int recno, int reccount, int short_ef,
                      unsigned char **result, size_t *resultlen)
 {
   int sw;
@@ -568,7 +573,8 @@ iso7816_read_record (int slot, int recno, int reccount,
 
   /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
      we check for this limit. */
-  if (recno < 0 || recno > 255 || reccount != 1)
+  if (recno < 0 || recno > 255 || reccount != 1
+      || short_ef < 0 || short_ef > 254 )
     return gpg_error (GPG_ERR_INV_VALUE);
 
   buffer = NULL;
@@ -577,7 +583,7 @@ iso7816_read_record (int slot, int recno, int reccount,
      with an Le of 0. */
   sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
                      recno, 
-                     0x04,
+                     short_ef? short_ef : 0x04,
                      -1, NULL,
                      254, &buffer, &bufferlen);
 
index 937326b..8f2b150 100644 (file)
@@ -67,6 +67,7 @@ gpg_error_t iso7816_get_challenge (int slot,
 gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax,
                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
+                                 int short_ef,
                                  unsigned char **result, size_t *resultlen);
 
 #endif /*ISO7816_H*/
index 6f8b330..3882e1d 100644 (file)
@@ -50,8 +50,10 @@ enum cmd_and_opt_values
 { 
   oInteractive    = 'i',
   oVerbose       = 'v',
+  oQuiet          = 'q',
   oReaderPort     = 500,
   octapiDriver,
+
   oDebug,
   oDebugAll,
 
@@ -68,6 +70,7 @@ static ARGPARSE_OPTS opts[] = {
   { 301, NULL, 0, "@Options:\n " },
 
   { oInteractive, "interactive", 0, "start in interactive explorer mode"},
+  { oQuiet,       "quiet", 0, "quiet" },
   { oVerbose, "verbose",   0, "verbose" },
   { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
   { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
@@ -86,7 +89,7 @@ static ARGPARSE_OPTS opts[] = {
 
 
 static void interactive_shell (int slot);
-
+static void dump_other_cards (int slot);
 
 static const char *
 my_strusage (int level)
@@ -168,6 +171,7 @@ main (int argc, char **argv )
       switch (pargs.r_opt)
         {
         case oVerbose: opt.verbose++; break;
+        case oQuiet: opt.quiet++; break;
         case oDebug: opt.debug |= pargs.r.ret_ulong; break;
         case oDebugAll: opt.debug = ~0; break;
         case oReaderPort: reader_port = pargs.r.ret_str; break;
@@ -191,7 +195,7 @@ main (int argc, char **argv )
   if (slot == -1)
     exit (1);
   
-  if (!gen_random)
+  if (!gen_random && !opt.quiet)
     {
       rc = atr_dump (slot, stdout); 
       if (rc)
@@ -210,12 +214,17 @@ main (int argc, char **argv )
       rc = app_select_openpgp (&appbuf);
       if (rc)
         {
-          log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
+          if (!opt.quiet)
+            log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
           memset (&appbuf, 0, sizeof appbuf);
           appbuf.slot = slot;
           rc = app_select_dinsig (&appbuf);
           if (rc)
-            log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc));
+            {
+              if (!opt.quiet)
+                log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc));
+              dump_other_cards (slot);
+            }
           else
             {
               appbuf.initialized = 1;
@@ -398,6 +407,7 @@ interactive_shell (int slot)
       cmdAPP,
       cmdREAD,
       cmdREADREC,
+      cmdREADSHORTREC,
       cmdDEBUG,
       cmdVERIFY,
       cmdCHANGEREF,
@@ -425,6 +435,7 @@ interactive_shell (int slot)
     { "rb"     , cmdREAD,  NULL },
     { "readrec", cmdREADREC,  "read record(s)" },
     { "rr"     , cmdREADREC,  NULL },
+    { "rsr"    , cmdREADSHORTREC,  "readshortrec RECNO SHORT_EF" },
     { "verify" , cmdVERIFY, "verify CHVNO PIN" },
     { "ver"    , cmdVERIFY, NULL },
     { "changeref", cmdCHANGEREF, "change reference data" },
@@ -559,7 +570,8 @@ interactive_shell (int slot)
               for (i=1, err=0; !err; i++)
                 {
                   xfree (result); result = NULL;
-                  err = iso7816_read_record (slot, i, 1, &result, &resultlen);
+                  err = iso7816_read_record (slot, i, 1, 0,
+                                             &result, &resultlen);
                   if (!err)
                     dump_buffer (result, resultlen);
                 }
@@ -568,13 +580,31 @@ interactive_shell (int slot)
             }
           else
             {
-              err = iso7816_read_record (slot, arg_number, 1,
+              err = iso7816_read_record (slot, arg_number, 1, 0,
                                          &result, &resultlen);
               if (!err)
                 dump_or_store_buffer (arg_string, result, resultlen);
             }
           break;
 
+        case cmdREADSHORTREC:
+          {
+            int short_ef;
+
+            short_ef = strtol (arg_next, NULL, 0);
+            
+            if (short_ef < 1 || short_ef > 254)
+              printf ("error: short EF must be between 1 and 254\n");
+            else
+              {
+                err = iso7816_read_record (slot, arg_number, 1, short_ef,
+                                           &result, &resultlen);
+                if (!err)
+                  dump_or_store_buffer (arg_string, result, resultlen);
+              }
+          }
+          break;
+
         case cmdVERIFY:
           if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31)
             printf ("error: invalid CHVNO\n");
@@ -637,3 +667,104 @@ interactive_shell (int slot)
   ;
 }
 
+
+
+/* Figure out whether the current card is a German Geldkarte and print
+   what we know about it. */
+static int
+dump_geldkarte (int slot)
+{
+  unsigned char *r = NULL;
+  size_t rlen;
+  const char *t;
+
+  if (iso7816_read_record (slot, 1, 1, 0xbc, &r, &rlen))
+    return -1;
+  /* We require that the record is at least 24 bytes, the first byte
+     is 0x67 and the filler byte is correct. */
+  if (rlen < 24 || *r != 0x67 || r[22])
+    return -1;
+  
+  /* The short Bankleitzahl consists of 3 bytes at offset 1.  */
+  switch (r[1])
+    {
+    case 0x21: t = "Oeffentlich-rechtliche oder private Bank"; break;
+    case 0x22: t = "Privat- oder Geschäftsbank"; break;
+    case 0x25: t = "Sparkasse"; break;
+    case 0x26:
+    case 0x29: t = "Genossenschaftsbank"; break;
+    default: 
+      xfree (r);
+      return -1;  /* Probably not a Geldkarte. */
+    }
+
+  printf ("KBLZ .....: %02X-%02X%02X (%s)\n", r[1], r[2], r[3], t);
+  printf ("Card-No ..: %02X%02X%02X%02X%02X\n", r[4], r[5], r[6], r[7], r[8]);
+   
+/*   Byte 10 enthält im linken Halbbyte eine Prüfziffer, die nach dem */
+/*   Verfahren 'Luhn formula for computing modulus 10' über die Ziffern der */
+/*   ersten 9 Byte berechnet ist. */
+  
+/*   Das rechte Halbbyte wird zu 'D' gesetzt.  */
+  
+/*   Für die Berechnung der Luhn-Prüfziffer sind die folgenden Schritte */
+/*   durchzuführen: */
+  
+/*   Schritt 1:        Mit der rechtesten Ziffer beginnend ist einschließlich dieser */
+/*   Ziffer jede übernächste Ziffer zu verdoppeln (mit 2 multiplizieren). */
+  
+/*   Schritt 2:        Die einzelnen Ziffern der Produkte aus Schritt 1 und die bei */
+/*   diesen Multiplikationen unberührt gebliebenen Ziffern sind zu addieren. */
+  
+/*   Schritt 3:        Das Ergebnis der Addition aus Schritt 2 ist von dem auf die */
+/*   nächst höhere Zahl mit der Einerstelle 0 aufgerundeten Ergebnis der */
+/*   Addition aus Schritt 2 abzuziehen. Wenn das Ergebnis der Addition aus */
+/*   Schritt 2 bereits eine Zahl mit der Einerstelle 0 ergibt (z.B. 30, 40, */
+/*   usw.), ist die Prüfziffer 0. */
+  
+/*   Beispiel: Kartennummer ohne Prüfziffer: 992 839 871 */
+  
+/*    9   9   2   8   3   9   8   7   1 */
+  
+/*   x 2     x 2     x 2     x 2     x 2       Schritt 1 */
+  
+/*   18       4       6      16       2 */
+  
+/*   1+8 +9  +4  +8  +6  +9 +1+6 +7  +2 = 61   Schritt 2 */
+  
+/*   70-61 = 9                                 Schritt 3 */
+  
+/*   Prüfziffer zu 992 839 871 = 9 */
+
+
+  printf ("Expires at: %02X/%02X\n", r[11], r[10] );
+  printf ("Valid from: %02X.%02X.%02X\n", r[14], r[13], r[12]);
+  printf ("Country ..: %02X%02X\n", r[15], r[16]);
+  printf ("Currency .: %c%c%c\n", isascii (r[17])? r[17]:' ',
+          isascii (r[18])? r[18]:' ', isascii (r[19])? r[19]:' ');
+  printf ("Cur.-Mult : %s\n", 
+          r[20] == 0x01? "0.01":
+          r[20] == 0x02? "0.1":
+          r[20] == 0x04? "1":
+          r[20] == 0x08? "10":
+          r[20] == 0x10? "100":
+          r[20] == 0x20? "1000": "?");
+  printf ("ZKA ChipID: %02X\n", r[21]);
+  printf ("OS version: %02X\n", r[23]);
+
+  xfree (r);
+  return 0;
+} 
+
+
+
+/* Try to figure out the type of teh card and dump its contents. */
+static void
+dump_other_cards (int slot)
+{
+
+  if (!dump_geldkarte (slot))
+    return; 
+
+} 
+
index 2bbf271..0987385 100644 (file)
 #include "../common/util.h"
 #include "../common/errors.h"
 
-/* Convenience funcion to be used instead of returning the old
-   GNUPG_Out_Of_Core. */
-static __inline__ gpg_error_t
-out_of_core (void)
-{
-  return gpg_error (gpg_err_code_from_errno (errno));
-}
-
 
 #define MAX_DIGEST_LEN 24