[svn] GnuPG - r3947 - in branches/GNUPG-1-9-BRANCH: . agent am kbx po scd tools

svn author wk cvs at cvs.gnupg.org
Mon Nov 28 12:52:28 CET 2005


Author: wk
Date: 2005-11-28 12:52:25 +0100 (Mon, 28 Nov 2005)
New Revision: 3947

Modified:
   branches/GNUPG-1-9-BRANCH/ChangeLog
   branches/GNUPG-1-9-BRANCH/NEWS
   branches/GNUPG-1-9-BRANCH/TODO
   branches/GNUPG-1-9-BRANCH/agent/ChangeLog
   branches/GNUPG-1-9-BRANCH/agent/agent.h
   branches/GNUPG-1-9-BRANCH/agent/call-scd.c
   branches/GNUPG-1-9-BRANCH/agent/command.c
   branches/GNUPG-1-9-BRANCH/agent/divert-scd.c
   branches/GNUPG-1-9-BRANCH/agent/minip12.c
   branches/GNUPG-1-9-BRANCH/agent/query.c
   branches/GNUPG-1-9-BRANCH/agent/t-protect.c
   branches/GNUPG-1-9-BRANCH/am/cmacros.am
   branches/GNUPG-1-9-BRANCH/configure.ac
   branches/GNUPG-1-9-BRANCH/kbx/keybox-blob.c
   branches/GNUPG-1-9-BRANCH/po/POTFILES.in
   branches/GNUPG-1-9-BRANCH/po/de.po
   branches/GNUPG-1-9-BRANCH/scd/ChangeLog
   branches/GNUPG-1-9-BRANCH/scd/apdu.c
   branches/GNUPG-1-9-BRANCH/scd/apdu.h
   branches/GNUPG-1-9-BRANCH/scd/app-dinsig.c
   branches/GNUPG-1-9-BRANCH/scd/app-nks.c
   branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c
   branches/GNUPG-1-9-BRANCH/scd/app-p15.c
   branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c
   branches/GNUPG-1-9-BRANCH/scd/ccid-driver.h
   branches/GNUPG-1-9-BRANCH/scd/iso7816.c
   branches/GNUPG-1-9-BRANCH/scd/iso7816.h
   branches/GNUPG-1-9-BRANCH/scd/scdaemon.c
   branches/GNUPG-1-9-BRANCH/scd/scdaemon.h
   branches/GNUPG-1-9-BRANCH/tools/ChangeLog
   branches/GNUPG-1-9-BRANCH/tools/gpgconf-comp.c
   branches/GNUPG-1-9-BRANCH/tools/rfc822parse.c
Log:
Preparing an interim release


Modified: branches/GNUPG-1-9-BRANCH/ChangeLog
===================================================================
--- branches/GNUPG-1-9-BRANCH/ChangeLog	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/ChangeLog	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1,3 +1,19 @@
+2005-11-28  Werner Koch  <wk at g10code.com>
+
+	* configure.ac: Append the revision to the version string.
+
+2005-11-13  Werner Koch  <wk at g10code.com>
+
+	* am/cmacros.am (-DGNUPG_SYSCONFDIR): Define it.
+
+2005-11-11  Werner Koch  <wk at g10code.com>
+
+	* configure.ac (NEED_KSBA_VERSION: Require 0.9.13.
+
+2005-09-12  Werner Koch  <wk at g10code.com>
+
+	Released 1.9.19.
+
 2005-08-01  Werner Koch  <wk at g10code.com>
 
 	Released 1.9.18.

Modified: branches/GNUPG-1-9-BRANCH/NEWS
===================================================================
--- branches/GNUPG-1-9-BRANCH/NEWS	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/NEWS	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1,3 +1,10 @@
+Noteworthy changes in version 1.9.20
+-------------------------------------------------
+
+ * [scdaemon] Support for keypads of some readers.  Tested only with
+   SPR532. New option --disable-keypad.
+
+
 Noteworthy changes in version 1.9.19 (2005-09-12)
 -------------------------------------------------
 

Modified: branches/GNUPG-1-9-BRANCH/TODO
===================================================================
--- branches/GNUPG-1-9-BRANCH/TODO	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/TODO	2005-11-28 11:52:25 UTC (rev 3947)
@@ -26,7 +26,6 @@
 * sm/gpgsm.c
 ** Support --output for all commands
 ** mark all unimplemented commands and options.
-** Print a hint when MD2 is the cause for a problem.
 ** Implement --default-key
 ** support the anyPolicy semantic
 ** Check that we are really following the verification procedures in rfc3280.

Modified: branches/GNUPG-1-9-BRANCH/agent/ChangeLog
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/ChangeLog	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/ChangeLog	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1,3 +1,20 @@
+2005-11-24  Werner Koch  <wk at g10code.com>
+
+	* minip12.c (p12_parse): Fixed for case that the key object comes
+	prior to the certificate.
+
+2005-10-19  Werner Koch  <wk at g10code.com>
+
+	* divert-scd.c (getpin_cb): Hack to use it for a keypad message.
+
+	* call-scd.c (inq_needpin): Reworked to support the new KEYPADINFO.
+
+	* query.c (start_pinentry): Keep track of the owner.
+	(popup_message_thread, agent_popup_message_start) 
+	(agent_popup_message_stop, agent_reset_query): New.
+	* command.c (start_command_handler): Make sure a popup window gets
+	closed.
+
 2005-10-08  Marcus Brinkmann  <marcus at g10code.de>
 
 	* Makefile.am (gpg_protect_tool_LDADD): Add ../gl/libgnu.a.

Modified: branches/GNUPG-1-9-BRANCH/agent/agent.h
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/agent.h	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/agent.h	2005-11-28 11:52:25 UTC (rev 3947)
@@ -133,7 +133,7 @@
   int have_keygrip;
 
   int use_auth_call; /* Hack to send the PKAUTH command instead of the
-                        PKSIGN command tro scdaemon.  */
+                        PKSIGN command to the scdaemon.  */
 };
 typedef struct server_control_s *CTRL;
 typedef struct server_control_s *ctrl_t;
@@ -200,6 +200,7 @@
 /*-- query.c --*/
 void initialize_module_query (void);
 void agent_query_dump_state (void);
+void agent_reset_query (ctrl_t ctrl);
 int agent_askpin (ctrl_t ctrl,
                   const char *desc_text, const char *prompt_text,
                   const char *inital_errtext,
@@ -209,7 +210,11 @@
                           const char *errtext);
 int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok,
 			    const char *cancel);
+int agent_popup_message_start (ctrl_t ctrl, const char *desc,
+                               const char *ok_btn, const char *cancel_btn);
+void agent_popup_message_stop (ctrl_t ctrl);
 
+
 /*-- cache.c --*/
 void agent_flush_cache (void);
 int agent_put_cache (const char *key, cache_mode_t cache_mode,

Modified: branches/GNUPG-1-9-BRANCH/agent/call-scd.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/call-scd.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/call-scd.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -633,27 +633,44 @@
   size_t pinlen;
   int rc;
 
-  if (!(!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])))
+  if (!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7]))
     {
+      line += 7;
+      while (*line == ' ')
+        line++;
+      
+      pinlen = 90;
+      pin = gcry_malloc_secure (pinlen);
+      if (!pin)
+        return ASSUAN_Out_Of_Core;
+
+      rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
+      if (rc)
+        rc = ASSUAN_Canceled;
+      if (!rc)
+        rc = assuan_send_data (parm->ctx, pin, pinlen);
+      xfree (pin);
+    }
+  else if (!strncmp (line, "KEYPADINFO", 10) && (line[10] == ' ' || !line[10]))
+    {
+      size_t code;
+      char *endp;
+
+      code = strtoul (line+10, &endp, 10);
+      line = endp;
+      while (*line == ' ')
+        line++;
+      
+      rc = parm->getpin_cb (parm->getpin_cb_arg, line, NULL, code);
+      if (rc)
+        rc = ASSUAN_Canceled;
+    }
+  else
+    {
       log_error ("unsupported inquiry `%s'\n", line);
-      return ASSUAN_Inquire_Unknown;
+      rc = ASSUAN_Inquire_Unknown;
     }
-  line += 7;
-  while (*line == ' ')
-    line++;
 
-  pinlen = 90;
-  pin = gcry_malloc_secure (pinlen);
-  if (!pin)
-    return ASSUAN_Out_Of_Core;
-
-  rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
-  if (rc)
-    rc = ASSUAN_Canceled;
-  if (!rc)
-    rc = assuan_send_data (parm->ctx, pin, pinlen);
-  xfree (pin);
-
   return rc;
 }
 

