2005-07-13 Moritz Schulte <moritz@g10code.com>
authorMoritz Schulte <mo@g10code.com>
Wed, 13 Jul 2005 17:24:41 +0000 (17:24 +0000)
committerMoritz Schulte <mo@g10code.com>
Wed, 13 Jul 2005 17:24:41 +0000 (17:24 +0000)
* configure.ac: Bump version number up to 0.3-cvs.

src/libscd

2005-07-13  Moritz Schulte  <moritz@g10code.com>

* apdu.c, apdu.h, ccid-driver.c, ccid-driver.h, iso7816.c,
iso7816.h, tlv.c, tlv.h: Updated from GnuPG.

src/common

2005-07-13  Moritz Schulte  <moritz@g10code.com>

* defs.h.in (POLDI_OLD_CARD_KEY_RETRIVAL_EXPLANATION): New symbol.
(POLDI_PIN2_QUERY_MSG, POLDI_PIN3_QUERY_MSG): Change strings.

* card.c: Include <assert.h>
(card_info): New API, return card version information, if
requested.
* card.h: Update card_info() API.

src/ctrl

2005-07-13  Moritz Schulte  <moritz@g10code.com>

* poldi-ctrl.c: Adjust to new card_info() API, use version
information in order to figure out if CHV3 is necessary for public
key retrival.

src/pam

2005-07-13  Moritz Schulte  <moritz@g10code.com>

* pam_poldi.c (wait_for_card): Adjust to new card_info() API.

17 files changed:
ChangeLog
NEWS
configure.ac
src/common/ChangeLog
src/common/card.c
src/common/card.h
src/common/defs.h.in
src/ctrl/ChangeLog
src/ctrl/poldi-ctrl.c
src/libscd/ChangeLog
src/libscd/apdu.c
src/libscd/ccid-driver.c
src/libscd/iso7816.c
src/libscd/tlv.c
src/libscd/tlv.h
src/pam/ChangeLog
src/pam/pam_poldi.c

index 2d8050f..5c382c2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2005-07-13  Moritz Schulte  <moritz@g10code.com>
+
+       * configure.ac: Bump version number up to 0.3-cvs.
+
 2004-11-29  Moritz Schulte  <moritz@g10code.com>
 
        * THANKS: New file.
diff --git a/NEWS b/NEWS
index c643650..901d797 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1 +1,4 @@
-Version 0.2 is a quasi-rewrite.
+Changes since version 0.2:
+
+* Better support for Version 0x0101 cards (no Admin PIN necessary for
+  public key retrival).
index 1ff9f52..d77a517 100644 (file)
@@ -1,5 +1,5 @@
 # configure.ac - for the GSCUTILSGnuPG 1.9
-# Copyright (C) 2004 g10 Code GmbH
+# Copyright (C) 2004, 2005 g10 Code GmbH
 # 
 # This file is part of Poldi.
 #
@@ -24,7 +24,7 @@ min_automake_version="1.7.9"
 
 # Version number: Remember to change it immediately *after* a release.
 #                 Add a "-cvs" prefix for non-released code.
-AC_INIT(poldi, 0.2, gnupg-devel@gnupg.org)
+AC_INIT(poldi, 0.3-cvs, gnupg-devel@gnupg.org)
 
 PACKAGE=$PACKAGE_NAME
 VERSION=$PACKAGE_VERSION
index 90ec515..6ad3618 100644 (file)
@@ -1,3 +1,13 @@
+2005-07-13  Moritz Schulte  <moritz@g10code.com>
+
+       * defs.h.in (POLDI_OLD_CARD_KEY_RETRIVAL_EXPLANATION): New symbol.
+       (POLDI_PIN2_QUERY_MSG, POLDI_PIN3_QUERY_MSG): Change strings.
+
+       * card.c: Include <assert.h>
+       (card_info): New API, return card version information, if
+       requested.
+       * card.h: Update card_info() API.
+
 2004-11-27  Moritz Schulte  <moritz@g10code.com>
 
        * options.c (options_parse_conf): Do not fail if file does not
index b73fe46..40c5dbc 100644 (file)
@@ -1,5 +1,5 @@
 /* card.c - High-Level access to OpenPGP smartcards.
-   Copyright (C) 2004 g10 Code GmbH.
+   Copyright (C) 2004, 2005 g10 Code GmbH.
  
    This file is part of Poldi.
   
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
+#include <assert.h>
 
 #include <gcrypt.h>
 
@@ -128,12 +129,14 @@ card_close (int slot)
 }
 
 gpg_error_t
-card_info (int slot, const char **serial_no, const char **fingerprint)
+card_info (int slot, const char **serial_no,
+          unsigned int *card_version, const char **fingerprint)
 {
   size_t fingerprint_new_n;
   char *fingerprint_new;
   char *serial_no_new;
   const unsigned char *value;
+  unsigned int version;
   unsigned char *data;
   size_t value_n;
   size_t data_n;
@@ -143,23 +146,34 @@ card_info (int slot, const char **serial_no, const char **fingerprint)
   fingerprint_new = NULL;
   serial_no_new = NULL;
   data = NULL;
+  version = 0;
   err = 0;
 
-  if (serial_no)
+  if (serial_no || card_version)
     {
       err = iso7816_get_data (slot, 0x004F, &data, &data_n);
       if (err)
        goto out;
 
-      serial_no_new = malloc ((data_n * 2) + 1);
-      if (! serial_no_new)
+      /* FIXME: assert correct?  */
+      assert (data_n == 16);
+
+      if (serial_no)
        {
-         err = gpg_error_from_errno (errno);
-         goto out;
+         serial_no_new = malloc ((data_n * 2) + 1);
+         if (! serial_no_new)
+           {
+             err = gpg_error_from_errno (errno);
+             goto out;
+           }
+         for (i = 0; i < data_n; i++)
+           sprintf (serial_no_new + (i * 2), "%02X", data[i]);
+       }
+      if (card_version)
+       {
+         version = data[6] << 8;
+         version |= data[7];
        }
-
-      for (i = 0; i < data_n; i++)
-       sprintf (serial_no_new + (i * 2), "%02X", data[i]);
     }
 
   if (fingerprint)
@@ -202,6 +216,8 @@ card_info (int slot, const char **serial_no, const char **fingerprint)
     {
       if (serial_no)
        *serial_no = (const char *) serial_no_new;
+      if (card_version)
+       *card_version = version;
       if (fingerprint)
        *fingerprint = (const char *) fingerprint_new;
     }
index 0ae4009..2b43cef 100644 (file)
@@ -1,5 +1,5 @@
 /* card.h - High-Level access to OpenPGP smartcards.
-   Copyright (C) 2004 g10 Code GmbH.
+   Copyright (C) 2004, 2005 g10 Code GmbH.
  
    This file is part of Poldi.
   
@@ -27,8 +27,8 @@ gcry_error_t card_open (const char *port, int *slot);
 gcry_error_t card_init (int slot, int wait, int require_card_switch);
 void card_close (int slot);
 
-gcry_error_t card_info (int slot,
-                       const char **serial_no, const char **fingerprint);
+gcry_error_t card_info (int slot, const char **serial_no,
+                       unsigned int *card_version, const char **fingerprint);
 gcry_error_t card_read_key (int slot, gcry_sexp_t *key);
 
 gcry_error_t card_pin_provide (int slot, int which, const unsigned char *pin);
index 55a00b9..310bea7 100644 (file)
@@ -1,5 +1,5 @@
 /* poldi.c - PAM authentication via OpenPGP smartcards.
-   Copyright (C) 2004 g10 Code GmbH
+   Copyright (C) 2004, 2005 g10 Code GmbH
  
    This file is part of Poldi.
   
 #define POLDI_USERS_DB_FILE  POLDI_CONF_DIRECTORY "/users"
 #define POLDI_KEY_DIRECTORY  POLDI_CONF_DIRECTORY "/keys"
 
-#define POLDI_PIN2_QUERY_MSG "Give me your PIN (CHV2): "
-#define POLDI_PIN3_QUERY_MSG "Give me your PIN (CHV3): "
+#define POLDI_PIN2_QUERY_MSG "PIN (CHV2): "
+#define POLDI_PIN3_QUERY_MSG "Admin PIN (CHV3): "
+
+#define POLDI_OLD_CARD_KEY_RETRIVAL_EXPLANATION \
+ "Card of version 0x%X detected, Admin PIN (CHV3) " \
+ "is necessary for retrieving the public key from the card\n"
 
 #endif
index 773c846..82a1af0 100644 (file)
@@ -1,3 +1,17 @@
+2005-07-13  Moritz Schulte  <moritz@g10code.com>
+
+       * poldi-ctrl.c: Adjust to new card_info() API, use version
+       information in order to figure out if CHV3 is necessary for public
+       key retrival.
+
+2005-07-12  Moritz Schulte  <moritz@g10code.com>
+
+       * poldi-ctrl.c (cmd_show_key): Only print KEY_STRING, if non-NULL.
+
+2005-01-30  Moritz Schulte  <moritz@g10code.com>
+
+       * poldi-ctrl.c (sexp_to_string): New function.
+
 2004-11-29  Moritz Schulte  <moritz@g10code.com>
 
        * poldi-ctrl.c: Fix contact address.
index ae8064c..dcef2de 100644 (file)
@@ -1,5 +1,5 @@
 /* poldi-ctrl.c - Poldi maintaince tool
-   Copyright (C) 2004 g10 Code GmbH.
+   Copyright (C) 2004, 2005 g10 Code GmbH.
  
    This file is part of Poldi.
   
@@ -57,6 +57,7 @@ struct poldi_ctrl_opt
   int require_card_switch;
   int cmd_test;
   int cmd_dump;
+  int cmd_dump_shadowed_key;
   int cmd_set_key;
   int cmd_show_key;
   int cmd_add_user;
@@ -94,6 +95,7 @@ enum arg_opt_ids
   {
     arg_test = 't',
     arg_dump = 'd',
+    arg_dump_shadowed_key = 'D',
     arg_set_key = 's',
     arg_show_key = 'k',
     arg_add_user  = 'a',
@@ -118,6 +120,8 @@ static ARGPARSE_OPTS arg_opts[] =
       "test",        256, "Test authentication"                },
     { arg_dump,
       "dump",        256, "Dump certain card information"      },
+    { arg_dump_shadowed_key,
+      "dump-shadowed-key", 256, "Dump shadowed key from card"  },
     { arg_add_user,
       "add-user",    256, "Add account to users db"            },
     { arg_remove_user,
@@ -222,6 +226,11 @@ poldi_ctrl_options_cb (ARGPARSE_ARGS *parg, void *opaque)
        poldi_ctrl_opt.cmd_dump = 1;
       break;
 
+    case arg_dump_shadowed_key:
+      if (parsing_stage)
+       poldi_ctrl_opt.cmd_dump_shadowed_key = 1;
+      break;
+
     case arg_add_user:
       if (parsing_stage)
        poldi_ctrl_opt.cmd_add_user = 1;
@@ -311,6 +320,7 @@ cmd_test (void)
   char *key_path;
   gcry_sexp_t key_sexp;
   char *key_string;
+  unsigned int version;
 
   slot = -1;
   pin = NULL;
@@ -321,6 +331,7 @@ cmd_test (void)
   challenge = NULL;
   signature = NULL;
   serialno = NULL;
+  version = 0;
 
   err = challenge_generate (&challenge, &challenge_n);
   if (err)
@@ -343,11 +354,12 @@ cmd_test (void)
   if (err)
     goto out;
 
-  err = card_info (slot, &serialno, NULL);
+  err = card_info (slot, &serialno, &version, NULL);
   if (err)
     goto out;
 
   printf ("Serial No: %s\n", serialno);
+  printf ("Card version: %u\n", version);
 
   err = serialno_to_username (serialno, &account);
   if (err)
@@ -417,16 +429,18 @@ static gpg_error_t
 cmd_dump (void)
 {
   gcry_sexp_t key;
+  char *key_s;
   const char *serialno;
   gpg_error_t err;
   int slot;
   char *pin;
+  unsigned int version;
 
   slot = -1;
   serialno = NULL;
   key = NULL;
-
-  pin = getpass (POLDI_PIN3_QUERY_MSG);
+  key_s = NULL;
+  pin = NULL;
 
   err = card_open (NULL, &slot);
   if (err)
@@ -436,28 +450,43 @@ cmd_dump (void)
   if (err)
     goto out;
 
-  err = card_pin_provide (slot, 3, pin);
+  err = card_info (slot, &serialno, &version, NULL);
   if (err)
     goto out;
 
-  err = card_info (slot, &serialno, NULL);
+  if (version <= 0x0100)
+    {
+      /* These cards contain a bug, which makes it necessary to pass
+        CHV3 to the card before reading out the public key.  */
+
+      printf (POLDI_OLD_CARD_KEY_RETRIVAL_EXPLANATION, version);
+
+      pin = getpass (POLDI_PIN3_QUERY_MSG);
+
+      err = card_pin_provide (slot, 3, pin);
+      if (err)
+       goto out;
+    }
+
+  err = card_read_key (slot, &key);
   if (err)
     goto out;
 
-  err = card_read_key (slot, &key);
+  err = sexp_to_string (key, &key_s);
   if (err)
     goto out;
-  
+
   printf ("Slot: %i\n", slot);
   printf ("Serial number: %s\n", serialno);
-  printf ("Key:\n");
-  gcry_sexp_dump (key);
+  printf ("Version: 0x%X\n", version);
+  printf ("Key:\n%s\n", key_s);
 
  out:
 
   if (slot != -1)
     card_close (slot);
   gcry_sexp_release (key);
+  gcry_free (key_s);
   free ((void *) serialno);
   free (pin);
 
@@ -465,6 +494,111 @@ cmd_dump (void)
 }
 
 static gpg_error_t
