Changes needed to support smartcards. Well, only _support_. There is
authorWerner Koch <wk@gnupg.org>
Thu, 28 Feb 2002 11:07:59 +0000 (11:07 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 28 Feb 2002 11:07:59 +0000 (11:07 +0000)
no real code yet.

23 files changed:
agent/ChangeLog
agent/Makefile.am
agent/agent.h
agent/command.c
agent/findkey.c
agent/gpg-agent.c
agent/keyformat.txt
agent/pkdecrypt.c
agent/pksign.c
agent/protect-tool.c
agent/protect.c
agent/query.c
common/errors.h
common/maperror.c
scd/Makefile.am
scd/card.c
scd/command.c
scd/scdaemon.c
scd/scdaemon.h
sm/ChangeLog
sm/call-agent.c
sm/call-dirmngr.c
sm/server.c

index 0c79306..63cc94a 100644 (file)
@@ -1,3 +1,22 @@
+2002-02-28  Werner Koch  <wk@gnupg.org>
+
+       * pksign.c (agent_pksign): Detect whether a Smartcard is to be
+       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.
+       * divert-scd.c: New.
+       
+2002-02-27  Werner Koch  <wk@gnupg.org>
+
+       * protect.c (agent_shadow_key): New.
+
+       * command.c (cmd_learn): New command LEARN.
+       * gpg-agent.c: New option --scdaemon-program.
+       * call-scd.c (start_scd): New. Based on query.c
+       * query.c: Add 2 more arguments to all uses of assuan_transact.
+
 2002-02-18  Werner Koch  <wk@gnupg.org>
 
        * findkey.c (unprotect): Show an error message for a bad passphrase.
index eb5fa7d..d2b01b7 100644 (file)
@@ -35,7 +35,9 @@ gpg_agent_SOURCES = \
        pkdecrypt.c \
        genkey.c \
        protect.c \
-       trustlist.c 
+       trustlist.c \
+       divert-scd.c \
+       call-scd.c
 
 gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a  \
                ../common/libcommon.a $(LIBGCRYPT_LIBS)
index a4cf862..875e69b 100644 (file)
@@ -36,6 +36,7 @@ struct {
   int batch;        /* batch mode */
   const char *homedir; /* configuration directory name */
   const char *pinentry_program; 
+  const char *scdaemon_program; 
   int no_grab;      /* don't let the pinentry grab the keyboard */
   unsigned long def_cache_ttl;
 
@@ -101,7 +102,8 @@ const char *trans (const char *text);
 void start_command_handler (int);
 
 /*-- findkey.c --*/
-GCRY_SEXP agent_key_from_file (const unsigned char *grip);
+GCRY_SEXP agent_key_from_file (const unsigned char *grip,
+                               unsigned char **shadow_info);
 int agent_key_available (const unsigned char *grip);
 
 /*-- query.c --*/
@@ -135,6 +137,11 @@ int agent_protect (const unsigned char *plainkey, const char *passphrase,
 int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
                      unsigned char **result, size_t *resultlen);
 int agent_private_key_type (const unsigned char *privatekey);
+int agent_shadow_key (const unsigned char *pubkey,
+                      const unsigned char *shadow_info,
+                      unsigned char **result);
+int agent_get_shadow_info (const unsigned char *shadowkey,
+                           unsigned char const **shadow_info);
 
 
 /*-- trustlist.c --*/
@@ -143,4 +150,14 @@ int agent_listtrusted (void *assuan_context);
 int agent_marktrusted (const char *name, const char *fpr, int flag);
 
 
+/*-- divert-scd.c --*/
+int divert_pksign (GCRY_SEXP *s_sig, GCRY_SEXP s_hash,
+                   const char *shadow_info);
+int divert_pkdecrypt (GCRY_SEXP *s_plain, GCRY_SEXP s_cipher,
+                      const char *shadow_info);
+
+/*-- call-scd.c --*/
+int agent_learn_card (void);
+
+
 #endif /*AGENT_H*/
index 0a32962..4e448f5 100644 (file)
@@ -462,6 +462,22 @@ cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
   return 0;
 }
 
+\f
+/* LEARN
+
+   Learn something about the currently inserted smartcard 
+ */
+static int
+cmd_learn (ASSUAN_CONTEXT ctx, char *line)
+{
+  int rc;
+
+  rc = agent_learn_card ();
+  if (rc)
+    log_error ("agent_learn_card failed: %s\n", gnupg_strerror (rc));
+  return map_to_assuan_status (rc);
+}
+
 
 \f
 /* Tell the assuan library about our commands */
@@ -485,6 +501,7 @@ register_commands (ASSUAN_CONTEXT ctx)
     { "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
     { "LISTTRUSTED",  0,  cmd_listtrusted },
     { "MARKTRUSTED",  0,  cmd_marktrusted },
+    { "LEARN",        0,  cmd_learn },
     { "",     ASSUAN_CMD_INPUT, NULL }, 
     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
     { NULL }
index 67e2834..14ad762 100644 (file)
@@ -95,9 +95,12 @@ unprotect (unsigned char **keybuf, const unsigned char *grip)
 
 
 /* Return the secret key as an S-Exp after locating it using the grip.
-   Returns NULL if key is not available. */
+   Returns NULL if key is not available or the operation should be
+   diverted to a token.  In the latter case shadow_info will point to
+   an allocated S-Expression with the shadow_info part from the
+   file. */
 GCRY_SEXP
-agent_key_from_file (const unsigned char *grip)
+agent_key_from_file (const unsigned char *grip, unsigned char **shadow_info)
 {
   int i, rc;
   char *fname;
@@ -108,6 +111,9 @@ agent_key_from_file (const unsigned char *grip)
   GCRY_SEXP s_skey;
   char hexgrip[40+4+1];
   
+  if (shadow_info)
+      *shadow_info = NULL;
+
   for (i=0; i < 20; i++)
     sprintf (hexgrip+2*i, "%02X", grip[i]);
   strcpy (hexgrip+40, ".key");
@@ -173,8 +179,30 @@ agent_key_from_file (const unsigned char *grip)
                    gnupg_strerror (rc));
       break;
     case PRIVATE_KEY_SHADOWED:
-      log_error ("shadowed private keys are not yet supported\n");
-      rc = GNUPG_Not_Implemented;
+      if (shadow_info)
+        {
+          const unsigned char *s;
+          size_t n;
+
+          rc = agent_get_shadow_info (buf, &s);
+          if (!rc)
+            {
+              n = gcry_sexp_canon_len (s, 0, NULL,NULL);
+              assert (n);
+              *shadow_info = xtrymalloc (n);
+              if (!*shadow_info)
+                rc = GNUPG_Out_Of_Core;
+              else
+                {
+                  memcpy (*shadow_info, s, n);
+                  rc = 0;
+                }
+            }
+          if (rc)
+            log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
+        }
+      rc = -1; /* ugly interface: we return an error but keep a value
+                  in shadow_info.  */
       break;
     default:
       log_error ("invalid private key format\n");
index 5e014bb..ca49a84 100644 (file)
@@ -69,6 +69,7 @@ enum cmd_and_opt_values
   oBatch,
   
   oPinentryProgram,
+  oScdaemonProgram,
   oDefCacheTTL,
 
 aTest };
@@ -92,7 +93,8 @@ static ARGPARSE_OPTS opts[] = {
   { oNoGrab, "no-grab"     ,0, N_("do not grab keyboard and mouse")},
   { oLogFile, "log-file"   ,2, N_("use a log file for the server")},
 
-  { oPinentryProgram, "pinentry-program", 2 , "path of PIN Entry program" },
+  { oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" },
+  { oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" },
   { oDefCacheTTL, "default-cache-ttl", 4,
                                  "|N|expire cached PINs after N seconds"},
 
@@ -372,6 +374,7 @@ main (int argc, char **argv )
         case oServer: pipe_server = 1; break;
 
         case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
+        case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break;
         case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break;
 
         default : pargs.err = configfp? 1:2; break;
index ab2ad65..bfb4ee4 100644 (file)
@@ -4,7 +4,8 @@ keyformat.txt (wk 2001-12-18)
 
 Some notes on the format of the secret keys used with gpg-agent.
 
-
+Location of keys
+================
 The secret keys[1] are stored on a per file basis in a directory below
 the ~/.gnupg home directory.  This directory is named
 
@@ -13,9 +14,12 @@ the ~/.gnupg home directory.  This directory is named
 and should have permissions 700.
 
 The secret keys are stored in files with a name matching the
-hexadecimal representation of the keygrip[2].  The content of the file
-is an S-Expression like the ones used with Libgcrypt.  Here is an
-example of an unprotected file:
+hexadecimal representation of the keygrip[2].
+
+Unprotected Private Key Format
+==============================
+The content of the file is an S-Expression like the ones used with
+Libgcrypt.  Here is an example of an unprotected file:
 
 (private-key
  (rsa
@@ -47,8 +51,9 @@ keys is in canonical representation[3]:
 )  
 
 
-
-This describes an unprotected key; a protected key is like this:
+Protected Private Key Format
+==============================
+A protected key is like this:
 
 (protected-private-key
    (rsa
@@ -116,12 +121,35 @@ the stored one - If they don't match the integrity of the key is not
 given.
 
 
+Shadowed Private Key Format
+============================
+To keep track of keys stored on IC cards we use a third format for
+private kyes which are called shadow keys as they are only a reference
+to keys stored on a token:
+
+(shadowed-private-key
+   (rsa
+    (n #00e0ce9..[some bytes not shown]..51#)
+    (e #010001#)
+    (shadowed protocol (info))
+   )
+   (uri http://foo.bar x-foo:whatever_you_want)
+)  
+
+The currently used protocol is "ti-v1" (token info version 1).  The
+second list with the information has this layout:
+
+(card_serial_number id_string_of_key)
+
+More items may be added to the list.
 
 
 
 
-Notes:
 
+
+Notes:
+======
 [1] I usually use the terms private and secret key exchangeable but prefer the
 term secret key because it can be visually be better distinguished
 from the term public key.
index 78f70ad..33663a9 100644 (file)
@@ -39,6 +39,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
                  FILE *outfp) 
 {
   GCRY_SEXP s_skey = NULL, s_cipher = NULL, s_plain = NULL;
+  unsigned char *shadow_info = NULL;
   int rc;
   char *buf = NULL;
   size_t len;
@@ -63,27 +64,38 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
       log_printhex ("keygrip:", ctrl->keygrip, 20);
       log_printhex ("cipher: ", ciphertext, ciphertextlen);
     }
-  s_skey = agent_key_from_file (ctrl->keygrip);
-  if (!s_skey)
+  s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info);
+  if (!s_skey && !shadow_info)
     {
       log_error ("failed to read the secret key\n");
       rc = seterr (No_Secret_Key);
       goto leave;
     }
-
-  if (DBG_CRYPTO)
-    {
-      log_debug ("skey: ");
-      gcry_sexp_dump (s_skey);
+  if (!s_skey)
+    { /* divert operation to the smartcard */
+      rc = divert_pkdecrypt (&s_plain, s_cipher, shadow_info);
+      if (rc)
+        {
+          log_error ("smartcard decryption failed: %s\n", gnupg_strerror (rc));
+          goto leave;
+        }
     }
+  else
+    { /* no smartcard, but a private key */
+      if (DBG_CRYPTO)
+        {
+          log_debug ("skey: ");
+          gcry_sexp_dump (s_skey);
+        }
 
-  rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
-  if (rc)
-    {
-      log_error ("decryption failed: %s\n", gcry_strerror (rc));
-      rc = map_gcry_err (rc);
-      goto leave;
-    }
+      rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
+      if (rc)
+        {
+          log_error ("decryption failed: %s\n", gcry_strerror (rc));
+          rc = map_gcry_err (rc);
+          goto leave;
+        }
+    }      
 
   if (DBG_CRYPTO)
     {
@@ -106,6 +118,7 @@ agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
   gcry_sexp_release (s_plain);
   gcry_sexp_release (s_cipher);
   xfree (buf);
+  xfree (shadow_info);
   return rc;
 }
 
index 9d1ad4f..6ec37cd 100644 (file)
@@ -90,6 +90,7 @@ agent_pksign (CTRL ctrl, FILE *outfp)
 {
   GCRY_SEXP s_skey = NULL, s_hash = NULL, s_sig = NULL;
   GCRY_MPI frame = NULL;
+  unsigned char *shadow_info = NULL;
   int rc;
   char *buf = NULL;
   size_t len;
@@ -97,39 +98,50 @@ agent_pksign (CTRL ctrl, FILE *outfp)
   if (!ctrl->have_keygrip)
     return seterr (No_Secret_Key);
 
-  s_skey = agent_key_from_file (ctrl->keygrip);
-  if (!s_skey)
+  s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info);
+  if (!s_skey && !shadow_info)
     {
       log_error ("failed to read the secret key\n");
       rc = seterr (No_Secret_Key);
       goto leave;
     }
 
-  /* put the hash into a sexp */
+  /* put the hash into a sexp FIXME: this belongs into libgcrypt/divert-scd.c*/
   rc = do_encode_md (ctrl->digest.value,
                      ctrl->digest.valuelen,
                      ctrl->digest.algo,
                      gcry_pk_get_nbits (s_skey),
                      &frame);
   if (rc)
-      goto leave;
+    goto leave;
   if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
     BUG ();
 
-  if (DBG_CRYPTO)
-    {
-      log_debug ("skey: ");
-      gcry_sexp_dump (s_skey);
+  if (!s_skey)
+    { /* divert operation to the smartcard */
+      rc = divert_pksign (&s_sig, s_hash, shadow_info);
+      if (rc)
+        {
+          log_error ("smartcard signing failed: %s\n", gnupg_strerror (rc));
+          goto leave;
+        }
     }
-
-
-  /* sign */
-  rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
-  if (rc)
-    {
-      log_error ("signing failed: %s\n", gcry_strerror (rc));
-      rc = map_gcry_err (rc);
-      goto leave;
+  else
+    { /* no smartcard, but a private key */
+      if (DBG_CRYPTO)
+        {
+          log_debug ("skey: ");
+          gcry_sexp_dump (s_skey);
+        }
+
+      /* sign */
+      rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
+      if (rc)
+        {
+          log_error ("signing failed: %s\n", gcry_strerror (rc));
+          rc = map_gcry_err (rc);
+          goto leave;
+        }
     }
 
   if (DBG_CRYPTO)
@@ -138,7 +150,6 @@ agent_pksign (CTRL ctrl, FILE *outfp)
       gcry_sexp_dump (s_sig);
     }
 
-
   len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
   assert (len);
   buf = xmalloc (len);
@@ -156,6 +167,7 @@ agent_pksign (CTRL ctrl, FILE *outfp)
   gcry_sexp_release (s_sig);
   gcry_mpi_release (frame);
   xfree (buf);
+  xfree (shadow_info);
   return rc;
 }
 
index df58290..e106628 100644 (file)
@@ -49,6 +49,8 @@ enum cmd_and_opt_values
   oUnprotect      = 'u',
   
   oNoVerbose = 500,
+  oShadow,
+  oShowShadowInfo,
 
 aTest };
 
@@ -65,6 +67,8 @@ static ARGPARSE_OPTS opts[] = {
   { oPassphrase, "passphrase", 2, "|STRING| Use passphrase STRING" },
   { oProtect, "protect",     256, "protect a private key"},
   { oUnprotect, "unprotect", 256, "unprotect a private key"},
+  { oShadow,  "shadow", 256, "create a shadow entry for a priblic key"},
+  { oShowShadowInfo,  "show-shadow-info", 256, "return the shadow info"},
 
   {0}
 };
@@ -125,8 +129,7 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
     case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
     case GCRY_LOG_BUG:  level = JNLIB_LOG_BUG; break;
     case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
-    default:            level = JNLIB_LOG_ERROR; break;  
-    }
+    default:            level = JNLIB_LOG_ERROR; break;      }
   log_logv (level, fmt, arg_ptr);
 }
 
@@ -291,6 +294,79 @@ read_and_unprotect (const char *fname)
 }
 
 
+\f
+static void
+read_and_shadow (const char *fname)
+{
+  int  rc;
+  unsigned char *key;
+  unsigned char *result;
+  size_t resultlen;
+  
+  key = read_key (fname);
+  if (!key)
+    return;
+
+  rc = agent_shadow_key (key, "(8:313233342:43)", &result);
+  xfree (key);
+  if (rc)
+    {
+      log_error ("shadowing the key failed: %s\n", gnupg_strerror (rc));
+      return;
+    }
+  resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
+  assert (resultlen);
+  
+  if (opt_armor)
+    {
+      char *p = make_advanced (result, resultlen);
+      xfree (result);
+      if (!p)
+        return;
+      result = p;
+      resultlen = strlen (p);
+    }
+
+  fwrite (result, resultlen, 1, stdout);
+  xfree (result);
+}
+
+static void
+show_shadow_info (const char *fname)
+{
+  int  rc;
+  unsigned char *key;
+  const unsigned char *info;
+  size_t infolen;
+  
+  key = read_key (fname);
+  if (!key)
+    return;
+
+  rc = agent_get_shadow_info (key, &info);
+  xfree (key);
+  if (rc)
+    {
+      log_error ("get_shadow_info failed: %s\n", gnupg_strerror (rc));
+      return;
+    }
+  infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
+  assert (infolen);
+  
+  if (opt_armor)
+    {
+      char *p = make_advanced (info, infolen);
+      if (!p)
+        return;
+      fwrite (p, strlen (p), 1, stdout);
+      xfree (p);
+    }
+  else
+    fwrite (info, infolen, 1, stdout);
+}
+
+
+
 
 int
 main (int argc, char **argv )
@@ -325,6 +401,8 @@ main (int argc, char **argv )
 
         case oProtect: cmd = oProtect; break;
         case oUnprotect: cmd = oUnprotect; break;
+        case oShadow: cmd = oShadow; break;
+        case oShowShadowInfo: cmd = oShowShadowInfo; break;
 
         case oPassphrase: passphrase = pargs.r.ret_str; break;
 
@@ -341,6 +419,10 @@ main (int argc, char **argv )
     read_and_protect (*argv);
   else if (cmd == oUnprotect)
     read_and_unprotect (*argv);
+  else if (cmd == oShadow)
+    read_and_shadow (*argv);
+  else if (cmd == oShowShadowInfo)
+    show_shadow_info (*argv);
   else
     log_info ("no action requested\n");
 
index 115a945..ea8e304 100644 (file)
@@ -780,7 +780,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
    PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
    value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
    PRIVATE_KEY_PROTECTED for an protected private key or
-   PRIVATE_KEY_SHADOWED for a sub key where the secret parts are store
+   PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
    elsewhere. */
 int
 agent_private_key_type (const unsigned char *privatekey)
@@ -886,3 +886,154 @@ hash_passphrase (const char *passphrase, int hashalgo,
 }
 
 
+\f
+/* Create a shadow key from a public key.  We use the shadow protocol
+  "ti-v1" and insert the S-expressionn SHADOW_INFO.  The resulting
+  S-expression is returned in an allocated buffer RESULT will point
+  to. The input parameters are expected to be valid canonilized
+  S-expressions */
+int 
+agent_shadow_key (const unsigned char *pubkey,
+                  const unsigned char *shadow_info,
+                  unsigned char **result)
+{
+  const unsigned char *s;
+  const unsigned char *point;
+  size_t n;
+  int depth = 0;
+  unsigned char *p;
+  size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
+  size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
+
+  if (!pubkey_len || !shadow_info_len)
+    return GNUPG_Invalid_Value;
+  s = pubkey;
+  if (*s != '(')
+    return GNUPG_Invalid_Sexp;
+  depth++;
+  s++;
+  n = snext (&s);
+  if (!n)
+    return GNUPG_Invalid_Sexp; 
+  if (!smatch (&s, n, "public-key"))
+    return GNUPG_Unknown_Sexp; 
+  if (*s != '(')
+    return GNUPG_Unknown_Sexp;
+  depth++;
+  s++;
+  n = snext (&s); 
+  if (!n)
+    return GNUPG_Invalid_Sexp; 
+  s += n; /* skip over the algorithm name */
+
+  while (*s != ')')
+    {
+      if (*s != '(')
+        return GNUPG_Invalid_Sexp;
+      depth++;
+      s++;
+      n = snext (&s);
+      if (!n) 
+        return GNUPG_Invalid_Sexp; 
+      s += n;
+      n = snext (&s);
+      if (!n)
+        return GNUPG_Invalid_Sexp; 
+      s +=n; /* skip value */
+      if (*s != ')')
+        return GNUPG_Invalid_Sexp; 
+      depth--;
+      s++;
+    }
+  point = s; /* insert right before the point */
+  depth--;
+  s++;
+  assert (depth == 1);
+
+  /* calculate required length by taking in account: the "shadowed-"
+     prefix, the "shadowed", "t1-v1" as well as some parenthesis */
+  n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
+  *result = p = xtrymalloc (n);
+  if (!p)
+      return GNUPG_Out_Of_Core;
+  p = stpcpy (p, "(20:shadowed-private-key");
+  /* (10:public-key ...)*/
+  memcpy (p, pubkey+14, point - (pubkey+14));
+  p += point - (pubkey+14);
+  p = stpcpy (p, "(8:shadowed5:t1-v1");
+  memcpy (p, shadow_info, shadow_info_len);
+  p += shadow_info_len;
+  *p++ = ')';
+  memcpy (p, point, pubkey_len - (point - pubkey));
+  p += pubkey_len - (point - pubkey);
+
+  return 0;
+}
+
+/* Parse a canonical encoded shadowed key and return a pointer to the
+   inner list with the shadow_info */
+int 
+agent_get_shadow_info (const unsigned char *shadowkey,
+                       unsigned char const **shadow_info)
+{
+  const unsigned char *s;
+  size_t n;
+  int depth = 0;
+
+  s = shadowkey;
+  if (*s != '(')
+    return GNUPG_Invalid_Sexp;
+  depth++;
+  s++;
+  n = snext (&s);
+  if (!n)
+    return GNUPG_Invalid_Sexp; 
+  if (!smatch (&s, n, "shadowed-private-key"))
+    return GNUPG_Unknown_Sexp; 
+  if (*s != '(')
+    return GNUPG_Unknown_Sexp;
+  depth++;
+  s++;
+  n = snext (&s); 
+  if (!n)
+    return GNUPG_Invalid_Sexp; 
+  s += n; /* skip over the algorithm name */
+
+  for (;;)
+    {
+      if (*s == ')')
+        return GNUPG_Unknown_Sexp;
+      if (*s != '(')
+        return GNUPG_Invalid_Sexp;
+      depth++;
+      s++;
+      n = snext (&s);
+      if (!n) 
+        return GNUPG_Invalid_Sexp; 
+      if (smatch (&s, n, "shadowed"))
+        break;
+      s += n;
+      n = snext (&s);
+      if (!n)
+        return GNUPG_Invalid_Sexp; 
+      s +=n; /* skip value */
+      if (*s != ')')
+        return GNUPG_Invalid_Sexp; 
+      depth--;
+      s++;
+    }
+  /* found the shadowed list, s points to the protocol */
+  n = snext (&s);
+  if (!n) 
+    return GNUPG_Invalid_Sexp; 
+  if (smatch (&s, n, "t1-v1"))
+    {
+      if (*s != '(')
+        return GNUPG_Invalid_Sexp;
+      *shadow_info = s;
+    }
+  else
+    return GNUPG_Unsupported_Protocol;
+  return 0;
+}
+
index 1abfefc..795e214 100644 (file)
@@ -97,7 +97,7 @@ start_pinentry (void)
 
   rc = assuan_transact (entry_ctx, 
                         opt.no_grab? "OPTION no-grab":"OPTION grab",
-                        NULL, NULL, NULL, NULL);
+                        NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -160,14 +160,14 @@ agent_askpin (const char *desc_text, const char *start_err_text,
 
   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
   rc = assuan_transact (entry_ctx,
                         pininfo->min_digits? "SETPROMPT PIN:"
                                            : "SETPROMPT Passphrase:",
-                        NULL, NULL, NULL, NULL);
+                        NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -189,13 +189,13 @@ agent_askpin (const char *desc_text, const char *start_err_text,
             snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
                       errtext, pininfo->failed_tries+1, pininfo->max_tries);
           line[DIM(line)-1] = 0;
-          rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+          rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
           if (rc)
             return map_assuan_err (rc);
           errtext = NULL;
         }
       
-      rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL);
+      rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
       if (rc == ASSUAN_Too_Much_Data)
         errtext = pininfo->min_digits? trans ("PIN too long")
                                      : trans ("Passphrase too long");
@@ -248,13 +248,13 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
   else
     snprintf (line, DIM(line)-1, "RESET");
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -262,7 +262,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
     {
       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
       line[DIM(line)-1] = 0;
-      rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+      rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
         return map_assuan_err (rc);
     }
@@ -274,7 +274,7 @@ agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
     return seterr (Out_Of_Core);
 
   assuan_begin_confidential (entry_ctx);
-  rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL);
+  rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
   if (rc)
     {
       xfree (parm.buffer);
@@ -317,7 +317,7 @@ agent_get_confirmation (const char *desc, const char *prompt)
   else
     snprintf (line, DIM(line)-1, "RESET");
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -325,12 +325,12 @@ agent_get_confirmation (const char *desc, const char *prompt)
     {
       snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
       line[DIM(line)-1] = 0;
-      rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL);
+      rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
         return map_assuan_err (rc);
     }
 
-  rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL);
+  rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
   return map_assuan_err (rc);
 }
 
