[git] GnuPG - branch, master, updated. gnupg-2.1.0-77-gdd65e21

by Werner Koch cvs at cvs.gnupg.org
Mon Dec 15 17:39:28 CET 2014


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  dd65e21cb4934b40e6f2f7a8095f39fd6d9971bc (commit)
      from  fc9a35d2dec2f838abac831fd88dca494773e082 (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 dd65e21cb4934b40e6f2f7a8095f39fd6d9971bc
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Dec 15 17:38:40 2014 +0100

    gpg: Add sub-command "factory-reset" to --card-edit.
    
    * common/util.h (GPG_ERR_OBJ_TERM_STATE): New.
    * scd/iso7816.c (map_sw): Add this error code.
    * scd/app-openpgp.c (do_getattr): Return the life cycle indicator.
    * scd/app.c (select_application): Allow a return value of
    GPG_ERR_OBJ_TERM_STATE.
    * scd/scdaemon.c (set_debug): Print the DBG_READER value.
    * g10/call-agent.c (start_agent): Print a status line for the
    termination state.
    (agent_scd_learn): Make arg "info" optional.
    (agent_scd_apdu): New.
    * g10/card-util.c (send_apdu): New.
    (factory_reset): New.
    (card_edit): Add command factory-reset.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/common/util.h b/common/util.h
index a6f8606..94878bc 100644
--- a/common/util.h
+++ b/common/util.h
@@ -38,7 +38,8 @@
 /* These error codes are used but not defined in the required
    libgpg-error version.  Define them here. */
 #if GPG_ERROR_VERSION_NUMBER < 0x011200  /* 1.18 */
-# define GPG_ERR_FORBIDDEN    251
+# define GPG_ERR_OBJ_TERM_STATE 225
+# define GPG_ERR_FORBIDDEN      251
 #endif
 
 
diff --git a/doc/DETAILS b/doc/DETAILS
index 9ad616c..ba2725f 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -765,6 +765,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
       - 4 :: No card available
       - 5 :: No card reader available
       - 6 :: No card support available
+      - 7 :: Card is in termination state
 
 *** SC_OP_FAILURE [<code>]
     An operation on a smartcard definitely failed.  Currently there is
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 43a5c4e..0450b81 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -343,6 +343,9 @@ start_agent (ctrl_t ctrl, int for_card)
             case GPG_ERR_NO_SCDAEMON:
               write_status_text (STATUS_CARDCTRL, "6");
               break;
+            case GPG_ERR_OBJ_TERM_STATE:
+              write_status_text (STATUS_CARDCTRL, "7");
+              break;
             default:
               write_status_text (STATUS_CARDCTRL, "4");
               log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
@@ -586,6 +589,8 @@ learn_status_cb (void *opaque, const char *line)
                     parm->extcap.ki = abool;
                   else if (!strcmp (p, "aac"))
                     parm->extcap.aac = abool;
+                  else if (!strcmp (p, "si"))
+                    parm->status_indicator = strtoul (p2, NULL, 10);
                 }
             }
           xfree (buf);
@@ -657,6 +662,9 @@ agent_scd_learn (struct agent_card_info_s *info)
   struct default_inq_parm_s parm;
   struct agent_card_info_s dummyinfo;
 
+  if (!info)
+    info = &dummyinfo;
+  memset (info, 0, sizeof *info);
   memset (&parm, 0, sizeof parm);
 
   rc = start_agent (NULL, 1);
@@ -675,11 +683,7 @@ agent_scd_learn (struct agent_card_info_s *info)
   if (rc)
     return rc;
 
-  if (!info)
-    info = &dummyinfo;
-
   parm.ctx = agent_ctx;
-  memset (info, 0, sizeof *info);
   rc = assuan_transact (agent_ctx, "LEARN --sendinfo",
                         dummy_data_cb, NULL, default_inq_cb, &parm,
                         learn_status_cb, info);
@@ -694,6 +698,63 @@ agent_scd_learn (struct agent_card_info_s *info)
 }
 
 