Modified: branches/GNUPG-1-9-BRANCH/agent/command.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/command.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/command.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -316,11 +316,11 @@
    this command is not used a default text will be used.  Note, that
    this description implictly selects the label used for the entry
    box; if the string contains the string PIN (which in general will
-   not be translated), "PIN" is used, other wiese the translation of
+   not be translated), "PIN" is used, otherwise the translation of
    'passphrase" is used.  The description string should not contain
    blanks unless they are percent or '+' escaped.
 
-   The descrition is only valid for the next PKSIGN or PKDECRYPT
+   The description is only valid for the next PKSIGN or PKDECRYPT
    operation.
 */
 static int
@@ -399,7 +399,7 @@
 /* PKSIGN <options>
 
    Perform the actual sign operation. Neither input nor output are
-   sensitive to eavesdropping */
+   sensitive to eavesdropping. */
 static int
 cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
 {
@@ -1085,6 +1085,9 @@
   /* Reset the SCD if needed. */
   agent_reset_scd (&ctrl);
 
+  /* Reset the pinentry (in case of popup messages). */
+  agent_reset_query (&ctrl);
+
   assuan_deinit_server (ctx);
   if (ctrl.display)
     free (ctrl.display);

Modified: branches/GNUPG-1-9-BRANCH/agent/divert-scd.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/divert-scd.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/divert-scd.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -204,7 +204,7 @@
   const char *again_text = NULL;
   const char *prompt = "PIN";
 
-  if (maxbuf < 2)
+  if (buf && maxbuf < 2)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* Parse the flags. */
@@ -223,6 +223,23 @@
   else if (info && *info == '|')
     log_debug ("pin_cb called without proper PIN info hack\n");
 
+  /* If BUF has been passed as NULL, we are in keypad mode: The
+     callback opens the popup and immediatley returns. */
+  if (!buf)
+    {
+      if (maxbuf == 0) /* Close the pinentry. */
+        {
+          agent_popup_message_stop (ctrl);
+          rc = 0;
+        }
+      else if (maxbuf == 1)  /* Open the pinentry. */
+        {
+          rc = agent_popup_message_start (ctrl, info, NULL, NULL);
+        }
+      else
+        rc = gpg_error (GPG_ERR_INV_VALUE);
+      return rc;
+    }
 
   /* FIXME: keep PI and TRIES in OPAQUE.  Frankly this is a whole
      mess because we should call the card's verify function from the

Modified: branches/GNUPG-1-9-BRANCH/agent/minip12.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/minip12.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/minip12.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -511,7 +511,7 @@
       goto bailout;
     }
 
-  /* Loop over all certificates inside the bab. */
+  /* Loop over all certificates inside the bag. */
   while (n)
     {
       int isbag = 0;
@@ -860,6 +860,7 @@
   size_t n = length;
   const char *where;
   int bagseqlength, len;
+  gcry_mpi_t *result = NULL;
 
   where = "pfx";
   if (parse_tag (&p, &n, &ti))
@@ -936,10 +937,17 @@
       else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
           && !memcmp (p, oid_data, DIM(oid_data)))
         {
-          p += DIM(oid_data);
-          n -= DIM(oid_data);
-          len -= DIM(oid_data);
-          return parse_bag_data (p, n, (p-buffer), pw);
+          if (result)
+            log_info ("already got an data object, skipping next one\n");
+          else
+            {
+              p += DIM(oid_data);
+              n -= DIM(oid_data);
+              len -= DIM(oid_data);
+              result = parse_bag_data (p, n, (p-buffer), pw);
+              if (!result)
+                goto bailout;
+            }
         }
       else
         log_info ( "unknown bag type - skipped\n");
@@ -950,9 +958,10 @@
       n -= len;
     }
   
-  return NULL;
+  return result;
  bailout:
   log_error ("error at \"%s\", offset %u\n", where, (p - buffer));
+  /* fixme: need to release RESULT. */
   return NULL;
 }
 

Modified: branches/GNUPG-1-9-BRANCH/agent/query.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/query.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/query.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -27,9 +27,10 @@
 #include <assert.h>
 #include <unistd.h>
 #include <sys/stat.h>
-#ifdef USE_GNU_PTH
-# include <pth.h>
+#ifndef HAVE_W32_SYSTEM
+#include <sys/wait.h>
 #endif
+#include <pth.h>
 
 #include "agent.h"
 #include "i18n.h"
@@ -48,14 +49,30 @@
    time. */
 #define LOCK_TIMEOUT  (1*60)
 
+/* The assuan context of the current pinentry. */
+static assuan_context_t entry_ctx;
 
-static assuan_context_t entry_ctx = NULL;
-#ifdef USE_GNU_PTH
+/* The control variable of the connection owning the current pinentry.
+   This is only valid if ENTRY_CTX is not NULL.  Note, that we care
+   only about the value of the pointer and that it should never be
+   dereferenced.  */
+static ctrl_t entry_owner;
+
+/* A mutex used to serialize access to the pinentry. */
 static pth_mutex_t entry_lock;
-#endif
 
-/* data to be passed to our callbacks */
-struct entry_parm_s {
+/* The thread ID of the popup working thread. */
+static pth_t  popup_tid;
+
+/* A flag used in communication between the popup working thread and
+   its stop function. */
+static int popup_finished;
+
+
+
+/* Data to be passed to our callbacks, */
+struct entry_parm_s
+{
   int lines;
   size_t size;
   unsigned char *buffer;
@@ -67,17 +84,17 @@
 /* This function must be called once to initialize this module.  This
    has to be done before a second thread is spawned.  We can't do the
    static initialization because Pth emulation code might not be able
-   to do a static init; in particualr, it is not possible for W32. */
+   to do a static init; in particular, it is not possible for W32. */
 void
 initialize_module_query (void)
 {
-#ifdef USE_GNU_PTH
   static int initialized;
 
   if (!initialized)
-    if (pth_mutex_init (&entry_lock))
-      initialized = 1;
-#endif /*USE_GNU_PTH*/
+    {
+      if (pth_mutex_init (&entry_lock))
+        initialized = 1;
+    }
 }
 
 
@@ -102,11 +119,22 @@
   log_info ("agent_query_dump_state: entry_lock=");
   dump_mutex_state (&entry_lock);
   log_printf ("\n");
-  log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld\n",
-            entry_ctx, (long)assuan_get_pid (entry_ctx));
+  log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
+            entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
 }
 
+/* Called to make sure that a popup window owned by the current
+   connection gets closed. */
+void
+agent_reset_query (ctrl_t ctrl)
+{
+  if (entry_ctx && popup_tid && entry_owner == ctrl)
+    {
+      agent_popup_message_stop (ctrl);
+    }
+}
 
+
 /* Unlock the pinentry so that another thread can start one and
    disconnect that pinentry - we do this after the unlock so that a
    stalled pinentry does not block other threads.  Fixme: We should
@@ -117,14 +145,12 @@
   assuan_context_t ctx = entry_ctx;
 
   entry_ctx = NULL;
-#ifdef USE_GNU_PTH
   if (!pth_mutex_release (&entry_lock))
     {
       log_error ("failed to release the entry lock\n");
       if (!rc)
         rc = gpg_error (GPG_ERR_INTERNAL);
     }
-#endif
   assuan_disconnect (ctx);
   return rc;
 }
@@ -145,7 +171,7 @@
    pinentry - we will serialize _all_ pinentry calls.
  */
 static int
-start_pinentry (CTRL ctrl)
+start_pinentry (ctrl_t ctrl)
 {
   int rc;
   const char *pgmname;
@@ -153,13 +179,10 @@
   const char *argv[5];
   int no_close_list[3];
   int i;
+  pth_event_t evt;
 
-#ifdef USE_GNU_PTH
- {
-   pth_event_t evt;
-
-   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
-   if (!pth_mutex_acquire (&entry_lock, 0, evt))
+  evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
+  if (!pth_mutex_acquire (&entry_lock, 0, evt))
     {
       if (pth_event_occurred (evt))
         rc = gpg_error (GPG_ERR_TIMEOUT);
@@ -170,10 +193,10 @@
                  gpg_strerror (rc));
       return rc;
     }
-   pth_event_free (evt, PTH_FREE_THIS);
- }
-#endif
+  pth_event_free (evt, PTH_FREE_THIS);
 
+  entry_owner = ctrl;
+
   if (entry_ctx)
     return 0; 
 
@@ -436,7 +459,7 @@
    passphrase is returned in RETPASS as an hex encoded string to be
    freed by the caller */
 int 
