[PATCH] scd: fix keytocard

NIIBE Yutaka gniibe at fsij.org
Wed Apr 1 09:57:48 CEST 2015


Hello,

This patch is fix for the issue:
    https://bugs.g10code.com/gnupg/issue1846

The Patch consists of three parts.

(1) agent: Don't update key storage at the time of KEYTOCARD
(2) agent: Enhance LEARN command to have --force option to update key storage
(3) g10: Fix keyedit to call LEARN --force

This fix is not a perfect solution as there is a possibility (in
theory) that user would remove the smartcard after "keytocard" before
"quit", but I think that it's good enough in practice.


diff --git a/agent/agent.h b/agent/agent.h
index f60061e..d61e634 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -495,7 +495,7 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline,


 /*-- learncard.c --*/
-int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context);
+int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);


 /*-- cvt-openpgp.c --*/
diff --git a/agent/command.c b/agent/command.c
index 96fbf19..3188bbd 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1655,25 +1655,27 @@ cmd_get_confirmation (assuan_context_t ctx, char *line)

 

 static const char hlp_learn[] =
-  "LEARN [--send][--sendinfo]\n"
+  "LEARN [--send] [--sendinfo] [--force]\n"
   "\n"
   "Learn something about the currently inserted smartcard.  With\n"
   "--sendinfo information about the card is returned; with --send\n"
-  "the available certificates are returned as D lines.";
+  "the available certificates are returned as D lines; with --force\n"
+  "private key storage will be updated by the result.";
 static gpg_error_t
 cmd_learn (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err;
-  int send, sendinfo;
+  int send, sendinfo, force;

   send = has_option (line, "--send");
   sendinfo = send? 1 : has_option (line, "--sendinfo");
+  force = has_option (line, "--force");

   if (ctrl->restricted)
     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));

-  err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL);
+  err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
   return leave_cmd (ctx, err);
 }

@@ -2409,12 +2411,10 @@ cmd_keytocard (assuan_context_t ctx, char *line)
   gpg_error_t err = 0;
   unsigned char grip[20];
   gcry_sexp_t s_skey = NULL;
-  gcry_sexp_t s_pkey = NULL;
   unsigned char *keydata;
   size_t keydatalen, timestamplen;
   const char *serialno, *timestamp_str, *id;
   unsigned char *shadow_info = NULL;
-  unsigned char *shdkey;
   time_t timestamp;

   if (ctrl->restricted)
@@ -2492,48 +2492,8 @@ cmd_keytocard (assuan_context_t ctx, char *line)
   snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
   keydatalen += 10 + 19 - 1;
   err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
-  if (err)
-    {
-      xfree (keydata);
-      goto leave;
-    }
-  xfree (keydata);
-
-  err = agent_public_key_from_file (ctrl, grip, &s_pkey);
-  if (err)
-    goto leave;
-
-  shadow_info = make_shadow_info (serialno, id);
-  if (!shadow_info)
-    {
-      err = gpg_error (GPG_ERR_ENOMEM);
-      gcry_sexp_release (s_pkey);
-      goto leave;
-    }
-  keydatalen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
-  keydata = xtrymalloc (keydatalen);
-  if (keydata == NULL)
-    {
-      err = gpg_error_from_syserror ();
-      gcry_sexp_release (s_pkey);
-      goto leave;
-    }
-  gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
-  gcry_sexp_release (s_pkey);
-  err = agent_shadow_key (keydata, shadow_info, &shdkey);
   xfree (keydata);
-  xfree (shadow_info);
-  if (err)
-    {
-      log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
-      goto leave;
-    }
-
-  keydatalen = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
-  err = agent_write_private_key (grip, shdkey, keydatalen, 1);
-  xfree (shdkey);

- leave:
   return leave_cmd (ctx, err);
 }

diff --git a/agent/learncard.c b/agent/learncard.c
index 62569ce..b7ce633 100644
--- a/agent/learncard.c
+++ b/agent/learncard.c
@@ -299,7 +299,7 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
 /* Perform the learn operation.  If ASSUAN_CONTEXT is not NULL and
    SEND is true all new certificates are send back via Assuan.  */
 int
-agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context)
+agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
 {
   int rc;

diff --git a/g10/call-agent.c b/g10/call-agent.c
index 4bac8a0..fa643a1 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -673,7 +673,7 @@ learn_status_cb (void *opaque, const char *line)

 /* Call the scdaemon to learn about a smartcard */
 int
-agent_scd_learn (struct agent_card_info_s *info)
+agent_scd_learn (struct agent_card_info_s *info, int force)
 {
   int rc;
   struct default_inq_parm_s parm;
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 9c104e8..df570a4 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -77,7 +77,7 @@ struct agent_card_genkey_s {
 void agent_release_card_info (struct agent_card_info_s *info);

 /* Return card info. */
-int agent_scd_learn (struct agent_card_info_s *info);
+int agent_scd_learn (struct agent_card_info_s *info, int force);

 /* Send an APDU to the card.  */
 gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
diff --git a/g10/card-util.c b/g10/card-util.c
index 4b584bf..a291a07 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -81,7 +81,7 @@ change_pin (int unblock_v2, int allow_admin)
   struct agent_card_info_s info;
   int rc;

-  rc = agent_scd_learn (&info);
+  rc = agent_scd_learn (&info, 0);
   if (rc)
     {
       log_error (_("OpenPGP card not available: %s\n"),
@@ -374,7 +374,7 @@ card_status (estream_t fp, char *serialno, size_t serialnobuflen)
   if (serialno && serialnobuflen)
     *serialno = 0;

-  rc = agent_scd_learn (&info);
+  rc = agent_scd_learn (&info, 0);
   if (rc)
     {
       if (opt.with_colons)
@@ -1702,7 +1702,7 @@ factory_reset (void)
       but tries to find out something about the card first.
    */

-  err = agent_scd_learn (&info);
+  err = agent_scd_learn (&info, 0);
   if (gpg_err_code (err) == GPG_ERR_OBJ_TERM_STATE
       && gpg_err_source (err) == GPG_ERR_SOURCE_SCD)
     termstate = 1;
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 91f5dae..2f9469f 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1450,6 +1450,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
   char *answer = NULL;
   int redisplay = 1;
   int modified = 0;
+  int sec_shadowing = 0;
   int run_subkey_warnings = 0;
   int toggle;
   int have_commands = !!commands;
@@ -1836,8 +1837,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 		if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
 		  {
 		    redisplay = 1;
-		    /* Only the secret key has been modified; thus
-                       there is no need to set the modified flag.  */
+		    sec_shadowing = 1;
 		  }
 	      }
 	  }
@@ -1923,7 +1923,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 		if (card_store_subkey (node, 0))
 		  {
 		    redisplay = 1;
-		    /* FIXME:sec_modified = 1;*/
+		    sec_shadowing = 1;
 		  }
 	      }
 	    release_kbnode (node);
@@ -2182,7 +2182,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 	case cmdQUIT:
 	  if (have_commands)
 	    goto leave;
-	  if (!modified)
+	  if (!modified && !sec_shadowing)
 	    goto leave;
 	  if (!cpr_get_answer_is_yes ("keyedit.save.okay",
 				      _("Save changes? (y/N) ")))
@@ -2204,7 +2204,18 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                   break;
                 }
 	    }
-	  else
+
+	  if (sec_shadowing)
+	    {
+	      err = agent_scd_learn (NULL, 1);
+	      if (err)
+                {
+                  log_error (_("update failed: %s\n"), gpg_strerror (err));
+                  break;
+                }
+	    }
+
+	  if (!modified && !sec_shadowing)
 	    tty_printf (_("Key not changed so no update needed.\n"));

 	  if (update_trust)
diff --git a/g10/keygen.c b/g10/keygen.c
index 769e193..4b0398a 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -4487,7 +4487,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
   /* Send the learn command so that the agent creates a shadow key for
      card key.  We need to do that now so that we are able to create
      the self-signatures. */
-  err = agent_scd_learn (NULL);
+  err = agent_scd_learn (NULL, 0);
   if (err)
     {
       /* Oops: Card removed during generation.  */
-- 



More information about the Gnupg-devel mailing list