g10: smartcard keygen change.
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 20 Oct 2016 04:30:47 +0000 (13:30 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 20 Oct 2016 04:30:47 +0000 (13:30 +0900)
* g10/call-agent.c (scd_genkey_cb_append_savedbytes): Remove.
(scd_genkey_cb): Only handle KEY-CREATED-AT and PROGRESS.
(agent_scd_genkey): Remove INFO argument.  CREATETIME is now in/out
argument.
(agent_readkey): Use READKEY --card instead of SCD READKEY.
* g10/keygen.c (gen_card_key): Use READKEY --card command of the agent
to retrieve public key information from card and let the agent make
a file for private key with shadow info.
--

This change removes gpg's KEY-DATA handling for SCD GENKEY.  Information
with KEY-DATA is simply not used.  Instead, it is read by READKEY --card
command of gpg-agent.  This can consolidate public key handling in a
single method by READKEY.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
g10/call-agent.c
g10/call-agent.h
g10/keygen.c

index 0fb392c..632cabe 100644 (file)
@@ -103,13 +103,6 @@ struct cache_nonce_parm_s
 };
 
 
-struct scd_genkey_parm_s
-{
-  struct agent_card_genkey_s *cgk;
-  char *savedbytes;     /* Malloced space to save key parameter chunks.  */
-};
-
-
 static gpg_error_t learn_status_cb (void *opaque, const char *line);
 
 
@@ -979,133 +972,50 @@ agent_scd_writekey (int keyno, const char *serialno,
 
 
 \f
-static gpg_error_t
-scd_genkey_cb_append_savedbytes (struct scd_genkey_parm_s *parm,
-                                 const char *line)
-{
-  gpg_error_t err = 0;
-  char *p;
-
-  if (!parm->savedbytes)
-    {
-      parm->savedbytes = xtrystrdup (line);
-      if (!parm->savedbytes)
-        err = gpg_error_from_syserror ();
-    }
-  else
-    {
-      p = xtrymalloc (strlen (parm->savedbytes) + strlen (line) + 1);
-      if (!p)
-        err = gpg_error_from_syserror ();
-      else
-        {
-          strcpy (stpcpy (p, parm->savedbytes), line);
-          xfree (parm->savedbytes);
-          parm->savedbytes = p;
-        }
-    }
-
-  return err;
-}
-
 /* Status callback for the SCD GENKEY command. */
 static gpg_error_t
 scd_genkey_cb (void *opaque, const char *line)
 {
-  struct scd_genkey_parm_s *parm = opaque;
+  u32 *createtime = opaque;
   const char *keyword = line;
   int keywordlen;
-  gpg_error_t rc = 0;
 
   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
     ;
   while (spacep (line))
     line++;
 
-  if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
-    {
-      parm->cgk->fprvalid = unhexify_fpr (line, parm->cgk->fpr);
-    }
-  else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
-    {
-      gcry_mpi_t a;
-      const char *name = line;
-
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-
-      if (*name == '-' && spacep (name+1))
-        rc = scd_genkey_cb_append_savedbytes (parm, line);
-      else
-        {
-          if (parm->savedbytes)
-            {
-              rc = scd_genkey_cb_append_savedbytes (parm, line);
-              if (!rc)
-                rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX,
-                                    parm->savedbytes, 0, NULL);
-            }
-          else
-            rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
-          if (rc)
-            log_error ("error parsing received key data: %s\n",
-                       gpg_strerror (rc));
-          else if (*name == 'n' && spacep (name+1))
-            parm->cgk->n = a;
-          else if (*name == 'e' && spacep (name+1))
-            parm->cgk->e = a;
-          else
-            {
-              log_info ("unknown parameter name in received key data\n");
-              gcry_mpi_release (a);
-              rc = gpg_error (GPG_ERR_INV_PARAMETER);
-            }
-
-          xfree (parm->savedbytes);
-          parm->savedbytes = NULL;
-        }
-    }
-  else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
+ if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
     {
-      parm->cgk->created_at = (u32)strtoul (line, NULL, 10);
+      *createtime = (u32)strtoul (line, NULL, 10);
     }
   else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen))
     {
       write_status_text (STATUS_PROGRESS, line);
     }
 
-  return rc;
+  return 0;
 }
 
-/* Send a GENKEY command to the SCdaemon.  SERIALNO is not used in
-   this implementation.  If CREATEDATE is not 0, it will be passed to
-   SCDAEMON so that the key is created with this timestamp.  INFO will
-   receive information about the generated key.  */
+/* Send a GENKEY command to the SCdaemon.  If CREATETIME is not 0, it
+  will be passed to SCDAEMON so that the key is created with this
+  timestamp.  On success, creation time  is stored back to CREATETIME.  */
 int
-agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
-                  const char *serialno, u32 createtime)
+agent_scd_genkey (int keyno, int force, u32 *createtime)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
   gnupg_isotime_t tbuf;
-  struct scd_genkey_parm_s parms;
   struct default_inq_parm_s dfltparm;
 
   memset (&dfltparm, 0, sizeof dfltparm);
 
-  (void)serialno;
-
-  memset (&parms, 0, sizeof parms);
-  parms.cgk = info;
-
   rc = start_agent (NULL, 1);
   if (rc)
     return rc;
 
