agent: Add --card option for READKEY.
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 20 Oct 2016 03:05:15 +0000 (12:05 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 20 Oct 2016 03:05:15 +0000 (12:05 +0900)
* agent/findkey.c (agent_write_shadow_key): New.
* agent/command-ssh.c (card_key_available): Use agent_write_shadow_key.
* agent/learncard.c (agent_handle_learn): Likewise.
* agent/command.c (cmd_readkey): Add --card option.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
agent/agent.h
agent/command-ssh.c
agent/command.c
agent/findkey.c
agent/learncard.c

index fe5ffba..a3ec457 100644 (file)
@@ -490,6 +490,9 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
                                  const unsigned char *s2ksalt,
                                  unsigned int s2kcount,
                                  unsigned char *key, size_t keylen);
+gpg_error_t agent_write_shadow_key (const unsigned char *grip,
+                                    const char *serialno, const char *keyid,
+                                    const unsigned char *pkbuf, int force);
 
 
 /*-- trustlist.c --*/
index 083b8d8..7bcda50 100644 (file)
@@ -2474,39 +2474,9 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
   if ( agent_key_available (grip) )
     {
       /* (Shadow)-key is not available in our key storage.  */
-      unsigned char *shadow_info;
-      unsigned char *tmp;
-
-      shadow_info = make_shadow_info (serialno, authkeyid);
-      if (!shadow_info)
-        {
-          err = gpg_error_from_syserror ();
-          xfree (pkbuf);
-          gcry_sexp_release (s_pk);
-          xfree (serialno);
-          xfree (authkeyid);
-          return err;
-        }
-      err = agent_shadow_key (pkbuf, shadow_info, &tmp);
-      xfree (shadow_info);
-      if (err)
-        {
-          log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err));
-          xfree (pkbuf);
-          gcry_sexp_release (s_pk);
-          xfree (serialno);
-          xfree (authkeyid);
-          return err;
-        }
-      xfree (pkbuf);
-      pkbuf = tmp;
-      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
-      assert (pkbuflen);
-
-      err = agent_write_private_key (grip, pkbuf, pkbuflen, 0);
+      err = agent_write_shadow_key (grip, serialno, authkeyid, pkbuf, 0);
       if (err)
         {
-          log_error (_("error writing key: %s\n"), gpg_strerror (err));
           xfree (pkbuf);
           gcry_sexp_release (s_pk);
           xfree (serialno);
index 1ecdf20..a291d5b 100644 (file)
@@ -988,8 +988,10 @@ cmd_genkey (assuan_context_t ctx, char *line)
 \f
 static const char hlp_readkey[] =
   "READKEY <hexstring_with_keygrip>\n"
+  "        --card <keyid>\n"
   "\n"
-  "Return the public key for the given keygrip.";
+  "Return the public key for the given keygrip or keyid.\n"
+  "With --card, private key file with card information will be created.";
 static gpg_error_t
 cmd_readkey (assuan_context_t ctx, char *line)
 {
@@ -997,10 +999,57 @@ cmd_readkey (assuan_context_t ctx, char *line)
   int rc;
   unsigned char grip[20];
   gcry_sexp_t s_pkey = NULL;
+  unsigned char *pkbuf = NULL;
+  size_t pkbuflen;
 
   if (ctrl->restricted)
     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
 
+  if (has_option_name (line, "--card"))
+    {
+      const char *keyid;
+      char *serialno = NULL;
+
+      keyid = skip_options (line);
+
+      rc = agent_card_getattr (ctrl, "SERIALNO", &serialno);
+      if (rc)
+        {
+          log_error (_("error getting serial number of card: %s\n"),
+                     gpg_strerror (rc));
+          goto leave;
+        }
+
+      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
+      rc = agent_card_readkey (ctrl, keyid, &pkbuf);
+      if (rc)
+        goto leave;
+      rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen);
+      if (rc)
+        goto leave;
+
+      if (!gcry_pk_get_keygrip (s_pkey, grip))
+        {
+          rc = gcry_pk_testkey (s_pkey);
+          if (rc == 0)
+            rc = gpg_error (GPG_ERR_INTERNAL);
+
+          goto leave;
+        }
+
+      rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0);
+      if (rc)
+        goto leave;
+
+      rc = assuan_send_data (ctx, pkbuf, pkbuflen);
+
+ leave:
+      xfree (serialno);
+      xfree (pkbuf);
+      gcry_sexp_release (s_pkey);
+      return leave_cmd (ctx, rc);
+    }
+
   rc = parse_keygrip (ctx, line, grip);
   if (rc)
     return rc; /* Return immediately as this is already an Assuan error code.*/
