* findkey.c (modify_description): Keep invalid % escapes, so that
authorWerner Koch <wk@gnupg.org>
Fri, 25 Feb 2005 16:14:55 +0000 (16:14 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 25 Feb 2005 16:14:55 +0000 (16:14 +0000)
%0A may pass through.

* agent.h (server_control_s): New field USE_AUTH_CALL.
* call-scd.c (agent_card_pksign): Make use of it.
* command-ssh.c (data_sign): Set the flag.
(ssh_send_key_public): New arg OVERRIDE_COMMENT.
(card_key_available): Add new arg CARDSN.
(ssh_handler_request_identities): Use the card s/n as comment.
(sexp_key_extract): Use GCRYMPI_FMT_STD.
(data_sign): Ditto.

* learncard.c (make_shadow_info): Moved to ..
* protect.c (make_shadow_info): .. here. Return NULL on malloc
failure. Made global.
* agent.h: Add prototype.

* xasprintf.c (xtryasprintf): New.

* app-openpgp.c (get_public_key): Make sure not to return negative
numbers.
(do_sign): Allow passing of indata with algorithm prefix.
(do_auth): Allow OPENPGP.3 as an alternative ID.

* app.c (app_getattr): Return just the S/N but not the timestamp.

* no-libgcrypt.c (gcry_strdup): New.

18 files changed:
agent/ChangeLog
agent/agent.h
agent/call-scd.c
agent/command-ssh.c
agent/findkey.c
agent/keyformat.txt
agent/learncard.c
agent/protect-tool.c
agent/protect.c
common/ChangeLog
common/util.h
common/xasprintf.c
scd/ChangeLog
scd/app-openpgp.c
scd/app.c
tools/ChangeLog
tools/gpg-connect-agent.c
tools/no-libgcrypt.c

index 118559c..2138f66 100644 (file)
@@ -1,3 +1,22 @@
+2005-02-25  Werner Koch  <wk@g10code.com>
+
+       * findkey.c (modify_description): Keep invalid % escapes, so that
+       %0A may pass through.
+
+       * agent.h (server_control_s): New field USE_AUTH_CALL.
+       * call-scd.c (agent_card_pksign): Make use of it.
+       * command-ssh.c (data_sign): Set the flag.
+       (ssh_send_key_public): New arg OVERRIDE_COMMENT.
+       (card_key_available): Add new arg CARDSN.
+       (ssh_handler_request_identities): Use the card s/n as comment.
+       (sexp_key_extract): Use GCRYMPI_FMT_STD.
+       (data_sign): Ditto.
+
+       * learncard.c (make_shadow_info): Moved to ..
+       * protect.c (make_shadow_info): .. here. Return NULL on malloc
+       failure. Made global.
+       * agent.h: Add prototype.
+
 2005-02-24  Werner Koch  <wk@g10code.com>
 
        * call-scd.c (unescape_status_string): New. Actual a copy of
index 39e479e..e12a02b 100644 (file)
@@ -116,6 +116,8 @@ struct server_control_s {
   char keygrip[20];
   int have_keygrip;
 
+  int use_auth_call; /* Hack to send the PKAUTH command instead of the
+                        PKSIGN command tro scdaemon.  */
 };
 typedef struct server_control_s *CTRL;
 typedef struct server_control_s *ctrl_t;
@@ -204,6 +206,7 @@ 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);
+unsigned char *make_shadow_info (const char *serialno, const char *idstring);
 int agent_shadow_key (const unsigned char *pubkey,
                       const unsigned char *shadow_info,
                       unsigned char **result);
index f7d32f7..9040592 100644 (file)
@@ -225,15 +225,16 @@ start_scd (ctrl_t ctrl)
   /* Tell the scdaemon that we want him to send us an event signal.
      But only do this if we are running as a regular sever and not
      simply as a pipe server. */