+cmd_dump_shadowed_key (void)
+{
+  gcry_sexp_t key_public;
+  gcry_sexp_t key_shadowed;
+  gcry_sexp_t value_pair;
+  char *key_s;
+  gcry_mpi_t mpi_n;
+  gcry_mpi_t mpi_e;
+  gpg_error_t err;
+  int slot;
+  char *pin;
+  char key_grip[41];
+  unsigned char key_grip_raw[20];
+  unsigned int i;
+
+  slot = -1;
+  key_public = NULL;
+  key_shadowed = NULL;
+  value_pair = NULL;
+  mpi_n = NULL;
+  mpi_e = NULL;
+  key_s = NULL;
+
+  pin = getpass (POLDI_PIN3_QUERY_MSG);
+
+  err = card_open (NULL, &slot);
+  if (err)
+    goto out;
+
+  err = card_init (slot, 0, 0);
+  if (err)
+    goto out;
+
+  err = card_pin_provide (slot, 3, pin);
+  if (err)
+    goto out;
+
+  err = card_read_key (slot, &key_public);
+  if (err)
+    goto out;
+
+  value_pair = gcry_sexp_find_token (key_public, "n", 0);
+  if (! value_pair)
+    {
+      err = gpg_error (GPG_ERR_INV_SEXP);
+      goto out;
+    }
+  mpi_n = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG);
+  if (! mpi_n)
+    {
+      err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
+      goto out;
+    }
+
+  gcry_sexp_release (value_pair);
+  value_pair = gcry_sexp_find_token (key_public, "e", 0);
+  if (! value_pair)
+    {
+      err = gpg_error (GPG_ERR_INV_SEXP);
+      goto out;
+    }
+  mpi_e = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG);
+  if (! mpi_e)
+    {
+      err = gpg_error (GPG_ERR_INTERNAL); /* FIXME? */
+      goto out;
+    }
+
+  err = gcry_sexp_build (&key_shadowed, NULL,
+                        "(shadowed-private-key"
+                        " (rsa"
+                        "  (n %m)"
+                        "  (e %m)))",
+                        mpi_n, mpi_e);
+  if (err)
+    goto out;
+
+  err = sexp_to_string (key_shadowed, &key_s);
+  if (err)
+    goto out;
+
+  gcry_pk_get_keygrip (key_public, key_grip_raw);
+  for (i = 0; i < 20; i++)
+    sprintf (key_grip + 2 * i, "%02X", key_grip_raw[i]);
+
+  printf ("Key grip:\n%s\n", key_grip);
+  printf ("Key:\n%s\n", key_s);
+
+ out:
+
+  gcry_mpi_release (mpi_n);
+  gcry_mpi_release (mpi_e);
+  gcry_sexp_release (value_pair);
+
+  if (slot != -1)
+    card_close (slot);
+  gcry_sexp_release (key_public);
+  gcry_sexp_release (key_shadowed);
+  gcry_free (key_s);
+  free (pin);
+
+  return err;
+}
+
+static gpg_error_t
 cmd_list_users (void)
 {
   char users_file[] = POLDI_USERS_DB_FILE;
@@ -685,6 +819,7 @@ cmd_set_key (void)
   const char *serialno;
   char *pin;
   gcry_sexp_t key_sexp;
+  unsigned int version;
   int ret;
 
   slot = -1;
@@ -694,6 +829,7 @@ cmd_set_key (void)
   serialno = NULL;
   key_sexp = NULL;
   key_string = NULL;
+  version = 0;
 
   err = card_open (NULL, &slot);
   if (err)
@@ -703,22 +839,25 @@ cmd_set_key (void)
   if (err)
     goto out;
 
-  err = card_info (slot, &serialno, NULL);
+  err = card_info (slot, &serialno, &version, NULL);
   if (err)
     goto out;
 
-  pin = getpass (POLDI_PIN3_QUERY_MSG);
-  if (! pin)
+  path = make_filename (POLDI_KEY_DIRECTORY, serialno, NULL);
+
+  if (version <= 0x0100)
     {
-      err = gpg_error_from_errno (errno);
-      goto out;
-    }
+      /* These cards contain a bug, which makes it necessary to pass
+        CHV3 to the card before reading out the public key.  */
 
-  err = card_pin_provide (slot, 3, pin);
-  if (err)
-    goto out;
+      printf (POLDI_OLD_CARD_KEY_RETRIVAL_EXPLANATION, version);
 
-  path = make_filename (POLDI_KEY_DIRECTORY, serialno, NULL);
+      pin = getpass (POLDI_PIN3_QUERY_MSG);
+
+      err = card_pin_provide (slot, 3, pin);
+      if (err)
+       goto out;
+    }
 
   err = card_read_key (slot, &key_sexp);
   if (err)
@@ -794,7 +933,8 @@ cmd_show_key (void)
   if (err)
     goto out;
 
-  printf ("%s", key_string);
+  if (key_string)
+    printf ("%s", key_string);
 
  out:
 
@@ -849,7 +989,8 @@ main (int argc, char **argv)
        + (poldi_ctrl_opt.cmd_add_user)
        + (poldi_ctrl_opt.cmd_remove_user)
        + (poldi_ctrl_opt.cmd_list_users)
-       + (poldi_ctrl_opt.cmd_dump)) != 1)
+       + (poldi_ctrl_opt.cmd_dump)
+       + (poldi_ctrl_opt.cmd_dump_shadowed_key)) != 1)
     {
       fprintf (stderr, "Error: no command given (try --help).\n");
       exit (EXIT_FAILURE);
@@ -859,6 +1000,8 @@ main (int argc, char **argv)
     err = cmd_test ();
   else if (poldi_ctrl_opt.cmd_dump)
     err = cmd_dump ();
+  else if (poldi_ctrl_opt.cmd_dump_shadowed_key)
+    err = cmd_dump_shadowed_key ();
   else if (poldi_ctrl_opt.cmd_set_key)
     err = cmd_set_key ();
   else if (poldi_ctrl_opt.cmd_show_key)
index e69de29..04f8d12 100644 (file)
@@ -0,0 +1,4 @@
+2005-07-13  Moritz Schulte  <moritz@g10code.com>
+
+       * apdu.c, apdu.h, ccid-driver.c, ccid-driver.h, iso7816.c,
+       iso7816.h, tlv.c, tlv.h: Updated from GnuPG.
index c734084..6c9994b 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: apdu.c,v 1.4.2.24 2004/10/20 08:54:45 wk Exp $
+ * $Id: apdu.c,v 1.4.2.30 2005/06/16 08:11:59 wk Exp $
  */
 
+/* NOTE: This module is also used by other software, thus the use of
+   the macro USE_GNU_PTH is mandatory.  For GnuPG this macro is
+   guaranteed to be defined true. */
+
 #include <config.h>
 #include <errno.h>
 #include <stdio.h>
 # include <unistd.h>
 # include <fcntl.h>
 #endif
-#ifdef HAVE_OPENSC
-# include <opensc/opensc.h>
-# ifdef USE_GNU_PTH
-# undef USE_GNU_PTH
-# endif
-#endif
+
 
 /* If requested include the definitions for the remote APDU protocol
    code. */
 #include "dynload.h"
 #include "ccid-driver.h"
 
+
+/* To to conflicting use of threading libraries we usually can't link
+   against libpcsclite.   Instead we use a wrapper program.  */
 #ifdef USE_GNU_PTH
+#ifndef HAVE_W32_SYSTEM
 #define NEED_PCSC_WRAPPER 1
 #endif
+#endif
 
 
 #define MAX_READER 4 /* Number of readers we support concurrently. */
@@ -114,12 +118,6 @@ struct reader_table_s {
     pid_t pid;
 #endif /*NEED_PCSC_WRAPPER*/
   } pcsc;
-#ifdef HAVE_OPENSC
-  struct {
-    struct sc_context *ctx;
-    struct sc_card *scard;
-  } osc;
-#endif /*HAVE_OPENSC*/
 #ifdef USE_G10CODE_RAPDU
   struct {
     rapdu_t handle;
@@ -153,14 +151,14 @@ static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad,
 static char (* DLSTDCALL CT_close) (unsigned short ctn);
 
 /* PC/SC constants and function pointer. */
-#define PCSC_SCOPE_USER      0 
-#define PCSC_SCOPE_TERMINAL  1 
-#define PCSC_SCOPE_SYSTEM    2 
-#define PCSC_SCOPE_GLOBAL    3 
+#define PCSC_SCOPE_USER      0
+#define PCSC_SCOPE_TERMINAL  1
+#define PCSC_SCOPE_SYSTEM    2
+#define PCSC_SCOPE_GLOBAL    3
 
-#define PCSC_PROTOCOL_T0     1 
-#define PCSC_PROTOCOL_T1     2 
-#define PCSC_PROTOCOL_RAW    4 
+#define PCSC_PROTOCOL_T0     1
+#define PCSC_PROTOCOL_T1     2
+#define PCSC_PROTOCOL_RAW    4
 
 #define PCSC_SHARE_EXCLUSIVE 1
 #define PCSC_SHARE_SHARED    2
@@ -171,7 +169,7 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_UNPOWER_CARD    2
 #define PCSC_EJECT_CARD      3
 
-#define PCSC_UNKNOWN    0x0001  
+#define PCSC_UNKNOWN    0x0001
 #define PCSC_ABSENT     0x0002  /* Card is absent.  */
 #define PCSC_PRESENT    0x0004  /* Card is present.  */
 #define PCSC_SWALLOWED  0x0008  /* Card is present and electrical connected. */
@@ -191,10 +189,32 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_STATE_INUSE       0x0100  /* Shared mode.  */
 #define PCSC_STATE_MUTE               0x0200  /* Unresponsive card.  */
 
-
-struct pcsc_io_request_s 
+/* Some PC/SC error codes.  */
+#define PCSC_E_CANCELLED               0x80100002
+#define PCSC_E_CANT_DISPOSE            0x8010000E
+#define PCSC_E_INSUFFICIENT_BUFFER     0x80100008
+#define PCSC_E_INVALID_ATR             0x80100015
+#define PCSC_E_INVALID_HANDLE          0x80100003
+#define PCSC_E_INVALID_PARAMETER       0x80100004
+#define PCSC_E_INVALID_TARGET          0x80100005
+#define PCSC_E_INVALID_VALUE           0x80100011
+#define PCSC_E_NO_MEMORY               0x80100006
+#define PCSC_E_UNKNOWN_READER          0x80100009
+#define PCSC_E_TIMEOUT                 0x8010000A
+#define PCSC_E_SHARING_VIOLATION       0x8010000B
+#define PCSC_E_NO_SMARTCARD            0x8010000C
+#define PCSC_E_UNKNOWN_CARD            0x8010000D
+#define PCSC_E_PROTO_MISMATCH          0x8010000F
+#define PCSC_E_NOT_READY               0x80100010
+#define PCSC_E_SYSTEM_CANCELLED        0x80100012
+#define PCSC_E_NOT_TRANSACTED          0x80100016
+#define PCSC_E_READER_UNAVAILABLE      0x80100017
+#define PCSC_W_REMOVED_CARD            0x80100069
+
+
+struct pcsc_io_request_s
 {
-  unsigned long protocol; 
+  unsigned long protocol;
   unsigned long pci_len;
 };
 
@@ -257,15 +277,15 @@ long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
 
 
 \f
-/* 
+/*
       Helper
  */
+
 
 /* Find an unused reader slot for PORTSTR and put it into the reader
    table.  Return -1 on error or the index into the reader table. */
-static int 
-new_reader_slot (void)    
+static int
+new_reader_slot (void)
 {
   int i, reader = -1;
 
@@ -382,8 +402,8 @@ apdu_strerror (int rc)
 
 
 \f
-/* 
-       ct API Interface 
+/*
+       ct API Interface
  */
 
 static const char *
@@ -420,9 +440,9 @@ ct_activate_card (int slot)
   int rc;
   unsigned char dad[1], sad[1], cmd[11], buf[256];
   unsigned short buflen;
-  
+
   /* Check whether card has been inserted. */
-  dad[0] = 1;     /* Destination address: CT. */    
+  dad[0] = 1;     /* Destination address: CT. */
   sad[0] = 2;     /* Source address: Host. */
 
   cmd[0] = 0x20;  /* Class byte. */
@@ -441,8 +461,8 @@ ct_activate_card (int slot)
       return SW_HOST_CARD_IO_ERROR;
     }
 
-  /* Connected, now activate the card. */           
-  dad[0] = 1;    /* Destination address: CT. */    
+  /* Connected, now activate the card. */
+  dad[0] = 1;    /* Destination address: CT. */
   sad[0] = 2;    /* Source address: Host. */
 
   cmd[0] = 0x20;  /* Class byte. */
@@ -512,13 +532,13 @@ ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
   int rc;
   unsigned char dad[1], sad[1];
   unsigned short ctbuflen;
-  
+
   /* If we don't have an ATR, we need to reset the reader first. */
   if (!reader_table[slot].atrlen
       && (rc = reset_ct_reader (slot)))
     return rc;
 
-  dad[0] = 0;     /* Destination address: Card. */    
+  dad[0] = 0;     /* Destination address: Card. */
   sad[0] = 2;     /* Source address: Host. */
   ctbuflen = *buflen;
   if (DBG_CARD_IO)
@@ -577,6 +597,10 @@ open_ct_reader (int port)
 }
 
 \f
+/*
+       PC/SC Interface
+ */
+
 #ifdef NEED_PCSC_WRAPPER
 static int
 writen (int fd, const void *buf, size_t nbytes)
@@ -619,7 +643,7 @@ readn (int fd, void *buf, size_t buflen, size_t *nread)
 #else
       n = read (fd, buf, nleft);
 #endif
-      if (n < 0 && errno == EINTR) 
+      if (n < 0 && errno == EINTR)
         continue;
       if (n < 0)
         return -1; /* read error. */
@@ -632,7 +656,7 @@ readn (int fd, void *buf, size_t buflen, size_t *nread)
     *nread = buflen - nleft;
 
 /*   log_printhex ("  readn:", orig_buf, *nread); */
-    
+
   return 0;
 }
 #endif /*NEED_PCSC_WRAPPER*/
