[git] GnuPG - branch, master, updated. gnupg-2.2.7-338-g79bed50

by Werner Koch cvs at cvs.gnupg.org
Tue Jan 29 13:47:31 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  79bed504e51034d960fcb858fb643901cad85913 (commit)
      from  9325c92284bb346d11c3591bb2ea88095989361a (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 79bed504e51034d960fcb858fb643901cad85913
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Jan 29 13:28:10 2019 +0100

    card: Support factory reset for Yubikey PIV application.
    
    * scd/app-common.h (struct app_ctx_s): Add field cardtype.
    * scd/app.c (app_new_register): Set cardtype for yubikey.
    (app_getattr): Add CARDTYPE.
    (app_write_learn_status): Emit new attribute.
    * scd/app-piv.c (do_getattr): Add CHV-USAGE.
    (do_learn_status): Emit it.
    * tools/card-tool.h (struct card_info_s): Add field cardtype.
    * tools/card-call-scd.c (learn_status_cb): Parse "CARDTYPE".
    
    * tools/gpg-card-tool.c (list_piv): Print PIN usage policy.
    (list_card): Print card type.
    (cmd_factoryreset): Implement for Yubikey with PIV.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/scd/app-common.h b/scd/app-common.h
index b1661b5..98d8464 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -52,6 +52,7 @@ struct app_ctx_s {
 
   unsigned char *serialno; /* Serialnumber in raw form, allocated. */
   size_t serialnolen;      /* Length in octets of serialnumber. */
+  const char *cardtype;    /* NULL or string with the token's type.  */
   const char *apptype;
   unsigned int card_version;
   unsigned int card_status;
diff --git a/scd/app-piv.c b/scd/app-piv.c
index 69f12f4..d984e9c 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -469,13 +469,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
     { "SERIALNO",     0x0000, -1 },
     { "$AUTHKEYID",   0x0000, -2 }, /* Default key for ssh.  */
     { "$DISPSERIALNO",0x0000, -3 },
-    { "CHV-STATUS",   0x0000, -4 }
+    { "CHV-STATUS",   0x0000, -4 },
+    { "CHV-USAGE",    0x007E, -5 }
   };
   gpg_error_t err = 0;
   int idx;
   void *relptr;
   unsigned char *value;
   size_t valuelen;
+  const unsigned char *s;
+  size_t n;
 
   for (idx=0; (idx < DIM (table)
                && ascii_strcasecmp (table[idx].name, name)); idx++)
@@ -521,6 +524,20 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
       err = send_status_printf (ctrl, table[idx].name, "%d %d %d",
                                 tmp[0], tmp[1], tmp[2]);
     }
+  else if (table[idx].special == -5) /* CHV-USAGE (aka PIN Usage Policy) */
+    {
+      /* We return 2 hex bytes or nothing in case the discovery object
+       * is not supported.  */
+      relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
+      if (relptr)
+        {
+          s = find_tlv (value, valuelen, 0x7E, &n);
+          if (s && n && (s = find_tlv (s, n, 0x5F2F, &n)) && n >=2 )
+            err = send_status_printf (ctrl, table[idx].name, "%02X %02X",
+                                      s[0], s[1]);
+          xfree (relptr);
+        }
+    }
   else
     {
       relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
@@ -577,6 +594,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
 
   (void)flags;
 
+  do_getattr (app, ctrl, "CHV-USAGE");
   do_getattr (app, ctrl, "CHV-STATUS");
 
   for (i=0; data_objects[i].tag; i++)
diff --git a/scd/app.c b/scd/app.c
index 219cee6..c79a174 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -228,6 +228,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
               && !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0,
                                        NULL, &buf, &buflen))
             {
+              app->cardtype = "yubikey";
               if (opt.verbose)
                 {
                   log_info ("Yubico: config=");
@@ -640,9 +641,12 @@ app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
   if (!app->fnc.learn_status)
     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
 
-  /* We do not send APPTYPE if only keypairinfo is requested.  */
+  /* We do not send CARD and APPTYPE if only keypairinfo is requested.  */
+  if (app->cardtype && !(flags & 1))
+    send_status_direct (ctrl, "CARDTYPE", app->cardtype);
   if (app->apptype && !(flags & 1))
     send_status_direct (ctrl, "APPTYPE", app->apptype);
+
   err = lock_app (app, ctrl);
   if (err)
     return err;
@@ -721,6 +725,11 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name)
   if (!app->ref_count)
     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
 
+  if (app->cardtype && name && !strcmp (name, "CARDTYPE"))
+    {
+      send_status_direct (ctrl, "CARDTYPE", app->cardtype);
+      return 0;
+    }
   if (app->apptype && name && !strcmp (name, "APPTYPE"))
     {
       send_status_direct (ctrl, "APPTYPE", app->apptype);
@@ -744,7 +753,7 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name)
   err = lock_app (app, ctrl);
   if (err)
     return err;
-  err =  app->fnc.getattr (app, ctrl, name);
+  err = app->fnc.getattr (app, ctrl, name);
   unlock_app (app);
   return err;
 }
