[git] GnuPG - branch, master, updated. gnupg-2.2.7-353-ge9e876c

by Werner Koch cvs at cvs.gnupg.org
Wed Feb 6 09:47:12 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  e9e876cb5572670322aa1d3462d64c75c03974d9 (commit)
       via  3231ecdafd71ac47b734469b07170756979ede72 (commit)
      from  1c0fa3e6f74692d5e9b5f08cda523f0fcec305eb (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 e9e876cb5572670322aa1d3462d64c75c03974d9
Author: Werner Koch <wk at gnupg.org>
Date:   Wed Feb 6 09:45:54 2019 +0100

    scd: Implement PIN changing and unblocking for PIV cards.
    
    * scd/app-piv.c: Some refactoring
    (do_change_chv): Implement.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/scd/app-piv.c b/scd/app-piv.c
index d34ff7d..42f16de 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -20,6 +20,24 @@
 /* Some notes:
  * - Specs for PIV are at http://dx.doi.org/10.6028/NIST.SP.800-73-4
  *
+ * - Access control matrix:
+ *   | Action       | 9B  | PIN | PUK |                              |
+ *   |--------------+-----+-----+-----+------------------------------|
+ *   | Generate key | yes |     |     |                              |
+ *   | Change 9B    | yes |     |     |                              |
+ *   | Change retry | yes | yes |     | Yubikey only                 |
+ *   | Import key   | yes |     |     |                              |
+ *   | Import cert  | yes |     |     |                              |
+ *   | Change CHUID | yes |     |     |                              |
+ *   | Reset card   |     |     |     | PIN and PUK in blocked state |
+ *   | Verify PIN   |     | yes |     |                              |
+ *   | Sign data    |     | yes |     |                              |
+ *   | Decrypt data |     | yes |     |                              |
+ *   | Change PIN   |     | yes |     |                              |
+ *   | Change PUK   |     |     | yes |                              |
+ *   | Unblock PIN  |     |     | yes | New PIN required             |
+ *   |---------------------------------------------------------------|
+ *   (9B indicates the 24 byte PIV Card Application Administration Key)
  */
 
 #include <config.h>
@@ -389,10 +407,10 @@ 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
+ * reference for a CHV object.  Return the one octet keyref or -1 for
  * an invalid reference.  */
 static int
-parse_pin_keyref (const char *keyrefstr)
+parse_chv_keyref (const char *keyrefstr)
 {
   if (!keyrefstr)
     return -1;
@@ -457,7 +475,7 @@ get_chv_status (app_t app, const char *keyrefstr)
   int result;
   int keyref;
 
-  keyref = parse_pin_keyref (keyrefstr);
+  keyref = parse_chv_keyref (keyrefstr);
   if (!keyrefstr)
     return -1;
 
@@ -467,7 +485,7 @@ get_chv_status (app_t app, const char *keyrefstr)
   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)
+  else if (sw == 0x6a88 || sw == 0x6a80)
     result = -2; /* No such PIN.  */
   else if (sw == 0x6983)
     result = -3; /* PIN is blocked.  */
@@ -540,7 +558,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
     }
   else if (table[idx].special == -4) /* CHV-STATUS */
     {
-      int tmp[3];
+      int tmp[4];
 
       tmp[0] = get_chv_status (app, "PIV.00");
       tmp[1] = get_chv_status (app, "PIV.80");
@@ -1177,40 +1195,29 @@ make_prompt (app_t app, int remaining, const char *firstline)
 }
 
 
-/* Verify the Application PIN KEYREF.  */
+/* Helper for verify_chv to ask for the PIN and to prepare/pad it.  On
+ * success the result is stored at (R_PIN,R_PINLEN).  */
 static gpg_error_t
-verify_pin (app_t app, int keyref,
-            gpg_error_t (*pincb)(void*,const char *,char **), void *pincb_arg)
+ask_and_prepare_chv (app_t app, int keyref, int ask_new, int remaining,
+                     gpg_error_t (*pincb)(void*,const char *,char **),
+                     void *pincb_arg, char **r_pin, unsigned int *r_pinlen)
 {
   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];
+  char *pinbuffer = NULL;
   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] = keyref;