-  if (ctrl->connection_fd != -1)
-  {
-#ifndef HAVE_W32_SYSTEM
-    char buf[100];
+  /* Fixme: gpg-agent does not use this signal yet.  */
+/*   if (ctrl->connection_fd != -1) */
+/*   { */
+/* #ifndef HAVE_W32_SYSTEM */
+/*     char buf[100]; */
 
-    sprintf (buf, "OPTION event-signal=%d", SIGUSR2);
-    assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL);
-#endif
-  }
+/*     sprintf (buf, "OPTION event-signal=%d", SIGUSR2); */
+/*     assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); */
+/* #endif */
+/*   } */
 
   return 0;
 }
@@ -505,7 +506,8 @@ agent_card_pksign (ctrl_t ctrl,
   inqparm.ctx = scd_ctx;
   inqparm.getpin_cb = getpin_cb;
   inqparm.getpin_cb_arg = getpin_cb_arg;
-  snprintf (line, DIM(line)-1, "PKSIGN %s", keyid);
+  snprintf (line, DIM(line)-1, 
+            ctrl->use_auth_call? "PKAUTH %s":"PKSIGN %s", keyid);
   line[DIM(line)-1] = 0;
   rc = assuan_transact (scd_ctx, line,
                         membuf_data_cb, &data,
@@ -518,7 +520,7 @@ agent_card_pksign (ctrl_t ctrl,
     }
   sigbuf = get_membuf (&data, &sigbuflen);
 
-  /* create an S-expression from it which is formatted like this:
+  /* Create an S-expression from it which is formatted like this:
      "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */
   *r_buflen = 21 + 11 + sigbuflen + 4;
   *r_buf = xtrymalloc (*r_buflen);
index 2c0d25e..ebb44fa 100644 (file)
@@ -659,7 +659,9 @@ open_control_file (FILE **r_fp, int append)
      (i.e. where Pth might switch threads) we need to employ a
      mutex.  */
   *r_fp = NULL;
-  fname = make_filename (opt.homedir, "sshcontrol.txt", NULL);
+  fname = make_filename (opt.homedir, "sshcontrol", NULL);
+  /* FIXME: With "a+" we are not able to check whether this will will
+     be created and thus the blurb needs to be written first.  */
   fp = fopen (fname, append? "a+":"r");
   if (!fp && errno == ENOENT)
     {
@@ -1146,7 +1148,9 @@ sexp_key_extract (gcry_sexp_t sexp,
          break;
        }
 
-      mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG);
+      /* Note that we need to use STD format; i.e. prepend a 0x00 to
+         indicate a positive number if the high bit is set. */
+      mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD);
       if (! mpi)
        {
          err = gpg_error (GPG_ERR_INV_SEXP);
@@ -1404,9 +1408,12 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size,
 }
                              
 
-/* Write the public key KEY_PUBLIC to STREAM in SSH key format. */
+/* Write the public key KEY_PUBLIC to STREAM in SSH key format.  If
+   OVERRIDE_COMMENT is not NULL, it will be used instead of the
+   comment stored in the key.  */
 static gpg_error_t
-ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
+ssh_send_key_public (estream_t stream, gcry_sexp_t key_public,
+                     const char *override_comment)
 {
   ssh_key_type_spec_t spec;
   gcry_mpi_t *mpi_list;
@@ -1442,7 +1449,8 @@ ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
   if (err)
     goto out;
 
-  err = stream_write_cstring (stream, comment);
+  err = stream_write_cstring (stream,
+                              override_comment? override_comment : comment);
   
  out:
 
@@ -1520,17 +1528,23 @@ key_secret_to_public (gcry_sexp_t *key_public,
 
 /* Chec whether a smartcard is available and whether it has a usable
    key.  Store a copy of that key at R_PK and return 0.  If no key is
-   available store NULL at R_PK and return an error code.  */
+   available store NULL at R_PK and return an error code.  If CARDSN
+   is no NULL, a string with the serial number of the card will be
+   amalloced and stored there. */
 static gpg_error_t
-card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk)
+card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn)
 {
   gpg_error_t err;
   char *appname;
-  unsigned char *sbuf;
-  size_t sbuflen;
-  gcry_sexp_t pk;
+  char *serialno = NULL;
+  unsigned char *pkbuf;
+  size_t pkbuflen;
+  gcry_sexp_t s_pk;
+  unsigned char grip[20];
 
   *r_pk = NULL;
+  if (cardsn)
+    *cardsn = NULL;
 
   /* First see whether a card is available and whether the application
      is supported.  */
@@ -1538,53 +1552,135 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk)
   if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED )
     {
       /* Ask for the serial number to reset the card.  */
-      err = agent_card_serialno (ctrl, &appname);
+      err = agent_card_serialno (ctrl, &serialno);
       if (err)
         {
           if (opt.verbose)
-            log_info (_("can't get serial number of card: %s\n"),
+            log_info (_("error getting serial number of card: %s\n"),
                       gpg_strerror (err));
           return err;
         }
-      log_info (_("detected card with S/N: %s\n"), appname);
-      xfree (appname);
+      log_info (_("detected card with S/N: %s\n"), serialno);
       err = agent_card_getattr (ctrl, "APPTYPE", &appname);
     }
   if (err)
     {
       log_error (_("error getting application type of card: %s\n"),
                  gpg_strerror (err));
+      xfree (serialno);
       return err;
     }
   if (strcmp (appname, "OPENPGP"))
     {
       log_info (_("card application `%s' is not supported\n"), appname);
       xfree (appname);
+      xfree (serialno);
       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     }
   xfree (appname);
   appname = NULL;
 
+  /* Get the S/N if we don't have it yet.  Use the fast getattr method.  */
+  if (!serialno && (err = agent_card_getattr (ctrl, "SERIALNO", &serialno)) )
+    {
+      log_error (_("error getting serial number of card: %s\n"),
+                 gpg_strerror (err));
+      return err;
+    }
+
   /* Read the public key.  */
-  err = agent_card_readkey (ctrl, "OPENPGP.3", &sbuf);
+  err = agent_card_readkey (ctrl, "OPENPGP.3", &pkbuf);
   if (err)
     {
       if (opt.verbose)
         log_info (_("no suitable card key found: %s\n"), gpg_strerror (err));
+      xfree (serialno);
       return err;
     }
 
-  sbuflen = gcry_sexp_canon_len (sbuf, 0, NULL, NULL);
-  err = gcry_sexp_sscan (&pk, NULL, sbuf, sbuflen);
-  xfree (sbuf);
+  pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
+  err = gcry_sexp_sscan (&s_pk, NULL, pkbuf, pkbuflen);
   if (err)
     {
       log_error ("failed to build S-Exp from received card key: %s\n",
                  gpg_strerror (err));
+      xfree (pkbuf);
+      xfree (serialno);
       return err;
     }
   
-  *r_pk = pk;
+  if ( !gcry_pk_get_keygrip (s_pk, grip) )
+    {
+      log_debug ("error computing keygrip from received card key\n");
+      xfree (pkbuf);
+      gcry_sexp_release (s_pk);
+      xfree (serialno);
+      return gpg_error (GPG_ERR_INTERNAL);
+    }
+
+  if ( agent_key_available (grip) )
+    {
+      /* (Shadow)-key is not available in our key storage.  */
+      unsigned char *shadow_info;
+      unsigned char *tmp;
+      
+      shadow_info = make_shadow_info (serialno, "OPENPGP.3");
+      if (!shadow_info)
+        {
+          err = gpg_error_from_errno (errno);
+          xfree (pkbuf);
+          gcry_sexp_release (s_pk);
+          xfree (serialno);
+          return err;
+        }
+      err = agent_shadow_key (pkbuf, shadow_info, &tmp);
+      xfree (shadow_info);
+      if (err)
+        {
+          log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err));
+          xfree (pkbuf);
+          gcry_sexp_release (s_pk);
+          xfree (serialno);
+          return err;
+        }
+      xfree (pkbuf);
+      pkbuf = tmp;
+      pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
+      assert (pkbuflen);
+
+      err = agent_write_private_key (grip, pkbuf, pkbuflen, 0);
+      if (err)
+        {
+          log_error (_("error writing key: %s\n"), gpg_strerror (err));
+          xfree (pkbuf);
+          gcry_sexp_release (s_pk);
+          xfree (serialno);
+          return err;
+        }
+    }
+
+  if (cardsn)
+    {
+      size_t snlen = strlen (serialno);
+
+      if (snlen == 32
+          && !memcmp (serialno, "D27600012401", 12)) /* OpenPGP card. */
+        *cardsn = xtryasprintf ("cardno:%.12s", serialno+16);
+      else /* Something is wrong: Print all. */
+        *cardsn = xtryasprintf ("cardno:%s", serialno);
+      if (!*cardsn)
+        {
+          err = gpg_error_from_errno (errno);
+          xfree (pkbuf);
+          gcry_sexp_release (s_pk);
+          xfree (serialno);
+          return err;
+        }
+    }
+
+  xfree (pkbuf);
+  xfree (serialno);
+  *r_pk = s_pk;
   return 0;
 }
 
