[git] GnuPG - branch, master, updated. gnupg-2.2.7-322-gfa9d703

by Werner Koch cvs at cvs.gnupg.org
Mon Jan 21 15:04:21 CET 2019


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  fa9d703de5c70ae925e8ca6604073506f24d641a (commit)
       via  29929e65521279eabc98a67c766fe485057405a9 (commit)
      from  ec56996029d95d4bd26e1badfe207232270c6247 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit fa9d703de5c70ae925e8ca6604073506f24d641a
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Jan 21 15:01:45 2019 +0100

    scd: Support CHV-STATUS and CHECKPIN for PIV.
    
    * scd/app-piv.c (parse_pin_keyref): New.
    (get_chv_status): New.
    (do_getattr): Add name CHV-STATUS.
    (verify_pin): Add arg keyref to support other PINs.
    (do_change_pin): New.  Right now limited to --clear.
    (do_check_pin): New.
    (app_select_piv): Register new commands.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/scd/app-piv.c b/scd/app-piv.c
index 9b40477..011b552 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -364,6 +364,25 @@ dump_all_do (int slot)
 }
 
 
+/* Parse the key reference KEYREFSTR which is expected to hold a key
+ * reference for a PIN object.  Return the one octet keyref or -1 for
+ * an invalid reference.  */
+static int
+parse_pin_keyref (const char *keyrefstr)
+{
+  if (!keyrefstr)
+    return -1;
+  else if (!ascii_strcasecmp (keyrefstr, "PIV.00"))
+    return 0x00;
+  else if (!ascii_strcasecmp (keyrefstr, "PIV.80"))
+    return 0x80;
+  else if (!ascii_strcasecmp (keyrefstr, "PIV.81"))
+    return 0x81;
+  else
+    return -1;
+}
+
+
 /* Return an allocated string with the serial number in a format to be
  * show to the user.  With FAILMODE is true return NULL if such an
  * abbreviated S/N is not available, else return the full serial
@@ -396,6 +415,47 @@ get_dispserialno (app_t app, int failmode)
 }
 
 
+/* The verify command can be used to retrieve the security status of
+ * the card.  Given the PIN name (e.g. "PIV.80" for thge application
+ * pin, a status is returned:
+ *
+ *        -1 = Error retrieving the data,
+ *        -2 = No such PIN,
+ *        -3 = PIN blocked,
+ *        -5 = Verify still valid,
+ *    n >= 0 = Number of verification attempts left.
+ */
+static int
+get_chv_status (app_t app, const char *keyrefstr)
+{
+  unsigned char apdu[4];
+  unsigned int sw;
+  int result;
+  int keyref;
+
+  keyref = parse_pin_keyref (keyrefstr);
+  if (!keyrefstr)
+    return -1;
+
+  apdu[0] = 0x00;
+  apdu[1] = ISO7816_VERIFY;
+  apdu[2] = 0x00;
+  apdu[3] = keyref;
+  if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
+    result = -5; /* No need to verification.  */
+  else if (sw == 0x6a88)
+    result = -2; /* No such PIN.  */
+  else if (sw == 0x6983)
+    result = -3; /* PIN is blocked.  */
+  else if ((sw & 0xfff0) == 0x63C0)
+    result = (sw & 0x000f);
+  else
+    result = -1; /* Error.  */
+
+  return result;
+}
+
+
 /* Implementation of the GETATTR command.  This is similar to the
  * LEARN command but returns only one value via status lines.  */
 static gpg_error_t
@@ -408,7 +468,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
   } table[] = {
     { "SERIALNO",     0x0000, -1 },
     { "$AUTHKEYID",   0x0000, -2 }, /* Default key for ssh.  */
-    { "$DISPSERIALNO",0x0000, -3 }
+    { "$DISPSERIALNO",0x0000, -3 },
+    { "CHV-STATUS",   0x0000, -4 }
   };
   gpg_error_t err = 0;
   int idx;
