Support a confirm flag for ssh.
authorWerner Koch <wk@gnupg.org>
Wed, 20 Jul 2011 18:49:41 +0000 (20:49 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 4 Aug 2011 12:42:31 +0000 (14:42 +0200)
This implements the suggestion from bug#1349.  With this change the
fingerprint of the ssh key is also displayed in the pinentry prompts.

NEWS
agent/ChangeLog
agent/agent.h
agent/command-ssh.c
agent/findkey.c
common/Makefile.am
common/t-ssh-utils.c
doc/gpg-agent.texi

diff --git a/NEWS b/NEWS
index ca7185a..a4dbff2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,8 @@ Noteworthy changes in version 2.0.18 (unreleased)
 
  * Bug fix for newer versions of Libgcrypt.
 
+ * Support the SSH confirm flag.
+
  * Improved dirmngr/gpgsm interaction for OCSP.
 
 
index ccd2772..9060a49 100644 (file)
@@ -1,5 +1,20 @@
 2011-08-04  Werner Koch  <wk@g10code.com>
 
+       * command-ssh.c (ssh_identity_register): Display the ssh
+       fingerprint in the prompt.
+       (add_control_entry): Add arg FMTFPR and use it as comment in
+       sshcontrol.
+       (confirm_flag_from_sshcontrol): New.
+       (data_sign): Ask for confirmaton if requested.
+       (search_control_file): Add new arg R_CONFIRM and enhance parser.
+       * findkey.c (agent_raw_key_from_file): New.
+       (modify_description): Add format letter %F.
+
+       * findkey.c (agent_key_from_file): Simplify comment extraction by
+       using gcry_sexp_nth_string.
+
+2011-08-04  Werner Koch  <wk@g10code.com>
+
        * genkey.c (check_passphrase_pattern): Use gpg_strerror.
 
        * command-ssh.c (ssh_receive_mpint_list): Remove set but unused
index 30af016..15cf8bf 100644 (file)
@@ -117,7 +117,7 @@ struct
 #define DBG_CACHE_VALUE   64   /* debug the caching */
 #define DBG_MEMSTAT_VALUE 128  /* show memory statistics */
 #define DBG_HASHING_VALUE 512  /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024   
+#define DBG_ASSUAN_VALUE 1024
 
 #define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
 #define DBG_CRYPTO  (opt.debug & DBG_CRYPTO_VALUE)
@@ -130,14 +130,14 @@ struct server_local_s;
 struct scd_local_s;
 
 /* Collection of data per session (aka connection). */
-struct server_control_s 
+struct server_control_s
 {
   /* Private data used to fire up the connection thread.  We use this
      structure do avoid an extra allocation for just a few bytes. */
   struct {
     gnupg_fd_t fd;
   } thread_startup;
-  
+
   /* Private data of the server (command.c). */
   struct server_local_s *server_local;
 
@@ -164,7 +164,7 @@ struct server_control_s
 };
 
 
-struct pin_entry_info_s 
+struct pin_entry_info_s
 {
   int min_digits; /* min. number of digits required or 0 for freeform entry */
   int max_digits; /* max. number of allowed digits allowed*/
@@ -179,7 +179,7 @@ struct pin_entry_info_s
 };
 
 
-enum 
+enum
   {
     PRIVATE_KEY_UNKNOWN = 0,
     PRIVATE_KEY_CLEAR = 1,
@@ -189,7 +189,7 @@ enum
 
 
 /* Values for the cache_mode arguments. */
-typedef enum 
+typedef enum
   {
     CACHE_MODE_IGNORE = 0, /* Special mode to bypass the cache. */
     CACHE_MODE_ANY,        /* Any mode except ignore matches. */
@@ -227,14 +227,16 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
 /*-- findkey.c --*/
 int agent_write_private_key (const unsigned char *grip,
                              const void *buffer, size_t length, int force);
-gpg_error_t agent_key_from_file (ctrl_t ctrl, 
+gpg_error_t agent_key_from_file (ctrl_t ctrl,
                                  const char *desc_text,
                                  const unsigned char *grip,
                                  unsigned char **shadow_info,
                                  cache_mode_t cache_mode,
                                  lookup_ttl_t lookup_ttl,
                                  gcry_sexp_t *result);
-gpg_error_t agent_public_key_from_file (ctrl_t ctrl, 
+gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
+                                     gcry_sexp_t *result);
+gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
                                         const unsigned char *grip,
                                         gcry_sexp_t *result);
 int agent_key_available (const unsigned char *grip);
@@ -285,7 +287,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
 
 /*-- genkey.c --*/
 int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
-int agent_genkey (ctrl_t ctrl, 
+int agent_genkey (ctrl_t ctrl,
                   const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
 int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
 
@@ -294,7 +296,7 @@ unsigned long get_standard_s2k_count (void);
 int agent_protect (const unsigned char *plainkey, const char *passphrase,
                    unsigned char **result, size_t *resultlen);
 int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
-                     gnupg_isotime_t protected_at, 
+                     gnupg_isotime_t protected_at,
                      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);
@@ -303,7 +305,7 @@ int agent_shadow_key (const unsigned char *pubkey,
                       unsigned char **result);
 int agent_get_shadow_info (const unsigned char *shadowkey,
                            unsigned char const **shadow_info);
-gpg_error_t parse_shadow_info (const unsigned char *shadow_info, 
+gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
                                char **r_hexsn, char **r_idstr);
 
 
@@ -317,7 +319,7 @@ void agent_reload_trustlist (void);
 
 
 /*-- divert-scd.c --*/
-int divert_pksign (ctrl_t ctrl, 
+int divert_pksign (ctrl_t ctrl,
                    const unsigned char *digest, size_t digestlen, int algo,
                    const unsigned char *shadow_info, unsigned char **r_sig);
 int divert_pkdecrypt (ctrl_t ctrl,
index d9708ad..2f96ef5 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "estream.h"
 #include "i18n.h"
+#include "../common/ssh-utils.h"
+
 
 \f
 
@@ -711,18 +713,25 @@ open_control_file (FILE **r_fp, int append)
 /* Search the file at stream FP from the beginning until a matching
    HEXGRIP is found; return success in this case and store true at
    DISABLED if the found key has been disabled.  If R_TTL is not NULL
-   a specified TTL for that key is stored there. */
+   a specified TTL for that key is stored there.  If R_CONFIRM is not
+   NULL it is set to 1 if the key has the confirm flag set. */
 static gpg_error_t
 search_control_file (FILE *fp, const char *hexgrip,
-                     int *r_disabled, int *r_ttl)
+                     int *r_disabled, int *r_ttl, int *r_confirm)
 {
-  int c, i;
+  int c, i, n;
   char *p, *pend, line[256];
   long ttl;
+  int lnr = 0;
+  const char fname[] = "sshcontrol";
 
   assert (strlen (hexgrip) == 40 );
 
-  rewind (fp);
+  if (r_confirm)
+    *r_confirm = 0;
+
+  fseek (fp, 0, SEEK_SET);
+  clearerr (fp);
   *r_disabled = 0;
  next_line:
   do
@@ -733,6 +742,7 @@ search_control_file (FILE *fp, const char *hexgrip,
             return gpg_error (GPG_ERR_EOF);
           return gpg_error (gpg_err_code_from_errno (errno));
         }
+      lnr++;
 
       if (!*line || line[strlen(line)-1] != '\n')
         {
@@ -762,7 +772,7 @@ search_control_file (FILE *fp, const char *hexgrip,
       goto next_line;
   if (i != 40 || !(spacep (p) || *p == '\n'))
     {
-      log_error ("invalid formatted line in ssh control file\n");
+      log_error ("invalid formatted line in `%s', line %d\n", fname, lnr);
       return gpg_error (GPG_ERR_BAD_DATA);
     }
 
@@ -770,13 +780,37 @@ search_control_file (FILE *fp, const char *hexgrip,
   p = pend;
   if (!(spacep (p) || *p == '\n') || ttl < -1)
     {
-      log_error ("invalid TTL value in ssh control file; assuming 0\n");
+      log_error ("invalid TTL value in `%s', line %d; assuming 0\n",
+                 fname, lnr);
       ttl = 0;
     }
   if (r_ttl)
     *r_ttl = ttl;
 
-  /* Here is the place to parse flags if we need them.  */
+  /* Now check for key-value pairs of the form NAME[=VALUE]. */
+  while (*p)
+    {
+      for (; spacep (p) && *p != '\n'; p++)
+        ;
+      if (!*p || *p == '\n')
+        break;
+      n = strcspn (p, "= \t\n");
+      if (p[n] == '=')
+        {
+          log_error ("assigning a value to a flag is not yet supported; "
+                     "in `%s', line %d; flag ignored\n", fname, lnr);
+          p++;
+        }
+      else if (n == 7 && !memcmp (p, "confirm", 7))
+        {
+          if (r_confirm)
+            *r_confirm = 1;
+        }
+      else
+        log_error ("invalid flag `%.*s' in `%s', line %d; ignored\n",
+                   n, p, fname, lnr);
+      p += n;
+    }
 
   return 0; /* Okay:  found it.  */
 }
@@ -785,11 +819,12 @@ search_control_file (FILE *fp, const char *hexgrip,
 
 /* Add an entry to the control file to mark the key with the keygrip
    HEXGRIP as usable for SSH; i.e. it will be returned when ssh asks
-   for it.  This function is in general used to add a key received
-   through the ssh-add function.  We can assume that the user wants to
-   allow ssh using this key. */
+   for it.  FMTFPR is the fingerprint string.  This function is in
+   general used to add a key received through the ssh-add function.
+   We can assume that the user wants to allow ssh using this key. */
 static gpg_error_t
-add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
+add_control_entry (ctrl_t ctrl, const char *hexgrip, const char *fmtfpr,
+                   int ttl, int confirm)
 {
   gpg_error_t err;
   FILE *fp;
@@ -801,7 +836,7 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
   if (err)
     return err;
 
-  err = search_control_file (fp, hexgrip, &disabled, NULL);
+  err = search_control_file (fp, hexgrip, &disabled, NULL, NULL);
   if (err && gpg_err_code(err) == GPG_ERR_EOF)
     {
       struct tm *tp;
@@ -810,10 +845,12 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
       /* Not yet in the file - add it. Because the file has been
          opened in append mode, we simply need to write to it.  */
       tp = localtime (&atime);
-      fprintf (fp, "# Key added on %04d-%02d-%02d %02d:%02d:%02d\n%s %d\n",
+      fprintf (fp, ("# Key added on: %04d-%02d-%02d %02d:%02d:%02d\n"
+                    "# Fingerprint:  %s\n"
+                    "%s %d%s\n"),
                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
                tp->tm_hour, tp->tm_min, tp->tm_sec,
-               hexgrip, ttl);
+               fmtfpr, hexgrip, ttl, confirm? " confirm":"");
 
     }
   fclose (fp);
@@ -834,7 +871,7 @@ ttl_from_sshcontrol (const char *hexgrip)
   if (open_control_file (&fp, 0))
     return 0; /* Error: Use the global default TTL.  */
 
-  if (search_control_file (fp, hexgrip, &disabled, &ttl)
+  if (search_control_file (fp, hexgrip, &disabled, &ttl, NULL)
       || disabled)
     ttl = 0;  /* Use the global default if not found or disabled.  */
 
@@ -844,6 +881,30 @@ ttl_from_sshcontrol (const char *hexgrip)
 }
 
 
+/* Scan the sshcontrol file and return the confirm flag.  */
+static int
+confirm_flag_from_sshcontrol (const char *hexgrip)
+{
+  FILE *fp;
+  int disabled, confirm;
+
+  if (!hexgrip || strlen (hexgrip) != 40)
+    return 1;  /* Wrong input: Better ask for confirmation.  */
+
+  if (open_control_file (&fp, 0))
+    return 1; /* Error: Better ask for confirmation.  */
+
+  if (search_control_file (fp, hexgrip, &disabled, NULL, &confirm)
+      || disabled)
+    confirm = 0;  /* If not found or disabled, there is no reason to
+                     ask for confirmation.  */
+
+  fclose (fp);
+
+  return confirm;
+}
+
+
 
 \f
 
@@ -1583,6 +1644,7 @@ ssh_key_grip (gcry_sexp_t key, unsigned char *buffer)
   return 0;
 }
 
+
 /* Converts the secret key KEY_SECRET into a public key, storing it in
    KEY_PUBLIC.  SPEC is the according key specification.  Returns zero
    on success or an error code.  */
@@ -1904,7 +1966,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
           hexgrip[40] = 0;
           if ( strlen (hexgrip) != 40 )
             continue;
-          if (search_control_file (ctrl_fp, hexgrip, &disabled, NULL)
+          if (search_control_file (ctrl_fp, hexgrip, &disabled, NULL, NULL)
               || disabled)
             continue;
 
@@ -2039,14 +2101,60 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder,
   const char *elems;
   size_t elems_n;
   gcry_mpi_t *mpis = NULL;
+  char hexgrip[40+1];
 
   *sig = NULL;
   *sig_n = 0;
 
+  /* Quick check to see whether we have a valid keygrip and convert it
+     to hex.  */
+  if (!ctrl->have_keygrip)
+    {
+      err = gpg_error (GPG_ERR_NO_SECKEY);
+      goto out;
+    }
+  bin2hex (ctrl->keygrip, 20, hexgrip);
+
+  /* Ask for confirmation if needed.  */
+  if (confirm_flag_from_sshcontrol (hexgrip))
+    {
+      gcry_sexp_t key;
+      char *fpr, *prompt;
+      char *comment = NULL;
+
+      err = agent_raw_key_from_file (ctrl, ctrl->keygrip, &key);
+      if (err)
+        goto out;
+      err = ssh_get_fingerprint_string (key, &fpr);
+      if (!err)
+        {
+          gcry_sexp_t tmpsxp = gcry_sexp_find_token (key, "comment", 0);
+          if (tmpsxp)
+            comment = gcry_sexp_nth_string (tmpsxp, 1);
+          gcry_sexp_release (tmpsxp);
+        }
+      gcry_sexp_release (key);
+      if (err)
+        goto out;
+      prompt = xtryasprintf (_("An ssh process requested the use of key%%0A"
+                               "  %s%%0A"
+                               "  (%s)%%0A"
+                               "Do you want to allow this?"),
+                             fpr, comment? comment:"");
+      xfree (fpr);
+      gcry_free (comment);
+      err = agent_get_confirmation (ctrl, prompt, _("Allow"), _("Deny"), 0);
+      xfree (prompt);
+      if (err)
+        goto out;
+    }
+
+  /* Create signature.  */
   ctrl->use_auth_call = 1;
   err = agent_pksign_do (ctrl,
                          _("Please enter the passphrase "
-                           "for the ssh key%0A  %c"), &signature_sexp,
+                           "for the ssh key%%0A  %F%%0A  (%c)"),
+                         &signature_sexp,
                          CACHE_MODE_SSH, ttl_from_sshcontrol);
   ctrl->use_auth_call = 0;
   if (err)
@@ -2365,7 +2473,7 @@ reenter_compare_cb (struct pin_entry_info_s *pi)
    our key storage, don't do anything.  When entering a new key also
    add an entry to the sshcontrol file.  */
 static gpg_error_t
-ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
+ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl, int confirm)
 {
   gpg_error_t err;
   unsigned char key_grip_raw[20];
@@ -2375,6 +2483,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
   char *description = NULL;
   const char *description2 = _("Please re-enter this passphrase");
   char *comment = NULL;
+  char *key_fpr = NULL;
   const char *initial_errtext = NULL;
   unsigned int i;
   struct pin_entry_info_s *pi = NULL, *pi2;
@@ -2388,6 +2497,9 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
   if ( !agent_key_available (key_grip_raw) )
     goto out; /* Yes, key is available.  */
 
+  err = ssh_get_fingerprint_string (key, &key_fpr);
+  if (err)
+    goto out;
 
   err = ssh_key_extract_comment (key, &comment);
   if (err)
@@ -2397,8 +2509,9 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
                  _("Please enter a passphrase to protect"
                    " the received secret key%%0A"
                    "   %s%%0A"
+                   "   %s%%0A"
                    "within gpg-agent's key storage"),
-                 comment ? comment : "?") < 0)
+                 key_fpr, comment ? comment : "") < 0)
     {
       err = gpg_error_from_syserror ();
       goto out;
@@ -2455,7 +2568,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
     goto out;
 
   /* And add an entry to the sshcontrol file.  */
-  err = add_control_entry (ctrl, key_grip, ttl);
+  err = add_control_entry (ctrl, key_grip, key_fpr, ttl, confirm);
 
 
  out:
@@ -2464,6 +2577,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
   xfree (pi);
   xfree (buffer);
   xfree (comment);
+  xfree (key_fpr);
   xfree (description);
 
   return err;
@@ -2548,9 +2662,7 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
   if (err)
     goto out;
 
-  /* FIXME: are constraints used correctly?  */
-
-  err = ssh_identity_register (ctrl, key, ttl);
+  err = ssh_identity_register (ctrl, key, ttl, confirm);
 
  out:
 
index 5c933f7..800db88 100644 (file)
@@ -1,6 +1,6 @@
 /* findkey.c - Locate the secret key
- * Copyright (C) 2001, 2002, 2003, 2004, 2005,
- *               2007  Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
+ *               2010, 2011 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 
 #include "agent.h"
 #include "i18n.h"
+#include "../common/ssh-utils.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
 
 /* Helper to pass data to the check callback of the unprotect function. */
-struct try_unprotect_arg_s 
+struct try_unprotect_arg_s
 {
   ctrl_t ctrl;
   const unsigned char *protected_key;
@@ -60,7 +61,7 @@ agent_write_private_key (const unsigned char *grip,
   FILE *fp;
   char hexgrip[40+4+1];
   int fd;
-  
+
   bin2hex (grip, 20, hexgrip);
   strcpy (hexgrip+40, ".key");
 
@@ -80,9 +81,9 @@ agent_write_private_key (const unsigned char *grip,
      then use fdopen to obtain a stream. */
   fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY | O_BINARY)
                          : (O_CREAT | O_EXCL | O_WRONLY | O_BINARY),
-             S_IRUSR | S_IWUSR 
+             S_IRUSR | S_IWUSR
 #ifndef HAVE_W32_SYSTEM
-                 | S_IRGRP 
+                 | S_IRGRP
 #endif
                  );
   if (fd < 0)
@@ -91,15 +92,15 @@ agent_write_private_key (const unsigned char *grip,
     {
       fp = fdopen (fd, "wb");
       if (!fp)
-        { 
+        {
           int save_e = errno;
           close (fd);
           errno = save_e;
         }
     }
 
-  if (!fp) 
-    { 
+  if (!fp)
+    {
       gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
       log_error ("can't create `%s': %s\n", fname, strerror (errno));
       xfree (fname);
@@ -168,7 +169,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
       if (strcmp (now, tmptime) > 0 )
         {
           /* Passphrase "expired".  */
-          desc = xtryasprintf 
+          desc = xtryasprintf
             (_("This passphrase has not been changed%%0A"
                "since %.4s-%.2s-%.2s.  Please change it now."),
              protected_at, protected_at+4, protected_at+6);
@@ -209,12 +210,14 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
 
    %% - Replaced by a single %
    %c - Replaced by the content of COMMENT.
+   %F - Replaced by an ssh style fingerprint computed from KEY.
 
    The functions returns 0 on success or an error code.  On success a
    newly allocated string is stored at the address of RESULT.
  */
 static gpg_error_t
-modify_description (const char *in, const char *comment, char **result)
+modify_description (const char *in, const char *comment, const gcry_sexp_t key,
+                    char **result)
 {
   size_t comment_length;
   size_t in_len;
@@ -222,6 +225,7 @@ modify_description (const char *in, const char *comment, char **result)
   char *out;
   size_t i;
   int special, pass;
+  char *ssh_fpr = NULL;
 
   comment_length = strlen (comment);
   in_len  = strlen (in);
@@ -257,6 +261,18 @@ modify_description (const char *in, const char *comment, char **result)
                     out_len += comment_length;
                   break;
 
+                case 'F': /* SSH style fingerprint.  */
+                  if (!ssh_fpr && key)
+                    ssh_get_fingerprint_string (key, &ssh_fpr);
+                  if (ssh_fpr)
+                    {
+                      if (out)
+                        out = stpcpy (out, ssh_fpr);
+                      else
+                        out_len += strlen (ssh_fpr);
+                    }
+                  break;
+
                 default: /* Invalid special sequences are kept as they are. */
                   if (out)
                     {
@@ -278,21 +294,25 @@ modify_description (const char *in, const char *comment, char **result)
                 out_len++;
             }
         }
-      
+
       if (!pass)
         {
           *result = out = xtrymalloc (out_len + 1);
           if (!out)
-            return gpg_error_from_syserror ();
+            {
+              xfree (ssh_fpr);
+              return gpg_error_from_syserror ();
+            }
         }
     }
 
   *out = 0;
   assert (*result + out_len == out);
+  xfree (ssh_fpr);
   return 0;
 }
 
-  
+
 
 /* Unprotect the canconical encoded S-expression key in KEYBUF.  GRIP
    should be the hex encoded keygrip of that key to be used with the
@@ -301,7 +321,7 @@ modify_description (const char *in, const char *comment, char **result)
    function is used to lookup the default ttl. */
 static int
 unprotect (ctrl_t ctrl, const char *desc_text,
-           unsigned char **keybuf, const unsigned char *grip, 
+           unsigned char **keybuf, const unsigned char *grip,
            cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
 {
   struct pin_entry_info_s *pi;
@@ -310,7 +330,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
   unsigned char *result;
   size_t resultlen;
   char hexgrip[40+1];
-  
+
   bin2hex (grip, 20, hexgrip);
 
   /* First try to get it from the cache - if there is none or we can't
@@ -319,7 +339,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
     {
       void *cache_marker;
       const char *pw;
-      
+
     retry:
       pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
       if (pw)
@@ -352,7 +372,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
             {
               /* We need to give the other thread a chance to actually put
                  it into the cache. */
-              pth_sleep (1); 
+              pth_sleep (1);
               goto retry;
             }
           /* Timeout - better call pinentry now the plain way. */
@@ -381,7 +401,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
         {
           size_t canlen, erroff;
           gcry_sexp_t s_skey;
-          
+
           assert (arg.unprotected_key);
           canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
           rc = gcry_sexp_sscan (&s_skey, &erroff,
@@ -399,7 +419,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
           gcry_sexp_release (s_skey);
           if (rc)
             {
-              log_error ("changing the passphrase failed: %s\n", 
+              log_error ("changing the passphrase failed: %s\n",
                          gpg_strerror (rc));
               wipememory (arg.unprotected_key, canlen);
               xfree (arg.unprotected_key);
@@ -407,8 +427,8 @@ unprotect (ctrl_t ctrl, const char *desc_text,
               return rc;
             }
         }
-      else 
-        agent_put_cache (hexgrip, cache_mode, pi->pin, 
+      else
+        agent_put_cache (hexgrip, cache_mode, pi->pin,
                          lookup_ttl? lookup_ttl (hexgrip) : 0);
       xfree (*keybuf);
       *keybuf = arg.unprotected_key;
@@ -432,7 +452,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
   size_t buflen, erroff;
   gcry_sexp_t s_skey;
   char hexgrip[40+4+1];
-  
+
   *result = NULL;
 
   bin2hex (grip, 20, hexgrip);
@@ -448,7 +468,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
       xfree (fname);
       return rc;
     }
-  
+
   if (fstat (fileno(fp), &st))
     {
       rc = gpg_error_from_syserror ();
@@ -507,7 +527,7 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
   size_t len, buflen, erroff;
   gcry_sexp_t s_skey;
   int got_shadow_info = 0;
-  
+
   *result = NULL;
   if (shadow_info)
     *shadow_info = NULL;
@@ -529,45 +549,26 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
       break; /* no unprotection needed */
     case PRIVATE_KEY_PROTECTED:
       {
-       gcry_sexp_t comment_sexp;
-       size_t comment_length;
        char *desc_text_final;
-       const char *comment = NULL;
+       char *comment = NULL;
 
         /* Note, that we will take the comment as a C string for
            display purposes; i.e. all stuff beyond a Nul character is
            ignored.  */
-       comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
-       if (comment_sexp)
-         comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
-       if (!comment)
-         {
-           comment = "";
-           comment_length = 0;
-         }
+        {
+          gcry_sexp_t comment_sexp;
+
+          comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
+          if (comment_sexp)
+            comment = gcry_sexp_nth_string (comment_sexp, 1);
+          gcry_sexp_release (comment_sexp);
+        }
 
         desc_text_final = NULL;
        if (desc_text)
-         {
-            if (comment[comment_length])
-              {
-                /* Not a C-string; create one.  We might here allocate
-                   more than actually displayed but well, that
-                   shouldn't be a problem.  */
-                char *tmp = xtrymalloc (comment_length+1);
-                if (!tmp)
-                  rc = gpg_error_from_syserror ();
-                else
-                  {
-                    memcpy (tmp, comment, comment_length);
-                    tmp[comment_length] = 0;
-                    rc = modify_description (desc_text, tmp, &desc_text_final);
-                    xfree (tmp);
-                  }
-              }
-            else
-              rc = modify_description (desc_text, comment, &desc_text_final);
-         }
+          rc = modify_description (desc_text, comment? comment:"", s_skey,
+                                   &desc_text_final);
+        gcry_free (comment);
 
        if (!rc)
          {
@@ -577,8 +578,7 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
              log_error ("failed to unprotect the secret key: %s\n",
                         gpg_strerror (rc));
          }
-        
-       gcry_sexp_release (comment_sexp);
+
        xfree (desc_text_final);
       }
       break;
@@ -638,13 +638,34 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
 }
 
 
+/* Return the key for the keygrip GRIP.  The result is stored at
+   RESULT.  This function extracts the key from the private key
+   database and returns it as an S-expression object as it is.  On
+   failure an error code is returned and NULL stored at RESULT. */
+gpg_error_t
+agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
+                         gcry_sexp_t *result)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_skey;
+
+  (void)ctrl;
+
+  *result = NULL;
+
+  err = read_key_file (grip, &s_skey);
+  if (!err)
+    *result = s_skey;
+  return err;
+}
+
 
 /* Return the public key for the keygrip GRIP.  The result is stored
    at RESULT.  This function extracts the public key from the private
    key database.  On failure an error code is returned and NULL stored
    at RESULT. */
 gpg_error_t
-agent_public_key_from_file (ctrl_t ctrl, 
+agent_public_key_from_file (ctrl_t ctrl,
                             const unsigned char *grip,
                             gcry_sexp_t *result)
 {
@@ -723,7 +744,7 @@ agent_public_key_from_file (ctrl_t ctrl,
       return rc;
     }
 
-  for (idx=0, s=elems; *s; s++, idx++ ) 
+  for (idx=0, s=elems; *s; s++, idx++ )
     {
       l2 = gcry_sexp_find_token (list, s, 1);
       if (!l2)
@@ -790,7 +811,7 @@ agent_public_key_from_file (ctrl_t ctrl,
 
   argidx = 0;
   p = stpcpy (stpcpy (format, "(public-key("), algoname);
-  for (idx=0, s=elems; *s; s++, idx++ ) 
+  for (idx=0, s=elems; *s; s++, idx++ )
     {
       *p++ = '(';
       *p++ = *s;
@@ -817,7 +838,7 @@ agent_public_key_from_file (ctrl_t ctrl,
   *p = 0;
   assert (argidx < DIM (args));
   args[argidx] = NULL;
-    
+
   rc = gcry_sexp_build_array (&list, NULL, format, args);
   xfree (format);
   for (i=0; array[i]; i++)
@@ -841,7 +862,7 @@ agent_key_available (const unsigned char *grip)
   int result;
   char *fname;
   char hexgrip[40+4+1];
-  
+
   bin2hex (grip, 20, hexgrip);
   strcpy (hexgrip+40, ".key");
 
@@ -867,7 +888,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
   int keytype;
 
   (void)ctrl;
-  
+
   if (r_keytype)
     *r_keytype = PRIVATE_KEY_UNKNOWN;
   if (r_shadow_info)
@@ -875,7 +896,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
 
   {
     gcry_sexp_t sexp;
-    
+
     err = read_key_file (grip, &sexp);
     if (err)
       {
@@ -889,12 +910,12 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
     if (err)
       return err;
   }
-  
+
   keytype = agent_private_key_type (buf);
   switch (keytype)
     {
     case PRIVATE_KEY_CLEAR:
-      break; 
+      break;
     case PRIVATE_KEY_PROTECTED:
       /* If we ever require it we could retrieve the comment fields
          from such a key. */
index 7a3a773..10c5403 100644 (file)
@@ -123,21 +123,8 @@ endif
 #
 # Module tests
 #
-<<<<<<< HEAD
 module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp \
-              t-session-env
-=======
-t_jnlib_src = t-support.c t-support.h
-jnlib_tests = t-stringhelp t-timestuff
-if HAVE_W32_SYSTEM
-jnlib_tests += t-w32-reg
-endif
-module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
-              t-session-env t-openpgp-oid t-ssh-utils
-if !HAVE_W32CE_SYSTEM
-module_tests += t-exechelp
-endif
->>>>>>> New functions to compute an ssh style fingerprint.
+              t-session-env t-ssh-utils
 module_maint_tests = t-helpfile t-b64
 
 t_common_ldadd = libcommon.a ../jnlib/libjnlib.a ../gl/libgnu.a \
@@ -152,9 +139,4 @@ t_sexputil_LDADD = $(t_common_ldadd)
 t_b64_LDADD = $(t_common_ldadd)
 t_exechelp_LDADD = $(t_common_ldadd)
 t_session_env_LDADD = $(t_common_ldadd)
-<<<<<<< HEAD
-
-=======
-t_openpgp_oid_LDADD = $(t_common_ldadd)
 t_ssh_utils_LDADD = $(t_common_ldadd)
->>>>>>> New functions to compute an ssh style fingerprint.
index cd1252f..a8a63cf 100644 (file)
 #include "util.h"
 #include "ssh-utils.h"
 
-#define pass()  do { ; } while(0)
-#define fail(a,e)                                                       \
-  do { fprintf (stderr, "%s:%d: test %d failed (%s)\n",                 \
-                __FILE__,__LINE__, (a), gpg_strerror (e));              \
-    exit (1);                                                           \
-  } while(0)
-
 
 static struct { const char *key; const char *fpr; } sample_keys[] = {
   { "(protected-private-key "
index cb5f7d7..2bd9572 100644 (file)
@@ -640,6 +640,12 @@ digits, optionally followed by the caching TTL in seconds and another
 optional field for arbitrary flags.  A non-zero TTL overrides the global
 default as set by @option{--default-cache-ttl-ssh}.
 
+The only flag support is @code{confirm}.  If this flag is found for a
+key, each use of the key will pop up a pinentry to confirm the use of
+that key.  The flag is automatically set if a new key was loaded into
+@code{gpg-agent} using the option @option{-c} of the @code{ssh-add}
+command.
+
 The keygrip may be prefixed with a @code{!} to disable an entry entry.
     
 The following example lists exactly one key.  Note that keys available
@@ -647,8 +653,9 @@ through a OpenPGP smartcard in the active smartcard reader are
 implicitly added to this list; i.e. there is no need to list them.
   
   @example
-  # Key added on 2005-02-25 15:08:29
-  5A6592BF45DC73BD876874A28FD4639282E29B52 0
+  # Key added on: 2011-07-20 20:38:46
+  # Fingerprint:  5e:8d:c4:ad:e7:af:6e:27:8a:d6:13:e4:79:ad:0b:81
+  34B62F25E277CF13D3C6BCEBFD3F85D08F0A864B 0 confirm
   @end example
 
 @item private-keys-v1.d/