index 42842af..a8389f8 100644 (file)
@@ -94,6 +94,11 @@ enum {
   GNUPG_Not_Confirmed = 65,
   GNUPG_Configuration_Error = 66,
   GNUPG_No_Policy_Match = 67,
+  GNUPG_Invalid_Index = 68,
+  GNUPG_Invalid_Id = 69,
+  GNUPG_No_Scdaemon = 70,
+  GNUPG_Scdaemon_Error = 71,
+  GNUPG_Unsupported_Protocol = 72,
 };
 
 /* Status codes - fixme: should go into another file */
index 91c97f9..30bdf07 100644 (file)
@@ -44,6 +44,7 @@ map_ksba_err (int err)
       break;
 
     case KSBA_Unsupported_Algorithm: err = GNUPG_Unsupported_Algorithm; break;
+    case KSBA_Invalid_Index: err = GNUPG_Invalid_Index; break;
       
     default:
       err = seterr (General_Error);
@@ -136,6 +137,7 @@ map_assuan_err (int err)
       break;
 
     case ASSUAN_Canceled:        err = GNUPG_Canceled; break;
+    case ASSUAN_Invalid_Index:   err = GNUPG_Invalid_Index; break;
 
     case ASSUAN_Not_Implemented: err = GNUPG_Not_Implemented; break;
     case ASSUAN_Server_Fault:    err = GNUPG_Assuan_Server_Fault; break;