@@ -1615,6 +1711,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
   gpg_error_t ret_err;
   int ret;
   FILE *ctrl_fp = NULL;
+  char *cardsn;
 
   /* Prepare buffer stream.  */
 
@@ -1665,13 +1762,14 @@ ssh_handler_request_identities (ctrl_t ctrl,
 
   /* First check whether a key is currently available in the card
      reader - this should be allowed even without being listed in
-     sshcontrol.txt. */
+     sshcontrol. */
 
-  if (!card_key_available (ctrl, &key_public))
+  if (!card_key_available (ctrl, &key_public, &cardsn))
     {
-      err = ssh_send_key_public (key_blobs, key_public);
+      err = ssh_send_key_public (key_blobs, key_public, cardsn);
       gcry_sexp_release (key_public);
       key_public = NULL;
+      xfree (cardsn);
       if (err)
         goto out;
       
@@ -1740,7 +1838,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
           gcry_sexp_release (key_secret);
           key_secret = NULL;
              
-          err = ssh_send_key_public (key_blobs, key_public);
+          err = ssh_send_key_public (key_blobs, key_public, NULL);
           if (err)
             goto out;
 
@@ -1845,9 +1943,11 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder,
   sig_value = NULL;
   mpis = NULL;
 
+  ctrl->use_auth_call = 1;
   err = agent_pksign_do (ctrl,
-                         _("Please provide the passphrase "
-                           "for the ssh key `%c':"), &signature_sexp, 0);
+                         _("Please enter the passphrase "
+                           "for the ssh key%0A  %c"), &signature_sexp, 0);
+  ctrl->use_auth_call = 0;
   if (err)
     goto out;
 
@@ -2189,7 +2289,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
 
   key_grip_raw[sizeof (key_grip_raw) - 1] = 0; /* FIXME:  Why?? */
 
-  /* Check whether the key is alread in our key storage.  Don't do
+  /* Check whether the key is already in our key storage.  Don't do
      anything then.  */
   if ( !agent_key_available (key_grip_raw) )
     goto out; /* Yes, key is available.  */
@@ -2200,8 +2300,8 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
     goto out;
 
   if ( asprintf (&description,
-                 _("Please enter a passphrase to protect%%0A"
-                   "the received secret key%%0A"
+                 _("Please enter a passphrase to protect"
+                   " the received secret key%%0A"
                    "   %s%%0A"
                    "within gpg-agent's key storage"),
                  comment ? comment : "?") < 0)
index 86a28d5..0b5816b 100644 (file)
@@ -166,9 +166,7 @@ modify_description (const char *in, const char *comment, char **result)
       special = 0;
       for (i = 0; i < in_len; i++)
         {
-          if (in[i] == '%')
-            special = 1;
-          else if (special)
+          if (special)
             {
               special = 0;
               switch (in[i])
@@ -190,10 +188,19 @@ modify_description (const char *in, const char *comment, char **result)
                     out_len += comment_length;
                   break;
 
-                default: /* Invalid special sequences are ignored.  */
+                default: /* Invalid special sequences are kept as they are. */
+                  if (out)
+                    {
+                      *out++ = '%';
+                      *out++ = in[i];
+                    }
+                  else
+                    out_len+=2;
                   break;
                 }
             }
+          else if (in[i] == '%')
+            special = 1;
           else
             {
               if (out)
index 7269903..7bdb94c 100644 (file)
@@ -161,9 +161,9 @@ term secret key because it can be visually be better distinguished
 from the term public key.
 
 [2] The keygrip is a unique identifier for a key pair, it is
-independent of any protocol, so that the same key can be ised with
+independent of any protocol, so that the same key can be used with
 different protocols.  PKCS-15 calls this a subjectKeyHash; it can be
-calculate using Libgcrypt's gcry_pk_get_keygrip().
+calculated using Libgcrypt's gcry_pk_get_keygrip ().
 
 [3] Even when canonical representation are required we will show the
 S-expression here in a more readable representation.
index 7dcacee..7223850 100644 (file)
@@ -1,5 +1,5 @@
 /* learncard.c - Handle the LEARN command
- *     Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -239,32 +239,6 @@ sinfo_cb (void *opaque, const char *keyword, size_t keywordlen,
 }
 
 
-/* Create an S-expression with the shadow info.  */
-static unsigned char *
-make_shadow_info (const char *serialno, const char *idstring)
-{
-  const char *s;
-  unsigned char *info, *p;
-  char numbuf[21];
-  int n;
-
-  for (s=serialno, n=0; *s && s[1]; s += 2)
-    n++;
-
-  info = p = xtrymalloc (1 + 21 + n
-                           + 21 + strlen (idstring) + 1 + 1);
-  *p++ = '(';
-  sprintf (numbuf, "%d:", n);
-  p = stpcpy (p, numbuf);
-  for (s=serialno; *s && s[1]; s += 2)
-    *p++ = xtoi_2 (s);
-  sprintf (numbuf, "%d:", strlen (idstring));
-  p = stpcpy (p, numbuf);
-  p = stpcpy (p, idstring);
-  *p++ = ')';
-  *p = 0;
-  return info;
-}
 
 static int
 send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
index ee0276a..c21aa05 100644 (file)
@@ -110,7 +110,7 @@ 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"},
+  { oShadow,  "shadow", 256, "create a shadow entry for a public key"},
   { oShowShadowInfo,  "show-shadow-info", 256, "return the shadow info"},
   { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
 
index cafeb46..ae3061c 100644 (file)
@@ -831,10 +831,43 @@ hash_passphrase (const char *passphrase, int hashalgo,
 
 
 \f
+
+/* Create an canonical encoded S-expression with the shadow info from
+   a card's SERIALNO and the IDSTRING.  */
+unsigned char *
+make_shadow_info (const char *serialno, const char *idstring)
+{
+  const char *s;
+  unsigned char *info, *p;
+  char numbuf[21];
+  int n;
+
+  for (s=serialno, n=0; *s && s[1]; s += 2)
+    n++;
+
+  info = p = xtrymalloc (1 + 21 + n
+                           + 21 + strlen (idstring) + 1 + 1);
+  if (!info)
+    return NULL;
+  *p++ = '(';
+  sprintf (numbuf, "%d:", n);
+  p = stpcpy (p, numbuf);
+  for (s=serialno; *s && s[1]; s += 2)
+    *p++ = xtoi_2 (s);
+  sprintf (numbuf, "%d:", strlen (idstring));
+  p = stpcpy (p, numbuf);
+  p = stpcpy (p, idstring);
+  *p++ = ')';
+  *p = 0;
+  return info;
+}
+
+
+
 /* 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
+  to. The input parameters are expected to be valid canonicalized
   S-expressions */
 int 
 agent_shadow_key (const unsigned char *pubkey,
@@ -894,7 +927,7 @@ agent_shadow_key (const unsigned char *pubkey,
   s++;
   assert (depth == 1);
 
-  /* calculate required length by taking in account: the "shadowed-"
+  /* 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);
index e323dc1..db05931 100644 (file)
@@ -1,3 +1,7 @@
+2005-02-25  Werner Koch  <wk@g10code.com>
+
+       * xasprintf.c (xtryasprintf): New.
+
 2005-01-26  Moritz Schulte  <moritz@g10code.com>
 
        * Makefile.am (libcommon_a_SOURCES): New source files: estream.c,
index 4ab55ac..bbf7241 100644 (file)
@@ -131,6 +131,10 @@ const char *default_homedir (void);
    freed using xfree.  This function simply dies on memory failure,
    thus no extra check is required. */
 char *xasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2);
+/* Same as asprintf but return an allocated buffer suitable to be
+   freed using xfree.  This function returns NULL on memory failure and
+   sets errno. */
+char *xtryasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2);
 
 const char *print_fname_stdout (const char *s);
 const char *print_fname_stdin (const char *s);
index 2c8fafc..a3b5e27 100644 (file)
@@ -1,5 +1,5 @@
 /* xasprintf.c
- *     Copyright (C) 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -42,3 +42,21 @@ xasprintf (const char *fmt, ...)
   free (buf);
   return p;
 }
+
+/* Same as above bit return NULL on memory failure.  */
+char *
+xtryasprintf (const char *fmt, ...)
+{
+  int rc;
+  va_list ap;
+  char *buf, *p;
+
+  va_start (ap, fmt);
+  rc = vasprintf (&buf, fmt, ap);
+  va_end (ap);
+  if (rc < 0)
+    return NULL;
+  p = xtrystrdup (buf);
+  free (buf);
+  return p;
+}
index dc394b6..e3b4ae6 100644 (file)
@@ -1,3 +1,12 @@
+2005-02-25  Werner Koch  <wk@g10code.com>
+
+       * app-openpgp.c (get_public_key): Make sure not to return negative
+       numbers.
+       (do_sign): Allow passing of indata with algorithm prefix.
+       (do_auth): Allow OPENPGP.3 as an alternative ID.
+
+       * app.c (app_getattr): Return just the S/N but not the timestamp.
+
 2005-02-24  Werner Koch  <wk@g10code.com>
 
        * app.c (app_getattr): Return APPTYPE or SERIALNO type even if the
index 14c802d..6ebc137 100644 (file)
@@ -794,6 +794,8 @@ get_public_key (app_t app, int keyno)
   const unsigned char *keydata, *m, *e;
   size_t buflen, keydatalen, mlen, elen;
   gcry_sexp_t sexp;
+  unsigned char *mbuf = NULL;
+  unsigned char *ebuf = NULL;
 
   if (keyno < 1 || keyno > 3)
     return gpg_error (GPG_ERR_INV_ID);
@@ -835,6 +837,7 @@ get_public_key (app_t app, int keyno)
           log_error (_("response does not contain the RSA modulus\n"));
           goto leave;
         }
+      
 
       e = find_tlv (keydata, keydatalen, 0x0082, &elen);
       if (!e)
@@ -844,10 +847,38 @@ get_public_key (app_t app, int keyno)
           goto leave;
         }
 
+      /* Prepend numbers with a 0 if needed.  */
+      if (mlen && (*m & 0x80))
+        {
+          mbuf = xtrymalloc ( mlen + 1);
+          if (!mbuf)
+            {
+              err = gpg_error_from_errno (errno);
+              goto leave;
+            }
+          *mbuf = 0;
+          memcpy (mbuf+1, m, mlen);
+          mlen++;
+          m = mbuf;
+        }
+      if (elen && (*e & 0x80))
+        {
+          ebuf = xtrymalloc ( elen + 1);
+          if (!ebuf)
+            {
+              err = gpg_error_from_errno (errno);
+              goto leave;
+            }
+          *ebuf = 0;
+          memcpy (ebuf+1, e, elen);
+          elen++;
+          e = ebuf;
+        }
+
+
       err = gcry_sexp_build (&sexp, NULL,
                              "(public-key (rsa (n %b) (e %b)))",
                              (int)mlen, m,(int)elen, e);
-
       if (err)
         {
           log_error ("error formatting the key into an S-expression: %s\n",
@@ -874,6 +905,8 @@ get_public_key (app_t app, int keyno)
   app->app_local->pk[keyno].read_done = 1;
 
   xfree (buffer);
+  xfree (mbuf);
+  xfree (ebuf);
   return 0;
 }
 #endif /* GNUPG_MAJOR_VERSION > 1 */
@@ -1557,7 +1590,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
 
   if (!keyidstr || !*keyidstr)
     return gpg_error (GPG_ERR_INV_VALUE);
-  if (indatalen != 20)
+  if (indatalen == 20)
+    ;
+  else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_SHA1
+           && !memcmp (indata, sha1_prefix, 15))
+    ;
+  else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_RMD160
+           && !memcmp (indata, rmd160_prefix, 15))
+    ;
+  else
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* Check whether an OpenPGP card of any version has been requested. */
@@ -1668,7 +1709,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
 /* Compute a digital signature using the INTERNAL AUTHENTICATE command
    on INDATA which is expected to be the raw message digest. For this
    application the KEYIDSTR consists of the serialnumber and the
-   fingerprint delimited by a slash.
+   fingerprint delimited by a slash.  Optionally the id OPENPGP.3 may
+   be given.
 
    Note that this fucntion may return the error code
    GPG_ERR_WRONG_CARD to indicate that the card currently present does
@@ -1693,27 +1735,31 @@ do_auth (app_t app, const char *keyidstr,
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* Check whether an OpenPGP card of any version has been requested. */
-  if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
-    return gpg_error (GPG_ERR_INV_ID);
-  
-  for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
+  if (!strcmp (keyidstr, "OPENPGP.3"))
     ;
-  if (n != 32)
+  else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
     return gpg_error (GPG_ERR_INV_ID);
-  else if (!*s)
-    ; /* no fingerprint given: we allow this for now. */
-  else if (*s == '/')
-    fpr = s + 1; 
   else
-    return gpg_error (GPG_ERR_INV_ID);
-
-  for (s=keyidstr, n=0; n < 16; s += 2, n++)
-    tmp_sn[n] = xtoi_2 (s);
+    {
+      for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
+        ;
+      if (n != 32)
+        return gpg_error (GPG_ERR_INV_ID);
+      else if (!*s)
+        ; /* no fingerprint given: we allow this for now. */
+      else if (*s == '/')
+        fpr = s + 1; 
+      else
+        return gpg_error (GPG_ERR_INV_ID);
 
-  if (app->serialnolen != 16)
-    return gpg_error (GPG_ERR_INV_CARD);
-  if (memcmp (app->serialno, tmp_sn, 16))
-    return gpg_error (GPG_ERR_WRONG_CARD);
+      for (s=keyidstr, n=0; n < 16; s += 2, n++)
+        tmp_sn[n] = xtoi_2 (s);
+      
+      if (app->serialnolen != 16)
+        return gpg_error (GPG_ERR_INV_CARD);
+      if (memcmp (app->serialno, tmp_sn, 16))
+        return gpg_error (GPG_ERR_WRONG_CARD);
+    }
 
   /* If a fingerprint has been specified check it against the one on
      the card.  This is allows for a meaningful error message in case
index 384ee21..0625dc8 100644 (file)
--- a/scd/app.c
+++ b/scd/app.c
@@ -314,7 +314,6 @@ app_getattr (APP app, CTRL ctrl, const char *name)
     }
   if (name && !strcmp (name, "SERIALNO"))
     {
-      char *serial_and_stamp;
       char *serial;
       time_t stamp;
       int rc;
@@ -322,15 +321,8 @@ app_getattr (APP app, CTRL ctrl, const char *name)
       rc = app_get_serial_and_stamp (app, &serial, &stamp);
       if (rc)
         return rc;
-      rc = asprintf (&serial_and_stamp, "%s %lu",
-                     serial, (unsigned long)stamp);
-      rc = (rc < 0)? gpg_error_from_errno (errno) : 0;
+      send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0);
       xfree (serial);
-      if (rc)
-        return rc;
-      send_status_info (ctrl, "SERIALNO",
-                        serial_and_stamp, strlen (serial_and_stamp), NULL, 0);
-      free (serial_and_stamp);
       return 0;
     }
 
index 6895198..4d520cf 100644 (file)
@@ -1,3 +1,7 @@
+2005-02-25  Werner Koch  <wk@g10code.com>
+
+       * no-libgcrypt.c (gcry_strdup): New.
+
 2005-02-24  Werner Koch  <wk@g10code.com>
 
        * gpg-connect-agent.c: New.
index 399a5d3..19ff160 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <ctype.h>
 #include <assuan.h>
 
 #include "i18n.h"
@@ -40,7 +41,8 @@ enum cmd_and_opt_values
     oVerbose   = 'v',
 
     oNoVerbose = 500,
-    oHomedir
+    oHomedir,
+    oHex
 
   };
 
@@ -52,6 +54,7 @@ static ARGPARSE_OPTS opts[] =
     
     { oVerbose, "verbose",  0, N_("verbose") },
     { oQuiet, "quiet",      0, N_("quiet") },
+    { oHex,   "hex",        0, N_("print data out hex encoded") },
 
     /* hidden options */
     { oNoVerbose, "no-verbose",  0, "@"},
@@ -66,7 +69,7 @@ struct
   int verbose;         /* Verbosity level.  */
   int quiet;           /* Be extra quiet.  */
   const char *homedir;  /* Configuration directory name */
-
+  int hex;              /* Print data lines in hex format. */
 } opt;
 
 
@@ -155,6 +158,7 @@ main (int argc, char **argv)
         case oVerbose:   opt.verbose++; break;
         case oNoVerbose: opt.verbose = 0; break;
         case oHomedir:   opt.homedir = pargs.r.ret_str; break;
+        case oHex:       opt.hex = 1; break;
 
         default: pargs.err = 2; break;
        }