+/* Send an APDU to the current card.  On success the status word is
+   stored at R_SW.  With HEXAPDU being NULL only a RESET command is
+   send to scd.  With HEXAPDU being the string "undefined" the command
+   "SERIALNO undefined" is send to scd. */
+gpg_error_t
+agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
+{
+  gpg_error_t err;
+
+  /* Start the agent but not with the card flag so that we do not
+     autoselect the openpgp application.  */
+  err = start_agent (NULL, 0);
+  if (err)
+    return err;
+
+  if (!hexapdu)
+    {
+      err = assuan_transact (agent_ctx, "SCD RESET",
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+
+    }
+  else if (!strcmp (hexapdu, "undefined"))
+    {
+      err = assuan_transact (agent_ctx, "SCD SERIALNO undefined",
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+    }
+  else
+    {
+      char line[ASSUAN_LINELENGTH];
+      membuf_t mb;
+      unsigned char *data;
+      size_t datalen;
+
+      init_membuf (&mb, 256);
+
+      snprintf (line, DIM(line)-1, "SCD APDU %s", hexapdu);
+      err = assuan_transact (agent_ctx, line,
+                             membuf_data_cb, &mb, NULL, NULL, NULL, NULL);
+      if (!err)
+        {
+          data = get_membuf (&mb, &datalen);
+          if (!data)
+            err = gpg_error_from_syserror ();
+          else if (datalen < 2) /* Ooops */
+            err = gpg_error (GPG_ERR_CARD);
+          else
+            {
+              *r_sw = (data[datalen-2] << 8) | data[datalen-1];
+            }
+          xfree (data);
+        }
+    }
+
+  return err;
+}
+
+
 int
 agent_keytocard (const char *hexgrip, int keyno, int force,
                  const char *serialno, const char *timestamp)
diff --git a/g10/call-agent.h b/g10/call-agent.h
index a24941e..bcb5ae9 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -61,6 +61,7 @@ struct agent_card_info_s
     unsigned int ki:1;     /* Key import available.  */
     unsigned int aac:1;    /* Algorithm attributes are changeable.  */
   } extcap;
+  unsigned int status_indicator;
 };
 
 struct agent_card_genkey_s {
@@ -78,6 +79,9 @@ void agent_release_card_info (struct agent_card_info_s *info);
 /* Return card info. */
 int agent_scd_learn (struct agent_card_info_s *info);
 
+/* Send an APDU to the card.  */
+gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
+
 /* Update INFO with the attribute NAME. */
 int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
 
diff --git a/g10/card-util.c b/g10/card-util.c
index 0535c1d..b030fad 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -1635,6 +1635,169 @@ card_store_subkey (KBNODE node, int use)
 }
 
 