@@ -153,6 +155,7 @@ map_assuan_err (int err)
     case ASSUAN_No_PKCS15_App:   err = GNUPG_No_PKCS15_App; break;
     case ASSUAN_Card_Not_Present: err= GNUPG_Card_Not_Present; break;
     case ASSUAN_Not_Confirmed:   err = GNUPG_Not_Confirmed; break;
+    case ASSUAN_Invalid_Id:      err = GNUPG_Invalid_Id; break;
 
     default:
       err = err < 100? GNUPG_Assuan_Server_Fault : GNUPG_Assuan_Error;
@@ -182,6 +185,7 @@ map_to_assuan_status (int rc)
     case GNUPG_Invalid_Name:      rc = ASSUAN_Invalid_Name; break;
     case GNUPG_Not_Trusted:       rc = ASSUAN_Not_Trusted; break;
     case GNUPG_Canceled:          rc = ASSUAN_Canceled; break;
+    case GNUPG_Invalid_Index:     rc = ASSUAN_Invalid_Index; break;
 
     case GNUPG_Card_Error:      
     case GNUPG_Card_Reset:      
@@ -194,7 +198,7 @@ map_to_assuan_status (int rc)
     case GNUPG_Invalid_Card:      rc = ASSUAN_Invalid_Card; break;
     case GNUPG_No_PKCS15_App:     rc = ASSUAN_No_PKCS15_App; break;
     case GNUPG_Not_Confirmed:     rc = ASSUAN_Not_Confirmed; break;
