Added more code fragments.
authorWerner Koch <wk@gnupg.org>
Mon, 4 Mar 2002 10:34:09 +0000 (10:34 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 4 Mar 2002 10:34:09 +0000 (10:34 +0000)
scd/card.c
scd/command.c
scd/scdaemon.h

index dbfbe53..543812d 100644 (file)
@@ -359,6 +359,28 @@ card_enum_keypairs (CARD card, int idx,
 
 
 \f
+static int
+idstr_to_id (const char *idstr, struct sc_pkcs15_id *id)
+{
+  const char *s;
+  int n;
+
+  /* For now we only support the standard DF */
+  if (strncmp (idstr, "3F005015.", 9) ) 
+    return GNUPG_Invalid_Id;
+  for (s=idstr+9, n=0; hexdigitp (s); s++, n++)
+    ;
+  if (*s || (n&1))
+    return GNUPG_Invalid_Id; /* invalid or odd number of digits */
+  n /= 2;
+  if (!n || n > SC_PKCS15_MAX_ID_SIZE)
+    return GNUPG_Invalid_Id; /* empty or too large */
+  for (s=idstr+9, n=0; *s; s += 2, n++)
+    id->value[n] = xtoi_2 (s);
+  id->len = n;
+  return 0;
+}
+
 /* Read the certificate identified by CERTIDSTR which is the
    hexadecimal encoded ID of the certificate, prefixed with the string
    "3F005015.". The certificate is return in DER encoded form in CERT
@@ -370,25 +392,14 @@ card_read_cert (CARD card, const char *certidstr,
   struct sc_pkcs15_id certid;
   struct sc_pkcs15_cert_info *certinfo;
   struct sc_pkcs15_cert      *certder;
-  const char *s;
-  int rc, n;
+  int rc;
 
   if (!card || !certidstr || !card->p15card || !cert || !ncert)
     return GNUPG_Invalid_Value;
 
-  /* For now we only support the standard DF */
-  if (strncmp (certidstr, "3F005015.", 9) ) 
-    return GNUPG_Invalid_Id;
-  for (s=certidstr+9, n=0; hexdigitp (s); s++, n++)
-    ;
-  if (*s || (n&1))
-    return GNUPG_Invalid_Id; /* invalid or odd number of digits */
-  n /= 2;
-  if (!n || n > SC_PKCS15_MAX_ID_SIZE)
-    return GNUPG_Invalid_Id; /* empty or too large */
-  for (s=certidstr+9, n=0; *s; s += 2, n++)
-    certid.value[n] = xtoi_2 (s);
-  certid.len = n;
+  rc = idstr_to_id (certidstr, &certid);
+  if (rc)
+    return rc;
 
   rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo);
   if (rc)
@@ -418,6 +429,75 @@ card_read_cert (CARD card, const char *certidstr,
 }
 
 
+\f
+/* Create the signature and return the allocated result in OUTDATA. */
+int 
+card_create_signature (CARD card, const char *keyidstr, int hashalgo,
+                       const void *indata, size_t indatalen,
+                       void **outdata, size_t *outdatalen )
+{
+  unsigned int cryptflags = 0;
+  struct sc_pkcs15_id keyid;
+  struct sc_pkcs15_prkey_info *key;
+  /*  struct sc_pkcs15_pin_info *pin;*/
+  int rc;
+  unsigned char *outbuf = NULL;
+  size_t outbuflen;
+
+  if (!card || !card->p15card || !indata || !indatalen
+      || !outdata || !outdatalen)
+    return GNUPG_Invalid_Value;
+  
+  if (hashalgo != GCRY_MD_SHA1)
+    return GNUPG_Unsupported_Algorithm;
+
+  rc = idstr_to_id (keyidstr, &keyid);
+  if (rc)
+    return rc;
+
+  rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &key);
+  if (rc < 0)
+    {
+      log_error ("private key not found: %s\n", sc_strerror(rc));
+      rc = GNUPG_No_Secret_Key;
+      goto leave;
+    }
+  rc = 0;
+  key = card->p15card->prkey_info;
+
+
+  /* FIXME: Handle PIN via callback */
+
+  cryptflags |= SC_PKCS15_HASH_SHA1;
+  cryptflags |= SC_PKCS15_PAD_PKCS1_V1_5;
 
+  outbuflen = 1024; 
+  outbuf = xtrymalloc (outbuflen);
+  if (!outbuf)
+    return GNUPG_Out_Of_Core;
+  
+  rc = sc_pkcs15_compute_signature (card->p15card, key,
+                                    cryptflags,
+                                    indata, indatalen,
+                                    outbuf, outbuflen );
+  if (rc < 0)
+    {
+      log_error ("failed to create signature: %s\n", sc_strerror (rc));
+      rc = GNUPG_Card_Error;
+    }
+  else
+    {
+      *outdatalen = rc;
+      *outdata = outbuf;
+      outbuf = NULL;
+      rc = 0;
+    }
+
+
+
+leave:
+  xfree (outbuf);
+  return rc;
+}
 
 
index b4eaa8a..e172484 100644 (file)
@@ -61,6 +61,8 @@ reset_notify (ASSUAN_CONTEXT ctx)
     {
       card_close (ctrl->card_ctx);
       ctrl->card_ctx = NULL;
+      xfree (ctrl->in_data.value);
+      ctrl->in_data.value = NULL;
     }
 }
 