@@ -651,48 +675,73 @@ pcsc_error_string (long err)
     {
     case 0x0002: s = "cancelled"; break;
     case 0x000e: s = "can't dispose"; break;
-    case 0x0008: s = "insufficient buffer"; break;   
+    case 0x0008: s = "insufficient buffer"; break;
     case 0x0015: s = "invalid ATR"; break;
     case 0x0003: s = "invalid handle"; break;
-    case 0x0004: s = "invalid parameter"; break; 
+    case 0x0004: s = "invalid parameter"; break;
     case 0x0005: s = "invalid target"; break;
-    case 0x0011: s = "invalid value"; break; 
-    case 0x0006: s = "no memory"; break;  
-    case 0x0013: s = "comm error"; break;      
-    case 0x0001: s = "internal error"; break;     
-    case 0x0014: s = "unknown error"; break; 
-    case 0x0007: s = "waited too long"; break;  
+    case 0x0011: s = "invalid value"; break;
+    case 0x0006: s = "no memory"; break;
+    case 0x0013: s = "comm error"; break;
+    case 0x0001: s = "internal error"; break;
+    case 0x0014: s = "unknown error"; break;
+    case 0x0007: s = "waited too long"; break;
     case 0x0009: s = "unknown reader"; break;
-    case 0x000a: s = "timeout"; break; 
-    case 0x000b: s = "sharing violation"; break;       
+    case 0x000a: s = "timeout"; break;
+    case 0x000b: s = "sharing violation"; break;
     case 0x000c: s = "no smartcard"; break;
-    case 0x000d: s = "unknown card"; break;   
-    case 0x000f: s = "proto mismatch"; break;          
-    case 0x0010: s = "not ready"; break;               
-    case 0x0012: s = "system cancelled"; break;        
+    case 0x000d: s = "unknown card"; break;
+    case 0x000f: s = "proto mismatch"; break;
+    case 0x0010: s = "not ready"; break;
+    case 0x0012: s = "system cancelled"; break;
     case 0x0016: s = "not transacted"; break;
-    case 0x0017: s = "reader unavailable"; break; 
-    case 0x0065: s = "unsupported card"; break;        
-    case 0x0066: s = "unresponsive card"; break;       
-    case 0x0067: s = "unpowered card"; break;          
-    case 0x0068: s = "reset card"; break;              
-    case 0x0069: s = "removed card"; break;            
-    case 0x006a: s = "inserted card"; break;           
-    case 0x001f: s = "unsupported feature"; break;     
-    case 0x0019: s = "PCI too small"; break;           
-    case 0x001a: s = "reader unsupported"; break;      
-    case 0x001b: s = "duplicate reader"; break;        
-    case 0x001c: s = "card unsupported"; break;        
-    case 0x001d: s = "no service"; break;              
-    case 0x001e: s = "service stopped"; break;      
+    case 0x0017: s = "reader unavailable"; break;
+    case 0x0065: s = "unsupported card"; break;
+    case 0x0066: s = "unresponsive card"; break;
+    case 0x0067: s = "unpowered card"; break;
+    case 0x0068: s = "reset card"; break;
+    case 0x0069: s = "removed card"; break;
+    case 0x006a: s = "inserted card"; break;
+    case 0x001f: s = "unsupported feature"; break;
+    case 0x0019: s = "PCI too small"; break;
+    case 0x001a: s = "reader unsupported"; break;
+    case 0x001b: s = "duplicate reader"; break;
+    case 0x001c: s = "card unsupported"; break;
+    case 0x001d: s = "no service"; break;
+    case 0x001e: s = "service stopped"; break;
     default:     s = "unknown PC/SC error code"; break;
     }
   return s;
 }
 
-/* 
-       PC/SC Interface
- */
+/* Map PC/SC error codes to our special host status words.  */
+static int
+pcsc_error_to_sw (long ec)
+{
+  int rc;
+
+  switch (ec)
+    {
+    case 0:  rc = 0; break;
+
+    case PCSC_E_CANCELLED:           rc = SW_HOST_ABORTED; break;
+    case PCSC_E_NO_MEMORY:           rc = SW_HOST_OUT_OF_CORE; break;
+    case PCSC_E_TIMEOUT:             rc = SW_HOST_CARD_IO_ERROR; break;
+    case PCSC_E_SHARING_VIOLATION:   rc = SW_HOST_LOCKING_FAILED; break;
+    case PCSC_E_NO_SMARTCARD:        rc = SW_HOST_NO_CARD; break;
+    case PCSC_W_REMOVED_CARD:        rc = SW_HOST_NO_CARD; break;
+
+    case PCSC_E_INVALID_TARGET:
+    case PCSC_E_INVALID_VALUE:
+    case PCSC_E_INVALID_HANDLE: 
+    case PCSC_E_INVALID_PARAMETER:
+    case PCSC_E_INSUFFICIENT_BUFFER: rc = SW_HOST_INV_VALUE; break;
+
+    default:  rc = SW_HOST_GENERAL_ERROR; break;
+    }
+
+  return rc;
+}
 
 static void
 dump_pcsc_reader_status (int slot)
@@ -708,6 +757,8 @@ dump_pcsc_reader_status (int slot)
 }
 
 
+/* Send an PC/SC reset command and return a status word on error or 0
+   on success. */
 static int
 reset_pcsc_reader (int slot)
 {
@@ -717,15 +768,16 @@ reset_pcsc_reader (int slot)
   size_t len;
   int i, n;
   unsigned char msgbuf[9];
+  int sw = SW_HOST_CARD_IO_ERROR;
 
   slotp = reader_table + slot;
 
-  if (slotp->pcsc.req_fd == -1 
-      || slotp->pcsc.rsp_fd == -1 
+  if (slotp->pcsc.req_fd == -1
+      || slotp->pcsc.rsp_fd == -1
       || slotp->pcsc.pid == (pid_t)(-1) )
     {
       log_error ("pcsc_get_status: pcsc-wrapper not running\n");
-      return SW_HOST_CARD_IO_ERROR;
+      return sw;
     }
 
   msgbuf[0] = 0x05; /* RESET command. */
@@ -758,16 +810,23 @@ reset_pcsc_reader (int slot)
   if (len > DIM (slotp->atr))
     {
       log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
+      sw = SW_HOST_GENERAL_ERROR;
       goto command_failed;
     }
   err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
   if (err)
     {
-      log_error ("PC/SC RESET failed: %s\n", pcsc_error_string (err));
+      log_error ("PC/SC RESET failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      /* If the error code is no smart card, we should not considere
+         this a major error and close the wrapper.  */
+      sw = pcsc_error_to_sw (err);
+      if (err == PCSC_E_NO_SMARTCARD)
+        return sw;
       goto command_failed;
     }
 
-  /* The open fucntion may return a zero for the ATR length to
+  /* The open function may return a zero for the ATR length to
      indicate that no card is present.  */
   n = len;
   if (n)
@@ -791,7 +850,7 @@ reset_pcsc_reader (int slot)
   kill (slotp->pcsc.pid, SIGTERM);
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
-  return -1;
+  return sw;
 
 #else /* !NEED_PCSC_WRAPPER */
   long err;
@@ -822,10 +881,10 @@ reset_pcsc_reader (int slot)
       log_error ("pcsc_connect failed: %s (0x%lx)\n",
                   pcsc_error_string (err), err);
       reader_table[slot].pcsc.card = 0;
-      return SW_HOST_CARD_IO_ERROR;
-    }      
+      return pcsc_error_to_sw (err);
+    }
+
 
-  
   atrlen = 33;
   nreader = sizeof reader - 1;
   err = pcsc_status (reader_table[slot].pcsc.card,
@@ -837,7 +896,7 @@ reset_pcsc_reader (int slot)
       log_error ("pcsc_status failed: %s (0x%lx)\n",
                   pcsc_error_string (err), err);
       reader_table[slot].atrlen = 0;
-      return SW_HOST_CARD_IO_ERROR;
+      return pcsc_error_to_sw (err);
     }
   if (atrlen >= DIM (reader_table[0].atr))
     log_bug ("ATR returned by pcsc_status is too large\n");
@@ -858,15 +917,16 @@ pcsc_get_status (int slot, unsigned int *status)
   int i, n;
   unsigned char msgbuf[9];
   unsigned char buffer[12];
+  int sw = SW_HOST_CARD_IO_ERROR;
 
   slotp = reader_table + slot;
 
-  if (slotp->pcsc.req_fd == -1 
-      || slotp->pcsc.rsp_fd == -1 
+  if (slotp->pcsc.req_fd == -1
+      || slotp->pcsc.rsp_fd == -1
       || slotp->pcsc.pid == (pid_t)(-1) )
     {
       log_error ("pcsc_get_status: pcsc-wrapper not running\n");
-      return SW_HOST_CARD_IO_ERROR;
+      return sw;
     }
 
   msgbuf[0] = 0x04; /* STATUS command. */
@@ -901,11 +961,12 @@ pcsc_get_status (int slot, unsigned int *status)
     {
       log_error ("pcsc_status failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
-      return SW_HOST_CARD_IO_ERROR;
+      /* This is a proper error code, so return immediately.  */
+      return pcsc_error_to_sw (err);
     }
 
   full_len = len;
-  
+
   n = 8 < len ? 8 : len;
   if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != 8)
     {
@@ -930,7 +991,7 @@ pcsc_get_status (int slot, unsigned int *status)
         }
       full_len -= n;
     }
-   
+
   /* We are lucky: The wrapper already returns the data in the
      required format. */
   *status = buffer[3];
@@ -945,26 +1006,26 @@ pcsc_get_status (int slot, unsigned int *status)
   kill (slotp->pcsc.pid, SIGTERM);
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
-  return -1;
+  return sw;
 
 #else /*!NEED_PCSC_WRAPPER*/
 
   long err;
   struct pcsc_readerstate_s rdrstates[1];
-  
+
   memset (rdrstates, 0, sizeof *rdrstates);
   rdrstates[0].reader = reader_table[slot].rdrname;
   rdrstates[0].current_state = PCSC_STATE_UNAWARE;
   err = pcsc_get_status_change (reader_table[slot].pcsc.context,
                                 0,
                                 rdrstates, 1);
-  if (err == 0x8010000a) /* Timeout.  */
-    err = 0;
+  if (err == PCSC_E_TIMEOUT)
+    err = 0; /* Timeout is no error error here. */
   if (err)
     {
       log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
-      return SW_HOST_CARD_IO_ERROR;
+      return pcsc_error_to_sw (err);
     }
 
 
@@ -992,8 +1053,8 @@ pcsc_get_status (int slot, unsigned int *status)
   if ( (*status & 6) == 6
        && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
     *status |= 1;
-  
-  return 0; 
+
+  return 0;
 #endif /*!NEED_PCSC_WRAPPER*/
 }
 
@@ -1011,6 +1072,7 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
   size_t len, full_len;
   int i, n;
   unsigned char msgbuf[9];
+  int sw = SW_HOST_CARD_IO_ERROR;
 
   if (!reader_table[slot].atrlen
       && (err = reset_pcsc_reader (slot)))
@@ -1021,12 +1083,12 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
 
   slotp = reader_table + slot;
 
-  if (slotp->pcsc.req_fd == -1 
-      || slotp->pcsc.rsp_fd == -1 
+  if (slotp->pcsc.req_fd == -1
+      || slotp->pcsc.rsp_fd == -1
       || slotp->pcsc.pid == (pid_t)(-1) )
     {
       log_error ("pcsc_send_apdu: pcsc-wrapper not running\n");
-      return SW_HOST_CARD_IO_ERROR;
+      return sw;
     }
 
   msgbuf[0] = 0x03; /* TRANSMIT command. */
@@ -1062,11 +1124,11 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
     {
       log_error ("pcsc_transmit failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
-      return SW_HOST_CARD_IO_ERROR;
+      return pcsc_error_to_sw (err);
     }
 
    full_len = len;
-   
+
    n = *buflen < len ? *buflen : len;
    if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n)
      {
@@ -1108,14 +1170,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
   kill (slotp->pcsc.pid, SIGTERM);
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
-  return -1;
+  return sw;
 
 #else /*!NEED_PCSC_WRAPPER*/
 
   long err;
   struct pcsc_io_request_s send_pci;
   unsigned long recv_len;
-  
+
   if (!reader_table[slot].atrlen
       && (err = reset_pcsc_reader (slot)))
     return err;
@@ -1136,8 +1198,8 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
   if (err)
     log_error ("pcsc_transmit failed: %s (0x%lx)\n",
                pcsc_error_string (err), err);
-  
-  return err? SW_HOST_CARD_IO_ERROR:0; 
+
+  return pcsc_error_to_sw (err);
 #endif /*!NEED_PCSC_WRAPPER*/
 }
 
@@ -1154,8 +1216,8 @@ close_pcsc_reader (int slot)
 
   slotp = reader_table + slot;
 
-  if (slotp->pcsc.req_fd == -1 
-      || slotp->pcsc.rsp_fd == -1 
+  if (slotp->pcsc.req_fd == -1
+      || slotp->pcsc.rsp_fd == -1
       || slotp->pcsc.pid == (pid_t)(-1) )
     {
       log_error ("close_pcsc_reader: pcsc-wrapper not running\n");
@@ -1193,10 +1255,10 @@ close_pcsc_reader (int slot)
   if (err)
     log_error ("pcsc_close failed: %s (0x%lx)\n",
                pcsc_error_string (err), err);
-  
-  /* We will the wrapper in any case - errors are merely
+
+  /* We will close the wrapper in any case - errors are merely
      informational. */
-  
+
  command_failed:
   close (slotp->pcsc.req_fd);
   close (slotp->pcsc.rsp_fd);
@@ -1217,6 +1279,7 @@ close_pcsc_reader (int slot)
 #endif /*!NEED_PCSC_WRAPPER*/
 }
 
+/* Note:  It is a pitty that we can't return proper error codes.  */
 static int
 open_pcsc_reader (const char *portstr)
 {
@@ -1232,6 +1295,7 @@ open_pcsc_reader (const char *portstr)
   size_t len;
   unsigned char msgbuf[9];
   int err;
+  int sw = SW_HOST_CARD_IO_ERROR;
 
   slot = new_reader_slot ();
   if (slot == -1)
@@ -1241,7 +1305,7 @@ open_pcsc_reader (const char *portstr)
   /* Fire up the pcsc wrapper.  We don't use any fork/exec code from
      the common directy but implement it direclty so that this file
      may still be source copied. */
-  
+
   if (pipe (rp) == -1)
     {
       log_error ("error creating a pipe: %s\n", strerror (errno));
@@ -1256,7 +1320,7 @@ open_pcsc_reader (const char *portstr)
       slotp->used = 0;
       return -1;
     }
-      
+
   pid = fork ();
   if (pid == -1)
     {
@@ -1278,7 +1342,7 @@ open_pcsc_reader (const char *portstr)
       /* Double fork. */
       pid = fork ();
       if (pid == -1)
-        _exit (31); 
+        _exit (31);
       if (pid)
         _exit (0); /* Immediate exit this parent, so that the child
                       gets cleaned up by the init process. */
@@ -1288,7 +1352,7 @@ open_pcsc_reader (const char *portstr)
         log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
       if (rp[1] != 1 && dup2 (rp[1], 1) == -1)
         log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
-      
+
       /* Send stderr to the bit bucket. */
       fd = open ("/dev/null", O_WRONLY);
       if (fd == -1)
@@ -1313,7 +1377,7 @@ open_pcsc_reader (const char *portstr)
       _exit (31);
     }
 
-  /* 
+  /*
      === Parent ===
    */
   close (wp[0]);
@@ -1323,9 +1387,9 @@ open_pcsc_reader (const char *portstr)
 
   /* Wait for the intermediate child to terminate. */
 #ifdef USE_GNU_PTH
-#define WAIT pth_waitpid 
+#define WAIT pth_waitpid
 #else
-#define WAIT waitpid 
+#define WAIT waitpid
 #endif
   while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
     ;
@@ -1368,6 +1432,7 @@ open_pcsc_reader (const char *portstr)
   if (err)
     {
       log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
+      sw = pcsc_error_to_sw (err);
       goto command_failed;
     }
 
@@ -1396,7 +1461,7 @@ open_pcsc_reader (const char *portstr)
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
-  dump_reader_status (slot); 
+  dump_reader_status (slot);
   return slot;
 
  command_failed:
@@ -1407,7 +1472,9 @@ open_pcsc_reader (const char *portstr)
   kill (slotp->pcsc.pid, SIGTERM);
   slotp->pcsc.pid = (pid_t)(-1);
   slotp->used = 0;
+  /* There is no way to return SW. */
   return -1;
+
 #else /*!NEED_PCSC_WRAPPER */
   long err;
   int slot;
@@ -1429,7 +1496,7 @@ open_pcsc_reader (const char *portstr)
       reader_table[slot].used = 0;
       return -1;
     }
-  
+
   err = pcsc_list_readers (reader_table[slot].pcsc.context,
                            NULL, NULL, &nreader);
   if (!err)
@@ -1440,7 +1507,7 @@ open_pcsc_reader (const char *portstr)
           log_error ("error allocating memory for reader list\n");
           pcsc_release_context (reader_table[slot].pcsc.context);
           reader_table[slot].used = 0;
-          return -1;
+          return -1 /*SW_HOST_OUT_OF_CORE*/;
         }
       err = pcsc_list_readers (reader_table[slot].pcsc.context,
                                NULL, list, &nreader);
@@ -1452,7 +1519,7 @@ open_pcsc_reader (const char *portstr)
       pcsc_release_context (reader_table[slot].pcsc.context);
       reader_table[slot].used = 0;
       xfree (list);
-      return -1;
+      return -1 /*pcsc_error_to_sw (err)*/;
     }
 
   listlen = nreader;
@@ -1478,7 +1545,7 @@ open_pcsc_reader (const char *portstr)
       log_error ("error allocating memory for reader name\n");
       pcsc_release_context (reader_table[slot].pcsc.context);
       reader_table[slot].used = 0;
-      return -1;
+      return -1 /*SW_HOST_OUT_OF_CORE*/;
     }
   strcpy (reader_table[slot].rdrname, portstr? portstr : list);
   xfree (list);
