* agent.h: Add a callback function to the pin_entry_info structure.
authorWerner Koch <wk@gnupg.org>
Mon, 17 Jun 2002 10:11:34 +0000 (10:11 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 17 Jun 2002 10:11:34 +0000 (10:11 +0000)
* query.c (agent_askpin): Use the callback to check for a correct
PIN.  Removed the start_err_text argument becuase it is not
anymore needed; changed callers.
* findkey.c (unprotect): Replace our own check loop by a callback.
(try_unprotect_cb): New.
* genkey.c (reenter_compare_cb): New.
(agent_genkey): Use this callback here.  Fixed setting of the pi2
variable and a segv in case of an empty PIN.

* divert-scd.c (getpin_cb): Removed some unused stuff and
explained what we still have to change.

agent/ChangeLog
agent/agent.h
agent/divert-scd.c
agent/findkey.c
agent/genkey.c
agent/query.c

index 2355e49..7ab1ac6 100644 (file)
@@ -1,3 +1,18 @@
+2002-06-17  Werner Koch  <wk@gnupg.org>
+
+       * agent.h: Add a callback function to the pin_entry_info structure.
+       * query.c (agent_askpin): Use the callback to check for a correct
+       PIN.  Removed the start_err_text argument becuase it is not
+       anymore needed; changed callers.
+       * findkey.c (unprotect): Replace our own check loop by a callback.
+       (try_unprotect_cb): New.
+       * genkey.c (reenter_compare_cb): New.
+       (agent_genkey): Use this callback here.  Fixed setting of the pi2
+       variable and a segv in case of an empty PIN.
+
+       * divert-scd.c (getpin_cb): Removed some unused stuff and
+       explained what we still have to change.
+
 2002-06-12  Werner Koch  <wk@gnupg.org>
 
        * gpg-agent.c (main): New option --disable-pth.
index 44b3832..75683a0 100644 (file)
@@ -85,6 +85,9 @@ struct pin_entry_info_s {
   int max_digits; /* max. number of allowed digits allowed*/
   int max_tries;
   int failed_tries;
+  int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
+  void *check_cb_arg;  /* optional argument which might be of use in the CB */
+  const char *cb_errtext; /* used by the cb to displaye a specific error */
   size_t max_length; /* allocated length of the buffer */
   char pin[1];
 };
@@ -114,8 +117,7 @@ GCRY_SEXP agent_key_from_file (const unsigned char *grip,
 int agent_key_available (const unsigned char *grip);
 
 /*-- query.c --*/
-int agent_askpin (const char *desc_text, const char *err_text,
-                  struct pin_entry_info_s *pininfo);
+int agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo);
 int agent_get_passphrase (char **retpass,
                           const char *desc, const char *prompt,
                           const char *errtext);
index ba0fa6e..f2a26ac 100644 (file)
@@ -166,7 +166,7 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
 /* Callback used to ask for the PIN which should be set into BUF.  The
    buf has been allocated by the caller and is of size MAXBUF which
    includes the terminating null.  The function should return an UTF-8
-   string with the passphrase, the buffer may optioanlly be padded
+   string with the passphrase, the buffer may optionally be padded
    with arbitrary characters */
 static int 
 getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
@@ -174,35 +174,27 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
   struct pin_entry_info_s *pi;
   int rc;
   int tries = 0;
-  const char *errtext;
-  
+
   assert (!opaque);
 
   if (maxbuf < 2)
     return GNUPG_Invalid_Value;
 
-  /* FIXME: keep PI and TRIES in OPAQUE */
+  /* FIXME: keep PI and TRIES in OPAQUE.  Actually this is a whole
+     mess becuase we should call the card's verify function from the
+     pinentry check pin CB. */
   pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
   pi->max_length = maxbuf-1;
   pi->min_digits = 0;  /* we want a real passphrase */
   pi->max_digits = 8;
   pi->max_tries = 3;
 
-  errtext = NULL;
-  do
+  rc = agent_askpin (info, pi);
+  if (!rc)
     {
-      rc = agent_askpin (info, errtext, pi);
-      if (!rc)
-        {
-          strncpy (buf, pi->pin, maxbuf-1);
-          buf[maxbuf-1] = 0;
-          xfree (pi);
-          return 0;
-        }
-      errtext = pi->min_digits? trans ("Bad PIN") : trans ("Bad Passphrase");
+      strncpy (buf, pi->pin, maxbuf-1);
+      buf[maxbuf-1] = 0;
     }
-  while ((rc == GNUPG_Bad_Passphrase || rc == GNUPG_Bad_PIN)
-         && tries++ < 3);
   xfree (pi);
   return rc;
 }
