[git] GnuPG - branch, master, updated. gnupg-2.2.7-166-g8a915cd

by Werner Koch cvs at cvs.gnupg.org
Mon Jul 2 21:44:37 CEST 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  8a915cd9faf052b4faa3c415f2ac5aa8d6ea1efe (commit)
      from  58baf40af641f8cbf597e508a292e85ae94688f1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 8a915cd9faf052b4faa3c415f2ac5aa8d6ea1efe
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Jul 2 21:24:15 2018 +0200

    agent: New commands PUT_SECRET and GET_SECRET.
    
    * agent/agent.h (CACHE_MODE_DATA): New const.
    * agent/cache.c (DEF_CACHE_TTL_DATA): new.
    (housekeeping): Tweak for CACHE_MODE_DATA.
    (cache_mode_equal): Ditto.
    (agent_get_cache): Ditto.
    (agent_put_cache): Implement CACHE_MODE_DATA.
    * agent/command.c (MAXLEN_PUT_SECRET): New.
    (parse_ttl): New.
    (cmd_get_secret): New.
    (cmd_put_secret): New.
    (register_commands): Register new commands.
    --
    
    These commands allow to store secrets in memory for the lifetime of
    the gpg-agent process.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/agent/agent.h b/agent/agent.h
index 9fdbc76..9baf596 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -304,11 +304,12 @@ enum
 typedef enum
   {
     CACHE_MODE_IGNORE = 0, /* Special mode to bypass the cache. */
-    CACHE_MODE_ANY,        /* Any mode except ignore matches. */
+    CACHE_MODE_ANY,        /* Any mode except ignore and data matches. */
     CACHE_MODE_NORMAL,     /* Normal cache (gpg-agent). */
     CACHE_MODE_USER,       /* GET_PASSPHRASE related cache. */
     CACHE_MODE_SSH,        /* SSH related cache. */
-    CACHE_MODE_NONCE       /* This is a non-predictable nonce.  */
+    CACHE_MODE_NONCE,      /* This is a non-predictable nonce.  */
+    CACHE_MODE_DATA        /* Arbitrary data.  */
   }
 cache_mode_t;
 
diff --git a/agent/cache.c b/agent/cache.c
index 238b6e2..799d595 100644
--- a/agent/cache.c
+++ b/agent/cache.c
@@ -28,6 +28,10 @@
 
 #include "agent.h"
 
+/* The default TTL for DATA items.  This has no configure
+ * option because it is expected that clients provide a TTL.  */
+#define DEF_CACHE_TTL_DATA  (10 * 60)  /* 10 minutes.  */
+
 /* The size of the encryption key in bytes.  */
 #define ENCRYPTION_KEYSIZE (128/8)
 
@@ -50,11 +54,12 @@ struct secret_data_s {
   char data[1];  /* A string.  */
 };
 
+/* The cache object.  */
 typedef struct cache_item_s *ITEM;
 struct cache_item_s {
   ITEM next;
   time_t created;
-  time_t accessed;
+  time_t accessed;  /* Not updated for CACHE_MODE_DATA */
   int ttl;  /* max. lifetime given in seconds, -1 one means infinite */
   struct secret_data_s *pw;
   cache_mode_t cache_mode;
@@ -211,14 +216,18 @@ housekeeping (void)
         }
     }
 
-  /* Second, make sure that we also remove them based on the created stamp so
-     that the user has to enter it from time to time. */
+  /* Second, make sure that we also remove them based on the created
+   * stamp so that the user has to enter it from time to time.  We
+   * don't do this for data items which are used to storage secrets in
+   * meory and are not user entered passphrases etc.  */
   for (r=thecache; r; r = r->next)
     {
       unsigned long maxttl;
 
       switch (r->cache_mode)
         {
+        case CACHE_MODE_DATA:
+          continue;  /* No MAX TTL here.  */
         case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
         default: maxttl = opt.max_cache_ttl; break;
         }
@@ -315,8 +324,11 @@ static int
 cache_mode_equal (cache_mode_t a, cache_mode_t b)
 {
   /* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE.  */
-  return ((a == CACHE_MODE_ANY && b != CACHE_MODE_IGNORE)
-          || (b == CACHE_MODE_ANY && a != CACHE_MODE_IGNORE) || a == b);
+  return ((a == CACHE_MODE_ANY
+           && !(b == CACHE_MODE_IGNORE || b == CACHE_MODE_DATA))
+          || (b == CACHE_MODE_ANY
+              && !(a == CACHE_MODE_IGNORE || a == CACHE_MODE_DATA))
+          || a == b);
 }
 
 
@@ -349,6 +361,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
       switch(cache_mode)
         {
         case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break;
+        case CACHE_MODE_DATA: ttl = DEF_CACHE_TTL_DATA; break;
         default: ttl = opt.def_cache_ttl; break;
         }
     }
