* pksign.c (agent_pksign): Detect whether a Smartcard is to be
authorWerner Koch <wk@gnupg.org>
Mon, 4 Mar 2002 10:34:51 +0000 (10:34 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 4 Mar 2002 10:34:51 +0000 (10:34 +0000)
used and divert the operation in this case.
* pkdecrypt.c (agent_pkdecrypt): Likewise
* findkey.c (agent_key_from_file): Add optional arg shadow_info
and have it return information about a shadowed key.
* protect.c (agent_get_shadow_info): New.
* protect.c (snext,sskip,smatch): Moved to
* sexp-parse.h: new file.
* divert-scd.c: New.

agent/ChangeLog
agent/Makefile.am
agent/agent.h
agent/call-scd.c
agent/command.c
agent/divert-scd.c
agent/pksign.c
agent/protect.c

index 63cc94a..72d2ba8 100644 (file)
@@ -6,6 +6,9 @@
        * findkey.c (agent_key_from_file): Add optional arg shadow_info
        and have it return information about a shadowed key.
        * protect.c (agent_get_shadow_info): New.
+
+       * protect.c (snext,sskip,smatch): Moved to
+       * sexp-parse.h: new file.
        * divert-scd.c: New.
        
 2002-02-27  Werner Koch  <wk@gnupg.org>
index d2b01b7..7ee2fb3 100644 (file)
@@ -37,7 +37,9 @@ gpg_agent_SOURCES = \
        protect.c \
        trustlist.c \
        divert-scd.c \
-       call-scd.c
+       call-scd.c \
+       sexp-parse.h
+
 
 gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a  \
                ../common/libcommon.a $(LIBGCRYPT_LIBS)
index 875e69b..56e89f0 100644 (file)
@@ -157,7 +157,8 @@ int divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
                       const char *shadow_info);
 
 /*-- call-scd.c --*/
-int agent_learn_card (void);
+int agent_card_learn (void);
+int agent_card_serialno (char **r_serialno);
 
 
 #endif /*AGENT_H*/