diff --git a/tools/card-call-scd.c b/tools/card-call-scd.c
index 2551b19..9a742a7 100644
--- a/tools/card-call-scd.c
+++ b/tools/card-call-scd.c
@@ -137,6 +137,7 @@ release_card_info (card_info_t info)
     return;
 
   xfree (info->reader); info->reader = NULL;
+  xfree (info->cardtype); info->cardtype = NULL;
   xfree (info->serialno); info->serialno = NULL;
   xfree (info->dispserialno); info->dispserialno = NULL;
   xfree (info->apptypestr); info->apptypestr = NULL;
@@ -157,7 +158,7 @@ release_card_info (card_info_t info)
       xfree (info->kinfo);
       info->kinfo = kinfo;
     }
-
+  info->chvusage[0] = info->chvusage[1] = 0;
 }
 
 
@@ -724,6 +725,11 @@ learn_status_cb (void *opaque, const char *line)
           parm->is_v2 = (strlen (parm->serialno) >= 16
                          && xtoi_2 (parm->serialno+12) >= 2 );
         }
+      else if (!memcmp (keyword, "CARDTYPE", keywordlen))
+        {
+          xfree (parm->cardtype);
+          parm->cardtype = unescape_status_string (line);
+        }
       else if (!memcmp (keyword, "DISP-SEX", keywordlen))
         {
           parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
@@ -779,17 +785,26 @@ learn_status_cb (void *opaque, const char *line)
       break;
 
     case 9:
-        if (!memcmp (keyword, "DISP-NAME", keywordlen))
-          {
-            xfree (parm->disp_name);
-            parm->disp_name = unescape_status_string (line);
-          }
-        else if (!memcmp (keyword, "DISP-LANG", keywordlen))
-          {
-            xfree (parm->disp_lang);
-            parm->disp_lang = unescape_status_string (line);
-          }
-      break;
+      if (!memcmp (keyword, "DISP-NAME", keywordlen))
+        {
+          xfree (parm->disp_name);
+          parm->disp_name = unescape_status_string (line);
+        }
+      else if (!memcmp (keyword, "DISP-LANG", keywordlen))
+        {
+          xfree (parm->disp_lang);
+          parm->disp_lang = unescape_status_string (line);
+        }
+      else if (!memcmp (keyword, "CHV-USAGE", keywordlen))
+        {
+          unsigned int byte1, byte2;
+
+          byte1 = byte2 = 0;
+          sscanf (line, "%x %x", &byte1, &byte2);
+          parm->chvusage[0] = byte1;
+          parm->chvusage[1] = byte2;
+        }
+        break;
 
     case 10:
       if (!memcmp (keyword, "PUBKEY-URL", keywordlen))
@@ -839,7 +854,7 @@ learn_status_cb (void *opaque, const char *line)
             }
           else if (parm->apptype == APP_TYPE_PIV)
             {
-              for (i=0; *p && DIM (parm->chvinfo); i++)
+              for (i=0; *p && i < DIM (parm->chvinfo); i++)
                 {
                   parm->chvinfo[i] = atoi (p);
                   while (*p && !spacep (p))
diff --git a/tools/card-tool.h b/tools/card-tool.h
index bcc257c..b1d8662 100644
--- a/tools/card-tool.h
+++ b/tools/card-tool.h
@@ -104,6 +104,7 @@ struct card_info_s
 {
   int error;         /* private. */
   char *reader;      /* Reader information.  */
+  char *cardtype;    /* NULL or type of the card.  */
   char *apptypestr;  /* Malloced application type string.  */
   app_type_t apptype;/* Translated from APPTYPESTR.  */
   char *serialno;    /* malloced hex string. */
@@ -128,6 +129,7 @@ struct card_info_s
   int is_v2;         /* True if this is a v2 openpgp card.  */
   int chvmaxlen[3];  /* Maximum allowed length of a CHV. */
   int chvinfo[3];    /* Allowed retries for the CHV; 0 = blocked. */
+  unsigned char chvusage[2]; /* Data object 5F2F */
   struct key_attr key_attr[3]; /* OpenPGP card key attributes.  */
   struct {
     unsigned int ki:1;     /* Key import available.  */
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index 5ba44fc..4f79620 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -763,15 +763,37 @@ static void
 list_piv (card_info_t info, estream_t fp)
 {
   static struct keyinfolabel_s keyinfolabels[] = {
-    { "PIV Authentication:", "PIV.9A" },
-    { "Card Authenticat. :", "PIV.9E" },
-    { "Digital Signature :", "PIV.9C" },
-    { "Key Management ...:", "PIV.9D" },
+    { "PIV authentication:", "PIV.9A" },
+    { "Card authenticat. :", "PIV.9E" },
+    { "Digital signature :", "PIV.9C" },
+    { "Key management ...:", "PIV.9D" },
     { NULL, NULL }
   };
   const char *s;
   int i;
 
+  if (info->chvusage[0] || info->chvusage[1])
+    {
+      tty_fprintf (fp, "PIN usage policy .:");
+      if ((info->chvusage[0] & 0x40))
+          tty_fprintf (fp, " app-pin");
+      if ((info->chvusage[0] & 0x20))
+        tty_fprintf (fp, " global-pin");
+      if ((info->chvusage[0] & 0x10))
+        tty_fprintf (fp, " occ");
+      if ((info->chvusage[0] & 0x08))
+        tty_fprintf (fp, " vci");
+      if ((info->chvusage[0] & 0x08) && !(info->chvusage[0] & 0x04))
+        tty_fprintf (fp, " pairing");
+
+      if (info->chvusage[1] == 0x10)
+        tty_fprintf (fp, " primary:card");
+      else if (info->chvusage[1] == 0x20)
+        tty_fprintf (fp, " primary:global");
+
+      tty_fprintf (fp, "\n");
+    }
+
   tty_fprintf (fp, "PIN retry counter :");
   for (i=0; i < DIM (info->chvinfo); i++)
     {
@@ -790,7 +812,7 @@ list_piv (card_info_t info, estream_t fp)
           tty_fprintf (fp, " %s", s);
         }
     }
-  tty_fprintf (fp, "\n", s);
+  tty_fprintf (fp, "\n");
   list_all_kinfo (info, keyinfolabels, fp);
 
 }
@@ -804,9 +826,11 @@ list_card (card_info_t info)
 
   tty_fprintf (fp, "Reader ...........: %s\n",
                info->reader? info->reader : "[none]");
+  if (info->cardtype)
+    tty_fprintf (fp, "Card type ........: %s\n", info->cardtype);
   tty_fprintf (fp, "Serial number ....: %s\n",
                info->serialno? info->serialno : "[none]");
-  tty_fprintf (fp, "Application Type .: %s%s%s%s\n",
+  tty_fprintf (fp, "Application type .: %s%s%s%s\n",
                app_type_string (info->apptype),
                info->apptype == APP_TYPE_UNKNOWN && info->apptypestr? "(":"",
                info->apptype == APP_TYPE_UNKNOWN && info->apptypestr
@@ -1836,26 +1860,32 @@ cmd_factoryreset (card_info_t info)
   char *answer = NULL;
   int termstate = 0;
   int any_apdu = 0;
+  int is_yubikey = 0;
   int i;
 
 
   if (!info)
     return print_help
       ("FACTORY-RESET\n\n"
-       "Do a complete reset of an OpenPGP card.  This deletes all\n"
-       "data and keys and resets the PINs to their default.  This\n"
-       "mainly used by developers with scratch cards.  Don't worry,\n"
-       "you need to confirm before the command proceeds.",
-       APP_TYPE_OPENPGP, 0);
+       "Do a complete reset of some OpenPGP and PIV cards.  This\n"
+       "deletes all data and keys and resets the PINs to their default.\n"
+       "This is mainly used by developers with scratch cards.  Don't\n"
+       "worry, you need to confirm before the command proceeds.",
+       APP_TYPE_OPENPGP, APP_TYPE_PIV, 0);
 
-  if (info->apptype != APP_TYPE_OPENPGP)
-    {
-      log_info ("Note: This is an OpenPGP only command.\n");
-      return gpg_error (GPG_ERR_NOT_SUPPORTED);
-    }
+  /* We support the factory reset for most OpenPGP cards and Yubikeys
+   * with the PIV application.  */
+  if (info->apptype == APP_TYPE_OPENPGP)
+    ;
+  else if (info->apptype == APP_TYPE_PIV
+           && info->cardtype && !strcmp (info->cardtype, "yubikey"))
+    is_yubikey = 1;
+  else
+
+    return gpg_error (GPG_ERR_NOT_SUPPORTED);
 
-  /* The code below basically does the same what this
-   * gpg-connect-agent script does:
+  /* For an OpenPGP card the code below basically does the same what
+   * this gpg-connect-agent script does:
    *
    *   scd reset
    *   scd serialno undefined
@@ -1873,7 +1903,8 @@ cmd_factoryreset (card_info_t info)
    *   scd reset
    *   /echo Card has been reset to factory defaults
    *
-   * but tries to find out something about the card first.
+   * For a PIV application on a Yubikey it merely issues the Yubikey
+   * specific resset command.
    */
 
   err = scd_learn (info);
@@ -1886,17 +1917,24 @@ cmd_factoryreset (card_info_t info)
       goto leave;
     }
 
-  if (!termstate)
+  if (!termstate || 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))
+      if (is_yubikey)
+        log_info (_("Yubikey no. %s with PIV application detected\n"),
+                  info->dispserialno? info->dispserialno : info->serialno);
+      else
         {
-          /* Note: We won't see status-indicator 3 here because it is not
-           * possible to select a card application in termination state.  */
-          log_error (_("This command is not supported by this card\n"));
-          err = gpg_error (GPG_ERR_NOT_SUPPORTED);
-          goto leave;
+          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
+               * is not possible to select a card application in
+               * termination state.  */
+              log_error (_("This command is not supported by this card\n"));
+              err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+              goto leave;
+            }
         }
 
       tty_printf ("\n");
@@ -1924,51 +1962,73 @@ cmd_factoryreset (card_info_t info)
           goto leave;
         }
 
