card: Print card version. Check for bad Yubikeys.
authorWerner Koch <wk@gnupg.org>
Tue, 5 Mar 2019 16:40:08 +0000 (17:40 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 5 Mar 2019 16:40:08 +0000 (17:40 +0100)
* scd/app.c (app_new_register): Set card version for Yubikeys.
(app_write_learn_status): Print CARDVERSION and APPVERSION.
* tools/card-call-scd.c (learn_status_cb): Detect them.
* tools/gpg-card.h (struct card_info_s): Add appversion and
cardversion.
* tools/gpg-card.c (list_openpgp): Remove version printing from serial
number.
(print_a_version): New.
(list_card): Print card and app version.
(cmd_generate): Do not allow broken Yubikeys.

Signed-off-by: Werner Koch <wk@gnupg.org>
scd/app.c
scd/command.c
tools/card-call-scd.c
tools/gpg-card.c
tools/gpg-card.h

index ada1eb9..2ee104d 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -263,6 +263,9 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
                                * set the serial number.  */
                             }
                         }
+                      s1 = find_tlv (buf+1, buflen-1, 0x05, &n);  /* version */
+                      if (s1 && n == 3)
+                        app->cardversion = ((s1[0]<<16)|(s1[1]<<8)|s1[2]);
                     }
                 }
               xfree (buf);
@@ -632,7 +635,7 @@ app_get_serialno (app_t app)
 }
 
 
-/* Write out the application specifig status lines for the LEARN
+/* Write out the application specific status lines for the LEARN
    command. */
 gpg_error_t
 app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
@@ -645,10 +648,17 @@ app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
 
   /* 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);
+  if (!(flags &1))
+    {
+      if (app->cardtype)
+        send_status_direct (ctrl, "CARDTYPE", app->cardtype);
+      if (app->cardversion)
+        send_status_printf (ctrl, "CARDVERSION", "%X", app->cardversion);
+      if (app->apptype)
+        send_status_direct (ctrl, "APPTYPE", app->apptype);
+      if (app->appversion)
+        send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
+    }
 
   err = lock_app (app, ctrl);
   if (err)
index 5b2ca6c..0d1a5cd 100644 (file)
@@ -1120,7 +1120,7 @@ static const char hlp_genkey[] =
   "\n"
   "  'p' and 'n' are the names of the RSA parameters; '-' is used to\n"
   "  indicate that HEXDATA is the first chunk of a parameter given\n"
-  "  by the next KEY-DATA.\n"
+  "  by the next KEY-DATA.  Only used by GnuPG version < 2.1.\n"
   "\n"
   "--force is required to overwrite an already existing key.  The\n"
   "KEY-CREATED-AT is required for further processing because it is\n"
index f7dbfd6..0a01bf5 100644 (file)
@@ -818,7 +818,7 @@ learn_status_cb (void *opaque, const char *line)
           parm->chvusage[0] = byte1;
           parm->chvusage[1] = byte2;
         }
-        break;
+      break;
 
     case 10:
       if (!memcmp (keyword, "PUBKEY-URL", keywordlen))
@@ -880,6 +880,13 @@ learn_status_cb (void *opaque, const char *line)
 
           xfree (buf);
         }
+      else if (!memcmp (keyword, "APPVERSION", keywordlen))
+        {
+          unsigned int val = 0;
+
+          sscanf (line, "%x", &val);
+          parm->appversion = val;
+        }
       break;
 
     case 11:
@@ -944,6 +951,13 @@ learn_status_cb (void *opaque, const char *line)
                 }
             }
         }
+      else if (!memcmp (keyword, "CARDVERSION", keywordlen))
+        {
+          unsigned int val = 0;
+
+          sscanf (line, "%x", &val);
+          parm->cardversion = val;
+        }
       break;
 
     case 12:
index bd450c0..89cefde 100644 (file)
@@ -781,11 +781,6 @@ list_openpgp (card_info_t info, estream_t fp)
       return;
     }
 
-  tty_fprintf (fp, "Version ..........: %.1s%c.%.1s%c\n",
-               info->serialno[12] == '0'?"":info->serialno+12,
-               info->serialno[13],
-               info->serialno[14] == '0'?"":info->serialno+14,
-               info->serialno[15]);
   tty_fprintf (fp, "Manufacturer .....: %s\n",
                get_manufacturer (xtoi_2(info->serialno+16)*256
                                  + xtoi_2 (info->serialno+18)));
@@ -941,6 +936,25 @@ list_piv (card_info_t info, estream_t fp)
 }
 
 
+
+static void
+print_a_version (estream_t fp, const char *prefix, unsigned int value)
+{
+  unsigned int a, b, c, d;
+  a = ((value >> 24) & 0xff);
+  b = ((value >> 16) & 0xff);
+  c = ((value >>  8) & 0xff);
+  d = ((value      ) & 0xff);
+
+  if (a)
+    tty_fprintf (fp, "%s %u.%u.%u.%u\n", prefix, a, b, c, d);
+  else if (b)
+    tty_fprintf (fp, "%s %u.%u.%u\n", prefix, b, c, d);
+  else
+    tty_fprintf (fp, "%s %u.%u\n", prefix, c, d);
+}
+
+
 /* Print all available information about the current card. */
 static void
 list_card (card_info_t info)
