sm: Support generation of card-based ECDSA CSR.
[gnupg.git] / sm / call-agent.c
index 20d879f..6ac715f 100644 (file)
@@ -334,7 +334,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
                   unsigned char *digest, size_t digestlen, int digestalgo,
                   unsigned char **r_buf, size_t *r_buflen )
 {
-  int rc, i;
+  int rc, i, pkalgo;
   char *p, line[ASSUAN_LINELENGTH];
   membuf_t data;
   size_t len;
@@ -342,6 +342,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   unsigned char *sigbuf;
   size_t sigbuflen;
   struct default_inq_parm_s inq_parm;
+  gcry_sexp_t sig;
 
   (void)desc;
 
@@ -366,6 +367,23 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   if (digestlen*2 + 50 > DIM(line))
     return gpg_error (GPG_ERR_GENERAL);
 
+  /* Get the key type from the scdaemon. */
+  snprintf (line, DIM(line), "SCD READKEY %s", keyid);
+  init_membuf (&data, 1024);
+  rc = assuan_transact (agent_ctx, line,
+                        put_membuf_cb, &data, NULL, NULL, NULL, NULL);
+  if (rc)
+    {
+      xfree (get_membuf (&data, &len));
+      return rc;
+    }
+
+  p = get_membuf (&data, &len);
+  pkalgo = get_pk_algo_from_canon_sexp (p, len);
+  xfree (p);
+  if (!pkalgo)
+    return gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+
   p = stpcpy (line, "SCD SETDATA " );
   for (i=0; i < digestlen ; i++, p += 2 )
     sprintf (p, "%02X", digest[i]);
@@ -386,24 +404,31 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
     }
   sigbuf = get_membuf (&data, &sigbuflen);
 
-  /* Create an S-expression from it which is formatted like this:
-     "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" Fixme: If a card ever
-     creates non-RSA keys we need to change things. */
-  *r_buflen = 21 + 11 + sigbuflen + 4;
-  p = xtrymalloc (*r_buflen);
-  *r_buf = (unsigned char*)p;
-  if (!p)
+  switch(pkalgo)
     {
-      xfree (sigbuf);
-      return 0;
+    case GCRY_PK_RSA:
+      rc = gcry_sexp_build (&sig, NULL, "(sig-val(rsa(s%b)))",
+                            sigbuflen, sigbuf);
+      break;
+
+    case GCRY_PK_ECC:
+      rc = gcry_sexp_build (&sig, NULL, "(sig-val(ecdsa(r%b)(s%b)))",
+                            sigbuflen/2, sigbuf,
+                            sigbuflen/2, sigbuf + sigbuflen/2);
+      break;
+
+    default:
+      rc = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
+      break;
     }
-  p = stpcpy (p, "(7:sig-val(3:rsa(1:s" );
-  sprintf (p, "%u:", (unsigned int)sigbuflen);
-  p += strlen (p);
-  memcpy (p, sigbuf, sigbuflen);
-  p += sigbuflen;
-  strcpy (p, ")))");
   xfree (sigbuf);
+  if (rc)
+    return rc;
+
+  rc = make_canon_sexp (sig, r_buf, r_buflen);
+  gcry_sexp_release (sig);
+  if (rc)
+    return rc;
 
   assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
   return  0;