-agent_get_passphrase (CTRL ctrl,
+agent_get_passphrase (ctrl_t ctrl,
                       char **retpass, const char *desc, const char *prompt,
                       const char *errtext)
 {
@@ -517,11 +540,11 @@
 
 
 /* Pop up the PIN-entry, display the text and the prompt and ask the
-   user to confirm this.  We return 0 for success, ie. the used
+   user to confirm this.  We return 0 for success, ie. the user
    confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
    other error. */
 int 
-agent_get_confirmation (CTRL ctrl,
+agent_get_confirmation (ctrl_t ctrl,
                         const char *desc, const char *ok, const char *cancel)
 {
   int rc;
@@ -562,4 +585,119 @@
 }
 
 
+/* The thread running the popup message. */
+static void *
+popup_message_thread (void *arg)
+{
+  assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
+  popup_finished = 1;
+  return NULL;
+}
 
+
+/* Pop up a message window similar to the confirm one but keep it open
+   until agent_popup_message_stop has been called.  It is crucial for
+   the caller to make sure that the stop function gets called as soon
+   as the message is not anymore required becuase the message is
+   system modal and all other attempts to use the pinentry will fail
+   (after a timeout). */
+int 
+agent_popup_message_start (ctrl_t ctrl, const char *desc,
+                           const char *ok_btn, const char *cancel_btn)
+{
+  int rc;
+  char line[ASSUAN_LINELENGTH];
+  pth_attr_t tattr;
+
+  rc = start_pinentry (ctrl);
+  if (rc)
+    return rc;
+
+  if (desc)
+    snprintf (line, DIM(line)-1, "SETDESC %s", desc);
+  else
+    snprintf (line, DIM(line)-1, "RESET");
+  line[DIM(line)-1] = 0;
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  if (rc)
+    return unlock_pinentry (map_assuan_err (rc));
+
+  if (ok_btn)
+    {
+      snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
+      line[DIM(line)-1] = 0;
+      rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
+      if (rc)
+        return unlock_pinentry (map_assuan_err (rc));
+    }
+  if (cancel_btn)
+    {
+      snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel_btn);
+      line[DIM(line)-1] = 0;
+      rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
+      if (rc)
+        return unlock_pinentry (map_assuan_err (rc));
+    }
+
+  tattr = pth_attr_new();
+  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
+  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
+  pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
+
+  popup_finished = 0;
+  popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
+  if (!popup_tid)
+    {
+      rc = gpg_error_from_errno (errno);
+      log_error ("error spawning popup message handler: %s\n",
+                 strerror (errno) );
+      pth_attr_destroy (tattr);
+      return unlock_pinentry (rc);
+    }
+  pth_attr_destroy (tattr);
+
+  return 0;
+}
+
+/* Close a popup window. */
+void
+agent_popup_message_stop (ctrl_t ctrl)
+{
+  int rc;
+  pid_t pid;
+
+  if (!popup_tid || !entry_ctx)
+    {
+      log_debug ("agent_popup_message_stop called with no active popup\n");
+      return; 
+    }
+
+  pid = assuan_get_pid (entry_ctx);
+  if (pid == (pid_t)(-1))
+    ; /* No pid available can't send a kill. */
+  else if (popup_finished)
+    ; /* Already finished and ready for joining. */
+  else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
+    { /* The daemon already died.  No need to send a kill.  However
+         because we already waited for the process, we need to tell
+         assuan that it should not wait again (done by
+         unlock_pinentry). */
+      if (rc == pid)
+        assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
+    }
+  else
+    kill (pid, SIGINT);
+
+  /* Now wait for the thread to terminate. */
+  rc = pth_join (popup_tid, NULL);
+  if (!rc)
+    log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
+               strerror (errno));
+  popup_tid = NULL;
+  entry_owner = NULL;
+
+  /* Now we can close the connection. */
+  unlock_pinentry (0);
+}
+
+

Modified: branches/GNUPG-1-9-BRANCH/agent/t-protect.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/agent/t-protect.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/agent/t-protect.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -173,7 +173,8 @@
 
   for (i = 0; i < DIM (specs); i++)
     {
-      ret = agent_protect (specs[i].key, specs[i].passphrase,
+      ret = agent_protect ((const unsigned char*)specs[i].key,
+                           specs[i].passphrase,
 			   &specs[i].result, &specs[i].resultlen);
       if (gpg_err_code (ret) != specs[i].ret_expected)
 	{

Modified: branches/GNUPG-1-9-BRANCH/am/cmacros.am
===================================================================
--- branches/GNUPG-1-9-BRANCH/am/cmacros.am	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/am/cmacros.am	2005-11-28 11:52:25 UTC (rev 3947)
@@ -25,7 +25,8 @@
 AM_CPPFLAGS += -DGNUPG_BINDIR="\"$(bindir)\""            \
                -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""    \
                -DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\""  \
-               -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\""
+               -DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \
+               -DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\""
 endif
 
 if GNUPG_AGENT_PGM

Modified: branches/GNUPG-1-9-BRANCH/configure.ac
===================================================================
--- branches/GNUPG-1-9-BRANCH/configure.ac	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/configure.ac	2005-11-28 11:52:25 UTC (rev 3947)
@@ -22,9 +22,12 @@
 AC_PREREQ(2.52)
 min_automake_version="1.9.3"
 
-# Version number: Remember to change it immediately *after* a release.
-#                 Add a "-cvs" prefix for non-released code.
-AC_INIT(gnupg, 1.9.19, gnupg-devel at gnupg.org)
+# Remember to change the version number immediately *after* a release.
+# Uncomment the my_iscvs macro for non-released code.
+m4_define(my_version, [1.9.20])
+m4_define(my_iscvs, yes)
+AC_INIT([gnupg], my_version[]m4_ifdef([my_iscvs], [-cvs[]m4_translit(
+                 [$Revision$],[Ra-z $:])]), [gnupg-devel at gnupg.org])
 # Set development_version to yes if the minor number is odd or you
 # feel that the default check for a development version is not
 # sufficient.
@@ -36,7 +39,7 @@
 
 NEED_LIBASSUAN_VERSION=0.6.10
 
-NEED_KSBA_VERSION=0.9.12
+NEED_KSBA_VERSION=0.9.13
 
 
 PACKAGE=$PACKAGE_NAME

Modified: branches/GNUPG-1-9-BRANCH/kbx/keybox-blob.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/kbx/keybox-blob.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/kbx/keybox-blob.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -61,7 +61,7 @@
    u32	offset to the n-th key's keyID (a keyID is always 8 byte)
         or 0 if not known which is the case only for X509.
    u16	special key flags
-	 bit 0 =
+	 bit 0 = qualified signature (not yet implemented}
    u16	reserved
  u16  size of serialnumber(may be zero) 
    n  u16 (see above) bytes of serial number

Modified: branches/GNUPG-1-9-BRANCH/po/POTFILES.in
===================================================================
--- branches/GNUPG-1-9-BRANCH/po/POTFILES.in	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/po/POTFILES.in	2005-11-28 11:52:25 UTC (rev 3947)
@@ -17,6 +17,7 @@
 
 scd/scdaemon.c
 scd/app-openpgp.c
+scd/app-nks.c
 
 sm/base64.c
 sm/call-agent.c

Modified: branches/GNUPG-1-9-BRANCH/po/de.po
===================================================================
--- branches/GNUPG-1-9-BRANCH/po/de.po	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/po/de.po	2005-11-28 11:52:25 UTC (rev 3947)
@@ -10,8 +10,8 @@
 msgstr ""
 "Project-Id-Version: gnupg2 1.9.18\n"
 "Report-Msgid-Bugs-To: translations at gnupg.org\n"
-"POT-Creation-Date: 2005-11-23 13:00+0100\n"
-"PO-Revision-Date: 2005-11-23 13:02+0100\n"
+"POT-Creation-Date: 2005-11-28 12:14+0100\n"
+"PO-Revision-Date: 2005-11-28 12:16+0100\n"
 "Last-Translator: Werner Koch <wk at gnupg.org>\n"
 "Language-Team: de\n"
 "MIME-Version: 1.0\n"
@@ -766,6 +766,10 @@
 msgid "can't access %s - invalid OpenPGP card?\n"
 msgstr "Zugriff auf %s nicht möglich - ungültige OpenPGP Karte?\n"
 
+#: scd/app-nks.c:344
+msgid "the NullPIN has not yet been changed\n"
+msgstr "Die Nullpin wurde noch nicht geändert\n"
+
 #: sm/base64.c:317
 #, c-format
 msgid "invalid radix64 character %02x skipped\n"
@@ -1369,7 +1373,7 @@
 
 #: sm/gpgsm.c:1475
 msgid "this command has not yet been implemented\n"
-msgstr "Diee Kommando wurde noch nicht implementiert\n"
+msgstr "Dieses Kommando wurde noch nicht implementiert\n"
 
 #: sm/gpgsm.c:1705 sm/gpgsm.c:1742 sm/qualified.c:73
 #, c-format
@@ -1548,10 +1552,10 @@
 msgstr ""
 "Sie sind dabei, eine Signatur mit dem Zertifikat:\n"
 "\"%s\"\n"
-"zu erzeugen.  Dies wird einen qualifizierte Signatur erzeugen, \n"
-"die gesetzlich einer handgeschriebene gleichgestellt ist.\n"
+"zu erzeugen.  Dies wird eine qualifizierte Signatur erzeugen, \n"
+"die gesetzlich einer handgeschriebenen gleichgestellt ist.\n"
 "\n"
-"%s%sSind Sie wirklich sicher, da Sie dies möchten?"
+"%s%sSind Sie wirklich sicher, daß Sie dies möchten?"
 
 #: sm/qualified.c:224
 msgid ""

Modified: branches/GNUPG-1-9-BRANCH/scd/ChangeLog
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/ChangeLog	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/ChangeLog	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1,3 +1,46 @@
+2005-11-23  Werner Koch  <wk at g10code.com>
+
+	* app-nks.c (verify_pin): Give a special error message for a Nullpin.
+
+2005-10-29  Werner Koch  <wk at g10code.com>
+
+	* ccid-driver.c (send_escape_cmd): New args RESULT, RESULTLEN and
+	RESULTMAX.  Changed all callers.
+	(ccid_transceive_escape): New.
+
+2005-10-27  Werner Koch  <wk at g10code.com>
+
+	* apdu.c [__CYGWIN__]: Make cygwin environment similar to _WIN32.
+	Suggested by John P. Clizbe.
+	* scdaemon.c [__CYGWIN__]: Set default PC/SC driver to winscard.dll.
+
+2005-10-19  Werner Koch  <wk at g10code.com>
+
+	* ccid-driver.h (CCID_DRIVER_ERR_NO_KEYPAD): New.
+	* apdu.h (SW_HOST_NO_KEYPAD): New.
+	* iso7816.h (struct iso7816_pininfo_s): New.
+	* iso7816.c (map_sw): Support new code.
+	(iso7816_check_keypad): New.
+	(iso7816_verify_kp, iso7816_change_reference_data_kp) 
+	(iso7816_reset_retry_counter_kp): New.  Extended versions of the
+	original functions.
+	* apdu.c (host_sw_string): Support new code. 
+	(reader_table_s): New field CHECK_KEYPAD.
+	(new_reader_slot, open_ct_reader, open_pcsc_reader) 
+	(open_ccid_reader, open_rapdu_reader): Initialize it.
+	(check_ccid_keypad): New.
+	(apdu_check_keypad): New.
+	(apdu_send_le): Factored all code out to ...
+	(send_le): .. new.  Takes an additional arg; changed all callers
+	of the orginal function to use this one with a NULL for the new
+	arg.
+	(apdu_send_simple_kp): New.
+	(ct_send_apdu, pcsc_send_apdu, my_rapdu_send_apdu) 
+	(send_apdu_ccid): New arg PININFO.
+	(send_apdu_ccid): Use the new arg.
+
+	* scdaemon.c: New option --disable-keypad.
+
 2005-10-08  Marcus Brinkmann  <marcus at g10code.de>
 
 	* Makefile.am (scdaemon_LDADD): Add ../gl/libgnu.a after
@@ -3,4 +46,16 @@
 	../common/libcommon.a.
 
+2005-09-20  Werner Koch  <wk at g10code.com>
+
+	* app-dinsig.c (verify_pin): Try ISO 9564 BCD encoding.
+
+	* iso7816.c (iso7816_select_application): Add arg FLAGS.  Changed
+	all callers to pass 0.
+	* app-openpgp.c (app_select_openpgp): But this one requires a
+	special flag.
+
+	* app-p15.c (app_select_p15): Don't use select application for the
+	BELPIC.
+
 2005-09-09  Werner Koch  <wk at g10code.com>
 

Modified: branches/GNUPG-1-9-BRANCH/scd/apdu.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/apdu.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/apdu.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -66,10 +66,10 @@
 #include "ccid-driver.h"
 
 
-/* To to conflicting use of threading libraries we usually can't link
+/* Due 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
+#if !defined(HAVE_W32_SYSTEM) && !defined(__CYGWIN__)
 #define NEED_PCSC_WRAPPER 1
 #endif
 #endif
@@ -78,7 +78,7 @@
 #define MAX_READER 4 /* Number of readers we support concurrently. */
 
 
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
 #define DLSTDCALL __stdcall
 #else
 #define DLSTDCALL
@@ -90,6 +90,14 @@
 #define MAX_OPEN_FDS 20
 #endif
 
+/* Helper to pass patrameters related to keypad based operations. */
+struct pininfo_s
+{
+  int mode;
+  int minlen;
+  int maxlen;
+  int padlen;
+};
 
 /* A structure to collect information pertaining to one reader
    slot. */
@@ -103,7 +111,8 @@
   int (*reset_reader)(int);
   int (*get_status_reader)(int, unsigned int *);
   int (*send_apdu_reader)(int,unsigned char *,size_t,
-                          unsigned char *, size_t *);
+                          unsigned char *, size_t *, struct pininfo_s *);
+  int (*check_keypad)(int, int, int, int, int, int);
   void (*dump_status_reader)(int);
 
   struct {
@@ -320,6 +329,7 @@
   reader_table[reader].reset_reader = NULL;
   reader_table[reader].get_status_reader = NULL;
   reader_table[reader].send_apdu_reader = NULL;
+  reader_table[reader].check_keypad = NULL;
   reader_table[reader].dump_status_reader = NULL;
 
   reader_table[reader].used = 1;
@@ -372,6 +382,7 @@
     case SW_HOST_GENERAL_ERROR: return "general error";
     case SW_HOST_NO_READER: return "no reader";
     case SW_HOST_ABORTED: return "aborted";
+    case SW_HOST_NO_KEYPAD: return "no keypad"; 
     default: return "unknown host status error";
     }
 }
@@ -533,7 +544,7 @@
    set to BUFLEN.  Returns: CT API error code. */
 static int
 ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-              unsigned char *buffer, size_t *buflen)
+              unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
 {
   int rc;
   unsigned char dad[1], sad[1];
@@ -596,6 +607,7 @@
   reader_table[reader].reset_reader = reset_ct_reader;
   reader_table[reader].get_status_reader = ct_get_status;
   reader_table[reader].send_apdu_reader = ct_send_apdu;
+  reader_table[reader].check_keypad = NULL;
   reader_table[reader].dump_status_reader = ct_dump_reader_status;
 
   dump_reader_status (reader);
@@ -1082,7 +1094,8 @@
    set to BUFLEN.  Returns: CT API error code. */
 static int
 pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-                unsigned char *buffer, size_t *buflen)
+                unsigned char *buffer, size_t *buflen, 
+                struct pininfo_s *pininfo)
 {
 #ifdef NEED_PCSC_WRAPPER
   long err;
@@ -1479,6 +1492,7 @@
   reader_table[slot].reset_reader = reset_pcsc_reader;
   reader_table[slot].get_status_reader = pcsc_get_status;
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
+  reader_table[slot].check_keypad = NULL;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
   /* Read the status so that IS_T0 will be set. */
@@ -1625,6 +1639,7 @@
   reader_table[slot].reset_reader = reset_pcsc_reader;
   reader_table[slot].get_status_reader = pcsc_get_status;
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
+  reader_table[slot].check_keypad = NULL;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
 /*   log_debug ("state    from pcsc_status: 0x%lx\n", card_state); */
@@ -1713,7 +1728,8 @@
    set to BUFLEN.  Returns: Internal CCID driver error code. */
 static int
 send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
-                unsigned char *buffer, size_t *buflen)
+                unsigned char *buffer, size_t *buflen,
+                struct pininfo_s *pininfo)
 {
   long err;
   size_t maxbuflen;
@@ -1727,9 +1743,18 @@
     log_printhex ("  APDU_data:", apdu, apdulen);
 
   maxbuflen = *buflen;
-  err = ccid_transceive (reader_table[slot].ccid.handle,
-                         apdu, apdulen,
-                         buffer, maxbuflen, buflen);
+  if (pininfo)
+    err = ccid_transceive_secure (reader_table[slot].ccid.handle,
+                                  apdu, apdulen,
+                                  pininfo->mode,
+                                  pininfo->minlen,
+                                  pininfo->maxlen,
+                                  pininfo->padlen,
+                                  buffer, maxbuflen, buflen);
+  else
+    err = ccid_transceive (reader_table[slot].ccid.handle,
+                           apdu, apdulen,
+                           buffer, maxbuflen, buflen);
   if (err)
     log_error ("ccid_transceive failed: (0x%lx)\n",
                err);
@@ -1737,6 +1762,24 @@
   return err;
 }
 