+
+/* Direct sending of an hex encoded APDU with error printing.  */
+static gpg_error_t
+send_apdu (const char *hexapdu, const char *desc, unsigned int ignore)
+{
+  gpg_error_t err;
+  unsigned int sw;
+
+  err = agent_scd_apdu (hexapdu, &sw);
+  if (err)
+    tty_printf ("sending card command %s failed: %s\n", desc,
+                gpg_strerror (err));
+  else if (!hexapdu || !strcmp (hexapdu, "undefined"))
+    ;
+  else if (ignore == 0xffff)
+    ; /* Ignore all status words.  */
+  else if (sw != 0x9000)
+    {
+      switch (sw)
+        {
+        case 0x6285: err = gpg_error (GPG_ERR_OBJ_TERM_STATE); break;
+        case 0x6982: err = gpg_error (GPG_ERR_BAD_PIN); break;
+        case 0x6985: err = gpg_error (GPG_ERR_USE_CONDITIONS); break;
+        default: err = gpg_error (GPG_ERR_CARD);
+        }
+      if (!(ignore && ignore == sw))
+        tty_printf ("card command %s failed: %s (0x%04x)\n", desc,
+                    gpg_strerror (err),  sw);
+    }
+  return err;
+}
+
+
+/* Do a factory reset after confirmation.  */
+static void
+factory_reset (void)
+{
+  struct agent_card_info_s info;
+  gpg_error_t err;
+  char *answer = NULL;
+  int termstate = 0;
+  int i;
+
+  /*  The code below basically does the same what this
+      gpg-connect-agent script does:
+
+        scd reset
+        scd serialno undefined
+        scd apdu 00 A4 04 00 06 D2 76 00 01 24 01
+        scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 81 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
+        scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
+        scd apdu 00 e6 00 00
+        scd reset
+        scd serialno undefined
+        scd apdu 00 A4 04 00 06 D2 76 00 01 24 01
+        scd apdu 00 44 00 00
+        /echo Card has been reset to factory defaults
+
+      but tries to find out something about the card first.
+   */
+
+  err = agent_scd_learn (&info);
+  if (gpg_err_code (err) == GPG_ERR_OBJ_TERM_STATE
+      && gpg_err_source (err) == GPG_ERR_SOURCE_SCD)
+    termstate = 1;
+  else if (err)
+    {
+      log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
+      return;
+    }
+
+  if (!termstate)
+    {
+      log_info (_("OpenPGP card no. %s detected\n"),
+                info.serialno? info.serialno : "[none]");
+      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"));
+          goto leave;
+        }
+
+      tty_printf ("\n");
+      log_info (_("Note: This command destroys all keys stored on the card!\n"));
+      tty_printf ("\n");
+      if (!cpr_get_answer_is_yes ("cardedit.factory-reset.proceed",
+                                  _("Continue? (y/N) ")))
+        goto leave;
+
+
+      answer = cpr_get ("cardedit.factory-reset.really",
+                        _("Really do a factory reset? (enter \"yes\") "));
+      cpr_kill_prompt ();
+      trim_spaces (answer);
+      if (strcmp (answer, "yes"))
+        goto leave;
+
+      /* 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. */
+      for (i=0; i < 4; i++)
+        send_apdu ("00200081084040404040404040", "VERIFY", 0xffff);
+      for (i=0; i < 4; i++)
+        send_apdu ("00200083084040404040404040", "VERIFY", 0xffff);
+
+      /* Send terminate datafile command.  */
+      err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
+      if (err)
+        goto leave;
+    }
+
+  /* The card is in termination state - reset and select again.  */
+  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. (no error checking here). */
+  send_apdu ("00A4040006D27600012401", "SELECT AID", 0xffff);
+
+  /* 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)
+    goto leave;
+
+ leave:
+  xfree (answer);
+  agent_release_card_info (&info);
+}
+
+
 

 /* Data used by the command parser.  This needs to be outside of the
    function scope to allow readline based command completion.  */
@@ -1644,7 +1807,7 @@ enum cmdids
     cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
     cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
     cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
-    cmdREADCERT, cmdUNBLOCK,
+    cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET,
     cmdINVCMD
   };
 