@@ -1489,7 +1556,7 @@ open_pcsc_reader (const char *portstr)
                       PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
                       &reader_table[slot].pcsc.card,
                       &reader_table[slot].pcsc.protocol);
-  if (err == 0x8010000c) /* No smartcard.  */
+  if (err == PCSC_E_NO_SMARTCARD) 
     reader_table[slot].pcsc.card = 0;
   else if (err)
     {
@@ -1500,8 +1567,8 @@ open_pcsc_reader (const char *portstr)
       reader_table[slot].rdrname = NULL;
       reader_table[slot].used = 0;
       xfree (list);
-      return -1;
-    }      
+      return -1 /*pcsc_error_to_sw (err)*/;
+    }
 
   reader_table[slot].atrlen = 0;
   reader_table[slot].last_status = 0;
@@ -1539,7 +1606,7 @@ open_pcsc_reader (const char *portstr)
 /*   log_debug ("state    from pcsc_status: 0x%lx\n", card_state); */
 /*   log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */
 
-  dump_reader_status (slot); 
+  dump_reader_status (slot);
   return slot;
 #endif /*!NEED_PCSC_WRAPPER */
 }
@@ -1548,7 +1615,7 @@ open_pcsc_reader (const char *portstr)
 
 \f
 #ifdef HAVE_LIBUSB
-/* 
+/*
      Internal CCID driver interface.
  */
 
@@ -1565,16 +1632,16 @@ close_ccid_reader (int slot)
   ccid_close_reader (reader_table[slot].ccid.handle);
   reader_table[slot].used = 0;
   return 0;
-}                       
-  
+}
+
 
 static int
 shutdown_ccid_reader (int slot)
 {
   ccid_shutdown_reader (reader_table[slot].ccid.handle);
   return 0;
-}                       
-  
+}
+
 
 static int
 reset_ccid_reader (int slot)
@@ -1591,10 +1658,10 @@ reset_ccid_reader (int slot)
   assert (sizeof slotp->atr >= sizeof atr);
   slotp->atrlen = atrlen;
   memcpy (slotp->atr, atr, atrlen);
-  dump_reader_status (slot); 
+  dump_reader_status (slot);
   return 0;
-}                       
-  
+}
+
 
 static int
 get_status_ccid (int slot, unsigned int *status)
@@ -1610,7 +1677,7 @@ get_status_ccid (int slot, unsigned int *status)
     *status = 1|2|4;
   else if (bits == 1)
     *status = 2;
-  else 
+  else
     *status = 0;
 
   return 0;
@@ -1642,8 +1709,8 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
   if (err)
     log_error ("ccid_transceive failed: (0x%lx)\n",
                err);
-  
-  return err; 
+
+  return err;
 }
 
 /* Open the reader and try to read an ATR.  */
@@ -1687,7 +1754,7 @@ open_ccid_reader (const char *portstr)
   reader_table[slot].send_apdu_reader = send_apdu_ccid;
   reader_table[slot].dump_status_reader = dump_ccid_reader_status;
 
-  dump_reader_status (slot); 
+  dump_reader_status (slot);
   return slot;
 }
 
@@ -1697,226 +1764,8 @@ open_ccid_reader (const char *portstr)
 
 
 \f
-#ifdef HAVE_OPENSC
-/* 
-     OpenSC Interface.
-
-     This uses the OpenSC primitives to send APDUs.  We need this
-     because we can't mix OpenSC and native (i.e. ctAPI or PC/SC)
-     access to a card for resource conflict reasons.
- */
-
-
-static int
-close_osc_reader (int slot)
-{
-  /* FIXME: Implement. */
-  reader_table[slot].used = 0;
-  return 0;
-}
-
-static int
-reset_osc_reader (int slot)
-{
-  return SW_HOST_NOT_SUPPORTED;
-}
-
-
-static int
-osc_get_status (int slot, unsigned int *status)
-{
-  return SW_HOST_NOT_SUPPORTED;
-}
-
-
-/* Actually send the APDU of length APDULEN to SLOT and return a
-   maximum of *BUFLEN data in BUFFER, the actual returned size will be
-   set to BUFLEN.  Returns: OpenSC error code. */
-static int
-osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-                unsigned char *buffer, size_t *buflen)
-{
-  long err;
-  struct sc_apdu a;
-  unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
-  unsigned char result[SC_MAX_APDU_BUFFER_SIZE];
-
-  if (DBG_CARD_IO)
-    log_printhex ("  APDU_data:", apdu, apdulen);
-
-  if (apdulen < 4)
-    {
-      log_error ("osc_send_apdu: APDU is too short\n");
-      return SW_HOST_INV_VALUE;
-    }
-
-  memset(&a, 0, sizeof a);
-  a.cla = *apdu++;
-  a.ins = *apdu++;
-  a.p1 = *apdu++;
-  a.p2 = *apdu++;
-  apdulen -= 4;
-
-  if (!apdulen)
-    a.cse = SC_APDU_CASE_1;
-  else if (apdulen == 1) 
-    {
-      a.le = *apdu? *apdu : 256;
-      apdu++; apdulen--;
-      a.cse = SC_APDU_CASE_2_SHORT;
-    }
-  else
-    {
-      a.lc = *apdu++; apdulen--;
-      if (apdulen < a.lc)
-        {
-          log_error ("osc_send_apdu: APDU shorter than specified in Lc\n");
-          return SW_HOST_INV_VALUE;
-
-        }
-      memcpy(data, apdu, a.lc);
-      apdu += a.lc; apdulen -= a.lc;
-
-      a.data = data;
-      a.datalen = a.lc;
-      
-      if (!apdulen)
-        a.cse = SC_APDU_CASE_3_SHORT;
-      else
-        {
-          a.le = *apdu? *apdu : 256;
-          apdu++; apdulen--;
-          if (apdulen)
-            {
-              log_error ("osc_send_apdu: APDU larger than specified\n");
-              return SW_HOST_INV_VALUE;
-            }
-          a.cse = SC_APDU_CASE_4_SHORT;
-        }
-    }
-
-  a.resp = result;
-  a.resplen = DIM(result);
-
-  err = sc_transmit_apdu (reader_table[slot].osc.scard, &a);
-  if (err)
-    {
-      log_error ("sc_apdu_transmit failed: %s\n", sc_strerror (err));
-      return SW_HOST_CARD_IO_ERROR;
-    }
-
-  if (*buflen < 2 || a.resplen > *buflen - 2)
-    {
-      log_error ("osc_send_apdu: provided buffer too short to store result\n");
-      return SW_HOST_INV_VALUE;
-    }
-  memcpy (buffer, a.resp, a.resplen);
-  buffer[a.resplen] = a.sw1;
-  buffer[a.resplen+1] = a.sw2;
-  *buflen = a.resplen + 2;
-  return 0;
-}
-
-static int
-open_osc_reader (int portno)
-{
-  int err;
-  int slot;
-  reader_table_t slotp;
-
-  slot = new_reader_slot ();
-  if (slot == -1)
-    return -1;
-  slotp = reader_table + slot;
-
-  err = sc_establish_context (&slotp->osc.ctx, "scdaemon");
-  if (err)
-    {
-      log_error ("failed to establish SC context: %s\n", sc_strerror (err));
-      slotp->used = 0;
-      return -1;
-    }
-  if (portno < 0 || portno >= slotp->osc.ctx->reader_count)
-    {
-      log_error ("no card reader available\n");
-      sc_release_context (slotp->osc.ctx);
-      slotp->used = 0;
-      return -1;
-    }
-
-  /* Redirect to our logging facility. */
-  slotp->osc.ctx->error_file = log_get_stream ();
-  slotp->osc.ctx->debug = opt.debug_sc;
-  slotp->osc.ctx->debug_file = log_get_stream ();
-
-  if (sc_detect_card_presence (slotp->osc.ctx->reader[portno], 0) != 1)
-    {
-      log_error ("no card present\n");
-      sc_release_context (slotp->osc.ctx);
-      slotp->used = 0;
-      return -1;
-    }
-  
-  /* We want the standard ISO driver. */
-  /*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */
-  err = sc_set_card_driver(slotp->osc.ctx, "emv");
-  if (err)
-    {
-      log_error ("failed to select the iso7816 driver: %s\n",
-                 sc_strerror (err));
-      sc_release_context (slotp->osc.ctx);
-      slotp->used = 0;
-      return -1;
-    }
-
-  /* Now connect the card and hope that OpenSC won't try to be too
-     smart. */
-  err = sc_connect_card (slotp->osc.ctx->reader[portno], 0,
-                         &slotp->osc.scard);
-  if (err)
-    {
-      log_error ("failed to connect card in reader %d: %s\n",
-                 portno, sc_strerror (err));
-      sc_release_context (slotp->osc.ctx);
-      slotp->used = 0;
-      return -1;
-    }
-  if (opt.verbose)
-    log_info ("connected to card in opensc reader %d using driver `%s'\n",
-              portno, slotp->osc.scard->driver->name);
-
-  err = sc_lock (slotp->osc.scard);
-  if (err)
-    {
-      log_error ("can't lock card in reader %d: %s\n",
-                 portno, sc_strerror (err));
-      sc_disconnect_card (slotp->osc.scard, 0);
-      sc_release_context (slotp->osc.ctx);
-      slotp->used = 0;
-      return -1;
-    }
-
-  if (slotp->osc.scard->atr_len >= DIM (slotp->atr))
-    log_bug ("ATR returned by opensc is too large\n");
-  slotp->atrlen = slotp->osc.scard->atr_len;
-  memcpy (slotp->atr, slotp->osc.scard->atr, slotp->atrlen);
-
-  reader_table[slot].close_reader = close_osc_reader;
-  reader_table[slot].reset_reader = reset_osc_reader;
-  reader_table[slot].get_status_reader = osc_get_status;
-  reader_table[slot].send_apdu_reader = osc_send_apdu;
-  reader_table[slot].dump_status_reader = NULL;
-
-  dump_reader_status (slot); 
-  return slot;
-}
-
-#endif /* HAVE_OPENSC */
-
-
-\f
 #ifdef USE_G10CODE_RAPDU
-/* 
+/*
      The Remote APDU Interface.
 
      This uses the Remote APDU protocol to contact a reader.
@@ -1935,9 +1784,9 @@ rapdu_status_to_sw (int status)
     {
     case RAPDU_STATUS_SUCCESS:  rc = 0; break;
 
-    case RAPDU_STATUS_INVCMD:  
-    case RAPDU_STATUS_INVPROT:  
-    case RAPDU_STATUS_INVSEQ:  
+    case RAPDU_STATUS_INVCMD:
+    case RAPDU_STATUS_INVPROT:
+    case RAPDU_STATUS_INVSEQ:
     case RAPDU_STATUS_INVCOOKIE:
     case RAPDU_STATUS_INVREADER:  rc = SW_HOST_INV_VALUE;  break;
 
@@ -2002,7 +1851,7 @@ reset_rapdu_reader (int slot)
     {
       log_error ("ATR returned by the RAPDU layer is too large\n");
       rapdu_msg_release (msg);
-      return SW_HOST_INV_VALUE; 
+      return SW_HOST_INV_VALUE;
     }
   slotp->atrlen = msg->datalen;
   memcpy (slotp->atr, msg->data, msg->datalen);
@@ -2056,7 +1905,7 @@ my_rapdu_get_status (int slot, unsigned int *status)
 
 /* Actually send the APDU of length APDULEN to SLOT and return a
    maximum of *BUFLEN data in BUFFER, the actual returned size will be
-   set to BUFLEN.  Returns: OpenSC error code. */
+   set to BUFLEN.  Returns: APDU error code. */
 static int
 my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
                     unsigned char *buffer, size_t *buflen)