@@ -415,9 +428,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
 }
 
 
-/* Try to find an item in the cache.  Note that we currently don't
-   make use of CACHE_MODE except for CACHE_MODE_NONCE and
-   CACHE_MODE_USER.  */
+/* Try to find an item in the cache.  */
 char *
 agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
 {
@@ -458,8 +469,11 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
           && r->restricted == restricted
           && !strcmp (r->key, key))
         {
-          /* Note: To avoid races KEY may not be accessed anymore below.  */
-          r->accessed = gnupg_get_time ();
+          /* Note: To avoid races KEY may not be accessed anymore
+           * below.  Note also that we don't update the accessed time
+           * for data items.  */
+          if (r->cache_mode != CACHE_MODE_DATA)
+            r->accessed = gnupg_get_time ();
           if (DBG_CACHE)
             log_debug ("... hit\n");
           if (r->pw->totallen < 32)
diff --git a/agent/command.c b/agent/command.c
index 9bc3b02..925d1f7 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -50,6 +50,8 @@
 #define MAXLEN_KEYPARAM 1024
 /* Maximum allowed size of key data as used in inquiries (bytes). */
 #define MAXLEN_KEYDATA 8192
+/* Maximum length of a secret to store under one key.  */
+#define MAXLEN_PUT_SECRET 4096
 /* The size of the import/export KEK key (in bytes).  */
 #define KEYWRAP_KEYSIZE (128/8)
 
@@ -292,6 +294,31 @@ parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
 }
 
 