-
+    case GNUPG_Invalid_Id:        rc = ASSUAN_Invalid_Id; break; 
 
     case GNUPG_Bad_PIN:
     case GNUPG_Bad_Passphrase:
index dca4f3b..5379d51 100644 (file)
@@ -20,7 +20,8 @@
 
 bin_PROGRAMS = scdaemon
 
-AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBOPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBOPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \
+             $(LIBKSBA_CFLAGS)
 LDFLAGS = @LDFLAGS@ 
 
 scdaemon_SOURCES = \
@@ -29,7 +30,8 @@ scdaemon_SOURCES = \
 
 
 scdaemon_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a  \
-               ../common/libcommon.a $(LIBOPENSC_LIBS) $(LIBGCRYPT_LIBS) 
+               ../common/libcommon.a \
+               $(LIBOPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBKSBA_LIBS)
 
 
 
index 3702ae3..dbfbe53 100644 (file)
@@ -26,6 +26,7 @@
 #include <time.h>
 
 #include <opensc-pkcs15.h>
+#include <ksba.h>
 
 #include "scdaemon.h"
 
@@ -114,13 +115,13 @@ card_open (CARD *rcard)
     }
   card->ctx->error_file = log_get_stream ();
   card->ctx->debug_file = log_get_stream ();
-  if (sc_detect_card (card->ctx, card->reader) != 1)
+  if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1)
     {
       rc = GNUPG_Card_Not_Present;
       goto leave;
     }
 
