[PATCH] agent: pksign result conversion to sexp to upper layer

NIIBE Yutaka gniibe at fsij.org
Mon Feb 25 01:47:31 CET 2013


Here is anoter patch in the smartcard ECDSA support series.

I think that some discussion would be needed for this implementation.

The call sequence in question is like this:

	agent/pksign.c:agent_pksign_do
	  -> agent/divert-scd.c:divert_pksign
	    ->  agent/call-scd.c:agent_card_pksign

This patch moves the conversion/building of SEXP structure from
agent_card_pksign to agent_pksign_do.

That's because lower layer of gpg-agent doesn't have the detail of the
information, such that what kind of key type, etc.

In this patch, we get the key type by agent_public_key_from_file and
build SEXP structure in agent_pksign_do.

Perhaps, the approach of completely opposite would be preferable.
That is, to let scdaemon build the SEXP structure, since scdaemon
has all relevant information.

In any cases, the changes will be similar for gpg-agent.  So, please
have a look.


diff --git a/agent/agent.h b/agent/agent.h
index 030b295..2fd0b8b 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -405,7 +405,8 @@ void agent_reload_trustlist (void);
 /*-- divert-scd.c --*/
 int divert_pksign (ctrl_t ctrl,
                    const unsigned char *digest, size_t digestlen, int algo,
-                   const unsigned char *shadow_info, unsigned char **r_sig);
+                   const unsigned char *shadow_info, unsigned char **r_sig,
+                   size_t *r_siglen);
 int divert_pkdecrypt (ctrl_t ctrl,
                       const unsigned char *cipher,
                       const unsigned char *shadow_info,
diff --git a/agent/call-scd.c b/agent/call-scd.c
index f4ea20b..a334b15 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -825,10 +825,6 @@ agent_card_pksign (ctrl_t ctrl,
   char *p, line[ASSUAN_LINELENGTH];
   membuf_t data;
   struct inq_needpin_s inqparm;
-  size_t len;
-  unsigned char *sigbuf;
-  size_t sigbuflen;
-  int prepend_nul;
 
   *r_buf = NULL;
   rc = start_scd (ctrl);
@@ -868,32 +864,13 @@ agent_card_pksign (ctrl_t ctrl,
 
   if (rc)
     {
+      size_t len;
+
       xfree (get_membuf (&data, &len));
       return unlock_scd (ctrl, rc);
     }
-  sigbuf = get_membuf (&data, &sigbuflen);
-
-  /* Create an S-expression from it which is formatted like this:
-     "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))".  We better make sure
-     that this won't be interpreted as a negative number.  */
-  prepend_nul = (sigbuflen && (*sigbuf & 0x80));
-
-  *r_buflen = 21 + 11 + prepend_nul + sigbuflen + 4;
-  p = xtrymalloc (*r_buflen);
-  *r_buf = (unsigned char*)p;
-  if (!p)
-    return unlock_scd (ctrl, out_of_core ());
-  p = stpcpy (p, "(7:sig-val(3:rsa(1:s" );
-  sprintf (p, "%u:", (unsigned int)sigbuflen + prepend_nul);
-  p += strlen (p);
-  if (prepend_nul)
-    *p++ = 0;
-  memcpy (p, sigbuf, sigbuflen);
-  p += sigbuflen;
-  strcpy (p, ")))");
-  xfree (sigbuf);
-
-  assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
+
+  *r_buf = get_membuf (&data, r_buflen);
   return unlock_scd (ctrl, 0);
 }
 
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index 5fb037e..f0d8473 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -335,7 +335,8 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
 int
 divert_pksign (ctrl_t ctrl,
                const unsigned char *digest, size_t digestlen, int algo,
-               const unsigned char *shadow_info, unsigned char **r_sig)
+               const unsigned char *shadow_info, unsigned char **r_sig,
+               size_t *r_siglen)
 {
   int rc;
   char *kid;
@@ -369,7 +370,10 @@ divert_pksign (ctrl_t ctrl,
     }
 
   if (!rc)
-    *r_sig = sigval;
+    {
+      *r_sig = sigval;
+      *r_siglen = siglen;
+    }
 
   xfree (kid);
 
diff --git a/agent/pksign.c b/agent/pksign.c
index dc44b88..1c56920 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -278,24 +278,105 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
   if (!s_skey)
     {
       /* Divert operation to the smartcard */
-
+      gcry_sexp_t s_pkey, l;
+      const char *name;
+      size_t len;
       unsigned char *buf = NULL;
-      size_t len = 0;
+      int is_RSA = 0, is_ECDSA = 0;
+
+      /* Check keytype by public key */
+      rc = agent_public_key_from_file (ctrl, ctrl->keygrip, &s_pkey);
+      if (rc)
+	{
+	  log_error ("failed to read the public key\n");
+	  goto leave;
+	}
+      l = gcry_sexp_cadr (s_pkey);
+      name = gcry_sexp_nth_data (l, 0, &len);
+      if (len == 3 && !memcmp (name, "rsa", 3))
+	is_RSA = 1;
+      else if (len == 5 && !memcmp (name, "ecdsa", 5))
+	is_ECDSA = 1;
+      gcry_sexp_release (l);
+      gcry_sexp_release (s_pkey);
 
       rc = divert_pksign (ctrl,
                           ctrl->digest.value,
                           ctrl->digest.valuelen,
                           ctrl->digest.algo,
-                          shadow_info, &buf);
+                          shadow_info, &buf, &len);
       if (rc)
         {
           log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
-      len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
-      assert (len);
 
-      rc = gcry_sexp_sscan (&s_sig, NULL, (char*)buf, len);
+      if (is_RSA)
+	{
+	  if (*buf & 0x80)
+	    {
+	      len++;
+	      buf = xtryrealloc (buf, len);
+	      if (!buf)
+		goto leave;
+
+	      memmove (buf + 1, buf, len - 1);
+	      *buf = 0;
+	    }
+
+	  rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", len, buf);
+	}
+      else if (is_ECDSA)
+	{
+	  unsigned char *r_buf, *s_buf;
+	  int r_buflen, s_buflen;
+
+	  r_buflen = s_buflen = len/2;
+
+	  if (*buf & 0x80)
+	    {
+	      r_buflen++;
+	      r_buf = xtrymalloc (r_buflen);
+	      if (!r_buf)
+		goto leave;
+
+	      memcpy (r_buf + 1, buf, len/2);
+	      *r_buf = 0;
+	    }
+	  else
+	    r_buf = buf;
+
+	  if (*(buf + len/2) & 0x80)
+	    {
+	      s_buflen++;
+	      s_buf = xtrymalloc (s_buflen);
+	      if (!s_buf)
+		{
+		  if (r_buflen > len/2)
+		    xfree (r_buf);
+
+		  goto leave;
+		}
+
+	      memcpy (s_buf + 1, buf + len/2, len/2);
+	      *s_buf = 0;
+	    }
+	  else
+	    s_buf = buf + len/2;
+
+	rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))",
+			      r_buflen, r_buf,
+			      s_buflen, s_buf);
+
+	if (r_buflen > len/2)
+	  xfree (r_buf);
+
+	if (s_buflen > len/2)
+	  xfree (s_buf);
+	}
+      else
+	rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+
       xfree (buf);
       if (rc)
 	{
-- 





More information about the Gnupg-devel mailing list