@@ -450,6 +511,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
       else
         err = gpg_error (GPG_ERR_INV_NAME);  /* No Abbreviated S/N.  */
     }
+  else if (table[idx].special == -4) /* CHV-STATUS */
+    {
+      int tmp[3];
+
+      tmp[0] = get_chv_status (app, "PIV.00");
+      tmp[1] = get_chv_status (app, "PIV.80");
+      tmp[2] = get_chv_status (app, "PIV.81");
+      err = send_status_printf (ctrl, table[idx].name, "%d %d %d",
+                                tmp[0], tmp[1], tmp[2]);
+    }
   else
     {
       relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
@@ -849,27 +920,28 @@ make_prompt (app_t app, int remaining, const char *firstline)
 }
 
 
-
-/* Verify the Application PIN for use with data object DOBJ.  */
+/* Verify the Application PIN KEYREF.  */
 static gpg_error_t
-verify_pin (app_t app, data_object_t dobj,
+verify_pin (app_t app, int keyref,
             gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
 {
   gpg_error_t err;
   unsigned char apdu[4];
   unsigned int sw;
   int remaining;
+  const char *label;
   char *prompt;
   char *pinvalue = NULL;
   unsigned int pinlen;
   char pinbuffer[8];
+  int minlen, maxlen, padding, onlydigits;
 
   /* First check whether a verify is at all needed.  This is done with
    * P1 being 0 and no Lc and command data send.  */
   apdu[0] = 0x00;
   apdu[1] = ISO7816_VERIFY;
   apdu[2] = 0x00;
-  apdu[3] = 0x80;
+  apdu[3] = keyref;
   if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
     {
       /* No need to verification.  */
@@ -881,11 +953,46 @@ verify_pin (app_t app, data_object_t dobj,
     remaining = -1;
 
   if (remaining != -1)
-    log_debug ("piv: PIN for %s has %d attempts left\n",
-               dobj->keyref, remaining);
+    log_debug ("piv: PIN %2X has %d attempts left\n", keyref, remaining);
+
+  switch (keyref)
+    {
+    case 0x00:
+      minlen = 6;
+      maxlen = 8;
+      padding = 1;
+      onlydigits = 1;
+      label = _("||Please enter the Global-PIN of your PIV card");
+      break;
+    case 0x80:
+      minlen = 6;
+      maxlen = 8;
+      padding = 1;
+      onlydigits = 1;
+      label = _("||Please enter the PIN of your PIV card");
+      break;
+    case 0x81:
+      minlen = 8;
+      maxlen = 8;
+      padding = 0;
+      onlydigits = 0;
+      label = _("||Please enter the Unblocking Key of your PIV card");
+      break;
+
+    case 0x96:
+    case 0x97:
+    case 0x98:
+    case 0x9B:
+      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+    default:
+      return gpg_error (GPG_ERR_INV_ID);
+    }
+  log_assert (sizeof pinbuffer >= maxlen);
+
 
   /* Ask for the PIN.  */
-  prompt = make_prompt (app, remaining, _("||Please enter your PIV PIN"));
+  prompt = make_prompt (app, remaining, label);
   err = pincb (pincb_arg, prompt, &pinvalue);
   xfree (prompt);
   prompt = NULL;
@@ -896,24 +1003,22 @@ verify_pin (app_t app, data_object_t dobj,
     }
 
   pinlen = pinvalue? strlen (pinvalue) : 0;
-  if (pinlen < 6)
+  if (pinlen < minlen)
     {
-      log_error (_("PIN for is too short;"
-                   " minimum length is %d\n"), 6);
+      log_error (_("PIN for is too short; minimum length is %d\n"), minlen);
       if (pinvalue)
         wipememory (pinvalue, pinlen);
       xfree (pinvalue);
       return gpg_error (GPG_ERR_BAD_PIN);
     }
-  if (pinlen > sizeof pinbuffer)
+  if (pinlen > maxlen)
     {
-      log_error (_("PIN for is too long;"
-                   " maximum length is %d\n"), (int)sizeof pinbuffer);
+      log_error (_("PIN for is too long; maximum length is %d\n"), maxlen);
       wipememory (pinvalue, pinlen);
       xfree (pinvalue);
       return gpg_error (GPG_ERR_BAD_PIN);
     }
-  if (strspn (pinvalue, "0123456789") != pinlen)
+  if (onlydigits && strspn (pinvalue, "0123456789") != pinlen)
     {
       log_error (_("PIN has invalid characters; only digits are allowed\n"));
       wipememory (pinvalue, pinlen);
@@ -921,20 +1026,102 @@ verify_pin (app_t app, data_object_t dobj,
       return gpg_error (GPG_ERR_BAD_PIN);
     }
   memcpy (pinbuffer, pinvalue, pinlen);
-  memset (pinbuffer + pinlen, 0xff, sizeof(pinbuffer) - pinlen);
-  wipememory (pinvalue, pinlen);
+  if (padding)
+    {
+      memset (pinbuffer + pinlen, 0xff, maxlen - pinlen);
+      wipememory (pinvalue, pinlen);
+      pinlen = maxlen;
+    }
+  else
+    wipememory (pinvalue, pinlen);
   xfree (pinvalue);
 
-  err = iso7816_verify (app->slot, 0x80,
-                        pinbuffer, sizeof pinbuffer);
-  wipememory (pinbuffer, sizeof pinbuffer);
+  err = iso7816_verify (app->slot, keyref, pinbuffer, pinlen);
+  wipememory (pinbuffer, pinlen);
   if (err)
-    log_error ("PIN verification failed: %s\n", gpg_strerror (err));
+    log_error ("PIN %02X verification failed: %s\n", keyref,gpg_strerror (err));
 
   return err;
 }
 
 
+/* Handle the PASSWD command.  Valid values for PWIDSTR are
+ * key references related to PINs; in particular:
+ *   PIV.00 - The Global PIN
+ *   PIV.80 - The Application PIN
+ *   PIV.81 - The PIN Unblocking key
+ * The supported flags are:
+ *   APP_CHANGE_FLAG_CLEAR   Clear the PIN verification state.
+ */
+static gpg_error_t
+do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
+               unsigned int flags,
+               gpg_error_t (*pincb)(void*, const char *, char **),
+               void *pincb_arg)
+{
+  gpg_error_t err;
+  int keyref;
+  unsigned char apdu[4];
+
+  char *newpin = NULL;
+  char *oldpin = NULL;
+  size_t newpinlen;
+  size_t oldpinlen;
+  const char *newdesc;
+  int pwid;
+  pininfo_t pininfo;
+
+  (void)ctrl;
+
+  /* The minimum and maximum lengths are enforced by PIV.  */
+  memset (&pininfo, 0, sizeof pininfo);
+  pininfo.minlen = 6;
+  pininfo.maxlen = 8;
+
+  keyref = parse_pin_keyref (pwidstr);
+  if (keyref == -1)
+    return gpg_error (GPG_ERR_INV_ID);
+
+  if ((flags & ~APP_CHANGE_FLAG_CLEAR))
+    return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
+  /* First see whether the special --clear mode has been requested.  */
+  if ((flags & APP_CHANGE_FLAG_CLEAR))
+    {
+      apdu[0] = 0x00;
+      apdu[1] = ISO7816_VERIFY;
+      apdu[2] = 0xff;
+      apdu[3] = keyref;
+      err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL);
+      goto leave;
+    }
+
+  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
+ leave:
+  xfree (oldpin);
+  xfree (newpin);
+  return err;
+}
+
+
+/* Perform a simple verify operation for the PIN specified by PWIDSTR.
+ * For valid values see do_change_pin.  */
+static gpg_error_t
+do_check_pin (app_t app, const char *pwidstr,
+              gpg_error_t (*pincb)(void*, const char *, char **),
+              void *pincb_arg)
+{
+  int keyref;
+
+  keyref = parse_pin_keyref (pwidstr);
+  if (keyref == -1)
+    return gpg_error (GPG_ERR_INV_ID);
+
+  return verify_pin (app, keyref, pincb, pincb_arg);
+}
+
+
 /* Compute a digital signature using the GENERAL AUTHENTICATE command
  * on INDATA which is expected to be the raw message digest.  The
  * KEYIDSTR has the key reference or its OID (e.g. "PIV.9A").  The
@@ -1045,8 +1232,8 @@ do_auth (app_t app, const char *keyidstr,
       goto leave;
     }
 
-  /* Now verify the PIN.  */
-  err = verify_pin (app, dobj, pincb, pincb_arg);
+  /* Now verify the Application PIN.  */
+  err = verify_pin (app, 0x80, pincb, pincb_arg);
   if (err)
     return err;
 
@@ -1226,8 +1413,8 @@ app_select_piv (app_t app)
   /* app->fnc.sign = do_sign; */
   app->fnc.auth = do_auth;
   /* app->fnc.decipher = do_decipher; */
-  /* app->fnc.change_pin = do_change_pin; */
-  /* app->fnc.check_pin = do_check_pin; */
+  app->fnc.change_pin = do_change_pin;
+  app->fnc.check_pin = do_check_pin;
 
 
 leave:

commit 29929e65521279eabc98a67c766fe485057405a9
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Jan 21 14:06:51 2019 +0100

    scd: Add option --clear to PASSWD.
    
    * scd/command.c (cmd_passwd): Add option --clear.
    (send_status_printf): New.
    * scd/app-common.h (APP_CHANGE_FLAG_CLEAR): New.
    * scd/app-nks.c (do_change_pin): Return an error if that option is
    used.
    * scd/app-openpgp.c (do_change_pin): Ditto.
    --
    
    Card application may support this option to clear the PIN verification
    status of a specific PIN.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/po/Makevars b/po/Makevars
index 90b0c5b..20d6ae9 100644
--- a/po/Makevars
+++ b/po/Makevars
@@ -63,6 +63,7 @@ XGETTEXT_OPTIONS = \
 	--flag=write_status_printf:2:c-format    \
 	--flag=kbxd_print_status:3:c-format      \
 	--flag=gpgconf_write_status:2:c-format   \
+        --flag=send_status_printf:3:c-format     \
 	--flag=wks_write_status:2:c-format
 
 
diff --git a/scd/app-common.h b/scd/app-common.h
index ff58318..b1661b5 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -26,8 +26,9 @@
 #include <ksba.h>
 
 
-#define APP_CHANGE_FLAG_RESET    1
-#define APP_CHANGE_FLAG_NULLPIN  2
+#define APP_CHANGE_FLAG_RESET    1  /* PIN Reset mode.  */
+#define APP_CHANGE_FLAG_NULLPIN  2  /* NULL PIN mode.  */
+#define APP_CHANGE_FLAG_CLEAR    4  /* Clear the given PIN.  */
 
 /* Bit flags set by the decipher function into R_INFO.  */
 #define APP_DECIPHER_INFO_NOPAD  1  /* Padding has been removed.  */
diff --git a/scd/app-nks.c b/scd/app-nks.c
index 801ab90..0f38e7c 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -1169,6 +1169,9 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *pwidstr,
   if (!newdesc)
     return gpg_error (GPG_ERR_INV_ID);
 
+  if ((flags & APP_CHANGE_FLAG_CLEAR))
+    return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
   err = switch_application (app, is_sigg);
   if (err)
     return err;
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index f25a360..fddc3b8 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -2602,10 +2602,14 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
   int pinlen = 0;
 
   (void)ctrl;
+
   memset (&pininfo, 0, sizeof pininfo);
   pininfo.fixedlen = -1;
   pininfo.minlen = minlen;
 
+  if ((flags & APP_CHANGE_FLAG_CLEAR))
+    return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
   if (reset_mode && chvno == 3)
     {
       rc = gpg_error (GPG_ERR_INV_ID);
diff --git a/scd/app.c b/scd/app.c
index 800c954..8e09555 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -997,7 +997,7 @@ app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
 }
 
 
-/* Perform a VERIFY operation without doing anything lese.  This may
+/* Perform a VERIFY operation without doing anything else.  This may
    be used to initialize a the PIN cache for long lasting other
    operations.  Its use is highly application dependent. */
 gpg_error_t
diff --git a/scd/command.c b/scd/command.c
index ea4ccbc..044831f 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -1215,12 +1215,13 @@ cmd_random (assuan_context_t ctx, char *line)
 
 

 static const char hlp_passwd[] =
-  "PASSWD [--reset] [--nullpin] <chvno>\n"
+  "PASSWD [--reset] [--nullpin] [--clear] <chvno>\n"
   "\n"
   "Change the PIN or, if --reset is given, reset the retry counter of\n"
   "the card holder verification vector CHVNO.  The option --nullpin is\n"
-  "used for TCOS cards to set the initial PIN.  The format of CHVNO\n"
-  "depends on the card application.";
+  "used for TCOS cards to set the initial PIN.  The option --clear clears\n"
+  "the security status associated with the PIN so that the PIN needs to\n"
+  "be presented again. The format of CHVNO depends on the card application.";
 static gpg_error_t
 cmd_passwd (assuan_context_t ctx, char *line)
 {
@@ -1233,6 +1234,8 @@ cmd_passwd (assuan_context_t ctx, char *line)
     flags |= APP_CHANGE_FLAG_RESET;
   if (has_option (line, "--nullpin"))
     flags |= APP_CHANGE_FLAG_NULLPIN;
+  if (has_option (line, "--clear"))
+    flags |= APP_CHANGE_FLAG_CLEAR;
 
   line = skip_options (line);
 
@@ -1243,6 +1246,11 @@ cmd_passwd (assuan_context_t ctx, char *line)
     line++;
   *line = 0;
 
+  /* Do not allow other flags aside of --clear. */
+  if ((flags & APP_CHANGE_FLAG_CLEAR) && (flags & ~APP_CHANGE_FLAG_CLEAR))
+    return set_error (GPG_ERR_UNSUPPORTED_OPERATION,
+                      "--clear used with other options");
+
   if ((rc = open_card (ctrl)))
     return rc;
 
@@ -1922,6 +1930,26 @@ send_status_direct (ctrl_t ctrl, const char *keyword, const char *args)
 }
 
 
+/* This status functions expects a printf style format string.  No
+ * filtering of the data is done instead the orintf formatted data is
+ * send using assuan_send_status. */
+gpg_error_t
+send_status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...)
+{
+  gpg_error_t err;
+  va_list arg_ptr;
+  assuan_context_t ctx;
+
+  if (!ctrl || !ctrl->server_local || !(ctx = ctrl->server_local->assuan_ctx))
+    return 0;
+
+  va_start (arg_ptr, format);
+  err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
+  va_end (arg_ptr);
+  return err;
+}
+
+
 void
 popup_prompt (void *opaque, int on)
 {
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index 238e6a8..73589ad 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -123,6 +123,9 @@ int  scd_command_handler (ctrl_t, int);
 void send_status_info (ctrl_t ctrl, const char *keyword, ...)
      GPGRT_ATTR_SENTINEL(1);
 void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
+gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword,
+                                const char *format, ...) GPGRT_ATTR_PRINTF(3,4);
+
 void popup_prompt (void *opaque, int on);
 void send_client_notifications (app_t app, int removal);
 void scd_kick_the_loop (void);

-----------------------------------------------------------------------

Summary of changes:
 po/Makevars       |   1 +
 scd/app-common.h  |   5 +-
 scd/app-nks.c     |   3 +
 scd/app-openpgp.c |   4 +
 scd/app-piv.c     | 237 ++++++++++++++++++++++++++++++++++++++++++++++++------
 scd/app.c         |   2 +-
 scd/command.c     |  34 +++++++-
 scd/scdaemon.h    |   3 +
 8 files changed, 258 insertions(+), 31 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list