-  if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
-    {
-      /* No need to verification.  */
-      return 0;  /* All fine.  */
-    }
-  if ((sw & 0xfff0) == 0x63C0)
-    remaining = (sw & 0x000f); /* PIN has REMAINING tries left.  */
-  else
+  *r_pin = NULL;
+  *r_pinlen = 0;
+
+  if (ask_new)
     remaining = -1;
 
   if (remaining != -1)
-    log_debug ("piv: PIN %2X has %d attempts left\n", keyref, remaining);
+    log_debug ("piv: CHV %02X has %d attempts left\n", keyref, remaining);
 
   switch (keyref)
     {
@@ -1219,21 +1226,24 @@ verify_pin (app_t app, int keyref,
       maxlen = 8;
       padding = 1;
       onlydigits = 1;
-      label = _("||Please enter the Global-PIN of your PIV card");
+      label = (ask_new? _("|N|Please enter the new Global-PIN")
+               /**/   : _("||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");
+      label = (ask_new? _("|N|Please enter the new PIN")
+               /**/   : _("||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");
+      label = (ask_new? _("|N|Please enter the new Unblocking Key")
+               /**/   :_("||Please enter the Unblocking Key of your PIV card"));
       break;
 
     case 0x96:
@@ -1245,8 +1255,6 @@ verify_pin (app_t app, int keyref,
     default:
       return gpg_error (GPG_ERR_INV_ID);
     }
-  log_assert (sizeof pinbuffer >= maxlen);
-
 
   /* Ask for the PIN.  */
   prompt = make_prompt (app, remaining, label);
@@ -1282,21 +1290,72 @@ verify_pin (app_t app, int keyref,
       xfree (pinvalue);
       return gpg_error (GPG_ERR_BAD_PIN);
     }
+
+  pinbuffer = xtrymalloc_secure (maxlen);
+  if (!pinbuffer)
+    {
+      err = gpg_error_from_syserror ();
+      wipememory (pinvalue, pinlen);
+      xfree (pinvalue);
+      return err;
+    }
+
   memcpy (pinbuffer, pinvalue, pinlen);
+  wipememory (pinvalue, pinlen);
+  xfree (pinvalue);
   if (padding)
     {
       memset (pinbuffer + pinlen, 0xff, maxlen - pinlen);
-      wipememory (pinvalue, pinlen);
       pinlen = maxlen;
     }
+
+  *r_pin = pinbuffer;
+  *r_pinlen = pinlen;
+
+  return 0;
+}
+
+
+/* Verify the card holder verification identified by KEYREF.  This is
+ * either the Appication PIN or the Global PIN. */
+static gpg_error_t
+verify_chv (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;
+  char *pin = NULL;
+  unsigned int pinlen;
+
+  /* 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] = keyref;
+  if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
+    {
+      /* No need to verification.  */
+      return 0;  /* All fine.  */
+    }
+  if ((sw & 0xfff0) == 0x63C0)
+    remaining = (sw & 0x000f); /* PIN has REMAINING tries left.  */
   else
-    wipememory (pinvalue, pinlen);
-  xfree (pinvalue);
+    remaining = -1;
 
-  err = iso7816_verify (app->slot, keyref, pinbuffer, pinlen);
-  wipememory (pinbuffer, pinlen);
+  err = ask_and_prepare_chv (app, keyref, 0, remaining, pincb, pincb_arg,
+                             &pin, &pinlen);
   if (err)
-    log_error ("PIN %02X verification failed: %s\n", keyref,gpg_strerror (err));
+    return err;
+
+  err = iso7816_verify (app->slot, keyref, pin, pinlen);
+  wipememory (pin, pinlen);
+  xfree (pin);
+  if (err)
+    log_error ("CHV %02X verification failed: %s\n",
+               keyref, gpg_strerror (err));
 
   return err;
 }
@@ -1309,40 +1368,41 @@ verify_pin (app_t app, int keyref,
  *   PIV.81 - The PIN Unblocking key
  * The supported flags are:
  *   APP_CHANGE_FLAG_CLEAR   Clear the PIN verification state.
+ *   APP_CHANGE_FLAG_RESET   Reset a PIN using the PUK.  Only
+ *                           allowed with PIV.80.
  */
 static gpg_error_t
-do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
+do_change_chv (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;
+  int keyref, targetkeyref;
   unsigned char apdu[4];
-
-  char *newpin = NULL;
+  unsigned int sw;
+  int remaining;
   char *oldpin = NULL;
-  /* size_t newpinlen; */
-  /* size_t oldpinlen; */
-  /* const char *newdesc; */
-  /* int pwid; */
-  pininfo_t pininfo;
+  unsigned int oldpinlen;
+  char *newpin = NULL;
+  unsigned int newpinlen;
 
   (void)ctrl;
-  (void)pincb;
-  (void)pincb_arg;
 
-  /* The minimum and maximum lengths are enforced by PIV.  */
-  memset (&pininfo, 0, sizeof pininfo);
-  pininfo.minlen = 6;
-  pininfo.maxlen = 8;
+  /* Check for unknown flags.  */
+  if ((flags & ~(APP_CHANGE_FLAG_CLEAR|APP_CHANGE_FLAG_RESET)))
+    {
+      err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+      goto leave;
+    }
 
-  keyref = parse_pin_keyref (pwidstr);
+  /* Parse the keyref.  */
+  targetkeyref = keyref = parse_chv_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);
+    {
+      err = gpg_error (GPG_ERR_INV_ID);
+      goto leave;
+    }
 
   /* First see whether the special --clear mode has been requested.  */
   if ((flags & APP_CHANGE_FLAG_CLEAR))
@@ -1355,7 +1415,82 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
       goto leave;
     }
 
-  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  /* Prepare reset mode.  */
+  if ((flags & APP_CHANGE_FLAG_RESET))
+    {
+      if (keyref == 0x81)
+        {
+          err = gpg_error (GPG_ERR_INV_ID); /* Can't reset the PUK.  */
+          goto leave;
+        }
+      /* Set the keyref to the PUK and keep the TARGETKEYREF.  */
+      keyref = 0x81;
+    }
+
+  /* Get the remaining tries count.  This is done by using the check
+   * for verified state feature.  */
+  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))
+    remaining = -1; /* Already verified, thus full number of tries.  */
+  else if ((sw & 0xfff0) == 0x63C0)
+    remaining = (sw & 0x000f); /* PIN has REMAINING tries left.  */
+  else
+    remaining = -1;
+
+  /* Ask for the old pin or puk.  */
+  err = ask_and_prepare_chv (app, keyref, 0, remaining, pincb, pincb_arg,
+                             &oldpin, &oldpinlen);
+  if (err)
+    return err;
+
+  /* Verify the old pin so that we don't prompt for the new pin if the
+   * old is wrong.  This is not possible for the PUK, though. */
+  if (keyref != 0x81)
+    {
+      err = iso7816_verify (app->slot, keyref, oldpin, oldpinlen);
+      if (err)
+        {
+          log_error ("CHV %02X verification failed: %s\n",
+                     keyref, gpg_strerror (err));
+          goto leave;
+        }
+    }
+
+  /* Ask for the new pin.  */
+  err = ask_and_prepare_chv (app, targetkeyref, 1, -1, pincb, pincb_arg,
+                             &newpin, &newpinlen);
+  if (err)
+    return err;
+
+  if ((flags & APP_CHANGE_FLAG_RESET))
+    {
+      char *buf = xtrymalloc_secure (oldpinlen + newpinlen);
+      if (!buf)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+      memcpy (buf, oldpin, oldpinlen);
+      memcpy (buf+oldpinlen, newpin, newpinlen);
+      err = iso7816_reset_retry_counter_with_rc (app->slot, targetkeyref,
+                                                 buf, oldpinlen+newpinlen);
+      xfree (buf);
+      if (err)
+        log_error ("resetting CHV %02X using CHV %02X failed: %s\n",
+                   targetkeyref, keyref, gpg_strerror (err));
+    }
+  else
+    {
+      err = iso7816_change_reference_data (app->slot, keyref,
+                                           oldpin, oldpinlen,
+                                           newpin, newpinlen);
+      if (err)
+        log_error ("CHV %02X changing PIN failed: %s\n",
+                   keyref, gpg_strerror (err));
+    }
 
  leave:
   xfree (oldpin);