+/* Parse the TTL from STRING.  Leading and trailing spaces are
+ * skipped.  The value is constrained to -1 .. MAXINT.  On error 0 is
+ * returned, else the number of bytes scanned.  */
+static size_t
+parse_ttl (const char *string, int *r_ttl)
+{
+  const char *string_orig = string;
+  long ttl;
+  char *pend;
+
+  ttl = strtol (string, &pend, 10);
+  string = pend;
+  if (string == string_orig || !(spacep (string) || !*string)
+      || ttl < -1L || (int)ttl != (long)ttl)
+    {
+      *r_ttl = 0;
+      return 0;
+    }
+  while (spacep (string) || *string== '\n')
+    string++;
+  *r_ttl = (int)ttl;
+  return string - string_orig;
+}
+
+
 /* Write an Assuan status line.  KEYWORD is the first item on the
  * status line.  The following arguments are all separated by a space
  * in the output.  The last argument must be a NULL.  Linefeeds and
@@ -2568,6 +2595,187 @@ cmd_keytocard (assuan_context_t ctx, char *line)
 
 
 

+static const char hlp_get_secret[] =
+  "GET_SECRET <key>\n"
+  "\n"
+  "Return the secret value stored under KEY\n";
+static gpg_error_t
+cmd_get_secret (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+  char *p, *key;
+  char *value = NULL;
+  size_t valuelen;
+
+  /* For now we allow this only for local connections.  */
+  if (ctrl->restricted)
+    {
+      err = gpg_error (GPG_ERR_FORBIDDEN);
+      goto leave;
+    }
+
+  line = skip_options (line);
+
+  for (p=line; *p == ' '; p++)
+    ;
+  key = p;
+  p = strchr (key, ' ');
+  if (p)
+    {
+      *p++ = 0;
+      for (; *p == ' '; p++)
+        ;
+      if (*p)
+        {
+          err = set_error (GPG_ERR_ASS_PARAMETER, "too many arguments");
+          goto leave;
+        }
+    }
+  if (!*key)
+    {
+      err = set_error (GPG_ERR_ASS_PARAMETER, "no key given");
+      goto leave;
+    }
+
+
+  value = agent_get_cache (ctrl, key, CACHE_MODE_DATA);
+  if (!value)
+    {
+      err = gpg_error (GPG_ERR_NO_DATA);
+      goto leave;
+    }
+
+  valuelen = percent_unescape_inplace (value, 0);
+  err = assuan_send_data (ctx, value, valuelen);
+  wipememory (value, valuelen);
+
+ leave:
+  xfree (value);
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_put_secret[] =
+  "PUT_SECRET [--clear] <key> <ttl> [<percent_escaped_value>]\n"
+  "\n"
+  "This commands stores a secret under KEY in gpg-agent's in-memory\n"
+  "cache.  The TTL must be explicitly given by TTL and the options\n"
+  "from the configuration file are not used.  The value is either given\n"
+  "percent-escaped as 3rd argument or if not given inquired by gpg-agent\n"
+  "using the keyword \"SECRET\".\n"
+  "The option --clear removes the secret from the cache."
+  "";
+static gpg_error_t
+cmd_put_secret (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  int opt_clear;
+  unsigned char *value = NULL;
+  size_t valuelen = 0;
+  size_t n;
+  char *p, *key, *ttlstr;
+  unsigned char *valstr;
+  int ttl;
+  char *string = NULL;
+
+  /* For now we allow this only for local connections.  */
+  if (ctrl->restricted)
+    {
+      err = gpg_error (GPG_ERR_FORBIDDEN);
+      goto leave;
+    }
+
+  opt_clear = has_option (line, "--clear");
+  line = skip_options (line);
+
+  for (p=line; *p == ' '; p++)
+    ;
+  key = p;
+  ttlstr = NULL;
+  valstr = NULL;
+  p = strchr (key, ' ');
+  if (p)
+    {
+      *p++ = 0;
+      for (; *p == ' '; p++)
+        ;
+      if (*p)
+        {
+          ttlstr = p;
+          p = strchr (ttlstr, ' ');
+          if (p)
+            {
+              *p++ = 0;
+              for (; *p == ' '; p++)
+                ;
+              if (*p)
+                valstr = p;
+            }
+        }
+    }
+  if (!*key)
+    {
+      err = set_error (GPG_ERR_ASS_PARAMETER, "no key given");
+      goto leave;
+    }
+  if (!ttlstr || !*ttlstr || !(n = parse_ttl (ttlstr, &ttl)))
+    {
+      err = set_error (GPG_ERR_ASS_PARAMETER, "no or invalid TTL given");
+      goto leave;
+    }
+  if (valstr && opt_clear)
+    {
+      err = set_error (GPG_ERR_ASS_PARAMETER,
+                       "value not expected with --clear");
+      goto leave;
+    }
+
+  if (valstr)
+    {
+      valuelen = percent_unescape_inplace (valstr, 0);
+      value = NULL;
+    }
+  else /* Inquire the value to store */
+    {
+      err = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u",MAXLEN_PUT_SECRET);
+      if (!err)
+        err = assuan_inquire (ctx, "SECRET",
+                              &value, &valuelen, MAXLEN_PUT_SECRET);
+      if (err)
+        goto leave;
+    }
+
+  /* Our cache expects strings and thus we need to turn the buffer
+   * into a string.  Instead of resorting to base64 encoding we use a
+   * special percent escaping which only quoted the Nul and the
+   * percent character. */
+  string = percent_data_escape (value? value : valstr, valuelen);
+  if (!string)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = agent_put_cache (ctrl, key, CACHE_MODE_DATA, string, ttl);
+
+
+ leave:
+  if (string)
+    {
+      wipememory (string, strlen (string));
+      xfree (string);
+    }
+  if (value)
+    {
+      wipememory (value, valuelen);
+      xfree (value);
+    }
+  return leave_cmd (ctx, err);
+}
+
+
+

 static const char hlp_getval[] =
   "GETVAL <key>\n"
   "\n"
@@ -3259,6 +3467,8 @@ register_commands (assuan_context_t ctx)
     { "IMPORT_KEY",     cmd_import_key, hlp_import_key },
     { "EXPORT_KEY",     cmd_export_key, hlp_export_key },
     { "DELETE_KEY",     cmd_delete_key, hlp_delete_key },
+    { "GET_SECRET",     cmd_get_secret, hlp_get_secret },
+    { "PUT_SECRET",     cmd_put_secret, hlp_put_secret },
     { "GETVAL",         cmd_getval,    hlp_getval },
     { "PUTVAL",         cmd_putval,    hlp_putval },
     { "UPDATESTARTUPTTY",  cmd_updatestartuptty, hlp_updatestartuptty },

-----------------------------------------------------------------------

Summary of changes:
 agent/agent.h   |   5 +-
 agent/cache.c   |  34 ++++++---
 agent/command.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 237 insertions(+), 12 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list