@@ -2102,12 +1951,12 @@ my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
       rapdu_msg_release (msg);
       return sw;
     }
-  
+
   if (msg->datalen > maxlen)
     {
       log_error ("rapdu response apdu too large\n");
       rapdu_msg_release (msg);
-      return SW_HOST_INV_VALUE; 
+      return SW_HOST_INV_VALUE;
     }
 
   *buflen = msg->datalen;
@@ -2191,11 +2040,11 @@ open_rapdu_reader (int portno,
   reader_table[slot].send_apdu_reader = my_rapdu_send_apdu;
   reader_table[slot].dump_status_reader = NULL;
 
-  dump_reader_status (slot); 
+  dump_reader_status (slot);
   rapdu_msg_release (msg);
   return slot;
 
- failure:      
+ failure:
   rapdu_msg_release (msg);
   rapdu_release (slotp->rapdu.handle);
   slotp->used = 0;
@@ -2206,7 +2055,7 @@ open_rapdu_reader (int portno,
 
 
 \f
-/* 
+/*
        Driver Access
  */
 
@@ -2251,8 +2100,7 @@ unlock_slot (int slot)
 
 /* Open the reader and return an internal slot number or -1 on
    error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
-   the first USB reader.  For PC/SC the first listed reader).  If
-   OpenSC support is compiled in, we first try to use OpenSC. */
+   the first USB reader.  For PC/SC the first listed reader). */
 int
 apdu_open_reader (const char *portstr)
 {
@@ -2278,16 +2126,6 @@ apdu_open_reader (const char *portstr)
 
 #endif /* HAVE_LIBUSB */
 
-#ifdef HAVE_OPENSC
-  if (!opt.disable_opensc)
-    {
-      int port = portstr? atoi (portstr) : 0;
-
-      return open_osc_reader (port);
-    }
-#endif /* HAVE_OPENSC */  
-
-
   if (opt.ctapi_driver && *opt.ctapi_driver)
     {
       int port = portstr? atoi (portstr) : 32768;
@@ -2295,7 +2133,7 @@ apdu_open_reader (const char *portstr)
       if (!ct_api_loaded)
         {
           void *handle;
-          
+
           handle = dlopen (opt.ctapi_driver, RTLD_LAZY);
           if (!handle)
             {
@@ -2317,7 +2155,7 @@ apdu_open_reader (const char *portstr)
       return open_ct_reader (port);
     }
 
-  
+
   /* No ctAPI configured, so lets try the PC/SC API */
   if (!pcsc_api_loaded)
     {
@@ -2366,16 +2204,16 @@ apdu_open_reader (const char *portstr)
       pcsc_set_timeout       = dlsym (handle, "SCardSetTimeout");
 
       if (!pcsc_establish_context
-          || !pcsc_release_context  
-          || !pcsc_list_readers     
+          || !pcsc_release_context
+          || !pcsc_list_readers
           || !pcsc_get_status_change
-          || !pcsc_connect          
+          || !pcsc_connect
           || !pcsc_reconnect
           || !pcsc_disconnect
           || !pcsc_status
           || !pcsc_begin_transaction
           || !pcsc_end_transaction
-          || !pcsc_transmit         
+          || !pcsc_transmit
           /* || !pcsc_set_timeout */)
         {
           /* Note that set_timeout is currently not used and also not
@@ -2383,21 +2221,21 @@ apdu_open_reader (const char *portstr)
           log_error ("apdu_open_reader: invalid PC/SC driver "
                      "(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
                      !!pcsc_establish_context,
-                     !!pcsc_release_context,  
-                     !!pcsc_list_readers,     
-                     !!pcsc_get_status_change,     
-                     !!pcsc_connect,          
-                     !!pcsc_reconnect,          
+                     !!pcsc_release_context,
+                     !!pcsc_list_readers,
+                     !!pcsc_get_status_change,
+                     !!pcsc_connect,
+                     !!pcsc_reconnect,
                      !!pcsc_disconnect,
                      !!pcsc_status,
                      !!pcsc_begin_transaction,
                      !!pcsc_end_transaction,
-                     !!pcsc_transmit,         
+                     !!pcsc_transmit,
                      !!pcsc_set_timeout );
           dlclose (handle);
           return -1;
         }
-#endif /*!NEED_PCSC_WRAPPER*/  
+#endif /*!NEED_PCSC_WRAPPER*/
       pcsc_api_loaded = 1;
     }
 
@@ -2411,7 +2249,7 @@ apdu_open_reader (const char *portstr)
    only be called once and the slot will not be valid afther this.
 
    If PORTSTR is NULL we default to the first availabe port.
-*/  
+*/
 int
 apdu_open_remote_reader (const char *portstr,
                          const unsigned char *cookie, size_t length,
@@ -2431,7 +2269,7 @@ apdu_open_remote_reader (const char *portstr,
                             writefnc, writefnc_value,
                             closefnc, closefnc_value);
 #else
-#ifdef _WIN32 
+#ifdef _WIN32
   errno = ENOENT;
 #else
   errno = ENOSYS;
@@ -2484,7 +2322,7 @@ apdu_reset (int slot)
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
-  
+
   if ((sw = lock_slot (slot)))
     return sw;
 
@@ -2516,7 +2354,7 @@ apdu_activate (int slot)
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
-  
+
   if ((sw = trylock_slot (slot)))
     return sw;
 
@@ -2545,21 +2383,21 @@ apdu_activate (int slot)
             }
         }
     }
-  
+
   unlock_slot (slot);
   return sw;
 }
 
-  
+
 
 unsigned char *
 apdu_get_atr (int slot, size_t *atrlen)
 {
-  char *buf;
+  unsigned char *buf;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return NULL;
-  
+
   buf = xtrymalloc (reader_table[slot].atrlen);
   if (!buf)
     return NULL;
@@ -2569,7 +2407,7 @@ apdu_get_atr (int slot, size_t *atrlen)
 }
 
 
-    
+
 /* Retrieve the status for SLOT. The function does only wait for the
    card to become available if HANG is set to true. On success the
    bits in STATUS will be set to
@@ -2655,7 +2493,7 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
    returned data.  The length of that data will be put into
    *RETBUFLEN.  The caller is reponsible for releasing the buffer even
    in case of errors.  */
-int 
+int
 apdu_send_le(int slot, int class, int ins, int p0, int p1,
              int lc, const char *data, int le,
              unsigned char **retbuf, size_t *retbuflen)
@@ -2677,9 +2515,9 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
                class, ins, p0, p1, lc, le);
 
   if (lc != -1 && (lc > 255 || lc < 0))
-    return SW_WRONG_LENGTH; 
+    return SW_WRONG_LENGTH;
   if (le != -1 && (le > 256 || le < 1))
-    return SW_WRONG_LENGTH; 
+    return SW_WRONG_LENGTH;
   if ((!data && lc != -1) || (data && lc == -1))
     return SW_HOST_INV_VALUE;
 
@@ -2716,7 +2554,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
   resultlen -= 2;
   if (DBG_CARD_IO)
     {
-      log_debug (" response: sw=%04X  datalen=%d\n", sw, resultlen);
+      log_debug (" response: sw=%04X  datalen=%d\n",
+                 sw, (unsigned int)resultlen);
       if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
         log_printhex ("     dump: ", result, resultlen);
     }
@@ -2758,7 +2597,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
       do
         {
           int len = (sw & 0x00ff);
-          
+
           if (DBG_CARD_IO)
             log_debug ("apdu_send_simple(%d): %d more bytes available\n",
                        slot, len);
@@ -2767,7 +2606,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
           apdu[apdulen++] = 0xC0;
           apdu[apdulen++] = 0;
           apdu[apdulen++] = 0;
-          apdu[apdulen++] = len; 
+          apdu[apdulen++] = len;
           memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
           resultlen = RESULTLEN;
           rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
@@ -2782,7 +2621,8 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
           resultlen -= 2;
           if (DBG_CARD_IO)
             {
-              log_debug ("     more: sw=%04X  datalen=%d\n", sw, resultlen);
+              log_debug ("     more: sw=%04X  datalen=%d\n",
+                         sw, (unsigned int)resultlen);
               if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
                 log_printhex ("     dump: ", result, resultlen);
             }
@@ -2815,7 +2655,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
                       slot, sw);
         }
       while ((sw & 0xff00) == SW_MORE_DATA);
-      
+
       if (retbuf)
         {
           *retbuflen = p - *retbuf;
@@ -2829,7 +2669,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
 
   if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS)
     log_printhex ("      dump: ", *retbuf, *retbuflen);
+
   return sw;
 #undef RESULTLEN
 }
@@ -2843,11 +2683,11 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
    data.  The length of that data will be put into *RETBUFLEN.  The
    caller is reponsible for releasing the buffer even in case of
    errors.  */
-int 
+int
 apdu_send (int slot, int class, int ins, int p0, int p1,
            int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
 {
-  return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256, 
+  return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256,
                        retbuf, retbuflen);
 }
 
@@ -2857,7 +2697,7 @@ apdu_send (int slot, int class, int ins, int p0, int p1,
    also be passed as NULL. The return value is the status word or -1
    for an invalid SLOT or other non card related error.  No data will be
    returned. */
-int 
+int
 apdu_send_simple (int slot, int class, int ins, int p0, int p1,
                   int lc, const char *data)
 {
@@ -2873,7 +2713,7 @@ apdu_send_simple (int slot, int class, int ins, int p0, int p1,
    the end.  The function does not return a regular status word but 0
    on success.  If the slot is locked, the fucntion returns
    immediately.*/
-int 
+int
 apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
                   int handle_more,
                   unsigned char **retbuf, size_t *retbuflen)
@@ -2915,7 +2755,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
   resultlen -= 2;
   if (DBG_CARD_IO)
     {
-      log_debug (" response: sw=%04X  datalen=%d\n", sw, resultlen);
+      log_debug (" response: sw=%04X  datalen=%d\n",
+                 sw, (unsigned int)resultlen);
       if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
         log_printhex ("     dump: ", result, resultlen);
     }
@@ -2943,7 +2784,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
       do
         {
           int len = (sw & 0x00ff);
-          
+
           if (DBG_CARD_IO)
             log_debug ("apdu_send_direct(%d): %d more bytes available\n",
                        slot, len);
@@ -2952,7 +2793,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
           apdu[apdulen++] = 0xC0;
           apdu[apdulen++] = 0;
           apdu[apdulen++] = 0;
-          apdu[apdulen++] = len; 
+          apdu[apdulen++] = len;
           memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
           resultlen = RESULTLEN;
           rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
@@ -2967,7 +2808,8 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
           resultlen -= 2;
           if (DBG_CARD_IO)
             {
-              log_debug ("     more: sw=%04X  datalen=%d\n", sw, resultlen);
+              log_debug ("     more: sw=%04X  datalen=%d\n",
+                         sw, (unsigned int)resultlen);
               if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
                 log_printhex ("     dump: ", result, resultlen);
             }
@@ -3000,7 +2842,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
                       slot, sw);
         }
       while ((sw & 0xff00) == SW_MORE_DATA);
-      
+
       if (retbuf)
         {
           *retbuflen = p - *retbuf;
@@ -3036,9 +2878,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
 
   if (DBG_CARD_IO && retbuf)
     log_printhex ("      dump: ", *retbuf, *retbuflen);
+
   return 0;
 #undef RESULTLEN
 }
-
-
index 15e9293..2eb36ac 100644 (file)
@@ -1,5 +1,5 @@
 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
- *     Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
  *      Written by Werner Koch.
  *
  * This file is part of GnuPG.
@@ -52,7 +52,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $Id: ccid-driver.c,v 1.1.2.21 2004/10/20 08:54:45 wk Exp $
+ * $Date: 2005/06/16 08:11:59 $
  */
 
 
 #  include "scdaemon.h"
 #endif
 
-/* Define to print information pertaining the T=1 protocol. */
-#undef DEBUG_T1 
-
 
 # define DEBUGOUT(t)         do { if (debug_level) \
                                   log_debug (DRVNAME t); } while (0)
                                   log_debug (DRVNAME t,(a),(b)); } while (0)
 # define DEBUGOUT_3(t,a,b,c) do { if (debug_level) \
                                   log_debug (DRVNAME t,(a),(b),(c));} while (0)
+# define DEBUGOUT_4(t,a,b,c,d) do { if (debug_level) \
+                              log_debug (DRVNAME t,(a),(b),(c),(d));} while (0)
 # define DEBUGOUT_CONT(t)    do { if (debug_level) \
                                   log_printf (t); } while (0)
 # define DEBUGOUT_CONT_1(t,a)  do { if (debug_level) \
                      fprintf (stderr, DRVNAME t, (a), (b)); } while (0)
 # define DEBUGOUT_3(t,a,b,c)  do { if (debug_level) \
                      fprintf (stderr, DRVNAME t, (a), (b), (c)); } while (0)
+# define DEBUGOUT_4(t,a,b,c,d)  do { if (debug_level) \
+                     fprintf (stderr, DRVNAME t, (a), (b), (c), (d));} while(0)
 # define DEBUGOUT_CONT(t)     do { if (debug_level) \
                      fprintf (stderr, t); } while (0)
 # define DEBUGOUT_CONT_1(t,a) do { if (debug_level) \
@@ -183,9 +184,18 @@ enum {
 };
 
 