@@ -1365,19 +1500,19 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
 
 
 /* Perform a simple verify operation for the PIN specified by PWIDSTR.
- * For valid values see do_change_pin.  */
+ * For valid values see do_change_chv.  */
 static gpg_error_t
-do_check_pin (app_t app, const char *pwidstr,
+do_check_chv (app_t app, const char *pwidstr,
               gpg_error_t (*pincb)(void*, const char *, char **),
               void *pincb_arg)
 {
   int keyref;
 
-  keyref = parse_pin_keyref (pwidstr);
+  keyref = parse_chv_keyref (pwidstr);
   if (keyref == -1)
     return gpg_error (GPG_ERR_INV_ID);
 
-  return verify_pin (app, keyref, pincb, pincb_arg);
+  return verify_chv (app, keyref, pincb, pincb_arg);
 }
 
 
@@ -1492,7 +1627,7 @@ do_auth (app_t app, const char *keyidstr,
     }
 
   /* Now verify the Application PIN.  */
-  err = verify_pin (app, 0x80, pincb, pincb_arg);
+  err = verify_chv (app, 0x80, pincb, pincb_arg);
   if (err)
     return err;
 
@@ -1675,8 +1810,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_chv;
+  app->fnc.check_pin = do_check_chv;
 
 
 leave:
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index 1c4413b..fd7aa9a 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -899,7 +899,7 @@ list_piv (card_info_t info, estream_t fp)
           switch (info->chvinfo[i])
             {
             case -1: s = "[error]"; break;
-            case -2: s = "-"; break;  /* No such PIN */
+            case -2: s = "-"; break;  /* No such PIN or info not available. */
             case -3: s = "[blocked]"; break;
             case -5: s = "[verified]"; break;
             default: s = "[?]"; break;
@@ -950,15 +950,21 @@ static gpg_error_t
 cmd_verify (card_info_t info, char *argstr)
 {
   gpg_error_t err;
+  const char *pinref;
 
   if (!info)
     return print_help ("verify [chvid]", 0);
 
-  if (info->apptype == APP_TYPE_OPENPGP)
-    err = scd_checkpin (info->serialno);
+  if (*argstr)
+    pinref = argstr;
+  else if (info->apptype == APP_TYPE_OPENPGP)
+    pinref = info->serialno;
+  else if (info->apptype == APP_TYPE_PIV)
+    pinref = "PIV.80";
   else
-    err = scd_checkpin (argstr);
+    return gpg_error (GPG_ERR_MISSING_VALUE);
 
+  err = scd_checkpin (pinref);
   if (err)
     log_error ("verify failed: %s <%s>\n",
                gpg_strerror (err), gpg_strsource (err));
@@ -1845,30 +1851,48 @@ cmd_generate (card_info_t info)
 /* Sub-menu to change a PIN.  The presented options may depend on the
  * the ALLOW_ADMIN flag.  */
 static gpg_error_t
-cmd_passwd (card_info_t info, int allow_admin)
+cmd_passwd (card_info_t info, int allow_admin, char *argstr)
 {
   gpg_error_t err;
   char *answer = NULL;
+  const char *pinref;
 
   if (!info)
     return print_help
-      ("PASSWD\n\n"
+      ("PASSWD [PINREF]\n\n"
        "Menu to change or unblock the PINs.  Note that the\n"
        "presented menu options depend on the type of card\n"
-       "and whether the admin mode is enabled.",
+       "and whether the admin mode is enabled.  For OpenPGP\n"
+       "and PIV cards defaults for PINREF are available.",
        0);
 
-  /* Convenience message because we did this in gpg --card-edit too.  */
-  if (info->apptype == APP_TYPE_OPENPGP)
-    log_info (_("OpenPGP card no. %s detected\n"),
+  if (opt.interactive || opt.verbose)
+    log_info (_("%s card no. %s detected\n"),
+              app_type_string (info->apptype),
               info->dispserialno? info->dispserialno : info->serialno);
 
-  if (!allow_admin)
+  if (!allow_admin || info->apptype != APP_TYPE_OPENPGP)
     {
-      err = scd_change_pin ("OPENPGP.1", 0);
+      if (*argstr)
+        pinref = argstr;
+      else if (info->apptype == APP_TYPE_OPENPGP)
+        pinref = "OPENPGP.1";
+      else if (info->apptype == APP_TYPE_PIV)
+        pinref = "PIV.80";
+      else
+        {
+          err = gpg_error (GPG_ERR_MISSING_VALUE);
+          goto leave;
+        }
+      err = scd_change_pin (pinref, 0);
       if (err)
         goto leave;
-      log_info ("PIN changed.\n");
+
+      if (info->apptype == APP_TYPE_PIV
+          && !ascii_strcasecmp (pinref, "PIV.81"))
+        log_info ("PUK changed.\n");
+      else
+        log_info ("PIN changed.\n");
     }
   else if (info->apptype == APP_TYPE_OPENPGP)
     {
@@ -1959,23 +1983,43 @@ cmd_unblock (card_info_t info)
        "command can be used to set a new PIN.",
        0);
 
-  if (info->apptype == APP_TYPE_OPENPGP)
-    log_info (_("OpenPGP card no. %s detected\n"),
+  if (opt.interactive || opt.verbose)
+    log_info (_("%s card no. %s detected\n"),
+              app_type_string (info->apptype),
               info->dispserialno? info->dispserialno : info->serialno);
 
-  if (info->apptype == APP_TYPE_OPENPGP && !info->is_v2)
-    log_error (_("This command is only available for version 2 cards\n"));
-  else if (info->apptype == APP_TYPE_OPENPGP && !info->chvinfo[1])
-    log_error (_("Reset Code not or not anymore available\n"));
-  else if (info->apptype == APP_TYPE_OPENPGP)
+  if (info->apptype == APP_TYPE_OPENPGP)
     {
-      err = scd_change_pin ("OPENPGP.2", 0);
+      if (!info->is_v2)
+        {
+          log_error (_("This command is only available for version 2 cards\n"));
+          err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+        }
+      else if (!info->chvinfo[1])
+        {
+          log_error (_("Reset Code not or not anymore available\n"));
+          err = gpg_error (GPG_ERR_PIN_BLOCKED);
+        }
+      else
+        {
+          err = scd_change_pin ("OPENPGP.2", 0);
+          if (!err)
+            log_info ("PIN changed.\n");
+        }
+    }
+  else if (info->apptype == APP_TYPE_PIV)
+    {
+      /* Unblock the Application PIN.  */
+      err = scd_change_pin ("PIV.80", 1);
       if (!err)
-        log_info ("PIN changed.\n");
+        log_info ("PIN unblocked and changed.\n");
     }
   else
-    log_info ("Unblocking not yet supported for '%s'\n",
-              app_type_string (info->apptype));
+    {
+      log_info ("Unblocking not yet supported for '%s'\n",
+                app_type_string (info->apptype));
+      err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+    }
 
   return err;
 }
@@ -2079,15 +2123,15 @@ cmd_factoryreset (card_info_t info)
       goto leave;
     }
 
+  if (opt.interactive || opt.verbose)
+    log_info (_("%s card no. %s detected\n"),
+              app_type_string (info->apptype),
+              info->dispserialno? info->dispserialno : info->serialno);
+
   if (!termstate || is_yubikey)
     {
-      if (is_yubikey)
-        log_info (_("Yubikey no. %s with PIV application detected\n"),
-                  info->dispserialno? info->dispserialno : info->serialno);
-      else
+      if (!is_yubikey)
         {
-          log_info (_("OpenPGP card no. %s detected\n"),
-                    info->dispserialno? info->dispserialno : info->serialno);
           if (!(info->status_indicator == 3 || info->status_indicator == 5))
             {
               /* Note: We won't see status-indicator 3 here because it
@@ -2865,7 +2909,7 @@ dispatch_command (card_info_t info, const char *orig_command)
     case cmdREADCERT:     err = cmd_readcert (info, argstr); break;
     case cmdFORCESIG:     err = cmd_forcesig (info); break;
     case cmdGENERATE:     err = cmd_generate (info); break;
-    case cmdPASSWD:       err = cmd_passwd (info, 1); break;
+    case cmdPASSWD:       err = cmd_passwd (info, 1, argstr); break;
     case cmdUNBLOCK:      err = cmd_unblock (info); break;
     case cmdFACTORYRESET: err = cmd_factoryreset (info); break;
     case cmdKDFSETUP:     err = cmd_kdfsetup (info, argstr); break;
@@ -3131,7 +3175,7 @@ interactive_loop (void)
         case cmdREADCERT:  err = cmd_readcert (info, argstr); break;
         case cmdFORCESIG:  err = cmd_forcesig (info); break;
         case cmdGENERATE:  err = cmd_generate (info); break;
-        case cmdPASSWD:    err = cmd_passwd (info, allow_admin); break;
+        case cmdPASSWD:    err = cmd_passwd (info, allow_admin, argstr); break;
         case cmdUNBLOCK:   err = cmd_unblock (info); break;
         case cmdFACTORYRESET:
           err = cmd_factoryreset (info);

commit 3231ecdafd71ac47b734469b07170756979ede72
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Feb 5 14:48:49 2019 +0100

    scd: Allow standard keyref scheme for app-openpgp.
    
    * scd/app-openpgp.c (do_change_pin): Allow prefixing the CHVNO with
    "OPENPGP."
    * tools/card-call-scd.c (scd_change_pin): Change API to use strings.
    * tools/gpg-card-tool.c (cmd_passwd): Adjust for change.
    (cmd_unblock): Ditto.
    --
    
    The generic keyref allows for better error detection in case a keyref
    is send to a wrong card.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/doc/wks.texi b/doc/wks.texi
index a0b2a34..f132b31 100644
--- a/doc/wks.texi
+++ b/doc/wks.texi
@@ -124,7 +124,7 @@ Requires installation of that command.
 @item --with-colons
 @opindex with-colons
 This option has currently only an effect on the @option{--supported}
-command.  If it is used all arguimenst on the command line are taken
+command.  If it is used all arguments on the command line are taken
 as domain names and tested for WKD support.  The output format is one
 line per domain with colon delimited fields.  The currently specified
 fields are (future versions may specify additional fields):
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index dbc51be..72ed80a 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -2583,6 +2583,8 @@ do_writecert (app_t app, ctrl_t ctrl,
      -       2   1      Verify CHV2 and set a new CHV1 and CHV2.
      -       2   2      Verify Reset Code and set a new PW1.
      -       3   any    Verify CHV3/PW3 and set a new CHV3/PW3.
+
+   The CHVNO can be prefixed with "OPENPGP.".
  */
 static gpg_error_t
 do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
@@ -2591,7 +2593,7 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
                void *pincb_arg)
 {
   int rc = 0;
-  int chvno = atoi (chvnostr);
+  int chvno;
   char *resetcode = NULL;
   char *oldpinvalue = NULL;
   char *pinvalue = NULL;
@@ -2605,6 +2607,17 @@ do_change_pin (app_t app, ctrl_t ctrl,  const char *chvnostr,
 
   (void)ctrl;
 
+  if (digitp (chvnostr))
+    chvno = atoi (chvnostr);
+  else if (!ascii_strcasecmp (chvnostr, "OPENPGP.1"))
+    chvno = 1;
+  else if (!ascii_strcasecmp (chvnostr, "OPENPGP.2"))
+    chvno = 2;
+  else if (!ascii_strcasecmp (chvnostr, "OPENPGP.3"))
+    chvno = 3;
+  else
+    return gpg_error (GPG_ERR_INV_ID);
+
   memset (&pininfo, 0, sizeof pininfo);
   pininfo.fixedlen = -1;
   pininfo.minlen = minlen;
diff --git a/scd/iso7816.c b/scd/iso7816.c
index c8a2138..69009c4 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -346,6 +346,7 @@ iso7816_change_reference_data (int slot, int chvno,
 
   sw = apdu_send_simple (slot, 0, 0x00, CMD_CHANGE_REFERENCE_DATA,
                          oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
+  wipememory (buf, oldchvlen+newchvlen);
   xfree (buf);
   return map_sw (sw);
 
diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c
index c51282f..7add56d 100644
--- a/tools/card-call-scd.c
+++ b/tools/card-call-scd.c
@@ -1368,28 +1368,23 @@ scd_cardlist (strlist_t *result)
  *     101: Set a new PIN and reset the retry counter
  *     102: For v1 cars: Same as 101.
  *          For v2 cards: Set a new Reset Code.
- * SERIALNO is not used.
  */
 gpg_error_t
-scd_change_pin (int chvno)
+scd_change_pin (const char *pinref, int reset_mode)
 {
   gpg_error_t err;
   char line[ASSUAN_LINELENGTH];
-  const char *reset = "";
   struct default_inq_parm_s dfltparm;
 
   memset (&dfltparm, 0, sizeof dfltparm);
 
-  if (chvno >= 100)
-    reset = "--reset";
-  chvno %= 100;
-
   err = start_agent (0);
   if (err)
     return err;
   dfltparm.ctx = agent_ctx;
 
-  snprintf (line, sizeof line, "SCD PASSWD %s %d", reset, chvno);
+  snprintf (line, sizeof line, "SCD PASSWD%s %s",
+            reset_mode? " --reset":"", pinref);
   err = assuan_transact (agent_ctx, line,
                          NULL, NULL,
                          default_inq_cb, &dfltparm,
diff --git a/tools/card-tool.h b/tools/card-tool.h
index 9aca813..2707b3e 100644
--- a/tools/card-tool.h
+++ b/tools/card-tool.h
@@ -212,7 +212,7 @@ gpg_error_t scd_serialno (char **r_serialno, const char *demand);
 gpg_error_t scd_readcert (const char *certidstr,
                           void **r_buf, size_t *r_buflen);
 gpg_error_t scd_cardlist (strlist_t *result);
-gpg_error_t scd_change_pin (int chvno);
+gpg_error_t scd_change_pin (const char *pinref, int reset_mode);
 gpg_error_t scd_checkpin (const char *serialno);
 
 unsigned long agent_get_s2k_count (void);
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index 243ee55..1c4413b 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -1865,7 +1865,7 @@ cmd_passwd (card_info_t info, int allow_admin)
 
   if (!allow_admin)
     {
-      err = scd_change_pin (1);
+      err = scd_change_pin ("OPENPGP.1", 0);
       if (err)
         goto leave;
       log_info ("PIN changed.\n");
@@ -1896,7 +1896,7 @@ cmd_passwd (card_info_t info, int allow_admin)
           if (*answer == '1')
             {
               /* Change PIN (same as the direct thing in non-admin mode).  */
-              err = scd_change_pin (1);
+              err = scd_change_pin ("OPENPGP.1", 0);
               if (err)
                 log_error ("Error changing the PIN: %s\n", gpg_strerror (err));
               else
@@ -1905,7 +1905,7 @@ cmd_passwd (card_info_t info, int allow_admin)
           else if (*answer == '2')
             {
               /* Unblock PIN by setting a new PIN.  */
-              err = scd_change_pin (101);
+              err = scd_change_pin ("OPENPGP.1", 1);
               if (err)
                 log_error ("Error unblocking the PIN: %s\n", gpg_strerror(err));
               else
@@ -1914,7 +1914,7 @@ cmd_passwd (card_info_t info, int allow_admin)
           else if (*answer == '3')
             {
               /* Change Admin PIN.  */
-              err = scd_change_pin (3);
+              err = scd_change_pin ("OPENPGP.3", 0);
               if (err)
                 log_error ("Error changing the PIN: %s\n", gpg_strerror (err));
               else
@@ -1923,7 +1923,7 @@ cmd_passwd (card_info_t info, int allow_admin)
           else if (*answer == '4')
             {
               /* Set a new Reset Code.  */
-              err = scd_change_pin (102);
+              err = scd_change_pin ("OPENPGP.2", 1);
               if (err)
                 log_error ("Error setting the Reset Code: %s\n",
                            gpg_strerror (err));
@@ -1969,7 +1969,7 @@ cmd_unblock (card_info_t info)
     log_error (_("Reset Code not or not anymore available\n"));
   else if (info->apptype == APP_TYPE_OPENPGP)
     {
-      err = scd_change_pin (2);
+      err = scd_change_pin ("OPENPGP.2", 0);
       if (!err)
         log_info ("PIN changed.\n");
     }

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

Summary of changes:
 doc/wks.texi          |   2 +-
 scd/app-openpgp.c     |  15 ++-
 scd/app-piv.c         | 267 +++++++++++++++++++++++++++++++++++++-------------
 scd/iso7816.c         |   1 +
 tools/card-call-scd.c |  11 +--
 tools/card-tool.h     |   2 +-
 tools/gpg-card-tool.c | 116 +++++++++++++++-------
 7 files changed, 301 insertions(+), 113 deletions(-)


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




More information about the Gnupg-commits mailing list