+
+/* Check whether the CCID reader supports the ISO command code COMMAND
+   on the keypad.  Return 0 on success.  For a description of the pin
+   parameters, see ccid-driver.c */
+static int
+check_ccid_keypad (int slot, int command, int pin_mode,
+                   int pinlen_min, int pinlen_max, int pin_padlen)
+{
+  unsigned char apdu[] = { 0, 0, 0, 0x81 };
+
+  apdu[1] = command;
+  return ccid_transceive_secure (reader_table[slot].ccid.handle,
+                                 apdu, sizeof apdu,
+                                 pin_mode, pinlen_min, pinlen_max, pin_padlen,
+                                 NULL, 0, NULL);
+}
+
+
 /* Open the reader and try to read an ATR.  */
 static int
 open_ccid_reader (const char *portstr)
@@ -1776,6 +1819,7 @@
   reader_table[slot].reset_reader = reset_ccid_reader;
   reader_table[slot].get_status_reader = get_status_ccid;
   reader_table[slot].send_apdu_reader = send_apdu_ccid;
+  reader_table[slot].check_keypad = check_ccid_keypad;
   reader_table[slot].dump_status_reader = dump_ccid_reader_status;
 
   dump_reader_status (slot);
@@ -1932,7 +1976,8 @@
    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)
