The keypad is now also used for OpenPGP signing keys.
authorWerner Koch <wk@gnupg.org>
Thu, 21 Dec 2006 12:13:44 +0000 (12:13 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 21 Dec 2006 12:13:44 +0000 (12:13 +0000)
scd/ChangeLog
scd/app-openpgp.c

index 49896af..6d71dc1 100644 (file)
@@ -1,3 +1,11 @@
+2006-12-21  Werner Koch  <wk@g10code.com>
+
+       * app-openpgp.c (verify_chv2): Factored most code out into...
+       (verify_a_chv): ... new.
+       (do_sign): Factored verification code out to new function and
+       take care of a keypad entered PIN.
+       (compare_fingerprint): Print an additional diagnostic.
+
 2006-11-28  Werner Koch  <wk@g10code.com>
 
        * apdu.c (send_le, apdu_send_direct): Increase RESULTLEN to 258 to
index 6c2eb82..a02ff03 100644 (file)
@@ -1277,94 +1277,164 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
 }
 
 
-
-/* Verify CHV2 if required.  Depending on the configuration of the
-   card CHV1 will also be verified. */
+/* Verify a CHV either using using the pinentry or if possibile by
+   using a keypad.  PINCB and PINCB_ARG describe the usual callback
+   for the pinentry.  CHVNO must be either 1 or 2. SIGCOUNT is only
+   ised with CHV1.  PINVALUE is the address of a pointer which will
+   receive a newly allocated block with the actual PIN (this is useful
+   in case that PIN shall be used for another verifiy operation).  The
+   caller needs to free this value.  If the function returns with
+   success and NULL is stored at PINVALUE, the caller should take this
+   as an indication that the keypad has been used.
+   */
 static gpg_error_t
-verify_chv2 (app_t app,
-             gpg_error_t (*pincb)(void*, const char *, char **),
-             void *pincb_arg)
+verify_a_chv (app_t app,
+              gpg_error_t (*pincb)(void*, const char *, char **),
+              void *pincb_arg,
+              int chvno, unsigned long sigcount, char **pinvalue)
 {
   int rc = 0;
+  char *prompt;
+  iso7816_pininfo_t pininfo;
+  int minlen = 6;
 
-  if (!app->did_chv2) 
-    {
-      char *pinvalue;
-      iso7816_pininfo_t pininfo;
-      int did_keypad = 0;
+  assert (chvno == 1 || chvno == 2);
 
-      memset (&pininfo, 0, sizeof pininfo);
-      pininfo.mode = 1;
-      pininfo.minlen = 6;
+  *pinvalue = NULL;
 
-      if (!opt.disable_keypad
-          && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
+  memset (&pininfo, 0, sizeof pininfo);
+  pininfo.mode = 1;
+  pininfo.minlen = minlen;
+  
+  if (!opt.disable_keypad
+      && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
+    {
+      /* The reader supports the verify command through the keypad. */
+
+      if (chvno == 1)
         {
-          /* The reader supports the verify command through the keypad. */
-          did_keypad = 1;
-          rc = pincb (pincb_arg,
-                      _("||Please enter your PIN at the reader's keypad"),
-                      NULL);
-          if (rc)
-            {
-              log_info (_("PIN callback returned error: %s\n"),
-                        gpg_strerror (rc));
-              return rc;
-            }
-          rc = iso7816_verify_kp (app->slot, 0x82, "", 0, &pininfo); 
-          /* Dismiss the prompt. */
-          pincb (pincb_arg, NULL, NULL);
+#define PROMPTSTRING  _("||Please enter your PIN at the reader's keypad%%0A" \
+                        "[sigs done: %lu]")
+          size_t promptsize = strlen (PROMPTSTRING) + 50;
+
+          prompt = xmalloc (promptsize);
+          if (!prompt)
+            return gpg_error_from_syserror ();
+          snprintf (prompt, promptsize-1, PROMPTSTRING, sigcount);
+          rc = pincb (pincb_arg, prompt, NULL); 
+          xfree (prompt);
+#undef PROMPTSTRING
         }
       else
+        rc = pincb (pincb_arg,
+                    _("||Please enter your PIN at the reader's keypad"),
+                    NULL);
+      if (rc)
         {
-          /* The reader has no keypad or we don't want to use it. */
-          rc = pincb (pincb_arg, "PIN", &pinvalue); 
-          if (rc)
-            {
-              log_info (_("PIN callback returned error: %s\n"),
-                        gpg_strerror (rc));
-              return rc;
-            }
-          
-          if (strlen (pinvalue) < 6)
-            {
-              log_error (_("PIN for CHV%d is too short;"
-                           " minimum length is %d\n"), 2, 6);
-              xfree (pinvalue);
-              return gpg_error (GPG_ERR_BAD_PIN);
-            }
+          log_info (_("PIN callback returned error: %s\n"),
+                    gpg_strerror (rc));
+          return rc;
+        }
+      rc = iso7816_verify_kp (app->slot, 0x80+chvno, "", 0, &pininfo); 
+      /* Dismiss the prompt. */
+      pincb (pincb_arg, NULL, NULL);
 
-          rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
+      assert (!*pinvalue);
+    }
+  else
+    {
+      /* The reader has no keypad or we don't want to use it. */
+
+      if (chvno == 1)
+        {
+#define PROMPTSTRING  _("||Please enter the PIN%%0A[sigs done: %lu]")
+          size_t promptsize = strlen (PROMPTSTRING) + 50;
+
+          prompt = xmalloc (promptsize);
+          if (!prompt)
+            return gpg_error_from_syserror ();
+          snprintf (prompt, promptsize-1, PROMPTSTRING, sigcount);
+          rc = pincb (pincb_arg, prompt, pinvalue); 
+          xfree (prompt);
+#undef PROMPTSTRING
         }
+      else
+        rc = pincb (pincb_arg, "PIN", pinvalue); 
 
       if (rc)
         {
-          log_error (_("verify CHV%d failed: %s\n"), 2, gpg_strerror (rc));
-          xfree (pinvalue);
-          flush_cache_after_error (app);
+          log_info (_("PIN callback returned error: %s\n"),
+                    gpg_strerror (rc));
           return rc;
         }
-      app->did_chv2 = 1;
+      
+      if (strlen (*pinvalue) < minlen)
+        {
+          log_error (_("PIN for CHV%d is too short;"
+                       " minimum length is %d\n"), chvno, minlen);
+          xfree (*pinvalue);
+          *pinvalue = NULL;
+          return gpg_error (GPG_ERR_BAD_PIN);
+        }
+
+      rc = iso7816_verify (app->slot, 0x80+chvno,
+                           *pinvalue, strlen (*pinvalue));
+    }
+  
+  if (rc)
+    {
+      log_error (_("verify CHV%d failed: %s\n"), chvno, gpg_strerror (rc));
+      xfree (*pinvalue);
+      *pinvalue = NULL;
+      flush_cache_after_error (app);
+    }
+
+  return rc;
+}
+
+
+/* Verify CHV2 if required.  Depending on the configuration of the
+   card CHV1 will also be verified. */
+static gpg_error_t
+verify_chv2 (app_t app,
+             gpg_error_t (*pincb)(void*, const char *, char **),
+             void *pincb_arg)
+{
+  int rc;
+  char *pinvalue;
 
-      if (!app->did_chv1 && !app->force_chv1 && !did_keypad)
+  if (app->did_chv2) 
+    return 0;  /* We already verified CHV2.  */
+
+  rc = verify_a_chv (app, pincb, pincb_arg, 2, 0, &pinvalue);
+  if (rc)
+    return rc;
+
+  app->did_chv2 = 1;
+  
+  if (!app->did_chv1 && !app->force_chv1 && pinvalue)
+    {
+      /* For convenience we verify CHV1 here too.  We do this only if
+         the card is not configured to require a verification before
+         each CHV1 controlled operation (force_chv1) and if we are not
+         using the keypad (PINVALUE == NULL). */
+      rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
+      if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
+        rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
+      if (rc)
         {
-          rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
-          if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
-            rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
-          if (rc)
-            {
-              log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc));
-              xfree (pinvalue);
-              flush_cache_after_error (app);
-              return rc;
-            }
-          app->did_chv1 = 1;
+          log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc));
+          flush_cache_after_error (app);
         }
