* configure.ac: Changed tests for libusb to also suuport the
authorWerner Koch <wk@gnupg.org>
Thu, 5 Aug 2004 09:24:36 +0000 (09:24 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 5 Aug 2004 09:24:36 +0000 (09:24 +0000)
stable version 0.1.x.

* scdaemon.texi (Card applications): New section.

* scdaemon.c (main): New option --disable-application.
* app.c (is_app_allowed): New.
(select_application): Use it to check for disabled applications.

* ccid-driver.h (CCID_DRIVER_ERR_ABORTED): New.
* ccid-driver.c (ccid_open_reader): Support the stable 0.1 version
of libusb.
(ccid_get_atr): Handle short messages.

* apdu.c (my_rapdu_get_status): Implemented.

16 files changed:
ChangeLog
TODO
configure.ac
doc/ChangeLog
doc/scdaemon.texi
scd/ChangeLog
scd/apdu.c
scd/apdu.h
scd/app.c
scd/ccid-driver.c
scd/ccid-driver.h
scd/iso7816.c
scd/scdaemon.c
scd/scdaemon.h
sm/ChangeLog
sm/certreqgen.c

index d83d94c..7b14b79 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2004-08-05  Werner Koch  <wk@g10code.de>
+
+       * configure.ac: Changed tests for libusb to also suuport the
+       stable version 0.1.x.
+
 2004-07-22  Werner Koch  <wk@g10code.de>
 
        Released 1.9.10.
diff --git a/TODO b/TODO
index ce835d8..6e5c8cf 100644 (file)
--- a/TODO
+++ b/TODO
@@ -79,3 +79,25 @@ might want to have an agent context for each service request
 * doc/
 ** Explain how to setup a root CA key as trusted
 ** Explain how trustlist.txt might be managed.
+
+
+* Requirements by the BSI
+** Support authorityKeyIdentifier.keyIdentifier
+   This needs support in libksba/src/cert.c as well as in sm/*.c.
+   Need test certs as well.  Same goes for CRL authorityKeyIdentifier.
+
+** For pkcs#10 request header.
+   We use "NEW CERTIFICATE REQUEST" the specs say "CERTIFICATE
+   REQUEST" should be used.  However it seems that their CA software
+   is also able to use our header.  Binary pkcs#10 request are not
+   allowed.
+
+** Dirmngr:  name subordination (nameRelativeToCRLIssuer) 
+   is not yet supported by Dirmngr.
+
+** Dirmngr: CRL DP URI
+  The CRL DP shall use an URI for LDAP without a host name.  The host
+  name shall be looked by using the DN in the URI.  We don't implement
+  this yet.  Solution is to have a mapping DN->host in our ldapservers
+  configuration file.
+
index ca6eaf1..f34faf4 100644 (file)
@@ -451,15 +451,13 @@ AM_PATH_KSBA("$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
 #
 # libusb allows us to use the integrated CCID smartcard reader driver.
 #
-# Note, that we need the CVS version.  FIXME: libusb should have a
-# regular check as the other libraries do.
-#
-AC_CHECK_LIB(usb, usb_find_device,
+AC_CHECK_LIB(usb, usb_bulk_write,
               [ LIBUSB_LIBS="$LIBUSB_LIBS -lusb"
                 AC_DEFINE(HAVE_LIBUSB,1,
                          [defined if libusb is available])
              ])
 AC_SUBST(LIBUSB_LIBS)
+AC_CHECK_FUNCS(usb_create_match)
 
 #
 # Check wether it is necessary to link against libdl.
index 1760695..79a8c95 100644 (file)
@@ -1,3 +1,7 @@
+2004-08-05  Werner Koch  <wk@g10code.de>
+
+       * scdaemon.texi (Card applications): New section.
+
 2004-06-22  Werner Koch  <wk@g10code.com>
 
        * glossary.texi: New.
index 51ec4b3..3e11a89 100644 (file)
@@ -10,7 +10,7 @@
 
 @c man begin DESCRIPTION
 
-The @sc{scdaeon} is a daemon to manage smartcards.  It is usually
+The @sc{scdaemon} is a daemon to manage smartcards.  It is usually
 invoked by gpg-agent and in general not used directly.
 
 @c man end
@@ -20,6 +20,7 @@ invoked by gpg-agent and in general not used directly.
 @menu
 * Scdaemon Commands::      List of all commands.
 * Scdaemon Options::       List of all options.
+* Card applications::      Description of card applications.
 * Scdaemon Examples::      Some usage examples.
 * Scdaemon Protocol::      The protocol the daemon uses.
 @end menu
@@ -176,18 +177,70 @@ is @code{libtowitoko.so}.
 @itemx --deny-admin
 @opindex allow-admin
 @opindex deny-admin
-This enables the use of Admin class commands for card application
+This enables the use of Admin class commands for card applications
 where this is supported.  Currently we support it for the OpenPGP
 card.  Deny is the default.  This commands is useful to inhibit
 accidental access to admin class command which could ultimately lock
 the card through worng PIN numbers.
 
+@item --disable-application @var{name}
+@opindex disable-application
+This option disables the use of the card application named
+@var{name}.  This is mainly useful for debugging or if a application
+with lower priority should be used by default.
+
 @end table
 
 All the long options may also be given in the configuration file after
 stripping off the two leading dashes.
 
 
+@c man begin CARD APPLICATIONS
+
+@node Card applications
+@section Description of card applications
+
+@sc{scdaemon} supports the card applications as described below.
+
+@menu
+* OpenPGP Card::          The OpenPGP card application
+* NKS Card::              The Telesec NetKey card application
+* DINSIG Card::           The DINSIG card application
+* PKCS#15 Card::          The PKCS#15 card application
+@end menu
+
+@node OpenPGP Card
+@subsection The OpenPGP card application ``openpgp''
+
+This application is currently only used by @sc{gpg} but may in
+future also be useful with @sc{gpgsm}. 
+
+The specification for such a card is available at
+@uref{http://g10code.com/docs/openpgp-card-1.0.pdf}.
+
+@node NKS Card
+@subsection The Telesec NetKey card ``nks''
+
+This is the main application of the Telesec cards as available in
+Germany.  It is a superset of the German DINSIG card.  The card is
+used by @sc{gpgsm}.
+
+@node DINSIG Card
+@subsection The DINSIG card application ``dinsig''
+
+This is an application as described in the German draft standard
+@emph{DIN V 66291-1}.  It is intended to be used by cards supporteing
+the German signature law and its bylaws (SigG and SigV).
+
+@node PKCS#15 Card
+@subsection The PKCS#15 card application ``p15''
+
+This is common fraqmework for smart card applications; support is only
+available if compiled with support for the OpenSC library.  It is used
+by @sc{gpgsm}.
+
+
+
 @c 
 @c  Examples
 @c
index b0f07dc..80b244e 100644 (file)
@@ -1,3 +1,16 @@
+2004-08-05  Werner Koch  <wk@g10code.de>
+
+       * scdaemon.c (main): New option --disable-application.
+       * app.c (is_app_allowed): New.
+       (select_application): Use it to check for disabled applications.
+
+       * ccid-driver.h (CCID_DRIVER_ERR_ABORTED): New.
+       * ccid-driver.c (ccid_open_reader): Support the stable 0.1 version
+       of libusb.
+       (ccid_get_atr): Handle short messages.
+
+       * apdu.c (my_rapdu_get_status): Implemented.
+
 2004-07-27  Moritz Schulte  <moritz@g10code.com>
 
        * apdu.c: Include <signal.h>.
index 7898452..5f800c9 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #include <config.h>
-
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -296,6 +295,7 @@ host_sw_string (long err)
     case SW_HOST_CARD_IO_ERROR: return "card I/O error";
     case SW_HOST_GENERAL_ERROR: return "general error";
     case SW_HOST_NO_READER: return "no reader";
+    case SW_HOST_ABORTED: return "aborted";
     default: return "unknown host status error";
     }
 }
@@ -1633,7 +1633,42 @@ reset_rapdu_reader (int slot)
 static int
 my_rapdu_get_status (int slot, unsigned int *status)
 {
-  return SW_HOST_NOT_SUPPORTED;
+  int err;
+  reader_table_t slotp;
+  rapdu_msg_t msg = NULL;
+  int oldslot;
+
+  slotp = reader_table + slot;
+
+  oldslot = rapdu_set_reader (slotp->rapdu.handle, slot);
+  err = rapdu_send_cmd (slotp->rapdu.handle, RAPDU_CMD_GET_STATUS);
+  rapdu_set_reader (slotp->rapdu.handle, oldslot);
+  if (err)
+    {
+      log_error ("sending rapdu command GET_STATUS failed: %s\n",
+                err < 0 ? strerror (errno): rapdu_strerror (err));
+      return rapdu_status_to_sw (err);
+    }
+  err = rapdu_read_msg (slotp->rapdu.handle, &msg);
+  if (err)
+    {
+      log_error ("receiving rapdu message failed: %s\n",
+                err < 0 ? strerror (errno): rapdu_strerror (err));
+      rapdu_msg_release (msg);
+      return rapdu_status_to_sw (err);
+    }
+  if (msg->cmd != RAPDU_STATUS_SUCCESS || !msg->datalen)
+    {
+      int sw = rapdu_status_to_sw (msg->cmd);
+      log_error ("rapdu command GET_STATUS failed: %s\n",
+                 rapdu_strerror (msg->cmd));
+      rapdu_msg_release (msg);
+      return sw;
+    }
+  *status = msg->data[0];
+
+  rapdu_msg_release (msg);
+  return 0;
 }
 
 
index a2b7812..a0654a2 100644 (file)
@@ -58,7 +58,8 @@ enum {
   SW_HOST_CARD_INACTIVE = 0x10009,
   SW_HOST_CARD_IO_ERROR = 0x1000a,
   SW_HOST_GENERAL_ERROR = 0x1000b,
-  SW_HOST_NO_READER     = 0x1000c
+  SW_HOST_NO_READER     = 0x1000c,
+  SW_HOST_ABORTED       = 0x1000d
 };
 
 
index a9a9243..b3a13f1 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
 #include "tlv.h"
 
 
+/* Check wether the application NAME is allowed.  This does not mean
+   we have support for it though.  */
+static int
+is_app_allowed (const char *name)
+{
+  strlist_t l;
+
+  for (l=opt.disabled_applications; l; l = l->next)
+    if (!strcmp (l->d, name))
+      return 0; /* no */
+  return 1; /* yes */
+}
+
 /* If called with NAME as NULL, select the best fitting application
    and return a context; otherwise select the application with NAME
    and return a context.  SLOT identifies the reader device. Returns
@@ -84,11 +97,11 @@ select_application (ctrl_t ctrl, int slot, const char *name)
 
   rc = gpg_error (GPG_ERR_NOT_FOUND);
 
-  if (!name || !strcmp (name, "openpgp"))
+  if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp")))
     rc = app_select_openpgp (app);
-  if (rc && (!name || !strcmp (name, "nks")))
+  if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
     rc = app_select_nks (app);
-  if (rc && (!name || !strcmp (name, "dinsig")))
+  if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
     rc = app_select_dinsig (app);
   if (rc && name)
     rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
index 4751b8c..0fc1685 100644 (file)
@@ -412,7 +412,13 @@ read_device_info (ccid_driver_t handle, struct usb_device *dev)
 {
   int cfg_no;
 
-  for (cfg_no=0; cfg_no < dev->descriptor->bNumConfigurations; cfg_no++)
+  for (cfg_no=0; cfg_no <
+#ifdef HAVE_USB_CREATE_MATCH
+         dev->descriptor->bNumConfigurations
+#else
+         dev->descriptor.bNumConfigurations
+#endif
+         ; cfg_no++)
     {
       struct usb_config_descriptor *config = dev->config + cfg_no;
       int ifc_no;
@@ -451,8 +457,9 @@ read_device_info (ccid_driver_t handle, struct usb_device *dev)
 int 
 ccid_open_reader (ccid_driver_t *handle, int readerno)
 {
+#ifdef HAVE_USB_CREATE_MATCH
+  /* This is the development version of libusb. */  
   static int initialized;
-
   int rc;
   usb_match_handle *match = NULL;
   struct usb_device *dev = NULL;
@@ -471,7 +478,7 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
       DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
       return CCID_DRIVER_ERR_NO_READER;
     }