-  if (createtime)
-    epoch2isotime (tbuf, createtime);
+  if (*createtime)
+    epoch2isotime (tbuf, *createtime);
   else
     *tbuf = 0;
 
@@ -1116,12 +1026,9 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
   line[DIM(line)-1] = 0;
 
   dfltparm.ctx = agent_ctx;
-  memset (info, 0, sizeof *info);
   rc = assuan_transact (agent_ctx, line,
                         NULL, NULL, default_inq_cb, &dfltparm,
-                        scd_genkey_cb, &parms);
-
-  xfree (parms.savedbytes);
+                        scd_genkey_cb, createtime);
 
   status_sc_op_failure (rc);
   return rc;
@@ -1854,7 +1761,8 @@ agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   if (err)
     return err;
 
-  snprintf (line, DIM(line)-1, "%sREADKEY %s", fromcard? "SCD ":"", hexkeygrip);
+  snprintf (line, DIM(line)-1, "READKEY %s%s", fromcard? "--card ":"",
+            hexkeygrip);
 
   init_membuf (&data, 1024);
   err = assuan_transact (agent_ctx, line,
index d85a6fd..032c345 100644 (file)
@@ -68,13 +68,6 @@ struct agent_card_info_s
   unsigned int status_indicator;
 };
 
-struct agent_card_genkey_s {
-  char fprvalid;
-  char fpr[20];
-  u32  created_at;
-  gcry_mpi_t n;
-  gcry_mpi_t e;
-};
 
 
 /* Release the card info structure. */
@@ -107,8 +100,7 @@ int agent_scd_writekey (int keyno, const char *serialno,
                         const unsigned char *keydata, size_t keydatalen);
 
 /* Send a GENKEY command to the SCdaemon. */
-int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
-                      const char *serialno, u32 createtime);
+int agent_scd_genkey (int keyno, int force, u32 *createtime);
 
 /* Send a READKEY command to the SCdaemon. */
 int agent_scd_readcert (const char *certidstr,
index 9cf314d..90f8544 100644 (file)
@@ -4870,9 +4870,14 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
 {
 #ifdef ENABLE_CARD_SUPPORT
   gpg_error_t err;
-  struct agent_card_genkey_s info;
   PACKET *pkt;
   PKT_public_key *pk;
+  char keyid[10];
+  unsigned char *public;
+  gcry_sexp_t s_key;
+
+  snprintf (keyid, DIM(keyid)-1, "OPENPGP.%d", keyno);
+  keyid[DIM(keyid)-1] = 0;
 
   if (algo != PUBKEY_ALGO_RSA)
     return gpg_error (GPG_ERR_PUBKEY_ALGO);
@@ -4888,7 +4893,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
     }
 
   /* Note: SCD knows the serialnumber, thus there is no point in passing it.  */
-  err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp);
+  err = agent_scd_genkey (keyno, 1, timestamp);
   /*  The code below is not used because we force creation of
    *  the a card key (3rd arg).
    * if (gpg_err_code (rc) == GPG_ERR_EEXIST)
@@ -4898,16 +4903,9 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
    *     tty_printf ("\n");
    *     if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
    *                                 _("Replace existing key? ")))
-   *       rc = agent_scd_genkey (&info, keyno, 1);
+   *       rc = agent_scd_genkey (keyno, 1, timestamp);
    *   }
   */
-  if (!err && (!info.n || !info.e))
-    {
-      log_error ("communication error with SCD\n");
-      gcry_mpi_release (info.n);
-      gcry_mpi_release (info.e);
-      err =  gpg_error (GPG_ERR_GENERAL);
-    }
   if (err)
     {
       log_error ("key generation failed: %s\n", gpg_strerror (err));
@@ -4916,30 +4914,40 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
       return err;
     }
 
-  /* Send the learn command so that the agent creates a shadow key for
+  /* Send the READKEY 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, 0);
+  err = agent_readkey (NULL, 1, keyid, &public);
+  if (err)
+    return err;
+  err = gcry_sexp_sscan (&s_key, NULL, public,
+                         gcry_sexp_canon_len (public, 0, NULL, NULL));
+  xfree (public);
+  if (err)
+    return err;
+
+  if (algo == PUBKEY_ALGO_RSA)
+    err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
+  else if (algo == PUBKEY_ALGO_ECDSA
+          || algo == PUBKEY_ALGO_EDDSA
+          || algo == PUBKEY_ALGO_ECDH )
+    err = ecckey_from_sexp (pk->pkey, s_key, algo);
+  else
+    err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+  gcry_sexp_release (s_key);
+
   if (err)
     {
-      /* Oops: Card removed during generation.  */
-      log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
-      xfree (pkt);
-      xfree (pk);
+      log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
+      free_public_key (pk);
       return err;
     }
 
-  if (*timestamp != info.created_at)
-    log_info ("NOTE: the key does not use the suggested creation date\n");
-  *timestamp = info.created_at;
-
-  pk->timestamp = info.created_at;
+  pk->timestamp = *timestamp;
   pk->version = 4;
   if (expireval)
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
-  pk->pkey[0] = info.n;
-  pk->pkey[1] = info.e;
 
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;