@@ -220,6 +224,7 @@ read_and_print_response (assuan_context_t ctx)
   char *line;
   int linelen;
   assuan_error_t rc;
+  int i, j;
 
   for (;;)
     {
@@ -234,8 +239,42 @@ read_and_print_response (assuan_context_t ctx)
       if (linelen >= 1
           && line[0] == 'D' && line[1] == ' ')
         {
-          fwrite (line, linelen, 1, stdout);
-          putchar ('\n');
+          if (opt.hex)
+            {
+              for (i=2; i < linelen; )
+                {
+                  int save_i = i;
+
+                  printf ("D[%04X] ", i-2);
+                  for (j=0; j < 16 ; j++, i++)
+                    {
+                      if (j == 8)
+                        putchar (' ');
+                      if (i < linelen)
+                        printf (" %02X", ((unsigned char*)line)[i]);
+                      else
+                        fputs ("   ", stdout);
+                    }
+                  fputs ("   ", stdout);
+                  i= save_i;
+                  for (j=0; j < 16; j++, i++)
+                    {
+                      unsigned int c = ((unsigned char*)line)[i];
+                      if ( i >= linelen )
+                        putchar (' ');
+                      else if (isascii (c) && isprint (c) && !iscntrl (c))
+                        putchar (c);
+                      else
+                        putchar ('.');
+                    }
+                  putchar ('\n');
+                }
+            }
+          else
+            {
+              fwrite (line, linelen, 1, stdout);
+              putchar ('\n');
+            }
         }
       else if (linelen >= 1
                && line[0] == 'S' 
index 0fabec9..82f6a8b 100644 (file)
@@ -53,6 +53,12 @@ gcry_xmalloc (size_t n)
   return p;
 }
 
+char *
+gcry_strdup (const char *string)
+{
+  return malloc (strlen (string)+1);
+}
+
 
 void *
 gcry_realloc (void *a, size_t n)