@@ -72,6 +74,63 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
 }
 
 
+/* If the card has not yet been opened, do it.  Note that this
+   function returns an Assuan error, so don't map the error a second
+   time */
+static AssuanError
+open_card (CTRL ctrl)
+{
+  if (!ctrl->card_ctx)
+    {
+      int rc = card_open (&ctrl->card_ctx);
+      if (rc)
+        return map_to_assuan_status (rc);
+    }
+  return 0;
+}
+
+
+/* SERIALNO 
+
+   Return the serial number of the card using a status reponse.  This
+   functon should be used to check for the presence of a card.
+
+   This function is special in that it can be used to reset the card.
+   Most other functions will return an error when a card change has
+   been detected and the use of this function is therefore required.
+
+   Background: We want to keep the client clear of handling card
+   changes between operations; i.e. the client can assume that all
+   operations are doneon the same card unless he call this function.
+ */
+static int
+cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+  int rc = 0;
+  char *serial_and_stamp;
+  char *serial;
+  time_t stamp;
+
+  if ((rc = open_card (ctrl)))
+    return rc;
+
+  rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
+  if (rc)
+    return map_to_assuan_status (rc);
+  rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
+  xfree (serial);
+  if (rc < 0)
+    return ASSUAN_Out_Of_Core;
+  rc = 0;
+  assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
+  free (serial_and_stamp);
+  return 0;
+}
+
+
+
+
 /* LEARN [--force]
 
    Learn all useful information of the currently inserted card.  When
@@ -98,14 +157,8 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
   int rc = 0;
   int idx;
 
-  /* if this is the first command issued for a new card, open the card and 
-     and create a context */
-  if (!ctrl->card_ctx)
-    {
-      rc = card_open (&ctrl->card_ctx);
-      if (rc)
-        return map_to_assuan_status (rc);
-    }
+  if ((rc = open_card (ctrl)))
+    return rc;
 
   /* Unless the force option is used we try a shortcut by identifying
      the card using a serial number and inquiring the client with
@@ -221,12 +274,8 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
   unsigned char *cert;
   size_t ncert;
 
-  if (!ctrl->card_ctx)
-    {
-      rc = card_open (&ctrl->card_ctx);
-      if (rc)
-        return map_to_assuan_status (rc);
-    }
+  if ((rc = open_card (ctrl)))
+    return rc;
 
   rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
   if (rc)
@@ -244,6 +293,61 @@ cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
   return map_to_assuan_status (rc);
 }
 
+
+\f
+
+/* SETDATA <hexstring> 
+
+   The client should use this command to tell us the data he want to
+   sign.  */
+static int
+cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+  int n;
+  char *p;
+  unsigned char *buf;
+
+  /* parse the hexstring */
+  for (p=line,n=0; hexdigitp (p); p++, n++)
+    ;
+  if (*p)
+    return set_error (Parameter_Error, "invalid hexstring");
+  if ((n&1))
+    return set_error (Parameter_Error, "odd number of digits");
+  n /= 2;
+  buf = xtrymalloc (n);
+  if (!buf)
+    return ASSUAN_Out_Of_Core;
+
+  ctrl->in_data.value = buf;
+  ctrl->in_data.valuelen = n;
+  for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
+    buf[n] = xtoi_2 (p);
+  return 0;
+}
+
+
+
+/* PKSIGN <hexified_id>
+
+ */
+static int
+cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+  int rc;
+
+  if ((rc = open_card (ctrl)))
+    return rc;
+
+
+
+  return map_to_assuan_status (rc);
+}
+
+
+
 \f
 /* Tell the assuan library about our commands */
 static int
@@ -254,8 +358,11 @@ register_commands (ASSUAN_CONTEXT ctx)
     int cmd_id;
     int (*handler)(ASSUAN_CONTEXT, char *line);
   } table[] = {
+    { "SERIALNO", 0, cmd_serialno },
     { "LEARN", 0, cmd_learn },
     { "READCERT", 0, cmd_readcert },
+    { "SETDATA", 0,  cmd_setdata },
+    { "PKSIGN", 0,   cmd_pksign },
     { "",     ASSUAN_CMD_INPUT, NULL }, 
     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
     { NULL }
index e770124..4104e87 100644 (file)
@@ -61,6 +61,10 @@ struct card_ctx_s;
 struct server_control_s {
   struct server_local_s *server_local;
   struct card_ctx_s *card_ctx;
+  struct {
+    unsigned char *value;  
+    int valuelen;
+  } in_data;  /* helper to store the value we are going to sign */
 
 };
 typedef struct server_control_s *CTRL;