@@ -951,6 +965,8 @@ list_card (card_info_t info)
                info->reader? info->reader : "[none]");
   if (info->cardtype)
     tty_fprintf (fp, "Card type ........: %s\n", info->cardtype);
+  if (info->cardversion)
+    print_a_version (fp, "Card firmware ....:", info->cardversion);
   tty_fprintf (fp, "Serial number ....: %s\n",
                info->serialno? info->serialno : "[none]");
   tty_fprintf (fp, "Application type .: %s%s%s%s\n",
@@ -959,9 +975,11 @@ list_card (card_info_t info)
                info->apptype == APP_TYPE_UNKNOWN && info->apptypestr
                ? info->apptypestr:"",
                info->apptype == APP_TYPE_UNKNOWN && info->apptypestr? ")":"");
+  if (info->appversion)
+    print_a_version (fp, "Version ..........:", info->appversion);
   if (info->serialno && info->dispserialno
       && strcmp (info->serialno, info->dispserialno))
-    tty_fprintf (fp, "Displayed S/N ....: %s\n", info->dispserialno);
+    tty_fprintf (fp, "Displayed s/n ....: %s\n", info->dispserialno);
 
   switch (info->apptype)
     {
@@ -2044,6 +2062,16 @@ cmd_generate (card_info_t info, char *argstr)
       keyref = keyref_buffer;
     }
 
+  /* Special checks.  */
+  if ((info->cardtype && !strcmp (info->cardtype, "yubikey"))
+      && info->cardversion >= 0x040200 && info->cardversion < 0x040305)
+    {
+      log_error ("On-chip key generation on this YubiKey has been blocked.\n");
+      log_info ("Please see <https://yubi.co/ysa201701> for details\n");
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      goto leave;
+    }
+
   /* Divert to dedicated functions.  */
   if (info->apptype == APP_TYPE_OPENPGP)
     {
index 3a86a67..099ea54 100644 (file)
@@ -142,8 +142,10 @@ struct card_info_s
   int error;         /* private. */
   char *reader;      /* Reader information.  */
   char *cardtype;    /* NULL or type of the card.  */
+  unsigned int cardversion; /* Firmware version of the card.  */
   char *apptypestr;  /* Malloced application type string.  */
   app_type_t apptype;/* Translated from APPTYPESTR.  */
+  unsigned int appversion; /* Version of the application.  */
   char *serialno;    /* malloced hex string. */
   char *dispserialno;/* malloced string. */
   char *disp_name;   /* malloced. */