* app.c (select_application): Fixed serial number extraction and
authorWerner Koch <wk@gnupg.org>
Thu, 9 Sep 2004 07:28:47 +0000 (07:28 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 9 Sep 2004 07:28:47 +0000 (07:28 +0000)
added the BMI card workaround.
(app_munge_serialno): New.
* app-openpgp.c (app_select_openpgp): Try munging serialno.

scd/ChangeLog
scd/app-common.h
scd/app-openpgp.c
scd/app.c

index 80b244e..a527b5d 100644 (file)
@@ -1,3 +1,10 @@
+2004-08-20  Werner Koch  <wk@g10code.de>
+
+       * app.c (select_application): Fixed serial number extraction and
+       added the BMI card workaround.
+       (app_munge_serialno): New.
+       * app-openpgp.c (app_select_openpgp): Try munging serialno.
+
 2004-08-05  Werner Koch  <wk@g10code.de>
 
        * scdaemon.c (main): New option --disable-application.
index c61bcca..c15f174 100644 (file)
@@ -95,6 +95,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
 /*-- app.c --*/
 app_t select_application (ctrl_t ctrl, int slot, const char *name);
 void release_application (app_t app);
+int app_munge_serialno (app_t app);
 int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
 int app_write_learn_status (app_t app, ctrl_t ctrl);
 int app_readcert (app_t app, const char *certid,
@@ -159,6 +160,9 @@ int app_select_nks (app_t app);
 /*-- app-dinsig.c --*/
 int app_select_dinsig (app_t app);
 
+/*-- app-p15.c --*/
+int app_select_p15 (app_t app);
+
 
 #endif
 
index 3dc015b..67bc336 100644 (file)
@@ -1394,6 +1394,13 @@ app_select_openpgp (APP app)
           log_info ("got AID: ");
           log_printhex ("", buffer, buflen);
         }
+#if GNUPG_MAJOR_VERSION != 1
+      /* A valid OpenPGP card should never need this but well the test
+         is cheap. */
+      rc = app_number_serialno (app);
+      if (rc)
+        goto leave;
+#endif
 
       app->card_version = buffer[6] << 8;
       app->card_version |= buffer[7];
index b3a13f1..55fb586 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -1,5 +1,5 @@
 /* app.c - Application selection.
- *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -45,6 +45,7 @@ is_app_allowed (const char *name)
   return 1; /* yes */
 }
 
+
 /* If called with NAME as NULL, select the best fitting application
    and return a context; otherwise select the application with NAME
    and return a context.  SLOT identifies the reader device. Returns
@@ -81,31 +82,50 @@ select_application (ctrl_t ctrl, int slot, const char *name)
       const unsigned char *p;
 
       p = find_tlv (result, resultlen, 0x5A, &n);
-      if (p && n && n >= (resultlen - (p - result)))
+      if (p)
+        resultlen -= (p-result);
+      if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
+        {
+          /* The object it does not fit into the buffer.  This is an
+             invalid encoding (or the buffer is too short.  However, I
+             have some test cards with such an invalid encoding and
+             therefore I use this ugly workaround to return something
+             I can further experiment with. */
+          log_debug ("enabling BMI testcard workaround\n");
+          n--;
+        }
+
+      if (p && n <= resultlen)
         {
           /* The GDO file is pretty short, thus we simply reuse it for
              storing the serial number. */
           memmove (result, p, n);
           app->serialno = result;
           app->serialnolen = n;
+          rc = app_munge_serialno (app);
+          if (rc)
+            goto leave;
         }
       else
         xfree (result);
       result = NULL;
     }
 
-
+  
   rc = gpg_error (GPG_ERR_NOT_FOUND);
 
   if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp")))
     rc = app_select_openpgp (app);
   if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
     rc = app_select_nks (app);
+/*   if (rc && is_app_allowed ("p12") && (!name || !strcmp (name, "p12"))) */
+/*     rc = app_select_p12 (app); */
   if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
     rc = app_select_dinsig (app);
   if (rc && name)
     rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
 
+ leave:
   if (rc)
     {
       if (name)
@@ -141,6 +161,39 @@ release_application (app_t app)
 
 
 
+/* The serial number may need some cosmetics.  Do it here.  This
+   function shall only be called once after a new serial number has
+   been put into APP->serialno. 
+
+   Prefixes we use:
+   
+     FF 00 00 = For serial numbers starting with an FF
+     FF 01 00 = Some german p15 cards return an empty serial number so the
+                serial number from the EF(TokeInfo is used instead.
+     
+     All other serial number not starting with FF are used as they are.
+*/
+int
+app_munge_serialno (app_t app)
+{
+  if (app->serialnolen && app->serialno[0] == 0xff)
+    { 
+      /* The serial number starts with our special prefix.  This
+         requires that we put our default prefix "FF0000" in front. */
+      unsigned char *p = xtrymalloc (app->serialnolen + 3);
+      if (!p)
+        return gpg_error (gpg_err_code_from_errno (errno));
+      memcpy (p, "\xff\0", 3);
+      memcpy (p+3, app->serialno, app->serialnolen);
+      app->serialnolen += 3;
+      xfree (app->serialno);
+      app->serialno = p;
+    }
+  return 0;
+}
+
+
+
 /* Retrieve the serial number and the time of the last update of the
    card.  The serial number is returned as a malloced string (hex
    encoded) in SERIAL and the time of update is returned in STAMP.  If