-  rc = sc_connect_card (card->ctx, card->reader, &card->scard);
+  rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard);
   if (rc)
     {
       log_error ("failed to connect card in reader %d: %s\n",
@@ -175,7 +176,7 @@ card_close (CARD card)
       if (card->scard)
         {
           sc_unlock (card->scard);
-          sc_disconnect_card (card->scard);
+          sc_disconnect_card (card->scard, 0);
           card->scard = NULL;
        }
       if (card->ctx)
@@ -219,3 +220,204 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
     return GNUPG_Out_Of_Core;
   return 0;
 }
+
+
+\f
+/* Get the keygrip from CERT, return 0 on success */
+static int
+get_keygrip (KsbaCert cert, unsigned char *array)
+{
+  GCRY_SEXP s_pkey;
+  int rc;
+  KsbaSexp p;
+  size_t n;
+  
+  p = ksba_cert_get_public_key (cert);
+  if (!p)
+    return -1; /* oops */
+  n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+  if (!n)
+    return -1; /* libksba did not return a proper S-expression */
+  rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
+  xfree (p);
+  if (rc)
+    return -1; /* can't parse that S-expression */
+  array = gcry_pk_get_keygrip (s_pkey, array);
+  gcry_sexp_release (s_pkey);
+  if (!array)
+    return -1; /* failed to calculate the keygrip */
+  return 0;
+}
+
+
+
+/* Enumerate all keypairs on the card and return the Keygrip as well
+   as the internal identification of the key.  KEYGRIP must be a
+   caller provided buffer with a size of 20 bytes which will receive
+   the KEYGRIP of the keypair.  If KEYID is not NULL, it returns the
+   ID field of the key in allocated memory, NKEYID will then receive
+   the length of it.  The function returns -1 when all keys have been
+   enumerated.  Note that the error GNUPG_Missing_Certificate may be
+   returned if there is just the private key but no public key (ie.e a
+   certificate) available.  Applications might want to continue
+   enumerating after this error.*/
+int
+card_enum_keypairs (CARD card, int idx,
+                    unsigned char *keygrip,
+                    unsigned char **keyid, size_t *nkeyid)
+{
+  int rc;
+  KsbaError krc;
+  struct sc_pkcs15_prkey_info *pinfo;
+  struct sc_pkcs15_cert_info *certinfo;
+  struct sc_pkcs15_cert      *certder;
+  KsbaCert cert;
+
+  if (keyid)
+    *keyid = NULL;
+  if (nkeyid)
+    *nkeyid = 0;
+
+  if (!card || !keygrip || !card->p15card)
+    return GNUPG_Invalid_Value;
+  if (idx < 0)
+    return GNUPG_Invalid_Index;
+       
+  rc = sc_pkcs15_enum_private_keys (card->p15card);
+  if (rc < 0) 
+    {
+      log_error ("sc_pkcs15_enum_private_keys failed: %s\n", sc_strerror (rc));
+      return GNUPG_Card_Error;
+    }
+  if ( idx >= card->p15card->prkey_count)
+    return -1;
+  pinfo = card->p15card->prkey_info + idx;
+  
+  /* now we need to read the certificate so that we can calculate the
+     keygrip */
+  rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &certinfo);
+  if (rc)
+    {
+      log_info ("certificate for private key %d not found: %s\n",
+                idx, sc_strerror (rc));
+      /* but we should return the ID anyway */
+      if (keyid)
+        {
+          *keyid = xtrymalloc (pinfo->id.len);
+          if (!*keyid)
+            return GNUPG_Out_Of_Core;
+          memcpy (*keyid, pinfo->id.value, pinfo->id.len);
+        }
+      if (nkeyid)
+        *nkeyid = pinfo->id.len;
+      return GNUPG_Missing_Certificate;
+    }
+  rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
+  if (rc)
+    {
+      log_info ("failed to read certificate for private key %d: %s\n",
+                idx, sc_strerror (rc));
+      return GNUPG_Card_Error;
+    }
+
+  cert = ksba_cert_new ();
+  if (!cert)
+    {
+      sc_pkcs15_free_certificate (certder);
+      return GNUPG_Out_Of_Core;
+    }
+  krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
+  sc_pkcs15_free_certificate (certder);
+  if (krc)
+    {
+      log_error ("failed to parse the certificate for private key %d: %s\n",
+                 idx, ksba_strerror (krc));
+      ksba_cert_release (cert);
+      return GNUPG_Card_Error;
+    }
+  if (get_keygrip (cert, keygrip))
+    {
+      log_error ("failed to calculate the keygrip of private key %d\n", idx);
+      ksba_cert_release (cert);
+      return GNUPG_Card_Error;
+    }      
+  ksba_cert_release (cert);
+
+  /* return the iD */
+  if (keyid)
+    {
+      *keyid = xtrymalloc (pinfo->id.len);
+      if (!*keyid)
+        return GNUPG_Out_Of_Core;
+      memcpy (*keyid, pinfo->id.value, pinfo->id.len);
+    }
+  if (nkeyid)
+    *nkeyid = pinfo->id.len;
+  
+  return 0;
+}
+
+
+\f
+/* 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
+   and NCERT. */
+int
+card_read_cert (CARD card, const char *certidstr,
+                unsigned char **cert, size_t *ncert)
+{
+  struct sc_pkcs15_id certid;
+  struct sc_pkcs15_cert_info *certinfo;
+  struct sc_pkcs15_cert      *certder;
+  const char *s;
+  int rc, n;
+
+  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 = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &certinfo);
+  if (rc)
+    {
+      log_info ("certificate '%s' not found: %s\n", 
+                certidstr, sc_strerror (rc));
+      return -1;
+    }
+  rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
+  if (rc)
+    {
+      log_info ("failed to read certificate '%s': %s\n",
+                certidstr, sc_strerror (rc));
+      return GNUPG_Card_Error;
+    }
+
+  *cert = xtrymalloc (certder->data_len);
+  if (!*cert)
+    {
+      sc_pkcs15_free_certificate (certder);
+      return GNUPG_Out_Of_Core;
+    }
+  memcpy (*cert, certder->data, certder->data_len);
+  *ncert = certder->data_len;
+  sc_pkcs15_free_certificate (certder);
+  return 0;
+}
+
+
+
+
+
index 10b9006..b4eaa8a 100644 (file)
@@ -75,14 +75,20 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
 /* LEARN [--force]
 
    Learn all useful information of the currently inserted card.  When
-   used without the force options, the command might to an INQUIRE
+   used without the force options, the command might do an INQUIRE
    like this:
 
       INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
 
    The client should just send an "END" if the processing should go on
    or a "CANCEL" to force the function to terminate with a Cancel
-   error message.
+   error message.  The response of this command is a list of status
+   lines formatted as this:
+
+     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.
 
 */
 static int