index 1a222ba..3a9dd53 100644 (file)
 #include <assert.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <assert.h>
 
 #include "agent.h"
 
+/* Helper to pass data to the check callback of the unprotect function. */
+struct try_unprotect_arg_s {
+  const unsigned char *protected_key;
+  unsigned char *unprotected_key;
+};
+
+
 
 int
 agent_write_private_key (const unsigned char *grip,
@@ -88,16 +96,32 @@ agent_write_private_key (const unsigned char *grip,
 }
 
 
+/* Callback function to try the unprotection from the passpharse query
+   code. */
+static int
+try_unprotect_cb (struct pin_entry_info_s *pi)
+{
+  struct try_unprotect_arg_s *arg = pi->check_cb_arg;
+  size_t dummy;
+
+  assert (!arg->unprotected_key);
+  return agent_unprotect (arg->protected_key, pi->pin,
+                          &arg->unprotected_key, &dummy);
+}
+
+
+/* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
+   should be the hex encoded keygrip of that key to be used with the
+   cahing mechanism. */
 static int
 unprotect (unsigned char **keybuf, const unsigned char *grip)
 {
   struct pin_entry_info_s *pi;
+  struct try_unprotect_arg_s arg;
   int rc, i;
   unsigned char *result;
   size_t resultlen;
-  int tries = 0;
   char hexgrip[40+1];
-  const char *errtext;
   
   for (i=0; i < 20; i++)
     sprintf (hexgrip+2*i, "%02X", grip[i]);
@@ -127,27 +151,19 @@ unprotect (unsigned char **keybuf, const unsigned char *grip)
   pi->min_digits = 0;  /* we want a real passphrase */
   pi->max_digits = 8;
   pi->max_tries = 3;
+  pi->check_cb = try_unprotect_cb;
+  arg.protected_key = *keybuf;
+  arg.unprotected_key = NULL;
+  pi->check_cb_arg = &arg;
 
-  errtext = NULL;
-  do
+  rc = agent_askpin (NULL, pi);
+  if (!rc)
     {
-      rc = agent_askpin (NULL, errtext, pi);
-      if (!rc)
-        {
-          rc = agent_unprotect (*keybuf, pi->pin, &result, &resultlen);
-          if (!rc)
-            {
-              agent_put_cache (hexgrip, pi->pin, 0);
-              xfree (*keybuf);
-              *keybuf = result;
-              xfree (pi);
-              return 0;
-            }
-        }
-      errtext = pi->min_digits? trans ("Bad PIN") : trans ("Bad Passphrase");
+      assert (arg.unprotected_key);
+      agent_put_cache (hexgrip, pi->pin, 0);
+      xfree (*keybuf);
+      *keybuf = arg.unprotected_key;
     }
-  while ((rc == GNUPG_Bad_Passphrase || rc == GNUPG_Bad_PIN)
-         && tries++ < 3);
   xfree (pi);
   return rc;
 }
index ae46c46..630e0e3 100644 (file)
@@ -70,6 +70,19 @@ store_key (GCRY_SEXP private, const char *passphrase)
   return rc;
 }
 
+/* Callback function to compare the first entered PIN with the one
+   currently beeing entered. */
+static int
+reenter_compare_cb (struct pin_entry_info_s *pi)
+{
+  const char *pin1 = pi->check_cb_arg;
+
+  if (!strcmp (pin1, pi->pin))
+    return 0; /* okay */
+  pi->cb_errtext = trans ("does not match - try again");
+  return -1;
+}
+
 
 
 /* Generate a new keypair according to the parameters given in
@@ -91,39 +104,30 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
       return seterr (Invalid_Data);
     }
 
-  /* Get the passphrase now, cause key generation may take a while */
+  /* Get the passphrase now, cause key generation may take a while. */
   {
     const char *text1 = trans ("Please enter the passphrase to%0A"
                                "to protect your new key");
     const char *text2 = trans ("Please re-enter this passphrase");
-    const char *nomatch = trans ("does not match - try again");
-    int tries = 0;
 
     pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
-    pi2 = pi + sizeof *pi;
+    pi2 = pi + (sizeof *pi + 100);
     pi->max_length = 100;
     pi->max_tries = 3;
     pi2->max_length = 100;
     pi2->max_tries = 3;
+    pi2->check_cb = reenter_compare_cb;
+    pi2->check_cb_arg = pi->pin;
 
-    rc = agent_askpin (text1, NULL, pi);
+    rc = agent_askpin (text1, pi);
     if (!rc)
-      {
-        do 
-          {
-            rc = agent_askpin (text2, tries? nomatch:NULL, pi2);
-            tries++;
-          }
-        while (!rc && tries < 3 && strcmp (pi->pin, pi2->pin));
-        if (!rc && strcmp (pi->pin, pi2->pin))
-          rc = GNUPG_Canceled;
-      }
+      rc = agent_askpin (text2, pi2);
     if (rc)
       return rc;
     if (!*pi->pin)
       {
         xfree (pi);
-        pi = NULL; /* use does not want a passphrase */
+        pi = NULL; /* User does not want a passphrase. */
       }
   }
 