+                    unsigned char *buffer, size_t *buflen,
+                    struct pininfo_s *pininfo)
 {
   int err;
   reader_table_t slotp;
@@ -2063,6 +2108,7 @@
   reader_table[slot].reset_reader = reset_rapdu_reader;
   reader_table[slot].get_status_reader = my_rapdu_get_status;
   reader_table[slot].send_apdu_reader = my_rapdu_send_apdu;
+  reader_table[slot].check_keypad = NULL;
   reader_table[slot].dump_status_reader = NULL;
 
   dump_reader_status (slot);
@@ -2198,28 +2244,28 @@
       pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
       pcsc_release_context   = dlsym (handle, "SCardReleaseContext");
       pcsc_list_readers      = dlsym (handle, "SCardListReaders");
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_list_readers)
         pcsc_list_readers    = dlsym (handle, "SCardListReadersA");
 #endif
       pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_get_status_change)
         pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
 #endif
       pcsc_connect           = dlsym (handle, "SCardConnect");
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_connect)
         pcsc_connect         = dlsym (handle, "SCardConnectA");
 #endif
       pcsc_reconnect         = dlsym (handle, "SCardReconnect");
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_reconnect)
         pcsc_reconnect       = dlsym (handle, "SCardReconnectA");
 #endif
       pcsc_disconnect        = dlsym (handle, "SCardDisconnect");
       pcsc_status            = dlsym (handle, "SCardStatus");
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__CYGWIN__)
       if (!pcsc_status)
         pcsc_status          = dlsym (handle, "SCardStatusA");
 #endif
@@ -2492,11 +2538,30 @@
 }
 
 
+/* Check whether the reader supports the ISO command code COMMAND on
+   the keypad.  Return 0 on success.  For a description of the pin
+   parameters, see ccid-driver.c */
+int
+apdu_check_keypad (int slot, int command, int pin_mode,
+                   int pinlen_min, int pinlen_max, int pin_padlen)
+{
+  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
+    return SW_HOST_NO_DRIVER;
+
+  if (reader_table[slot].check_keypad)
+    return reader_table[slot].check_keypad (slot, command,
+                                            pin_mode, pinlen_min, pinlen_max,
+                                            pin_padlen);
+  else
+    return SW_HOST_NOT_SUPPORTED;
+}
+
+
 /* Dispatcher for the actual send_apdu function. Note, that this
    function should be called in locked state. */
 static int
 send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-           unsigned char *buffer, size_t *buflen)