-
+  
   while (usb_find_device(match, dev, &dev) >= 0) 
     {
       DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
@@ -530,7 +537,6 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
       readerno--;
     }
 
-
  leave:
   if (idev)
     usb_close (idev);
@@ -542,6 +548,96 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
     rc = -1; /* In case we didn't enter the while loop at all. */
 
   return rc;
+#else /* Stable 0.1 version of libusb.  */
+  static int initialized;
+  int rc = 0;
+  struct usb_bus *busses, *bus;
+  struct usb_device *dev = NULL;
+  usb_dev_handle *idev = NULL;
+
+  *handle = NULL;
+  if (!initialized)
+    {
+      usb_init ();
+      initialized = 1;
+    }
+  
+  usb_find_busses();
+  usb_find_devices();
+  busses = usb_get_busses();
+
+  for (bus = busses; bus; bus = bus->next) 
+    {
+      for (dev = bus->devices; dev; dev = dev->next)
+        {
+          DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
+                      dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+          if (!readerno)
+            {
+              *handle = calloc (1, sizeof **handle);
+              if (!*handle)
+                {
+                  DEBUGOUT ("out of memory\n");
+                  rc = CCID_DRIVER_ERR_OUT_OF_CORE;
+                  free (*handle);
+                  *handle = NULL;
+                  goto leave;
+                }
+
+              rc = read_device_info (*handle, dev);
+              if (rc)
+                {
+                  DEBUGOUT ("device not supported\n");
+                  free (*handle);
+                  *handle = NULL;
+                  continue;
+                }
+
+              idev = usb_open (dev);
+              if (!idev)
+                {
+                  DEBUGOUT_1 ("usb_open failed: %s\n", strerror (errno));
+                  free (*handle);
+                  *handle = NULL;
+                  rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+                  goto leave;
+                }
+
+              /* fixme: Do we need to claim and set the interface as
+                 determined by read_device_info ()? */
+              rc = usb_claim_interface (idev, 0);
+              if (rc)
+                {
+                  DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
+                  free (*handle);
+                  *handle = NULL;
+                  rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+                  goto leave;
+                }
+
+              (*handle)->idev = idev;
+              idev = NULL;
+              /* FIXME: Do we need to get the endpoint addresses from the
+                 structure and store them with the handle? */
+              
+              goto leave; /* ready. */
+            }
+          readerno--;
+        }
+    }
+
+ leave:
+  if (idev)
+    usb_close (idev);
+  /* fixme: Do we need to release dev or is it supposed to be a
+     shallow copy of the list created internally by usb_init ? */
+
+  if (!rc && !*handle)
+    rc = -1; /* In case we didn't enter the while loop at all. */
+
+  return rc;
+#endif /* Stable version 0.1 of libusb.  */
 }
 
 