+/* Two macro to detect whether a CCID command has failed and to get
+   the error code.  These macros assume that we can access the
+   mandatory first 10 bytes of a CCID message in BUF. */
+#define CCID_COMMAND_FAILED(buf) ((buf)[7] & 0x40)
+#define CCID_ERROR_CODE(buf)     (((unsigned char *)(buf))[8])
+
+
 /* We need to know the vendor to do some hacks. */
 enum {
-  VENDOR_SCM = 0x04e6
+  VENDOR_SCM    = 0x04e6,
+  VENDOR_CHERRY = 0x046a,
+  VENDOR_GEMPC  = 0x08e6
 };
 
 
@@ -198,6 +208,10 @@ struct ccid_driver_s
   unsigned short id_vendor;
   unsigned short id_product;
   unsigned short bcd_device;
+  int ifc_no;
+  int ep_bulk_out;
+  int ep_bulk_in;
+  int ep_intr;
   int seqno;
   unsigned char t1_ns;
   unsigned char t1_nr;
@@ -207,18 +221,24 @@ struct ccid_driver_s
   int ifsd;
   int powered_off;
   int has_pinpad;
+  int apdu_level;     /* Reader supports short APDU level exchange.  */
 };
 
 
 static int initialized_usb; /* Tracks whether USB has been initialized. */
-static int debug_level;     /* Flag to control the debug output.  */
+static int debug_level;     /* Flag to control the debug output. 
+                               0 = No debugging
+                               1 = USB I/O info
+                               2 = T=1 protocol tracing
+                              */
 
 
 static unsigned int compute_edc (const unsigned char *data, size_t datalen,
                                  int use_crc);
 static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
 static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
-                    size_t *nread, int expected_type, int seqno);
+                    size_t *nread, int expected_type, int seqno, int timeout,
+                    int no_debug);
 
 /* Convert a little endian stored 4 byte value into an unsigned
    integer. */
@@ -238,6 +258,53 @@ set_msg_len (unsigned char *msg, unsigned int length)
 }
 
 
+/* Pint an error message for a failed CCID command including a textual
+   error code.  MSG is shall be the CCID message of at least 10 bytes. */
+static void
+print_command_failed (const unsigned char *msg)
+{
+  const char *t;
+  char buffer[100];
+  int ec;
+
+  if (!debug_level)
+    return;
+
+  ec = CCID_ERROR_CODE (msg);
+  switch (ec)
+    {
+    case 0x00: t = "Command not supported"; break;
+    
+    case 0xE0: t = "Slot busy"; break;
+    case 0xEF: t = "PIN cancelled"; break;
+    case 0xF0: t = "PIN timeout"; break;
+
+    case 0xF2: t = "Automatic sequence ongoing"; break;
+    case 0xF3: t = "Deactivated Protocol"; break;
+    case 0xF4: t = "Procedure byte conflict"; break;
+    case 0xF5: t = "ICC class not supported"; break;
+    case 0xF6: t = "ICC protocol not supported"; break;
+    case 0xF7: t = "Bad checksum in ATR"; break;
+    case 0xF8: t = "Bad TS in ATR"; break;
+
+    case 0xFB: t = "An all inclusive hardware error occurred"; break;
+    case 0xFC: t = "Overrun error while talking to the ICC"; break;
+    case 0xFD: t = "Parity error while talking to the ICC"; break;
+    case 0xFE: t = "CCID timed out while talking to the ICC"; break;
+    case 0xFF: t = "Host aborted the current activity"; break;
+
+    default:
+      if (ec > 0 && ec < 128)
+        sprintf (buffer, "Parameter error at offset %d", ec);
+      else
+        sprintf (buffer, "Error code %02X", ec);
+      t = buffer;
+      break;
+    }
+  DEBUGOUT_1 ("CCID command failed: %s\n", t);
+}
+  
+
 
 
 /* Parse a CCID descriptor, optionally print all available features
@@ -260,6 +327,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   handle->max_ifsd = 32;
   handle->ifsd = 0;
   handle->has_pinpad = 0;
+  handle->apdu_level = 0;
   DEBUGOUT_3 ("idVendor: %04X  idProduct: %04X  bcdDevice: %04X\n",
               handle->id_vendor, handle->id_product, handle->bcd_device);
   if (buflen < 54 || buf[0] < 54)
@@ -372,9 +440,15 @@ parse_ccid_descriptor (ccid_driver_t handle,
       have_tpdu = 1;
     } 
   else if ((us & 0x00020000))
-    DEBUGOUT ("    Short APDU level exchange\n");
+    {
+      DEBUGOUT ("    Short APDU level exchange\n");
+      handle->apdu_level = 1;
+    }
   else if ((us & 0x00040000))
-    DEBUGOUT ("    Short and extended APDU level exchange\n");
+    {
+      DEBUGOUT ("    Short and extended APDU level exchange\n");
+      handle->apdu_level = 1;
+    }
   else if ((us & 0x00070000))
     DEBUGOUT ("    WARNING: conflicting exchange levels\n");
 
@@ -391,7 +465,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   if (buf[49] == 0xff)
     DEBUGOUT_CONT ("echo\n");
   else
-    DEBUGOUT_1 ("  %02X\n", buf[48]);
+    DEBUGOUT_CONT_1 ("  %02X\n", buf[48]);
 
   DEBUGOUT (  "  wlcdLayout           ");
   if (!buf[50] && !buf[51])
@@ -421,10 +495,10 @@ parse_ccid_descriptor (ccid_driver_t handle,
     DEBUGOUT_LF ();
   }
 
-  if (!have_t1 || !have_tpdu || !have_auto_conf)
+  if (!have_t1 || !(have_tpdu  || handle->apdu_level) || !have_auto_conf)
     {
       DEBUGOUT ("this drivers requires that the reader supports T=1, "
-                "TPDU level exchange and auto configuration - "
+                "TPDU or APDU level exchange and auto configuration - "
                 "this is not available\n");
       return -1;
     }
@@ -434,12 +508,20 @@ parse_ccid_descriptor (ccid_driver_t handle,
      send a frame of n*wMaxPacketSize back to us.  Given that
      wMaxPacketSize is 64 for these readers we set the IFSD to a value
      lower than that:
-        64 - 10 CCID header -  4 T1frame - 2 reserved = 48 */
+        64 - 10 CCID header -  4 T1frame - 2 reserved = 48
+     Product Ids:
+        0xe001 - SCR 331 
+        0x5111 - SCR 331-DI 
+        0x5115 - SCR 335 
+        0xe003 - SPR 532 
+  */
   if (handle->id_vendor == VENDOR_SCM
-      /* FIXME: check whether it is the same
-                firmware version for all drivers.  */
-      && handle->bcd_device < 0x0513
-      && handle->max_ifsd > 48)
+      && handle->max_ifsd > 48      
+      && (  (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
+          ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
+          ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0514)
+          ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
+          ))
     {
       DEBUGOUT ("enabling workaround for buggy SCM readers\n");
       handle->max_ifsd = 48;
@@ -473,7 +555,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
      all in a 2 bute Unicode encoding using little endian. */
   rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
                         (USB_DT_STRING << 8), 0, 
-                        buf, sizeof buf, 1000 /* ms timeout */);
+                        (char*)buf, sizeof buf, 1000 /* ms timeout */);
   if (rc < 4)
     langid = 0x0409; /* English.  */
   else
@@ -481,7 +563,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
 
   rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
                         (USB_DT_STRING << 8) + idx, langid,
-                        buf, sizeof buf, 1000 /* ms timeout */);
+                        (char*)buf, sizeof buf, 1000 /* ms timeout */);
   if (rc < 2 || buf[1] != USB_DT_STRING)
     return NULL; /* Error or not a string. */
   len = buf[0];
@@ -546,6 +628,36 @@ make_reader_id (usb_dev_handle *idev,
 }
 
 
+/* Helper to find the endpoint from an interface descriptor.  */
+static int
+find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
+{
+  int no;
+  int want_bulk_in = 0;
+
+  if (mode == 1)
+    want_bulk_in = 0x80;
+  for (no=0; no < ifcdesc->bNumEndpoints; no++)
+    {
+      struct usb_endpoint_descriptor *ep = ifcdesc->endpoint + no;
+      if (ep->bDescriptorType != USB_DT_ENDPOINT)
+        ;
+      else if (mode == 2
+          && ((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+              == USB_ENDPOINT_TYPE_INTERRUPT)
+          && (ep->bEndpointAddress & 0x80))
+        return (ep->bEndpointAddress & 0x0f);
+      else if (((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+                == USB_ENDPOINT_TYPE_BULK)
+               && (ep->bEndpointAddress & 0x80) == want_bulk_in)
+        return (ep->bEndpointAddress & 0x0f);
+    }
+  /* Should never happen.  */
+  return mode == 2? 0x83 : mode == 1? 0x82 :1;
+}
+
+
+
 /* Combination function to either scan all CCID devices or to find and
    open one specific device. 
 
@@ -579,7 +691,9 @@ scan_or_find_devices (int readerno, const char *readerid,
                       char **r_rid,
                       struct usb_device **r_dev,
                       unsigned char **ifcdesc_extra,
-                      size_t *ifcdesc_extra_len)
+                      size_t *ifcdesc_extra_len,
+                      int *interface_number,
+                      int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
 {
   char *rid_list = NULL;
   int count = 0;
@@ -597,6 +711,8 @@ scan_or_find_devices (int readerno, const char *readerid,
     *ifcdesc_extra = NULL;
   if (ifcdesc_extra_len)
     *ifcdesc_extra_len = 0;
+  if (interface_number)
+    *interface_number = 0;
 
   /* See whether we want scan or find mode. */
   if (scan_mode) 
@@ -653,9 +769,7 @@ scan_or_find_devices (int readerno, const char *readerid,
                                   && ifcdesc->bInterfaceProtocol == 0)
                               || (ifcdesc->bInterfaceClass == 255
                                   && dev->descriptor.idVendor == 0x04e6
-                                  && dev->descriptor.idProduct == 0xe003
-                                  && ifcdesc->bInterfaceSubClass == 1
-                                  && ifcdesc->bInterfaceProtocol == 1)))
+                                  && dev->descriptor.idProduct == 0xe003)))
                         {
                           idev = usb_open (dev);
                           if (!idev)
@@ -721,6 +835,16 @@ scan_or_find_devices (int readerno, const char *readerid,
                                               ifcdesc->extralen);
                                       *ifcdesc_extra_len = ifcdesc->extralen;
                                     }
+                                  if (interface_number)
+                                    *interface_number = (ifcdesc->
+                                                         bInterfaceNumber);
+                                  if (ep_bulk_out)
+                                    *ep_bulk_out = find_endpoint (ifcdesc, 0);
+                                  if (ep_bulk_in)
+                                    *ep_bulk_in = find_endpoint (ifcdesc, 1);
+                                  if (ep_intr)
+                                    *ep_intr = find_endpoint (ifcdesc, 2);
+
 
                                   if (r_dev)
                                     *r_dev = dev;
@@ -765,7 +889,8 @@ scan_or_find_devices (int readerno, const char *readerid,
 
 /* Set the level of debugging to to usea dn return the old level.  -1
    just returns the old level.  A level of 0 disables debugging, 1
-   enables debugging, other values are not yet defined. */
+   enables debugging, 2 enables additional tracing of the T=1
+   protocol, other values are not yet defined. */
 int
 ccid_set_debug_level (int level)
 {
@@ -787,7 +912,8 @@ ccid_get_reader_list (void)
       initialized_usb = 1;
     }
 
-  scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL);
+  scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
+                        NULL, NULL, NULL);
   return reader_list;
 }
 
@@ -804,6 +930,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
   unsigned char *ifcdesc_extra = NULL;
   size_t ifcdesc_extra_len;
   int readerno;
+  int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
 
   *handle = NULL;
 
@@ -832,7 +959,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
     readerno = 0;  /* Default. */
 
   idev = scan_or_find_devices (readerno, readerid, &rid, &dev,
-                               &ifcdesc_extra, &ifcdesc_extra_len);
+                               &ifcdesc_extra, &ifcdesc_extra_len,
+                               &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
   if (!idev)
     {
       if (readerno == -1)
@@ -856,6 +984,10 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
   (*handle)->id_vendor = dev->descriptor.idVendor;
   (*handle)->id_product = dev->descriptor.idProduct;
   (*handle)->bcd_device = dev->descriptor.bcdDevice;
+  (*handle)->ifc_no = ifc_no;
+  (*handle)->ep_bulk_out = ep_bulk_out;
+  (*handle)->ep_bulk_in = ep_bulk_in;
+  (*handle)->ep_intr = ep_intr;
 
   DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n",  readerno, rid );
 
@@ -867,9 +999,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
       goto leave;
     }
   
-  /* fixme: Do we need to claim and set the interface as
-     determined above? */
-  rc = usb_claim_interface (idev, 0);
+  rc = usb_claim_interface (idev, ifc_no);
   if (rc)
     {
       DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
@@ -877,9 +1007,6 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
       goto leave;
     }
   
-  /* FIXME: Do we need to get the endpoint addresses from the
-     structure and store them with the handle? */
-              
  leave:
   free (ifcdesc_extra);
   if (rc)
@@ -916,12 +1043,13 @@ do_close_reader (ccid_driver_t handle)
       
       rc = bulk_out (handle, msg, msglen);
       if (!rc)
-        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno);
+        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+                 seqno, 2000, 0);
       handle->powered_off = 1;
     }
   if (handle->idev)
     {
-      usb_release_interface (handle->idev, 0);
+      usb_release_interface (handle->idev, handle->ifc_no);
       usb_close (handle->idev);
       handle->idev = NULL;
     }
@@ -944,6 +1072,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
   usb_dev_handle *idev = NULL;
   unsigned char *ifcdesc_extra = NULL;
   size_t ifcdesc_extra_len;
+  int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
 
   if (!handle || !handle->rid)
     return CCID_DRIVER_ERR_INV_VALUE;
@@ -951,7 +1080,8 @@ ccid_shutdown_reader (ccid_driver_t handle)
   do_close_reader (handle);
 
   idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