+           unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -2504,24 +2569,20 @@
   if (reader_table[slot].send_apdu_reader)
     return reader_table[slot].send_apdu_reader (slot,
                                                 apdu, apdulen,
-                                                buffer, buflen);
+                                                buffer, buflen, pininfo);
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
-/* Send an APDU to the card in SLOT.  The APDU is created from all
-   given parameters: CLASS, INS, P0, P1, LC, DATA, LE.  A value of -1
-   for LC won't sent this field and the data field; in this case DATA
-   must also be passed as NULL.  The return value is the status word
-   or -1 for an invalid SLOT or other non card related error.  If
-   RETBUF is not NULL, it will receive an allocated buffer with the
-   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
-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)
+
+/* Core APDU trabceiver function. Parameters are described at
+   apdu_send_le with the exception of PININFO which indicates keypad
+   related operations if not NULL. */
+static int
+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,
+         struct pininfo_s *pininfo)
 {
 #define RESULTLEN 256
   unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
@@ -2570,7 +2631,7 @@
   /* As safeguard don't pass any garbage from the stack to the driver. */
   memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
   resultlen = RESULTLEN;
-  rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
+  rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
   if (rc || resultlen < 2)
     {
       log_error ("apdu_send_simple(%d) failed: %s\n",
@@ -2638,7 +2699,7 @@
           apdu[apdulen++] = len;
           memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
           resultlen = RESULTLEN;
-          rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
+          rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
           if (rc || resultlen < 2)
             {
               log_error ("apdu_send_simple(%d) for get response failed: %s\n",
@@ -2704,6 +2765,27 @@
 }
 
 /* Send an APDU to the card in SLOT.  The APDU is created from all
+   given parameters: CLASS, INS, P0, P1, LC, DATA, LE.  A value of -1
+   for LC won't sent this field and the data field; in this case DATA
+   must also be passed as NULL.  The return value is the status word
+   or -1 for an invalid SLOT or other non card related error.  If
+   RETBUF is not NULL, it will receive an allocated buffer with the
+   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
+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)
+{
+  return send_le (slot, class, ins, p0, p1,
+                  lc, data, le,
+                  retbuf, retbuflen,
+                  NULL);
+}
+
+
+/* Send an APDU to the card in SLOT.  The APDU is created from all
    given parameters: CLASS, INS, P0, P1, LC, DATA.  A value of -1 for
    LC won't sent this field and the data field; in this case DATA must
    also be passed as NULL. The return value is the status word or -1
@@ -2716,8 +2798,8 @@
 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,
-                       retbuf, retbuflen);
+  return send_le (slot, class, ins, p0, p1, lc, data, 256,
+                  retbuf, retbuflen, NULL);
 }
 
 /* Send an APDU to the card in SLOT.  The APDU is created from all
@@ -2730,10 +2812,28 @@
 apdu_send_simple (int slot, int class, int ins, int p0, int p1,
                   int lc, const char *data)
 {
-  return apdu_send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL);
+  return send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL, NULL);
 }
 
 
+/* Same as apdu_send_simple but uses the keypad of the reader. */
+int
+apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
+                     int lc, const char *data,  
+                     int pin_mode,
+                     int pinlen_min, int pinlen_max, int pin_padlen)
+{
+  struct pininfo_s pininfo;
+
+  pininfo.mode = pin_mode;
+  pininfo.minlen = pinlen_min;
+  pininfo.maxlen = pinlen_max;
+  pininfo.padlen = pin_padlen;
+  return send_le (slot, class, ins, p0, p1, lc, data, -1,
+                  NULL, NULL, &pininfo);
+}
+
+
 /* This is a more generic version of the apdu sending routine.  It
    takes an already formatted APDU in APDUDATA or length APDUDATALEN
    and returns the with the APDU including the status word.  With
@@ -2771,7 +2871,7 @@
   class = apdulen? *apdu : 0;
 
   resultlen = RESULTLEN;
-  rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
+  rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
   if (rc || resultlen < 2)
     {
       log_error ("apdu_send_direct(%d) failed: %s\n",
@@ -2825,7 +2925,7 @@
           apdu[apdulen++] = len;
           memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
           resultlen = RESULTLEN;
-          rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
+          rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
           if (rc || resultlen < 2)
             {
               log_error ("apdu_send_direct(%d) for get response failed: %s\n",

Modified: branches/GNUPG-1-9-BRANCH/scd/apdu.h
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/apdu.h	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/apdu.h	2005-11-28 11:52:25 UTC (rev 3947)
@@ -63,7 +63,8 @@
   SW_HOST_CARD_IO_ERROR = 0x1000a,
   SW_HOST_GENERAL_ERROR = 0x1000b,
   SW_HOST_NO_READER     = 0x1000c,
-  SW_HOST_ABORTED       = 0x1000d
+  SW_HOST_ABORTED       = 0x1000d,
+  SW_HOST_NO_KEYPAD     = 0x1000e
 };
 
 
@@ -96,8 +97,14 @@
 int apdu_reset (int slot);
 int apdu_get_status (int slot, int hang,
                      unsigned int *status, unsigned int *changed);
+int apdu_check_keypad (int slot, int command, int pin_mode,
+                       int pinlen_min, int pinlen_max, int pin_padlen);
 int apdu_send_simple (int slot, int class, int ins, int p0, int p1,
                       int lc, const char *data);
+int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
+                         int lc, const char *data,  
+                         int pin_mode,
+                         int pinlen_min, int pinlen_max, int pin_padlen);
 int apdu_send (int slot, int class, int ins, int p0, int p1,
                int lc, const char *data,
                unsigned char **retbuf, size_t *retbuflen);

Modified: branches/GNUPG-1-9-BRANCH/scd/app-dinsig.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/app-dinsig.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/app-dinsig.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1,5 +1,5 @@
 /* app-dinsig.c - The DINSIG (DIN V 66291-1) card application.
- *	Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ *	Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -280,10 +280,11 @@
 {
   if (!app->did_chv1 || app->force_chv1 ) 
     {
+      const char *s;
       char *pinvalue;
       int rc;
 
-      rc = pincb (pincb_arg, "PIN", &pinvalue); 
+      rc = pincb (pincb_arg, "PIN", &pinvalue);
       if (rc)
         {
           log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
@@ -291,8 +292,16 @@
         }
 
       /* We require the PIN to be at least 6 and at max 8 bytes.
-         According to the specs, this should all be ASCII but we don't
-         check this. */
+         According to the specs, this should all be ASCII.  */
+      for (s=pinvalue; digitp (s); s++)
+        ;
+      if (*s)
+        {
+          log_error ("Non-numeric digits found in PIN\n");
+          xfree (pinvalue);
+          return gpg_error (GPG_ERR_BAD_PIN);
+        }
+
       if (strlen (pinvalue) < 6)
         {
           log_error ("PIN is too short; minimum length is 6\n");
@@ -307,6 +316,28 @@
         }
 
       rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
+      if (gpg_err_code (rc) == GPG_ERR_INV_VALUE)
+        {
+          /* We assume that ISO 9564-1 encoding is used and we failed
+             because the first nibble we passed was 3 and not 2.  DIN
+             says something about looking up such an encoding in the
+             SSD but I was not able to find any tag relevant to
+             this. */
+          char paddedpin[8];
+          int i, ndigits;
+
+          for (ndigits=0, s=pinvalue; *s; ndigits++, s++)
+            ;
+          i = 0;
+          paddedpin[i++] = 0x20 | (ndigits & 0x0f);
+          for (s=pinvalue; i < sizeof paddedpin && *s && s[1]; s = s+2 )
+            paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f));
+          if (i < sizeof paddedpin && *s)
+            paddedpin[i++] = (((*s - '0') << 4) | 0x0f);
+          while (i < sizeof paddedpin)
+              paddedpin[i++] = 0xff;
+          rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin);
+        }
       if (rc)
         {
           log_error ("verify PIN failed\n");
@@ -404,7 +435,7 @@
   int slot = app->slot;
   int rc;
   
-  rc = iso7816_select_application (slot, aid, sizeof aid);
+  rc = iso7816_select_application (slot, aid, sizeof aid, 0);
   if (!rc)
     {
       app->apptype = "DINSIG";

Modified: branches/GNUPG-1-9-BRANCH/scd/app-nks.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/app-nks.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/app-nks.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -27,7 +27,7 @@
 #include <time.h>
 
 #include "scdaemon.h"
-
+#include "i18n.h"
 #include "iso7816.h"
 #include "app-common.h"
 #include "tlv.h"
@@ -320,7 +320,7 @@
           return rc;
         }
 
-      /* The follwoing limits are due to TCOS but also defined in the
+      /* The following limits are due to TCOS but also defined in the
          NKS specs. */
       if (strlen (pinvalue) < 6)
         {
@@ -340,7 +340,10 @@
       rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
       if (rc)
         {
-          log_error ("verify PIN failed\n");
+          if ( gpg_error (rc) == GPG_ERR_USE_CONDITIONS )
+            log_error (_("the NullPIN has not yet been changed\n"));
+          else
+            log_error ("verify PIN failed\n");
           xfree (pinvalue);
           return rc;
         }
@@ -492,7 +495,7 @@
   int slot = app->slot;
   int rc;
   
-  rc = iso7816_select_application (slot, aid, sizeof aid);
+  rc = iso7816_select_application (slot, aid, sizeof aid, 0);
   if (!rc)
     {
       app->apptype = "NKS";

Modified: branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/app-openpgp.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1284,7 +1284,12 @@
   if (!app->did_chv2) 
     {
       char *pinvalue;
+      iso7816_pininfo_t pininfo;
 
+      memset (&pininfo, 0, sizeof pininfo);
+      pininfo.mode = 1;
+      pininfo.minlen = 6;
+
       rc = pincb (pincb_arg, "PIN", &pinvalue); 
       if (rc)
         {
@@ -2455,7 +2460,9 @@
   size_t buflen;
   void *relptr;
   
-  rc = iso7816_select_application (slot, aid, sizeof aid);
+  /* Note that the card can't cope with P2=0xCO, thus we need to pass a
+     special flag value. */
+  rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
   if (!rc)
     {
       unsigned int manufacturer;

Modified: branches/GNUPG-1-9-BRANCH/scd/app-p15.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/app-p15.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/app-p15.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -3268,18 +3268,15 @@
   int direct = 0;
   int is_belpic = 0;
 
-  rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid);
+  rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid, 0);
   if (rc)
-    {
-      rc = iso7816_select_application (slot, pkcs15be_aid,sizeof pkcs15be_aid);
-      if (!rc)
-        is_belpic = 1;
-    }
-  if (rc)
     { /* Not found: Try to locate it from 2F00.  We use direct path
          selection here because it seems that the Belgian eID card
          does only allow for that.  Many other cards supports this
-         selection method too. */
+         selection method too.  Note, that we don't use
+         select_application above for the Belgian card - the call
+         works but it seems that it did not switch to the correct DF.
+         Using the 2f02 just works. */
       unsigned short path[1] = { 0x2f00 };
 
       rc = iso7816_select_path (app->slot, path, 1, NULL, NULL);

Modified: branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/ccid-driver.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1240,7 +1240,9 @@
   if (CCID_COMMAND_FAILED (buffer))
     print_command_failed (buffer);
 
-  /* Check whether a card is at all available. */
+  /* Check whether a card is at all available.  Note: If you add new
+     error codes here, check whether they need to be ignored in
+     send_escape_cmd. */
   switch ((buffer[7] & 0x03))
     {
     case 0: /* no error */ break;
@@ -1253,16 +1255,23 @@
 
 
 /* Note that this function won't return the error codes NO_CARD or
-   CARD_INACTIVE */
+   CARD_INACTIVE.  IF RESULT is not NULL, the result from the
+   operation will get returned in RESULT and its length in RESULTLEN.
+   If the response is larger than RESULTMAX, an error is returned and
+   the required buffer length returned in RESULTLEN.  */
 static int 
 send_escape_cmd (ccid_driver_t handle,
-                 const unsigned char *data, size_t datalen)
+                 const unsigned char *data, size_t datalen,
+                 unsigned char *result, size_t resultmax, size_t *resultlen)
 {
   int i, rc;
   unsigned char msg[100];
   size_t msglen;
   unsigned char seqno;
 
+  if (resultlen)
+    *resultlen = 0;
+
   if (datalen > sizeof msg - 10)
     return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large.  */
 
@@ -1285,11 +1294,42 @@
     return rc;
   rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
                 seqno, 5000, 0);
-
+  if (result)
+    switch (rc)
+      {
+        /* We need to ignore certain errorcode here. */
+      case 0:
+      case CCID_DRIVER_ERR_CARD_INACTIVE:
+      case CCID_DRIVER_ERR_NO_CARD:
+        {
+          if (msglen > resultmax)
+            rc = CCID_DRIVER_ERR_INV_VALUE; /* Response too large. */
+          else
+            {
+              memcpy (result, msg, msglen);
+              *resultlen = msglen;
+            }
+          rc = 0;
+        }
+        break;
+      default:
+        break;
+      }
+  
   return rc;
 }
 
 
+int
+ccid_transceive_escape (ccid_driver_t handle,
+                        const unsigned char *data, size_t datalen,
+                        unsigned char *resp, size_t maxresplen, size_t *nresp)
+{
+  return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp);
+}
+
+
+
 /* experimental */
 int
 ccid_poll (ccid_driver_t handle)
@@ -1445,7 +1485,8 @@
     {
       tried_iso = 1;
       /* Try switching to ISO mode. */
-      if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2))
+      if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2,
+                            NULL, 0, NULL))
         goto again;
     }
   else if (CCID_COMMAND_FAILED (msg))