@@ -158,7 +162,7 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
   
   /* store the secret key */
   log_debug ("storing private key\n");
-  rc = store_key (s_private, pi->pin);
+  rc = store_key (s_private, pi? pi->pin:NULL);
   xfree (pi); pi = NULL;
   gcry_sexp_release (s_private);
   if (rc)
index af513b8..724bbd5 100644 (file)
@@ -218,13 +218,12 @@ all_digitsp( const char *s)
    number here and repeat it as long as we have invalid formed
    numbers. */
 int
-agent_askpin (const char *desc_text, const char *start_err_text,
-              struct pin_entry_info_s *pininfo)
+agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
   struct entry_parm_s parm;
-  const char *errtext = start_err_text;
+  const char *errtext = NULL;
 
   if (opt.batch)
     return 0; /* fixme: we should return BAD PIN */
@@ -261,14 +260,8 @@ agent_askpin (const char *desc_text, const char *start_err_text,
       if (errtext)
         { 
           /* fixme: should we show the try count? It must be translated */
-          if (start_err_text)
-            {
-              snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
-              start_err_text = NULL;
-            }
-          else
-            snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
-                      errtext, pininfo->failed_tries+1, pininfo->max_tries);
+          snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
+                    errtext, pininfo->failed_tries+1, pininfo->max_tries);
           line[DIM(line)-1] = 0;
           rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
           if (rc)
@@ -276,25 +269,42 @@ agent_askpin (const char *desc_text, const char *start_err_text,
           errtext = NULL;
         }
       
-      rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
+      rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
+                            NULL, NULL, NULL, NULL);
       if (rc == ASSUAN_Too_Much_Data)
         errtext = pininfo->min_digits? trans ("PIN too long")
                                      : trans ("Passphrase too long");
       else if (rc)
         return unlock_pinentry (map_assuan_err (rc));
-      if (!errtext && !pininfo->min_digits)
-        return unlock_pinentry (0); /* okay, got a passphrase */
-      if (!errtext && !all_digitsp (pininfo->pin))
-        errtext = trans ("Invalid characters in PIN");
-      if (!errtext && pininfo->max_digits
-          && strlen (pininfo->pin) > pininfo->max_digits)
-        errtext = trans ("PIN too long");
-      if (!errtext
-          && strlen (pininfo->pin) < pininfo->min_digits)
-        errtext = trans ("PIN too short");
+
+      if (!errtext && pininfo->min_digits)
+        {
+          /* do some basic checks on the entered PIN. */
+          if (!all_digitsp (pininfo->pin))
+            errtext = trans ("Invalid characters in PIN");
+          else if (pininfo->max_digits
+                   && strlen (pininfo->pin) > pininfo->max_digits)
+            errtext = trans ("PIN too long");
+          else if (strlen (pininfo->pin) < pininfo->min_digits)
+            errtext = trans ("PIN too short");
+        }
+
+      if (!errtext && pininfo->check_cb)
+        {
+          /* More checks by utilizing the optional callback. */
+          pininfo->cb_errtext = NULL;
+          rc = pininfo->check_cb (pininfo);
+          if (rc == -1 && pininfo->cb_errtext)
+            errtext = pininfo->cb_errtext;
+          else if (rc == GNUPG_Bad_Passphrase || rc == GNUPG_Bad_PIN)
+            errtext = (pininfo->min_digits? trans ("Bad PIN")
+                       : trans ("Bad Passphrase"));
+          else if (rc)
+            return unlock_pinentry (map_assuan_err (rc));
+        }
 
       if (!errtext)
-        return unlock_pinentry (0); /* okay, got a PIN */
+        return unlock_pinentry (0); /* okay, got a PIN or passphrase */
     }
 
   return unlock_pinentry (pininfo->min_digits? GNUPG_Bad_PIN