-                               &ifcdesc_extra, &ifcdesc_extra_len);
+                               &ifcdesc_extra, &ifcdesc_extra_len,
+                               &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
   if (!idev)
     {
       DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
@@ -960,6 +1090,10 @@ ccid_shutdown_reader (ccid_driver_t handle)
 
 
   handle->idev = idev;
+  handle->ifc_no = ifc_no;
+  handle->ep_bulk_out = ep_bulk_out;
+  handle->ep_bulk_in = ep_bulk_in;
+  handle->ep_intr = ep_intr;
 
   if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
     {
@@ -968,9 +1102,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
       goto leave;
     }
   
-  /* fixme: Do we need to claim and set the interface as
-     determined above? */
-  rc = usb_claim_interface (idev, 0);
+  rc = usb_claim_interface (idev, ifc_no);
   if (rc)
     {
       DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
@@ -1022,8 +1154,8 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
   int rc;
 
   rc = usb_bulk_write (handle->idev, 
-                       1, /*endpoint */
-                       msg, msglen,
+                       handle->ep_bulk_out,
+                       (char*)msg, msglen,
                        1000 /* ms timeout */);
   if (rc == msglen)
     return 0;
@@ -1040,10 +1172,12 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
    BUFFER and return the actual read number if bytes in NREAD. SEQNO
    is the sequence number used to send the request and EXPECTED_TYPE
    the type of message we expect. Does checks on the ccid
-   header. Returns 0 on success. */
+   header. TIMEOUT is the timeout value in ms. NO_DEBUG may be set to
+   avoid debug messages in case of no error. Returns 0 on success. */
 static int
 bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
-         size_t *nread, int expected_type, int seqno)
+         size_t *nread, int expected_type, int seqno, int timeout,
+         int no_debug)
 {
   int i, rc;
   size_t msglen;
@@ -1053,11 +1187,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
   memset (buffer, 0, length);
  retry:
   rc = usb_bulk_read (handle->idev, 
-                      0x82,
-                      buffer, length,
-                      10000 /* ms timeout */ );
-  /* Fixme: instead of using a 10 second timeout we should better
-     handle the timeout here and retry if appropriate.  */
+                      handle->ep_bulk_in,
+                      (char*)buffer, length,
+                      timeout);
   if (rc < 0)
     {
       DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
@@ -1095,13 +1227,19 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
                   buffer[7], buffer[8]);
       goto retry;
     }
-  
-  DEBUGOUT_3 ("status: %02X  error: %02X  octet[9]: %02X\n"
-              "               data:",  buffer[7], buffer[8], buffer[9] );
-  for (i=10; i < msglen; i++)
-    DEBUGOUT_CONT_1 (" %02X", buffer[i]);
-  DEBUGOUT_LF ();
 
+  if (!no_debug)
+    {
+      DEBUGOUT_3 ("status: %02X  error: %02X  octet[9]: %02X\n"
+                  "               data:",  buffer[7], buffer[8], buffer[9] );
+      for (i=10; i < msglen; i++)
+        DEBUGOUT_CONT_1 (" %02X", buffer[i]);
+      DEBUGOUT_LF ();
+    }
+  if (CCID_COMMAND_FAILED (buffer))
+    print_command_failed (buffer);
+
+  /* Check whether a card is at all available. */
   switch ((buffer[7] & 0x03))
     {
     case 0: /* no error */ break;
@@ -1113,7 +1251,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
 }
 
 
-/* Note that this fucntion won't return the error codes NO_CARD or
+/* Note that this function won't return the error codes NO_CARD or
    CARD_INACTIVE */
 static int 
 send_escape_cmd (ccid_driver_t handle,
@@ -1144,7 +1282,8 @@ send_escape_cmd (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
+                seqno, 5000, 0);
 
   return rc;
 }
@@ -1160,8 +1299,8 @@ ccid_poll (ccid_driver_t handle)
   int i, j;
 
   rc = usb_bulk_read (handle->idev, 
-                      0x83,
-                      msg, sizeof msg,
+                      handle->ep_intr,
+                      (char*)msg, sizeof msg,
                       0 /* ms timeout */ );
   if (rc < 0 && errno == ETIMEDOUT)
     return 0;
@@ -1214,7 +1353,9 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
   unsigned char msg[100];
   size_t msglen;
   unsigned char seqno;
+  int retries = 0;
 
+ retry:
   msg[0] = PC_to_RDR_GetSlotStatus;
   msg[5] = 0; /* slot */
   msg[6] = seqno = handle->seqno++;
@@ -1226,7 +1367,24 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
   rc = bulk_out (handle, msg, 10);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
+  /* Note that we set the NO_DEBUG flag here, so that the logs won't
+     get cluttered up by a ticker function checking for the slot
+     status and debugging enabled. */
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+                seqno, retries? 1000 : 200, 1);
+  if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
+    {
+      if (!retries)
+        {
+          DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n");
+          usb_clear_halt (handle->idev, handle->ep_bulk_in);
+          usb_clear_halt (handle->idev, handle->ep_bulk_out);
+        }
+      else
+          DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n");
+      retries++;
+      goto retry;
+    }
   if (rc && rc != CCID_DRIVER_ERR_NO_CARD
       && rc != CCID_DRIVER_ERR_CARD_INACTIVE)
     return rc;
@@ -1241,6 +1399,7 @@ ccid_get_atr (ccid_driver_t handle,
               unsigned char *atr, size_t maxatrlen, size_t *atrlen)
 {
   int rc;
+  int statusbits;
   unsigned char msg[100];
   unsigned char *tpdu;
   size_t msglen, tpdulen;
@@ -1248,7 +1407,18 @@ ccid_get_atr (ccid_driver_t handle,
   int use_crc = 0;
   unsigned int edc;
   int i;
+  int tried_iso = 0;
+
+  /* First check whether a card is available.  */
+  rc = ccid_slot_status (handle, &statusbits);
+  if (rc)
+    return rc;
+  if (statusbits == 2)
+    return CCID_DRIVER_ERR_NO_CARD;
 
+  /* For an inactive and also for an active card, issue the PowerOn
+     command to get the ATR.  */
+ again:
   msg[0] = PC_to_RDR_IccPowerOn;
   msg[5] = 0; /* slot */
   msg[6] = seqno = handle->seqno++;
@@ -1261,9 +1431,25 @@ ccid_get_atr (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
+                seqno, 5000, 0);
   if (rc)
     return rc;
+  if (!tried_iso && CCID_COMMAND_FAILED (msg) && CCID_ERROR_CODE (msg) == 0xbb
+      && ((handle->id_vendor == VENDOR_CHERRY
+           && handle->id_product == 0x0005)
+          || (handle->id_vendor == VENDOR_GEMPC
+              && handle->id_product == 0x4433)
+          ))
+    {
+      tried_iso = 1;
+      /* Try switching to ISO mode. */
+      if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2))
+        goto again;
+    }
+  else if (CCID_COMMAND_FAILED (msg))
+    return CCID_DRIVER_ERR_CARD_IO_ERROR;
+
 
   handle->powered_off = 0;
   
@@ -1305,7 +1491,8 @@ ccid_get_atr (ccid_driver_t handle,
   if (rc)
     return rc;
   /* Note that we ignore the error code on purpose. */
-  bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
+  bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+           seqno, 5000, 0);
 
   handle->t1_ns = 0;
   handle->t1_nr = 0;