-      xfree (pinvalue);
+      else
+        app->did_chv1 = 1;
     }
+  xfree (pinvalue);
+
   return rc;
 }
 
+
 /* Verify CHV3 if required. */
 static gpg_error_t
 verify_chv3 (app_t app,
@@ -2076,6 +2146,7 @@ compare_fingerprint (app_t app, int keyno, unsigned char *sha1fpr)
     if (sha1fpr[i] != fpr[i])
       {
         xfree (buffer);
+        log_info (_("fingerprint on card does not match requested one\n"));
         return gpg_error (GPG_ERR_WRONG_SECKEY);
       }
   xfree (buffer);
@@ -2230,44 +2301,16 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
     {
       char *pinvalue;
 
-      {
-        char *prompt;
-#define PROMPTSTRING  _("||Please enter the PIN%%0A[sigs done: %lu]")
-
-        prompt = malloc (strlen (PROMPTSTRING) + 50);
-        if (!prompt)
-          return gpg_error_from_syserror ();
-        sprintf (prompt, PROMPTSTRING, sigcount);
-        rc = pincb (pincb_arg, prompt, &pinvalue); 
-        free (prompt);
-#undef PROMPTSTRING
-      }
+      rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount, &pinvalue);
       if (rc)
-        {
-          log_info (_("PIN callback returned error: %s\n"), gpg_strerror (rc));
-          return rc;
-        }
-
-      if (strlen (pinvalue) < 6)
-        {
-          log_error (_("PIN for CHV%d is too short;"
-                       " minimum length is %d\n"), 1, 6);
-          xfree (pinvalue);
-          return gpg_error (GPG_ERR_BAD_PIN);
-        }
+        return rc;
 
-      rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
-      if (rc)
-        {
-          log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc));
-          xfree (pinvalue);
-          flush_cache_after_error (app);
-          return rc;
-        }
       app->did_chv1 = 1;
-      if (!app->did_chv2)
+
+      if (!app->did_chv2 && pinvalue)
         {
-          /* We should also verify CHV2. */
+          /* We should also verify CHV2.  Note, that we can't do that
+             if the keypad has been used. */
           rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
           if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
             rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);