@@ -894,10 +990,7 @@ ccid_get_atr (ccid_driver_t handle,
       tpdulen = msglen - 10;
       
       if (tpdulen < 4) 
-        {
-          DEBUGOUT ("cannot yet handle short blocks!\n");
-          return -1; 
-        }
+        return CCID_DRIVER_ERR_ABORTED; 
 
 #ifdef DEBUG_T1
       fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
@@ -1092,10 +1185,9 @@ ccid_transceive (ccid_driver_t handle,
       
       if (tpdulen < 4) 
         {
-          DEBUGOUT ("cannot yet handle short blocks!\n");
-          return CCID_DRIVER_ERR_NOT_SUPPORTED; 
+          usb_clear_halt (handle->idev, 0x82);
+          return CCID_DRIVER_ERR_ABORTED; 
         }
-
 #ifdef DEBUG_T1
       fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
                ((msg[11] & 0xc0) == 0x80)? 'R' :
index 0b108f1..0cb52e1 100644 (file)
@@ -70,7 +70,7 @@
 #define CCID_DRIVER_ERR_CARD_IO_ERROR  0x1000a
 #define CCID_DRIVER_ERR_GENERAL_ERROR  0x1000b
 #define CCID_DRIVER_ERR_NO_READER      0x1000c
-
+#define CCID_DRIVER_ERR_ABORTED        0x1000d
 
 struct ccid_driver_s;
 typedef struct ccid_driver_s *ccid_driver_t;
index d5db607..cbb314e 100644 (file)
@@ -90,6 +90,7 @@ map_sw (int sw)
     case SW_HOST_CARD_IO_ERROR:  ec = GPG_ERR_EIO; break;
     case SW_HOST_GENERAL_ERROR:  ec = GPG_ERR_GENERAL; break;
     case SW_HOST_NO_READER:      ec = GPG_ERR_ENODEV; break;
+    case SW_HOST_ABORTED:        ec = GPG_ERR_CANCELED; break;
 
     default:
       if ((sw & 0x010000))
index f647aec..b54a638 100644 (file)
@@ -80,6 +80,7 @@ enum cmd_and_opt_values
   oDisableOpenSC,
   oAllowAdmin,
   oDenyAdmin,
+  oDisableApplication,
 
 aTest };
 
@@ -124,6 +125,7 @@ static ARGPARSE_OPTS opts[] = {
                                          /* end --disable-opensc */},
   { oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
   { oDenyAdmin,  "deny-admin",  0, "@" },  
+  { oDisableApplication, "disable-application", 2, "@"},
 
   {0}
 };
@@ -493,6 +495,10 @@ main (int argc, char **argv )
         case oAllowAdmin: opt.allow_admin = 1; break;
         case oDenyAdmin: opt.allow_admin = 0; break;
 
+        case oDisableApplication:
+          add_to_strlist (&opt.disabled_applications, pargs.r.ret_str); 
+          break;
+
         default : pargs.err = configfp? 1:2; break;
        }
     }