@@ -1008,20 +1057,16 @@ cmd_readkey (assuan_context_t ctx, char *line)
   rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
   if (!rc)
     {
-      size_t len;
-      unsigned char *buf;
-
-      len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
-      assert (len);
-      buf = xtrymalloc (len);
-      if (!buf)
+      pkbuflen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
+      assert (pkbuflen);
+      pkbuf = xtrymalloc (pkbuflen);
+      if (!pkbuf)
         rc = gpg_error_from_syserror ();
       else
         {
-          len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, buf, len);
-          assert (len);
-          rc = assuan_send_data (ctx, buf, len);
-          xfree (buf);
+          gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, pkbuflen);
+          rc = assuan_send_data (ctx, pkbuf, pkbuflen);
+          xfree (pkbuf);
         }
       gcry_sexp_release (s_pkey);
     }
index c5ab0e9..23e94f0 100644 (file)
@@ -1492,3 +1492,39 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
   gcry_sexp_release (s_skey);
   return err;
 }
+
+
+/* Write an S-expression formatted shadow key to our key storage.
+   Shadow key is created by an S-expression public key in PKBUF and
+   card's SERIALNO and the IDSTRING.  With FORCE passed as true an
+   existing key with the given GRIP will get overwritten.  */
+gpg_error_t
+agent_write_shadow_key (const unsigned char *grip,
+                        const char *serialno, const char *keyid,
+                        const unsigned char *pkbuf, int force)
+{
+  gpg_error_t err;
+  unsigned char *shadow_info;
+  unsigned char *shdkey;
+  size_t len;
+
+  shadow_info = make_shadow_info (serialno, keyid);
+  if (!shadow_info)
+    return gpg_error_from_syserror ();
+
+  err = agent_shadow_key (pkbuf, shadow_info, &shdkey);
+  xfree (shadow_info);
+  if (err)
+    {
+      log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
+  err = agent_write_private_key (grip, shdkey, len, force);
+  xfree (shdkey);
+  if (err)
+    log_error ("error writing key: %s\n", gpg_strerror (err));
+
+  return err;
+}
index e9304fb..103a821 100644 (file)
@@ -381,8 +381,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
 
   for (item = parm.info; item; item = item->next)
     {
-      unsigned char *pubkey, *shdkey;
-      size_t n;
+      unsigned char *pubkey;
 
       if (opt.verbose)
         log_info ("          id: %s    (grip=%s)\n", item->id, item->hexgrip);
@@ -410,33 +409,10 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
           goto leave;
         }
 
-      {
-        unsigned char *shadow_info = make_shadow_info (serialno, item->id);
-        if (!shadow_info)
-          {
-            rc = gpg_error (GPG_ERR_ENOMEM);
-            xfree (pubkey);
-            goto leave;
-          }
-        rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
-        xfree (shadow_info);
-      }
+      rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force);
       xfree (pubkey);
       if (rc)
-        {
-          log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
-          goto leave;
-        }
-      n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
-      assert (n);
-
-      rc = agent_write_private_key (grip, shdkey, n, force);
-      xfree (shdkey);
-      if (rc)
-        {
-          log_error ("error writing key: %s\n", gpg_strerror (rc));
-          goto leave;
-        }
+        goto leave;
 
       if (opt.verbose)
         log_info ("          id: %s - shadow key created\n", item->id);