index 7905873..af4d59f 100644 (file)
@@ -102,7 +102,7 @@ start_scd (void)
 static AssuanError
 learn_status_cb (void *opaque, const char *line)
 {
-  struct learn_parm_s *parm = opaque;
+  /*  struct learn_parm_s *parm = opaque;*/
   const char *keyword = line;
   int keywordlen;
 
@@ -127,7 +127,7 @@ learn_status_cb (void *opaque, const char *line)
 /* Perform the learn command and return a list of all private keys
    stored on the card. */
 int
-agent_learn_card (void)
+agent_card_learn (void)
 {
   int rc;
   struct learn_parm_s parm;
@@ -151,3 +151,71 @@ agent_learn_card (void)
   return 0;
 }
 
+
+\f
+static AssuanError
+get_serialno_cb (void *opaque, const char *line)
+{
+  char **serialno = opaque;
+  const char *keyword = line;
+  const char *s;
+  int keywordlen, n;
+
+  for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+    ;
+  while (spacep (line))
+    line++;
+
+  if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+    {
+      if (*serialno)
+        return ASSUAN_Unexpected_Status;
+      for (n=0,s=line; hexdigitp (s); s++, n++)
+        ;
+      if (!n || (n&1)|| !(spacep (s) || !*s) )
+        return ASSUAN_Invalid_Status;
+      *serialno = xtrymalloc (n+1);
+      if (!*serialno)
+        return ASSUAN_Out_Of_Core;
+      memcpy (*serialno, line, n);
+      (*serialno)[n] = 0;
+    }
+  
+  return 0;
+}
+
+/* Return the serial number of the card or an appropriate error.  The
+   serial number is returned as a hext string. */
+int
+agent_card_serialno (char **r_serialno)
+{
+  int rc;
+  char *serialno = NULL;
+
+  rc = start_scd ();
+  if (rc)
+    return rc;
+
+  /* Hmm, do we really need this reset - scddaemon should do this or
+     we can do this if we for some reason figure out that the
+     operation might have failed due to a missing RESET.  Hmmm, I feel
+     this is really SCdaemon's duty */
+  rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
+  if (rc)
+    return map_assuan_err (rc);
+
+  rc = assuan_transact (scd_ctx, "SERIALNO",
+                        NULL, NULL, NULL, NULL,
+                        get_serialno_cb, &serialno);
+  if (rc)
+    {
+      xfree (serialno);
+      return map_assuan_err (rc);
+    }
+  *r_serialno = serialno;
+  return 0;
+}
+
+
+
+
index 4e448f5..bed9da6 100644 (file)
@@ -472,7 +472,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
 {
   int rc;
 
-  rc = agent_learn_card ();
+  rc = agent_card_learn ();
   if (rc)
     log_error ("agent_learn_card failed: %s\n", gnupg_strerror (rc));
   return map_to_assuan_status (rc);
index ca81929..0dc9c12 100644 (file)
 #include <sys/stat.h>
 
 #include "agent.h"
+#include "sexp-parse.h"
+
+
+
+static int
+ask_for_card (const unsigned char *shadow_info, char **r_kid)
+{
+  int rc, i;
+  const unsigned char *s;
+  size_t n;
+  char *serialno;
+  int no_card = 0;
+  char *desc;
+  char *want_sn, *want_kid;
+
+  *r_kid = NULL;
+  s = shadow_info;
+  if (*s != '(')
+    return GNUPG_Invalid_Sexp;
+  s++;
+  n = snext (&s);
+  if (!n)
+    return GNUPG_Invalid_Sexp;
+  want_sn = xtrymalloc (n+1);
+  if (!want_sn)
+    return GNUPG_Out_Of_Core;
+  memcpy (want_sn, s, n);
+  want_sn[n] = 0;
+  s += n;
+
+  n = snext (&s);
+  if (!n)
+    return GNUPG_Invalid_Sexp;
+  want_kid = xtrymalloc (n+1);
+  if (!want_kid)
+    {
+      xfree (want_sn);
+      return GNUPG_Out_Of_Core;
+    }
+  memcpy (want_kid, s, n);
+  want_kid[n] = 0;
+
+  for (;;)
+    {
+      rc = agent_card_serialno (&serialno);
+      if (!rc)
+        {
+          log_debug ("detected card with S/N %s\n", serialno);
+          i = strcmp (serialno, want_sn);
+          xfree (serialno);
+          serialno = NULL;
+          if (!i)
+            {
+              xfree (want_sn);
+              *r_kid = want_kid;
+              return 0; /* yes, we have the correct card */
+            }
+        }
+      else if (rc == GNUPG_Card_Not_Present)
+        {
+          log_debug ("no card present\n");
+          rc = 0;
+          no_card = 1;
+        }
+      else
+        {
+          log_error ("error accesing card: %s\n", gnupg_strerror (rc));
+        }
+
+      if (!rc)
+        {
+          if (asprintf (&desc,
+                    "%s:%%0A%%0A"
+                    "  \"%s\"",
+                    no_card? "Please insert the card with serial number" 
+                    : "Please remove the current card and "
+                    "insert the one with serial number",
+                    want_sn) < 0)
+            {
+              rc = GNUPG_Out_Of_Core;
+            }
+          else
+            {
+              rc = agent_get_confirmation (desc, NULL);
+              free (desc);
+            }
+        }
+      if (rc)
+        {
+          xfree (want_sn);
+          xfree (want_kid);
+          return rc;
+        }
+    }
+}
 
 
 
 int
 divert_pksign (GCRY_SEXP *s_sig, GCRY_SEXP s_hash, const char *shadow_info)
 {
+  int rc;
+  char *kid;
+
+  rc = ask_for_card (shadow_info, &kid);
+  if (rc)
+    return rc;
+
+  xfree (kid);
   return GNUPG_Not_Implemented;
 }
 
@@ -43,5 +147,17 @@ int
 divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
                   const char *shadow_info)
 {
+  int rc;
+  char *kid;
+
+  rc = ask_for_card (shadow_info, &kid);
+  if (rc)
+    return rc;
+
+  xfree (kid);
   return GNUPG_Not_Implemented;
 }
+
+
+
index 6ec37cd..bdf1ff4 100644 (file)
@@ -57,7 +57,7 @@ do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
   
   /* We encode the MD in this way:
    *
-   *      0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
+   *      0  1 PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
    *
    * PAD consists of FF bytes.
    */
index ea8e304..08f322b 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "agent.h"
 
+#include "sexp-parse.h"
+
 #define PROT_CIPHER        GCRY_CIPHER_AES
 #define PROT_CIPHER_STRING "aes"
 #define PROT_CIPHER_KEYLEN (128/8)
@@ -54,80 +56,6 @@ hash_passphrase (const char *passphrase, int hashalgo,
                  unsigned char *key, size_t keylen);
 
 
-
-/* Return the length of the next S-Exp part and update the pointer to
-   the first data byte.  0 is return on error */
-static size_t
-snext (unsigned char const **buf)
-{
-  const unsigned char *s;
-  int n;
-
-  s = *buf;
-  for (n=0; *s && *s != ':' && digitp (s); s++)
-    n = n*10 + atoi_1 (s);
-  if (!n || *s != ':')
-    return 0; /* we don't allow empty lengths */
-  *buf = s+1;
-  return n;
-}
-
-/* Skip over the S-Expression BUF points to and update BUF to point to
-   the chacter right behind.  DEPTH gives the initial number of open
-   lists and may be passed as a positive number to skip over the
-   remainder of an S-Expression if the current position is somewhere
-   in an S-Expression.  The function may return an error code if it
-   encounters an impossible conditions */
-static int
-sskip (unsigned char const **buf, int *depth)
-{
-  const unsigned char *s = *buf;
-  size_t n;
-  int d = *depth;
-  
-  while (d > 0)
-    {
-      if (*s == '(')
-        {
-          d++;
-          s++;
-        }
-      else if (*s == ')')
-        {
-          d--;
-          s++;
-        }
-      else
-        {
-          if (!d)
-            return GNUPG_Invalid_Sexp;
-          n = snext (&s);
-          if (!n)
-            return GNUPG_Invalid_Sexp; 
-          s += n;
-        }
-    }
-  *buf = s;
-  *depth = d;
-  return 0;
-}
-
-
-/* Check whether the the string at the address BUF points to matches
-   the token.  Return true on match and update BUF to point behind the
-   token. */
-static int
-smatch (unsigned char const **buf, size_t buflen, const char *token)
-{
-  size_t toklen = strlen (token);
-
-  if (buflen != toklen || memcmp (*buf, token, toklen))
-    return 0;
-  *buf += toklen;
-  return 1;
-}
-
-
 \f
 /* Calculate the MIC for a private key S-Exp. SHA1HASH should pint to
    a 20 byte buffer.  This function is suitable for any algorithms. */