* tdbio.h, tdbio.c (tdbio_read_record, tdbio_write_record): Store trust
[gnupg.git] / scd / command.c
index 30191dd..aa410a6 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <ksba.h>
 
 #include "scdaemon.h"
 #include "../assuan/assuan.h"
@@ -150,7 +151,17 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
      S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
 
    If there is no certificate yet stored on the card a single "X" is
-   returned as the keygrip.
+   returned as the keygrip.  In addition to the keypair info, information
+   about all certificates stored on the card is also returned:
+
+     S CERTINFO <certtype> <hexstring_with_id>
+
+   Where CERTINFO is a number indicating the type of certificate:
+      0   := Unknown
+      100 := Regular X.509 cert
+      101 := Trusted X.509 cert
+      102 := Useful X.509 cert
+
 
 */
 static int
@@ -208,15 +219,41 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
     free (serial_and_stamp);
   }
 
+  /* Return information about the certificates. */
+  for (idx=0; !rc; idx++)
+    {
+      char *certid;
+      int certtype;
+
+      rc = card_enum_certs (ctrl->card_ctx, idx, &certid, &certtype);
+      if (!rc)
+        {
+          char *buf;
+
+          buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
+          if (!buf)
+            rc = GNUPG_Out_Of_Core;
+          else
+            {
+              sprintf (buf, "%d %s", certtype, certid);
+              assuan_write_status (ctx, "CERTINFO", buf);
+              xfree (buf);
+            }
+        }
+      xfree (certid);
+    }
+  if (rc == -1)
+    rc = 0;
+
+
+  /* Return information about the keys. */
   for (idx=0; !rc; idx++)
     {
       unsigned char keygrip[20];
-      unsigned char *keyid;
-      size_t nkeyid;
+      char *keyid;
       int no_cert = 0;
 
-      rc = card_enum_keypairs (ctrl->card_ctx, idx, 
-                               keygrip, &keyid, &nkeyid);
+      rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid);
       if (rc == GNUPG_Missing_Certificate && keyid)
         {
           /* this does happen with an incomplete personalized
@@ -231,7 +268,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
         {
           char *buf, *p;
 
-          buf = p = xtrymalloc (40+1+9+2*nkeyid+1);
+          buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
           if (!buf)
             rc = GNUPG_Out_Of_Core;
           else
@@ -246,11 +283,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
                     sprintf (p, "%02X", keygrip[i]);
                 }
               *p++ = ' ';
-              /* fixme: we need to get the pkcs-15 DF from the card function */
-              p = stpcpy (p, "3F005015.");
-              for (i=0; i < nkeyid; i++, p += 2)
-                sprintf (p, "%02X", keyid[i]);
-              *p = 0;
+              strcpy (p, keyid);
               assuan_write_status (ctx, "KEYPAIRINFO", buf);
               xfree (buf);
             }
@@ -297,6 +330,65 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
 }
 
 
+/* READKEY <hexified_certid>
+
+   Return the public key for the given cert or key ID as an standard
+   S-Expression.  */
+static int
+cmd_readkey (ASSUAN_CONTEXT ctx, char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+  int rc;
+  unsigned char *cert = NULL;
+  size_t ncert, n;
+  KsbaCert kc = NULL;
+  KsbaSexp p;
+
+  if ((rc = open_card (ctrl)))
+    return rc;
+
+  rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
+  if (rc)
+    {
+      log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
+      goto leave;
+    }
+      
+  kc = ksba_cert_new ();
+  if (!kc)
+    {
+      xfree (cert);
+      rc = GNUPG_Out_Of_Core;
+      goto leave;
+    }
+  rc = ksba_cert_init_from_mem (kc, cert, ncert);
+  if (rc)
+    {
+      log_error ("failed to parse the certificate: %s\n", ksba_strerror (rc));
+      rc = map_ksba_err (rc);
+      goto leave;
+    }
+
+  p = ksba_cert_get_public_key (kc);
+  if (!p)
+    {
+      rc = GNUPG_No_Public_Key;
+      goto leave;
+    }
+
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  rc = assuan_send_data (ctx, p, n);
+  rc = map_assuan_err (rc);
+  xfree (p);
+
+
+ leave:
+  ksba_cert_release (kc);
+  xfree (cert);
+  return map_to_assuan_status (rc);
+}
+
+
 \f
 
 /* SETDATA <hexstring> 
@@ -376,18 +468,26 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
   int rc;
   void *outdata;
   size_t outdatalen;
+  char *keyidstr;
 
   if ((rc = open_card (ctrl)))
     return rc;
 
-  rc = card_create_signature (ctrl->card_ctx,
-                              line, GCRY_MD_SHA1,
-                              pin_cb, ctx,
-                              ctrl->in_data.value, ctrl->in_data.valuelen,
-                              &outdata, &outdatalen);
+  /* We have to use a copy of the key ID because the function may use
+     the pin_cb which in turn uses the assuan line buffer and thus
+     overwriting the original line with the keyid */
+  keyidstr = strdup (line);
+  if (!keyidstr)
+    return ASSUAN_Out_Of_Core;
+  rc = card_sign (ctrl->card_ctx,
+                  keyidstr, GCRY_MD_SHA1,
+                  pin_cb, ctx,
+                  ctrl->in_data.value, ctrl->in_data.valuelen,
+                  &outdata, &outdatalen);
+  free (keyidstr);
   if (rc)
     {
-      log_error ("card_create_signature failed: %s\n", gnupg_strerror (rc));
+      log_error ("card_sign failed: %s\n", gnupg_strerror (rc));
     }
   else
     {
@@ -410,15 +510,20 @@ cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
   int rc;
   void *outdata;
   size_t outdatalen;
+  char *keyidstr;
 
   if ((rc = open_card (ctrl)))
     return rc;
 
+  keyidstr = strdup (line);
+  if (!keyidstr)
+    return ASSUAN_Out_Of_Core;
   rc = card_decipher (ctrl->card_ctx,
-                      line
+                      keyidstr
                       pin_cb, ctx,
                       ctrl->in_data.value, ctrl->in_data.valuelen,
                       &outdata, &outdatalen);
+  free (keyidstr);
   if (rc)
     {
       log_error ("card_create_signature failed: %s\n", gnupg_strerror (rc));
@@ -449,6 +554,7 @@ register_commands (ASSUAN_CONTEXT ctx)
     { "SERIALNO", 0, cmd_serialno },
     { "LEARN", 0, cmd_learn },
     { "READCERT", 0, cmd_readcert },
+    { "READKEY", 0,  cmd_readkey },
     { "SETDATA", 0,  cmd_setdata },
     { "PKSIGN", 0,   cmd_pksign },
     { "PKDECRYPT", 0,cmd_pkdecrypt },