@@ -1339,12 +1526,13 @@ ccid_get_atr (ccid_driver_t handle,
         DEBUGOUT_CONT_1 (" %02X", msg[i]);
       DEBUGOUT_LF ();
 
-#ifdef DEBUG_T1      
-      fprintf (stderr, "T1: put %c-block seq=%d\n",
-               ((msg[11] & 0xc0) == 0x80)? 'R' :
-               (msg[11] & 0x80)? 'S' : 'I',
-               ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
-#endif  
+      if (debug_level > 1)
+        DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n",
+                      ((msg[11] & 0xc0) == 0x80)? 'R' :
+                                (msg[11] & 0x80)? 'S' : 'I',
+                      ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+                                       : !!(msg[11] & 0x40)),
+                    (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
 
       rc = bulk_out (handle, msg, msglen);
       if (rc)
@@ -1352,7 +1540,7 @@ ccid_get_atr (ccid_driver_t handle,
 
 
       rc = bulk_in (handle, msg, sizeof msg, &msglen,
-                    RDR_to_PC_DataBlock, seqno);
+                    RDR_to_PC_DataBlock, seqno, 5000, 0);
       if (rc)
         return rc;
       
@@ -1362,14 +1550,15 @@ ccid_get_atr (ccid_driver_t handle,
       if (tpdulen < 4) 
         return CCID_DRIVER_ERR_ABORTED; 
 
-#ifdef DEBUG_T1
-      fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
-               ((msg[11] & 0xc0) == 0x80)? 'R' :
-               (msg[11] & 0x80)? 'S' : 'I',
-               ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
-               ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
-               );
-#endif
+      if (debug_level > 1)
+        DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+                    ((msg[11] & 0xc0) == 0x80)? 'R' :
+                              (msg[11] & 0x80)? 'S' : 'I',
+                    ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+                                     : !!(msg[11] & 0x40)),
+                    ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+                    (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
+
       if ((tpdu[1] & 0xe0) != 0xe0 || tpdu[2] != 1)
         {
           DEBUGOUT ("invalid response for S-block (Change-IFSD)\n");
@@ -1402,6 +1591,78 @@ compute_edc (const unsigned char *data, size_t datalen, int use_crc)
 }
 
 
+/* Helper for ccid_transceive used for APDU level exchanges.  */
+static int
+ccid_transceive_apdu_level (ccid_driver_t handle,
+                            const unsigned char *apdu_buf, size_t apdu_buflen,
+                            unsigned char *resp, size_t maxresplen,
+                            size_t *nresp)
+{
+  int rc;
+  unsigned char send_buffer[10+259], recv_buffer[10+259];
+  const unsigned char *apdu;
+  size_t apdulen;
+  unsigned char *msg;
+  size_t msglen;
+  unsigned char seqno;
+  int i;
+
+  msg = send_buffer;
+
+  apdu = apdu_buf;
+  apdulen = apdu_buflen;
+  assert (apdulen);
+
+  if (apdulen > 254)
+    return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
+
+  msg[0] = PC_to_RDR_XfrBlock;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 4; /* bBWI */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  memcpy (msg+10, apdu, apdulen);
+  set_msg_len (msg, apdulen);
+  msglen = 10 + apdulen;
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+  
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+
+  msg = recv_buffer;
+  rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+                RDR_to_PC_DataBlock, seqno, 5000, 0);
+  if (rc)
+    return rc;
+      
+  apdu = msg + 10;
+  apdulen = msglen - 10;
+      
+  if (resp)
+    {
+      if (apdulen > maxresplen)
+        {
+          DEBUGOUT_2 ("provided buffer too short for received data "
+                      "(%u/%u)\n",
+                      (unsigned int)apdulen, (unsigned int)maxresplen);
+          return CCID_DRIVER_ERR_INV_VALUE;
+        }
+      
+      memcpy (resp, apdu, apdulen); 
+      *nresp = apdulen;
+    }
+          
+  return 0;
+}
+
+
+
 /*
   Protocol T=1 overview
 
@@ -1478,6 +1739,13 @@ ccid_transceive (ccid_driver_t handle,
     nresp = &dummy_nresp;
   *nresp = 0;
 
+  /* Smarter readers allow to send APDUs directly; divert here. */
+  if (handle->apdu_level)
+    return ccid_transceive_apdu_level (handle, apdu_buf, apdu_buflen,
+                                       resp, maxresplen, nresp);
+
+  /* The other readers we support require sending TPDUs.  */
+
   tpdulen = 0; /* Avoid compiler warning about no initialization. */
   msg = send_buffer;
   for (;;)
@@ -1529,12 +1797,13 @@ ccid_transceive (ccid_driver_t handle,
         DEBUGOUT_CONT_1 (" %02X", msg[i]);
       DEBUGOUT_LF ();
 
-#ifdef DEBUG_T1      
-      fprintf (stderr, "T1: put %c-block seq=%d\n",
-               ((msg[11] & 0xc0) == 0x80)? 'R' :
-               (msg[11] & 0x80)? 'S' : 'I',
-        ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
-#endif  
+      if (debug_level > 1)
+          DEBUGOUT_3 ("T=1: put %c-block seq=%d%s\n",
+                      ((msg[11] & 0xc0) == 0x80)? 'R' :
+                                (msg[11] & 0x80)? 'S' : 'I',
+                      ((msg[11] & 0x80)? !!(msg[11]& 0x10)
+                                       : !!(msg[11] & 0x40)),
+                      (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
 
       rc = bulk_out (handle, msg, msglen);
       if (rc)
@@ -1542,7 +1811,7 @@ ccid_transceive (ccid_driver_t handle,
 
       msg = recv_buffer;
       rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
-                    RDR_to_PC_DataBlock, seqno);
+                    RDR_to_PC_DataBlock, seqno, 5000, 0);
       if (rc)
         return rc;
       
@@ -1551,17 +1820,17 @@ ccid_transceive (ccid_driver_t handle,
       
       if (tpdulen < 4) 
         {
-          usb_clear_halt (handle->idev, 0x82);
+          usb_clear_halt (handle->idev, handle->ep_bulk_in);
           return CCID_DRIVER_ERR_ABORTED; 
         }
-#ifdef DEBUG_T1
-      fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
-               ((msg[11] & 0xc0) == 0x80)? 'R' :
-               (msg[11] & 0x80)? 'S' : 'I',
-        ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
-               ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
-               );
-#endif
+
+      if (debug_level > 1)
+        DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+                    ((msg[11] & 0xc0) == 0x80)? 'R' :
+                              (msg[11] & 0x80)? 'S' : 'I',
+                    ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+                    ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+                    (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
 
       if (!(tpdu[1] & 0x80))
         { /* This is an I-block. */
@@ -1637,8 +1906,8 @@ ccid_transceive (ccid_driver_t handle,
               msg = send_buffer;
               tpdulen = last_tpdulen;
             }
-          else if (sending && !!(tpdu[1] & 0x40) == handle->t1_ns)
-            { /* Reponse does not match our sequence number. */
+          else if (sending && !!(tpdu[1] & 0x10) == handle->t1_ns)
+            { /* Response does not match our sequence number. */
               DEBUGOUT ("R-block with wrong seqno received on more bit\n");
               return CCID_DRIVER_ERR_CARD_IO_ERROR;
             }
@@ -1658,7 +1927,7 @@ ccid_transceive (ccid_driver_t handle,
       else 
         { /* This is a S-block. */
           retries = 0;
-          DEBUGOUT_2 ("T1 S-block %s received cmd=%d\n",
+          DEBUGOUT_2 ("T=1 S-block %s received cmd=%d\n",
                       (tpdu[1] & 0x20)? "response": "request",
                       (tpdu[1] & 0x1f));
           if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
@@ -1676,7 +1945,7 @@ ccid_transceive (ccid_driver_t handle,
               if (use_crc)
                 tpdu[tpdulen++] = (edc >> 8);
               tpdu[tpdulen++] = edc;
-              DEBUGOUT_1 ("T1 waittime extension of bwi=%d\n", bwi);
+              DEBUGOUT_1 ("T=1 waittime extension of bwi=%d\n", bwi);
             }
           else
             return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -1757,7 +2026,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   if (handle->id_vendor == VENDOR_SCM)
     {
       DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
-      rc = send_escape_cmd (handle, "\x80\x02\x00", 3);
+      rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3);
       if (rc)
         return rc;
     }
@@ -1819,7 +2088,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   
   msg = recv_buffer;
   rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
-                RDR_to_PC_DataBlock, seqno);
+                RDR_to_PC_DataBlock, seqno, 5000, 0);
   if (rc)
     return rc;
   
@@ -1828,17 +2097,16 @@ ccid_transceive_secure (ccid_driver_t handle,
   
   if (tpdulen < 4) 
     {
-      usb_clear_halt (handle->idev, 0x82);
+      usb_clear_halt (handle->idev, handle->ep_bulk_in);
       return CCID_DRIVER_ERR_ABORTED; 
     }
-#ifdef DEBUG_T1
-  fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
-           ((msg[11] & 0xc0) == 0x80)? 'R' :
-           (msg[11] & 0x80)? 'S' : 'I',
-           ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
-           ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
-           );
-#endif
+  if (debug_level > 1)
+    DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
+                ((msg[11] & 0xc0) == 0x80)? 'R' :
+                          (msg[11] & 0x80)? 'S' : 'I',
+                ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
+                ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0,
+                (!(msg[11] & 0x80) && (msg[11] & 0x20)? " [more]":""));
 
   if (!(tpdu[1] & 0x80))
     { /* This is an I-block. */
@@ -1885,7 +2153,7 @@ ccid_transceive_secure (ccid_driver_t handle,
           DEBUGOUT ("No retries supported for Secure operation\n");
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
-      else if (!!(tpdu[1] & 0x40) == handle->t1_ns)
+      else if (!!(tpdu[1] & 0x10) == handle->t1_ns)
         { /* Reponse does not match our sequence number. */
           DEBUGOUT ("R-block with wrong seqno received on more bit\n");
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -1898,7 +2166,7 @@ ccid_transceive_secure (ccid_driver_t handle,
     }
   else 
     { /* This is a S-block. */
-      DEBUGOUT_2 ("T1 S-block %s received cmd=%d for Secure operation\n",
+      DEBUGOUT_2 ("T=1 S-block %s received cmd=%d for Secure operation\n",
                   (tpdu[1] & 0x20)? "response": "request",
                   (tpdu[1] & 0x1f));
       return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -1977,6 +2245,7 @@ main (int argc, char **argv)
   int no_pinpad = 0;
   int verify_123456 = 0;
   int did_verify = 0;
+  int no_poll = 0;
 
   if (argc)
     {
@@ -2001,6 +2270,11 @@ main (int argc, char **argv)
           ccid_set_debug_level (1);
           argc--; argv++;
         }
+      else if ( !strcmp (*argv, "--no-poll"))
+        {
+          no_poll = 1;
+          argc--; argv++;
+        }
       else if ( !strcmp (*argv, "--no-pinpad"))
         {
           no_pinpad = 1;
@@ -2019,7 +2293,8 @@ main (int argc, char **argv)
   if (rc)
     return 1;
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
   fputs ("getting ATR ...\n", stderr);
   rc = ccid_get_atr (ccid, NULL, 0, NULL);
   if (rc)
@@ -2028,7 +2303,8 @@ main (int argc, char **argv)
       return 1;
     }
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
   fputs ("getting slot status ...\n", stderr);
   rc = ccid_slot_status (ccid, &slotstat);
   if (rc)
@@ -2037,7 +2313,8 @@ main (int argc, char **argv)
       return 1;
     }
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
 
   fputs ("selecting application OpenPGP ....\n", stderr);
   {
@@ -2050,7 +2327,8 @@ main (int argc, char **argv)
   }
   
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
 
   fputs ("getting OpenPGP DO 0x65 ....\n", stderr);
   {
index 23ffb10..f2a13d2 100644 (file)
@@ -17,7 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  *
- * $Id: iso7816.c,v 1.3.2.11 2004/10/20 08:54:45 wk Exp $
+ * $Id: iso7816.c,v 1.3.2.13 2005/06/16 08:11:59 wk Exp $
  */
 
 #include <config.h>
@@ -153,7 +153,7 @@ iso7816_select_file (int slot, int tag, int is_dir,
       p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
       p1 = 0x0c; /* No FC return. */
       sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
-                             p0, p1, 2, tagbuf );
+                             p0, p1, 2, (char*)tagbuf );
       return map_sw (sw);
     }
 
@@ -285,7 +285,7 @@ iso7816_put_data (int slot, int tag,
 
   sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
                          ((tag >> 8) & 0xff), (tag & 0xff),
-                         datalen, data);
+                         datalen, (const char*)data);
   return map_sw (sw);
 }
 
@@ -299,10 +299,11 @@ iso7816_manage_security_env (int slot, int p1, int p2,
 {
   int sw;
 
-  if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen)
+  if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 )
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, datalen, data);
+  sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, 
+                         data? datalen : -1, (const char*)data);
   return map_sw (sw);
 }
 
@@ -322,7 +323,7 @@ iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
   *result = NULL;
   *resultlen = 0;
 
-  sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, data,
+  sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, (const char*)data,
                   result, resultlen);
   if (sw != SW_SUCCESS)
     {
@@ -363,13 +364,15 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
 
       *buf = padind; /* Padding indicator. */
       memcpy (buf+1, data, datalen);
-      sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf,
+      sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
+                      datalen+1, (char*)buf,
                       result, resultlen);
       xfree (buf);
     }
   else
     {
-      sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen, data,
+      sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86,
+                      datalen, (const char *)data,
                       result, resultlen);
     }
   if (sw != SW_SUCCESS)
@@ -398,7 +401,7 @@ iso7816_internal_authenticate (int slot,
   *resultlen = 0;
 
   sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
-                  datalen, data,  result, resultlen);
+                  datalen, (const char*)data,  result, resultlen);
   if (sw != SW_SUCCESS)
     {
       /* Make sure that pending buffers are released. */
@@ -425,7 +428,7 @@ do_generate_keypair (int slot, int readonly,
   *resultlen = 0;
 
   sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
-                  datalen, data,  result, resultlen);
+                  datalen, (const char*)data,  result, resultlen);
   if (sw != SW_SUCCESS)
     {
       /* Make sure that pending buffers are released. */
@@ -605,7 +608,7 @@ iso7816_read_record (int slot, int recno, int reccount, int short_ef,
 
   buffer = NULL;
   bufferlen = 0;
-  /* Fixme: Either the ccid driver of the TCOS cards have problems
+  /* Fixme: Either the ccid driver or the TCOS cards have problems
      with an Le of 0. */
   sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
                      recno, 
index 5b9d0d6..b436d95 100644 (file)
@@ -1,5 +1,5 @@
 /* tlv.c - Tag-Length-Value Utilities
- *     Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include <string.h>
 #include <assert.h>
 
+#if GNUPG_MAJOR_VERSION == 1
+#define GPG_ERR_EOF               (-1)
+#define GPG_ERR_BAD_BER           (1)  /*G10ERR_GENERAL*/
+#define GPG_ERR_INV_SEXP          (45) /*G10ERR_INV_ARG*/
+typedef int gpg_error_t;
+#define gpg_error(n) (n)
+#else
 #include <gpg-error.h>
+#endif
 
 #include "tlv.h"
 
@@ -113,17 +121,32 @@ do_find_tlv (const unsigned char *buffer, size_t length,
 
 /* Locate a TLV encoded data object in BUFFER of LENGTH and
    return a pointer to value as well as its length in NBYTES.  Return
-   NULL if it was not found.  Note, that the function does not check
-   whether the value fits into the provided buffer. */
+   NULL if it was not found or if the object does not fit into the buffer. */
 const unsigned char *
 find_tlv (const unsigned char *buffer, size_t length,
           int tag, size_t *nbytes)
 {
-  return do_find_tlv (buffer, length, tag, nbytes, 0);
+  const unsigned char *p;
+
+  p = do_find_tlv (buffer, length, tag, nbytes, 0);
+  if (p && *nbytes > (length - (p-buffer)))
+    p = NULL; /* Object longer than buffer. */
+  return p;
 }
 
 
 
+/* Locate a TLV encoded data object in BUFFER of LENGTH and
+   return a pointer to value as well as its length in NBYTES.  Return
+   NULL if it was not found.  Note, that the function does not check
+   whether the value fits into the provided buffer. */
+const unsigned char *
+find_tlv_unchecked (const unsigned char *buffer, size_t length,
+                    int tag, size_t *nbytes)
+{
+  return do_find_tlv (buffer, length, tag, nbytes, 0);
+}
+
 
 /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
    and the length part from the TLV triplet.  Update BUFFER and SIZE
@@ -206,3 +229,76 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
   *size = length;
   return 0;
 }
+
+
+/* FIXME: The following function should not go into this file but for
+   now it is easier to keep it here. */
+
+/* Return the next token of an canconical encoded S-expression.  BUF
+   is the pointer to the S-expression and BUFLEN is a pointer to the
+   length of this S-expression (used to validate the syntax).  Both
+   are updated to reflect the new position.  The token itself is
+   returned as a pointer into the orginal buffer at TOK and TOKLEN.
+   If a parentheses is the next token, TOK will be set to NULL.
+   TOKLEN is checked to be within the bounds.  On error a error code
+   is returned and all pointers should are not guaranteed to point to
+   a meanigful value. DEPTH should be initialized to 0 and will
+   reflect on return the actual depth of the tree. To detect the end
+   of the S-expression it is advisable to check DEPTH after a
+   successful return:
+
+   depth = 0;
+   while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
+          && depth)
+     process_token (tok, toklen);
+   if (err)  
+     handle_error ();
+ */
+gpg_error_t
+parse_sexp (unsigned char const **buf, size_t *buflen,
+            int *depth, unsigned char const **tok, size_t *toklen)
+{
+  const unsigned char *s;
+  size_t n, vlen;
+
+  s = *buf;
+  n = *buflen;
+  *tok = NULL;
+  *toklen = 0;
+  if (!n)
+    return *depth ? gpg_error (GPG_ERR_INV_SEXP) : 0;
+  if (*s == '(')
+    {
+      s++; n--;
+      (*depth)++;
+      *buf = s;
+      *buflen = n;
+      return 0;
+    }
+  if (*s == ')')
+    {
+      if (!*depth)
+        return gpg_error (GPG_ERR_INV_SEXP);
+      *toklen = 1;
+      s++; n--;
+      (*depth)--;
+      *buf = s;
+      *buflen = n;
+      return 0;
+    }
+  for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
+    vlen = vlen*10 + (*s - '0');
+  if (!n || *s != ':')
+    return gpg_error (GPG_ERR_INV_SEXP);
+  s++; n--;
+  if (vlen > n)
+    return gpg_error (GPG_ERR_INV_SEXP);
+  *tok = s;
+  *toklen = vlen;
+  s += vlen;
+  n -= vlen;
+  *buf = s;
+  *buflen = n;
+  return 0;
+}
+
index 26a9905..f587dd9 100644 (file)
@@ -62,13 +62,20 @@ enum tlv_tag_type {
 };
 
 
+/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
+   pointer to value as well as its length in NBYTES.  Return NULL if
+   it was not found or if the object does not fit into the buffer. */
+const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
+                               int tag, size_t *nbytes);
+
 
 /* Locate a TLV encoded data object in BUFFER of LENGTH and return a
    pointer to value as well as its length in NBYTES.  Return NULL if
    it was not found.  Note, that the function does not check whether
    the value fits into the provided buffer.*/
-const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
-                               int tag, size_t *nbytes);
+const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
+                                         size_t length,
+                                         int tag, size_t *nbytes);
 
 
 /* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
@@ -81,4 +88,21 @@ gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
 
 
 
+/* Return the next token of an canconical encoded S-expression.  BUF
+   is the pointer to the S-expression and BUFLEN is a pointer to the
+   length of this S-expression (used to validate the syntax).  Both
+   are updated to reflect the new position.  The token itself is
+   returned as a pointer into the orginal buffer at TOK and TOKLEN.
+   If a parentheses is the next token, TOK will be set to NULL.
+   TOKLEN is checked to be within the bounds.  On error a error code
+   is returned and all pointers should are not guaranteed to point to
+   a meanigful value. DEPTH should be initialized to 0 and will
+   reflect on return the actual depth of the tree. To detect the end
+   of the S-expression it is advisable to check DEPTH after a
+   successful return. */
+gpg_error_t parse_sexp (unsigned char const **buf, size_t *buflen,
+                        int *depth, unsigned char const **tok, size_t *toklen);
+
+
+
 #endif /* SCD_TLV_H */
index 9bb8e6e..15f272a 100644 (file)
@@ -1,3 +1,7 @@
+2005-07-13  Moritz Schulte  <moritz@g10code.com>
+
+       * pam_poldi.c (wait_for_card): Adjust to new card_info() API.
+
 2004-11-27  Moritz Schulte  <moritz@g10code.com>
 
        * pam_poldi.c (wait_for_card): Adjust card_init caller.
index d2820ac..7ab2a8b 100644 (file)
@@ -1,5 +1,5 @@
 /* poldi.c - PAM authentication via OpenPGP smartcards.
-   Copyright (C) 2004 g10 Code GmbH
+   Copyright (C) 2004, 2005 g10 Code GmbH
  
    This file is part of Poldi.
   
@@ -373,7 +373,7 @@ wait_for_card (int slot, int fake, int require_card_switch,
   if (err)
     goto out;
 
-  err = card_info (slot, &serialno_new, NULL);
+  err = card_info (slot, &serialno_new, NULL, NULL);
   if (err)
     goto out;