@@ -90,6 +96,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
 {
   CTRL ctrl = assuan_get_pointer (ctx);
   int rc = 0;
+  int idx;
 
   /* if this is the first command issued for a new card, open the card and 
      and create a context */
@@ -104,40 +111,138 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line)
      the card using a serial number and inquiring the client with
      that. The client may choose to cancel the operation if he already
      knows about this card */
-  if (!has_option (line, "--force"))
+  {
+    char *serial_and_stamp;
+    char *serial;
+    time_t stamp;
+   
+    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);
+
+    if (!has_option (line, "--force"))
+      {
+        char *command;
+
+        rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
+        if (rc < 0)
+          {
+            free (serial_and_stamp);
+            return ASSUAN_Out_Of_Core;
+          }
+        rc = 0;
+        rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
+        free (command);  /* (must use standard free here) */
+        if (rc)
+          {
+            if (rc != ASSUAN_Canceled)
+              log_error ("inquire KNOWNCARDP failed: %s\n",
+                         assuan_strerror (rc));
+            free (serial_and_stamp);
+            return rc; 
+          }
+        /* not canceled, so we have to proceeed */
+      }
+    free (serial_and_stamp);
+  }
+
+  for (idx=0; !rc; idx++)
     {
-      char *serial;
-      time_t stamp;
-      char *command;
-
-      rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
-      if (rc)
-        return map_to_assuan_status (rc);
-
-      rc = asprintf (&command, "KNOWNCARDP %s %lu",
-                     serial, (unsigned long)stamp);
-      xfree (serial);
-      if (rc < 0)
-        return ASSUAN_Out_Of_Core;
-      rc = 0;
-      rc = assuan_inquire (ctx, command, NULL, NULL, 0); 
-      free (command);  /* (must use standard free here) */
-      if (rc)
+      unsigned char keygrip[20];
+      unsigned char *keyid;
+      size_t nkeyid;
+      int no_cert = 0;
+
+      rc = card_enum_keypairs (ctrl->card_ctx, idx, 
+                               keygrip, &keyid, &nkeyid);
+      if (rc == GNUPG_Missing_Certificate && keyid)
+        {
+          /* this does happen with an incomplete personalized
+             card; i.e. during the time we have stored the key on the
+             card but not stored the certificate; probably becuase it
+             has not yet been received back from the CA.  Note that we
+             must release KEYID in this case. */
+          rc = 0; 
+          no_cert = 1;
+        }
+      if (!rc)
         {
-          if (rc != ASSUAN_Canceled)
-            log_error ("inquire KNOWNCARDP failed: %s\n",
-                       assuan_strerror (rc));
-          return rc; 
+          char *buf, *p;
+
+          buf = p = xtrymalloc (40+1+9+2*nkeyid+1);
+          if (!buf)
+            rc = GNUPG_Out_Of_Core;
+          else
+            {
+              int i;
+              
+              if (no_cert)
+                *p++ = 'X';
+              else
+                {
+                  for (i=0; i < 20; i++, p += 2)
+                    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;
+              assuan_write_status (ctx, "KEYPAIRINFO", buf);
+              xfree (buf);
+            }
         }
-      /* not canceled, so we have to proceeed */
+      xfree (keyid);
     }
+  if (rc == -1)
+    rc = 0;
+
 
   return map_to_assuan_status (rc);
 }
 
 