index 1dd32ae..c8d78c8 100644 (file)
@@ -52,6 +52,8 @@ struct {
   int disable_ccid;    /* Disable the use of the internal CCID driver. */
   int allow_admin;     /* Allow the use of admin commands for certain
                           cards. */
+  strlist_t disabled_applications;  /* card applications we do not
+                                       want to use. */
 } opt;
 
 
index b9780cc..b21a5fa 100644 (file)
@@ -1,3 +1,8 @@
+2004-07-23  Werner Koch  <wk@g10code.de>
+
+       * certreqgen.c (proc_parameters): Do not allow key length below
+       1024.
+
 2004-07-22  Werner Koch  <wk@g10code.de>
 
        * keylist.c (list_cert_raw): Print the keygrip.
index 969ed14..ab1f539 100644 (file)
@@ -444,7 +444,7 @@ proc_parameters (ctrl_t ctrl,
   if (i < 1 || i != GCRY_PK_RSA )
     {
       r = get_parameter (para, pKEYTYPE);
-      log_error ("line %d: invalid algorithm\n", r->lnr);
+      log_error (_("line %d: invalid algorithm\n"), r->lnr);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
   
@@ -453,11 +453,12 @@ proc_parameters (ctrl_t ctrl,
     nbits = 1024;
   else
     nbits = get_parameter_uint (para, pKEYLENGTH);
-  if (nbits < 512 || nbits > 4096)
+  if (nbits < 1024 || nbits > 4096)
     {
+      /* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */
       r = get_parameter (para, pKEYTYPE);
-      log_error ("line %d: invalid key length %u (valid are 512 to 4096)\n",
-                 r->lnr, nbits);
+      log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"),
+                 r->lnr, nbits, 1024, 4096);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
     
@@ -470,7 +471,7 @@ proc_parameters (ctrl_t ctrl,
   if (!(s=get_parameter_value (para, pNAMEDN)))
     {
       r = get_parameter (para, pKEYTYPE);
-      log_error ("line %d: no subject name given\n", r->lnr);
+      log_error (_("line %d: no subject name given\n"), r->lnr);
       return gpg_error (GPG_ERR_INV_PARAMETER);
     }
   /* fixme check s */
@@ -485,7 +486,7 @@ proc_parameters (ctrl_t ctrl,
           || strstr(s, ".."))
         {
           r = get_parameter (para, pKEYTYPE);
-          log_error ("line %d: not a valid email address\n", r->lnr);
+          log_error (_("line %d: not a valid email address\n"), r->lnr);
           return gpg_error (GPG_ERR_INV_PARAMETER);
         }
     }
@@ -497,7 +498,7 @@ proc_parameters (ctrl_t ctrl,
   if (rc)
     {
       r = get_parameter (para, pKEYTYPE);
-      log_error ("line %d: key generation failed: %s\n",
+      log_error (_("line %d: key generation failed: %s\n"),
                  r->lnr, gpg_strerror (rc));
       return rc;
     }