@@ -1676,6 +1839,7 @@ static struct
     { "passwd"  , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
     { "verify"  , cmdVERIFY, 0, N_("verify the PIN and list all data")},
     { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
+    { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
     /* Note, that we do not announce these command yet. */
     { "privatedo", cmdPRIVATEDO, 0, NULL },
     { "readcert", cmdREADCERT, 0, NULL },
@@ -1848,7 +2012,7 @@ card_edit (ctrl_t ctrl, strlist_t commands)
           for (i=0; cmds[i].name; i++ )
             if(cmds[i].desc
 	       && (!cmds[i].admin_only || (cmds[i].admin_only && allow_admin)))
-              tty_printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
+              tty_printf("%-14s %s\n", cmds[i].name, _(cmds[i].desc) );
           break;
 
 	case cmdADMIN:
@@ -1953,6 +2117,10 @@ card_edit (ctrl_t ctrl, strlist_t commands)
           change_pin (1, allow_admin);
           break;
 
+        case cmdFACTORYRESET:
+          factory_reset ();
+          break;
+
         case cmdQUIT:
           goto leave;
 
diff --git a/scd/apdu.h b/scd/apdu.h
index 2e518b1..7e30f76 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -53,7 +53,7 @@ enum {
   SW_CLA_NOT_SUP    = 0x6e00,
   SW_SUCCESS        = 0x9000,
 
-  /* The follwoing statuswords are no real ones but used to map host
+  /* The following statuswords are no real ones but used to map host
      OS errors into status words.  A status word is 16 bit so that
      those values can't be issued by a card. */
   SW_HOST_OUT_OF_CORE = 0x10001,  /* No way yet to differentiate
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index ac290c9..daf0310 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1073,10 +1073,10 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
     }
   if (table[idx].special == -2)
     {
-      char tmp[100];
+      char tmp[110];
 
       snprintf (tmp, sizeof tmp,
-                "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d sm=%d",
+                "gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d sm=%d si=%u",
                 app->app_local->extcap.get_challenge,
                 app->app_local->extcap.key_import,
                 app->app_local->extcap.change_force_chv,
@@ -1085,7 +1085,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
                 app->app_local->extcap.algo_attr_change,
                 (app->app_local->extcap.sm_supported
                  ? (app->app_local->extcap.sm_aes128? 7 : 2)
-                 : 0));
+                 : 0),
+                app->app_local->status_indicator);
       send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
       return 0;
     }
diff --git a/scd/app.c b/scd/app.c
index 1694ea1..5fa06b0 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -389,7 +389,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
     err = app_select_dinsig (app);
   if (err && is_app_allowed ("sc-hsm") && (!name || !strcmp (name, "sc-hsm")))
     err = app_select_sc_hsm (app);
-  if (err && name)
+  if (err && name && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE)
     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
 
  leave:
diff --git a/scd/iso7816.c b/scd/iso7816.c
index f1dbcff..3c43a4c 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -64,7 +64,7 @@ map_sw (int sw)
   switch (sw)
     {
     case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
-    case SW_TERM_STATE:     ec = GPG_ERR_CARD; break;
+    case SW_TERM_STATE:     ec = GPG_ERR_OBJ_TERM_STATE; break;
     case SW_WRONG_LENGTH:   ec = GPG_ERR_INV_VALUE; break;
     case SW_SM_NOT_SUP:     ec = GPG_ERR_NOT_SUPPORTED; break;
     case SW_CC_NOT_SUP:     ec = GPG_ERR_NOT_SUPPORTED; break;
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 763ce2d..7c786c2 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -344,7 +344,7 @@ set_debug (const char *level)
   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 
   if (opt.debug)
-    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s\n",
+    log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s\n",
               (opt.debug & DBG_COMMAND_VALUE)? " command":"",
               (opt.debug & DBG_MPI_VALUE    )? " mpi":"",
               (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
@@ -353,7 +353,8 @@ set_debug (const char *level)
               (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
               (opt.debug & DBG_HASHING_VALUE)? " hashing":"",
               (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"",
-              (opt.debug & DBG_CARD_IO_VALUE)? " cardio":"");
+              (opt.debug & DBG_CARD_IO_VALUE)? " cardio":"",
+              (opt.debug & DBG_READER_VALUE )? " reader":"");
 }
 
 

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

Summary of changes:
 common/util.h     |    3 +-
 doc/DETAILS       |    1 +
 g10/call-agent.c  |   69 +++++++++++++++++++--
 g10/call-agent.h  |    4 ++
 g10/card-util.c   |  172 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 scd/apdu.h        |    2 +-
 scd/app-openpgp.c |    7 ++-
 scd/app.c         |    2 +-
 scd/iso7816.c     |    2 +-
 scd/scdaemon.c    |    5 +-
 10 files changed, 252 insertions(+), 15 deletions(-)


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




More information about the Gnupg-commits mailing list