+\f
+/* READCERT <hexified_certid>
 
+ */
+static int
+cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+  int rc;
+  unsigned char *cert;
+  size_t ncert;
 
+  if (!ctrl->card_ctx)
+    {
+      rc = card_open (&ctrl->card_ctx);
+      if (rc)
+        return map_to_assuan_status (rc);
+    }
+
+  rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
+  if (rc)
+    {
+      log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
+    }
+  if (!rc)
+    {
+      rc = assuan_send_data (ctx, cert, ncert);
+      xfree (cert);
+      if (rc)
+        return rc;
+    }
+
+  return map_to_assuan_status (rc);
+}
 
 \f
 /* Tell the assuan library about our commands */
@@ -150,6 +255,7 @@ register_commands (ASSUAN_CONTEXT ctx)
     int (*handler)(ASSUAN_CONTEXT, char *line);
   } table[] = {
     { "LEARN", 0, cmd_learn },
+    { "READCERT", 0, cmd_readcert },
     { "",     ASSUAN_CMD_INPUT, NULL }, 
     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
     { NULL }
index d217b00..92bccec 100644 (file)
@@ -34,6 +34,7 @@
 #include <unistd.h>
 #include <signal.h>
 
+#include <ksba.h>
 #include <gcrypt.h>
 
 #define JNLIB_NEED_LOG_LOGV
@@ -242,6 +243,7 @@ main (int argc, char **argv )
                    "1.1.5", gcry_check_version (NULL) );
     }
 