@@ -1957,14 +1998,16 @@
 }
 
 
-/* Send the CCID Secure command to the reader.  APDU_BUF should contain the APDU   template.  PIN_MODE defines now the pin gets formatted:
+/* Send the CCID Secure command to the reader.  APDU_BUF should
+   contain the APDU template.  PIN_MODE defines how the pin gets
+   formatted:
    
      1 := The PIN is ASCII encoded and of variable length.  The
           length of the PIN entered will be put into Lc by the reader.
           The APDU should me made up of 4 bytes without Lc.
 
    PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
-   may be used t enable usbale defaults.  PIN_PADLEN should be 0
+   may be used t enable reasonable defaults.  PIN_PADLEN should be 0.
    
    When called with RESP and NRESP set to NULL, the function will
    merely check whether the reader supports the secure command for the
@@ -1996,7 +2039,7 @@
   else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
     return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
   else
-    return CCID_DRIVER_ERR_NOT_SUPPORTED;
+    return CCID_DRIVER_ERR_NO_KEYPAD;
     
   if (pin_mode != 1)
     return CCID_DRIVER_ERR_NOT_SUPPORTED;
@@ -2027,7 +2070,8 @@
   if (handle->id_vendor == VENDOR_SCM)
     {
       DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
-      rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3);
+      rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3,
+                            NULL, 0, NULL);
       if (rc)
         return rc;
     }
@@ -2044,7 +2088,7 @@
   if (handle->id_vendor == VENDOR_SCM)
     {
       /* For the SPR532 the next 2 bytes need to be zero.  We do this
-         for all SCM product. Kudos to to Martin Paljak for this
+         for all SCM product. Kudos to Martin Paljak for this
          hint.  */
       msg[13] = msg[14] = 0;
     }

Modified: branches/GNUPG-1-9-BRANCH/scd/ccid-driver.h
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/ccid-driver.h	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/ccid-driver.h	2005-11-28 11:52:25 UTC (rev 3947)
@@ -58,7 +58,7 @@
 #ifndef CCID_DRIVER_H
 #define CCID_DRIVER_H
 
-/* The CID driver returns the same error codes as the statsu words
+/* The CID driver returns the same error codes as the status words
    used by GnuPG's apdu.h.  For ease of maintenance they should always
    match.  */
 #define CCID_DRIVER_ERR_OUT_OF_CORE    0x10001 
@@ -74,6 +74,7 @@
 #define CCID_DRIVER_ERR_GENERAL_ERROR  0x1000b
 #define CCID_DRIVER_ERR_NO_READER      0x1000c
 #define CCID_DRIVER_ERR_ABORTED        0x1000d
+#define CCID_DRIVER_ERR_NO_KEYPAD      0x1000e
 
 struct ccid_driver_s;
 typedef struct ccid_driver_s *ccid_driver_t;
@@ -94,6 +95,10 @@
                      int pin_mode, 
                      int pinlen_min, int pinlen_max, int pin_padlen, 
                      unsigned char *resp, size_t maxresplen, size_t *nresp);
+int ccid_transceive_escape (ccid_driver_t handle,
+                            const unsigned char *data, size_t datalen,
+                            unsigned char *resp, size_t maxresplen,
+                            size_t *nresp);
 
 
 

Modified: branches/GNUPG-1-9-BRANCH/scd/iso7816.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/iso7816.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/iso7816.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -47,9 +47,9 @@
 
 
 #define CMD_SELECT_FILE 0xA4
-#define CMD_VERIFY      0x20
-#define CMD_CHANGE_REFERENCE_DATA 0x24
-#define CMD_RESET_RETRY_COUNTER   0x2C
+#define CMD_VERIFY                ISO7816_VERIFY
+#define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA
+#define CMD_RESET_RETRY_COUNTER   ISO7816_RESET_RETRY_COUNTER
 #define CMD_GET_DATA    0xCA
 #define CMD_PUT_DATA    0xDA
 #define CMD_MSE         0x22
@@ -95,6 +95,7 @@
     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;
+    case SW_HOST_NO_KEYPAD:      ec = GPG_ERR_NOT_SUPPORTED; break;
 
     default:
       if ((sw & 0x010000))
@@ -124,12 +125,15 @@
    requested application ID.  The function can't be used to enumerate
    AIDs and won't return the AID on success.  The return value is 0
    for okay or a GPG error code.  Note that ISO error codes are
-   internally mapped. */
+   internally mapped.  Bit 0 of FLAGS should be set if the card does
+   not understand P2=0xC0. */
 gpg_error_t
-iso7816_select_application (int slot, const char *aid, size_t aidlen)
+iso7816_select_application (int slot, const char *aid, size_t aidlen,
+                            unsigned int flags)
 {
   int sw;
-  sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
+  sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4,
+                         (flags&1)? 0 :0x0c, aidlen, aid);
   return map_sw (sw);
 }
 
@@ -221,27 +225,59 @@
 }
 
 
+/* Check whether the reader supports the ISO command code COMMAND on
+   the keypad.  Returns 0 on success.  */
+gpg_error_t
+iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
+{
+  int sw;
 
+  sw = apdu_check_keypad (slot, command, 
+                          pininfo->mode, pininfo->minlen, pininfo->maxlen,
+                          pininfo->padlen);
+  return map_sw (sw);
+}
+
+
 /* Perform a VERIFY command on SLOT using the card holder verification
-   vector CHVNO with a CHV of lenght CHVLEN.  Returns 0 on success. */
+   vector CHVNO with a CHV of lenght CHVLEN.  With PININFO non-NULL
+   the keypad of the reader will be used.  Returns 0 on success. */
 gpg_error_t
-iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
+iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen,
+                   iso7816_pininfo_t *pininfo)
 {
   int sw;
 
-  sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
+  if (pininfo && pininfo->mode)
+    sw = apdu_send_simple_kp (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv,
+                              pininfo->mode,
+                              pininfo->minlen,
+                              pininfo->maxlen,
+                              pininfo->padlen);
+  else
+    sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
   return map_sw (sw);
 }
 
+/* Perform a VERIFY command on SLOT using the card holder verification
+   vector CHVNO with a CHV of lenght CHVLEN.  Returns 0 on success. */
+gpg_error_t
+iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
+{
+  return iso7816_verify_kp (slot, chvno, chv, chvlen, NULL);
+}
+
 /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
    verification vector CHVNO.  If the OLDCHV is NULL (and OLDCHVLEN
    0), a "change reference data" is done, otherwise an "exchange
    reference data".  The new reference data is expected in NEWCHV of
-   length NEWCHVLEN.  */
+   length NEWCHVLEN.  With PININFO non-NULL the keypad of the reader
+   will be used.  */
 gpg_error_t
-iso7816_change_reference_data (int slot, int chvno,
-                               const char *oldchv, size_t oldchvlen,
-                               const char *newchv, size_t newchvlen)
+iso7816_change_reference_data_kp (int slot, int chvno,
+                                  const char *oldchv, size_t oldchvlen,
+                                  const char *newchv, size_t newchvlen,
+                                  iso7816_pininfo_t *pininfo)
 {
   int sw;
   char *buf;
@@ -258,28 +294,69 @@
     memcpy (buf, oldchv, oldchvlen);
   memcpy (buf+oldchvlen, newchv, newchvlen);
 
-  sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
-                         oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
+  if (pininfo && pininfo->mode)
+    sw = apdu_send_simple_kp (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
+                           oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf,
+                           pininfo->mode,
+                           pininfo->minlen,
+                           pininfo->maxlen,
+                           pininfo->padlen);
+  else
+    sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
+                           oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
   xfree (buf);
   return map_sw (sw);
 
 }
 
+/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
+   verification vector CHVNO.  If the OLDCHV is NULL (and OLDCHVLEN
+   0), a "change reference data" is done, otherwise an "exchange
+   reference data".  The new reference data is expected in NEWCHV of
+   length NEWCHVLEN.  */
 gpg_error_t
-iso7816_reset_retry_counter (int slot, int chvno,
-                             const char *newchv, size_t newchvlen)
+iso7816_change_reference_data (int slot, int chvno,
+                               const char *oldchv, size_t oldchvlen,
+                               const char *newchv, size_t newchvlen)
 {
+  return iso7816_change_reference_data_kp (slot, chvno, oldchv, oldchvlen,
+                                           newchv, newchvlen, NULL);
+}
+
+
+gpg_error_t
+iso7816_reset_retry_counter_kp (int slot, int chvno,
+                                const char *newchv, size_t newchvlen,
+                                iso7816_pininfo_t *pininfo)
+{
   int sw;
 
   if (!newchv || !newchvlen )
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
-                         2, chvno, newchvlen, newchv);
+  if (pininfo && pininfo->mode)
+    sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER,
+                           2, chvno, newchvlen, newchv,
+                           pininfo->mode,
+                           pininfo->minlen,
+                           pininfo->maxlen,
+                           pininfo->padlen);
+  else
+    sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
+                           2, chvno, newchvlen, newchv);
   return map_sw (sw);
 }
 
 