-      any_apdu = 1;
-      /* We need to select a card application before we can send APDUs
-       * to the card without scdaemon doing anything on its own.  */
-      err = send_apdu (NULL, "RESET", 0);
-      if (err)
-        goto leave;
-      err = send_apdu ("undefined", "dummy select ", 0);
-      if (err)
-        goto leave;
 
-      /* Select the OpenPGP application.  */
-      err = send_apdu ("00A4040006D27600012401", "SELECT AID", 0);
-      if (err)
-        goto leave;
+      if (is_yubikey)
+        {
+          /* The PIV application si already selected, we only need to
+           * send the special reset APDU after having blocked PIN and
+           * PUK.  Note that blocking the PUK is done using the
+           * unblock PIN command.  */
+          any_apdu = 1;
+          for (i=0; i < 5; i++)
+            send_apdu ("0020008008FFFFFFFFFFFFFFFF", "VERIFY", 0xffff);
+          for (i=0; i < 5; i++)
+            send_apdu ("002C008010FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
+                       "RESET RETRY COUNTER", 0xffff);
+          err = send_apdu ("00FB000001FF", "YUBIKEY RESET", 0);
+          if (err)
+            goto leave;
+        }
+      else /* OpenPGP card.  */
+        {
+          any_apdu = 1;
+          /* We need to select a card application before we can send APDUs
+           * to the card without scdaemon doing anything on its own.  */
+          err = send_apdu (NULL, "RESET", 0);
+          if (err)
+            goto leave;
+          err = send_apdu ("undefined", "dummy select ", 0);
+          if (err)
+            goto leave;
+          /* Select the OpenPGP application.  */
+          err = send_apdu ("00A4040006D27600012401", "SELECT AID", 0);
+          if (err)
+            goto leave;
+
+          /* Do some dummy verifies with wrong PINs to set the retry
+           * counter to zero.  We can't easily use the card version 2.1
+           * feature of presenting the admin PIN to allow the terminate
+           * command because there is no machinery in scdaemon to catch
+           * the verify command and ask for the PIN when the "APDU"
+           * command is used.
+           * Here, the length of dummy wrong PIN is 32-byte, also
+           * supporting authentication with KDF DO.  */
+          for (i=0; i < 4; i++)
+            send_apdu ("0020008120"
+                       "40404040404040404040404040404040"
+                       "40404040404040404040404040404040", "VERIFY", 0xffff);
+          for (i=0; i < 4; i++)
+            send_apdu ("0020008320"
+                       "40404040404040404040404040404040"
+                       "40404040404040404040404040404040", "VERIFY", 0xffff);
+
+          /* Send terminate datafile command.  */
+          err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
+          if (err)
+            goto leave;
+        }
+    }
 