+  ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
   assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
   gcry_set_log_handler (my_gcry_logger, NULL);
   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
index 7d43dc1..e770124 100644 (file)
@@ -77,6 +77,11 @@ void scd_command_handler (int);
 int card_open (CARD *rcard);
 void card_close (CARD card);
 int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp);
+int card_enum_keypairs (CARD card, int idx,
+                        unsigned char *keygrip,
+                        unsigned char **keyid, size_t *nkeyid);
+int card_read_cert (CARD card, const char *certidstr,
+                    unsigned char **cert, size_t *ncert);
 
 
 
index 8388b39..4bddd24 100644 (file)
@@ -1,3 +1,8 @@
+2002-02-27  Werner Koch  <wk@gnupg.org>
+
+       * call-dirmngr.c, call-agent.c: Add 2 more arguments to all uses
+       of assuan_transact.
+
 2002-02-25  Werner Koch  <wk@gnupg.org>
 
        * server.c (option_handler): Allow to use -2 for "send all certs
index 54e8fac..14e2fdf 100644 (file)
@@ -245,13 +245,13 @@ gpgsm_agent_pksign (const char *keygrip,
   if (digestlen*2 + 50 > DIM(line))
     return seterr (General_Error);
 
-  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
   snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -259,13 +259,13 @@ gpgsm_agent_pksign (const char *keygrip,
   p = line + strlen (line);
   for (i=0; i < digestlen ; i++, p += 2 )
     sprintf (p, "%02X", digest[i]);
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, "PKSIGN",
-                        membuf_data_cb, &data, NULL, NULL);
+                        membuf_data_cb, &data, NULL, NULL, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -327,14 +327,14 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
   if (rc)
     return rc;
 
-  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
   assert ( DIM(line) >= 50 );
   snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
   line[DIM(line)-1] = 0;
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -344,7 +344,7 @@ gpgsm_agent_pkdecrypt (const char *keygrip,
   cipher_parm.ciphertextlen = ciphertextlen;
   rc = assuan_transact (agent_ctx, "PKDECRYPT",
                         membuf_data_cb, &data,
-                        inq_ciphertext_cb, &cipher_parm);
+                        inq_ciphertext_cb, &cipher_parm, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -403,7 +403,7 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
   if (rc)
     return rc;
 
-  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return map_assuan_err (rc);
 
@@ -415,7 +415,7 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
     return GNUPG_Invalid_Value;
   rc = assuan_transact (agent_ctx, "GENKEY",
                         membuf_data_cb, &data, 
-                        inq_genkey_parms, &gk_parm);
+                        inq_genkey_parms, &gk_parm, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -458,7 +458,7 @@ gpgsm_agent_istrusted (KsbaCert cert)
   line[DIM(line)-1] = 0;
   xfree (fpr);
 
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   return map_assuan_err (rc);
 }
 
@@ -492,7 +492,7 @@ gpgsm_agent_marktrusted (KsbaCert cert)
   ksba_free (dn);
   xfree (fpr);
 
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   return map_assuan_err (rc);
 }
 
@@ -516,7 +516,7 @@ gpgsm_agent_havekey (const char *hexkeygrip)
   snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
   line[DIM(line)-1] = 0;
 
-  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   return map_assuan_err (rc);
 }
 
index ee41eb4..172a4d0 100644 (file)
@@ -227,7 +227,8 @@ gpgsm_dirmngr_isvalid (KsbaCert cert)
   line[DIM(line)-1] = 0;
   xfree (certid);
 
-  rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, inq_certificate, &parm);
+  rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
+                        inq_certificate, &parm, NULL, NULL);
   return map_assuan_err (rc);
 }
 
index ebcb7f9..065fc5a 100644 (file)
@@ -371,7 +371,7 @@ cmd_message (ASSUAN_CONTEXT ctx, char *line)
 
 
 /* Note that the line contains a space separated list of pappern where
-   each pappern is percent escaped and spacesmay be replaced by
+   each pappern is percent escaped and spaces may be replaced by
    '+'. */
 static int 
 cmd_listkeys (ASSUAN_CONTEXT ctx, char *line)