+gpg_error_t
+iso7816_reset_retry_counter (int slot, int chvno,
+                             const char *newchv, size_t newchvlen)
+{
+  return iso7816_reset_retry_counter_kp (slot, chvno, newchv, newchvlen, NULL);
+}
+
+
+
 /* Perform a GET DATA command requesting TAG and storing the result in
    a newly allocated buffer at the address passed by RESULT.  Return
    the length of this data at the address of RESULTLEN. */

Modified: branches/GNUPG-1-9-BRANCH/scd/iso7816.h
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/iso7816.h	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/iso7816.h	2005-11-28 11:52:25 UTC (rev 3947)
@@ -28,10 +28,30 @@
 #include "cardglue.h"
 #endif
 
+/* Command codes used by iso7816_check_keypad. */
+#define ISO7816_VERIFY                0x20
+#define ISO7816_CHANGE_REFERENCE_DATA 0x24
+#define ISO7816_RESET_RETRY_COUNTER   0x2C
+
+
+/* Information to be passed to keypad equipped readers.  See
+   ccid-driver.c for details. */
+struct iso7816_pininfo_s
+{
+  int mode;    /* A mode of 0 means: Do not use the keypad. */
+  int minlen;
+  int maxlen;
+  int padlen;
+  int padchar;
+};
+typedef struct iso7816_pininfo_s iso7816_pininfo_t;
+
+
 gpg_error_t iso7816_map_sw (int sw);
 
 gpg_error_t iso7816_select_application (int slot,
-                                        const char *aid, size_t aidlen);
+                                        const char *aid, size_t aidlen,
+                                        unsigned int flags);
 gpg_error_t iso7816_select_file (int slot, int tag, int is_dir,
                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_select_path (int slot,
@@ -39,13 +59,26 @@
                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_list_directory (int slot, int list_dirs,
                                     unsigned char **result, size_t *resultlen);
+gpg_error_t iso7816_check_keypad (int slot, int command,
+                                  iso7816_pininfo_t *pininfo);
 gpg_error_t iso7816_verify (int slot,
                             int chvno, const char *chv, size_t chvlen);
+gpg_error_t iso7816_verify_kp (int slot,
+                               int chvno, const char *chv, size_t chvlen,
+                               iso7816_pininfo_t *pininfo);
 gpg_error_t iso7816_change_reference_data (int slot, int chvno,
                                const char *oldchv, size_t oldchvlen,
                                const char *newchv, size_t newchvlen);
+gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno,
+                               const char *oldchv, size_t oldchvlen,
+                               const char *newchv, size_t newchvlen,
+                               iso7816_pininfo_t *pininfo);
 gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
                                          const char *newchv, size_t newchvlen);
+gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno,
+                                            const char *newchv,
+                                            size_t newchvlen,
+                                            iso7816_pininfo_t *pininfo);
 gpg_error_t iso7816_get_data (int slot, int tag,
                               unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_put_data (int slot, int tag,

Modified: branches/GNUPG-1-9-BRANCH/scd/scdaemon.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/scdaemon.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/scdaemon.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -84,6 +84,7 @@
   opcscDriver,
   oDisableCCID,
   oDisableOpenSC,
+  oDisableKeypad,
   oAllowAdmin,
   oDenyAdmin,
   oDisableApplication,
@@ -126,6 +127,7 @@
                                     "@"
 #endif
                                          /* end --disable-ccid */},
+  { oDisableKeypad, "disable-keypad", 0, N_("do not use a reader's keypad")},
   { oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
   { oDenyAdmin,  "deny-admin",  0, "@" },  
   { oDisableApplication, "disable-application", 2, "@"},
@@ -135,7 +137,7 @@
 
 
 /* The card dirver we use by default for PC/SC.  */
-#ifdef HAVE_W32_SYSTEM
+#if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__)
 #define DEFAULT_PCSC_DRIVER "winscard.dll"
 #else
 #define DEFAULT_PCSC_DRIVER "libpcsclite.so"
@@ -489,6 +491,8 @@
         case oDisableCCID: opt.disable_ccid = 1; break;
         case oDisableOpenSC: break;
 
+        case oDisableKeypad: opt.disable_keypad = 1; break;
+
         case oAllowAdmin: opt.allow_admin = 1; break;
         case oDenyAdmin: opt.allow_admin = 0; break;
 

Modified: branches/GNUPG-1-9-BRANCH/scd/scdaemon.h
===================================================================
--- branches/GNUPG-1-9-BRANCH/scd/scdaemon.h	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/scd/scdaemon.h	2005-11-28 11:52:25 UTC (rev 3947)
@@ -39,21 +39,22 @@
 
 #define MAX_DIGEST_LEN 24 
 
-/* A large struct name "opt" to keep global flags */
+/* A large struct name "opt" to keep global flags. */
 struct {
-  unsigned int debug; /* debug flags (DBG_foo_VALUE) */
-  int verbose;      /* verbosity level */
-  int quiet;        /* be as quiet as possible */
-  int dry_run;      /* don't change any persistent data */
-  int batch;        /* batch mode */
-  const char *homedir; /* configuration directory name */
+  unsigned int debug; /* Debug flags (DBG_foo_VALUE). */
+  int verbose;        /* Verbosity level. */
+  int quiet;          /* Be as quiet as possible. */
+  int dry_run;        /* Don't change any persistent data. */
+  int batch;          /* Batch mode. */
+  const char *homedir;      /* Configuration directory name. */
   const char *ctapi_driver; /* Library to access the ctAPI. */
   const char *pcsc_driver;  /* Library to access the PC/SC system. */
   const char *reader_port;  /* NULL or reder port to use. */
   int disable_ccid;    /* Disable the use of the internal CCID driver. */
+  int disable_keypad;  /* Do not use a keypad. */
   int allow_admin;     /* Allow the use of admin commands for certain
                           cards. */
-  strlist_t disabled_applications;  /* card applications we do not
+  strlist_t disabled_applications;  /* Card applications we do not
                                        want to use. */
 } opt;
 

Modified: branches/GNUPG-1-9-BRANCH/tools/ChangeLog
===================================================================
--- branches/GNUPG-1-9-BRANCH/tools/ChangeLog	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/tools/ChangeLog	2005-11-28 11:52:25 UTC (rev 3947)
@@ -1,3 +1,11 @@
+2005-10-19  Werner Koch  <wk at g10code.com>
+
+	* gpgconf-comp.c (gc_options_scdaemon): New option --disable-keypad.
+
+2005-09-22  Werner Koch  <wk at g10code.com>
+
+	* rfc822parse.c (parse_field): Tread Content-Disposition special.
+
 2005-10-08  Marcus Brinkmann  <marcus at g10code.de>
 
 	* Makefile.am (watchgnupg_LDADD): New variable.

Modified: branches/GNUPG-1-9-BRANCH/tools/gpgconf-comp.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/tools/gpgconf-comp.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/tools/gpgconf-comp.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -528,8 +528,10 @@
    { "disable-ccid", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
      "gnupg", "do not use the internal CCID driver",
      GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
+   { "disable-keypad", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
+     "gnupg", "do not use a reader's keypad",
+     GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
 
-
    { "Debug",
      GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
      "gnupg", N_("Options useful for debugging") },
@@ -2447,7 +2449,8 @@
 		{
 #ifdef HAVE_W32_SYSTEM
                   /* FIXME: Won't work becuase W32 doesn't silently
-                     overwrite. */
+                     overwrite. Fix it by creating a backup copy and
+                     deliting the orginal file first. */
                   err = rename (src_pathname[i], dest_pathname[i]);
 #else /*!HAVE_W32_SYSTEM*/
 		  /* This is a bit safer than rename() because we

Modified: branches/GNUPG-1-9-BRANCH/tools/rfc822parse.c
===================================================================
--- branches/GNUPG-1-9-BRANCH/tools/rfc822parse.c	2005-11-23 12:38:38 UTC (rev 3946)
+++ branches/GNUPG-1-9-BRANCH/tools/rfc822parse.c	2005-11-28 11:52:25 UTC (rev 3947)
@@ -766,6 +766,7 @@
   } tspecial_header[] = {
     { "Content-Type", 12},
     { "Content-Transfer-Encoding", 25},
+    { "Content-Disposition", 19},
     { NULL, 0}
   };
   const char *delimiters;




More information about the Gnupg-commits mailing list