-      /* Do some dummy verifies with wrong PINs to set the retry
-       * counter to zero.  We can't easily use the card version 2.1
-       * feature of presenting the admin PIN to allow the terminate
-       * command because there is no machinery in scdaemon to catch
-       * the verify command and ask for the PIN when the "APDU"
-       * command is used.
-       * Here, the length of dummy wrong PIN is 32-byte, also
-       * supporting authentication with KDF DO.  */
-      for (i=0; i < 4; i++)
-        send_apdu ("0020008120"
-                   "40404040404040404040404040404040"
-                   "40404040404040404040404040404040", "VERIFY", 0xffff);
-      for (i=0; i < 4; i++)
-        send_apdu ("0020008320"
-                   "40404040404040404040404040404040"
-                   "40404040404040404040404040404040", "VERIFY", 0xffff);
-
-      /* Send terminate datafile command.  */
-      err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
+  if (!is_yubikey)
+    {
+      any_apdu = 1;
+      /* Send activate datafile command.  This is used without
+       * confirmation if the card is already in termination state.  */
+      err = send_apdu ("00440000", "ACTIVATE DF", 0);
       if (err)
         goto leave;
     }
 
-  any_apdu = 1;
-  /* Send activate datafile command.  This is used without
-   * confirmation if the card is already in termination state.  */
-  err = send_apdu ("00440000", "ACTIVATE DF", 0);
-  if (err)
-    goto leave;
-
   /* Finally we reset the card reader once more.  */
   err = send_apdu (NULL, "RESET", 0);
   if (err)
@@ -1979,7 +2039,7 @@ cmd_factoryreset (card_info_t info)
   err = scd_serialno (&answer, NULL);
 
  leave:
-  if (err && any_apdu)
+  if (err && any_apdu && !is_yubikey)
     {
       log_info ("Due to an error the card might be in an inconsistent state\n"
                 "You should run the LIST command to check this.\n");

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

Summary of changes:
 scd/app-common.h      |   1 +
 scd/app-piv.c         |  20 +++++-
 scd/app.c             |  13 +++-
 tools/card-call-scd.c |  41 +++++++----
 tools/card-tool.h     |   2 +
 tools/gpg-card-tool.c | 196 ++++++++++++++++++++++++++++++++------------------
 6 files changed, 189 insertions(+), 84 deletions(-)


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




More information about the Gnupg-commits mailing list