Imported Upstream version 2.1.12 upstream/2.1.12
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:09 +0000 (16:00 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 9 Feb 2021 07:00:09 +0000 (16:00 +0900)
236 files changed:
Makefile.am
NEWS
agent/Makefile.am
agent/agent.h
agent/command-ssh.c
agent/command.c
agent/cvt-openpgp.c
agent/findkey.c
agent/genkey.c
agent/gpg-agent.c
agent/keyformat.txt
agent/protect-tool.c
agent/protect.c
agent/t-protect.c
autogen.rc
build-aux/config.guess
build-aux/config.sub
build-aux/speedo.mk
build-aux/speedo/patches/sqlite.patch [new file with mode: 0755]
build-aux/speedo/w32/inst.nsi
build-aux/speedo/w32/pkg-copyright.txt
common/Makefile.am
common/README
common/argparse.c
common/exechelp-posix.c
common/exechelp-w32.c
common/exechelp-w32ce.c
common/exechelp.h
common/exectool.c
common/homedir.c
common/iobuf.c
common/iobuf.h
common/logging.c
common/logging.h
common/miscellaneous.c
common/openpgpdefs.h
common/private-keys.c [new file with mode: 0644]
common/private-keys.h [new file with mode: 0644]
common/server-help.c [new file with mode: 0644]
common/server-help.h [new file with mode: 0644]
common/sexp-parse.h
common/simple-pwquery.c
common/status.h
common/strlist.c
common/strlist.h
common/sysutils.c
common/sysutils.h
common/t-exechelp.c
common/t-private-keys.c [new file with mode: 0644]
common/t-session-env.c
common/utf8conv.c
common/util.h
configure.ac
dirmngr/Makefile.am
dirmngr/dirmngr-client.c
dirmngr/dns-stuff.c
dirmngr/http.c
dirmngr/http.h
dirmngr/ks-engine-hkp.c
dirmngr/ks-engine-http.c
dirmngr/server.c
dirmngr/t-http.c
doc/DETAILS
doc/HACKING
doc/Makefile.am
doc/TRANSLATE
doc/debugging.texi
doc/gnupg-module-overview.svg [new file with mode: 0644]
doc/gpg-agent.texi
doc/gpg.texi
doc/gpgsm.texi
doc/gpgv.texi
doc/help.ru.txt
doc/help.txt
doc/mkdefsinc.c
g10/Makefile.am
g10/armor.c
g10/build-packet.c
g10/call-agent.c
g10/call-dirmngr.c
g10/call-dirmngr.h
g10/card-util.c
g10/cipher.c
g10/compress.c
g10/dearmor.c
g10/decrypt-data.c
g10/decrypt.c
g10/dek.h
g10/delkey.c
g10/ecdh.c
g10/encrypt.c
g10/export.c
g10/free-packet.c
g10/getkey.c
g10/gpg.c
g10/gpgcompose.c [new file with mode: 0644]
g10/gpgv.c
g10/import.c
g10/kbnode.c
g10/keydb.c
g10/keydb.h
g10/keyedit.c
g10/keygen.c
g10/keyid.c
g10/keylist.c
g10/keyring.c
g10/keyserver-internal.h
g10/keyserver.c
g10/main.h
g10/mainproc.c
g10/mdfilter.c
g10/migrate.c
g10/misc.c
g10/openfile.c
g10/options.h
g10/packet.h
g10/parse-packet.c
g10/passphrase.c
g10/pkclist.c
g10/pkglue.c
g10/plaintext.c
g10/progress.c
g10/pubkey-enc.c
g10/revoke.c
g10/seckey-cert.c
g10/server.c
g10/seskey.c
g10/sig-check.c
g10/sign.c
g10/skclist.c
g10/sqlite.c
g10/t-stutter-data.asc [new file with mode: 0644]
g10/t-stutter.c [new file with mode: 0644]
g10/tdbdump.c
g10/tdbio.c
g10/test-stubs.c
g10/test.c
g10/textfilter.c
g10/tofu.c
g10/trust.c
g10/trustdb.c
g10/trustdb.h
g10/verify.c
g13/Makefile.am
g13/backend.c
g13/backend.h
g13/be-dmcrypt.c [new file with mode: 0644]
g13/be-dmcrypt.h [new file with mode: 0644]
g13/call-syshelp.c [new file with mode: 0644]
g13/call-syshelp.h [new file with mode: 0644]
g13/create.c
g13/create.h
g13/g13-syshelp.c [new file with mode: 0644]
g13/g13-syshelp.h [new file with mode: 0644]
g13/g13.c
g13/g13.h
g13/g13tuple.c [moved from g13/utils.c with 51% similarity]
g13/g13tuple.h [moved from g13/utils.h with 74% similarity]
g13/keyblob.c [new file with mode: 0644]
g13/keyblob.h
g13/mount.c
g13/mount.h
g13/mountinfo.c
g13/server.c
g13/sh-blockdev.c [new file with mode: 0644]
g13/sh-cmd.c [new file with mode: 0644]
g13/sh-dmcrypt.c [new file with mode: 0644]
g13/suspend.c [new file with mode: 0644]
g13/suspend.h [new file with mode: 0644]
g13/t-g13tuple.c [new file with mode: 0644]
kbx/keybox-file.c
po/ca.po
po/cs.po
po/da.po
po/de.po
po/el.po
po/eo.po
po/es.po
po/et.po
po/fi.po
po/fr.po
po/gl.po
po/hu.po
po/id.po
po/it.po
po/ja.po
po/nb.po
po/pl.po
po/pt.po
po/ro.po
po/ru.po
po/sk.po
po/sv.po
po/tr.po
po/uk.po
po/zh_CN.po
po/zh_TW.po
scd/Makefile.am
scd/ccid-driver.c
scd/command.c
sm/Makefile.am
sm/call-agent.c
sm/gpgsm.c
sm/gpgsm.h
sm/keydb.c
sm/passphrase.c [new file with mode: 0644]
sm/passphrase.h [new file with mode: 0644]
sm/server.c
tests/migrations/Makefile.am [new file with mode: 0644]
tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc [new file with mode: 0644]
tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc [new file with mode: 0644]
tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc [new file with mode: 0644]
tests/migrations/extended-private-key-format.gpghome/pubring.kbx.asc [new file with mode: 0644]
tests/migrations/extended-private-key-format.gpghome/trustdb.gpg.asc [new file with mode: 0644]
tests/migrations/extended-private-key-format.test [new file with mode: 0755]
tests/migrations/from-classic.gpghome/pubring.gpg.asc [new file with mode: 0644]
tests/migrations/from-classic.gpghome/secring.gpg.asc [new file with mode: 0644]
tests/migrations/from-classic.gpghome/trustdb.gpg.asc [new file with mode: 0644]
tests/migrations/from-classic.test [new file with mode: 0755]
tests/openpgp/Makefile.am
tests/openpgp/default-key.test
tests/openpgp/defs.inc
tests/openpgp/fake-pinentry.c [new file with mode: 0644]
tests/openpgp/gpg-agent.conf.tmpl
tests/openpgp/gpgtar.test
tests/openpgp/mds.test
tests/openpgp/mkdemodirs
tests/openpgp/plain-largeo.asc [new file with mode: 0644]
tests/openpgp/signdemokey
tests/openpgp/use-exact-key.test
tests/openpgp/version.test
tools/gpg-zip.in
tools/gpgconf-comp.c
tools/gpgparsemail.c
tools/gpgtar.c
tools/mk-tdata.c

index 19f13fe..bf12302 100644 (file)
@@ -19,7 +19,8 @@
 ## Process this file with automake to produce Makefile.in
 
 ACLOCAL_AMFLAGS = -I m4
-DISTCHECK_CONFIGURE_FLAGS = --enable-symcryptrun --enable-mailto --enable-g13
+DISTCHECK_CONFIGURE_FLAGS = --enable-symcryptrun --enable-g13 \
+  --enable-gpg2-is-gpg
 
 GITLOG_TO_CHANGELOG=gitlog-to-changelog
 
@@ -42,7 +43,8 @@ EXTRA_DIST = build-aux/config.rpath build-aux/potomo autogen.sh autogen.rc \
              build-aux/speedo/w32/gnupg-logo-164x314.bmp    \
              build-aux/speedo/patches/atk-1.32.0.patch     \
              build-aux/speedo/patches/libiconv-1.14.patch   \
-             build-aux/speedo/patches/pango-1.29.4.patch
+             build-aux/speedo/patches/pango-1.29.4.patch    \
+             build-aux/speedo/patches/sqlite.patch
 
 
 DISTCLEANFILES = g10defs.h
diff --git a/NEWS b/NEWS
index acae85a..4aa7a01 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,56 @@
+Noteworthy changes in version 2.1.12 (2016-05-04)
+-------------------------------------------------
+
+ * gpg: New --edit-key sub-command "change-usage" for testing
+   purposes.
+
+ * gpg: Out of order key-signatures are now systematically detected
+   and fixed by --edit-key.
+
+ * gpg: Improved detection of non-armored messages.
+
+ * gpg: Removed the extra prompt needed to create Curve25519 keys.
+
+ * gpg: Improved user ID selection for --quick-sign-key.
+
+ * gpg: Use the root CAs provided by the system with --fetch-key.
+
+ * gpg: Add support for the experimental Web Key Directory key
+   location service.
+
+ * gpg: Improve formatting of Tofu messages and emit new Tofu specific
+   status lines.
+
+ * gpgsm: Add option --pinentry-mode to support a loopback pinentry.
+
+ * gpgsm: A new pubring.kbx is now created with the header blob so
+   that gpg can detect that the keybox format needs to be used.
+
+ * agent: Add read support for the new private key protection format
+   openpgp-s2k-ocb-aes.
+
+ * agent: Add read support for the new extended private key format.
+
+ * agent: Default to --allow-loopback-pinentry and add option
+   --no-allow-loopback-pinentry.
+
+ * scd: Changed to use the new libusb 1.0 API for the internal CCID
+   driver.
+
+ * dirmngr: The dirmngr-client does now auto-detect the PEM format.
+
+ * g13: Add experimental support for dm-crypt.
+
+ * w32: Tofu support is now available with the Speedo build method.
+
+ * w32: Removed the need for libiconv.dll.
+
+ * The man pages for gpg and gpgv are now installed under the correct
+   name (gpg2 or gpg - depending on a configure option).
+
+ * Lots of internal cleanups and bug fixes.
+
+
 Noteworthy changes in version 2.1.11 (2016-01-26)
 -------------------------------------------------
 
index b33593d..4be9090 100644 (file)
@@ -74,7 +74,7 @@ gpg_agent_DEPENDENCIES = $(resource_objs)
 
 gpg_protect_tool_SOURCES = \
        protect-tool.c \
-       protect.c
+       protect.c cvt-openpgp.c
 
 gpg_protect_tool_CFLAGS = $(AM_CFLAGS) $(LIBASSUAN_CFLAGS)
 gpg_protect_tool_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \
index c2726bb..0dcb201 100644 (file)
@@ -471,7 +471,7 @@ unsigned long get_standard_s2k_count (void);
 unsigned char get_standard_s2k_count_rfc4880 (void);
 int agent_protect (const unsigned char *plainkey, const char *passphrase,
                    unsigned char **result, size_t *resultlen,
-                  unsigned long s2k_count);
+                  unsigned long s2k_count, int use_ocb);
 int agent_unprotect (ctrl_t ctrl,
                      const unsigned char *protectedkey, const char *passphrase,
                      gnupg_isotime_t protected_at,
index 6e809f6..0e1d9fc 100644 (file)
@@ -3125,7 +3125,7 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
   gcry_sexp_sprint (key, GCRYSEXP_FMT_CANON, buffer_new, buffer_new_n);
   /* FIXME: guarantee?  */
 
-  err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
+  err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1);
 
  out:
 
index 421df00..c94fdd3 100644 (file)
@@ -41,6 +41,7 @@
 #include "cvt-openpgp.h"
 #include "../common/ssh-utils.h"
 #include "../common/asshelp.h"
+#include "../common/server-help.h"
 
 
 /* Maximum allowed size of the inquired ciphertext.  */
@@ -229,86 +230,6 @@ reset_notify (assuan_context_t ctx, char *line)
 }
 
 
-/* Skip over options in LINE.
-
-   Blanks after the options are also removed.  Options are indicated
-   by two leading dashes followed by a string consisting of non-space
-   characters.  The special option "--" indicates an explicit end of
-   options; all what follows will not be considered an option.  The
-   first no-option string also indicates the end of option parsing. */
-static char *
-skip_options (const char *line)
-{
-  while (spacep (line))
-    line++;
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return (char*)line;
-}
-
-
-/* Check whether the option NAME appears in LINE.  An example for a
-   line with options is:
-     --algo=42 --data foo bar
-   This function would then only return true if NAME is "data".  */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return 0;
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-
-/* Same as has_option but does only test for the name of the option
-   and ignores an argument, i.e. with NAME being "--hash" it would
-   return true for "--hash" as well as for "--hash=foo". */
-static int
-has_option_name (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return 0;
-  return (s && (s == line || spacep (s-1))
-          && (!s[n] || spacep (s+n) || s[n] == '='));
-}
-
-
-/* Return a pointer to the argument of the option with NAME.  If such
-   an option is not given, NULL is retruned. */
-static char *
-option_value (const char *line, const char *name)
-{
-  char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return NULL;
-  if (s && (s == line || spacep (s-1))
-      && s[n] && (spacep (s+n) || s[n] == '='))
-    {
-      s += n + 1;
-      s += strspn (s, " ");
-      if (*s && !spacep(s))
-        return s;
-    }
-  return NULL;
-}
-
-
 /* Replace all '+' by a blank in the string S. */
 static void
 plus_to_blank (char *s)
@@ -2219,7 +2140,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
   if (passphrase)
     {
       err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
-                           ctrl->s2k_count);
+                           ctrl->s2k_count, -1);
       if (!err)
         err = agent_write_private_key (grip, finalkey, finalkeylen, force);
     }
index 8df6b8e..40d9a3e 100644 (file)
@@ -1066,7 +1066,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
 
           if (!agent_protect (*r_key, passphrase,
                               &protectedkey, &protectedkeylen,
-                              ctrl->s2k_count))
+                              ctrl->s2k_count, -1))
             agent_write_private_key (grip, protectedkey, protectedkeylen, 1);
           xfree (protectedkey);
         }
index c5e7ae7..a78709c 100644 (file)
@@ -35,6 +35,7 @@
 #include "agent.h"
 #include "i18n.h"
 #include "../common/ssh-utils.h"
+#include "../common/private-keys.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
@@ -51,6 +52,75 @@ struct try_unprotect_arg_s
 };
 
 
+static gpg_error_t
+write_extended_private_key (char *fname, estream_t fp,
+                            const void *buf, size_t len)
+{
+  gpg_error_t err;
+  pkc_t pk = NULL;
+  gcry_sexp_t key = NULL;
+  int remove = 0;
+  int line;
+
+  err = pkc_parse (&pk, &line, fp);
+  if (err)
+    {
+      log_error ("error parsing '%s' line %d: %s\n",
+                 fname, line, gpg_strerror (err));
+      goto leave;
+    }
+
+  err = gcry_sexp_sscan (&key, NULL, buf, len);
+  if (err)
+    goto leave;
+
+  err = pkc_set_private_key (pk, key);
+  if (err)
+    goto leave;
+
+  err = es_fseek (fp, 0, SEEK_SET);
+  if (err)
+    goto leave;
+
+  err = pkc_write (pk, fp);
+  if (err)
+    {
+      log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
+      remove = 1;
+      goto leave;
+    }
+
+  if (ftruncate (es_fileno (fp), es_ftello (fp)))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (err));
+      remove = 1;
+      goto leave;
+    }
+
+  if (es_fclose (fp))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
+      remove = 1;
+      goto leave;
+    }
+  else
+    fp = NULL;
+
+  bump_key_eventcounter ();
+
+ leave:
+  if (fp)
+    es_fclose (fp);
+  if (remove)
+    gnupg_remove (fname);
+  xfree (fname);
+  gcry_sexp_release (key);
+  pkc_release (pk);
+  return err;
+}
+
 /* Write an S-expression formatted key to our key storage.  With FORCE
    passed as true an existing key with the given GRIP will get
    overwritten.  */
@@ -77,7 +147,7 @@ agent_write_private_key (const unsigned char *grip,
       return gpg_error (GPG_ERR_EEXIST);
     }
 
-  fp = es_fopen (fname, force? "wb,mode=-rw" : "wbx,mode=-rw");
+  fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
   if (!fp)
     {
       gpg_error_t tmperr = gpg_error_from_syserror ();
@@ -86,6 +156,38 @@ agent_write_private_key (const unsigned char *grip,
       return tmperr;
     }
 
+  /* See if an existing key is in extended format.  */
+  if (force)
+    {
+      gpg_error_t rc;
+      char first;
+
+      if (es_fread (&first, 1, 1, fp) != 1)
+        {
+          rc = gpg_error_from_syserror ();
+          log_error ("error reading first byte from '%s': %s\n",
+                     fname, strerror (errno));
+          xfree (fname);
+          es_fclose (fp);
+          return rc;
+        }
+
+      rc = es_fseek (fp, 0, SEEK_SET);
+      if (rc)
+        {
+          log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
+          xfree (fname);
+          es_fclose (fp);
+          return rc;
+        }
+
+      if (first != '(')
+        {
+          /* Key is in extended format.  */
+          return write_extended_private_key (fname, fp, buffer, length);
+        }
+    }
+
   if (es_fwrite (buffer, length, 1, fp) != 1)
     {
       gpg_error_t tmperr = gpg_error_from_syserror ();
@@ -95,6 +197,18 @@ agent_write_private_key (const unsigned char *grip,
       xfree (fname);
       return tmperr;
     }
+
+  /* When force is given, the file might have to be truncated.  */
+  if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
+    {
+      gpg_error_t tmperr = gpg_error_from_syserror ();
+      log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
+      es_fclose (fp);
+      gnupg_remove (fname);
+      xfree (fname);
+      return tmperr;
+    }
+
   if (es_fclose (fp))
     {
       gpg_error_t tmperr = gpg_error_from_syserror ();
@@ -531,6 +645,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];
+  char first;
 
   *result = NULL;
 
@@ -548,6 +663,50 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
       return rc;
     }
 
+  if (es_fread (&first, 1, 1, fp) != 1)
+    {
+      rc = gpg_error_from_syserror ();
+      log_error ("error reading first byte from '%s': %s\n",
+                 fname, strerror (errno));
+      xfree (fname);
+      es_fclose (fp);
+      return rc;
+    }
+
+  rc = es_fseek (fp, 0, SEEK_SET);
+  if (rc)
+    {
+      log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
+      xfree (fname);
+      es_fclose (fp);
+      return rc;
+    }
+
+  if (first != '(')
+    {
+      /* Key is in extended format.  */
+      pkc_t pk;
+      int line;
+
+      rc = pkc_parse (&pk, &line, fp);
+      es_fclose (fp);
+
+      if (rc)
+        log_error ("error parsing '%s' line %d: %s\n",
+                   fname, line, gpg_strerror (rc));
+      else
+        {
+          rc = pkc_get_private_key (pk, result);
+          pkc_release (pk);
+          if (rc)
+            log_error ("error getting private key from '%s': %s\n",
+                       fname, gpg_strerror (rc));
+        }
+
+      xfree (fname);
+      return rc;
+    }
+
   if (fstat (es_fileno (fp), &st))
     {
       rc = gpg_error_from_syserror ();
@@ -1311,7 +1470,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
       break;
 
     case PRIVATE_KEY_SHADOWED:
-      err = gpg_error (GPG_ERR_KEY_ON_CARD);
+      err = remove_key_file (grip);
       break;
 
     default:
index 2eec974..12c3e34 100644 (file)
@@ -58,7 +58,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
     {
       unsigned char *p;
 
-      rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
+      rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
       if (rc)
         {
           xfree (buf);
index 8aab2b9..a950530 100644 (file)
@@ -122,6 +122,7 @@ enum cmd_and_opt_values
   oNoAllowMarkTrusted,
   oAllowPresetPassphrase,
   oAllowLoopbackPinentry,
+  oNoAllowLoopbackPinentry,
   oNoAllowExternalCache,
   oAllowEmacsPinentry,
   oKeepTTY,
@@ -220,8 +221,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oAllowMarkTrusted,   "allow-mark-trusted", "@"),
   ARGPARSE_s_n (oAllowPresetPassphrase, "allow-preset-passphrase",
                 /* */                    N_("allow presetting passphrase")),
-  ARGPARSE_s_n (oAllowLoopbackPinentry, "allow-loopback-pinentry",
-                                   N_("allow caller to override the pinentry")),
+  ARGPARSE_s_n (oNoAllowLoopbackPinentry, "no-allow-loopback-pinentry",
+                                N_("disallow caller to override the pinentry")),
+  ARGPARSE_s_n (oAllowLoopbackPinentry, "allow-loopback-pinentry", "@"),
   ARGPARSE_s_n (oAllowEmacsPinentry,  "allow-emacs-pinentry",
                 /* */    N_("allow passphrase to be prompted through Emacs")),
 
@@ -626,6 +628,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.ignore_cache_for_signing = 0;
       opt.allow_mark_trusted = 1;
       opt.allow_external_cache = 1;
+      opt.allow_loopback_pinentry = 1;
       opt.allow_emacs_pinentry = 0;
       opt.disable_scdaemon = 0;
       disable_check_own_socket = 0;
@@ -699,6 +702,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     case oAllowPresetPassphrase: opt.allow_preset_passphrase = 1; break;
 
     case oAllowLoopbackPinentry: opt.allow_loopback_pinentry = 1; break;
+    case oNoAllowLoopbackPinentry: opt.allow_loopback_pinentry = 0; break;
 
     case oNoAllowExternalCache: opt.allow_external_cache = 0;
       break;
@@ -1154,8 +1158,8 @@ main (int argc, char **argv )
 #ifdef HAVE_W32_SYSTEM
       es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
 #endif
-      es_printf ("allow-loopback-pinentry:%lu:\n",
-                 GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
+      es_printf ("no-allow-loopback-pinentry:%lu:\n",
+              GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("allow-emacs-pinentry:%lu:\n",
                  GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
       es_printf ("pinentry-timeout:%lu:0:\n",
@@ -1908,9 +1912,13 @@ create_private_keys_directory (const char *home)
       else if (!opt.quiet)
         log_info (_("directory '%s' created\n"), fname);
     }
+  if (gnupg_chmod (fname, "-rwx"))
+    log_error (_("can't set permissions of '%s': %s\n"),
+               fname, strerror (errno));
   xfree (fname);
 }
 
+
 /* Create the directory only if the supplied directory name is the
    same as the default one.  This way we avoid to create arbitrary
    directories when a non-default home directory is used.  To cope
index 42c4b1f..c1a59ce 100644 (file)
@@ -1,11 +1,11 @@
-keyformat.txt (wk 2001-12-18)
------------------------------
+keyformat.txt               emacs, please switch to -*- org -*- mode
+-------------
 
 
 Some notes on the format of the secret keys used with gpg-agent.
 
-Location of keys
-================
+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
 
@@ -16,9 +16,72 @@ and should have permissions 700.
 The secret keys are stored in files with a name matching the
 hexadecimal representation of the keygrip[2] and suffixed with ".key".
 
+* Extended Private Key Format
+
+GnuPG 2.3+ will use a new format to store private keys that is both
+more flexible and easier to read and edit by human beings.  The new
+format stores name,value-pairs using the common mail and http header
+convention.  Example (here indented with two spaces):
+
+  Description: Key to sign all GnuPG released tarballs.
+    The key is actually stored on a smart card.
+  Use-for-ssh: yes
+  OpenSSH-cert: long base64 encoded string wrapped so that this
+    key file can be easily edited with a standard editor.
+  Key: (shadowed-private-key
+    (rsa
+    (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900
+    2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4
+    83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7
+    19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997
+    601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E
+    72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D
+    F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0
+    8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A
+    E186A02BA2497FDC5D1221#)
+    (e #00010001#)
+    (shadowed t1-v1
+     (#D2760001240102000005000011730000# OPENPGP.1)
+    )))
+
+GnuPG 2.2 is able to read and update keys using the new format, but
+will not create new files using the new format.  Furthermore, it only
+makes use of the value stored under the name 'Key:'.
+
+Keys in the extended format can be recognized by looking at the first
+byte of the file.  If it starts with a '(' it is a naked S-expression,
+otherwise it is a key in extended format.
+
+** Names
+
+A name must start with a letter and end with a colon.  Valid
+characters are all ASCII letters, numbers and the hyphen.  Comparison
+of names is done case insensitively.  Names may be used several times
+to represent an array of values.
+
+The name "Key:" is special in that it may occur only once and the
+associated value holds the actual S-expression with the cryptographic
+key.  The S-expression is formatted using the 'Advanced Format'
+(GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters so that
+the file can be easily inspected and edited.  See section 'Private Key
+Format' below for details.
+
+** Values
+
+Values are UTF-8 encoded strings.  Values can be wrapped at any point,
+and continued in the next line indicated by leading whitespace.  A
+continuation line with one leading space does not introduce a blank so
+that the lines can be effectively concatenated.  A blank line as part
+of a continuation line encodes a newline.
+
+** Comments
+
+Lines containing only whitespace, and lines starting with whitespace
+followed by '#' are considered to be comments and are ignored.
+
+* Private Key Format
+** Unprotected Private Key Format
 
-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:
 
@@ -43,26 +106,8 @@ optional but required for some operations to calculate the fingerprint
 of the key.  This timestamp should be a string with the number of
 seconds since Epoch or an ISO time string (yyyymmddThhmmss).
 
-Actually this form should not be used for regular purposes and only
-accepted by gpg-agent with the configuration option:
---allow-non-canonical-key-format.  The regular way to represent the
-keys is in canonical representation[3]:
-
-(private-key
-   (rsa
-    (n #00e0ce9..[some bytes not shown]..51#)
-    (e #010001#)
-    (d #046129F..[some bytes not shown]..81#)
-    (p #00e861b..[some bytes not shown]..f1#)
-    (q #00f7a7c..[some bytes not shown]..61#)
-    (u #304559a..[some bytes not shown]..9b#)
-   )
-   (uri http://foo.bar x-foo:whatever_you_want)
-)
-
+** Protected Private Key Format
 
-Protected Private Key Format
-==============================
 A protected key is like this:
 
 (protected-private-key
@@ -86,11 +131,11 @@ optional; the isotimestamp is 15 bytes long (e.g. "19610711T172000").
 
 The currently defined protection modes are:
 
-1. openpgp-s2k3-sha1-aes-cbc
+*** openpgp-s2k3-sha1-aes-cbc
 
   This describes an algorithm using using AES in CBC mode for
   encryption, SHA-1 for integrity protection and the String to Key
-  algorithm 3 from OpenPGP (rfc2440).
+  algorithm 3 from OpenPGP (rfc4880).
 
   Example:
 
@@ -116,7 +161,7 @@ The currently defined protection modes are:
   easily be stripped by looking for the end of the list.
 
   The hash is calculated on the concatenation of the public key and
-  secret key parameter lists: i.e it is required to hash the
+  secret key parameter lists: i.e. it is required to hash the
   concatenation of these 6 canonical encoded lists for RSA, including
   the parenthesis, the algorithm keyword and (if used) the protected-at
   list.
@@ -135,7 +180,45 @@ The currently defined protection modes are:
   the stored one - If they don't match the integrity of the key is not
   given.
 
-2. openpgp-native
+*** openpgp-s2k3-ocb-aes
+
+  This describes an algorithm using using AES-128 in OCB mode, a nonce
+  of 96 bit, a taglen of 128 bit, and the String to Key algorithm 3
+  from OpenPGP (rfc4880).
+
+  Example:
+
+  (protected openpgp-s2k3-ocb-aes
+    ((sha1 16byte_salt no_of_iterations) 12byte_nonce)
+    encrypted_octet_string
+  )
+
+  The encrypted_octet string should yield this S-Exp (in canonical
+  representation) after decryption:
+
+  (
+   (
+    (d #046129F..[some bytes not shown]..81#)
+    (p #00e861b..[some bytes not shown]..f1#)
+    (q #00f7a7c..[some bytes not shown]..61#)
+    (u #304559a..[some bytes not shown]..9b#)
+   )
+  )
+
+  For padding reasons, random bytes may be appended to this list -
+  they can easily be stripped by looking for the end of the list.
+
+  The associated data required for this protection mode is the list
+  formiing the public key parameters.  For the above example this is
+  is this canonical encoded S-expression:
+
+  (rsa
+   (n #00e0ce9..[some bytes not shown]..51#)
+   (e #010001#)
+   (protected-at "18950523T000000")
+  )
+
+*** openpgp-native
 
   This is a wrapper around the OpenPGP Private Key Transport format
   which resembles the standard OpenPGP format and allows the use of an
@@ -172,10 +255,8 @@ The currently defined protection modes are:
    (uri http://foo.bar x-foo:whatever_you_want)
    (comment whatever))
 
+** Shadowed Private Key Format
 
-
-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:
@@ -202,9 +283,7 @@ readers don't allow passing a variable length PIN.
 
 More items may be added to the list.
 
-
-OpenPGP Private Key Transfer Format
-===================================
+** OpenPGP Private Key Transfer Format
 
 This format is used to transfer keys between gpg and gpg-agent.
 
@@ -217,28 +296,28 @@ This format is used to transfer keys between gpg and gpg-agent.
   (protection PROTTYPE PROTALGO IV S2KMODE S2KHASH S2KSALT S2KCOUNT))
 
 
-* V is the packet version number (3 or 4).
-* PUBKEYALGO is a Libgcrypt algo name
-* CURVENAME is the name of the curve - only used with ECC.
-* P1 .. PN are the parameters; the public parameters are never encrypted
-  the secrect key parameters are encrypted if the "protection" list is
-  given.  To make this more explicit each parameter is preceded by a
-  flag "_" for cleartext or "e" for encrypted text.
-* CSUM is the deprecated 16 bit checksum as defined by OpenPGP.  This
-  is an optional element.
-* If PROTTYPE is "sha1" the new style SHA1 checksum is used if it is "sum"
-  the old 16 bit checksum (above) is used and if it is "none" no
-  protection at all is used.
-* PROTALGO is a Libgcrypt style cipher algorithm name
-* IV is the initialization verctor.
-* S2KMODE is the value from RFC-4880.
-* S2KHASH is a a libgcrypt style hash algorithm identifier.
-* S2KSALT is the 8 byte salt
-* S2KCOUNT is the count value from RFC-4880.
-
-
-Persistent Passphrase Format
-============================
+ * V is the packet version number (3 or 4).
+ * PUBKEYALGO is a Libgcrypt algo name
+ * CURVENAME is the name of the curve - only used with ECC.
+ * P1 .. PN are the parameters; the public parameters are never encrypted
+   the secrect key parameters are encrypted if the "protection" list is
+   given.  To make this more explicit each parameter is preceded by a
+   flag "_" for cleartext or "e" for encrypted text.
+ * CSUM is the deprecated 16 bit checksum as defined by OpenPGP.  This
+   is an optional element.
+ * If PROTTYPE is "sha1" the new style SHA1 checksum is used if it is "sum"
+   the old 16 bit checksum (above) is used and if it is "none" no
+   protection at all is used.
+ * PROTALGO is a Libgcrypt style cipher algorithm name
+ * IV is the initialization verctor.
+ * S2KMODE is the value from RFC-4880.
+ * S2KHASH is a a libgcrypt style hash algorithm identifier.
+ * S2KSALT is the 8 byte salt
+ * S2KCOUNT is the count value from RFC-4880.
+
+** Persistent Passphrase Format
+
+Note: That this has not yet been implemented.
 
 To allow persistent storage of cached passphrases we use a scheme
 similar to the private-key storage format.  This is a master
@@ -331,14 +410,8 @@ hashed:
     (protected-at "20100915T111722")
    )
 
+* 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 03dbda9..ad036ee 100644 (file)
@@ -69,6 +69,7 @@ enum cmd_and_opt_values
   oHomedir,
   oPrompt,
   oStatusMsg,
+  oDebugUseOCB,
 
   oAgentProgram
 };
@@ -96,6 +97,7 @@ static const char *opt_passphrase;
 static char *opt_prompt;
 static int opt_status_msg;
 static const char *opt_agent_program;
+static int opt_debug_use_ocb;
 
 static char *get_passphrase (int promptno);
 static void release_passphrase (char *pw);
@@ -132,6 +134,8 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
 
+  ARGPARSE_s_n (oDebugUseOCB,  "debug-use-ocb", "@"), /* For hacking only.  */
+
   ARGPARSE_end ()
 };
 
@@ -333,7 +337,8 @@ read_and_protect (const char *fname)
     return;
 
   pw = get_passphrase (1);
-  rc = agent_protect (key, pw, &result, &resultlen, 0);
+  rc = agent_protect (key, pw, &result, &resultlen, 0,
+                      opt_debug_use_ocb? 1 : -1);
   release_passphrase (pw);
   xfree (key);
   if (rc)
@@ -358,7 +363,7 @@ read_and_protect (const char *fname)
 
 
 static void
-read_and_unprotect (const char *fname)
+read_and_unprotect (ctrl_t ctrl, const char *fname)
 {
   int  rc;
   unsigned char *key;
@@ -371,7 +376,7 @@ read_and_unprotect (const char *fname)
   if (!key)
     return;
 
-  rc = agent_unprotect (NULL, key, (pw=get_passphrase (1)),
+  rc = agent_unprotect (ctrl, key, (pw=get_passphrase (1)),
                         protected_at, &result, &resultlen);
   release_passphrase (pw);
   xfree (key);
@@ -383,10 +388,14 @@ read_and_unprotect (const char *fname)
       return;
     }
   if (opt.verbose)
-    log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
-              protected_at, protected_at+4, protected_at+6,
-              protected_at+9, protected_at+11, protected_at+13);
-
+    {
+      if (*protected_at)
+        log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
+                  protected_at, protected_at+4, protected_at+6,
+                  protected_at+9, protected_at+11, protected_at+13);
+      else
+        log_info ("key protection done at [unknown]\n");
+    }
 
   if (opt_armor)
     {
@@ -547,6 +556,7 @@ main (int argc, char **argv )
   ARGPARSE_ARGS pargs;
   int cmd = 0;
   const char *fname;
+  ctrl_t ctrl;
 
   early_system_init ();
   set_strusage (my_strusage);
@@ -598,6 +608,7 @@ main (int argc, char **argv )
         case oHaveCert: opt_have_cert = 1; break;
         case oPrompt: opt_prompt = pargs.r.ret_str; break;
         case oStatusMsg: opt_status_msg = 1; break;
+        case oDebugUseOCB: opt_debug_use_ocb = 1; break;
 
         default: pargs.err = ARGPARSE_PRINT_ERROR; break;
        }
@@ -611,6 +622,15 @@ main (int argc, char **argv )
   else if (argc > 1)
     usage (1);
 
+  /* Allocate an CTRL object.  An empty object should sufficent.  */
+  ctrl = xtrycalloc (1, sizeof *ctrl);
+  if (!ctrl)
+    {
+      log_error ("error allocating connection control data: %s\n",
+                 strerror (errno));
+      agent_exit (1);
+    }
+
   /* Set the information which can't be taken from envvars.  */
   gnupg_prepare_get_passphrase (GPG_ERR_SOURCE_DEFAULT,
                                 opt.verbose,
@@ -624,7 +644,7 @@ main (int argc, char **argv )
   if (cmd == oProtect)
     read_and_protect (fname);
   else if (cmd == oUnprotect)
-    read_and_unprotect (fname);
+    read_and_unprotect (ctrl, fname);
   else if (cmd == oShadow)
     read_and_shadow (fname);
   else if (cmd == oShowShadowInfo)
@@ -640,6 +660,8 @@ main (int argc, char **argv )
   else
     show_file (fname);
 
+  xfree (ctrl);
+
   agent_exit (0);
   return 8; /*NOTREACHED*/
 }
@@ -731,12 +753,79 @@ release_passphrase (char *pw)
 
 
 /* Stub function.  */
+int
+agent_key_available (const unsigned char *grip)
+{
+  (void)grip;
+  return -1;  /* Not available.  */
+}
+
+char *
+agent_get_cache (const char *key, cache_mode_t cache_mode)
+{
+  (void)key;
+  (void)cache_mode;
+  return NULL;
+}
+
 gpg_error_t
-convert_from_openpgp_native (gcry_sexp_t s_pgp, const char *passphrase,
-                             unsigned char **r_key)
+agent_askpin (ctrl_t ctrl,
+              const char *desc_text, const char *prompt_text,
+              const char *initial_errtext,
+              struct pin_entry_info_s *pininfo,
+              const char *keyinfo, cache_mode_t cache_mode)
+{
+  gpg_error_t err;
+  unsigned char *passphrase;
+  size_t size;
+
+  (void)ctrl;
+  (void)desc_text;
+  (void)prompt_text;
+  (void)initial_errtext;
+  (void)keyinfo;
+  (void)cache_mode;
+
+  *pininfo->pin = 0; /* Reset the PIN. */
+  passphrase = get_passphrase (0);
+  size = strlen (passphrase);
+  if (size >= pininfo->max_length)
+    return gpg_error (GPG_ERR_TOO_LARGE);
+
+  memcpy (&pininfo->pin, passphrase, size);
+  xfree (passphrase);
+  pininfo->pin[size] = 0;
+  if (pininfo->check_cb)
+    {
+      /* More checks by utilizing the optional callback. */
+      pininfo->cb_errtext = NULL;
+      err = pininfo->check_cb (pininfo);
+    }
+  else
+    err = 0;
+  return err;
+}
+
+/* Replacement for the function in findkey.c.  Here we write the key
+ * to stdout. */
+int
+agent_write_private_key (const unsigned char *grip,
+                         const void *buffer, size_t length, int force)
 {
-  (void)s_pgp;
-  (void)passphrase;
-  (void)r_key;
-  return gpg_error (GPG_ERR_BUG);
+  char hexgrip[40+4+1];
+  char *p;
+
+  (void)force;
+
+  bin2hex (grip, 20, hexgrip);
+  strcpy (hexgrip+40, ".key");
+  p = make_advanced (buffer, length);
+  if (p)
+    {
+      printf ("# Begin dump of %s\n%s%s# End dump of %s\n",
+              hexgrip, p, (*p && p[strlen(p)-1] == '\n')? "":"\n", hexgrip);
+      xfree (p);
+    }
+
+  return 0;
 }
index cdb39fd..ee08e57 100644 (file)
 #include "cvt-openpgp.h"
 #include "sexp-parse.h"
 
+
+#if GCRYPT_VERSION_NUMBER < 0x010700
+# define OCB_MODE_SUPPORTED 0
+#else
+# define OCB_MODE_SUPPORTED 1
+#endif
+
+/* To use the openpgp-s2k3-ocb-aes scheme by default set the value of
+ * this macro to 1.  Note that the caller of agent_protect may
+ * override this default.  */
+#define PROT_DEFAULT_TO_OCB 0
+
 /* The protection mode for encryption.  The supported modes for
    decryption are listed in agent_unprotect().  */
 #define PROT_CIPHER        GCRY_CIPHER_AES128
@@ -87,6 +99,7 @@ hash_passphrase (const char *passphrase, int hashalgo,
                  unsigned char *key, size_t keylen);
 
 
+
 \f
 /* Get the process time and store it in DATA.  */
 static void
@@ -95,11 +108,13 @@ calibrate_get_time (struct calibrate_time_s *data)
 #ifdef HAVE_W32_SYSTEM
 # ifdef HAVE_W32CE_SYSTEM
   GetThreadTimes (GetCurrentThread (),
+                  &data->creation_time, &data->exit_time,
+                  &data->kernel_time, &data->user_time);
 # else
   GetProcessTimes (GetCurrentProcess (),
-# endif
                    &data->creation_time, &data->exit_time,
                    &data->kernel_time, &data->user_time);
+# endif
 #else
   struct tms tmp;
 
@@ -300,70 +315,108 @@ calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
    encrypted block in RESULT or return with an error code.  SHA1HASH
    is the 20 byte SHA-1 hash required for the integrity code.
 
-   The parameter block is expected to be an incomplete S-Expression of
-   the form (example in advanced format):
+   The parameter block is expected to be an incomplete canonical
+   encoded S-Expression of the form (example in advanced format):
 
      (d #046129F..[some bytes not shown]..81#)
      (p #00e861b..[some bytes not shown]..f1#)
      (q #00f7a7c..[some bytes not shown]..61#)
      (u #304559a..[some bytes not shown]..9b#)
 
-   the returned block is the S-Expression:
+     the returned block is the S-Expression:
 
-    (protected mode (parms) encrypted_octet_string)
+     (protected mode (parms) encrypted_octet_string)
 
 */
 static int
-do_encryption (const unsigned char *protbegin, size_t protlen,
-               const char *passphrase,  const unsigned char *sha1hash,
+do_encryption (const unsigned char *hashbegin, size_t hashlen,
+               const unsigned char *protbegin, size_t protlen,
+               const char *passphrase,
+               const char *timestamp_exp, size_t timestamp_exp_len,
                unsigned char **result, size_t *resultlen,
-              unsigned long s2k_count)
+              unsigned long s2k_count, int use_ocb)
 {
   gcry_cipher_hd_t hd;
-  const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
+  const char *modestr;
+  unsigned char hashvalue[20];
   int blklen, enclen, outlen;
   unsigned char *iv = NULL;
+  unsigned int ivsize;  /* Size of the buffer allocated for IV.  */
+  const unsigned char *s2ksalt; /* Points into IV.  */
   int rc;
   char *outbuf = NULL;
   char *p;
   int saltpos, ivpos, encpos;
 
+  s2ksalt = iv;  /* Silence compiler warning.  */
+
   *resultlen = 0;
   *result = NULL;
 
-  rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
+  if (use_ocb && !OCB_MODE_SUPPORTED)
+    return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
+
+  modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
+             /*   */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
+
+  rc = gcry_cipher_open (&hd, PROT_CIPHER,
+#if OCB_MODE_SUPPORTED
+                         use_ocb? GCRY_CIPHER_MODE_OCB :
+#endif
+                         GCRY_CIPHER_MODE_CBC,
                          GCRY_CIPHER_SECURE);
   if (rc)
     return rc;
 
-
   /* We need to work on a copy of the data because this makes it
-     easier to add the trailer and the padding and more important we
-     have to prefix the text with 2 parenthesis, so we have to
-     allocate enough space for:
-
-     ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
-
-     We always append a full block of random bytes as padding but
-     encrypt only what is needed for a full blocksize.  */
+   * easier to add the trailer and the padding and more important we
+   * have to prefix the text with 2 parenthesis.  In CBC mode we
+   * have to allocate enough space for:
+   *
+   *   ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
+   *
+   * we always append a full block of random bytes as padding but
+   * encrypt only what is needed for a full blocksize.  In OCB mode we
+   * have to allocate enough space for just:
+   *
+   *   ((<parameter_list>))
+   */
   blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
-  outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
-  enclen = outlen/blklen * blklen;
-  outbuf = gcry_malloc_secure (outlen);
+  if (use_ocb)
+    {
+      /*       ((            )) */
+      outlen = 2 + protlen + 2 ;
+      enclen = outlen + 16 /* taglen */;
+      outbuf = gcry_malloc_secure (enclen);
+    }
+  else
+    {
+      /*       ((            )( 4:hash 4:sha1 20:<hash> ))  <padding>  */
+      outlen = 2 + protlen + 2 + 6   + 6    + 23      + 2 + blklen;
+      enclen = outlen/blklen * blklen;
+      outbuf = gcry_malloc_secure (outlen);
+    }
   if (!outbuf)
     rc = out_of_core ();
+
+  /* Allocate a buffer for the nonce and the salt.  */
   if (!rc)
     {
-      /* Allocate random bytes to be used as IV, padding and s2k salt. */
-      iv = xtrymalloc (blklen*2+8);
+      /* Allocate random bytes to be used as IV, padding and s2k salt
+       * or in OCB mode for a nonce and the s2k salt.  The IV/nonce is
+       * set later because for OCB we need to set the key first.  */
+      ivsize = (use_ocb? 12 : (blklen*2)) + 8;
+      iv = xtrymalloc (ivsize);
       if (!iv)
-        rc = gpg_error (GPG_ERR_ENOMEM);
+        rc = gpg_error_from_syserror ();
       else
         {
-          gcry_create_nonce (iv, blklen*2+8);
-          rc = gcry_cipher_setiv (hd, iv, blklen);
+          gcry_create_nonce (iv, ivsize);
+          s2ksalt = iv + ivsize - 8;
         }
     }
+
+  /* Hash the passphrase and set the key.  */
   if (!rc)
     {
       unsigned char *key;
@@ -375,14 +428,54 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
       else
         {
           rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
-                                3, iv+2*blklen,
-                               s2k_count ? s2k_count : get_standard_s2k_count(),
+                                3, s2ksalt,
+                               s2k_count? s2k_count:get_standard_s2k_count(),
                                key, keylen);
           if (!rc)
             rc = gcry_cipher_setkey (hd, key, keylen);
           xfree (key);
         }
     }
+
+  /* Set the IV/nonce.  */
+  if (!rc)
+    {
+      rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
+    }
+
+  if (use_ocb)
+    {
+      /* In OCB Mode we use only the public key parameters as AAD.  */
+      rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
+      if (!rc)
+        rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
+      if (!rc)
+        rc = gcry_cipher_authenticate
+          (hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
+
+    }
+  else
+    {
+      /* Hash the entire expression for CBC mode.  Because
+       * TIMESTAMP_EXP won't get protected, we can't simply hash a
+       * continuous buffer but need to call md_write several times.  */
+      gcry_md_hd_t md;
+
+      rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
+      if (!rc)
+        {
+          gcry_md_write (md, hashbegin, protbegin - hashbegin);
+          gcry_md_write (md, protbegin, protlen);
+          gcry_md_write (md, timestamp_exp, timestamp_exp_len);
+          gcry_md_write (md, protbegin+protlen,
+                         hashlen - (protbegin+protlen - hashbegin));
+          memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
+          gcry_md_close (md);
+        }
+    }
+
+
+  /* Encrypt.  */
   if (!rc)
     {
       p = outbuf;
@@ -390,17 +483,42 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
       *p++ = '(';
       memcpy (p, protbegin, protlen);
       p += protlen;
-      memcpy (p, ")(4:hash4:sha120:", 17);
-      p += 17;
-      memcpy (p, sha1hash, 20);
-      p += 20;
-      *p++ = ')';
-      *p++ = ')';
-      memcpy (p, iv+blklen, blklen);
-      p += blklen;
+      if (use_ocb)
+        {
+          *p++ = ')';
+          *p++ = ')';
+        }
+      else
+        {
+          memcpy (p, ")(4:hash4:sha120:", 17);
+          p += 17;
+          memcpy (p, hashvalue, 20);
+          p += 20;
+          *p++ = ')';
+          *p++ = ')';
+          memcpy (p, iv+blklen, blklen); /* Add padding.  */
+          p += blklen;
+        }
       assert ( p - outbuf == outlen);
-      rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
+#if OCB_MODE_SUPPORTED
+      if (use_ocb)
+        {
+          gcry_cipher_final (hd);
+          rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
+          if (!rc)
+            {
+              log_assert (outlen + 16 == enclen);
+              rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
+            }
+        }
+      else
+#endif /*OCB_MODE_SUPPORTED*/
+        {
+          rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
+        }
     }
+
+  /* Release cipher handle and check for errors.  */
   gcry_cipher_close (hd);
   if (rc)
     {
@@ -427,7 +545,7 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
        (int)strlen (modestr), modestr,
        &saltpos,
        (unsigned int)strlen (countbuf), countbuf,
-       blklen, &ivpos, blklen, "",
+       use_ocb? 12 : blklen, &ivpos, use_ocb? 12 : blklen, "",
        enclen, &encpos, enclen, "");
     if (!p)
       {
@@ -436,11 +554,12 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
         xfree (outbuf);
         return tmperr;
       }
+
   }
   *resultlen = strlen (p);
   *result = (unsigned char*)p;
-  memcpy (p+saltpos, iv+2*blklen, 8);
-  memcpy (p+ivpos, iv, blklen);
+  memcpy (p+saltpos, s2ksalt, 8);
+  memcpy (p+ivpos, iv, use_ocb? 12 : blklen);
   memcpy (p+encpos, outbuf, enclen);
   xfree (iv);
   xfree (outbuf);
@@ -450,11 +569,13 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
 
 
 /* Protect the key encoded in canonical format in PLAINKEY.  We assume
-   a valid S-Exp here. */
+   a valid S-Exp here.  With USE_UCB set to -1 the default scheme is
+   used (ie. either CBC or OCB), set to 0 the old CBC mode is used,
+   and set to 1 OCB is used. */
 int
 agent_protect (const unsigned char *plainkey, const char *passphrase,
                unsigned char **result, size_t *resultlen,
-              unsigned long s2k_count)
+              unsigned long s2k_count, int use_ocb)
 {
   int rc;
   const char *parmlist;
@@ -464,15 +585,16 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
   const unsigned char *prot_begin, *prot_end, *real_end;
   size_t n;
   int c, infidx, i;
-  unsigned char hashvalue[20];
   char timestamp_exp[35];
   unsigned char *protected;
   size_t protectedlen;
   int depth = 0;
   unsigned char *p;
-  gcry_md_hd_t md;
   int have_curve = 0;
 
+  if (use_ocb == -1)
+    use_ocb = PROT_DEFAULT_TO_OCB;
+
   /* Create an S-expression with the protected-at timestamp.  */
   memcpy (timestamp_exp, "(12:protected-at15:", 19);
   gnupg_get_isotime (timestamp_exp+19);
@@ -573,21 +695,10 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
   assert (!depth);
   real_end = s-1;
 
-  /* Hash the stuff.  Because the timestamp_exp won't get protected,
-     we can't simply hash a continuous buffer but need to use several
-     md_writes.  */
-  rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
-  if (rc)
-    return rc;
-  gcry_md_write (md, hash_begin, hash_end - hash_begin);
-  gcry_md_write (md, timestamp_exp, 35);
-  gcry_md_write (md, ")", 1);
-  memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
-  gcry_md_close (md);
-
-  rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
-                      passphrase,  hashvalue,
-                      &protected, &protectedlen, s2k_count);
+  rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
+                      prot_begin, prot_end - prot_begin + 1,
+                      passphrase, timestamp_exp, sizeof (timestamp_exp),
+                      &protected, &protectedlen, s2k_count, use_ocb);
   if (rc)
     return rc;
 
@@ -629,11 +740,13 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
 \f
 /* Do the actual decryption and check the return list for consistency.  */
 static int
-do_decryption (const unsigned char *protected, size_t protectedlen,
+do_decryption (const unsigned char *aad_begin, size_t aad_len,
+               const unsigned char *aadhole_begin, size_t aadhole_len,
+               const unsigned char *protected, size_t protectedlen,
                const char *passphrase,
                const unsigned char *s2ksalt, unsigned long s2kcount,
                const unsigned char *iv, size_t ivlen,
-               int prot_cipher, int prot_cipher_keylen,
+               int prot_cipher, int prot_cipher_keylen, int is_ocb,
                unsigned char **result)
 {
   int rc = 0;
@@ -642,11 +755,29 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
   unsigned char *outbuf;
   size_t reallen;
 
+  if (is_ocb && !OCB_MODE_SUPPORTED)
+    return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
+
   blklen = gcry_cipher_get_algo_blklen (prot_cipher);
-  if (protectedlen < 4 || (protectedlen%blklen))
-    return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+  if (is_ocb)
+    {
+      /* OCB does not require a multiple of the block length but we
+       * check that it is long enough for the 128 bit tag and that we
+       * have the 96 bit nonce.  */
+      if (protectedlen < (4 + 16) || ivlen != 12)
+        return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+    }
+  else
+    {
+      if (protectedlen < 4 || (protectedlen%blklen))
+        return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+    }
 
-  rc = gcry_cipher_open (&hd, prot_cipher, GCRY_CIPHER_MODE_CBC,
+  rc = gcry_cipher_open (&hd, prot_cipher,
+#if OCB_MODE_SUPPORTED
+                         is_ocb? GCRY_CIPHER_MODE_OCB :
+#endif
+                         GCRY_CIPHER_MODE_CBC,
                          GCRY_CIPHER_SECURE);
   if (rc)
     return rc;
@@ -654,8 +785,8 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
   outbuf = gcry_malloc_secure (protectedlen);
   if (!outbuf)
     rc = out_of_core ();
-  if (!rc)
-    rc = gcry_cipher_setiv (hd, iv, ivlen);
+
+  /* Hash the passphrase and set the key.  */
   if (!rc)
     {
       unsigned char *key;
@@ -672,21 +803,60 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
           xfree (key);
         }
     }
+
+  /* Set the IV/nonce.  */
   if (!rc)
-    rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
-                              protected, protectedlen);
+    {
+      rc = gcry_cipher_setiv (hd, iv, ivlen);
+    }
+
+  /* Decrypt.  */
+  if (!rc)
+    {
+#if OCB_MODE_SUPPORTED
+      if (is_ocb)
+        {
+          rc = gcry_cipher_authenticate (hd, aad_begin,
+                                         aadhole_begin - aad_begin);
+          if (!rc)
+            rc = gcry_cipher_authenticate
+              (hd, aadhole_begin + aadhole_len,
+               aad_len - (aadhole_begin+aadhole_len - aad_begin));
+
+          if (!rc)
+            {
+              gcry_cipher_final (hd);
+              rc = gcry_cipher_decrypt (hd, outbuf, protectedlen - 16,
+                                        protected, protectedlen - 16);
+            }
+          if (!rc)
+            rc = gcry_cipher_checktag (hd, protected + protectedlen - 16, 16);
+        }
+      else
+#endif /*OCB_MODE_SUPPORTED*/
+        {
+          rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
+                                    protected, protectedlen);
+        }
+    }
+
+  /* Release cipher handle and check for errors.  */
   gcry_cipher_close (hd);
   if (rc)
     {
       xfree (outbuf);
       return rc;
     }
-  /* Do a quick check first. */
+
+  /* Do a quick check on the data structure. */
   if (*outbuf != '(' && outbuf[1] != '(')
     {
+      /* Note that in OCB mode this is actually invalid _encrypted_
+       * data and not a bad passphrase.  */
       xfree (outbuf);
       return gpg_error (GPG_ERR_BAD_PASSPHRASE);
     }
+
   /* Check that we have a consistent S-Exp. */
   reallen = gcry_sexp_canon_len (outbuf, protectedlen, NULL, NULL);
   if (!reallen || (reallen + blklen < protectedlen) )
@@ -700,11 +870,12 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
 
 
 /* Merge the parameter list contained in CLEARTEXT with the original
-   protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
-   Return the new list in RESULT and the MIC value in the 20 byte
-   buffer SHA1HASH.  CUTOFF and CUTLEN will receive the offset and the
-   length of the resulting list which should go into the MIC
-   calculation but then be removed.  */
+ * protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
+ * Return the new list in RESULT and the MIC value in the 20 byte
+ * buffer SHA1HASH; if SHA1HASH is NULL no MIC will be computed.
+ * CUTOFF and CUTLEN will receive the offset and the length of the
+ * resulting list which should go into the MIC calculation but then be
+ * removed.  */
 static int
 merge_lists (const unsigned char *protectedkey,
              size_t replacepos,
@@ -728,7 +899,7 @@ merge_lists (const unsigned char *protectedkey,
     return gpg_error (GPG_ERR_BUG);
 
   /* Estimate the required size of the resulting list.  We have a large
-     safety margin of >20 bytes (MIC hash from CLEARTEXT and the
+     safety margin of >20 bytes (FIXME: MIC hash from CLEARTEXT and the
      removed "protected-" */
   newlistlen = gcry_sexp_canon_len (protectedkey, 0, NULL, NULL);
   if (!newlistlen)
@@ -747,7 +918,7 @@ merge_lists (const unsigned char *protectedkey,
   memcpy (p, protectedkey+15+10, replacepos-15-10);
   p += replacepos-15-10;
 
-  /* copy the cleartext */
+  /* Copy the cleartext.  */
   s = cleartext;
   if (*s != '(' && s[1] != '(')
     return gpg_error (GPG_ERR_BUG);  /*we already checked this */
@@ -772,26 +943,29 @@ merge_lists (const unsigned char *protectedkey,
     goto invalid_sexp;
   endpos = s;
   s++;
-  /* Intermezzo: Get the MIC */
-  if (*s != '(')
-    goto invalid_sexp;
-  s++;
-  n = snext (&s);
-  if (!smatch (&s, n, "hash"))
-    goto invalid_sexp;
-  n = snext (&s);
-  if (!smatch (&s, n, "sha1"))
-    goto invalid_sexp;
-  n = snext (&s);
-  if (n != 20)
-    goto invalid_sexp;
-  memcpy (sha1hash, s, 20);
-  s += n;
-  if (*s != ')')
-    goto invalid_sexp;
-  /* End intermezzo */
 
-  /* append the parameter list */
+  /* Intermezzo: Get the MIC if requested.  */
+  if (sha1hash)
+    {
+      if (*s != '(')
+        goto invalid_sexp;
+      s++;
+      n = snext (&s);
+      if (!smatch (&s, n, "hash"))
+        goto invalid_sexp;
+      n = snext (&s);
+      if (!smatch (&s, n, "sha1"))
+        goto invalid_sexp;
+      n = snext (&s);
+      if (n != 20)
+        goto invalid_sexp;
+      memcpy (sha1hash, s, 20);
+      s += n;
+      if (*s != ')')
+        goto invalid_sexp;
+    }
+
+  /* Append the parameter list.  */
   memcpy (p, startpos, endpos - startpos);
   p += endpos - startpos;
 
@@ -865,9 +1039,11 @@ agent_unprotect (ctrl_t ctrl,
     const char *name; /* Name of the protection method. */
     int algo;         /* (A zero indicates the "openpgp-native" hack.)  */
     int keylen;       /* Used key length in bytes.  */
+    unsigned int is_ocb:1;
   } algotable[] = {
     { "openpgp-s2k3-sha1-aes-cbc",    GCRY_CIPHER_AES128, (128/8)},
     { "openpgp-s2k3-sha1-aes256-cbc", GCRY_CIPHER_AES256, (256/8)},
+    { "openpgp-s2k3-ocb-aes",         GCRY_CIPHER_AES128, (128/8), 1},
     { "openpgp-native", 0, 0 }
   };
   int rc;
@@ -880,6 +1056,8 @@ agent_unprotect (ctrl_t ctrl,
   unsigned long s2kcount;
   const unsigned char *iv;
   int prot_cipher, prot_cipher_keylen;
+  int is_ocb;
+  const unsigned char *aad_begin, *aad_end, *aadhole_begin, *aadhole_end;
   const unsigned char *prot_begin;
   unsigned char *cleartext;
   unsigned char *final;
@@ -900,6 +1078,15 @@ agent_unprotect (ctrl_t ctrl,
     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
   if (*s != '(')
     return gpg_error (GPG_ERR_UNKNOWN_SEXP);
+  {
+    aad_begin = aad_end = s;
+    aad_end++;
+    i = 1;
+    rc = sskip (&aad_end, &i);
+    if (rc)
+      return rc;
+  }
+
   s++;
   n = snext (&s);
   if (!n)
@@ -911,7 +1098,6 @@ agent_unprotect (ctrl_t ctrl,
   if (!protect_info[infidx].algo)
     return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
 
-
   /* See wether we have a protected-at timestamp.  */
   protect_list = s;  /* Save for later.  */
   if (protected_at)
@@ -967,6 +1153,14 @@ agent_unprotect (ctrl_t ctrl,
         return rc;
     }
   /* found */
+  {
+    aadhole_begin = aadhole_end = prot_begin;
+    aadhole_end++;
+    i = 1;
+    rc = sskip (&aadhole_end, &i);
+    if (rc)
+      return rc;
+  }
   n = snext (&s);
   if (!n)
     return gpg_error (GPG_ERR_INV_SEXP);
@@ -974,14 +1168,17 @@ agent_unprotect (ctrl_t ctrl,
   /* Lookup the protection algo.  */
   prot_cipher = 0;        /* (avoid gcc warning) */
   prot_cipher_keylen = 0; /* (avoid gcc warning) */
-  for (i= 0; i < DIM (algotable); i++)
+  is_ocb = 0;
+  for (i=0; i < DIM (algotable); i++)
     if (smatch (&s, n, algotable[i].name))
       {
         prot_cipher = algotable[i].algo;
         prot_cipher_keylen = algotable[i].keylen;
+        is_ocb = algotable[i].is_ocb;
         break;
       }
-  if (i == DIM (algotable))
+  if (i == DIM (algotable)
+      || (is_ocb && !OCB_MODE_SUPPORTED))
     return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
 
   if (!prot_cipher)  /* This is "openpgp-native".  */
@@ -1046,8 +1243,16 @@ agent_unprotect (ctrl_t ctrl,
   s++; /* skip list end */
 
   n = snext (&s);
-  if (n != 16) /* Wrong blocksize for IV (we support only 128 bit). */
-    return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+  if (is_ocb)
+    {
+      if (n != 12) /* Wrong size of the nonce. */
+        return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+    }
+  else
+    {
+      if (n != 16) /* Wrong blocksize for IV (we support only 128 bit). */
+        return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+    }
   iv = s;
   s += n;
   if (*s != ')' )
@@ -1058,15 +1263,19 @@ agent_unprotect (ctrl_t ctrl,
     return gpg_error (GPG_ERR_INV_SEXP);
 
   cleartext = NULL; /* Avoid cc warning. */
-  rc = do_decryption (s, n,
+  rc = do_decryption (aad_begin, aad_end - aad_begin,
+                      aadhole_begin, aadhole_end - aadhole_begin,
+                      s, n,
                       passphrase, s2ksalt, s2kcount,
-                      iv, 16, prot_cipher, prot_cipher_keylen,
+                      iv, is_ocb? 12:16,
+                      prot_cipher, prot_cipher_keylen, is_ocb,
                       &cleartext);
   if (rc)
     return rc;
 
   rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
-                    sha1hash, &final, &finallen, &cutoff, &cutlen);
+                    is_ocb? NULL : sha1hash,
+                    &final, &finallen, &cutoff, &cutlen);
   /* Albeit cleartext has been allocated in secure memory and thus
      xfree will wipe it out, we do an extra wipe just in case
      somethings goes badly wrong. */
@@ -1075,15 +1284,19 @@ agent_unprotect (ctrl_t ctrl,
   if (rc)
     return rc;
 
-  rc = calculate_mic (final, sha1hash2);
-  if (!rc && memcmp (sha1hash, sha1hash2, 20))
-    rc = gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
-  if (rc)
+  if (!is_ocb)
     {
-      wipememory (final, finallen);
-      xfree (final);
-      return rc;
+      rc = calculate_mic (final, sha1hash2);
+      if (!rc && memcmp (sha1hash, sha1hash2, 20))
+        rc = gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
+      if (rc)
+        {
+          wipememory (final, finallen);
+          xfree (final);
+          return rc;
+        }
     }
+
   /* Now remove the part which is included in the MIC but should not
      go into the final thing.  */
   if (cutlen)
@@ -1182,7 +1395,6 @@ agent_private_key_type (const unsigned char *privatekey)
           n = snext (&s);
           if (!n)
             return PRIVATE_KEY_UNKNOWN; /* Invalid sexp.  */
-          log_debug ("openpgp-native protection '%.*s'\n", (int)n, s);
           if (smatch (&s, n, "none"))
             return PRIVATE_KEY_OPENPGP_NONE;  /* Yes.  */
         }
index 9096cb2..431eccf 100644 (file)
@@ -195,7 +195,7 @@ test_agent_protect (void)
     {
       ret = agent_protect ((const unsigned char*)specs[i].key,
                            specs[i].passphrase,
-                          &specs[i].result, &specs[i].resultlen, 0);
+                          &specs[i].result, &specs[i].resultlen, 0, -1);
       if (gpg_err_code (ret) != specs[i].ret_expected)
        {
          printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n",
index 832d6c4..8cb7eed 100644 (file)
@@ -8,7 +8,7 @@ case "$myhost:$myhostsub" in
     extraoptions="$extraoptions --disable-zip --enable-gpg2-is-gpg"
     ;;
   w32:)
-    extraoptions="--enable-gpgtar"
+    extraoptions="--enable-gpgtar --enable-gpg2-is-gpg"
     ;;
 esac
 
index dbfb978..0967f2a 100755 (executable)
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2015 Free Software Foundation, Inc.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2015-01-01'
+timestamp='2016-04-02'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ timestamp='2015-01-01'
 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 #
 # Please send patches to <config-patches@gnu.org>.
 
@@ -50,7 +50,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2015 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -168,20 +168,27 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        # Note: NetBSD doesn't particularly care about the vendor
        # portion of the name.  We always set it to "unknown".
        sysctl="sysctl -n hw.machine_arch"
-       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
-           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+           /sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || \
+           echo unknown)`
        case "${UNAME_MACHINE_ARCH}" in
            armeb) machine=armeb-unknown ;;
            arm*) machine=arm-unknown ;;
            sh3el) machine=shl-unknown ;;
            sh3eb) machine=sh-unknown ;;
            sh5el) machine=sh5le-unknown ;;
+           earmv*)
+               arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+               endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+               machine=${arch}${endian}-unknown
+               ;;
            *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
        esac
        # The Operating System including object format, if it has switched
        # to ELF recently, or will in the future.
        case "${UNAME_MACHINE_ARCH}" in
-           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+           arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax)
                eval $set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
                        | grep -q __ELF__
@@ -197,6 +204,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
                os=netbsd
                ;;
        esac
+       # Determine ABI tags.
+       case "${UNAME_MACHINE_ARCH}" in
+           earm*)
+               expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+               abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
+               ;;
+       esac
        # The OS release
        # Debian GNU/NetBSD machines have a different userland, and
        # thus, need a distinct triplet. However, they do not need
@@ -207,13 +221,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
                release='-gnu'
                ;;
            *)
-               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
                ;;
        esac
        # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
        # contains redundant information, the shorter form:
        # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-       echo "${machine}-${os}${release}"
+       echo "${machine}-${os}${release}${abi}"
        exit ;;
     *:Bitrig:*:*)
        UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
@@ -223,6 +237,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
        echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
        exit ;;
+    *:LibertyBSD:*:*)
+       UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+       echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+       exit ;;
     *:ekkoBSD:*:*)
        echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
        exit ;;
@@ -235,6 +253,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:MirBSD:*:*)
        echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
        exit ;;
+    *:Sortix:*:*)
+       echo ${UNAME_MACHINE}-unknown-sortix
+       exit ;;
     alpha:OSF1:*:*)
        case $UNAME_RELEASE in
        *4.0)
@@ -251,42 +272,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
        case "$ALPHA_CPU_TYPE" in
            "EV4 (21064)")
-               UNAME_MACHINE="alpha" ;;
+               UNAME_MACHINE=alpha ;;
            "EV4.5 (21064)")
-               UNAME_MACHINE="alpha" ;;
+               UNAME_MACHINE=alpha ;;
            "LCA4 (21066/21068)")
-               UNAME_MACHINE="alpha" ;;
+               UNAME_MACHINE=alpha ;;
            "EV5 (21164)")
-               UNAME_MACHINE="alphaev5" ;;
+               UNAME_MACHINE=alphaev5 ;;
            "EV5.6 (21164A)")
-               UNAME_MACHINE="alphaev56" ;;
+               UNAME_MACHINE=alphaev56 ;;
            "EV5.6 (21164PC)")
-               UNAME_MACHINE="alphapca56" ;;
+               UNAME_MACHINE=alphapca56 ;;
            "EV5.7 (21164PC)")
-               UNAME_MACHINE="alphapca57" ;;
+               UNAME_MACHINE=alphapca57 ;;
            "EV6 (21264)")
-               UNAME_MACHINE="alphaev6" ;;
+               UNAME_MACHINE=alphaev6 ;;
            "EV6.7 (21264A)")
-               UNAME_MACHINE="alphaev67" ;;
+               UNAME_MACHINE=alphaev67 ;;
            "EV6.8CB (21264C)")
-               UNAME_MACHINE="alphaev68" ;;
+               UNAME_MACHINE=alphaev68 ;;
            "EV6.8AL (21264B)")
-               UNAME_MACHINE="alphaev68" ;;
+               UNAME_MACHINE=alphaev68 ;;
            "EV6.8CX (21264D)")
-               UNAME_MACHINE="alphaev68" ;;
+               UNAME_MACHINE=alphaev68 ;;
            "EV6.9A (21264/EV69A)")
-               UNAME_MACHINE="alphaev69" ;;
+               UNAME_MACHINE=alphaev69 ;;
            "EV7 (21364)")
-               UNAME_MACHINE="alphaev7" ;;
+               UNAME_MACHINE=alphaev7 ;;
            "EV7.9 (21364A)")
-               UNAME_MACHINE="alphaev79" ;;
+               UNAME_MACHINE=alphaev79 ;;
        esac
        # A Pn.n version is a patched version.
        # A Vn.n version is a released version.
        # A Tn.n version is a released field test version.
        # A Xn.n version is an unreleased experimental baselevel.
        # 1.2 uses "1.2" for uname -r.
-       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
        # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
        exitcode=$?
        trap '' 0
@@ -359,16 +380,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
        eval $set_cc_for_build
-       SUN_ARCH="i386"
+       SUN_ARCH=i386
        # If there is a compiler, see if it is configured for 64-bit objects.
        # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
        # This test works for both compilers.
-       if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+       if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
            if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-               (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+               (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
                grep IS_64BIT_ARCH >/dev/null
            then
-               SUN_ARCH="x86_64"
+               SUN_ARCH=x86_64
            fi
        fi
        echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -393,7 +414,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
        exit ;;
     sun*:*:4.2BSD:*)
        UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-       test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+       test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
        case "`/bin/arch`" in
            sun3)
                echo m68k-sun-sunos${UNAME_RELEASE}
@@ -618,13 +639,13 @@ EOF
                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
                    case "${sc_cpu_version}" in
-                     523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-                     528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+                     523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+                     528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
                      532)                      # CPU_PA_RISC2_0
                        case "${sc_kernel_bits}" in
-                         32) HP_ARCH="hppa2.0n" ;;
-                         64) HP_ARCH="hppa2.0w" ;;
-                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+                         32) HP_ARCH=hppa2.0n ;;
+                         64) HP_ARCH=hppa2.0w ;;
+                         '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
                        esac ;;
                    esac
                fi
@@ -663,11 +684,11 @@ EOF
                    exit (0);
                }
 EOF
-                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
                    test -z "$HP_ARCH" && HP_ARCH=hppa
                fi ;;
        esac
-       if [ ${HP_ARCH} = "hppa2.0w" ]
+       if [ ${HP_ARCH} = hppa2.0w ]
        then
            eval $set_cc_for_build
 
@@ -680,12 +701,12 @@ EOF
            # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
            # => hppa64-hp-hpux11.23
 
-           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+           if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
                grep -q __LP64__
            then
-               HP_ARCH="hppa2.0w"
+               HP_ARCH=hppa2.0w
            else
-               HP_ARCH="hppa64"
+               HP_ARCH=hppa64
            fi
        fi
        echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -790,14 +811,14 @@ EOF
        echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
        exit ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-       FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+       FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+       FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
        exit ;;
     5000:UNIX_System_V:4.*:*)
-       FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+       FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+       FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
        exit ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
@@ -879,7 +900,7 @@ EOF
        exit ;;
     *:GNU/*:*:*)
        # other systems with GNU libc and userland
-       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
        exit ;;
     i*86:Minix:*:*)
        echo ${UNAME_MACHINE}-pc-minix
@@ -902,7 +923,7 @@ EOF
          EV68*) UNAME_MACHINE=alphaev68 ;;
        esac
        objdump --private-headers /bin/sh | grep -q ld.so.1
-       if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+       if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
     arc:Linux:*:* | arceb:Linux:*:*)
@@ -933,6 +954,9 @@ EOF
     crisv32:Linux:*:*)
        echo ${UNAME_MACHINE}-axis-linux-${LIBC}
        exit ;;
+    e2k:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
     frv:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
@@ -945,6 +969,9 @@ EOF
     ia64:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
+    k1om:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       exit ;;
     m32r*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
        exit ;;
@@ -1021,7 +1048,7 @@ EOF
        echo ${UNAME_MACHINE}-dec-linux-${LIBC}
        exit ;;
     x86_64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+       echo ${UNAME_MACHINE}-pc-linux-${LIBC}
        exit ;;
     xtensa*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
@@ -1100,7 +1127,7 @@ EOF
        # uname -m prints for DJGPP always 'pc', but it prints nothing about
        # the processor, so we play safe by assuming i586.
        # Note: whatever this is, it MUST be the same as what config.sub
-       # prints for the "djgpp" host, or else GDB configury will decide that
+       # prints for the "djgpp" host, or else GDB configure will decide that
        # this is a cross-build.
        echo i586-pc-msdosdjgpp
        exit ;;
@@ -1249,6 +1276,9 @@ EOF
     SX-8R:SUPER-UX:*:*)
        echo sx8r-nec-superux${UNAME_RELEASE}
        exit ;;
+    SX-ACE:SUPER-UX:*:*)
+       echo sxace-nec-superux${UNAME_RELEASE}
+       exit ;;
     Power*:Rhapsody:*:*)
        echo powerpc-apple-rhapsody${UNAME_RELEASE}
        exit ;;
@@ -1262,9 +1292,9 @@ EOF
            UNAME_PROCESSOR=powerpc
        fi
        if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
-           if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+           if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
                if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-                   (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+                   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
                    grep IS_64BIT_ARCH >/dev/null
                then
                    case $UNAME_PROCESSOR in
@@ -1286,7 +1316,7 @@ EOF
        exit ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
        UNAME_PROCESSOR=`uname -p`
-       if test "$UNAME_PROCESSOR" = "x86"; then
+       if test "$UNAME_PROCESSOR" = x86; then
                UNAME_PROCESSOR=i386
                UNAME_MACHINE=pc
        fi
@@ -1317,7 +1347,7 @@ EOF
        # "uname -m" is not consistent, so use $cputype instead. 386
        # is converted to i386 for consistency with other x86
        # operating systems.
-       if test "$cputype" = "386"; then
+       if test "$cputype" = 386; then
            UNAME_MACHINE=i386
        else
            UNAME_MACHINE="$cputype"
@@ -1359,7 +1389,7 @@ EOF
        echo i386-pc-xenix
        exit ;;
     i*86:skyos:*:*)
-       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+       echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
        exit ;;
     i*86:rdos:*:*)
        echo ${UNAME_MACHINE}-pc-rdos
@@ -1370,6 +1400,9 @@ EOF
     x86_64:VMkernel:*:*)
        echo ${UNAME_MACHINE}-unknown-esx
        exit ;;
+    amd64:Isilon\ OneFS:*:*)
+       echo x86_64-unknown-onefs
+       exit ;;
 esac
 
 cat >&2 <<EOF
@@ -1379,9 +1412,9 @@ This script, last modified $timestamp, has failed to recognize
 the operating system you are using. It is advised that you
 download the most up to date version of the config scripts from
 
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 and
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
 If the version you run ($0) is already up to date, please
 send the following data and any information you think might be
index 6d2e94c..8d39c4b 100755 (executable)
@@ -1,8 +1,8 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright 1992-2015 Free Software Foundation, Inc.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
 
-timestamp='2015-01-01'
+timestamp='2016-03-30'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ timestamp='2015-01-01'
 # Otherwise, we print the canonical config type on stdout and succeed.
 
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
@@ -53,8 +53,7 @@ timestamp='2015-01-01'
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
-       $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
 
 Canonicalize a configuration name.
 
@@ -68,7 +67,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright 1992-2015 Free Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -117,7 +116,7 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
   nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
   linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
-  knetbsd*-gnu* | netbsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
   kopensolaris*-gnu* | \
   storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
@@ -255,11 +254,12 @@ case $basic_machine in
        | arc | arceb \
        | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
        | avr | avr32 \
+       | ba \
        | be32 | be64 \
        | bfin \
        | c4x | c8051 | clipper \
        | d10v | d30v | dlx | dsp16xx \
-       | epiphany \
+       | e2k | epiphany \
        | fido | fr30 | frv | ft32 \
        | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
        | hexagon \
@@ -305,7 +305,7 @@ case $basic_machine in
        | riscv32 | riscv64 \
        | rl78 | rx \
        | score \
-       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+       | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
        | sh64 | sh64le \
        | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
        | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
@@ -376,12 +376,13 @@ case $basic_machine in
        | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
        | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
        | avr-* | avr32-* \
+       | ba-* \
        | be32-* | be64-* \
        | bfin-* | bs2000-* \
        | c[123]* | c30-* | [cjt]90-* | c4x-* \
        | c8051-* | clipper-* | craynv-* | cydra-* \
        | d10v-* | d30v-* | dlx-* \
-       | elxsi-* \
+       | e2k-* | elxsi-* \
        | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
        | h8300-* | h8500-* \
        | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
@@ -428,12 +429,13 @@ case $basic_machine in
        | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
        | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
        | pyramid-* \
+       | riscv32-* | riscv64-* \
        | rl78-* | romp-* | rs6000-* | rx-* \
        | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
        | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
        | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
        | sparclite-* \
-       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
        | tahoe-* \
        | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
        | tile*-* \
@@ -518,6 +520,9 @@ case $basic_machine in
                basic_machine=i386-pc
                os=-aros
                ;;
+       asmjs)
+               basic_machine=asmjs-unknown
+               ;;
        aux)
                basic_machine=m68k-apple
                os=-aux
@@ -1373,11 +1378,11 @@ case $os in
              | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
              | -sym* | -kopensolaris* | -plan9* \
              | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-             | -aos* | -aros* \
+             | -aos* | -aros* | -cloudabi* | -sortix* \
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
              | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
              | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
-             | -bitrig* | -openbsd* | -solidbsd* \
+             | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
              | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
              | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
              | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
@@ -1393,7 +1398,8 @@ case $os in
              | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
              | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
              | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+             | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+             | -onefs* | -tirtos*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
@@ -1525,6 +1531,8 @@ case $os in
                ;;
        -nacl*)
                ;;
+       -ios)
+               ;;
        -none)
                ;;
        *)
index 5dde0fe..d286655 100644 (file)
@@ -172,9 +172,9 @@ speedo_spkgs  = \
 
 ifeq ($(TARGETOS),w32)
 speedo_spkgs += \
-       zlib bzip2 adns libiconv
+       zlib bzip2 adns sqlite
 ifeq ($(WITH_GUI),1)
-speedo_spkgs += gettext
+speedo_spkgs += gettext libiconv
 endif
 endif
 
@@ -306,6 +306,11 @@ adns_ver  := $(shell awk '$$1=="adns_ver" {print $$2}' swdb.lst)
 adns_sha1 := $(shell awk '$$1=="adns_sha1" {print $$2}' swdb.lst)
 adns_sha2 := $(shell awk '$$1=="adns_sha2" {print $$2}' swdb.lst)
 
+sqlite_ver  := $(shell awk '$$1=="sqlite_ver" {print $$2}' swdb.lst)
+sqlite_sha1 := $(shell awk '$$1=="sqlite_sha1_gz" {print $$2}' swdb.lst)
+sqlite_sha2 := $(shell awk '$$1=="sqlite_sha2_gz" {print $$2}' swdb.lst)
+
+
 $(info Information from the version database)
 $(info GnuPG ..........: $(gnupg_ver) (building $(gnupg_ver_this)))
 $(info Libgpg-error ...: $(libgpg_error_ver))
@@ -315,6 +320,7 @@ $(info Libassuan ......: $(libassuan_ver))
 $(info Zlib ...........: $(zlib_ver))
 $(info Bzip2 ..........: $(bzip2_ver))
 $(info ADNS ...........: $(adns_ver))
+$(info SQLite .........: $(sqlite_ver))
 $(info GPGME ..........: $(gpgme_ver))
 $(info Pinentry .......: $(pinentry_ver))
 $(info GPA ............: $(gpa_ver))
@@ -412,6 +418,7 @@ endif
 speedo_pkg_pkg_config_tar = $(pkg2rep)/pkg-config-$(pkg_config_ver).tar.gz
 speedo_pkg_zlib_tar       = $(pkgrep)/zlib/zlib-$(zlib_ver).tar.gz
 speedo_pkg_bzip2_tar      = $(pkgrep)/bzip2/bzip2-$(bzip2_ver).tar.gz
+speedo_pkg_sqlite_tar     = $(pkgrep)/sqlite/sqlite-autoconf-$(sqlite_ver).tar.gz
 speedo_pkg_adns_tar       = $(pkg10rep)/adns/adns-$(adns_ver).tar.bz2
 speedo_pkg_libiconv_tar   = $(pkg2rep)/libiconv-$(libiconv_ver).tar.gz
 speedo_pkg_gettext_tar    = $(pkg2rep)/gettext-$(gettext_ver).tar.gz
@@ -859,9 +866,13 @@ $(stampdir)/stamp-$(1)-00-unpack: $(stampdir)/stamp-directories
                  | sed -e 's,\.tar.*$$$$,,'`;          \
           mv $$$${base} $(1);                          \
           patch="$(patdir)/$(1)-$$$${base#$(1)-}.patch";\
+          patchx="$(patdir)/$(1).patch";               \
           if [ -x "$$$${patch}" ]; then                \
              echo "speedo: applying patch $$$${patch}"; \
              cd $(1); "$$$${patch}";                   \
+          elif [ -x "$$$${patchx}" ]; then             \
+             echo "speedo: applying patch $$$${patchx}";\
+             cd $(1); "$$$${patchx}";                  \
           elif [ -f "$$$${patch}" ]; then              \
              echo "speedo: warning: $$$${patch} is not executable"; \
           fi;                                          \
diff --git a/build-aux/speedo/patches/sqlite.patch b/build-aux/speedo/patches/sqlite.patch
new file mode 100755 (executable)
index 0000000..f81a414
--- /dev/null
@@ -0,0 +1,42 @@
+#! /bin/sh
+grep static-libgcc Makefile.am >/dev/null && exit 0
+patch -p0 -l -f $* < $0
+exit $?
+
+Use -static-libgcc to avoid linking to libgcc_s_sjlj-1.dll.
+
+Since gcc 4.8 there is a regression in that plain C programs may link
+to libgcc_s.a which has a dependency on libgcc_s_sjlj.dll.  This is
+for example triggered by using long long arithmetic on a 32 bit
+Windows (e.g symbol __udivdi3).
+
+As usual the gcc maintainers don't care about backward compatibility
+and declare that as some kind of compatibility fix and not as
+regression from 4.7 and all earlier versions.
+
+Note that we ignore this patch if it seems to be already applied
+upstream.
+
+--- Makefile.am~       2016-04-18 20:56:32.000000000 +0200
++++ Makefile.am        2016-05-04 12:08:53.254035717 +0200
+@@ -3,7 +3,7 @@
+
+ lib_LTLIBRARIES = libsqlite3.la
+ libsqlite3_la_SOURCES = sqlite3.c
+-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
++libsqlite3_la_LDFLAGS = -XCClinker -static-libgcc -no-undefined -version-info 8:6:8
+
+ bin_PROGRAMS = sqlite3
+ sqlite3_SOURCES = shell.c sqlite3.h
+
+--- Makefile.in~       2016-04-18 20:56:36.000000000 +0200
++++ Makefile.in        2016-05-04 12:13:36.570020590 +0200
+@@ -365,7 +365,7 @@
+ AM_CFLAGS = @THREADSAFE_FLAGS@ @DYNAMIC_EXTENSION_FLAGS@ @FTS5_FLAGS@ @JSON1_FLAGS@ -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_RTREE
+ lib_LTLIBRARIES = libsqlite3.la
+ libsqlite3_la_SOURCES = sqlite3.c
+-libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8
++libsqlite3_la_LDFLAGS = -XCClinker -static-libgcc -no-undefined -version-info 8:6:8
+ sqlite3_SOURCES = shell.c sqlite3.h
+ EXTRA_sqlite3_SOURCES = sqlite3.c
+ sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
index cb73e91..2c671c2 100644 (file)
@@ -156,10 +156,10 @@ VIAddVersionKey "FileVersion" "${PROD_VERSION}"
 !insertmacro MUI_PAGE_LICENSE "${TOP_SRCDIR}/COPYING"
 
 !define MUI_PAGE_CUSTOMFUNCTION_SHOW PrintNonAdminWarning
+!define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckExistingVersion
 !insertmacro MUI_PAGE_COMPONENTS
 
-!define MUI_PAGE_CUSTOMFUNCTION_LEAVE CheckExistingVersion
-!insertmacro MUI_PAGE_DIRECTORY
+# We don't have MUI_PAGE_DIRECTORY
 
 !ifdef HAVE_STARTMENU
 
@@ -260,11 +260,11 @@ LangString T_RunKeyManager ${LANG_GERMAN} \
    "Die Schlüsselverwaltung aufrufen"
 
 LangString T_MoreInfo ${LANG_ENGLISH} \
-   "Click here for GnuPG's website"
+   "Click here to see how to help the GnuPG Project"
 LangString T_MoreInfo ${LANG_GERMAN} \
-   "Hier klicken um zur GnuPG Homepage zu gelangen"
-LangString T_MoreInfoURL ${LANG_ENGLISH} "https://gnupg.org"
-LangString T_MoreInfoURL ${LANG_GERMAN}  "https://gnupg.org"
+   "Hier klicken um dem GnuPG Projekt zu zu helfen"
+LangString T_MoreInfoURL ${LANG_ENGLISH} "https://gnupg.org/donate"
+LangString T_MoreInfoURL ${LANG_GERMAN}  "https://gnupg.org/donate"
 
 LangString T_ShowReadme ${LANG_ENGLISH} \
    "Show the README file"
@@ -319,8 +319,8 @@ FunctionEnd
 
 
 # Check whether GnuPG has already been installed.  This is called as
-# a leave function from the directory page.  A call to abort will get
-# back to the directory selection.
+# a leave function from the components page.  A call to abort will get
+# back to the components selection.
 Function CheckExistingVersion
   ClearErrors
   FileOpen $0 "$INSTDIR\VERSION" r
@@ -573,8 +573,8 @@ Section "GnuPG" SEC_gnupg
   SectionIn RO
 
   SetOutPath "$INSTDIR\bin"
-  File /oname=gpg.exe "bin/gpg2.exe"
-  File /oname=gpgv.exe "bin/gpgv2.exe"
+  File "bin/gpg.exe"
+  File "bin/gpgv.exe"
   File "bin/gpgsm.exe"
   File "bin/gpgconf.exe"
   File "bin/gpg-connect-agent.exe"
@@ -608,6 +608,63 @@ Section "GnuPG" SEC_gnupg
   File "share/gnupg/gpg-conf.skel"
   File "share/gnupg/dirmngr-conf.skel"
   File "share/gnupg/distsigkey.gpg"
+
+  SetOutPath "$INSTDIR\share\locale\ca\LC_MESSAGES"
+  File share/locale/ca/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\cs\LC_MESSAGES"
+  File share/locale/cs/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\da\LC_MESSAGES"
+  File share/locale/da/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\de\LC_MESSAGES"
+  File share/locale/de/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\el\LC_MESSAGES"
+  File share/locale/el/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\en@boldquot\LC_MESSAGES"
+  File share/locale/en@boldquot/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\en@quot\LC_MESSAGES"
+  File share/locale/en@quot/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\eo\LC_MESSAGES"
+  File share/locale/eo/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\es\LC_MESSAGES"
+  File share/locale/es/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\et\LC_MESSAGES"
+  File share/locale/et/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\fi\LC_MESSAGES"
+  File share/locale/fi/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\fr\LC_MESSAGES"
+  File share/locale/fr/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\gl\LC_MESSAGES"
+  File share/locale/gl/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\hu\LC_MESSAGES"
+  File share/locale/hu/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\id\LC_MESSAGES"
+  File share/locale/id/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\it\LC_MESSAGES"
+  File share/locale/it/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\ja\LC_MESSAGES"
+  File share/locale/ja/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\nb\LC_MESSAGES"
+  File share/locale/nb/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\pl\LC_MESSAGES"
+  File share/locale/pl/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\pt\LC_MESSAGES"
+  File share/locale/pt/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\ro\LC_MESSAGES"
+  File share/locale/ro/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\ru\LC_MESSAGES"
+  File share/locale/ru/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\sk\LC_MESSAGES"
+  File share/locale/sk/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\sv\LC_MESSAGES"
+  File share/locale/sv/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\tr\LC_MESSAGES"
+  File share/locale/tr/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\uk\LC_MESSAGES"
+  File share/locale/uk/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\zh_CN\LC_MESSAGES"
+  File share/locale/zh_CN/LC_MESSAGES/gnupg2.mo
+  SetOutPath "$INSTDIR\share\locale\zh_TW\LC_MESSAGES"
+  File share/locale/zh_TW/LC_MESSAGES/gnupg2.mo
 SectionEnd
 
 
@@ -631,11 +688,44 @@ Section "-libgpg-error" SEC_libgpg_error
   File /oname=libgpg-error.imp lib/libgpg-error.dll.a
   SetOutPath "$INSTDIR\include"
   File include/gpg-error.h
-SectionEnd
-
-Section "-libiconv" SEC_libiconv
-  SetOutPath "$INSTDIR\bin"
-  File bin/libiconv-2.dll
+  SetOutPath "$INSTDIR\share\locale\cs\LC_MESSAGES"
+  File share/locale/cs/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\da\LC_MESSAGES"
+  File share/locale/da/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\de\LC_MESSAGES"
+  File share/locale/de/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\eo\LC_MESSAGES"
+  File share/locale/eo/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\fr\LC_MESSAGES"
+  File share/locale/fr/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\hu\LC_MESSAGES"
+  File share/locale/hu/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\it\LC_MESSAGES"
+  File share/locale/it/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\ja\LC_MESSAGES"
+  File share/locale/ja/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\nl\LC_MESSAGES"
+  File share/locale/nl/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\pl\LC_MESSAGES"
+  File share/locale/pl/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\pt\LC_MESSAGES"
+  File share/locale/pt/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\ro\LC_MESSAGES"
+  File share/locale/ro/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\ru\LC_MESSAGES"
+  File share/locale/ru/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\sr\LC_MESSAGES"
+  File share/locale/sr/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\sv\LC_MESSAGES"
+  File share/locale/sv/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\uk\LC_MESSAGES"
+  File share/locale/uk/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\vi\LC_MESSAGES"
+  File share/locale/vi/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\zh_CN\LC_MESSAGES"
+  File share/locale/zh_CN/LC_MESSAGES/libgpg-error.mo
+  SetOutPath "$INSTDIR\share\locale\zh_TW\LC_MESSAGES"
+  File share/locale/zh_TW/LC_MESSAGES/libgpg-error.mo
 SectionEnd
 
 Section "-zlib" SEC_zlib
@@ -700,7 +790,17 @@ Section "-gpgme" SEC_gpgme
   File include/gpgme.h
 SectionEnd
 
+Section "-sqlite" SEC_sqlite
+  SetOutPath "$INSTDIR\bin"
+  File bin/libsqlite3-0.dll
+SectionEnd
+
 !ifdef WITH_GUI
+Section "-libiconv" SEC_libiconv
+  SetOutPath "$INSTDIR\bin"
+  File bin/libiconv-2.dll
+SectionEnd
+
 Section "-gettext" SEC_gettext
   SetOutPath "$INSTDIR\bin"
   File bin/libintl-8.dll
@@ -1054,6 +1154,10 @@ Section "-un.gettext"
   Delete "$INSTDIR\bin\libintl-8.dll"
 SectionEnd
 
+Section "-un.libiconv"
+  Delete "$INSTDIR\bin\libiconv-2.dll"
+SectionEnd
+
 Section "-un.gpgme"
   Delete "$INSTDIR\bin\libgpgme-11.dll"
   Delete "$INSTDIR\bin\libgpgme-glib-11.dll"
@@ -1097,14 +1201,68 @@ Section "-un.zlib"
   Delete "$INSTDIR\bin\zlib1.dll"
 SectionEnd
 
-Section "-un.libiconv"
-  Delete "$INSTDIR\bin\libiconv-2.dll"
-SectionEnd
-
 Section "-un.libgpg-error"
   Delete "$INSTDIR\bin\libgpg-error-0.dll"
   Delete "$INSTDIR\lib\libgpg-error.imp"
   Delete "$INSTDIR\include\gpg-error.h"
+  Delete "$INSTDIR\share\locale\cs\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\cs\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\cs"
+  Delete "$INSTDIR\share\locale\da\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\da\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\da"
+  Delete "$INSTDIR\share\locale\de\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\de\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\de"
+  Delete "$INSTDIR\share\locale\eo\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\eo\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\eo"
+  Delete "$INSTDIR\share\locale\fr\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\fr\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\fr"
+  Delete "$INSTDIR\share\locale\hu\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\hu\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\hu"
+  Delete "$INSTDIR\share\locale\it\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\it\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\it"
+  Delete "$INSTDIR\share\locale\ja\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\ja\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ja"
+  Delete "$INSTDIR\share\locale\nl\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\nl\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\nl"
+  Delete "$INSTDIR\share\locale\pl\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\pl\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\pl"
+  Delete "$INSTDIR\share\locale\pt\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\pt\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\pt"
+  Delete "$INSTDIR\share\locale\ro\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\ro\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ro"
+  Delete "$INSTDIR\share\locale\ru\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\ru\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ru"
+  Delete "$INSTDIR\share\locale\sr\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\sr\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\sr"
+  Delete "$INSTDIR\share\locale\sv\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\sv\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\sv"
+  Delete "$INSTDIR\share\locale\uk\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\uk\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\uk"
+  Delete "$INSTDIR\share\locale\vi\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\vi\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\vi"
+  Delete "$INSTDIR\share\locale\zh_CN\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\zh_CN\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\zh_CN"
+  Delete "$INSTDIR\share\locale\zh_TW\LC_MESSAGES\libgpg-error.mo"
+  RMDir "$INSTDIR\share\locale\zh_TW\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\zh_TW"
+  RMDir "$INSTDIR\share\locale"
 SectionEnd
 
 Section "-un.gnupg"
@@ -1118,8 +1276,100 @@ Section "-un.gnupg"
   Delete "$INSTDIR\bin\gpg-connect-agent.exe"
   Delete "$INSTDIR\bin\gpgtar.exe"
 
+  Delete "$INSTDIR\share\gnupg\dirmngr-conf.skel"
+  Delete "$INSTDIR\share\gnupg\distsigkey.gpg"
   Delete "$INSTDIR\share\gnupg\gpg-conf.skel"
   RMDir  "$INSTDIR\share\gnupg"
+
+  Delete "$INSTDIR\share\locale\ca\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\ca\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ca"
+  Delete "$INSTDIR\share\locale\cs\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\cs\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\cs"
+  Delete "$INSTDIR\share\locale\da\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\da\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\da"
+  Delete "$INSTDIR\share\locale\de\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\de\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\de"
+  Delete "$INSTDIR\share\locale\el\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\el\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\el"
+  Delete "$INSTDIR\share\locale\en@boldquot\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\en@boldquot\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\en@boldquot"
+  Delete "$INSTDIR\share\locale\en@quot\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\en@quot\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\en@quot"
+  Delete "$INSTDIR\share\locale\eo\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\eo\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\eo"
+  Delete "$INSTDIR\share\locale\es\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\es\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\es"
+  Delete "$INSTDIR\share\locale\et\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\et\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\et"
+  Delete "$INSTDIR\share\locale\fi\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\fi\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\fi"
+  Delete "$INSTDIR\share\locale\fr\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\fr\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\fr"
+  Delete "$INSTDIR\share\locale\gl\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\gl\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\gl"
+  Delete "$INSTDIR\share\locale\hu\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\hu\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\hu"
+  Delete "$INSTDIR\share\locale\id\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\id\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\id"
+  Delete "$INSTDIR\share\locale\it\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\it\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\it"
+  Delete "$INSTDIR\share\locale\ja\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\ja\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ja"
+  Delete "$INSTDIR\share\locale\nb\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\nb\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\nb"
+  Delete "$INSTDIR\share\locale\pl\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\pl\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\pl"
+  Delete "$INSTDIR\share\locale\pt\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\pt\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\pt"
+  Delete "$INSTDIR\share\locale\ro\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\ro\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ro"
+  Delete "$INSTDIR\share\locale\ru\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\ru\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\ru"
+  Delete "$INSTDIR\share\locale\sk\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\sk\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\sk"
+  Delete "$INSTDIR\share\locale\sv\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\sv\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\sv"
+  Delete "$INSTDIR\share\locale\tr\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\tr\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\tr"
+  Delete "$INSTDIR\share\locale\uk\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\uk\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\uk"
+  Delete "$INSTDIR\share\locale\zh_CN\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\zh_CN\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\zh_CN"
+  Delete "$INSTDIR\share\locale\zh_TW\LC_MESSAGES\gnupg2.mo"
+  RMDir "$INSTDIR\share\locale\zh_TW\LC_MESSAGES"
+  RMDir "$INSTDIR\share\locale\zh_TW"
+  RMDir "$INSTDIR\share\locale"
+SectionEnd
+
+Section "-un.sqlite"
+  Delete "$INSTDIR\bin\libsqlite3-0.dll"
 SectionEnd
 
 Section "-un.gnupginst"
index 4cc4dc9..9495bcd 100644 (file)
@@ -1,11 +1,11 @@
 Here is a list with collected copyright notices. For details see the
-description of each individual package.  [Compiled by wk FIXME]
+description of each individual package.  [Compiled by wk 2016-04-20]
 
 GnuPG is
 
-  Copyright (C) 1997-2015 Werner Koch
-  Copyright (C) 1994-2015 Free Software Foundation, Inc.
-  Copyright (C) 2003-2015 g10 Code GmbH
+  Copyright (C) 1997-2016 Werner Koch
+  Copyright (C) 1994-2016 Free Software Foundation, Inc.
+  Copyright (C) 2003-2016 g10 Code GmbH
   Copyright (C) 2002 Klarälvdalens Datakonsult AB
   Copyright (C) 1995-1997, 2000-2007 Ulrich Drepper <drepper@gnu.ai.mit.edu>
   Copyright (C) 1994 X Consortium
@@ -102,3 +102,21 @@ NSIS is
 
   [It is distributed along with NSIS and the same conditions as stated
    above apply]
+
+
+ADNS is
+
+  Copyright (C) 1997-2000,2003,2006 Ian Jackson
+  Copyright (C) 1999-2000,2003,2006 Tony Finch
+  Copyright (C) 1991 Massachusetts Institute of Technology
+
+
+SQLite has
+
+  been put into the public-domain by its author D. Richard Hipp:
+  The author disclaims copyright to this source code.  In place of
+  a legal notice, here is a blessing:
+
+      May you do good and not evil.
+      May you find forgiveness for yourself and forgive others.
+      May you share freely, never taking more than you give.
index d09f0df..4a35f64 100644 (file)
@@ -88,7 +88,9 @@ common_sources = \
        mkdir_p.c mkdir_p.h \
        strlist.c strlist.h \
        call-gpg.c call-gpg.h \
-       exectool.c exectool.h
+       exectool.c exectool.h \
+       server-help.c server-help.h \
+       private-keys.c private-keys.h
 
 if HAVE_W32_SYSTEM
 common_sources += w32-reg.c w32-afunix.c w32-afunix.h
@@ -153,7 +155,8 @@ endif
 module_tests = t-stringhelp t-timestuff \
                t-convert t-percent t-gettime t-sysutils t-sexputil \
               t-session-env t-openpgp-oid t-ssh-utils \
-              t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist
+              t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
+              t-private-keys
 if !HAVE_W32CE_SYSTEM
 module_tests += t-exechelp
 endif
@@ -202,6 +205,7 @@ t_zb32_LDADD = $(t_common_ldadd)
 t_mbox_util_LDADD = $(t_common_ldadd)
 t_iobuf_LDADD = $(t_common_ldadd)
 t_strlist_LDADD = $(t_common_ldadd)
+t_private_keys_LDADD = $(t_common_ldadd)
 
 # System specific test
 if HAVE_W32_SYSTEM
index a90224b..73799a8 100644 (file)
@@ -1,11 +1 @@
-Stuff used by several modules of GnuPG.
-
-These directories use it:
-
-gpg
-sm
-agent
-
-These directories don't use it:
-
-kbx
\ No newline at end of file
+Common functionality used by all modules of GnuPG.
index c69241d..00cde23 100644 (file)
@@ -26,7 +26,7 @@
  *
  * You should have received a copies of the GNU General Public License
  * and the GNU Lesser General Public License along with this program;
- * if not, see <http://www.gnu.org/licenses/>.
+ * if not, see <https://gnu.org/licenses/>.
  */
 
 /* This file may be used as part of GnuPG or standalone.  A GnuPG
@@ -1492,10 +1492,10 @@ strusage( int level )
     case 10:
 #if ARGPARSE_GPL_VERSION == 3
       p = ("License GPLv3+: GNU GPL version 3 or later "
-           "<http://gnu.org/licenses/gpl.html>");
+           "<https://gnu.org/licenses/gpl.html>");
 #else
       p = ("License GPLv2+: GNU GPL version 2 or later "
-           "<http://gnu.org/licenses/>");
+           "<https://gnu.org/licenses/>");
 #endif
       break;
     case 11: p = "foo"; break;
@@ -1517,7 +1517,7 @@ ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
 "GNU General Public License for more details.\n\n"
 "You should have received a copy of the GNU General Public License\n"
-"along with this software.  If not, see <http://www.gnu.org/licenses/>.\n";
+"along with this software.  If not, see <https://gnu.org/licenses/>.\n";
       break;
     case 40: /* short and long usage */
     case 41: p = ""; break;
index 5706dbe..6614eb7 100644 (file)
@@ -310,6 +310,15 @@ gnupg_create_outbound_pipe (int filedes[2])
 }
 
 
+/* Portable function to create a pipe.  Under Windows both ends are
+   inheritable.  */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+  return do_create_pipe (filedes);
+}
+
+
 
 static gpg_error_t
 create_pipe_and_estream (int filedes[2], estream_t *r_fp,
@@ -513,60 +522,94 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
 }
 
 
-/* See exechelp.h for the description.  */
+/* See exechelp.h for a description.  */
 gpg_error_t
 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
 {
-  gpg_err_code_t ec;
-  int i, status;
+  return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
+}
 
-  if (r_exitcode)
-    *r_exitcode = -1;
+/* See exechelp.h for a description.  */
+gpg_error_t
+gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+                      int hang, int *r_exitcodes)
+{
+  gpg_err_code_t ec = 0;
+  size_t i, left;
 
-  if (pid == (pid_t)(-1))
-    return gpg_error (GPG_ERR_INV_VALUE);
+  for (i = 0; i < count; i++)
+    {
+      if (r_exitcodes)
+        r_exitcodes[i] = -1;
+
+      if (pids[i] == (pid_t)(-1))
+        return gpg_error (GPG_ERR_INV_VALUE);
+    }
+
+  left = count;
+  while (left > 0)
+    {
+      pid_t pid;
+      int status;
 
 #ifdef USE_NPTH
-  i = npth_waitpid (pid, &status, hang? 0:WNOHANG);
+      pid = npth_waitpid (-1, &status, hang ? 0 : WNOHANG);
 #else
-  while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
-        && errno == EINTR);
+      while ((pid = waitpid (-1, &status, hang ? 0 : WNOHANG)) == (pid_t)(-1)
+             && errno == EINTR);
 #endif
 
-  if (i == (pid_t)(-1))
-    {
-      ec = gpg_err_code_from_errno (errno);
-      log_error (_("waiting for process %d to terminate failed: %s\n"),
-                 (int)pid, strerror (errno));
-    }
-  else if (!i)
-    {
-      ec = GPG_ERR_TIMEOUT; /* Still running.  */
-    }
-  else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
-    {
-      log_error (_("error running '%s': probably not installed\n"), pgmname);
-      ec = GPG_ERR_CONFIGURATION;
-    }
-  else if (WIFEXITED (status) && WEXITSTATUS (status))
-    {
-      if (!r_exitcode)
-        log_error (_("error running '%s': exit status %d\n"), pgmname,
-                   WEXITSTATUS (status));
+      if (pid == (pid_t)(-1))
+        {
+          ec = gpg_err_code_from_errno (errno);
+          log_error (_("waiting for processes to terminate failed: %s\n"),
+                     strerror (errno));
+          break;
+        }
+      else if (!pid)
+        {
+          ec = GPG_ERR_TIMEOUT; /* Still running.  */
+          break;
+        }
       else
-        *r_exitcode = WEXITSTATUS (status);
-      ec = GPG_ERR_GENERAL;
-    }
-  else if (!WIFEXITED (status))
-    {
-      log_error (_("error running '%s': terminated\n"), pgmname);
-      ec = GPG_ERR_GENERAL;
-    }
-  else
-    {
-      if (r_exitcode)
-        *r_exitcode = 0;
-      ec = 0;
+        {
+          for (i = 0; i < count; i++)
+            if (pid == pids[i])
+              break;
+
+          if (i == count)
+            /* No match, ignore this pid.  */
+            continue;
+
+          /* Process PIDS[i] died.  */
+          left -= 1;
+
+          if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
+            {
+              log_error (_("error running '%s': probably not installed\n"),
+                         pgmnames[i]);
+              ec = GPG_ERR_CONFIGURATION;
+            }
+          else if (WIFEXITED (status) && WEXITSTATUS (status))
+            {
+              if (!r_exitcodes)
+                log_error (_("error running '%s': exit status %d\n"),
+                           pgmnames[i], WEXITSTATUS (status));
+              else
+                r_exitcodes[i] = WEXITSTATUS (status);
+              ec = GPG_ERR_GENERAL;
+            }
+          else if (!WIFEXITED (status))
+            {
+              log_error (_("error running '%s': terminated\n"), pgmnames[i]);
+              ec = GPG_ERR_GENERAL;
+            }
+          else
+            {
+              if (r_exitcodes)
+                r_exitcodes[i] = 0;
+            }
+        }
     }
 
   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
index bc9b5b4..3e407d2 100644 (file)
@@ -65,7 +65,7 @@
 #include "exechelp.h"
 
 /* Define to 1 do enable debugging.  */
-#define DEBUG_W32_SPAWN 1
+#define DEBUG_W32_SPAWN 0
 
 
 /* It seems Vista doesn't grok X_OK and so fails access() tests.
@@ -233,45 +233,41 @@ build_w32_commandline (const char *pgmname, const char * const *argv,
 }
 
 
-/* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
-   the read end is inheritable, with 1 the write end is inheritable.  */
+#define INHERIT_READ   1
+#define INHERIT_WRITE  2
+#define INHERIT_BOTH   (INHERIT_READ|INHERIT_WRITE)
+
+/* Create pipe.  FLAGS indicates which ends are inheritable.  */
 static int
-create_inheritable_pipe (HANDLE filedes[2], int inherit_idx)
+create_inheritable_pipe (HANDLE filedes[2], int flags)
 {
-  HANDLE r, w, h;
+  HANDLE r, w;
   SECURITY_ATTRIBUTES sec_attr;
 
   memset (&sec_attr, 0, sizeof sec_attr );
   sec_attr.nLength = sizeof sec_attr;
-  sec_attr.bInheritHandle = FALSE;
+  sec_attr.bInheritHandle = TRUE;
 
   if (!CreatePipe (&r, &w, &sec_attr, 0))
     return -1;
 
-  if (!DuplicateHandle (GetCurrentProcess(), inherit_idx? w : r,
-                        GetCurrentProcess(), &h, 0,
-                        TRUE, DUPLICATE_SAME_ACCESS ))
-    {
-      log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
-      CloseHandle (r);
-      CloseHandle (w);
-      return -1;
-    }
+  if ((flags & INHERIT_READ) == 0)
+    if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0))
+      goto fail;
 
-  if (inherit_idx)
-    {
-      CloseHandle (w);
-      w = h;
-    }
-  else
-    {
-      CloseHandle (r);
-      r = h;
-    }
+  if ((flags & INHERIT_WRITE) == 0)
+    if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0))
+      goto fail;
 
   filedes[0] = r;
   filedes[1] = w;
   return 0;
+
+ fail:
+  log_error ("SetHandleInformation failed: %s\n", w32_strerror (-1));
+  CloseHandle (r);
+  CloseHandle (w);
+  return -1;
 }
 
 
@@ -291,16 +287,16 @@ w32_open_null (int for_write)
 
 
 static gpg_error_t
-do_create_pipe (int filedes[2], int inherit_idx)
+do_create_pipe (int filedes[2], int flags)
 {
   gpg_error_t err = 0;
   HANDLE fds[2];
 
   filedes[0] = filedes[1] = -1;
   err = gpg_error (GPG_ERR_GENERAL);
-  if (!create_inheritable_pipe (fds, inherit_idx))
+  if (!create_inheritable_pipe (fds, flags))
     {
-      filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), 0);
+      filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
       if (filedes[0] == -1)
         {
           log_error ("failed to translate osfhandle %p\n", fds[0]);
@@ -308,7 +304,7 @@ do_create_pipe (int filedes[2], int inherit_idx)
         }
       else
         {
-          filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), 1);
+          filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND);
           if (filedes[1] == -1)
             {
               log_error ("failed to translate osfhandle %p\n", fds[1]);
@@ -328,7 +324,7 @@ do_create_pipe (int filedes[2], int inherit_idx)
 gpg_error_t
 gnupg_create_inbound_pipe (int filedes[2])
 {
-  return do_create_pipe (filedes, 1);
+  return do_create_pipe (filedes, INHERIT_WRITE);
 }
 
 
@@ -337,7 +333,16 @@ gnupg_create_inbound_pipe (int filedes[2])
 gpg_error_t
 gnupg_create_outbound_pipe (int filedes[2])
 {
-  return do_create_pipe (filedes, 0);
+  return do_create_pipe (filedes, INHERIT_READ);
+}
+
+
+/* Portable function to create a pipe.  Under Windows both ends are
+   inheritable.  */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+  return do_create_pipe (filedes, INHERIT_BOTH);
 }
 
 
@@ -383,9 +388,9 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
     *r_errfp = NULL;
   *pid = (pid_t)(-1); /* Always required.  */
 
-  if (infp)
+  if (r_infp)
     {
-      if (create_inheritable_pipe (inpipe, 0))
+      if (create_inheritable_pipe (inpipe, INHERIT_READ))
         {
           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
@@ -409,7 +414,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
 
   if (r_outfp)
     {
-      if (create_inheritable_pipe (outpipe, 1))
+      if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
         {
           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
@@ -430,7 +435,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
           if (infp)
             es_fclose (infp);
           else if (inpipe[1] != INVALID_HANDLE_VALUE)
-            CloseHandle (outpipe[1]);
+            CloseHandle (inpipe[1]);
           if (inpipe[0] != INVALID_HANDLE_VALUE)
             CloseHandle (inpipe[0]);
           return err;
@@ -439,7 +444,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
 
   if (r_errfp)
     {
-      if (create_inheritable_pipe (errpipe, 1))
+      if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
         {
           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
@@ -466,7 +471,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
           if (infp)
             es_fclose (infp);
           else if (inpipe[1] != INVALID_HANDLE_VALUE)
-            CloseHandle (outpipe[1]);
+            CloseHandle (inpipe[1]);
           if (inpipe[0] != INVALID_HANDLE_VALUE)
             CloseHandle (inpipe[0]);
           return err;
@@ -483,12 +488,12 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
   if (err)
     return err;
 
-  if (inpipe[0] != INVALID_HANDLE_VALUE)
+  if (inpipe[0] == INVALID_HANDLE_VALUE)
     nullhd[0] = w32_open_null (0);
-  if (outpipe[1] != INVALID_HANDLE_VALUE)
-    nullhd[1] = w32_open_null (0);
-  if (errpipe[1] != INVALID_HANDLE_VALUE)
-    nullhd[2] = w32_open_null (0);
+  if (outpipe[1] == INVALID_HANDLE_VALUE)
+    nullhd[1] = w32_open_null (1);
+  if (errpipe[1] == INVALID_HANDLE_VALUE)
+    nullhd[2] = w32_open_null (1);
 
   /* Start the process.  Note that we can't run the PREEXEC function
      because this might change our own environment. */
@@ -677,63 +682,86 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
 gpg_error_t
 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
 {
-  gpg_err_code_t ec;
-  HANDLE proc = fd_to_handle (pid);
+  return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
+}
+
+/* See exechelp.h for a description.  */
+gpg_error_t
+gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+                      int hang, int *r_exitcodes)
+{
+  gpg_err_code_t ec = 0;
+  size_t i;
+  HANDLE *procs;
   int code;
-  DWORD exc;
 
-  if (r_exitcode)
-    *r_exitcode = -1;
+  procs = xtrycalloc (count, sizeof *procs);
+  if (procs == NULL)
+    return gpg_error_from_syserror ();
+
+  for (i = 0; i < count; i++)
+    {
+      if (r_exitcodes)
+        r_exitcodes[i] = -1;
+
+      if (pids[i] == (pid_t)(-1))
+        return gpg_error (GPG_ERR_INV_VALUE);
 
-  if (pid == (pid_t)(-1))
-    return gpg_error (GPG_ERR_INV_VALUE);
+      procs[i] = fd_to_handle (pids[i]);
+    }
 
   /* FIXME: We should do a pth_waitpid here.  However this has not yet
      been implemented.  A special W32 pth system call would even be
      better.  */
-  code = WaitForSingleObject (proc, hang? INFINITE : 0);
+  code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
   switch (code)
     {
     case WAIT_TIMEOUT:
       ec = GPG_ERR_TIMEOUT;
-      break;
+      goto leave;
 
     case WAIT_FAILED:
-      log_error (_("waiting for process %d to terminate failed: %s\n"),
-                 (int)pid, w32_strerror (-1));
+      log_error (_("waiting for processes to terminate failed: %s\n"),
+                 w32_strerror (-1));
       ec = GPG_ERR_GENERAL;
-      break;
+      goto leave;
 
     case WAIT_OBJECT_0:
-      if (!GetExitCodeProcess (proc, &exc))
-        {
-          log_error (_("error getting exit code of process %d: %s\n"),
-                     (int)pid, w32_strerror (-1) );
-          ec = GPG_ERR_GENERAL;
-        }
-      else if (exc)
+      for (i = 0; i < count; i++)
         {
-          log_error (_("error running '%s': exit status %d\n"),
-                     pgmname, (int)exc );
-          if (r_exitcode)
-            *r_exitcode = (int)exc;
-          ec = GPG_ERR_GENERAL;
-        }
-      else
-        {
-          if (r_exitcode)
-            *r_exitcode = 0;
-          ec = 0;
+          DWORD exc;
+
+          if (! GetExitCodeProcess (procs[i], &exc))
+            {
+              log_error (_("error getting exit code of process %d: %s\n"),
+                         (int) pids[i], w32_strerror (-1) );
+              ec = GPG_ERR_GENERAL;
+            }
+          else if (exc)
+            {
+              if (!r_exitcodes)
+                log_error (_("error running '%s': exit status %d\n"),
+                           pgmnames[i], (int)exc);
+              else
+                r_exitcodes[i] = (int)exc;
+              ec = GPG_ERR_GENERAL;
+            }
+          else
+            {
+              if (r_exitcodes)
+                r_exitcodes[i] = 0;
+            }
         }
       break;
 
     default:
-      log_error ("WaitForSingleObject returned unexpected "
-                 "code %d for pid %d\n", code, (int)pid );
+      log_error ("WaitForMultipleObjects returned unexpected "
+                 "code %d\n", code);
       ec = GPG_ERR_GENERAL;
       break;
     }
 
+ leave:
   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
 }
 
@@ -829,6 +857,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
 
   CloseHandle (pi.hThread);
+  CloseHandle (pi.hProcess);
 
   return 0;
 }
index 49ccdbb..e208f6e 100644 (file)
@@ -465,6 +465,15 @@ gnupg_create_outbound_pipe (int filedes[2])
 }
 
 
+/* Portable function to create a pipe.  Under Windows both ends are
+   inheritable.  */
+gpg_error_t
+gnupg_create_pipe (int filedes[2])
+{
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+
+
 static int
 create_process (const char *pgmname, const char *cmdline,
                 PROCESS_INFORMATION *pi)
@@ -787,6 +796,15 @@ gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *exitcode)
 }
 
 
+/* See exechelp.h for a description.  */
+gpg_error_t
+gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
+                      int hang, int *r_exitcodes)
+{
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+}
+
+
 void
 gnupg_release_process (pid_t pid)
 {
index 9088342..82224fd 100644 (file)
@@ -59,6 +59,11 @@ gpg_error_t gnupg_create_inbound_pipe (int filedes[2]);
    inheritable.  */
 gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
 
+/* Portable function to create a pipe.  Under Windows both ends are
+   inheritable.  */
+gpg_error_t gnupg_create_pipe (int filedes[2]);
+
+
 #define GNUPG_SPAWN_NONBLOCK   16
 #define GNUPG_SPAWN_RUN_ASFW   64
 #define GNUPG_SPAWN_DETACHED  128
@@ -156,6 +161,10 @@ gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
 gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
                                 int *r_exitcode);
 
+/* Like gnupg_wait_process, but for COUNT processes.  */
+gpg_error_t gnupg_wait_processes (const char **pgmnames, pid_t *pids,
+                                 size_t count, int hang, int *r_exitcodes);
+
 
 /* Kill a process; that is send an appropriate signal to the process.
    gnupg_wait_process must be called to actually remove the process
index 766ee94..7b3a8f1 100644 (file)
@@ -417,24 +417,33 @@ gnupg_exec_tool (const char *pgmname, const char *argv[],
   if (err)
     goto leave;
 
-  *result = xtrymalloc (len);
-  if (*result == NULL)
+  *result = xtrymalloc (len + 1);
+  if (!*result)
     {
       err = my_error_from_syserror ();
       goto leave;
     }
 
-  err = es_read (output, *result, len, &nread);
-  if (! err)
+  if (len)
     {
-      assert (nread == len || !"short read on memstream");
-      if (resultlen)
-        *resultlen = len;
+      err = es_read (output, *result, len, &nread);
+      if (err)
+        goto leave;
+      if (nread != len)
+        log_fatal ("%s: short read from memstream\n", __func__);
     }
+  (*result)[len] = 0;
+
+  if (resultlen)
+    *resultlen = len;
 
  leave:
-  if (input)
-    es_fclose (input);
+  es_fclose (input);
   es_fclose (output);
+  if (err)
+    {
+      xfree (*result);
+      *result = NULL;
+    }
   return err;
 }
index 3918693..5bf5173 100644 (file)
@@ -256,9 +256,7 @@ check_portable_app (const char *dir)
   char *fname;
 
   fname = xstrconcat (dir, DIRSEP_S "gpgconf.exe", NULL);
-  if (access (fname, F_OK))
-    log_error ("required binary '%s' is not installed\n", fname);
-  else
+  if (!access (fname, F_OK))
     {
       strcpy (fname + strlen (fname) - 3, "ctl");
       if (!access (fname, F_OK))
@@ -731,7 +729,11 @@ gnupg_module_name (int which)
       X(bindir, "gpgsm");
 
     case GNUPG_MODULE_NAME_GPG:
-      X(bindir, NAME_OF_INSTALLED_GPG);
+#if USE_GPG2_HACK
+      X(bindir, GPG_NAME "2");
+#else
+      X(bindir, GPG_NAME);
+#endif
 
     case GNUPG_MODULE_NAME_CONNECT_AGENT:
       X(bindir, "gpg-connect-agent");
index b6e7885..c8ec00f 100644 (file)
@@ -1515,11 +1515,11 @@ iobuf_ioctl (iobuf_t a, iobuf_ioctl_t cmd, int intval, void *ptrval)
         log_debug ("iobuf-*.*: ioctl '%s' fsync\n",
                    ptrval? (const char*)ptrval:"<null>");
 
-       if (!a && !intval && ptrval)
-         {
-           return fd_cache_synchronize (ptrval);
-         }
-      }
+      if (!a && !intval && ptrval)
+        {
+          return fd_cache_synchronize (ptrval);
+        }
+    }
 
 
   return -1;
@@ -1683,10 +1683,10 @@ iobuf_push_filter2 (iobuf_t a,
 /****************
  * Remove an i/o filter.
  */
-static int
-pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
-                              iobuf_t chain, byte * buf, size_t * len),
-           void *ov)
+int
+iobuf_pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
+                                       iobuf_t chain, byte * buf, size_t * len),
+                  void *ov)
 {
   iobuf_t b;
   size_t dummy_len = 0;
@@ -1716,12 +1716,13 @@ pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
     if (b->filter == f && (!ov || b->filter_ov == ov))
       break;
   if (!b)
-    log_bug ("pop_filter(): filter function not found\n");
+    log_bug ("iobuf_pop_filter(): filter function not found\n");
 
   /* flush this stream if it is an output stream */
   if (a->use == IOBUF_OUTPUT && (rc = filter_flush (b)))
     {
-      log_error ("filter_flush failed in pop_filter: %s\n", gpg_strerror (rc));
+      log_error ("filter_flush failed in iobuf_pop_filter: %s\n",
+                 gpg_strerror (rc));
       return rc;
     }
   /* and tell the filter to free it self */
@@ -2227,8 +2228,8 @@ size_t
 iobuf_copy (iobuf_t dest, iobuf_t source)
 {
   char *temp;
-  /* Use a 1 MB buffer.  */
-  const size_t temp_size = 1024 * 1024;
+  /* Use a 32 KB buffer.  */
+  const size_t temp_size = 32 * 1024;
 
   size_t nread;
   size_t nwrote = 0;
@@ -2237,6 +2238,9 @@ iobuf_copy (iobuf_t dest, iobuf_t source)
   assert (source->use == IOBUF_INPUT || source->use == IOBUF_INPUT_TEMP);
   assert (dest->use == IOBUF_OUTPUT || source->use == IOBUF_OUTPUT_TEMP);
 
+  if (iobuf_error (dest))
+    return -1;
+
   temp = xmalloc (temp_size);
   while (1)
     {
@@ -2250,6 +2254,9 @@ iobuf_copy (iobuf_t dest, iobuf_t source)
         break;
       nwrote += nread;
     }
+
+  /* Burn the buffer.  */
+  wipememory (temp, sizeof (temp));
   xfree (temp);
 
   return nwrote;
@@ -2260,9 +2267,9 @@ void
 iobuf_flush_temp (iobuf_t temp)
 {
   if (temp->use == IOBUF_INPUT || temp->use == IOBUF_INPUT_TEMP)
-    log_bug ("iobuf_writestr called on an input pipeline!\n");
+    log_bug ("iobuf_flush_temp called on an input pipeline!\n");
   while (temp->chain)
-    pop_filter (temp, temp->filter, NULL);
+    iobuf_pop_filter (temp, temp->filter, NULL);
 }
 
 
@@ -2461,9 +2468,9 @@ iobuf_seek (iobuf_t a, off_t newpos)
 
   /* remove filters, but the last */
   if (a->chain)
-    log_debug ("pop_filter called in iobuf_seek - please report\n");
+    log_debug ("iobuf_pop_filter called in iobuf_seek - please report\n");
   while (a->chain)
-    pop_filter (a, a->filter, NULL);
+    iobuf_pop_filter (a, a->filter, NULL);
 
   return 0;
 }
@@ -2509,31 +2516,35 @@ iobuf_get_fname_nonnull (iobuf_t a)
 
 
 /****************
- * enable partial block mode as described in the OpenPGP draft.
- * LEN is the first length byte on read, but ignored on writes.
+ * Enable or disable partial body length mode (RFC 4880 4.2.2.4).
+ *
+ * If LEN is 0, this disables partial block mode by popping the
+ * partial body length filter, which which must be the most recently
+ * added filter.
+ *
+ * If LEN is non-zero, it pushes a partial body length filter.  If
+ * this is a read filter, LEN must be the length byte from the first
+ * chunk and A should be position just after this first partial body
+ * length header.
  */
 void
-iobuf_set_partial_block_mode (iobuf_t a, size_t len)
+iobuf_set_partial_body_length_mode (iobuf_t a, size_t len)
 {
   block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx);
 
   ctx->use = a->use;
   if (!len)
+    /* Disable partial body length mode.  */
     {
       if (a->use == IOBUF_INPUT)
-       log_debug ("pop_filter called in set_partial_block_mode"
+       log_debug ("iobuf_pop_filter called in set_partial_block_mode"
                   " - please report\n");
-      /* XXX: This pop_filter doesn't make sense.  Since we haven't
-        actually added the filter to the pipeline yet, why are we
-        popping anything?  Moreover, since we don't report an error,
-        the caller won't directly see an error.  I think that it
-        would be better to push the filter and set a->error to
-        GPG_ERR_BAD_DATA, but Werner thinks it's impossible for len
-        to be 0 (but he doesn't want to remove the check just in
-        case).  */
-      pop_filter (a, block_filter, NULL);
+
+      log_assert (a->filter == block_filter);
+      iobuf_pop_filter (a, block_filter, NULL);
     }
   else
+    /* Enabled partial body length mode.  */
     {
       ctx->partial = 1;
       ctx->size = 0;
index 8ba02b3..a8ca4dc 100644 (file)
@@ -421,6 +421,13 @@ int iobuf_push_filter2 (iobuf_t a,
                                  byte * buf, size_t * len), void *ov,
                        int rel_ov);
 
+/* Pop the top filter.  The top filter must have the filter function F
+   and the cookie OV.  The cookie check is ignored if OV is NULL.  */
+int iobuf_pop_filter (iobuf_t a,
+                      int (*f) (void *opaque, int control,
+                                iobuf_t chain, byte * buf, size_t * len),
+                      void *ov);
+
 /* Used for debugging.  Prints out the chain using log_debug if
    IOBUF_DEBUG_MODE is not 0.  */
 int iobuf_print_chain (iobuf_t a);
@@ -592,7 +599,7 @@ const char *iobuf_get_fname_nonnull (iobuf_t a);
    length headers (see Section 4.2.2.4 of RFC 4880).  Concretely, it
    just returns / writes the data and finishes the packet with an
    EOF.  */
-void iobuf_set_partial_block_mode (iobuf_t a, size_t len);
+void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len);
 
 /* If PARTIAL is set, then read from the pipeline until the first EOF
    is returned.
index b7f1419..9175b4f 100644 (file)
@@ -715,7 +715,21 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
   if (fmt)
     {
       if (ignore_arg_ptr)
-        es_fputs_unlocked (fmt, logstream);
+        { /* This is used by log_string and comes with the extra
+           * feature that after a LF the next line is indent at the
+           * length of the prefix.  Note that we do not yet include
+           * the length of the timestamp and pid in the indent
+           * computation.  */
+          const char *p, *pend;
+
+          for (p = fmt; (pend = strchr (p, '\n')); p = pend+1)
+            es_fprintf_unlocked (logstream, "%*s%.*s",
+                                 (int)((p != fmt
+                                        && (with_prefix || force_prefixes))
+                                       ?strlen (prefix_buffer)+2:0), "",
+                                 (int)(pend - p)+1, p);
+          es_fputs_unlocked (p, logstream);
+        }
       else
         es_vfprintf_unlocked (logstream, fmt, arg_ptr);
       if (*fmt && fmt[strlen(fmt)-1] != '\n')
@@ -769,12 +783,13 @@ do_log_ignore_arg (int level, const char *str, ...)
 }
 
 
+/* Log STRING at LEVEL but indent from the second line on by the
+ * length of the prefix.  */
 void
 log_string (int level, const char *string)
 {
   /* We need a dummy arg_ptr, but there is no portable way to create
-     one.  So we call the do_logv function through a variadic wrapper.
-     MB: Why not just use "%s"?  */
+   * one.  So we call the do_logv function through a variadic wrapper. */
   do_log_ignore_arg (level, string);
 }
 
@@ -919,18 +934,37 @@ log_clock (const char *string)
 }
 
 
-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
+#ifdef GPGRT_HAVE_MACRO_FUNCTION
 void
 bug_at( const char *file, int line, const char *func )
 {
-  log_log (GPGRT_LOG_BUG, ("... this is a bug (%s:%d:%s)\n"), file, line, func);
+  log_log (GPGRT_LOG_BUG, "... this is a bug (%s:%d:%s)\n", file, line, func);
   abort (); /* Never called; just to make the compiler happy.  */
 }
-#else
+#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
 void
 bug_at( const char *file, int line )
 {
-  log_log (GPGRT_LOG_BUG, _("you found a bug ... (%s:%d)\n"), file, line);
+  log_log (GPGRT_LOG_BUG, "you found a bug ... (%s:%d)\n", file, line);
   abort (); /* Never called; just to make the compiler happy.  */
 }
-#endif
+#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
+
+
+#ifdef GPGRT_HAVE_MACRO_FUNCTION
+void
+_log_assert (const char *expr, const char *file, int line, const char *func)
+{
+  log_log (GPGRT_LOG_BUG, "Assertion \"%s\" in %s failed (%s:%d)\n",
+           expr, func, file, line);
+  abort (); /* Never called; just to make the compiler happy.  */
+}
+#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
+void
+_log_assert (const char *expr, const char *file, int line)
+{
+  log_log (GPGRT_LOG_BUG, "Assertion \"%s\" failed (%s:%d)\n",
+           file, line, func);
+  abort (); /* Never called; just to make the compiler happy.  */
+}
+#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
index c4ae5d0..2f0b504 100644 (file)
@@ -52,11 +52,22 @@ estream_t log_get_stream (void);
 #ifdef GPGRT_HAVE_MACRO_FUNCTION
   void bug_at (const char *file, int line, const char *func)
                GPGRT_ATTR_NORETURN;
-# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__ )
-#else
-  void bug_at( const char *file, int line );
+  void _log_assert (const char *expr, const char *file, int line,
+                    const char *func) GPGRT_ATTR_NORETURN;
+# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__)
+# define log_assert(expr)    do {                               \
+    if (!(expr))                                                \
+      _log_assert (#expr, __FILE__, __LINE__, __FUNCTION__);    \
+  } while (0)
+#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
+  void bug_at (const char *file, int line);
+  void _log_assert (const char *expr, const char *file, int line;
 # define BUG() bug_at( __FILE__ , __LINE__ )
-#endif
+# define log_assert(expr)    do {                               \
+    if (!(expr))                                                \
+      _log_assert (#expr, __FILE__, __LINE__);                  \
+  } while (0)
+#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
 
 /* Flag values for log_set_prefix. */
 #define GPGRT_LOG_WITH_PREFIX  1
@@ -79,8 +90,6 @@ enum jnlib_log_levels {
 void log_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3);
 void log_logv (int level, const char *fmt, va_list arg_ptr);
 void log_string (int level, const char *string);
-
-
 void log_bug (const char *fmt, ...)    GPGRT_ATTR_NR_PRINTF(1,2);
 void log_fatal (const char *fmt, ...)  GPGRT_ATTR_NR_PRINTF(1,2);
 void log_error (const char *fmt, ...)  GPGRT_ATTR_PRINTF(1,2);
index ec36f08..8d9a7aa 100644 (file)
@@ -106,6 +106,17 @@ setup_libgcrypt_logging (void)
 }
 
 
+/* Print an out of core message and let the process die.  The printed
+ * error is taken from ERRNO.  */
+void
+xoutofcore (void)
+{
+  gpg_error_t err = gpg_error_from_syserror ();
+  log_fatal (_("error allocating enough memory: %s\n"), gpg_strerror (err));
+  abort (); /* Never called; just to make the compiler happy.  */
+}
+
+
 /* A wrapper around gcry_cipher_algo_name to return the string
    "AES-128" instead of "AES".  Given that we have an alias in
    libgcrypt for it, it does not harm to too much to return this other
index c81109a..e200d6b 100644 (file)
@@ -56,6 +56,34 @@ typedef enum
   }
 pkttype_t;
 
+static inline const char *
+pkttype_str (pkttype_t type)
+{
+  switch (type)
+    {
+    case PKT_PUBKEY_ENC: return "PUBKEY_ENC";
+    case PKT_SIGNATURE: return "SIGNATURE";
+    case PKT_SYMKEY_ENC: return "SYMKEY_ENC";
+    case PKT_ONEPASS_SIG: return "ONEPASS_SIG";
+    case PKT_SECRET_KEY: return "SECRET_KEY";
+    case PKT_PUBLIC_KEY: return "PUBLIC_KEY";
+    case PKT_SECRET_SUBKEY: return "SECRET_SUBKEY";
+    case PKT_COMPRESSED: return "COMPRESSED";
+    case PKT_ENCRYPTED: return "ENCRYPTED";
+    case PKT_MARKER: return "MARKER";
+    case PKT_PLAINTEXT: return "PLAINTEXT";
+    case PKT_RING_TRUST: return "RING_TRUST";
+    case PKT_USER_ID: return "USER_ID";
+    case PKT_PUBLIC_SUBKEY: return "PUBLIC_SUBKEY";
+    case PKT_OLD_COMMENT: return "OLD_COMMENT";
+    case PKT_ATTRIBUTE: return "ATTRIBUTE";
+    case PKT_ENCRYPTED_MDC: return "ENCRYPTED_MDC";
+    case PKT_MDC: return "MDC";
+    case PKT_COMMENT: return "COMMENT";
+    case PKT_GPG_CONTROL: return "GPG_CONTROL";
+    default: return "unknown packet type";
+    }
+}
 
 typedef enum
   {
diff --git a/common/private-keys.c b/common/private-keys.c
new file mode 100644 (file)
index 0000000..4cf7d22
--- /dev/null
@@ -0,0 +1,750 @@
+/* private-keys.c - Parser and writer for the extended private key format.
+ *     Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <assert.h>
+#include <gcrypt.h>
+#include <gpg-error.h>
+#include <string.h>
+
+#include "private-keys.h"
+#include "mischelp.h"
+#include "strlist.h"
+#include "util.h"
+
+struct private_key_container
+{
+  struct private_key_entry *first;
+  struct private_key_entry *last;
+};
+
+
+struct private_key_entry
+{
+  struct private_key_entry *prev;
+  struct private_key_entry *next;
+
+  /* The name.  Comments and blank lines have NAME set to NULL.  */
+  char *name;
+
+  /* The value as stored in the file.  We store it when when we parse
+     a file so that we can reproduce it.  */
+  strlist_t raw_value;
+
+  /* The decoded value.  */
+  char *value;
+};
+
+
+/* Helper */
+static inline gpg_error_t
+my_error_from_syserror (void)
+{
+  return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
+}
+
+
+\f
+
+/* Allocation and deallocation.  */
+
+/* Allocate a private key container structure.  */
+pkc_t
+pkc_new (void)
+{
+  return xtrycalloc (1, sizeof (struct private_key_container));
+}
+
+
+static void
+pke_release (pke_t entry)
+{
+  if (entry == NULL)
+    return;
+
+  xfree (entry->name);
+  if (entry->value)
+    wipememory (entry->value, strlen (entry->value));
+  xfree (entry->value);
+  free_strlist_wipe (entry->raw_value);
+  xfree (entry);
+}
+
+
+/* Release a private key container structure.  */
+void
+pkc_release (pkc_t pk)
+{
+  pke_t e, next;
+
+  if (pk == NULL)
+    return;
+
+  for (e = pk->first; e; e = next)
+    {
+      next = e->next;
+      pke_release (e);
+    }
+
+  xfree (pk);
+}
+
+\f
+
+/* Dealing with names and values.  */
+
+/* Check whether the given name is valid.  Valid names start with a
+   letter, end with a colon, and contain only alphanumeric characters
+   and the hyphen.  */
+static int
+valid_name (const char *name)
+{
+  size_t i, len = strlen (name);
+
+  if (! alphap (name) || len == 0 || name[len - 1] != ':')
+    return 0;
+
+  for (i = 1; i < len - 1; i++)
+    if (! alnump (&name[i]) && name[i] != '-')
+      return 0;
+
+  return 1;
+}
+
+
+/* Makes sure that ENTRY has a RAW_VALUE.  */
+static gpg_error_t
+assert_raw_value (pke_t entry)
+{
+  gpg_error_t err = 0;
+  size_t len, offset;
+#define LINELEN        70
+  char buf[LINELEN+3];
+
+  if (entry->raw_value)
+    return 0;
+
+  len = strlen (entry->value);
+  offset = 0;
+  while (len)
+    {
+      size_t amount, linelen = LINELEN;
+
+      /* On the first line we need to subtract space for the name.  */
+      if (entry->raw_value == NULL && strlen (entry->name) < linelen)
+       linelen -= strlen (entry->name);
+
+      /* See if the rest of the value fits in this line.  */
+      if (len <= linelen)
+       amount = len;
+      else
+       {
+         size_t i;
+
+         /* Find a suitable space to break on.  */
+         for (i = linelen - 1; linelen - i < 30 && linelen - i > offset; i--)
+           if (ascii_isspace (entry->value[i]))
+             break;
+
+         if (ascii_isspace (entry->value[i]))
+           {
+             /* Found one.  */
+             amount = i;
+           }
+         else
+           {
+             /* Just induce a hard break.  */
+             amount = linelen;
+           }
+       }
+
+      snprintf (buf, sizeof buf, " %.*s\n", (int) amount,
+               &entry->value[offset]);
+      if (append_to_strlist_try (&entry->raw_value, buf) == NULL)
+       {
+         err = my_error_from_syserror ();
+         goto leave;
+       }
+
+      offset += amount;
+      len -= amount;
+    }
+
+ leave:
+  if (err)
+    {
+      free_strlist_wipe (entry->raw_value);
+      entry->raw_value = NULL;
+    }
+
+  return err;
+#undef LINELEN
+}
+
+
+/* Computes the length of the value encoded as continuation.  If
+   *SWALLOW_WS is set, all whitespace at the beginning of S is
+   swallowed.  If START is given, a pointer to the beginning of the
+   value is stored there.  */
+static size_t
+continuation_length (const char *s, int *swallow_ws, const char **start)
+{
+  size_t len;
+
+  if (*swallow_ws)
+    {
+      /* The previous line was a blank line and we inserted a newline.
+        Swallow all whitespace at the beginning of this line.  */
+      while (ascii_isspace (*s))
+       s++;
+    }
+  else
+    {
+      /* Iff a continuation starts with more than one space, it
+        encodes a space.  */
+      if (ascii_isspace (*s))
+       s++;
+    }
+
+  /* Strip whitespace at the end.  */
+  len = strlen (s);
+  while (len > 0 && ascii_isspace (s[len-1]))
+    len--;
+
+  if (len == 0)
+    {
+      /* Blank lines encode newlines.  */
+      len = 1;
+      s = "\n";
+      *swallow_ws = 1;
+    }
+  else
+    *swallow_ws = 0;
+
+  if (start)
+    *start = s;
+
+  return len;
+}
+
+
+/* Makes sure that ENTRY has a VALUE.  */
+static gpg_error_t
+assert_value (pke_t entry)
+{
+  size_t len;
+  int swallow_ws;
+  strlist_t s;
+  char *p;
+
+  if (entry->value)
+    return 0;
+
+  len = 0;
+  swallow_ws = 0;
+  for (s = entry->raw_value; s; s = s->next)
+    len += continuation_length (s->d, &swallow_ws, NULL);
+
+  /* Add one for the terminating zero.  */
+  len += 1;
+
+  entry->value = p = xtrymalloc (len);
+  if (entry->value == NULL)
+    return my_error_from_syserror ();
+
+  swallow_ws = 0;
+  for (s = entry->raw_value; s; s = s->next)
+    {
+      const char *start;
+      size_t l = continuation_length (s->d, &swallow_ws, &start);
+
+      memcpy (p, start, l);
+      p += l;
+    }
+
+  *p++ = 0;
+  assert (p - entry->value == len);
+
+  return 0;
+}
+
+
+/* Get the name.  */
+char *
+pke_name (pke_t pke)
+{
+  return pke->name;
+}
+
+
+/* Get the value.  */
+char *
+pke_value (pke_t pke)
+{
+  if (assert_value (pke))
+    return NULL;
+  return pke->value;
+}
+
+\f
+
+/* Adding and modifying values.  */
+
+/* Add (NAME, VALUE, RAW_VALUE) to PK.  NAME may be NULL for comments
+   and blank lines.  At least one of VALUE and RAW_VALUE must be
+   given.  If PRESERVE_ORDER is not given, entries with the same name
+   are grouped.  NAME, VALUE and RAW_VALUE is consumed.  */
+static gpg_error_t
+_pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value,
+         int preserve_order)
+{
+  gpg_error_t err = 0;
+  pke_t e;
+
+  assert (value || raw_value);
+
+  if (name && ! valid_name (name))
+    {
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+
+  if (name && ascii_strcasecmp (name, "Key:") == 0 && pkc_lookup (pk, "Key:"))
+    {
+      err = gpg_error (GPG_ERR_INV_NAME);
+      goto leave;
+    }
+
+  e = xtrycalloc (1, sizeof *e);
+  if (e == NULL)
+    {
+      err = my_error_from_syserror ();
+      goto leave;
+    }
+
+  e->name = name;
+  e->value = value;
+  e->raw_value = raw_value;
+
+  if (pk->first)
+    {
+      pke_t last;
+
+      if (preserve_order || name == NULL)
+       last = pk->last;
+      else
+       {
+         /* See if there is already an entry with NAME.  */
+         last = pkc_lookup (pk, name);
+
+         /* If so, find the last in that block.  */
+         if (last)
+            {
+              while (last->next)
+                {
+                  pke_t next = last->next;
+
+                  if (next->name && ascii_strcasecmp (next->name, name) == 0)
+                    last = next;
+                  else
+                    break;
+                }
+            }
+         else /* Otherwise, just find the last entry.  */
+           last = pk->last;
+       }
+
+      if (last->next)
+       {
+         e->prev = last;
+         e->next = last->next;
+         last->next = e;
+         e->next->prev = e;
+       }
+      else
+       {
+         e->prev = last;
+         last->next = e;
+         pk->last = e;
+       }
+    }
+  else
+    pk->first = pk->last = e;
+
+ leave:
+  if (err)
+    {
+      xfree (name);
+      if (value)
+       wipememory (value, strlen (value));
+      xfree (value);
+      free_strlist_wipe (raw_value);
+    }
+
+  return err;
+}
+
+
+/* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
+   is not updated but the new entry is appended.  */
+gpg_error_t
+pkc_add (pkc_t pk, const char *name, const char *value)
+{
+  char *k, *v;
+
+  k = xtrystrdup (name);
+  if (k == NULL)
+    return my_error_from_syserror ();
+
+  v = xtrystrdup (value);
+  if (v == NULL)
+    {
+      xfree (k);
+      return my_error_from_syserror ();
+    }
+
+  return _pkc_add (pk, k, v, NULL, 0);
+}
+
+
+/* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
+   is updated with VALUE.  If multiple entries with NAME exist, the
+   first entry is updated.  */
+gpg_error_t
+pkc_set (pkc_t pk, const char *name, const char *value)
+{
+  pke_t e;
+
+  if (! valid_name (name))
+    return GPG_ERR_INV_NAME;
+
+  e = pkc_lookup (pk, name);
+  if (e)
+    {
+      char *v;
+
+      v = xtrystrdup (value);
+      if (v == NULL)
+       return my_error_from_syserror ();
+
+      free_strlist_wipe (e->raw_value);
+      e->raw_value = NULL;
+      if (e->value)
+       wipememory (e->value, strlen (e->value));
+      xfree (e->value);
+      e->value = v;
+
+      return 0;
+    }
+  else
+    return pkc_add (pk, name, value);
+}
+
+
+/* Delete the given entry from PK.  */
+void
+pkc_delete (pkc_t pk, pke_t entry)
+{
+  if (entry->prev)
+    entry->prev->next = entry->next;
+  else
+    pk->first = entry->next;
+
+  if (entry->next)
+    entry->next->prev = entry->prev;
+  else
+    pk->last = entry->prev;
+
+  pke_release (entry);
+}
+
+\f
+
+/* Lookup and iteration.  */
+
+/* Get the first non-comment entry.  */
+pke_t
+pkc_first (pkc_t pk)
+{
+  pke_t entry;
+  for (entry = pk->first; entry; entry = entry->next)
+    if (entry->name)
+      return entry;
+  return NULL;
+}
+
+
+/* Get the first entry with the given name.  */
+pke_t
+pkc_lookup (pkc_t pk, const char *name)
+{
+  pke_t entry;
+  for (entry = pk->first; entry; entry = entry->next)
+    if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
+      return entry;
+  return NULL;
+}
+
+
+/* Get the next non-comment entry.  */
+pke_t
+pke_next (pke_t entry)
+{
+  for (entry = entry->next; entry; entry = entry->next)
+    if (entry->name)
+      return entry;
+  return NULL;
+}
+
+
+/* Get the next entry with the given name.  */
+pke_t
+pke_next_value (pke_t entry, const char *name)
+{
+  for (entry = entry->next; entry; entry = entry->next)
+    if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
+      return entry;
+  return NULL;
+}
+
+\f
+
+/* Private key handling.  */
+
+/* Get the private key.  */
+gpg_error_t
+pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp)
+{
+  gpg_error_t err;
+  pke_t e;
+
+  e = pkc_lookup (pk, "Key:");
+  if (e == NULL)
+    return gpg_error (GPG_ERR_MISSING_KEY);
+
+  err = assert_value (e);
+  if (err)
+    return err;
+
+  return gcry_sexp_sscan (retsexp, NULL, e->value, strlen (e->value));
+}
+
+
+/* Set the private key.  */
+gpg_error_t
+pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp)
+{
+  gpg_error_t err;
+  char *raw, *clean, *p;
+  size_t len, i;
+
+  len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
+
+  raw = xtrymalloc (len);
+  if (raw == NULL)
+    return my_error_from_syserror ();
+
+  clean = xtrymalloc (len);
+  if (clean == NULL)
+    {
+      xfree (raw);
+      return my_error_from_syserror ();
+    }
+
+  gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, raw, len);
+
+  /* Strip any whitespace at the end.  */
+  i = strlen (raw) - 1;
+  while (i && ascii_isspace (raw[i]))
+    {
+      raw[i] = 0;
+      i--;
+    }
+
+  /* Replace any newlines with spaces, remove superfluous whitespace.  */
+  len = strlen (raw);
+  for (p = clean, i = 0; i < len; i++)
+    {
+      char c = raw[i];
+
+      /* Collapse contiguous and superfluous spaces.  */
+      if (ascii_isspace (c) && i > 0
+         && (ascii_isspace (raw[i-1]) || raw[i-1] == '(' || raw[i-1] == ')'))
+       continue;
+
+      if (c == '\n')
+       c = ' ';
+
+      *p++ = c;
+    }
+  *p = 0;
+
+  err = pkc_set (pk, "Key:", clean);
+  xfree (raw);
+  xfree (clean);
+  return err;
+}
+
+\f
+
+/* Parsing and serialization.  */
+
+/* Parse STREAM and return a newly allocated private key container
+   structure in RESULT.  If ERRLINEP is given, the line number the
+   parser was last considering is stored there.  */
+gpg_error_t
+pkc_parse (pkc_t *result, int *errlinep, estream_t stream)
+{
+  gpg_error_t err = 0;
+  gpgrt_ssize_t len;
+  char *buf = NULL;
+  size_t buf_len = 0;
+  char *name = NULL;
+  strlist_t raw_value = NULL;
+
+
+  *result = pkc_new ();
+  if (*result == NULL)
+    return my_error_from_syserror ();
+
+  if (errlinep)
+    *errlinep = 0;
+  while ((len = es_read_line (stream, &buf, &buf_len, NULL)))
+    {
+      char *p;
+      if (errlinep)
+       *errlinep += 1;
+
+      /* Skip any whitespace.  */
+      for (p = buf; *p && ascii_isspace (*p); p++)
+       /* Do nothing.  */;
+
+      if (name && (spacep (buf) || *p == 0))
+       {
+         /* A continuation.  */
+         if (append_to_strlist_try (&raw_value, buf) == NULL)
+           {
+             err = my_error_from_syserror ();
+             goto leave;
+           }
+         continue;
+       }
+
+      /* No continuation.  Add the current entry if any.  */
+      if (raw_value)
+       {
+         err = _pkc_add (*result, name, NULL, raw_value, 1);
+         if (err)
+           goto leave;
+       }
+
+      /* And prepare for the next one.  */
+      name = NULL;
+      raw_value = NULL;
+
+      if (*p != 0 && *p != '#')
+       {
+         char *colon, *value, tmp;
+
+         colon = strchr (buf, ':');
+         if (colon == NULL)
+           {
+             err = gpg_error (GPG_ERR_INV_VALUE);
+             goto leave;
+           }
+
+         value = colon + 1;
+         tmp = *value;
+         *value = 0;
+         name = xtrystrdup (p);
+         *value = tmp;
+
+         if (name == NULL)
+           {
+             err = my_error_from_syserror ();
+             goto leave;
+           }
+
+         if (append_to_strlist_try (&raw_value, value) == NULL)
+           {
+             err = my_error_from_syserror ();
+             goto leave;
+           }
+         continue;
+       }
+
+      if (append_to_strlist_try (&raw_value, buf) == NULL)
+       {
+         err = my_error_from_syserror ();
+         goto leave;
+       }
+    }
+
+  /* Add the final entry.  */
+  if (raw_value)
+    err = _pkc_add (*result, name, NULL, raw_value, 1);
+
+ leave:
+  gpgrt_free (buf);
+  if (err)
+    {
+      pkc_release (*result);
+      *result = NULL;
+    }
+
+  return err;
+}
+
+
+/* Write a representation of PK to STREAM.  */
+gpg_error_t
+pkc_write (pkc_t pk, estream_t stream)
+{
+  gpg_error_t err;
+  pke_t entry;
+  strlist_t s;
+
+  for (entry = pk->first; entry; entry = entry->next)
+    {
+      if (entry->name)
+       es_fputs (entry->name, stream);
+
+      err = assert_raw_value (entry);
+      if (err)
+       return err;
+
+      for (s = entry->raw_value; s; s = s->next)
+       es_fputs (s->d, stream);
+
+      if (es_ferror (stream))
+       return my_error_from_syserror ();
+    }
+
+  return 0;
+}
diff --git a/common/private-keys.h b/common/private-keys.h
new file mode 100644 (file)
index 0000000..d21e94f
--- /dev/null
@@ -0,0 +1,109 @@
+/* private-keys.h - Parser and writer for the extended private key format.
+ *     Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_PRIVATE_KEYS_H
+#define GNUPG_COMMON_PRIVATE_KEYS_H
+
+struct private_key_container;
+typedef struct private_key_container *pkc_t;
+
+struct private_key_entry;
+typedef struct private_key_entry *pke_t;
+
+\f
+
+/* Memory management, and dealing with entries.  */
+
+/* Allocate a private key container structure.  */
+pkc_t pkc_new (void);
+
+/* Release a private key container structure.  */
+void pkc_release (pkc_t pk);
+
+/* Get the name.  */
+char *pke_name (pke_t pke);
+
+/* Get the value.  */
+char *pke_value (pke_t pke);
+
+\f
+
+/* Lookup and iteration.  */
+
+/* Get the first non-comment entry.  */
+pke_t pkc_first (pkc_t pk);
+
+/* Get the first entry with the given name.  */
+pke_t pkc_lookup (pkc_t pk, const char *name);
+
+/* Get the next non-comment entry.  */
+pke_t pke_next (pke_t entry);
+
+/* Get the next entry with the given name.  */
+pke_t pke_next_value (pke_t entry, const char *name);
+
+\f
+
+/* Adding and modifying values.  */
+
+/* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
+   is not updated but the new entry is appended.  */
+gpg_error_t pkc_add (pkc_t pk, const char *name, const char *value);
+
+/* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
+   is updated with VALUE.  If multiple entries with NAME exist, the
+   first entry is updated.  */
+gpg_error_t pkc_set (pkc_t pk, const char *name, const char *value);
+
+/* Delete the given entry from PK.  */
+void pkc_delete (pkc_t pk, pke_t pke);
+
+\f
+
+/* Private key handling.  */
+
+/* Get the private key.  */
+gpg_error_t pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp);
+
+/* Set the private key.  */
+gpg_error_t pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp);
+
+\f
+
+/* Parsing and serialization.  */
+
+/* Parse STREAM and return a newly allocated private key container
+   structure in RESULT.  If ERRLINEP is given, the line number the
+   parser was last considering is stored there.  */
+gpg_error_t pkc_parse (pkc_t *result, int *errlinep, estream_t stream);
+
+/* Write a representation of PK to STREAM.  */
+gpg_error_t pkc_write (pkc_t pk, estream_t stream);
+
+#endif /* GNUPG_COMMON_PRIVATE_KEYS_H */
diff --git a/common/server-help.c b/common/server-help.c
new file mode 100644 (file)
index 0000000..2a59dc6
--- /dev/null
@@ -0,0 +1,137 @@
+/* server-help.h - Helper functions for writing Assuan servers.
+ *     Copyright (C) 2003, 2009, 2010 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <string.h>
+
+#include "server-help.h"
+#include "util.h"
+
+/* Skip over options in LINE.
+
+   Blanks after the options are also removed.  Options are indicated
+   by two leading dashes followed by a string consisting of non-space
+   characters.  The special option "--" indicates an explicit end of
+   options; all what follows will not be considered an option.  The
+   first no-option string also indicates the end of option parsing. */
+char *
+skip_options (const char *line)
+{
+  while (spacep (line))
+    line++;
+  while (*line == '-' && line[1] == '-')
+    {
+      while (*line && !spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+    }
+  return (char*) line;
+}
+
+
+/* Check whether the option NAME appears in LINE.  */
+int
+has_option (const char *line, const char *name)
+{
+  const char *s;
+  int n = strlen (name);
+
+  s = strstr (line, name);
+  if (s && s >= skip_options (line))
+    return 0;
+  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
+}
+
+
+/* Same as has_option but only considers options at the begin of the
+   line.  This is useful for commands which allow arbitrary strings on
+   the line.  */
+int
+has_leading_option (const char *line, const char *name)
+{
+  const char *s;
+  int n;
+
+  if (name[0] != '-' || name[1] != '-' || !name[2] || spacep (name+2))
+    return 0;
+  n = strlen (name);
+  while ( *line == '-' && line[1] == '-' )
+    {
+      s = line;
+      while (*line && !spacep (line))
+        line++;
+      if (n == (line - s) && !strncmp (s, name, n))
+        return 1;
+      while (spacep (line))
+        line++;
+    }
+  return 0;
+}
+
+
+/* Same as has_option but does only test for the name of the option
+   and ignores an argument, i.e. with NAME being "--hash" it would
+   return a pointer for "--hash" as well as for "--hash=foo".  If
+   there is no such option NULL is returned.  The pointer returned
+   points right behind the option name, this may be an equal sign, Nul
+   or a space.  */
+const char *
+has_option_name (const char *line, const char *name)
+{
+  const char *s;
+  int n = strlen (name);
+
+  s = strstr (line, name);
+  return (s && (s == line || spacep (s-1))
+          && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
+}
+
+
+/* Return a pointer to the argument of the option with NAME.  If such
+   an option is not given, NULL is returned. */
+char *
+option_value (const char *line, const char *name)
+{
+  char *s;
+  int n = strlen (name);
+
+  s = strstr (line, name);
+  if (s && s >= skip_options (line))
+    return NULL;
+  if (s && (s == line || spacep (s-1))
+      && s[n] && (spacep (s+n) || s[n] == '='))
+    {
+      s += n + 1;
+      s += strspn (s, " ");
+      if (*s && !spacep(s))
+        return s;
+    }
+  return NULL;
+}
diff --git a/common/server-help.h b/common/server-help.h
new file mode 100644 (file)
index 0000000..6df9e2c
--- /dev/null
@@ -0,0 +1,62 @@
+/* server-help.h - Helper functions for writing Assuan servers.
+ *     Copyright (C) 2003, 2009, 2010 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_SERVER_HELP_H
+#define GNUPG_COMMON_SERVER_HELP_H
+
+/* Skip over options in LINE.
+
+   Blanks after the options are also removed.  Options are indicated
+   by two leading dashes followed by a string consisting of non-space
+   characters.  The special option "--" indicates an explicit end of
+   options; all what follows will not be considered an option.  The
+   first no-option string also indicates the end of option parsing. */
+char *skip_options (const char *line);
+
+/* Check whether the option NAME appears in LINE.  */
+int has_option (const char *line, const char *name);
+
+/* Same as has_option but only considers options at the begin of the
+   line.  This is useful for commands which allow arbitrary strings on
+   the line.  */
+int has_leading_option (const char *line, const char *name);
+
+/* Same as has_option but does only test for the name of the option
+   and ignores an argument, i.e. with NAME being "--hash" it would
+   return a pointer for "--hash" as well as for "--hash=foo".  If
+   there is no such option NULL is returned.  The pointer returned
+   points right behind the option name, this may be an equal sign, Nul
+   or a space.  */
+const char *has_option_name (const char *line, const char *name);
+
+/* Return a pointer to the argument of the option with NAME.  If such
+   an option is not given, NULL is returned. */
+char *option_value (const char *line, const char *name);
+
+#endif /* GNUPG_COMMON_SERVER_HELP_H */
index f68c552..442d106 100644 (file)
@@ -49,7 +49,7 @@ snext (unsigned char const **buf)
 }
 
 /* Skip over the S-Expression BUF points to and update BUF to point to
-   the chacter right behind.  DEPTH gives the initial number of open
+   the character right behind.  DEPTH gives the initial number of open
    lists and may be passed as a positive number to skip over the
    remainder of an S-Expression if the current position is somewhere
    in an S-Expression.  The function may return an error code if it
index 90d04c0..bdad140 100644 (file)
@@ -618,6 +618,7 @@ simple_query (const char *query)
   int fd = -1;
   int nread;
   char response[500];
+  int have = 0;
   int rc;
 
   rc = agent_open (&fd);
@@ -628,40 +629,78 @@ simple_query (const char *query)
   if (rc)
     goto leave;
 
-  /* get response */
-  nread = readline (fd, response, 499);
-  if (nread < 0)
-    {
-      rc = -nread;
-      goto leave;
-    }
-  if (nread < 3)
+  while (1)
     {
-      rc = SPWQ_PROTOCOL_ERROR;
-      goto leave;
-    }
+      if (! have || ! strchr (response, '\n'))
+        /* get response */
+        {
+          nread = readline (fd, &response[have],
+                            sizeof (response) - 1 /* NUL */ - have);
+          if (nread < 0)
+            {
+              rc = -nread;
+              goto leave;
+            }
+          have += nread;
+          if (have < 3)
+            {
+              rc = SPWQ_PROTOCOL_ERROR;
+              goto leave;
+            }
+          response[have] = 0;
+        }
 
-  if (response[0] == 'O' && response[1] == 'K')
-    /* OK, do nothing.  */;
-  else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
-            && (response[7] == ' ' || response[7] == '\n') )
-           || ((nread > 4 && !memcmp (response, "ERR ", 4)
-                && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
-    {
-      /* 111 is the old Assuan code for canceled which might still
-         be in use by old installations. 99 is GPG_ERR_CANCELED as
-         used by modern gpg-agents; 0xffff is used to mask out the
-         error source.  */
+      if (response[0] == 'O' && response[1] == 'K')
+        /* OK, do nothing.  */;
+      else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
+                && (response[7] == ' ' || response[7] == '\n') )
+               || ((nread > 4 && !memcmp (response, "ERR ", 4)
+                    && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
+        {
+          /* 111 is the old Assuan code for canceled which might still
+             be in use by old installations. 99 is GPG_ERR_CANCELED as
+             used by modern gpg-agents; 0xffff is used to mask out the
+             error source.  */
 #ifdef SPWQ_USE_LOGGING
-      log_info (_("canceled by user\n") );
+          log_info (_("canceled by user\n") );
 #endif
-    }
-  else
-    {
+        }
+      else if (response[0] == 'S' && response[1] == ' ')
+        {
+          char *nextline;
+          int consumed;
+
+          nextline = strchr (response, '\n');
+          if (! nextline)
+            /* Point to the NUL.  */
+            nextline = &response[have];
+          else
+            /* Move past the \n.  */
+            nextline ++;
+
+          consumed = (size_t) nextline - (size_t) response;
+
+          /* Skip any additional newlines.  */
+          while (consumed < have && response[consumed] == '\n')
+            consumed ++;
+
+          have -= consumed;
+
+          if (have)
+            memmove (response, &response[consumed], have + 1);
+
+          continue;
+        }
+      else
+        {
 #ifdef SPWQ_USE_LOGGING
-      log_error (_("problem with the agent\n"));
+          log_error (_("problem with the agent (unexpected response \"%s\")\n"),
+                     response);
 #endif
-      rc = SPWQ_ERR_RESPONSE;
+          rc = SPWQ_ERR_RESPONSE;
+        }
+
+      break;
     }
 
  leave:
index e50827f..730a75c 100644 (file)
@@ -133,6 +133,11 @@ enum
     STATUS_PKA_TRUST_BAD,
     STATUS_PKA_TRUST_GOOD,
 
+    STATUS_TOFU_USER,
+    STATUS_TOFU_STATS,
+    STATUS_TOFU_STATS_SHORT,
+    STATUS_TOFU_STATS_LONG,
+
     STATUS_TRUNCATED,
     STATUS_MOUNTPOINT,
 
index 760a460..d4f8644 100644 (file)
@@ -39,6 +39,7 @@
 #include "common-defs.h"
 #include "strlist.h"
 #include "utf8conv.h"
+#include "mischelp.h"
 
 void
 free_strlist( strlist_t sl )
@@ -52,6 +53,19 @@ free_strlist( strlist_t sl )
 }
 
 
+void
+free_strlist_wipe (strlist_t sl)
+{
+    strlist_t sl2;
+
+    for(; sl; sl = sl2 ) {
+       sl2 = sl->next;
+        wipememory (sl, sizeof *sl + strlen (sl->d));
+       xfree(sl);
+    }
+}
+
+
 /* Add STRING to the LIST at the front.  This function terminates the
    process on memory shortage.  */
 strlist_t
@@ -112,9 +126,24 @@ add_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
 strlist_t
 append_to_strlist( strlist_t *list, const char *string )
 {
+  strlist_t sl;
+  sl = append_to_strlist_try (list, string);
+  if (!sl)
+    xoutofcore ();
+  return sl;
+}
+
+
+/* Add STRING to the LIST at the end.  */
+strlist_t
+append_to_strlist_try (strlist_t *list, const char *string)
+{
     strlist_t r, sl;
 
-    sl = xmalloc( sizeof *sl + strlen(string));
+    sl = xtrymalloc( sizeof *sl + strlen(string));
+    if (sl == NULL)
+      return NULL;
+
     sl->flags = 0;
     strcpy(sl->d, string);
     sl->next = NULL;
index acb92f7..45f5543 100644 (file)
@@ -40,12 +40,15 @@ struct string_list
 typedef struct string_list *strlist_t;
 
 void    free_strlist (strlist_t sl);
+void   free_strlist_wipe (strlist_t sl);
+
 strlist_t add_to_strlist (strlist_t *list, const char *string);
 strlist_t add_to_strlist_try (strlist_t *list, const char *string);
 
 strlist_t add_to_strlist2( strlist_t *list, const char *string, int is_utf8);
 
 strlist_t append_to_strlist (strlist_t *list, const char *string);
+strlist_t append_to_strlist_try (strlist_t *list, const char *string);
 strlist_t append_to_strlist2 (strlist_t *list, const char *string,
                               int is_utf8);
 
index ccd3542..18625d0 100644 (file)
@@ -554,6 +554,40 @@ gnupg_remove (const char *fname)
 }
 
 
+#ifndef HAVE_W32_SYSTEM
+static mode_t
+modestr_to_mode (const char *modestr)
+{
+  mode_t mode = 0;
+
+  if (modestr && *modestr)
+    {
+      modestr++;
+      if (*modestr && *modestr++ == 'r')
+        mode |= S_IRUSR;
+      if (*modestr && *modestr++ == 'w')
+        mode |= S_IWUSR;
+      if (*modestr && *modestr++ == 'x')
+        mode |= S_IXUSR;
+      if (*modestr && *modestr++ == 'r')
+        mode |= S_IRGRP;
+      if (*modestr && *modestr++ == 'w')
+        mode |= S_IWGRP;
+      if (*modestr && *modestr++ == 'x')
+        mode |= S_IXGRP;
+      if (*modestr && *modestr++ == 'r')
+        mode |= S_IROTH;
+      if (*modestr && *modestr++ == 'w')
+        mode |= S_IWOTH;
+      if (*modestr && *modestr++ == 'x')
+        mode |= S_IXOTH;
+    }
+
+  return mode;
+}
+#endif
+
+
 /* A wrapper around mkdir which takes a string for the mode argument.
    This makes it easier to handle the mode argument which is not
    defined on all systems.  The format of the modestring is
@@ -589,31 +623,22 @@ gnupg_mkdir (const char *name, const char *modestr)
      because this sets ERRNO.  */
   return mkdir (name);
 #else
-  mode_t mode = 0;
+  return mkdir (name, modestr_to_mode (modestr));
+#endif
+}
 
-  if (modestr && *modestr)
-    {
-      modestr++;
-      if (*modestr && *modestr++ == 'r')
-        mode |= S_IRUSR;
-      if (*modestr && *modestr++ == 'w')
-        mode |= S_IWUSR;
-      if (*modestr && *modestr++ == 'x')
-        mode |= S_IXUSR;
-      if (*modestr && *modestr++ == 'r')
-        mode |= S_IRGRP;
-      if (*modestr && *modestr++ == 'w')
-        mode |= S_IWGRP;
-      if (*modestr && *modestr++ == 'x')
-        mode |= S_IXGRP;
-      if (*modestr && *modestr++ == 'r')
-        mode |= S_IROTH;
-      if (*modestr && *modestr++ == 'w')
-        mode |= S_IWOTH;
-      if (*modestr && *modestr++ == 'x')
-        mode |= S_IXOTH;
-    }
-  return mkdir (name, mode);
+
+/* A wrapper around mkdir which takes a string for the mode argument.
+   This makes it easier to handle the mode argument which is not
+   defined on all systems.  The format of the modestring is the same
+   as for gnupg_mkdir.  */
+int
+gnupg_chmod (const char *name, const char *modestr)
+{
+#ifdef HAVE_W32_SYSTEM
+  return 0;
+#else
+  return chmod (name, modestr_to_mode (modestr));
 #endif
 }
 
index 95276de..ba66ce6 100644 (file)
@@ -61,6 +61,7 @@ void gnupg_reopen_std (const char *pgmname);
 void gnupg_allow_set_foregound_window (pid_t pid);
 int  gnupg_remove (const char *fname);
 int  gnupg_mkdir (const char *name, const char *modestr);
+int gnupg_chmod (const char *name, const char *modestr);
 char *gnupg_mkdtemp (char *template);
 int  gnupg_setenv (const char *name, const char *value, int overwrite);
 int  gnupg_unsetenv (const char *name);
index 19079d3..3a47dc8 100644 (file)
@@ -35,18 +35,18 @@ print_open_fds (int *array)
 {
   int n;
 
+  if (!verbose)
+    return;
+
   for (n=0; array[n] != -1; n++)
     ;
   printf ("open file descriptors: %d", n);
-  if (verbose)
-    {
-      putchar (' ');
-      putchar (' ');
-      putchar ('(');
-      for (n=0; array[n] != -1; n++)
-        printf ("%d%s", array[n], array[n+1] == -1?"":" ");
-      putchar (')');
-    }
+  putchar (' ');
+  putchar (' ');
+  putchar ('(');
+  for (n=0; array[n] != -1; n++)
+    printf ("%d%s", array[n], array[n+1] == -1?"":" ");
+  putchar (')');
   putchar ('\n');
 }
 
@@ -84,7 +84,8 @@ test_close_all_fds (void)
   system (buffer);
 #endif
 
-  printf ("max. file descriptors: %d\n", max_fd);
+  if (verbose)
+    printf ("max. file descriptors: %d\n", max_fd);
   array = xget_all_open_fds ();
   print_open_fds (array);
   for (initial_count=n=0; array[n] != -1; n++)
diff --git a/common/t-private-keys.c b/common/t-private-keys.c
new file mode 100644 (file)
index 0000000..1027e70
--- /dev/null
@@ -0,0 +1,541 @@
+/* t-private-keys.c - Module test for private-keys.c
+ *     Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "private-keys.h"
+
+static int verbose;
+
+void
+test_getting_values (pkc_t pk)
+{
+  pke_t e;
+
+  e = pkc_lookup (pk, "Comment:");
+  assert (e);
+
+  /* Names are case-insensitive.  */
+  e = pkc_lookup (pk, "comment:");
+  assert (e);
+  e = pkc_lookup (pk, "COMMENT:");
+  assert (e);
+
+  e = pkc_lookup (pk, "SomeOtherName:");
+  assert (e);
+}
+
+
+void
+test_key_extraction (pkc_t pk)
+{
+  gpg_error_t err;
+  gcry_sexp_t key;
+
+  err = pkc_get_private_key (pk, &key);
+  assert (err == 0);
+  assert (key);
+
+  if (verbose)
+    gcry_sexp_dump (key);
+
+  gcry_sexp_release (key);
+}
+
+
+void
+test_iteration (pkc_t pk)
+{
+  int i;
+  pke_t e;
+
+  i = 0;
+  for (e = pkc_first (pk); e; e = pke_next (e))
+    i++;
+  assert (i == 4);
+
+  i = 0;
+  for (e = pkc_lookup (pk, "Comment:");
+       e;
+       e = pke_next_value (e, "Comment:"))
+    i++;
+  assert (i == 3);
+}
+
+
+void
+test_whitespace (pkc_t pk)
+{
+  pke_t e;
+
+  e = pkc_lookup (pk, "One:");
+  assert (e);
+  assert (strcmp (pke_value (e), "WithoutWhitespace") == 0);
+
+  e = pkc_lookup (pk, "Two:");
+  assert (e);
+  assert (strcmp (pke_value (e), "With Whitespace") == 0);
+
+  e = pkc_lookup (pk, "Three:");
+  assert (e);
+  assert (strcmp (pke_value (e),
+                  "Blank lines in continuations encode newlines.\n"
+                  "Next paragraph.") == 0);
+}
+
+
+struct
+{
+  char *value;
+  void (*test_func) (pkc_t);
+} tests[] =
+  {
+    {
+      "# This is a comment followed by an empty line\n"
+      "\n",
+      NULL,
+    },
+    {
+      "# This is a comment followed by two empty lines, Windows style\r\n"
+      "\r\n"
+      "\r\n",
+      NULL,
+    },
+    {
+      "# Some name,value pairs\n"
+      "Comment: Some comment.\n"
+      "SomeOtherName: Some value.\n",
+      test_getting_values,
+    },
+    {
+      "  # Whitespace is preserved as much as possible\r\n"
+      "Comment:Some comment.\n"
+      "SomeOtherName: Some value.   \n",
+      test_getting_values,
+    },
+    {
+      "# Values may be continued in the next line as indicated by leading\n"
+      "# space\n"
+      "Comment: Some rather long\n"
+      "  comment that is continued in the next line.\n"
+      "\n"
+      "  Blank lines with or without whitespace are allowed within\n"
+      "  continuations to allow paragraphs.\n"
+      "SomeOtherName: Some value.\n",
+      test_getting_values,
+    },
+    {
+      "# Names may be given multiple times forming an array of values\n"
+      "Comment: Some comment, element 0.\n"
+      "Comment: Some comment, element 1.\n"
+      "Comment: Some comment, element 2.\n"
+      "SomeOtherName: Some value.\n",
+      test_iteration,
+    },
+    {
+      "# One whitespace at the beginning of a continuation is swallowed.\n"
+      "One: Without\n"
+      " Whitespace\n"
+      "Two: With\n"
+      "  Whitespace\n"
+      "Three: Blank lines in continuations encode newlines.\n"
+      "\n"
+      "  Next paragraph.\n",
+      test_whitespace,
+    },
+    {
+      "Description: Key to sign all GnuPG released tarballs.\n"
+      "  The key is actually stored on a smart card.\n"
+      "Use-for-ssh: yes\n"
+      "OpenSSH-cert: long base64 encoded string wrapped so that this\n"
+      "  key file can be easily edited with a standard editor.\n"
+      "Key: (shadowed-private-key\n"
+      "  (rsa\n"
+      "  (n #00AA1AD2A55FD8C8FDE9E1941772D9CC903FA43B268CB1B5A1BAFDC900\n"
+      "  2961D8AEA153424DC851EF13B83AC64FBE365C59DC1BD3E83017C90D4365B4\n"
+      "  83E02859FC13DB5842A00E969480DB96CE6F7D1C03600392B8E08EF0C01FC7\n"
+      "  19F9F9086B25AD39B4F1C2A2DF3E2BE317110CFFF21D4A11455508FE407997\n"
+      "  601260816C8422297C0637BB291C3A079B9CB38A92CE9E551F80AA0EBF4F0E\n"
+      "  72C3F250461E4D31F23A7087857FC8438324A013634563D34EFDDCBF2EA80D\n"
+      "  F9662C9CCD4BEF2522D8BDFED24CEF78DC6B309317407EAC576D889F88ADA0\n"
+      "  8C4FFB480981FB68C5C6CA27503381D41018E6CDC52AAAE46B166BDC10637A\n"
+      "  E186A02BA2497FDC5D1221#)\n"
+      "  (e #00010001#)\n"
+      "  (shadowed t1-v1\n"
+      "   (#D2760001240102000005000011730000# OPENPGP.1)\n"
+      "    )))\n",
+      test_key_extraction,
+    },
+  };
+
+
+static char *
+pkc_to_string (pkc_t pk)
+{
+  gpg_error_t err;
+  char *buf;
+  size_t len;
+  estream_t sink;
+
+  sink = es_fopenmem (0, "rw");
+  assert (sink);
+
+  err = pkc_write (pk, sink);
+  assert (err == 0);
+
+  len = es_ftell (sink);
+  buf = xmalloc (len+1);
+  assert (buf);
+
+  es_fseek (sink, 0, SEEK_SET);
+  es_read (sink, buf, len, NULL);
+  buf[len] = 0;
+
+  es_fclose (sink);
+  return buf;
+}
+
+
+void dummy_free (void *p) { (void) p; }
+void *dummy_realloc (void *p, size_t s) { (void) s; return p; }
+
+void
+run_tests (void)
+{
+  gpg_error_t err;
+  pkc_t pk;
+
+  int i;
+  for (i = 0; i < DIM (tests); i++)
+    {
+      estream_t source;
+      char *buf;
+      size_t len;
+
+      len = strlen (tests[i].value);
+      source = es_mopen (tests[i].value, len, len,
+                        0, dummy_realloc, dummy_free, "r");
+      assert (source);
+
+      err = pkc_parse (&pk, NULL, source);
+      assert (err == 0);
+      assert (pk);
+
+      if (verbose)
+       {
+         err = pkc_write (pk, es_stderr);
+         assert (err == 0);
+       }
+
+      buf = pkc_to_string (pk);
+      assert (memcmp (tests[i].value, buf, len) == 0);
+
+      es_fclose (source);
+      xfree (buf);
+
+      if (tests[i].test_func)
+       tests[i].test_func (pk);
+
+      pkc_release (pk);
+    }
+}
+
+
+void
+run_modification_tests (void)
+{
+  gpg_error_t err;
+  pkc_t pk;
+  gcry_sexp_t key;
+  char *buf;
+
+  pk = pkc_new ();
+  assert (pk);
+
+  pkc_set (pk, "Foo:", "Bar");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Bar\n") == 0);
+  xfree (buf);
+
+  pkc_set (pk, "Foo:", "Baz");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Baz\n") == 0);
+  xfree (buf);
+
+  pkc_set (pk, "Bar:", "Bazzel");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
+  xfree (buf);
+
+  pkc_add (pk, "Foo:", "Bar");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
+  xfree (buf);
+
+  pkc_add (pk, "DontExistYet:", "Bar");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\nDontExistYet: Bar\n")
+         == 0);
+  xfree (buf);
+
+  pkc_delete (pk, pkc_lookup (pk, "DontExistYet:"));
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0);
+  xfree (buf);
+
+  pkc_delete (pk, pke_next_value (pkc_lookup (pk, "Foo:"), "Foo:"));
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0);
+  xfree (buf);
+
+  pkc_delete (pk, pkc_lookup (pk, "Foo:"));
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Bar: Bazzel\n") == 0);
+  xfree (buf);
+
+  pkc_delete (pk, pkc_first (pk));
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "") == 0);
+  xfree (buf);
+
+  pkc_set (pk, "Foo:", "A really long value spanning across multiple lines"
+          " that has to be wrapped at a convenient space.");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: A really long value spanning across multiple"
+                 " lines that has to be\n  wrapped at a convenient space.\n")
+         == 0);
+  xfree (buf);
+
+  pkc_set (pk, "Foo:", "XA really long value spanning across multiple lines"
+          " that has to be wrapped at a convenient space.");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: XA really long value spanning across multiple"
+                 " lines that has to\n  be wrapped at a convenient space.\n")
+         == 0);
+  xfree (buf);
+
+  pkc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines"
+          " that has to be wrapped at a convenient space.");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: XXXXA really long value spanning across multiple"
+                 " lines that has\n  to be wrapped at a convenient space.\n")
+         == 0);
+  xfree (buf);
+
+  pkc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines"
+          "thathastobewrappedataconvenientspacethatisnotthere.");
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Foo: Areallylongvaluespanningacrossmultiplelinesthat"
+                 "hastobewrappedataco\n nvenientspacethatisnotthere.\n")
+         == 0);
+  xfree (buf);
+  pkc_release (pk);
+
+  pk = pkc_new ();
+  assert (pk);
+
+  err = gcry_sexp_build (&key, NULL, "(hello world)");
+  assert (err == 0);
+  assert (key);
+
+  err = pkc_set_private_key (pk, key);
+  gcry_sexp_release (key);
+  assert (err == 0);
+  buf = pkc_to_string (pk);
+  assert (strcmp (buf, "Key: (hello world)\n") == 0);
+  xfree (buf);
+  pkc_release (pk);
+}
+
+
+void
+convert (const char *fname)
+{
+  gpg_error_t err;
+  estream_t source;
+  gcry_sexp_t key;
+  char *buf;
+  size_t buflen;
+  struct stat st;
+  pkc_t pk;
+
+  source = es_fopen (fname, "rb");
+  if (source == NULL)
+    goto leave;
+
+  if (fstat (es_fileno (source), &st))
+    goto leave;
+
+  buflen = st.st_size;
+  buf = xtrymalloc (buflen+1);
+  assert (buf);
+
+  if (es_fread (buf, buflen, 1, source) != 1)
+    goto leave;
+
+  err = gcry_sexp_sscan (&key, NULL, buf, buflen);
+  if (err)
+    {
+      fprintf (stderr, "malformed s-expression in %s\n", fname);
+      exit (1);
+    }
+
+  pk = pkc_new ();
+  assert (pk);
+
+  err = pkc_set_private_key (pk, key);
+  assert (err == 0);
+
+  err = pkc_write (pk, es_stdout);
+  assert (err == 0);
+
+  return;
+
+ leave:
+  perror (fname);
+  exit (1);
+}
+
+
+void
+parse (const char *fname)
+{
+  gpg_error_t err;
+  estream_t source;
+  char *buf;
+  pkc_t pk_a, pk_b;
+  pke_t e;
+  int line;
+
+  source = es_fopen (fname, "rb");
+  if (source == NULL)
+    {
+      perror (fname);
+      exit (1);
+    }
+
+  err = pkc_parse (&pk_a, &line, source);
+  if (err)
+    {
+      fprintf (stderr, "failed to parse %s line %d: %s\n",
+              fname, line, gpg_strerror (err));
+      exit (1);
+    }
+
+  buf = pkc_to_string (pk_a);
+  xfree (buf);
+
+  pk_b = pkc_new ();
+  assert (pk_b);
+
+  for (e = pkc_first (pk_a); e; e = pke_next (e))
+    {
+      gcry_sexp_t key = NULL;
+
+      if (strcasecmp (pke_name (e), "Key:") == 0)
+       {
+         err = pkc_get_private_key (pk_a, &key);
+         if (err)
+           key = NULL;
+       }
+
+      if (key)
+       {
+         err = pkc_set_private_key (pk_b, key);
+         assert (err == 0);
+       }
+      else
+       {
+         err = pkc_add (pk_b, pke_name (e), pke_value (e));
+         assert (err == 0);
+       }
+    }
+
+    buf = pkc_to_string (pk_b);
+    if (verbose)
+      fprintf (stdout, "%s", buf);
+    xfree (buf);
+}
+
+
+void
+print_usage (void)
+{
+  fprintf (stderr,
+          "usage: t-private-keys [--verbose]"
+          " [--convert <private-key-file>"
+          " || --parse <extended-private-key-file>]\n");
+  exit (2);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  enum { TEST, CONVERT, PARSE } command = TEST;
+
+  if (argc)
+    { argc--; argv++; }
+  if (argc && !strcmp (argv[0], "--verbose"))
+    {
+      verbose = 1;
+      argc--; argv++;
+    }
+
+  if (argc && !strcmp (argv[0], "--convert"))
+    {
+      command = CONVERT;
+      argc--; argv++;
+      if (argc != 1)
+       print_usage ();
+    }
+
+  if (argc && !strcmp (argv[0], "--parse"))
+    {
+      command = PARSE;
+      argc--; argv++;
+      if (argc != 1)
+       print_usage ();
+    }
+
+  switch (command)
+    {
+    case TEST:
+      run_tests ();
+      run_modification_tests ();
+      break;
+
+    case CONVERT:
+      convert (*argv);
+      break;
+
+    case PARSE:
+      parse (*argv);
+      break;
+    }
+
+  return 0;
+}
index 46c6552..c5c7b0e 100644 (file)
@@ -55,13 +55,24 @@ show_stdnames (void)
 {
   const char *name, *assname;
   int iterator = 0;
+  int count;
 
-  printf ("Known envvars:");
+  printf ("    > Known envvars:");
+  count = 20;
   while ((name = session_env_list_stdenvnames (&iterator, &assname)))
     {
+      if (count > 60)
+        {
+          printf ("\n    >");
+          count = 7;
+        }
       printf ( " %s", name);
+      count += strlen (name) + 1;
       if (assname)
-        printf ( "(%s)", assname);
+        {
+          printf ( "(%s)", assname);
+          count += strlen (assname) + 2;
+        }
     }
   putchar('\n');
 }
index 8a2cf8a..83e6eae 100644 (file)
 #include <langinfo.h>
 #endif
 #include <errno.h>
-#ifndef HAVE_ANDROID_SYSTEM
+
+#if HAVE_W32_SYSTEM
+# /* Tell libgpg-error to provide the iconv macros.  */
+# define GPGRT_ENABLE_W32_ICONV_MACROS 1
+#elif HAVE_ANDROID_SYSTEM
+# /* No iconv support.  */
+#else
 # include <iconv.h>
 #endif
 
+
 #include "util.h"
 #include "common-defs.h"
 #include "i18n.h"
@@ -244,8 +251,8 @@ set_native_charset (const char *newset)
      as Latin-1.  This makes sense because many Unix system don't have
      their locale set up properly and thus would get annoying error
      messages and we have to handle all the "bug" reports. Latin-1 has
-     always been the character set used for 8 bit characters on Unix
-     systems. */
+     traditionally been the character set used for 8 bit characters on
+     Unix systems. */
   if ( !*newset
        || !ascii_strcasecmp (newset, "8859-1" )
        || !ascii_strcasecmp (newset, "646" )
@@ -700,7 +707,8 @@ jnlib_iconv (jnlib_iconv_t cd,
              const char **inbuf, size_t *inbytesleft,
              char **outbuf, size_t *outbytesleft)
 {
-  return iconv ((iconv_t)cd, (char**)inbuf, inbytesleft, outbuf, outbytesleft);
+  return iconv ((iconv_t)cd, (ICONV_CONST char**)inbuf, inbytesleft,
+                outbuf, outbytesleft);
 }
 
 /* Wrapper function for iconv_close, required for W32 as we dlopen that
index 6410b11..84a15ab 100644 (file)
@@ -263,6 +263,9 @@ const char *gnupg_messages_locale_name (void);
    logging subsystem. */
 void setup_libgcrypt_logging (void);
 
+/* Print an out of core emssage and die.  */
+void xoutofcore (void);
+
 /* Same as estream_asprintf but die on memory failure.  */
 char *xasprintf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
 /* This is now an alias to estream_asprintf.  */
@@ -333,6 +336,9 @@ int _gnupg_isatty (int fd);
 /*-- Macros to replace ctype ones to avoid locale problems. --*/
 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
+#define alphap(p)   ((*(p) >= 'A' && *(p) <= 'Z')       \
+                     || (*(p) >= 'a' && *(p) <= 'z'))
+#define alnump(p)   (alphap (p) || digitp (p))
 #define hexdigitp(a) (digitp (a)                     \
                       || (*(a) >= 'A' && *(a) <= 'F')  \
                       || (*(a) >= 'a' && *(a) <= 'f'))
index 266eae5..6aeca17 100644 (file)
@@ -28,7 +28,7 @@ min_automake_version="1.14"
 m4_define([mym4_package],[gnupg])
 m4_define([mym4_major], [2])
 m4_define([mym4_minor], [1])
-m4_define([mym4_micro], [11])
+m4_define([mym4_micro], [12])
 
 # To start a new development series, i.e a new major or minor number
 # you need to mark an arbitrary commit before the first beta release
@@ -47,8 +47,9 @@ m4_define([mym4_version],      m4_argn(4, mym4_verslist))
 m4_define([mym4_revision],     m4_argn(7, mym4_verslist))
 m4_define([mym4_revision_dec], m4_argn(8, mym4_verslist))
 m4_esyscmd([echo ]mym4_version[>VERSION])
-AC_INIT([mym4_package],[mym4_version], [http://bugs.gnupg.org])
+AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org])
 
+# Note that for Windows we require version 1.22
 NEED_GPG_ERROR_VERSION=1.21
 
 NEED_LIBGCRYPT_API=1
@@ -111,7 +112,7 @@ use_exec=yes
 use_trust_models=yes
 use_tofu=yes
 card_support=yes
-use_ccid_driver=yes
+use_ccid_driver=auto
 dirmngr_auto_start=yes
 use_tls_library=no
 large_secmem=no
@@ -215,13 +216,10 @@ test -n "$GNUPG_DIRMNGR_LDAP_PGM" \
 AC_ARG_ENABLE(gpg2-is-gpg,
     AC_HELP_STRING([--enable-gpg2-is-gpg],[Set installed name of gpg2 to gpg]),
     gpg2_is_gpg=$enableval)
-if test "$gpg2_is_gpg" = "yes"; then
-   name_of_installed_gpg=gpg
-else
-   name_of_installed_gpg=gpg2
+if test "$gpg2_is_gpg" != "yes"; then
+   AC_DEFINE(USE_GPG2_HACK, 1, [Define to install gpg as gpg2])
 fi
-AC_DEFINE_UNQUOTED(NAME_OF_INSTALLED_GPG, "$name_of_installed_gpg",
-                   [The name of the installed GPG tool])
+AM_CONDITIONAL(USE_GPG2_HACK, test "$gpg2_is_gpg" != "yes")
 
 
 # SELinux support includes tracking of sensitive files to avoid
@@ -263,8 +261,11 @@ AC_MSG_CHECKING([whether to enable TOFU])
 AC_ARG_ENABLE(tofu,
                 AC_HELP_STRING([--disable-tofu],
                                [disable the TOFU trust model]),
-              use_tofu=$enableval, use_tofu=yes)
+              use_tofu=$enableval, use_tofu=$use_trust_models)
 AC_MSG_RESULT($use_tofu)
+if test "$use_trust_models" = no && test "$use_tofu" = yes; then
+    AC_MSG_ERROR([both --disable-trust-models and --enable-tofu given])
+fi
 
 
 
@@ -639,6 +640,7 @@ case "${host}" in
                    we use a simplified version of gettext])
         have_dosish_system=yes
         have_w32_system=yes
+        require_iconv=no
         run_tests=no
         use_ldapwrapper=no  # Fixme: Do this only for CE.
         case "${host}" in
@@ -782,16 +784,65 @@ AM_PATH_KSBA("$NEED_KSBA_API:$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
 # libusb allows us to use the integrated CCID smartcard reader driver.
 #
 # FiXME: Use GNUPG_CHECK_LIBUSB and modify to use separate AC_SUBSTs.
-if test "$use_ccid_driver" = yes ; then
-  AC_CHECK_LIB(usb, usb_bulk_write,
-                [ LIBUSB_LIBS="$LIBUSB_LIBS -lusb"
-                  AC_DEFINE(HAVE_LIBUSB,1,
-                           [defined if libusb is available])
-                  have_libusb=yes
-               ])
-  AC_CHECK_FUNCS(usb_create_match)
+if test "$use_ccid_driver" = auto || test "$use_ccid_driver" = yes; then
+   case "${host}" in
+     *-mingw32*)
+       LIBUSB_LIBS=
+       LIBUSB_CPPFLAGS=
+       ;;
+     *-*-darwin*)
+       LIBUSB_LIBS="-lusb-1.0 -Wl,-framework,CoreFoundation -Wl,-framework,IOKit"
+       ;;
+     *-*-freebsd*)
+       # FreeBSD has a native 1.0 compatible library by -lusb.
+       LIBUSB_LIBS="-lusb"
+       ;;
+     *)
+       LIBUSB_LIBS="-lusb-1.0"
+       ;;
+   esac
+fi
+if test x"$LIBUSB_LIBS" != x ; then
+   AC_CHECK_LIB(usb-1.0, libusb_init,
+                [ LIBUSB_LIBS="$LIBUSB_LIBS"
+                  have_libusb=yes ])
+   AC_MSG_CHECKING([libusb include dir])
+   usb_incdir_found="no"
+   for _incdir in "" "/usr/include/libusb-1.0" "/usr/local/include/libusb-1.0"; do
+     _libusb_save_cppflags=$CPPFLAGS
+     if test -n "${_incdir}"; then
+       CPPFLAGS="-I${_incdir} ${CPPFLAGS}"
+     fi
+     AC_PREPROC_IFELSE([AC_LANG_SOURCE([[@%:@include <libusb.h>]])],
+     [usb_incdir=${_incdir}; usb_incdir_found="yes"], [])
+     CPPFLAGS=${_libusb_save_cppflags}
+     if test "$usb_incdir_found" = "yes"; then
+       break
+     fi
+   done
+   if test "$usb_incdir_found" = "yes"; then
+     AC_MSG_RESULT([${usb_incdir}])
+   else
+     AC_MSG_RESULT([not found])
+     usb_incdir=""
+     have_libusb=no
+     if test "$use_ccid_driver" != yes; then
+       use_ccid_driver=no
+     fi
+     LIBUSB_LIBS=""
+   fi
+
+   if test "$have_libusb" = yes; then
+     AC_DEFINE(HAVE_LIBUSB,1, [defined if libusb is available])
+   fi
+   if test x"$usb_incdir" = x; then
+     LIBUSB_CPPFLAGS=""
+   else
+     LIBUSB_CPPFLAGS="-I${usb_incdir}"
+   fi
 fi
 AC_SUBST(LIBUSB_LIBS)
+AC_SUBST(LIBUSB_CPPFLAGS)
 
 #
 # Check wether it is necessary to link against libdl.
@@ -1810,6 +1861,17 @@ if test "$require_iconv" = yes; then
   fi
 fi
 
+if test "$use_ccid_driver" = yes; then
+  if test "$have_libusb" != yes; then
+    die=yes
+    AC_MSG_NOTICE([[
+***
+*** You need libusb to build the internal ccid driver.  Please
+*** install a libusb suitable for your system.
+***]])
+  fi
+fi
+
 if test "$die" = "yes"; then
     AC_MSG_ERROR([[
 ***
index 1c74d10..cbc0090 100644 (file)
@@ -140,10 +140,12 @@ t_ldap_parse_uri_SOURCES = \
        t-ldap-parse-uri.c ldap-parse-uri.c ldap-parse-uri.h \
         http.c dns-stuff.c \
         $(ldap_url) $(t_common_src)
-t_ldap_parse_uri_CFLAGS = -DWITHOUT_NPTH=1
+t_ldap_parse_uri_CFLAGS = -DWITHOUT_NPTH=1 \
+                         $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
 t_ldap_parse_uri_LDADD = $(ldaplibs) $(t_common_ldadd) $(DNSLIBS)
 
-t_dns_stuff_CFLAGS = -DWITHOUT_NPTH=1
+t_dns_stuff_CFLAGS = -DWITHOUT_NPTH=1 \
+                    $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)
 t_dns_stuff_SOURCES = t-dns-stuff.c dns-stuff.c
 t_dns_stuff_LDADD   = $(t_common_ldadd) $(DNSLIBS)
 
index 02920d6..c6a33d7 100644 (file)
@@ -116,6 +116,25 @@ static unsigned char bintoasc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 static unsigned char asctobin[256]; /* runtime initialized */
 
 
+/* Build the helptable for radix64 to bin conversion. */
+static void
+init_asctobin (void)
+{
+  static int initialized;
+  int i;
+  unsigned char *s;
+
+  if (initialized)
+    return;
+  initialized = 1;
+
+  for (i=0; i < 256; i++ )
+    asctobin[i] = 255; /* Used to detect invalid characters. */
+  for (s=bintoasc, i=0; *s; s++, i++)
+    asctobin[*s] = i;
+}
+
+
 /* Prototypes.  */
 static gpg_error_t read_certificate (const char *fname,
                                      unsigned char **rbuf, size_t *rbuflen);
@@ -234,19 +253,6 @@ main (int argc, char **argv )
   if (log_get_errorcount (0))
     exit (2);
 
-  /* Build the helptable for radix64 to bin conversion. */
-  if (opt.pem)
-    {
-      int i;
-      unsigned char *s;
-
-      for (i=0; i < 256; i++ )
-        asctobin[i] = 255; /* Used to detect invalid characters. */
-      for (s=bintoasc, i=0; *s; s++, i++)
-        asctobin[*s] = i;
-    }
-
-
   if (cmd_ping)
     err = 0;
   else if (cmd_lookup || cmd_loadcrl)
@@ -461,6 +467,8 @@ read_pem_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
     s_waitend
   } state = s_init;
 
+  init_asctobin ();
+
   fp = fname? fopen (fname, "r") : stdin;
   if (!fp)
     return gpg_error_from_errno (errno);
@@ -612,6 +620,15 @@ read_certificate (const char *fname, unsigned char **rbuf, size_t *rbuflen)
 
   if (opt.pem)
     return read_pem_certificate (fname, rbuf, rbuflen);
+  else if (fname)
+    {
+      /* A filename has been given.  Let's just assume it is in PEM
+         format and decode it, and fall back to interpreting it as
+         binary certificate if that fails.  */
+      err = read_pem_certificate (fname, rbuf, rbuflen);
+      if (! err)
+        return 0;
+    }
 
   fp = fname? fopen (fname, "rb") : stdin;
   if (!fp)
index 63dfc8d..191719e 100644 (file)
@@ -177,13 +177,17 @@ map_eai_to_gpg_error (int ec)
     case EAI_BADFLAGS:  err = gpg_error (GPG_ERR_INV_FLAG); break;
     case EAI_FAIL:      err = gpg_error (GPG_ERR_SERVER_FAILED); break;
     case EAI_MEMORY:    err = gpg_error (GPG_ERR_ENOMEM); break;
+#ifdef EAI_NODATA
     case EAI_NODATA:    err = gpg_error (GPG_ERR_NO_DATA); break;
+#endif
     case EAI_NONAME:    err = gpg_error (GPG_ERR_NO_NAME); break;
     case EAI_SERVICE:   err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
     case EAI_FAMILY:    err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
     case EAI_SOCKTYPE:  err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
 #ifndef HAVE_W32_SYSTEM
+# ifdef EAI_ADDRFAMILY
     case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
+# endif
     case EAI_SYSTEM:    err = gpg_error_from_syserror (); break;
 #endif
     default:            err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
@@ -817,8 +821,8 @@ get_dns_cert (const char *name, int want_certtype,
                  answer, 65536);
   /* Not too big, not too small, no errors and at least 1 answer. */
   if (r >= sizeof (HEADER) && r <= 65536
-      && (((HEADER *) answer)->rcode) == NOERROR
-      && (count = ntohs (((HEADER *) answer)->ancount)))
+      && (((HEADER *)(void *) answer)->rcode) == NOERROR
+      && (count = ntohs (((HEADER *)(void *) answer)->ancount)))
     {
       int rc;
       unsigned char *pt, *emsg;
@@ -1077,8 +1081,12 @@ getsrv (const char *name,struct srventry **list)
   }
 #else /*!USE_ADNS*/
   {
-    unsigned char answer[2048];
-    HEADER *header = (HEADER *)answer;
+    union {
+      unsigned char ans[2048];
+      HEADER header[1];
+    } res;
+    unsigned char *answer = res.ans;
+    HEADER *header = res.header;
     unsigned char *pt, *emsg;
     int r;
     u16 dlen;
@@ -1301,8 +1309,12 @@ get_dns_cname (const char *name, char **r_cname)
   }
 #else /*!USE_ADNS*/
   {
-    unsigned char answer[2048];
-    HEADER *header = (HEADER *)answer;
+    union {
+      unsigned char ans[2048];
+      HEADER header[1];
+    } res;
+    unsigned char *answer = res.ans;
+    HEADER *header = res.header;
     unsigned char *pt, *emsg;
     int r;
     char *cname;
index aa33917..f0fcd0d 100644 (file)
@@ -560,10 +560,14 @@ http_session_release (http_session_t sess)
 
 
 /* Create a new session object which is currently used to enable TLS
-   support.  It may eventually allow reusing existing connections.  */
+ * support.  It may eventually allow reusing existing connections.
+ * Valid values for FLAGS are:
+ *   HTTP_FLAG_TRUST_DEF - Use the CAs set with http_register_tls_ca
+ *   HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system
+ */
 gpg_error_t
 http_session_new (http_session_t *r_session, const char *tls_priority,
-                  const char *intended_hostname)
+                  const char *intended_hostname, unsigned int flags)
 {
   gpg_error_t err;
   http_session_t sess;
@@ -629,14 +633,34 @@ http_session_new (http_session_t *r_session, const char *tls_priority,
       }
 
     /* Add configured certificates to the session.  */
-    for (sl = tls_ca_certlist; sl; sl = sl->next)
+    if ((flags & HTTP_FLAG_TRUST_DEF))
+      {
+        for (sl = tls_ca_certlist; sl; sl = sl->next)
+          {
+            rc = gnutls_certificate_set_x509_trust_file
+              (sess->certcred, sl->d,
+               (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
+            if (rc < 0)
+              log_info ("setting CA from file '%s' failed: %s\n",
+                        sl->d, gnutls_strerror (rc));
+          }
+      }
+
+    /* Add system certificates to the session.  */
+    if ((flags & HTTP_FLAG_TRUST_SYS))
       {
-        rc = gnutls_certificate_set_x509_trust_file
-          (sess->certcred, sl->d,
-           (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
+#if GNUTLS_VERSION_NUMBER >= 0x030014
+        static int shown;
+
+        rc = gnutls_certificate_set_x509_system_trust (sess->certcred);
         if (rc < 0)
-          log_info ("setting CA from file '%s' failed: %s\n",
-                    sl->d, gnutls_strerror (rc));
+          log_info ("setting system CAs failed: %s\n", gnutls_strerror (rc));
+        else if (!shown)
+          {
+            shown = 1;
+            log_info ("number of system provided CAs: %d\n", rc);
+          }
+#endif /* gnutls >= 3.0.20 */
       }
 
     rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
index 58b8c1a..569ccea 100644 (file)
@@ -80,11 +80,13 @@ enum
     HTTP_FLAG_TRY_PROXY = 1,     /* Try to use a proxy.  */
     HTTP_FLAG_SHUTDOWN = 2,      /* Close sending end after the request.  */
     HTTP_FLAG_FORCE_TOR = 4,     /* Force a TOR connection.  */
-    HTTP_FLAG_LOG_RESP = 8,      /* Log the server respone.  */
+    HTTP_FLAG_LOG_RESP = 8,      /* Log the server response.  */
     HTTP_FLAG_FORCE_TLS = 16,    /* Force the use of TLS.  */
     HTTP_FLAG_IGNORE_CL = 32,    /* Ignore content-length.  */
     HTTP_FLAG_IGNORE_IPv4 = 64,  /* Do not use IPv4.  */
-    HTTP_FLAG_IGNORE_IPv6 = 128  /* Do not use IPv6.  */
+    HTTP_FLAG_IGNORE_IPv6 = 128, /* Do not use IPv6.  */
+    HTTP_FLAG_TRUST_DEF   = 256, /* Use the default CAs.  */
+    HTTP_FLAG_TRUST_SYS   = 512  /* Also use the system defined CAs.  */
   };
 
 
@@ -99,7 +101,8 @@ void http_register_tls_ca (const char *fname);
 
 gpg_error_t http_session_new (http_session_t *r_session,
                               const char *tls_priority,
-                              const char *intended_hostname);
+                              const char *intended_hostname,
+                              unsigned int flags);
 http_session_t http_session_ref (http_session_t sess);
 void http_session_release (http_session_t sess);
 
index eca02f0..636eaf7 100644 (file)
@@ -991,7 +991,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
 
   *r_fp = NULL;
 
-  err = http_session_new (&session, NULL, httphost);
+  err = http_session_new (&session, NULL, httphost, HTTP_FLAG_TRUST_DEF);
   if (err)
     goto leave;
   http_session_set_log_cb (session, cert_log_cb);
index c51c0ce..00d0c4b 100644 (file)
@@ -38,12 +38,20 @@ ks_http_help (ctrl_t ctrl, parsed_uri_t uri)
   const char const data[] =
     "Handler for HTTP URLs:\n"
     "  http://\n"
+#if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
     "  https://\n"
+#endif
     "Supported methods: fetch\n";
   gpg_error_t err;
 
+#if  HTTP_USE_GNUTLS || HTTP_USE_NTBTLS
+  const char data2[] = "  http\n  https";
+#else
+  const char data2[] = "  http";
+#endif
+
   if (!uri)
-    err = ks_print_help (ctrl, "  http");
+    err = ks_print_help (ctrl, data2);
   else if (uri->is_http && strcmp (uri->scheme, "hkp"))
     err = ks_print_help (ctrl, data);
   else
@@ -65,7 +73,9 @@ ks_http_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
   estream_t fp = NULL;
   char *request_buffer = NULL;
 
-  err = http_session_new (&session, NULL, NULL);
+  /* Note that we only use the system provided certificates with the
+   * fetch command.  */
+  err = http_session_new (&session, NULL, NULL, HTTP_FLAG_TRUST_SYS);
   if (err)
     goto leave;
   http_session_set_log_cb (session, cert_log_cb);
index 0794509..80ce5b5 100644 (file)
@@ -1,7 +1,7 @@
 /* server.c - LDAP and Keyserver access server
  * Copyright (C) 2002 Klarälvdalens Datakonsult AB
  * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011, 2015 g10 Code GmbH
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2014, 2015, 2016 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -53,6 +53,7 @@
 #include "dns-stuff.h"
 #include "mbox-util.h"
 #include "zb32.h"
+#include "server-help.h"
 
 /* To avoid DoS attacks we limit the size of a certificate to
    something reasonable.  The DoS was actually only an issue back when
@@ -273,78 +274,6 @@ strcpy_escaped_plus (char *d, const unsigned char *s)
 }
 
 
-/* Check whether the option NAME appears in LINE */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-/* Same as has_option but only considers options at the begin of the
-   line.  This is useful for commands which allow arbitrary strings on
-   the line.  */
-static int
-has_leading_option (const char *line, const char *name)
-{
-  const char *s;
-  int n;
-
-  if (name[0] != '-' || name[1] != '-' || !name[2] || spacep (name+2))
-    return 0;
-  n = strlen (name);
-  while ( *line == '-' && line[1] == '-' )
-    {
-      s = line;
-      while (*line && !spacep (line))
-        line++;
-      if (n == (line - s) && !strncmp (s, name, n))
-        return 1;
-      while (spacep (line))
-        line++;
-    }
-  return 0;
-}
-
-
-/* Same as has_option but does only test for the name of the option
-   and ignores an argument, i.e. with NAME being "--hash" it would
-   return a pointer for "--hash" as well as for "--hash=foo".  If
-   thhere is no such option NULL is returned.  The pointer returned
-   points right behind the option name, this may be an equal sign, Nul
-   or a space.  */
-/* static const char * */
-/* has_option_name (const char *line, const char *name) */
-/* { */
-/*   const char *s; */
-/*   int n = strlen (name); */
-
-/*   s = strstr (line, name); */
-/*   return (s && (s == line || spacep (s-1)) */
-/*           && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL; */
-/* } */
-
-
-/* Skip over options.  It is assumed that leading spaces have been
-   removed (this is the case for lines passed to a handler from
-   assuan).  Blanks after the options are also removed. */
-static char *
-skip_options (char *line)
-{
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return line;
-}
-
-
 /* This fucntion returns true if a Tor server is running.  The sattus
    is cached for the current conenction.  */
 static int
@@ -692,7 +621,7 @@ static const char hlp_dns_cert[] =
   "  *     Return the first record of any supported subtype\n"
   "  PGP   Return the first record of subtype PGP (3)\n"
   "  IPGP  Return the first record of subtype IPGP (6)\n"
-  "If the content of a certifciate is available (PGP) it is returned\n"
+  "If the content of a certificate is available (PGP) it is returned\n"
   "by data lines.  Fingerprints and URLs are returned via status lines.\n"
   "In --pka mode the fingerprint and if available an URL is returned.\n"
   "In --dane mode the key is returned from RR type 61";
@@ -869,6 +798,75 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
 
 
 \f
+static const char hlp_wkd_get[] =
+  "WKD_GET <user_id>\n"
+  "\n"
+  "Return the key for <user_id> from a Web Key Directory.\n";
+static gpg_error_t
+cmd_wkd_get (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  char *mbox = NULL;
+  char *domain;     /* Points to mbox.  */
+  char sha1buf[20];
+  char *uri = NULL;
+  char *encodedhash = NULL;
+
+  line = skip_options (line);
+
+  mbox = mailbox_from_userid (line);
+  if (!mbox || !(domain = strchr (mbox, '@')))
+    {
+      err = set_error (GPG_ERR_INV_USER_ID, "no mailbox in user id");
+      goto leave;
+    }
+  *domain++ = 0;
+
+  gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, mbox, strlen (mbox));
+  encodedhash = zb32_encode (sha1buf, 8*20);
+  if (!encodedhash)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  uri = strconcat ("https://",
+                   domain,
+                   "/.well-known/openpgpkey/hu/",
+                   domain,
+                   "/",
+                   encodedhash,
+                   NULL);
+  if (!uri)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Setup an output stream and perform the get.  */
+  {
+    estream_t outfp;
+
+    outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
+    if (!outfp)
+      err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
+    else
+      {
+        err = ks_action_fetch (ctrl, uri, outfp);
+        es_fclose (outfp);
+      }
+  }
+
+ leave:
+  xfree (uri);
+  xfree (encodedhash);
+  xfree (mbox);
+  return leave_cmd (ctx, err);
+}
+
+
+\f
 static const char hlp_ldapserver[] =
   "LDAPSERVER <data>\n"
   "\n"
@@ -1147,7 +1145,7 @@ static const char hlp_checkocsp[] =
   "Processing then takes place without further interaction; in\n"
   "particular dirmngr tries to locate other required certificates by\n"
   "its own mechanism which includes a local certificate store as well\n"
-  "as a list of trusted root certifciates.\n"
+  "as a list of trusted root certificates.\n"
   "\n"
   "If the option --force-default-responder is given, only the default\n"
   "OCSP responder will be used and any other methods of obtaining an\n"
@@ -2089,7 +2087,7 @@ cmd_ks_fetch (assuan_context_t ctx, char *line)
   /* No options for now.  */
   line = skip_options (line);
 
-  err = ensure_keyserver (ctrl);
+  err = ensure_keyserver (ctrl);  /* FIXME: Why do we needs this here?  */
   if (err)
     goto leave;
 
@@ -2332,6 +2330,7 @@ register_commands (assuan_context_t ctx)
     const char * const help;
   } table[] = {
     { "DNS_CERT",   cmd_dns_cert,   hlp_dns_cert },
+    { "WKD_GET",    cmd_wkd_get,    hlp_wkd_get },
     { "LDAPSERVER", cmd_ldapserver, hlp_ldapserver },
     { "ISVALID",    cmd_isvalid,    hlp_isvalid },
     { "CHECKCRL",   cmd_checkcrl,   hlp_checkcrl },
index 9d5ea5f..3a6be6c 100644 (file)
@@ -262,7 +262,7 @@ main (int argc, char **argv)
   http_register_tls_callback (verify_callback);
   http_register_tls_ca (cafile);
 
-  err = http_session_new (&session, NULL, NULL);
+  err = http_session_new (&session, NULL, NULL, HTTP_FLAG_TRUST_DEF);
   if (err)
     log_error ("http_session_new failed: %s\n", gpg_strerror (err));
 
index 7d5a5a8..5ceab68 100644 (file)
@@ -668,10 +668,54 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
        - shell :: The standard X.509 model.
        - chain :: The chain model.
        - steed :: The STEED model.
+       - tofu  :: The TOFU model
 
     Note that the term =TRUST_= in the status names is used for
     historic reasons; we now speak of validity.
 
+*** TOFU_USER <fingerprint_in_hex> <mbox>
+
+    This status identifies the key and the userid for all following
+    Tofu information.  The fingerprint is the fingerprint of the
+    primary key and the mbox is in general the mailbox part of the
+    userid encoded in UTF-8 and percent escaped.
+
+*** TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2>]]
+
+    Statistics for the current user id.
+
+    Values for VALIDITY are:
+    - 0 :: conflict
+    - 1 :: key without history
+    - 2 :: key with too little history
+    - 3 :: key with enough history for basic trust
+    - 4 :: key with a lot of history
+
+    Values for POLICY are:
+    - none    :: No Policy set
+    - auto    :: Policy is "auto"
+    - good    :: Policy is "good"
+    - bad     :: Policy is "bad"
+    - ask     :: Policy is "ask"
+    - unknown :: Policy is not known.
+
+    TM1 gives the number of seconds since the the first messages was
+    verified.  TM2 gives the number of seconds since the most recent
+    message was verified.
+
+*** TOFU_STATS_SHORT <long_string>
+
+    Information about the TOFU binding for the signature.
+    Example: "15 signatures verified. 10 messages encrypted"
+
+*** TOFU_STATS_LONG <long_string>
+
+    Information about the TOFU binding for the signature in verbose
+    format.  The LONG_STRING is percent escaped.
+    Example: 'Verified 9 messages signed by "Werner Koch
+    (dist sig)" in the past 3 minutes, 40 seconds.  The most
+    recent message was verified 4 seconds ago.'
+
 *** PKA_TRUST_
     This is is one:
 
index 2f3dd43..d2168d6 100644 (file)
@@ -51,6 +51,7 @@ are
  - build   :: Changes to the build system
  - speedo  :: Speedo build system specific changes
  - doc     :: Documentation changes
+ - indent  :: Indentation and similar changes
 
 Typo fixes and documentation updates don't need a ChangeLog entry;
 thus you would use a commit message like
@@ -73,7 +74,6 @@ do this after this scissor line:
 Note that such a comment will be removed if the git commit option
 =--cleanup=scissor= is used.
 
-
 ** License policy
 
   GnuPG is licensed under the GPLv3+ with some files under a mixed
@@ -130,12 +130,13 @@ Note that such a comment will be removed if the git commit option
   - Ignore signed/unsigned pointer mismatches
   - No arithmetic on void pointers; cast to char* first.
   - We use our own printf style functions like =es_printf=, and
-    =es_asprintf= which implement most C99 features with the exception
-    of =wchar_t= (which should anyway not be used).  Please always use
-    them and do not resort to those provided by libc.  The rationale
-    for using them is that we know that the format specifiers work on
-    all platforms and that we do not need to chase platform dependent
-    bugs.
+    =gpgrt_asprintf= (or the =es_asprintf= macro) which implement most
+    C99 features with the exception of =wchar_t= (which should anyway
+    not be used).  Please use them always and do not resort to those
+    provided by libc.  The rationale for using them is that we know
+    that the format specifiers work on all platforms and that we do
+    not need to chase platform dependent bugs.  Note also that in
+    gnupg asprintf is a macro already evaluating to gpgrt_asprintf.
   - It is common to have a label named "leave" for a function's
     cleanup and return code.  This helps with freeing memory and is a
     convenient location to set a breakpoint for debugging.
@@ -149,6 +150,23 @@ Note that such a comment will be removed if the git commit option
     end up in BSS.
   - Use --enable-maintainer-mode with configure.
 
+** Variable names
+
+  Follow the GNU standards.  Here are some conventions you may want to
+  stick to (do not rename existing "wrong" uses without a goog
+  reason).
+
+  - err :: This conveys an error code of type =gpg_error_t= which is
+           compatible to an =int=.  To compare such a variable to a
+           GPG_ERR_ constant, it is necessary to map the value like
+           this: =gpg_err_code(err)=.
+  - ec  :: This is used for a gpg-error code which has no source part
+           (=gpg_err_code_t=) and will eventually be used as input to
+           =gpg_err_make=.
+  - rc  :: Used for all kind of other errors; for example system
+           calls.  The value is not compatible with gpg-error.
+
+
 *** C99 language features
 
   In GnuPG 2.x, but *not in 1.4* and not in most libraries, a limited
index a1a570c..bc06cd5 100644 (file)
@@ -33,15 +33,16 @@ helpfiles = help.txt help.be.txt help.ca.txt help.cs.txt            \
             help.sv.txt help.tr.txt help.zh_CN.txt help.zh_TW.txt
 
 EXTRA_DIST = samplekeys.asc mksamplekeys \
-            gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png\
-             gnupg-card-architecture.eps gnupg-card-architecture.png \
-             gnupg-card-architecture.pdf \
+            gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \
+            gnupg-module-overview.png gnupg-module-overview.pdf \
+             gnupg-card-architecture.png gnupg-card-architecture.pdf \
              FAQ gnupg7.texi mkdefsinc.c defsincdate \
              opt-homedir.texi see-also-note.texi specify-user-id.texi \
             gpgv.texi yat2m.c ChangeLog-2011 whats-new-in-2.1.txt
 
-BUILT_SOURCES = gnupg-card-architecture.eps gnupg-card-architecture.png \
-                gnupg-card-architecture.pdf defsincdate defs.inc
+BUILT_SOURCES = gnupg-module-overview.png gnupg-module-overview.pdf \
+                gnupg-card-architecture.png gnupg-card-architecture.pdf \
+                defsincdate defs.inc
 
 info_TEXINFOS = gnupg.texi
 
@@ -56,11 +57,18 @@ nobase_dist_doc_DATA = FAQ DETAILS HACKING DCO TRANSLATE OpenPGP KEYSERVER \
 gnupg_TEXINFOS = \
        gpg.texi gpgsm.texi gpg-agent.texi scdaemon.texi instguide.texi \
        tools.texi debugging.texi glossary.texi contrib.texi gpl.texi \
-       sysnotes.texi gnupg-card-architecture.fig dirmngr.texi \
+       sysnotes.texi dirmngr.texi \
+        gnupg-module-overview.svg \
+        gnupg-card-architecture.fig \
        howtos.texi howto-create-a-server-cert.texi
 
 gnupg.texi : defs.inc
 
+# We need EPS files for "make distcheck" but we do not want to distribute
+# them due to their size.  Let's build them as needed.
+gnupg.dvi : gnupg-module-overview.eps gnupg-card-architecture.eps
+
+
 DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips
 
 AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css
@@ -70,11 +78,16 @@ YAT2M_OPTIONS = -I $(srcdir) \
 
 myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
                dirmngr.texi scdaemon.texi tools.texi
-myman_pages   = gpg2.1 gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 gpgv2.1 \
+myman_pages   = gpgsm.1 gpg-agent.1 dirmngr.8 scdaemon.1 \
                 watchgnupg.1 gpgconf.1 addgnupghome.8 gpg-preset-passphrase.1 \
                gpg-connect-agent.1 gpgparsemail.1 symcryptrun.1 \
                applygnupgdefaults.8 \
                dirmngr-client.1
+if USE_GPG2_HACK
+myman_pages += gpg2.1 gpgv2.1
+else
+myman_pages += gpg.1 gpgv.1
+endif
 
 man_MANS = $(myman_pages) gnupg.7
 
@@ -84,6 +97,8 @@ watchgnupg_SOURCE = gnupg.texi
 CLEANFILES = yat2m mkdefsinc defs.inc
 
 DISTCLEANFILES = gnupg.tmp gnupg.ops yat2m-stamp.tmp yat2m-stamp \
+                 gnupg-card-architecture.eps \
+                 gnupg-module-overview.eps \
                 $(myman_pages) gpg-zip.1 gnupg.7
 
 yat2m: yat2m.c
@@ -93,6 +108,14 @@ mkdefsinc: mkdefsinc.c Makefile ../config.h
        $(CC_FOR_BUILD) -I. -I.. -I$(srcdir) $(AM_CPPFLAGS) \
                         -o $@ $(srcdir)/mkdefsinc.c
 
+.svg.eps:
+       convert `test -f '$<' || echo '$(srcdir)/'`$< $@
+
+.svg.png:
+       convert `test -f '$<' || echo '$(srcdir)/'`$< $@
+
+.svg.pdf:
+       convert `test -f '$<' || echo '$(srcdir)/'`$< $@
 
 .fig.png:
        fig2dev -L png `test -f '$<' || echo '$(srcdir)/'`$< $@
@@ -147,10 +170,13 @@ defs.inc : defsincdate Makefile mkdefsinc
            $(gnupg_TEXINFOS) >$@
 
 
-online: gnupg.html gnupg.pdf
+online: gnupg.html gnupg.pdf gnupg-module-overview.png \
+           gnupg-card-architecture.png
        set -e; \
        echo "Uploading current manuals to www.gnupg.org ..."; \
        cp $(srcdir)/gnupg-logo-tr.png gnupg.html/; \
+       cp gnupg-module-overview.png gnupg.html/; \
+       cp gnupg-card-architecture.png gnupg.html/; \
         user=werner ; webhost="ftp.gnupg.org" ; dashdevel="" ; \
         if echo "@PACKAGE_VERSION@" | grep -- "-beta" >/dev/null; then \
          dashdevel="-devel" ; \
index 38a6fd9..2a20aad 100644 (file)
@@ -26,7 +26,7 @@ help used to be translated the usual way with gettext but it turned
 out that this is too inflexible and does for example not allow to
 correct little mistakes in the English text.  For some newer features
 we require editable help files anyway and thus the existing help
-strings have neen moved to plain text files names "help.LL.txt".  We
+strings have been moved to plain text files names "help.LL.txt".  We
 distribute these files and allow overriding them by files of that name
 in /etc/gnupg.  The syntax of these files is documented in
 doc/help.txt.  This is also the original we use to describe new
index 7965dbc..debdd40 100644 (file)
@@ -262,19 +262,30 @@ can't do anything about it without actually downloading the keys.
 
 
 @menu
-* GnuPG-1 and GnuPG-2::   Relationship between the two branches.
+* Component interaction:: How the components work together.
+* GnuPG-1 and GnuPG-2::   Relationship between GnuPG 1.4 and 2.x.
 @end menu
 
-@node GnuPG-1 and GnuPG-2
-@subsection  Relationship between the two branches.
 
-Here is a little picture showing how the components work together:
+@node Component interaction
+@subsection How the components work together.
 
-@image{gnupg-card-architecture, 10cm}
 
-@noindent
-Lets try to explain it:
+@float Figure,fig:moduleoverview
+@caption{GnuPG module overview}
+@center @image{gnupg-module-overview, 150mm,,GnuPG modules}
+@end float
+
+
+@node GnuPG-1 and GnuPG-2
+@subsection  Relationship between GnuPG 1.4 and 2.x.
+
+Here is a little picture showing how the different GnuPG versions make
+use of a smartcard:
 
-TO BE DONE.
+@float Figure,fig:cardarchitecture
+@caption{GnuPG card architecture}
+@center @image{gnupg-card-architecture, 150mm,, GnuPG card architecture}
+@end float
 
 
diff --git a/doc/gnupg-module-overview.svg b/doc/gnupg-module-overview.svg
new file mode 100644 (file)
index 0000000..5b22f0d
--- /dev/null
@@ -0,0 +1,892 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="1052.3622"
+   height="744.09448"
+   id="svg5013"
+   version="1.1"
+   inkscape:version="0.48.3.1 r9886"
+   sodipodi:docname="gnupg-module-overview.svg">
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1672"
+     inkscape:window-height="978"
+     id="namedview5247"
+     showgrid="false"
+     inkscape:zoom="1.0964545"
+     inkscape:cx="549.42213"
+     inkscape:cy="371.37197"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg5013"
+     showguides="true"
+     inkscape:guide-bbox="true">
+    <inkscape:grid
+       id="grid3097"
+       type="xygrid"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata5249">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs5015">
+    <marker
+       inkscape:stockid="Arrow2Sstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Sstart"
+       style="overflow:visible">
+      <path
+         id="path4021"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(0.3,0,0,0.3,-0.69,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow2Mend"
+       style="overflow:visible">
+      <path
+         id="path4018"
+         style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="scale(-0.6,-0.6)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Mend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="Arrow1Mend"
+       style="overflow:visible">
+      <path
+         id="path4000"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt"
+         transform="matrix(-0.4,0,0,-0.4,-4,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       orient="auto"
+       markerHeight="3"
+       markerWidth="4"
+       markerUnits="strokeWidth"
+       refY="5"
+       refX="0"
+       viewBox="0 0 10 10"
+       id="ArrowEnd">
+      <path
+         id="path5018"
+         d="M 0,0 10,5 0,10 z"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       orient="auto"
+       markerHeight="3"
+       markerWidth="4"
+       markerUnits="strokeWidth"
+       refY="5"
+       refX="10"
+       viewBox="0 0 10 10"
+       id="ArrowStart">
+      <path
+         id="path5021"
+         d="M 10,0 0,5 10,10 z"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="ArrowEndo"
+       orient="auto"
+       markerHeight="3"
+       markerWidth="4"
+       markerUnits="strokeWidth"
+       refY="5"
+       refX="0"
+       viewBox="0 0 10 10"
+       id="ArrowEndo">
+      <path
+         id="path4964"
+         d="M 0,0 10,5 0,10 z"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker6214"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Send">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path6216" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4916"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Send">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4918" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker4916-9"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow2Send">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         id="path4918-0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow2Send"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4292"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4294"
+         style="fill:#707070;fill-opacity:1;fill-rule:evenodd;stroke:#707070;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+         d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+         transform="matrix(-0.3,0,0,-0.3,0.69,0)" />
+    </marker>
+  </defs>
+  <path
+     sodipodi:nodetypes="ccc"
+     style="fill:none;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+     d="m 287.5667,471.57196 0,97.32813 125.9533,0"
+     id="path4897"
+     inkscape:connector-curvature="0" />
+  <path
+     sodipodi:nodetypes="cccc"
+     style="fill:none;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+     d="m 287.5667,378.67655 312.68618,0 307.44416,0 -0.19429,-59.6196"
+     id="path4683"
+     inkscape:connector-curvature="0" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path6223"
+     d="m 287.70069,169.03486 -0.12386,102.03147"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     sodipodi:nodetypes="cc" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path5608"
+     d="m 567.28751,169.03486 -0.12386,102.03147"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     sodipodi:nodetypes="cc" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path6212"
+     d="M 740.82251,277.66035 740.69865,174.39089"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+     d="m 523.40929,311.79252 0,124.65874"
+     id="path6073"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path6047"
+     d="m 740.69179,316.07585 0,119.95752"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path3376-9"
+     d="m 287.6031,433.13662 0,-57.34608 0,-57.34607"
+     style="fill:#707070;fill-opacity:1;fill-rule:evenodd;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+     sodipodi:nodetypes="ccc" />
+  <rect
+     style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect3352"
+     width="97.554695"
+     height="40.571972"
+     x="391.51746"
+     y="636.94879"
+     ry="13.673332"
+     rx="13.673332" />
+  <text
+     y="662.4939"
+     x="409.48114"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     id="text3354">
+    <tspan
+       id="tspan3356"
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">Keyserver</tspan>
+  </text>
+  <path
+     inkscape:connector-curvature="0"
+     id="path3378"
+     d="m 440.28156,586.50326 0,45.86759"
+     style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker4916)"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cc"
+     style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker4916)"
+     d="m 556.46073,586.50326 0,45.86759"
+     id="path3376"
+     inkscape:connector-curvature="0" />
+  <path
+     style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker4916)"
+     d="m 429.01048,170.98678 0,100.99292"
+     id="path6342"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:none;stroke:#0093dd;stroke-width:2.75242877;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+     d="m 907.57277,170.14422 0,113.50352"
+     id="path5123"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+     d="m 673.43067,568.61382 -98.4701,0"
+     id="path6243"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path6201"
+     d="m 453.30881,317.35087 0.18784,34.85336 53.29577,-0.16228 190.29392,-0.16229 0.18785,-30.27572"
+     style="fill:none;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     sodipodi:nodetypes="ccccc" />
+  <rect
+     rx="4.3253841"
+     ry="4.3253841"
+     y="276.6272"
+     x="675.82629"
+     height="40.530724"
+     width="123.10358"
+     id="rect6187"
+     style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <text
+     id="text5121"
+     transform="scale(1.0507543,0.95169727)"
+     style="font-size:13.02898884px;line-height:125%;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="674.47369"
+     y="315.29083"
+     sodipodi:linespacing="125%">
+    <tspan
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4497">gpg-agent</tspan>
+  </text>
+  <rect
+     style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect6197"
+     width="123.10358"
+     height="40.530724"
+     x="846.021"
+     y="276.6272"
+     ry="4.3253841"
+     rx="4.3253841" />
+  <rect
+     style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect6192"
+     width="123.10358"
+     height="40.530724"
+     x="675.82629"
+     y="129.8378"
+     ry="4.3253841"
+     rx="4.3253841" />
+  <path
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none"
+     d="m 498.35189,473.54808 0,75.31261"
+     id="path6069"
+     inkscape:connector-curvature="0"
+     sodipodi:nodetypes="cc" />
+  <rect
+     style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect6177"
+     width="164.51004"
+     height="40.445511"
+     x="416.09686"
+     y="548.39105"
+     ry="4.3253841"
+     rx="4.3253841" />
+  <rect
+     style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect6173"
+     width="123.10358"
+     height="40.530724"
+     x="367.47192"
+     y="276.6272"
+     ry="4.3253841"
+     rx="4.3253841" />
+  <rect
+     rx="4.3253841"
+     ry="4.3253841"
+     y="276.6272"
+     x="505.63153"
+     height="40.530724"
+     width="123.10358"
+     id="rect6168"
+     style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <rect
+     rx="13.673332"
+     ry="13.673332"
+     y="433.47479"
+     x="691.91449"
+     height="40.571972"
+     width="97.554695"
+     id="rect6083"
+     style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path6071"
+     d="m 473.29453,317.56143 0,118.88983"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none" />
+  <path
+     sodipodi:nodetypes="cc"
+     inkscape:connector-curvature="0"
+     id="path6056"
+     d="m 129.94217,317.56143 0,119.95753"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none" />
+  <rect
+     style="fill:#f0f0fc;fill-opacity:1;stroke:#0093dd;stroke-width:2.06634402;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect5612"
+     width="403.86743"
+     height="39.392567"
+     x="225.40582"
+     y="130.97597" />
+  <path
+     style="fill:none;stroke:#524646;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:0.5,0.5;stroke-dashoffset:0"
+     d="m 58.463573,227.2185 928.110467,0 0,382.29175 -928.110467,0 0,-382.29175 z"
+     id="path5025"
+     inkscape:connector-curvature="0" />
+  <text
+     id="text5061"
+     transform="scale(1.0507332,0.95171638)"
+     style="font-size:13.0976572px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="518.80000"
+     y="315.28461">
+    <tspan
+       style="font-size:13.76214409px"
+       id="tspan4513">gpgsm</tspan>
+  </text>
+  <text
+     id="text5073"
+     transform="scale(1.0507333,0.95171629)"
+     style="font-size:13.02924919px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="395.6857"
+     y="315.28461">
+    <tspan
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4515">gpg</tspan>
+  </text>
+  <rect
+     rx="13.673332"
+     ry="12.771004"
+     y="548.32782"
+     x="673.75952"
+     height="40.571972"
+     width="133.86456"
+     id="rect6095"
+     style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <text
+     id="text5105"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="680.94543"
+     y="573.11676">
+    <tspan
+       style="font-size:12.38593006px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4529">CRL/Certificate Cache</tspan>
+  </text>
+  <text
+     id="text5129"
+     transform="scale(1.0507438,0.95170678)"
+     style="font-size:13.02911949px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="830.64813"
+     y="317.11887">
+    <tspan
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4509">scdaemon</tspan>
+  </text>
+  <rect
+     style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#020202;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect5628"
+     width="67.014503"
+     height="121.84404"
+     x="103.36046"
+     y="-968.49481"
+     ry="7.6290565"
+     rx="7.6290565"
+     transform="matrix(0,1,-1,0,0,0)" />
+  <text
+     y="142.0016"
+     x="875.88068"
+     id="text5135"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica">
+    <tspan
+       id="tspan4507"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">Smartcard</tspan>
+  </text>
+  <g
+     id="g5153"
+     transform="matrix(1.3762144,0,0,1.3762144,61.101249,-38.173118)">
+    <path
+       inkscape:connector-curvature="0"
+       id="path5155"
+       d="m 19.4715,229.854 61.1008,0 c 2.6103,0 4.7291,1.919 4.7291,4.283 l 0,19.78 c 0,2.364 -2.1188,4.283 -4.7291,4.283 l -61.1008,0 c -2.6102,0 -4.729,-1.919 -4.729,-4.283 l 0,-19.78 c 0,-2.364 2.1188,-4.283 4.729,-4.283 z"
+       style="fill:#feff66;fill-rule:evenodd;stroke:#000000;stroke-width:0.283465" />
+    <text
+       id="text5157"
+       style="font-size:9.94777203px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+       x="21.563971"
+       y="247.59825">
+      <tspan
+         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+         id="tspan4517">watchgnupg</tspan>
+    </text>
+  </g>
+  <text
+     id="text5181"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="702.94672"
+     y="457.17776">
+    <tspan
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4527">Private Keys</tspan>
+  </text>
+  <text
+     id="text5199"
+     transform="scale(1.0230018,0.97751538)"
+     style="font-size:15.83039284px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="317.46622"
+     y="158.42787">
+    <tspan
+       style="font-size:16.51457214px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan5886">GPGME aware Applications</tspan>
+  </text>
+  <text
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     id="text5632"
+     x="710.88654"
+     y="153.50237">
+    <tspan
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan5634">Pinentry</tspan>
+  </text>
+  <path
+     inkscape:connector-curvature="0"
+     id="path6067"
+     d="m 567.29104,317.51986 -0.12386,226.20179"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     sodipodi:nodetypes="cc" />
+  <rect
+     rx="13.673332"
+     ry="13.673332"
+     y="433.47479"
+     x="449.57455"
+     height="40.571972"
+     width="97.554695"
+     id="rect6088"
+     style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <text
+     id="text5175"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="463.25439"
+     y="457.33569">
+    <tspan
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4521">Public Keys</tspan>
+  </text>
+  <text
+     id="text5089"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="472.05396"
+     y="572.03088">
+    <tspan
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan4523">dirmngr</tspan>
+  </text>
+  <rect
+     style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+     id="rect6111"
+     width="97.554695"
+     height="40.571972"
+     x="81.164833"
+     y="433.47479"
+     ry="13.673332"
+     rx="13.673332" />
+  <text
+     y="457.33569"
+     x="96.524628"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     id="text5163">
+    <tspan
+       id="tspan4519"
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">Log Socket</tspan>
+  </text>
+  <path
+     sodipodi:nodetypes="cc"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     d="m 429.1316,317.51986 -0.12386,226.20179"
+     id="path6179"
+     inkscape:connector-curvature="0" />
+  <path
+     sodipodi:nodetypes="cc"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     d="m 629.27326,296.76206 42.33457,0.0512"
+     id="path6203"
+     inkscape:connector-curvature="0" />
+  <g
+     id="g6225"
+     transform="matrix(1.3762144,0,0,1.3762144,118.49324,-38.173118)">
+    <rect
+       style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.40000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect6205"
+       width="89.450874"
+       height="29.450878"
+       x="78.150215"
+       y="228.74368"
+       ry="3.1429582"
+       rx="3.1429582" />
+    <g
+       id="g6207"
+       transform="matrix(1,0,0,1.0478715,-311.25716,-12.101961)">
+      <text
+         y="258.88663"
+         x="393.02432"
+         style="font-size:9.46736145px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+         transform="scale(1.0507438,0.95170677)"
+         id="text6209">
+        <tspan
+           id="tspan6211"
+           style="font-size:10px">gpgconf</tspan>
+      </text>
+    </g>
+  </g>
+  <rect
+     rx="13.673332"
+     ry="13.673332"
+     y="433.47479"
+     x="238.81912"
+     height="40.571972"
+     width="97.554695"
+     id="rect6217"
+     style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <text
+     y="457.37265"
+     x="252.14281"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     id="text6219">
+    <tspan
+       id="tspan6221"
+       style="font-size:13.76214409px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">Config Files</tspan>
+  </text>
+  <path
+     inkscape:connector-curvature="0"
+     id="path6294"
+     d="m 799.10128,296.76206 42.33458,0.0512"
+     style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.50485762, 2.75242881;stroke-dashoffset:0;marker-end:url(#marker6214)"
+     sodipodi:nodetypes="cc" />
+  <rect
+     rx="13.673332"
+     ry="13.673332"
+     y="636.94879"
+     x="507.69662"
+     height="40.571972"
+     width="97.554695"
+     id="rect3358"
+     style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+  <text
+     id="text3360"
+     style="font-size:13.69026756px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+     x="509.57916"
+     y="661.91278">
+    <tspan
+       style="font-size:12.38593006px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+       id="tspan3362">CRLs/Certificates</tspan>
+  </text>
+  <path
+     sodipodi:nodetypes="cc"
+     style="fill:#707070;fill-opacity:1;fill-rule:evenodd;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+     d="m 398.90883,378.89687 0,-59.343"
+     id="path4891"
+     inkscape:connector-curvature="0" />
+  <path
+     inkscape:connector-curvature="0"
+     id="path4893"
+     d="m 601.00042,378.89687 0,-59.343"
+     style="fill:#707070;fill-opacity:1;fill-rule:evenodd;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+     sodipodi:nodetypes="cc" />
+  <path
+     sodipodi:nodetypes="cc"
+     style="fill:#707070;fill-opacity:1;fill-rule:evenodd;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+     d="m 771.49503,378.89687 0,-59.343"
+     id="path4895"
+     inkscape:connector-curvature="0" />
+  <g
+     id="g5086"
+     transform="translate(0,-6)">
+    <rect
+       style="fill:#f0f0fc;fill-opacity:1;stroke:#0093dd;stroke-width:1.99633956;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       id="rect2987"
+       width="159.27866"
+       height="228.80177"
+       x="849.40546"
+       y="454.11374" />
+    <text
+       xml:space="preserve"
+       style="font-size:18.12819099px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Liberation Sans;-inkscape-font-specification:Liberation Sans"
+       x="913.58813"
+       y="498.23856"
+       id="text3759"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan3761"
+         x="913.58813"
+         y="498.23856"
+         style="font-size:23.30767632px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:Roboto;-inkscape-font-specification:Roboto">GnuPG</tspan></text>
+    <g
+       id="g6169"
+       transform="matrix(0.49007212,0,0,0.49007212,836.80821,295.5608)">
+      <rect
+         y="390.43344"
+         x="58.297867"
+         height="47.099998"
+         width="70"
+         id="rect3132"
+         style="fill:#0093dd;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+      <rect
+         y="371.00229"
+         x="63.037552"
+         height="19.485378"
+         width="15.009007"
+         id="rect4103"
+         style="fill:#0093dd;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+      <rect
+         y="371.22836"
+         x="108.41566"
+         height="19.239996"
+         width="15.18455"
+         id="rect4105"
+         style="fill:#0093dd;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+      <path
+         id="path6045"
+         d="m 93.922866,345.53344 c -22.46905,0.16165 -30.875,20.99835 -30.875,25.56249 6.14654,0 12.81165,0.34375 14.21875,0.34375 0.33001,0 0.39884,8e-5 0.71875,0 1.67836,-6.87024 7.86511,-11.96874 15.25,-11.96874 7.352024,0 13.507864,5.05103 15.218754,11.87499 0.38707,-1.8e-4 0.56404,0 0.96875,0 12.63916,0 14.125,0.0937 14.125,0.0937 0,0 -5.04885,-26.08179 -29.625004,-25.90624 z"
+         style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="ccsc"
+         id="path7026"
+         d="m 68.567186,370.73896 c 11.42171,-23.28824 27.43165,-20.04817 36.688924,-18.61339 0,0 -12.173084,-5.82971 -23.874214,-0.082 -11.47547,5.63682 -12.81471,18.69542 -12.81471,18.69542 z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         inkscape:connector-curvature="0" />
+      <path
+         sodipodi:nodetypes="cssscccccccccc"
+         id="path7997"
+         d="m 58.047866,413.78343 c 0,0 7.78901,-8.70131 14.0625,-11 8.1875,-3 18.1875,-2.0625 34.750004,-5.375 5.86257,-1.17251 7.6875,-2.625 16.625,-7.25 0.75499,-0.39069 5.375,-0.3125 5.375,-0.3125 l -0.375,6.25 c -10.1875,10.6875 -33.437504,16.65625 -35.375004,16.5625 19.667484,2.63843 30.165594,-7.55691 34.437504,-8.1875 -9.9375,21.125 -45.187504,20.0625 -45.187504,20.0625 20.437504,5.5625 37.062504,-2.75 37.062504,-2.75 -9.3125,15.40625 -43.687504,13.3125 -43.687504,13.3125 -3.59375,0.3125 -6.5,2.625 -6.5,2.625 l -11.0625,0.3125 -0.125,-24.25 z"
+         style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+         inkscape:connector-curvature="0" />
+    </g>
+    <text
+       id="text5079"
+       style="font-size:10.04583168px;fill:#4d4d4d;fill-rule:evenodd;stroke:none;font-family:Palatino-Roman"
+       x="958.4126"
+       y="672.75244">
+      <tspan
+         style="font-size:9px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4d4d4d;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+         id="tspan4550">2016-02-16</tspan>
+    </text>
+    <path
+       inkscape:connector-curvature="0"
+       id="path5029"
+       d="m 858.59964,575.15188 0,0 0,0 0,0 0,0 z"
+       style="fill:none;stroke:#000000;stroke-width:1.37621439" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path5031"
+       d="m 850.64237,521.64467 0,0 0,0 0,0 0,0 z"
+       style="fill:none;stroke:#000000;stroke-width:1.37621439" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path5081"
+       d="m 925.49559,530.74765 0,0 0,0 0,0 0,0 z"
+       style="fill:none;stroke:#000000;stroke-width:1.37621439" />
+    <text
+       id="text5219"
+       transform="scale(1.0657564,0.93830074)"
+       style="font-size:7.41257px;fill:#4d4d4d;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+       x="811.75702"
+       y="581.03601">
+      <tspan
+         style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4d4d4d;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+         id="tspan4544">closely linked</tspan>
+    </text>
+    <g
+       transform="translate(0,-2)"
+       id="g5069">
+      <text
+         y="611.05994"
+         x="812.3645"
+         style="font-size:7.41257px;fill:#4d4d4d;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+         transform="scale(1.0657564,0.93830074)"
+         id="text5221">
+        <tspan
+           id="tspan4546"
+           style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4d4d4d;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">Assuan protocol</tspan>
+      </text>
+      <path
+         inkscape:connector-curvature="0"
+         id="path5618"
+         d="m 865.13523,560.69899 80.92233,0.0512"
+         style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.5048576, 2.7524288;stroke-dashoffset:0;marker-end:url(#marker6214)"
+         sodipodi:nodetypes="cc" />
+    </g>
+    <path
+       sodipodi:nodetypes="cc"
+       inkscape:connector-curvature="0"
+       id="path4323"
+       d="m 865.13523,532.18831 84.92605,0"
+       style="fill:#0093dd;fill-opacity:1;fill-rule:evenodd;stroke:#0093dd;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:none" />
+    <text
+       y="510.38229"
+       x="915.55554"
+       style="font-size:10.04583168px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Palatino-Roman"
+       id="text6327">
+      <tspan
+         id="tspan6329"
+         style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4d4d4d;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">architecture</tspan>
+    </text>
+    <g
+       transform="translate(0,-2)"
+       id="g5074">
+      <text
+         y="640.84277"
+         x="811.75702"
+         style="font-size:7.41257px;fill:#4d4d4d;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+         transform="scale(1.0657564,0.93830073)"
+         id="text5217">
+        <tspan
+           id="tspan4548"
+           style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4d4d4d;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">execute/access</tspan>
+      </text>
+      <path
+         inkscape:connector-curvature="0"
+         id="path4912-6"
+         d="m 865.13523,587.99572 81.37511,0"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2.75242877;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:5.5048576, 2.7524288;stroke-dashoffset:0;marker-end:url(#marker4916)"
+         sodipodi:nodetypes="cc" />
+    </g>
+    <g
+       transform="translate(0,22.156206)"
+       id="g5053">
+      <rect
+         rx="4.3253841"
+         ry="3.3909659"
+         y="612.22021"
+         x="865.13519"
+         height="18.246916"
+         width="84.926071"
+         id="rect6354"
+         style="fill:#feff66;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.55048579;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
+      <text
+         id="text6350"
+         transform="scale(1.0657564,0.93830074)"
+         style="font-size:7.41257px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+         x="832.3197"
+         y="664.93915">
+        <tspan
+           style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+           id="tspan6352">process</tspan>
+      </text>
+      <rect
+         style="fill:#ffa44f;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.40877044;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+         id="rect6356"
+         width="84.926071"
+         height="16.446747"
+         x="865.13519"
+         y="636.65216"
+         ry="13.673332"
+         rx="6.1170168" />
+      <text
+         y="691.21802"
+         x="837.2547"
+         style="font-size:7.41257px;fill:#000000;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+         transform="scale(1.0657564,0.93830074)"
+         id="text6358">
+        <tspan
+           id="tspan6360"
+           style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;font-family:Droid Sans;-inkscape-font-specification:Droid Sans">object</tspan>
+      </text>
+    </g>
+    <g
+       transform="translate(0,-2)"
+       id="g5079">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5019"
+         d="m 865.06095,613.70189 83.42501,-0.114"
+         style="fill:#707070;fill-opacity:1;fill-rule:evenodd;stroke:#707070;stroke-width:1.37621439;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker4292)"
+         sodipodi:nodetypes="cc" />
+      <text
+         id="text5065"
+         transform="scale(1.0657564,0.93830073)"
+         style="font-size:7.41257px;fill:#4d4d4d;fill-rule:evenodd;stroke:none;font-family:Helvetica"
+         x="811.75702"
+         y="666.24689">
+        <tspan
+           style="font-size:11.00971508px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#4d4d4d;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+           id="tspan5067">configure</tspan>
+      </text>
+    </g>
+  </g>
+</svg>
index f4da9cf..2989d3b 100644 (file)
@@ -54,6 +54,32 @@ The agent is automatically started on demand by @command{gpg},
 Thus there is no reason to start it manually.  In case you want to use
 the included Secure Shell Agent you may start the agent using:
 
+@c From dkg on gnupg-devel on 2016-04-21:
+@c
+@c Here's an attempt at writing a short description of the goals of an
+@c isolated cryptographic agent:
+@c
+@c   A cryptographic agent should control access to secret key material.
+@c   The agent permits use of the secret key material by a supplicant
+@c   without providing a copy of the secret key material to the supplicant.
+@c
+@c   An isolated cryptographic agent separates the request for use of
+@c   secret key material from permission for use of secret key material.
+@c   That is, the system or process requesting use of the key (the
+@c   "supplicant") can be denied use of the key by the owner/operator of
+@c   the agent (the "owner"), which the supplicant has no control over.
+@c
+@c   One way of enforcing this split is a per-key or per-session
+@c   passphrase, known only by the owner, which must be supplied to the
+@c   agent to permit the use of the secret key material.  Another way is
+@c   with an out-of-band permission mechanism (e.g. a button or GUI
+@c   interface that the owner has access to, but the supplicant does not).
+@c
+@c   The rationale for this separation is that it allows access to the
+@c   secret key to be tightly controled and audited, and it doesn't permit
+@c   the the supplicant to either copy the key or to override the owner's
+@c   intentions.
+
 @example
 gpg-connect-agent /bye
 @end example
@@ -243,9 +269,15 @@ debugger.
 This option inhibits the use of the very secure random quality level
 (Libgcrypt’s @code{GCRY_VERY_STRONG_RANDOM}) and degrades all request
 down to standard random quality.  It is only used for testing and
-shall not be used for any production quality keys.  This option is
+should not be used for any production quality keys.  This option is
 only effective when given on the command line.
 
+On GNU/Linux, another way to quickly generate insecure keys is to use
+@command{rngd} to fill the kernel's entropy pool with lower quality
+random data.  @command{rngd} is typically provided by the
+@command{rng-tools} package.  It can be run as follows: @samp{sudo
+rngd -f -r /dev/urandom}.
+
 @item --debug-pinentry
 @opindex debug-pinentry
 This option enables extra debug information pertaining to the
@@ -297,11 +329,13 @@ accept Root-CA keys.
 This option allows the use of @command{gpg-preset-passphrase} to seed the
 internal cache of @command{gpg-agent} with passphrases.
 
-@anchor{option --allow-loopback-pinentry}
+@anchor{option --no-allow-loopback-pinentry}
+@item --no-allow-loopback-pinentry
 @item --allow-loopback-pinentry
+@opindex no-allow-loopback-pinentry
 @opindex allow-loopback-pinentry
-Allow clients to use the loopback pinentry features; see the option
-@option{pinentry-mode} for details.
+Disallow or allow clients to use the loopback pinentry features; see
+the option @option{pinentry-mode} for details.  Allow is the default.
 
 @item --no-allow-external-cache
 @opindex no-allow-external-cache
@@ -1423,7 +1457,7 @@ following values are defined:
   Use a loopback pinentry.  This fakes a pinentry by using inquiries
   back to the caller to ask for a passphrase.  This option may only be
   set if the agent has been configured for that.
-  Use the @xref{option --allow-loopback-pinentry}.
+  To disable this feature use @xref{option --no-allow-loopback-pinentry}.
 
   @end table
 
index e1835cf..3cad361 100644 (file)
 @cindex command options
 @cindex options, GPG command
 
-@macro gpgname
-gpg2
-@end macro
+
+@c Begin standard stuff
+@ifclear gpgtwohack
+@manpage gpg.1
+@ifset manverb
+.B gpg
+\- OpenPGP encryption and signing tool
+@end ifset
+
+@mansect synopsis
+@ifset manverb
+.B  gpg
+.RB [ \-\-homedir
+.IR dir ]
+.RB [ \-\-options
+.IR file ]
+.RI [ options ]
+.I command
+.RI [ args ]
+@end ifset
+@end ifclear
+@c End standard stuff
+
+@c Begin gpg2 hack stuff
+@ifset gpgtwohack
 @manpage gpg2.1
 @ifset manverb
 .B gpg2
@@ -31,6 +53,8 @@ gpg2
 .I command
 .RI [ args ]
 @end ifset
+@end ifset
+@c End gpg2 hack stuff
 
 
 @mansect description
@@ -40,17 +64,21 @@ OpenPGP standard. @command{@gpgname} features complete key management and
 all bells and whistles you can expect from a decent OpenPGP
 implementation.
 
-In contrast to the standalone command gpg from GnuPG 1.x, which is
+@ifclear gpgtwohack
+Note that this version of GnuPG features all modern algorithms and
+should thus be preferred over older GnuPG versions.  If you are
+looking for version 1 of GnuPG, you may find that version installed
+under the name @command{gpg1}.
+@end ifclear
+@ifset gpgtwohack
+In contrast to the standalone command gpg from GnuPG 1.x, which
 might be better suited for server and embedded platforms, the 2.x
-version is commonly installed under the name @command{gpg2} and
+version is commonly installed under the name @command{@gpgname} and
 targeted to the desktop as it requires several other modules to be
 installed.
+@end ifset
 
 @manpause
-The old 1.x version will be kept maintained and it is possible to
-install both versions on the same system.  Documentation for the old
-GnuPG 1.x command is available as a man page and at
-@inforef{Top,GnuPG 1,gpg}.
 
 @xref{Option Index}, for an index to @command{@gpgname}'s commands and options.
 @mancont
@@ -448,7 +476,8 @@ only LDAP supports them all.
 @opindex fetch-keys
 Retrieve keys located at the specified URIs. Note that different
 installations of GnuPG may support different protocols (HTTP, FTP,
-LDAP, etc.)
+LDAP, etc.).  When using HTTPS the system provided root certificates
+are used by this command.
 
 @item --update-trustdb
 @opindex update-trustdb
@@ -538,8 +567,8 @@ Use the source, Luke :-). The output format is still subject to change.
 Pack or unpack an arbitrary input into/from an OpenPGP ASCII armor.
 This is a GnuPG extension to OpenPGP and in general not very useful.
 
-@item --tofu-set-policy @code{auto|good|unknown|bad|ask}  @code{key...}
-@opindex tofu-set-policy
+@item --tofu-policy @code{auto|good|unknown|bad|ask}  @code{key...}
+@opindex tofu-policy
 Set the TOFU policy for all the bindings associated with the specified
 keys.  For more information about the meaning of the policies,
 @pxref{trust-model-tofu}.  The keys may be specified either by their
@@ -666,7 +695,8 @@ line.
   Make a trust signature. This is a signature that combines the notions
   of certification (like a regular signature), and trust (like the
   "trust" command). It is generally only useful in distinct communities
-  or groups.
+  or groups.  For more information please read the sections
+  ``Trust Signature'' and ``Regular Expression'' in RFC-4880.
 @end table
 
 @c man:.RS
@@ -944,9 +974,12 @@ Directly sign a key from the passphrase without any further user
 interaction.  The @code{fpr} must be the verified primary fingerprint
 of a key in the local keyring. If no @code{names} are given, all
 useful user ids are signed; with given [@code{names}] only useful user
-ids matching one of theses names are signed.  The command
-@option{--quick-lsign-key} marks the signatures as non-exportable.  If
-such a non-exportable signature already exists the
+ids matching one of theses names are signed.  By default, or if a name
+is prefixed with a '*', a case insensitive substring match is used.
+If a name is prefixed with a '=' a case sensitive exact match is done.
+
+The command @option{--quick-lsign-key} marks the signatures as
+non-exportable.  If such a non-exportable signature already exists the
 @option{--quick-sign-key} turns it into a exportable signature.
 
 This command uses reasonable defaults and thus does not provide the
@@ -1227,10 +1260,12 @@ the opposite meaning. The options are:
 @itemx --disable-large-rsa
 @opindex enable-large-rsa
 @opindex disable-large-rsa
-With --gen-key and --batch, enable the creation of larger RSA secret
-keys than is generally recommended (up to 8192 bits).  These large
-keys are more expensive to use, and their signatures and
-certifications are also larger.
+With --gen-key and --batch, enable the creation of RSA secret keys as
+large as 8192 bit.  Note: 8192 bit is more than is generally
+recommended.  These large keys don't significantly improve security,
+but they are more expensive to use, and their signatures and
+certifications are larger.  This option is only available if the
+binary was build with large-secmem support.
 
 @item --enable-dsa2
 @itemx --disable-dsa2
@@ -1565,6 +1600,10 @@ mechanisms, in the order they are to be tried:
   Locate a key using DANE, as specified
   in draft-ietf-dane-openpgpkey-05.txt.
 
+  @item wkd
+  Locate a key using the Web Key Directory protocol.
+  This is an experimental method and semantics may change.
+
   @item ldap
   Using DNS Service Discovery, check the domain in question for any LDAP
   keyservers to use.  If this fails, attempt to locate the key using the
@@ -1775,7 +1814,7 @@ This is dummy option. @command{@gpgname} always requires the agent.
 
 @item --gpg-agent-info
 @opindex gpg-agent-info
-This is dummy option. It has no effect when used with @command{gpg2}.
+This is dummy option. It has no effect when used with @command{@gpgname}.
 
 
 @item --agent-program @var{file}
@@ -2200,6 +2239,11 @@ Print the ICAO spelling of the fingerprint in addition to the hex digits.
 @opindex with-keygrip
 Include the keygrip in the key listings.
 
+@item --with-wkd-hash
+@opindex with-wkd-hash
+Print a Web Key Directory indentifier along with each user ID in key
+listings.  This is an experimental feature and semantics may change.
+
 @item --with-secret
 @opindex with-secret
 Include info about the presence of a secret key in public key listings
@@ -3392,7 +3436,7 @@ for @samp{Subkey-Type}.
 
 @item Key-Length: @var{nbits}
 The requested length of the generated key in bits.  The default is
-returned by running the command @samp{gpg2 --gpgconf-list}.
+returned by running the command @samp{@gpgname --gpgconf-list}.
 
 @item Key-Grip: @var{hexstring}
 This is optional and used to generate a CSR or certificate for an
@@ -3415,7 +3459,7 @@ can be handled.  See also @samp{Key-Type} above.
 
 @item Subkey-Length: @var{nbits}
 Length of the secondary key (subkey) in bits.  The default is returned
-by running the command @samp{gpg2 --gpgconf-list}".
+by running the command @samp{@gpgname --gpgconf-list}".
 
 @item Subkey-Usage: @var{usage-list}
 Key usage lists for a subkey; similar to @samp{Key-Usage}.
@@ -3494,9 +3538,9 @@ $ cat >foo <<EOF
      %commit
      %echo done
 EOF
-$ gpg2 --batch --gen-key foo
+$ @gpgname --batch --gen-key foo
  [...]
-$ gpg2 --no-default-keyring --secret-keyring ./foo.sec \
+$ @gpgname --no-default-keyring --secret-keyring ./foo.sec \
        --keyring ./foo.pub --list-secret-keys
 /home/wk/work/gnupg-stable/scratch/foo.sec
 ------------------------------------------
index 2bcbec5..b585975 100644 (file)
@@ -737,11 +737,33 @@ This is actually not a debugging option but only useful as such.  It
 lets @command{gpgsm} ignore all notAfter dates, this is used by the regression
 tests.
 
-@item --fixed-passphrase @var{string}
-@opindex fixed-passphrase
-Supply the passphrase @var{string} to the gpg-protect-tool.  This
-option is only useful for the regression tests included with this
-package and may be revised or removed at any time without notice.
+@item --passphrase-fd @code{n}
+@opindex passphrase-fd
+Read the passphrase from file descriptor @code{n}. Only the first line
+will be read from file descriptor @code{n}. If you use 0 for @code{n},
+the passphrase will be read from STDIN. This can only be used if only
+one passphrase is supplied.
+
+Note that this passphrase is only used if the option @option{--batch}
+has also been given.
+
+@item --pinentry-mode @code{mode}
+@opindex pinentry-mode
+Set the pinentry mode to @code{mode}.  Allowed values for @code{mode}
+are:
+@table @asis
+  @item default
+  Use the default of the agent, which is @code{ask}.
+  @item ask
+  Force the use of the Pinentry.
+  @item cancel
+  Emulate use of Pinentry's cancel button.
+  @item error
+  Return a Pinentry error (``No Pinentry'').
+  @item loopback
+  Redirect Pinentry queries to the caller.  Note that in contrast to
+  Pinentry the user is not prompted again if he enters a bad password.
+@end table
 
 @item --no-common-certs-import
 @opindex no-common-certs-import
index 280966b..1d9a81e 100644 (file)
@@ -8,11 +8,8 @@
 
 @include defs.inc
 
-@c Begin GnuPG 1.x specific stuff
-@ifset gpgone
-@macro gpgvname
-gpgv
-@end macro
+@c Begin standard stuff
+@ifclear gpgtwohack
 @manpage gpgv.1
 @node gpgv
 @section Verify OpenPGP signatures
@@ -27,14 +24,11 @@ gpgv
 .RI [ options ]
 .I signed_files
 @end ifset
-@end ifset
-@c End GnuPG 1.x specific stuff
+@end ifclear
+@c End standard stuff
 
-@c Begin GnuPG 2 specific stuff
-@ifclear gpgone
-@macro gpgvname
-gpgv2
-@end macro
+@c Begin gpg2 hack stuff
+@ifset gpgtwohack
 @manpage gpgv2.1
 @node gpgv
 @section Verify OpenPGP signatures
@@ -49,10 +43,8 @@ gpgv2
 .RI [ options ]
 .I signed_files
 @end ifset
-@end ifclear
-@c End GnuPG 2 specific stuff
-
-
+@end ifset
+@c End gpg2 hack stuff
 
 @mansect description
 @code{@gpgvname} is an OpenPGP signature verification tool.
index bd4ae14..5a98cb3 100644 (file)
@@ -1,5 +1,6 @@
-# help.ru.txt - ru GnuPG online help
+# help.ru.txt - Russian GnuPG online help
 # Copyright (C) 2007 Free Software Foundation, Inc.
+# Copyright (C) 2016 Ineiev <ineiev@gnu.org> (translation)
 #
 # This file is part of GnuPG.
 #
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
-# 
+#
 # GnuPG is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-# 
+#
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
+# The translated revision was taken from HEAD b8bb16c6c08d3c2947f1ff67
+# which is the same as the revision from STABLE-BRANCH-2-0 776bee6d370
+
+.#pinentry.qualitybar.tooltip
+# [remove the hash mark from the key to enable this text]
+# This entry is just an example on how to customize the tooltip shown
+# when hovering over the quality bar of the pinentry.  We don't
+# install this text so that the hardcoded translation takes
+# precedence.  An administrator should write up a short help to tell
+# the users about the configured passphrase constraints and save that
+# to /etc/gnupg/help.txt.  The help text should not be longer than
+# about 800 characters.
+Этот индикатор показывает качество введенной выше фразы-пароля.
+
+Пока индикатор красный, GnuPG считает фразу-пароль неприемлемо слабой.
+Уточните у своего администратора принятые требования к фразе-паролю.
+.
+
+
+.gnupg.agent-problem
+# There was a problem accessing or starting the agent.
+К запущенному Gpg-Agent было невозможно подключиться, либо возникла
+проблема соединения с ним.
+
+Система использует фоновый процесс под названием Gpg-Agent
+для обработки секретных ключей и запроса фраз-паролей. Обычно процесс
+запускается при входе пользователя в систему и работает, пока
+пользователь не выйдет. Если процесс недоступен, система пытается
+запустить его на ходу, но функции этой версий несколько ограничены,
+это может привести к небольшим проблемам.
+
+Вероятно, для решения проблемы нужно обратиться к администратору.
+В качестве временной меры можно выйти и снова войти в систему;
+может быть, это поможет. В любом случае сообщите об этом
+администратору, потому что это указывает на недочет в программе.
+.
+
+
+.gnupg.dirmngr-problem
+# There was a problen accessing the dirmngr.
+К запущенному Dirmngr было невозможно подключиться, либо возникла
+проблема соединения с ним.
+
+Для просмотра списков отзыва сертификатов во время проверки
+сертификатов и для поиска ключей на локальных серверах система
+пользуется внешней служебной программой Dirmngr. Обычно она работает
+как системная служба (демон) и не нуждается в каких-либо действиях
+со стороны пользователя. В случае проблем система может запускать
+новую копию Dirmngr по каждому запросу; это запасной вариант
+с ухудшенными характеристиками.
+
+Если Вы столкнулись с этой проблемой, обратитесь к системному
+администратору. В качестве временного решения можно попробовать
+отключить проверку списков отзыва сертификатов в настройках gpgsm.
+.
+
 
 .gpg.edit_ownertrust.value
-Вы должны ввести здесь значение; оно никогда не будет экспортировано
-третьей стороне.  Это необходимо для реализации Сети Доверия;
-и не имеет ничего общего с (неявно созданной) сетью сертификатов.
+# The help identies prefixed with "gpg." used to be hard coded in gpg
+# but may now be overridden by help texts from this file.
+Если хотите, поставьте здесь значение; оно никогда не будет выводиться
+для третьих сторон. Нам оно нужно для реализации сети доверия; оно
+никак не связано с (неявно создаваемой) сетью сертификатов.
 .
 
 .gpg.edit_ownertrust.set_ultimate.okay
-Для построения Сети Доверия, GnuPG должен знать, к каким ключам
-имеется абсолютное доверие - обычно это ключи для которых у Вас есть
-секретный ключ.  Ответьте "yes" для присвоения абсолютного доверия
-данному ключу
+Для построения Сети доверия GnuPG нужно знать, каким ключам доверять
+полностью - обычно это ключи, секретные части которых у Вас есть.
+Ответ "да" установит полное доверие этому ключу.
 
-.
 
 .gpg.untrusted_key.override
-Если хотите использовать данный недоверяемый ключ - ответьте "yes".
+Если Вы хотите все равно пользоваться этим недоверенным ключом,
+ответьте "да".
 .
 
 .gpg.pklist.user_id.enter
-Введите User ID адресата, которому хотите отправить сообщение.
+Введите ID пользователя - получателя Вашего сообщения.
 .
 
 .gpg.keygen.algo
 Выберите алгоритм.
 
-DSA (aka DSS) - Digital Signature Algorithm может использоваться
-только для подписей.
+DSA (он же DSS) можно применять только для подписей.
 
-Elgamal - алгоритм используемый только для шифрования.
+Elgamal - алгоритм только для шифрования.
 
-RSA Ð¼Ð¾Ð¶ÐµÑ\82 Ð¸Ñ\81полÑ\8cзоваÑ\82Ñ\8cÑ\81Ñ\8f Ð¸ Ð´Ð»Ñ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81и, Ð¸ Ð´Ð»Ñ\8f Ñ\88иÑ\84Ñ\80ованиÑ\8f.
+RSA Ð¼Ð¾Ð¶Ð½Ð¾ Ð¿Ñ\80именÑ\8fÑ\82Ñ\8c Ð´Ð»Ñ\8f Ñ\88иÑ\84Ñ\80ованиÑ\8f Ð¸Ð»Ð¸ Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей.
 
\9fеÑ\80вÑ\8bй (он Ð¶Ðµ Ð³Ð»Ð°Ð²Ð½Ñ\8bй) ÐºÐ»Ñ\8eÑ\87 Ð²Ñ\81егда Ð´Ð¾Ð»Ð¶ÐµÐ½ Ð±Ñ\8bÑ\82Ñ\8c Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8bваÑ\8eÑ\89им.
\9fеÑ\80вÑ\8bй (пеÑ\80виÑ\87нÑ\8bй) ÐºÐ»Ñ\8eÑ\87 Ð²Ñ\81егда Ð´Ð¾Ð»Ð¶ÐµÐ½ Ð±Ñ\8bÑ\82Ñ\8c Ð¿Ñ\80игоден Ð´Ð»Ñ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей.
 .
 
+
 .gpg.keygen.algo.rsa_se
-Обычно не рекомендуется использовать один ключ и для подписи, и для шифрования.
-Данный алгоритм следует использовтаь только в некоторых случаях.
-Проконсультируйтесь с Вашим экспертом по безопасности перед тем,
-как использовать данный ключ.
+В целом неразумно пользоваться одним и тем же ключом и для подписи,
+и для шифрования. Это может быть полезно только в определенных
+случаях. Проконсультируйтесь со своим экспертом по безопасности.
+.
+
+
+.gpg.keygen.flags
+Поменять функции ключа.
+
+Переключать можно только функции, доступные для выбранного
+алгоритма.
+
+Для быстрой установки сразу всех возможностей введите сначала '=',
+а за ним список букв, задающих набор функций: '1' - подпись, '2' -
+шифрование, '3' - аутентификация. Неправильные буквы и функции
+не учитываются. Сразу после быстрого ввода это подменю закрывается.
 .
 
+
 .gpg.keygen.size
-Введите размер ключа
+Введите размер ключа.
+
+Предлагаемое значение обычно хорошо подходит.
+
+Если Вам нужен ключ большого размера, например, 4096 бит, подумайте,
+действительно ли это для Вас имеет смысл. См. комикс на странице
+http://www.xkcd.com/538/ .
 .
 
 .gpg.keygen.size.huge.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
+
 .gpg.keygen.size.large.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
+
 .gpg.keygen.valid
-Введите требуемое значение, как показано в подсказке.
\9cожно Ð²Ð²ÐµÑ\81Ñ\82и Ð´Ð°Ñ\82Ñ\83 Ð² ISO Ñ\84оÑ\80маÑ\82е (YYYY-MM-DD), Ð½Ð¾ Ð\92Ñ\8b Ð½Ðµ Ð¿Ð¾Ð»Ñ\83Ñ\87иÑ\82е
-уведомление при ошибке в формате - вместо этого система попробует
¸Ð½Ñ\82еÑ\80пÑ\80еÑ\82иÑ\80оваÑ\82Ñ\8c Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ð¾Ðµ Ð·Ð½Ð°Ñ\87ение ÐºÐ°Ðº Ð¸Ð½Ñ\82еÑ\80вал.
+Введите нужное значение, как показано в приглашении.
\9cожно Ð²Ð²ÐµÑ\81Ñ\82и Ð´Ð°Ñ\82Ñ\83 Ð\98СÐ\9e (Ð\93Ð\93Ð\93Ð\93\9cÐ\9c\94Ð\94), Ð½Ð¾ Ñ\81ообÑ\89ениÑ\8f Ð¾Ð± Ð¾Ñ\88ибкаÑ\85 Ð±Ñ\83дÑ\83Ñ\82
+неудобочитаемыми: система пытается интерпретировать данное значение
+как интервал.
 .
 
 .gpg.keygen.valid.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
+
 .gpg.keygen.name
-Введите имя владельца ключа
+Введите имя владельца ключа.
+Символы "<" и ">" недопустимы.
+Пример: Вася Пушкин
 .
 
+
 .gpg.keygen.email
-введите необязательный, но очень рекомендуемый email адрес
+Введите, пожалуйста, адрес электронной почты (необязательно,
+но очень рекомендуется).
+Пример: vp@test.ru
 .
 
 .gpg.keygen.comment
-Введите необязательный комментарий
+Введите, пожалуйста, необязательное примечание.
+Символы "(" и ")" недопустимы.
+В общем и целом оно не нужно.
 .
 
+
 .gpg.keygen.userid.cmd
-N  изменить имя.
-C  изменить комментарий.
-E  изменить email адрес.
+# (Keep a leading empty line)
+
+N  сменить имя.
+C  сменить примечание.
+E  сменить адрес.
 O  продолжить создание ключа.
-Q  Ð²Ñ\8bйÑ\82и Ð¸ Ð¿Ñ\80еÑ\80вать создание ключа.
+Q  Ð¿Ñ\80екÑ\80аÑ\82ить создание ключа.
 .
 
 .gpg.keygen.sub.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" (или Ñ\82олÑ\8cко "y"), ÐµÑ\81ли Ð³Ð¾Ñ\82овÑ\8b Ñ\81оздаваÑ\82Ñ\8c Ð¿Ð¾Ð´ÐºÐ»Ñ\8eÑ\87.
\92ведиÑ\82е "да" (или "y"), Ñ\87Ñ\82обÑ\8b Ñ\80азÑ\80еÑ\88иÑ\82Ñ\8c Ñ\81оздание ÐºÐ»Ñ\8eÑ\87а.
 .
 
 .gpg.sign_uid.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
 .gpg.sign_uid.class
\9fеÑ\80ед Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8bванием User ID ÐºÐ»Ñ\8eÑ\87а, Ñ\81ледÑ\83еÑ\82 Ð¿Ñ\80ежде Ñ\83доÑ\81Ñ\82овеÑ\80иÑ\82Ñ\8cÑ\81Ñ\8f, Ñ\87Ñ\82о
-ключ действительно принадлежит человеку указанному в User ID. Это очень важно
´Ð»Ñ\8f Ñ\82еÑ\85, ÐºÑ\82о Ñ\83Ñ\87иÑ\82Ñ\8bваеÑ\82 ÐºÐ°Ðº Ñ\85оÑ\80оÑ\88о Ð\92Ñ\8b Ð¿Ñ\80овеÑ\80Ñ\8fеÑ\82е Ð´Ð¾Ñ\81Ñ\82овеÑ\80ноÑ\81Ñ\82Ñ\8c User ID.
\9aогда Ð\92Ñ\8b Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8bваеÑ\82е Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f Ð² ÐºÐ»Ñ\8eÑ\87е, Ð½Ñ\83жно Ñ\81наÑ\87ала
+удостовериться, что ключ принадлежит указанному в идентификаторе лицу.
\94Ñ\80Ñ\83гим Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ Ð·Ð½Ð°Ñ\82Ñ\8c, Ð½Ð°Ñ\81колÑ\8cко Ñ\82Ñ\89аÑ\82елÑ\8cно Ð\92Ñ\8b Ñ\8dÑ\82о Ð¿Ñ\80овеÑ\80или.
 
-"0" означает, что Вы не можете сказать, как хорошо Вы проверили ключ.
-"1" означает, что Вы полагаете, что ключ принадлежит человеку, который
-    указан в нем, но Вы не могли или не проводили проверку ключа совсем.
-    Это полезно, когда Вы подписываете ключ с псевдонимом человека.
+"0" значит, что Вы не указываете, насколько тщательно вы проверяли ключ.
 
-"2" означает, что Вы делали неаккуратную проверку ключа.  Например, это может
-    Ð¾Ð·Ð½Ð°Ñ\87аÑ\82Ñ\8c, Ñ\87Ñ\82о Ð\92Ñ\8b Ð¿Ñ\80овеÑ\80или Ð¾Ñ\82пеÑ\87аÑ\82ок ÐºÐ»Ñ\8eÑ\87а Ð¸ Ð¿Ñ\80овеÑ\80или User ID Ð½Ð°
-    ключе на основании фото ID.
+"1" значит, что Вы считаете, что ключ принадлежит заявленному лицу, но Вы
+    Ð½Ðµ Ð¼Ð¾Ð³Ð»Ð¸ Ð¿Ñ\80овеÑ\80иÑ\82Ñ\8c Ð¸Ð»Ð¸ Ð½Ðµ Ð¿Ñ\80овеÑ\80Ñ\8fли ÐºÐ»Ñ\8eÑ\87. Ð­Ñ\82о Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ Ð´Ð»Ñ\8f Ð¿Ñ\80овеÑ\80ки
+    "инкогнито", когда вы подписываете ключ с псевдонимом.
 
-"3" означает, что Вы выполнили всестороннюю проверку ключа.  Например, это может
-    означать, что Вы сверили отпечаток ключа с владельцем ключа лично
-    и что Вы сверили всё посредством трудноподделываемого документа с
-    фотографией (таким как паспорт), что имя владельца ключа совпадает с
-    именем в User ID ключа и наконец, что Вы проверили (обменом шифрованными
-    письмами), что email адрес на ключе принадлежит владельцу ключа.
+"2" значит, что Вы провели частичную проверку ключа. Например, проверили
+    отпечаток ключа и идентификатор пользователя из ключа
+    по фотоидентификатору.
 
-Учтите, что примеры данные для уровней 2 и 3 - только примеры.
-В конечном итоге, Вам решать, как классифицировать "неаккуратно" и "всесторонне",
-при подписывании чужих ключей.
+"3" значит, что Вы провели тщательную проверку ключа. Например,
+    Вы проверили отпечаток ключа, а также проверили по удостоверению
+    личности (такому как паспорт), что имя владельца ключа совпадает
+    с именем человека, записанным в идентификаторе пользователя ключа;
+    наконец, Вы удостоверились (обменявшись электронной почтой), что
+    адрес электронной почты принадлежит владельцу ключа.
 
-Если Вы не можете определиться с правильным ответом, ответьте "0".
+Имейте в виду, что примеры, данные для уровней 2 и 3 - это *только*
+примеры. В конечном счете Вы сами решаете, что значит "частичная"
+и "тщательная" проверка, когда Вы подписываете другие ключи.
+
+Если затрудняетесь с ответом, поставьте "0".
 .
 
 .gpg.change_passwd.empty.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
+
 .gpg.keyedit.save.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
+
 .gpg.keyedit.cancel.okay
\9eÑ\82веÑ\82Ñ\8cÑ\82е "yes" Ð¸Ð»Ð¸ "no"
\9eÑ\82веÑ\87айÑ\82е "да" Ð¸Ð»Ð¸ "неÑ\82".
 .
 
 .gpg.keyedit.sign_all.okay
-Ответьте "yes", если хотите подписать ВСЕ User ID
+Ответьте "да", если хотите подписать ВСЕ идентификаторы пользователя.
 .
 
 .gpg.keyedit.remove.uid.okay
-Ответьте "yes", если действительно хотите удалить данный User ID.
-Все сертификаты также будут потеряны!
+Ответьте "да", если действительно хотите удалить этот идентификатор
+пользователя.
+Все сертификаты будут также удалены!
 .
 
 .gpg.keyedit.remove.subkey.okay
-Ответьте "yes", если готовы удалить подключ
+Ответьте "да", если подключ можно удалить.
 .
 
+
 .gpg.keyedit.delsig.valid
-ЭÑ\82о Ð´ÐµÐ¹Ñ\81Ñ\82виÑ\82елÑ\8cнаÑ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c Ð½Ð° ÐºÐ»Ñ\8eÑ\87е; Ð¾Ð±Ñ\8bÑ\87но Ð½Ðµ Ð¶ÐµÐ»Ð°Ñ\82елÑ\8cно
-удалять такие подписи, потому, что она может быть важна для установления
-достоверности ключа или других ключей подписанных данным ключом.
+ЭÑ\82о Ð²ÐµÑ\80наÑ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c ÐºÐ»Ñ\8eÑ\87а; ÐºÐ°Ðº Ð¿Ñ\80авило, ÐµÐµ Ð½Ðµ Ð½Ñ\83жно Ñ\83далÑ\8fÑ\82Ñ\8c,
+поскольку может быть важно установить отношение доверия между
+этим ключом и другими ключами.
 .
 
 .gpg.keyedit.delsig.unknown
-Данная подпись не может быть проверена потому, что Вы не имеете
-соответствующего ключа.  Можете отложить ее удаление, пока не
-узнаете, какой ключ был использован, т.к. эта подпись может
-устанавливать достоверность через другие уже удостоверенные ключи.
+Эту подпись нельзя проверить, поскольку отсутствует соответствующий
+ключ. Удаление ее нужно отложить до тех пор, пока не станет
+известно, какой из ключей был использован, так как подпись
+этого ключа могло бы установить отношение доверия через
+другой, уже сертифицированный ключ.
 .
 
 .gpg.keyedit.delsig.invalid
-Подпись недействительна.  Это дает основания удалить ее из
-связки ключей.
+Подпись недействительна. Имеет смысл удалить ее из Вашей таблицы
+ключей.
 .
 
 .gpg.keyedit.delsig.selfsig
-Данная подпись является самоподписью и привязывает User ID к ключу.
-Обычно это плохая идея удалить такую подпись.  На самом деле
-GnuPG может не позволить использовать такой ключ далее.
-Делайте это только если данная самоподпись не действительна по
-каким-либо причинам и существует доступная вторая.
+Эта подпись связывает идентификатор пользователя с ключом. Обычно
+удалять такие подписи не следует. Это может сделать ключ непригодным
+для пользования с GnuPG. Так что делайте это только если эта
+самоподпись по какой-то причине недействительна и есть другая.
 .
 
 .gpg.keyedit.updpref.okay
\98зменение Ð¿Ñ\80едпоÑ\87Ñ\82ений Ð´Ð»Ñ\8f Ð²Ñ\81еÑ\85 User ID (или Ñ\82олÑ\8cко Ð´Ð»Ñ\8f Ð²Ñ\8bбÑ\80аннÑ\8bÑ\85)
-на текущий список предпочтений.  Отметка времени на всех затронутых
-самоподписях будет увеличена на одну секунду.
-
\98змениÑ\82Ñ\8c Ð¿Ñ\80едпоÑ\87Ñ\82ениÑ\8f Ð´Ð»Ñ\8f Ð²Ñ\81еÑ\85 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80ов Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f (или
+только для выбранных) на текущий список предпочтений. Дата всех
+самоподписей, которых это касается, будет сдвинута вперед
+на одну секунду.
 .
 
+
 .gpg.passphrase.enter
-Введите фразу-пароль (это секретная строка) 
+# (keep a leading empty line)
 
+Введите, пожалуйста, фразу-пароль (секретное предложение).
 .
 
+
 .gpg.passphrase.repeat
-Повторите фразу-пароль, чтобы убедиться в том, что она набрана правильно.
+Повторите введенную фразу-пароль, чтобы проверить, что Вы не ошиблись.
 .
 
 .gpg.detached_signature.filename
\92ведиÑ\82е Ð¸Ð¼Ñ\8f Ñ\84айла, Ðº ÐºÐ¾Ñ\82оÑ\80омÑ\83 Ð¾Ñ\82ноÑ\81иÑ\82Ñ\81Ñ\8f Ð´Ð°Ð½Ð½Ð°Ñ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c
\97адайÑ\82е Ð¸Ð¼Ñ\8f Ñ\84айла, ÐºÐ¾Ñ\82оÑ\80Ñ\8bй Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8bваеÑ\82Ñ\81Ñ\8f.
 .
 
 .gpg.openfile.overwrite.okay
-Ответьте "yes", если хотите перезаписать файл
+# openfile.c (overwrite_filep)
+Ответьте "да", если файл можно перезаписать.
 .
 
 .gpg.openfile.askoutname
-Введите новое имя файла. Если нажмете только RETURN будет использован
-по умолчанию тот файл, который показан в квадратных скобках.
+# openfile.c (ask_outfile_name)
+Введите новое имя файла. Если просто нажать "Enter", будет
+использован файл по умолчанию (указан в скобках).
 .
 
 .gpg.ask_revocation_reason.code
-Сейчас сможете указать причину отзыва ключа.  Основываясь на 
ºÐ¾Ð½Ñ\82екÑ\81Ñ\82е Ð¾Ñ\82зÑ\8bва - Ð¼Ð¾Ð¶ÐµÑ\82е Ð²Ñ\8bбÑ\80аÑ\82Ñ\8c Ð¾Ð´Ð¸Ð½ Ð¸Ð· Ñ\81ледÑ\83Ñ\8eÑ\89иÑ\85 Ð²Ð°Ñ\80ианÑ\82ов:
-  "Ð\9aлÑ\8eÑ\87 Ð±Ñ\8bл Ñ\81компÑ\80омеÑ\82иÑ\80ован"
-      Ð\92Ñ\8bбеÑ\80иÑ\82е, ÐµÑ\81ли Ð¿Ñ\80едполагаеÑ\82е, Ñ\87Ñ\82о Ð¿Ð¾Ñ\81Ñ\82оÑ\80онний Ñ\87еловек
-      Ð¿Ð¾Ð»Ñ\83Ñ\87ил Ð´Ð¾Ñ\81Ñ\82Ñ\83п Ðº Ð\92аÑ\88емÑ\83 секретному ключу.
+# revoke.c (ask_revocation_reason)
\9dÑ\83жно Ñ\83казаÑ\82Ñ\8c Ð¿Ñ\80иÑ\87инÑ\83 Ð¾Ñ\82зÑ\8bва. Ð\9cожно Ð²Ñ\8bбÑ\80аÑ\82Ñ\8c Ð¸Ð· Ñ\81пиÑ\81ка:
+  "Ð\9aлÑ\8eÑ\87 Ð±Ñ\8bл Ñ\80аÑ\81кÑ\80Ñ\8bÑ\82"
+      Ð\95Ñ\81Ñ\82Ñ\8c Ð¾Ñ\81нованиÑ\8f Ð¿Ð¾Ð»Ð°Ð³Ð°Ñ\82Ñ\8c, Ñ\87Ñ\82о ÐºÐ°ÐºÐ¸Ðµ-Ñ\82о Ð»Ð¸Ñ\86а Ð¿Ð¾Ð»Ñ\83Ñ\87или
+      Ð½ÐµÑ\81анкÑ\86иониÑ\80ованнÑ\8bй Ð´Ð¾Ñ\81Ñ\82Ñ\83п Ðº секретному ключу.
   "Ключ заменен другим"
-      Выберите, если заменяете данный ключ на другой.
+      Вы заменили ключ на новый.
   "Ключ больше не используется"
-      Выберите, если отказываетесь от использования данного ключа.
-  "User ID больше не действителен"
-      Выберите, если больше не собираетесь использовать данный User ID.
-      Обычно используется, для указания, что данный e-mail больше
-      не используется
-
+      Вы дали ключу отставку.
+  "ID пользователя больше не действителен"
+      ID пользователя больше не должен употребляться; обычно это значит,
+      что адрес электронной почты недействителен.
 .
 
 .gpg.ask_revocation_reason.text
-При необходимости здесь можно прокомментировать причины
-создания сертификата отзыва.  Будьте кратки.
\94лÑ\8f Ð·Ð°Ð²ÐµÑ\80Ñ\88ениÑ\8f Ð²Ð²ÐµÐ´Ð¸Ñ\82е Ð¿Ñ\83Ñ\81Ñ\82Ñ\83Ñ\8e Ñ\81Ñ\82Ñ\80окÑ\83.
-
+# revoke.c (ask_revocation_reason)
+Если хотите, можете ввести текст, поясняющий причину, по которой
²Ñ\8bпÑ\83Ñ\89ен Ñ\8dÑ\82оÑ\82 Ñ\81еÑ\80Ñ\82иÑ\84икаÑ\82 Ð¾Ñ\82зÑ\8bва. Ð\92Ñ\8bÑ\80ажайÑ\82еÑ\81Ñ\8c, Ð¿Ð¾Ð¶Ð°Ð»Ñ\83йÑ\81Ñ\82а, Ñ\8fÑ\81но.
+Текст заканчивается пустой строкой.
 .
 
 
 
+
+.gpgsm.root-cert-not-trusted
+# This text gets displayed by the audit log if
+# a root certificates was not trusted.
+Нет доверия к корневому сертификату. В зависимости от настроек
+Вам могли предложить пометить этот корневой сертификат как доверенный
+или вручную указать GnuPG, что этому сертификату нужно доверять.
+Доверенные сертификаты задаются в файле trustlist.txt в домашнем
+каталоге GnuPG. Если сомневаетесь, спросите своего системного
+администратора, следует ли Вам доверять этому сертификату.
+
+
+.gpgsm.crl-problem
+# This tex is displayed by the audit log for problems with
+# the CRL or OCSP checking.
+В зависимости от настроек возникла проблема в получении списка
+отозванных сертификатов или в выполнении проверки по протоколу
+OCSP. Это могло случиться по очень многим причинам. Обратитесь
+к документации за возможными решениями.
+
+
 # Local variables:
-# mode: fundamental
+# mode: default-generic
 # coding: utf-8
 # End:
index f545c2b..e92cfbe 100644 (file)
@@ -207,7 +207,7 @@ N  to change the name.
 C  to change the comment.
 E  to change the email address.
 O  to continue with key generation.
-Q  to to quit the key generation.
+Q  to quit the key generation.
 .
 
 .gpg.keygen.sub.okay
@@ -337,7 +337,7 @@ file (which is shown in brackets) will be used.
 
 .gpg.ask_revocation_reason.code
 # revoke.c (ask_revocation_reason)
-You should specify a reason for the certification.  Depending on the
+You should specify a reason for the revocation.  Depending on the
 context you have the ability to choose from this list:
   "Key has been compromised"
       Use this if you have a reason to believe that unauthorized persons
@@ -373,7 +373,7 @@ your system administrator whether you should trust this certificate.
 
 
 .gpgsm.crl-problem
-# This tex is displayed by the audit log for problems with
+# This text is displayed by the audit log for problems with
 # the CRL or OCSP checking.
 Depending on your configuration a problem retrieving the CRL or
 performing an OCSP check occurred.  There are a great variety of
index 6495585..f3e2f35 100644 (file)
 #endif /*HAVE_W32_SYSTEM*/
 
 
+#if USE_GPG2_HACK
+# define gpg2_suffix "2"
+#else
+# define gpg2_suffix ""
+#endif
+
+
 static int verbose;
 
 
@@ -267,7 +274,17 @@ main (int argc, char **argv)
 
   fputs ("@c defs.inc                         -*- texinfo -*-\n"
          "@c Common and build specific constants for the manuals.\n"
-         "@c This file has been created by " PGM ".\n", stdout);
+         "@c This file has been created by " PGM ".\n\n", stdout);
+
+  fputs ("@ifclear defsincincluded\n"
+         "@set defsincincluded 1\n\n", stdout);
+
+
+  fputs ("\n@c Flags\n\n", stdout);
+
+#if USE_GPG2_HACK
+  fputs ("@set gpgtwohack 1\n\n", stdout);
+#endif
 
   fputs ("\n@c Directories\n\n", stdout);
 
@@ -306,8 +323,16 @@ main (int argc, char **argv)
   /* Fixme: Use a config.h macro here:  */
   fputs ("@set GPGSYMENCALGO AES-128\n", stdout);
 
+  fputs ("\n@c Macros\n\n", stdout);
+
+  printf ("@macro gpgname\n%s%s\n@end macro\n", GPG_NAME, gpg2_suffix);
+  printf ("@macro gpgvname\n%sv%s\n@end macro\n", GPG_NAME, gpg2_suffix);
+
 
+  /* Trailer.  */
   fputs ("\n"
+         "@end ifclear\n"
+         "\n"
          "@c Loc" "al Variables:\n"
          "@c buffer-read-only: t\n"
          "@c End:\n", stdout);
index 10714f6..18a1b69 100644 (file)
@@ -21,7 +21,7 @@
 EXTRA_DIST = options.skel dirmngr-conf.skel distsigkey.gpg \
             ChangeLog-2011 gpg-w32info.rc \
             gpg.w32-manifest.in test.c t-keydb-keyring.kbx \
-            t-keydb-get-keyblock.gpg
+            t-keydb-get-keyblock.gpg t-stutter-data.asc
 
 AM_CPPFLAGS = -I$(top_srcdir)/common
 
@@ -32,11 +32,27 @@ AM_CFLAGS = $(SQLITE3_CFLAGS) $(LIBGCRYPT_CFLAGS) \
 
 needed_libs = ../kbx/libkeybox.a $(libcommon)
 
-bin_PROGRAMS = gpg2
+# Because there are no program specific transform macros we need to
+# work around that to allow installing gpg as gpg2.
+gpg2_hack_list = gpg gpgv
+if USE_GPG2_HACK
+gpg2_hack_uninst = gpg2 gpgv2
+use_gpg2_hack = yes
+else
+gpg2_hack_uninst = $(gpg2_hack_list)
+use_gpg2_hack = no
+endif
+
+# NB: We use noinst_ for gpg and gpgv so that we can install them with
+# the install-hook target under the name gpg2/gpgv2.
+noinst_PROGRAMS = gpg
 if !HAVE_W32CE_SYSTEM
-bin_PROGRAMS += gpgv2
+noinst_PROGRAMS += gpgv
 endif
-noinst_PROGRAMS = $(module_tests)
+if MAINTAINER_MODE
+noinst_PROGRAMS += gpgcompose
+endif
+noinst_PROGRAMS += $(module_tests)
 TESTS = $(module_tests)
 
 if ENABLE_BZIP2_SUPPORT
@@ -104,8 +120,7 @@ common_source =  \
              pkglue.c pkglue.h \
              ecdh.c
 
-gpg2_SOURCES  = gpg.c          \
-             server.c          \
+gpg_sources = server.c          \
              $(common_source)  \
              pkclist.c         \
              skclist.c         \
@@ -118,7 +133,6 @@ gpg2_SOURCES  = gpg.c               \
              sign.c            \
              verify.c          \
              revoke.c          \
-             keyedit.c         \
              dearmor.c         \
              import.c          \
              export.c          \
@@ -135,7 +149,12 @@ gpg2_SOURCES  = gpg.c              \
              $(card_source) \
              exec.c exec.h
 
-gpgv2_SOURCES = gpgv.c           \
+gpg_SOURCES  = gpg.c \
+       keyedit.c       \
+       $(gpg_sources)
+
+gpgcompose_SOURCES  = gpgcompose.c  $(gpg_sources)
+gpgv_SOURCES = gpgv.c           \
              $(common_source)  \
              verify.c
 
@@ -148,17 +167,22 @@ gpgv2_SOURCES = gpgv.c           \
 
 LDADD =  $(needed_libs) ../common/libgpgrl.a \
          $(ZLIBS) $(LIBINTL) $(CAPLIBS) $(NETLIBS)
-gpg2_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+gpg_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
              $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
             $(LIBICONV) $(resource_objs) $(extra_sys_libs)
-gpg2_LDFLAGS = $(extra_bin_ldflags)
-gpgv2_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
+gpg_LDFLAGS = $(extra_bin_ldflags)
+gpgv_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) \
               $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(resource_objs) $(extra_sys_libs)
-gpgv2_LDFLAGS = $(extra_bin_ldflags)
+gpgv_LDFLAGS = $(extra_bin_ldflags)
+
+gpgcompose_LDADD = $(LDADD) $(SQLITE3_LIBS) $(LIBGCRYPT_LIBS) $(LIBREADLINE) \
+             $(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
+            $(LIBICONV) $(resource_objs) $(extra_sys_libs)
+gpgcompose_LDFLAGS = $(extra_bin_ldflags)
 
 t_common_ldadd =
-module_tests = t-rmd160 t-keydb t-keydb-get-keyblock
+module_tests = t-rmd160 t-keydb t-keydb-get-keyblock t-stutter
 t_rmd160_SOURCES = t-rmd160.c rmd160.c
 t_rmd160_LDADD = $(t_common_ldadd)
 t_keydb_SOURCES = t-keydb.c test-stubs.c $(common_source)
@@ -168,10 +192,50 @@ t_keydb_get_keyblock_SOURCES = t-keydb-get-keyblock.c test-stubs.c \
              $(common_source)
 t_keydb_get_keyblock_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
              $(LIBICONV) $(t_common_ldadd)
+t_stutter_SOURCES = t-stutter.c test-stubs.c \
+             $(common_source)
+t_stutter_LDADD = $(LDADD) $(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) \
+             $(LIBICONV) $(t_common_ldadd)
 
 
 $(PROGRAMS): $(needed_libs) ../common/libgpgrl.a
 
+# NB: To install gpg and gpgv we use this -hook.  This code has to
+# duplicate most of the automake generated install-binPROGRAMS target
+# so that directories are created and the transform feature works.
+install-exec-hook:
+       @echo "running install-exec-hook"; \
+        echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+        $(MKDIR_P) "$(DESTDIR)$(bindir)"; \
+       for p in $(gpg2_hack_list); do \
+          echo "$$p$(EXEEXT) $$p$(EXEEXT)"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p \
+         ; then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' \
+           -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           for f in $$files; do \
+              if test $(use_gpg2_hack) = yes ; \
+                then f2=`echo "$${f}" | sed 's/$(EXEEXT)$$//'`2$(EXEEXT); \
+                else f2="$${f}" ;\
+              fi ; \
+              echo "$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) \
+                     $${f} '$(DESTDIR)$(bindir)/$${f2}'"; \
+              $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) \
+                     $${f} "$(DESTDIR)$(bindir)/$${f2}"; \
+           done; \
+       done
+
+
 install-data-local:
        $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
        $(INSTALL_DATA) $(srcdir)/options.skel \
@@ -181,15 +245,15 @@ install-data-local:
        $(INSTALL_DATA) $(srcdir)/distsigkey.gpg \
                                $(DESTDIR)$(pkgdatadir)/distsigkey.gpg
 
+# NB: For uninstalling gpg and gpgv we use -local because there is
+# no need for a specific order the targets need to be run.
 uninstall-local:
        -@rm $(DESTDIR)$(pkgdatadir)/gpg-conf.skel
        -@rm $(DESTDIR)$(pkgdatadir)/dirmngr-conf.skel
        -@rm $(DESTDIR)$(pkgdatadir)/distsigkey.gpg
-
-
-# There has never been a gpg for WindowsCE, thus we don't need a gpg2 here
-if HAVE_W32CE_SYSTEM
-install-exec-hook:
-       mv -f $(DESTDIR)$(bindir)/gpg2$(EXEEXT) \
-              $(DESTDIR)$(bindir)/gpg$(EXEEXT)
-endif
+       -@files=`for p in $(gpg2_hack_uninst); do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' \
+       `; \
+       echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(bindir)" && rm -f $$files
index 55ee5d3..fb74655 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
@@ -137,7 +136,7 @@ release_armor_context (armor_filter_context_t *afx)
 {
   if (!afx)
     return;
-  assert (afx->refcount);
+  log_assert (afx->refcount);
   if ( --afx->refcount )
     return;
   xfree (afx);
@@ -193,36 +192,77 @@ initialize(void)
 
 /****************
  * Check whether this is an armored file or not See also
- * parse-packet.c for details on this code For unknown historic
- * reasons we use a string here but only the first byte will be used.
+ * parse-packet.c for details on this code.
  * Returns: True if it seems to be armored
  */
 static int
 is_armored( const byte *buf )
 {
-    int ctb, pkttype;
+  int ctb, pkttype;
+  int indeterminate_length_allowed;
 
     ctb = *buf;
     if( !(ctb & 0x80) )
-       return 1; /* invalid packet: assume it is armored */
+      /* The most significant bit of the CTB must be set.  Since it is
+         cleared, this is not a binary OpenPGP message.  Assume it is
+         armored.  */
+      return 1;
+
     pkttype =  ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
     switch( pkttype ) {
-      case PKT_MARKER:
+      case PKT_PUBKEY_ENC:
+      case PKT_SIGNATURE:
       case PKT_SYMKEY_ENC:
       case PKT_ONEPASS_SIG:
-      case PKT_PUBLIC_KEY:
       case PKT_SECRET_KEY:
-      case PKT_PUBKEY_ENC:
-      case PKT_SIGNATURE:
-      case PKT_COMMENT:
-      case PKT_OLD_COMMENT:
-      case PKT_PLAINTEXT:
+      case PKT_PUBLIC_KEY:
+      case PKT_SECRET_SUBKEY:
+      case PKT_MARKER:
+      case PKT_RING_TRUST:
+      case PKT_USER_ID:
+      case PKT_PUBLIC_SUBKEY:
+      case PKT_ATTRIBUTE:
+      case PKT_MDC:
+       indeterminate_length_allowed = 0;
+        break;
+
       case PKT_COMPRESSED:
       case PKT_ENCRYPTED:
-       return 0; /* seems to be a regular packet: not armored */
+      case PKT_ENCRYPTED_MDC:
+      case PKT_PLAINTEXT:
+      case PKT_OLD_COMMENT:
+      case PKT_COMMENT:
+      case PKT_GPG_CONTROL:
+       indeterminate_length_allowed = 1;
+        break;
+
+      default:
+        /* Invalid packet type.  */
+        return 1;
     }
 
-    return 1;
+    if (! indeterminate_length_allowed)
+      /* It is only legal to use an indeterminate length with a few
+         packet types.  If a packet uses an indeterminate length, but
+         that is not allowed, then the data is not valid binary
+         OpenPGP data.  */
+      {
+        int new_format;
+        int indeterminate_length;
+
+        new_format = !! (ctb & (1 << 6));
+        if (new_format)
+          indeterminate_length = (buf[1] >= 224 && buf[1] < 255);
+        else
+          indeterminate_length = (ctb & 3) == 3;
+
+        if (indeterminate_length)
+          return 1;
+      }
+
+    /* The first CTB seems legit.  It is probably not armored
+       data.  */
+    return 0;
 }
 
 
@@ -796,6 +836,24 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
                }
            }
 
+            /* Occasionally a bug MTA will leave the = escaped as
+               =3D.  If the 4 characters following that are valid
+               Radix64 characters and they are following by a new
+               line, assume that this is the case and skip the
+               3D.  */
+            if (afx->buffer_pos + 6 < afx->buffer_len
+                && afx->buffer[afx->buffer_pos + 0] == '3'
+                && afx->buffer[afx->buffer_pos + 1] == 'D'
+                && asctobin[afx->buffer[afx->buffer_pos + 2]] != 255
+                && asctobin[afx->buffer[afx->buffer_pos + 3]] != 255
+                && asctobin[afx->buffer[afx->buffer_pos + 4]] != 255
+                && asctobin[afx->buffer[afx->buffer_pos + 5]] != 255
+                && afx->buffer[afx->buffer_pos + 6] == '\n')
+              {
+                afx->buffer_pos += 2;
+                afx->qp_detected = 1;
+              }
+
            if (!n)
              onlypad = 1;
 
index 269c63c..9b64967 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
@@ -54,6 +53,29 @@ static int write_sign_packet_header( IOBUF out, int ctb, u32 len );
 static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen );
 static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
 
+/* Returns 1 if CTB is a new format ctb and 0 if CTB is an old format
+   ctb.  */
+static int
+ctb_new_format_p (int ctb)
+{
+  /* Bit 7 must always be set.  */
+  log_assert ((ctb & (1 << 7)));
+  /* Bit 6 indicates whether the packet is a new format packet.  */
+  return (ctb & (1 << 6));
+}
+
+/* Extract the packet type from a CTB.  */
+static int
+ctb_pkttype (int ctb)
+{
+  if (ctb_new_format_p (ctb))
+    /* Bits 0 through 5 are the packet type.  */
+    return (ctb & ((1 << 6) - 1));
+  else
+    /* Bits 2 through 5 are the packet type.  */
+    return (ctb & ((1 << 6) - 1)) >> 2;
+}
+
 /****************
  * Build a packet and write it to INP
  * Returns: 0 := okay
@@ -68,7 +90,7 @@ build_packet( IOBUF out, PACKET *pkt )
 
     if( DBG_PACKET )
        log_debug("build_packet() type=%d\n", pkt->pkttype );
-    assert( pkt->pkt.generic );
+    log_assert( pkt->pkt.generic );
 
     switch ((pkttype = pkt->pkttype))
       {
@@ -243,7 +265,7 @@ calc_packet_length( PACKET *pkt )
     u32 n=0;
     int new_ctb = 0;
 
-    assert( pkt->pkt.generic );
+    log_assert (pkt->pkt.generic);
     switch( pkt->pkttype ) {
       case PKT_PLAINTEXT:
        n = calc_plaintext( pkt->pkt.plaintext );
@@ -287,11 +309,19 @@ write_fake_data (IOBUF out, gcry_mpi_t a)
 }
 
 
+/* Serialize the user id (RFC 4880, Section 5.11) or the user
+   attribute UID (Section 5.12) and write it to OUT.
+
+   CTB is the serialization's CTB.  It specifies the header format and
+   the packet's type.  The header length must not be set.  */
 static int
 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 {
   int rc;
 
+  log_assert (ctb_pkttype (ctb) == PKT_USER_ID
+              || ctb_pkttype (ctb) == PKT_ATTRIBUTE);
+
   if (uid->attrib_data)
     {
       write_header(out, ctb, uid->attrib_len);
@@ -306,12 +336,37 @@ do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 }
 
 
+/* Serialize the key (RFC 4880, Section 5.5) described by PK and write
+   it to OUT.
+
+   This function serializes both primary keys and subkeys with or
+   without a secret part.
+
+   CTB is the serialization's CTB.  It specifies the header format and
+   the packet's type.  The header length must not be set.
+
+   PK->VERSION specifies the serialization format.  A value of 0 means
+   to use the default version.  Currently, only version 4 packets are
+   supported.
+ */
 static int
 do_key (iobuf_t out, int ctb, PKT_public_key *pk)
 {
   gpg_error_t err = 0;
+  /* The length of the body is stored in the packet's header, which
+     occurs before the body.  Unfortunately, we don't know the length
+     of the packet's body until we've written all of the data!  To
+     work around this, we first write the data into this temporary
+     buffer, then generate the header, and finally copy the contents
+     of this buffer to OUT.  */
+  iobuf_t a = iobuf_temp();
   int i, nskey, npkey;
-  iobuf_t a = iobuf_temp(); /* Build in a self-enlarging buffer.  */
+
+  log_assert (pk->version == 0 || pk->version == 4);
+  log_assert (ctb_pkttype (ctb) == PKT_PUBLIC_KEY
+              || ctb_pkttype (ctb) == PKT_PUBLIC_SUBKEY
+              || ctb_pkttype (ctb) == PKT_SECRET_KEY
+              || ctb_pkttype (ctb) == PKT_SECRET_SUBKEY);
 
   /* Write the version number - if none is specified, use 4 */
   if ( !pk->version )
@@ -323,7 +378,7 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
   iobuf_put (a, pk->pubkey_algo );
 
   /* Get number of secret and public parameters.  They are held in one
-     array first the public ones, then the secret ones.  */
+     array: the public ones followed by the secret ones.  */
   nskey = pubkey_get_nskey (pk->pubkey_algo);
   npkey = pubkey_get_npkey (pk->pubkey_algo);
 
@@ -335,7 +390,7 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
       write_fake_data (a, pk->pkey[0]);
       goto leave;
     }
-  assert (npkey < nskey);
+  log_assert (npkey < nskey);
 
   for (i=0; i < npkey; i++ )
     {
@@ -409,7 +464,7 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
           byte *p;
           unsigned int ndatabits;
 
-          assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
+          log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
           p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
           if (p)
             iobuf_write (a, p, (ndatabits+7)/8 );
@@ -430,8 +485,8 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
       /* Build the header of the packet - which we must do after
          writing all the other stuff, so that we know the length of
          the packet */
-      write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes);
-      /* And finally write it out to the real stream. */
+      write_header2 (out, ctb, iobuf_get_temp_length(a), 0);
+       /* And finally write it out to the real stream. */
       err = iobuf_write_temp (out, a);
     }
 
@@ -439,16 +494,36 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
   return err;
 }
 
+/* Serialize the symmetric-key encrypted session key packet (RFC 4880,
+   5.3) described by ENC and write it to OUT.
+
+   CTB is the serialization's CTB.  It specifies the header format and
+   the packet's type.  The header length must not be set.  */
 static int
 do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
 {
     int rc = 0;
     IOBUF a = iobuf_temp();
 
-    assert( enc->version == 4 );
-    switch( enc->s2k.mode ) {
-      case 0: case 1: case 3: break;
-      default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode );
+    log_assert (ctb_pkttype (ctb) == PKT_SYMKEY_ENC);
+
+    /* The only acceptable version.  */
+    log_assert( enc->version == 4 );
+
+    /* RFC 4880, Section 3.7.  */
+    switch( enc->s2k.mode )
+      {
+      /* Simple S2K.  */
+      case 0:
+      /* Salted S2K.  */
+      case 1:
+      /* Iterated and salted S2K.  */
+      case 3:
+        /* Reasonable values.  */
+        break;
+
+      default:
+        log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode );
     }
     iobuf_put( a, enc->version );
     iobuf_put( a, enc->cipher_algo );
@@ -470,6 +545,11 @@ do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
 }
 
 
+/* Serialize the public-key encrypted session key packet (RFC 4880,
+   5.1) described by ENC and write it to OUT.
+
+   CTB is the serialization's CTB.  It specifies the header format and
+   the packet's type.  The header length must not be set.  */
 static int
 do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
 {
@@ -477,6 +557,8 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
   int n, i;
   IOBUF a = iobuf_temp();
 
+  log_assert (ctb_pkttype (ctb) == PKT_PUBKEY_ENC);
+
   iobuf_put (a, 3); /* Version.  */
 
   if ( enc->throw_keyid )
@@ -512,6 +594,8 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
 }
 
 
+/* Calculate the length of the serialized plaintext packet PT (RFC
+   4480, Section 5.9).  */
 static u32
 calc_plaintext( PKT_plaintext *pt )
 {
@@ -525,48 +609,70 @@ calc_plaintext( PKT_plaintext *pt )
   return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
 }
 
+/* Serialize the plaintext packet (RFC 4880, 5.9) described by PT and
+   write it to OUT.
+
+   The body of the message is stored in PT->BUF.  The amount of data
+   to write is PT->LEN.  (PT->BUF should be configured to return EOF
+   after this much data has been read.)  If PT->LEN is 0 and CTB
+   indicates that this is a new format packet, then partial block mode
+   is assumed to have been enabled on OUT.  On success, partial block
+   mode is disabled.
+
+   If PT->BUF is NULL, the the caller must write out the data.  In
+   this case, if PT->LEN was 0, then partial body length mode was
+   enabled and the caller must disable it by calling
+   iobuf_set_partial_body_length_mode (out, 0).  */
 static int
 do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
 {
-    int i, rc = 0;
-    u32 n;
-    byte buf[1000]; /* this buffer has the plaintext! */
-    int nbytes;
+    int rc = 0;
+    size_t nbytes;
+
+    log_assert (ctb_pkttype (ctb) == PKT_PLAINTEXT);
 
     write_header(out, ctb, calc_plaintext( pt ) );
+    log_assert (pt->mode == 'b' || pt->mode == 't' || pt->mode == 'u'
+                || pt->mode == 'l' || pt->mode == '1');
     iobuf_put(out, pt->mode );
     iobuf_put(out, pt->namelen );
-    for(i=0; i < pt->namelen; i++ )
-       iobuf_put(out, pt->name[i] );
+    iobuf_write (out, pt->name, pt->namelen);
     rc = write_32(out, pt->timestamp );
     if (rc)
       return rc;
 
-    n = 0;
-    while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
-      rc = iobuf_write (out, buf, nbytes);
-      if (rc)
-        break;
-      n += nbytes;
-    }
-    wipememory(buf,1000); /* burn the buffer */
-    if( (ctb&0x40) && !pt->len )
-      iobuf_set_partial_block_mode(out, 0 ); /* turn off partial */
-    if( pt->len && n != pt->len )
-      log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
-               (ulong)n, (ulong)pt->len );
+    if (pt->buf)
+      {
+        nbytes = iobuf_copy (out, pt->buf);
+        if(ctb_new_format_p (ctb) && !pt->len)
+          /* Turn off partial body length mode.  */
+          iobuf_set_partial_body_length_mode (out, 0);
+        if( pt->len && nbytes != pt->len )
+          log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
+                    (ulong)nbytes, (ulong)pt->len );
+      }
 
     return rc;
 }
 
 
 
+/* Serialize the symmetrically encrypted data packet (RFC 4880,
+   Section 5.7) described by ED and write it to OUT.
+
+   Note: this only writes the packets header!  The call must then
+   follow up and write the initial random data and the body to OUT.
+   (If you use the encryption iobuf filter (cipher_filter), then this
+   is done automatically.)  */
 static int
 do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed )
 {
     int rc = 0;
     u32 n;
 
+    log_assert (! ed->mdc_method);
+    log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED);
+
     n = ed->len ? (ed->len + ed->extralen) : 0;
     write_header(out, ctb, n );
 
@@ -575,13 +681,22 @@ do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed )
     return rc;
 }
 
+/* Serialize the symmetrically encrypted integrity protected data
+   packet (RFC 4880, Section 5.13) described by ED and write it to
+   OUT.
+
+   Note: this only writes the packet's header!  The caller must then
+   follow up and write the initial random data, the body and the MDC
+   packet to OUT.  (If you use the encryption iobuf filter
+   (cipher_filter), then this is done automatically.)  */
 static int
 do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed )
 {
     int rc = 0;
     u32 n;
 
-    assert( ed->mdc_method );
+    log_assert (ed->mdc_method);
+    log_assert (ctb_pkttype (ctb) == PKT_ENCRYPTED_MDC);
 
     /* Take version number and the following MDC packet in account. */
     n = ed->len ? (ed->len + ed->extralen + 1 + 22) : 0;
@@ -594,11 +709,18 @@ do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed )
 }
 
 
+/* Serialize the compressed packet (RFC 4880, Section 5.6) described
+   by CD and write it to OUT.
+
+   Note: this only writes the packet's header!  The caller must then
+   follow up and write the body to OUT.  */
 static int
 do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
 {
     int rc = 0;
 
+    log_assert (ctb_pkttype (ctb) == PKT_COMPRESSED);
+
     /* We must use the old convention and don't use blockmode for the
        sake of PGP 2 compatibility.  However if the new_ctb flag was
        set, CTB is already formatted as new style and write_header2
@@ -675,7 +797,7 @@ delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
 
     if (!okay)
         log_error ("delete_subpkt: buffer shorter than subpacket\n");
-    assert (unused <= area->len);
+    log_assert (unused <= area->len);
     area->len -= unused;
     return !!unused;
 }
@@ -947,6 +1069,42 @@ build_attribute_subpkt(PKT_user_id *uid,byte type,
   uid->attrib_len+=idx+headerlen+buflen;
 }
 
+/* Returns a human-readable string corresponding to the notation.
+   This ignores notation->value.  The caller must free the result.  */
+static char *
+notation_value_to_human_readable_string (struct notation *notation)
+{
+  if(notation->bdat)
+    /* Binary data.  */
+    {
+      size_t len = notation->blen;
+      int i;
+      char preview[20];
+
+      for (i = 0; i < len && i < sizeof (preview) - 1; i ++)
+        if (isprint (notation->bdat[i]))
+          preview[i] = notation->bdat[i];
+        else
+          preview[i] = '?';
+      preview[i] = 0;
+
+      return xasprintf (_("[ not human readable (%zu bytes: %s%s) ]"),
+                        len, preview, i < len ? "..." : "");
+    }
+  else
+    /* The value is human-readable.  */
+    return xstrdup (notation->value);
+}
+
+/* Turn the notation described by the string STRING into a notation.
+
+   STRING has the form:
+
+     - -name - Delete the notation.
+     - name@domain.name=value - Normal notation
+     - !name@domain.name=value - Notation with critical bit set.
+
+   The caller must free the result using free_notation().  */
 struct notation *
 string_to_notation(const char *string,int is_utf8)
 {
@@ -1037,6 +1195,83 @@ string_to_notation(const char *string,int is_utf8)
   return NULL;
 }
 
+/* Like string_to_notation, but store opaque data rather than human
+   readable data.  */
+struct notation *
+blob_to_notation(const char *name, const char *data, size_t len)
+{
+  const char *s;
+  int saw_at=0;
+  struct notation *notation;
+
+  notation=xmalloc_clear(sizeof(*notation));
+
+  if(*name=='-')
+    {
+      notation->flags.ignore=1;
+      name++;
+    }
+
+  if(*name=='!')
+    {
+      notation->flags.critical=1;
+      name++;
+    }
+
+  /* If and when the IETF assigns some official name tags, we'll have
+     to add them here. */
+
+  for( s=name ; *s; s++ )
+    {
+      if( *s=='@')
+       saw_at++;
+
+      /* -notationname is legal without an = sign */
+      if(!*s && notation->flags.ignore)
+       break;
+
+      if (*s == '=')
+        {
+          log_error(_("a notation name may not contain an '=' character\n"));
+          goto fail;
+        }
+
+      if (!isascii (*s) || (!isgraph(*s) && !isspace(*s)))
+       {
+         log_error(_("a notation name must have only printable characters"
+                     " or spaces\n") );
+         goto fail;
+       }
+    }
+
+  notation->name=xstrdup (name);
+
+  if(!saw_at && !opt.expert)
+    {
+      log_error(_("a user notation name must contain the '@' character\n"));
+      goto fail;
+    }
+
+  if (saw_at > 1)
+    {
+      log_error(_("a notation name must not contain more than"
+                 " one '@' character\n"));
+      goto fail;
+    }
+
+  notation->bdat = xmalloc (len);
+  memcpy (notation->bdat, data, len);
+  notation->blen = len;
+
+  notation->value = notation_value_to_human_readable_string (notation);
+
+  return notation;
+
+ fail:
+  free_notation(notation);
+  return NULL;
+}
+
 struct notation *
 sig_to_notation(PKT_signature *sig)
 {
@@ -1045,6 +1280,15 @@ sig_to_notation(PKT_signature *sig)
   int seq=0,crit;
   struct notation *list=NULL;
 
+  /* See RFC 4880, 5.2.3.16 for the format of notation data.  In
+     short, a notation has:
+
+       - 4 bytes of flags
+       - 2 byte name length (n1)
+       - 2 byte value length (n2)
+       - n1 bytes of name data
+       - n2 bytes of value data
+   */
   while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION,&len,&seq,&crit)))
     {
       int n1,n2;
@@ -1056,7 +1300,9 @@ sig_to_notation(PKT_signature *sig)
          continue;
        }
 
+      /* name length.  */
       n1=(p[4]<<8)|p[5];
+      /* value length.  */
       n2=(p[6]<<8)|p[7];
 
       if(8+n1+n2!=len)
@@ -1072,21 +1318,20 @@ sig_to_notation(PKT_signature *sig)
       n->name[n1]='\0';
 
       if(p[0]&0x80)
+        /* The value is human-readable.  */
        {
          n->value=xmalloc(n2+1);
          memcpy(n->value,&p[8+n1],n2);
          n->value[n2]='\0';
        }
       else
+        /* Binary data.  */
        {
          n->bdat=xmalloc(n2);
          n->blen=n2;
          memcpy(n->bdat,&p[8+n1],n2);
 
-         n->value=xmalloc(2+strlen(_("not human readable"))+2+1);
-         strcpy(n->value,"[ ");
-         strcat(n->value,_("not human readable"));
-         strcat(n->value," ]");
+          n->value = notation_value_to_human_readable_string (n);
        }
 
       n->flags.critical=crit;
@@ -1098,6 +1343,9 @@ sig_to_notation(PKT_signature *sig)
   return list;
 }
 
+/* Release the resources associated with the *list* of notations.  To
+   release a single notation, make sure that notation->next is
+   NULL.  */
 void
 free_notation(struct notation *notation)
 {
@@ -1114,6 +1362,8 @@ free_notation(struct notation *notation)
     }
 }
 
+/* Serialize the signature packet (RFC 4880, Section 5.2) described by
+   SIG and write it to OUT.  */
 static int
 do_signature( IOBUF out, int ctb, PKT_signature *sig )
 {
@@ -1121,8 +1371,16 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
   int n, i;
   IOBUF a = iobuf_temp();
 
-  if ( !sig->version )
-    iobuf_put( a, 3 );
+  log_assert (ctb_pkttype (ctb) == PKT_SIGNATURE);
+
+  if ( !sig->version || sig->version == 3)
+    {
+      iobuf_put( a, 3 );
+
+      /* Version 3 packets don't support subpackets.  */
+      log_assert (! sig->hashed);
+      log_assert (! sig->unhashed);
+    }
   else
     iobuf_put( a, sig->version );
   if ( sig->version < 4 )
@@ -1173,28 +1431,28 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
 }
 
 
+/* Serialize the one-pass signature packet (RFC 4880, Section 5.4)
+   described by OPS and write it to OUT.  */
 static int
 do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops )
 {
-    int rc = 0;
-    IOBUF a = iobuf_temp();
+    log_assert (ctb_pkttype (ctb) == PKT_ONEPASS_SIG);
 
-    iobuf_put (a, 3);  /* Version.  */
-    iobuf_put(a, ops->sig_class );
-    iobuf_put(a, ops->digest_algo );
-    iobuf_put(a, ops->pubkey_algo );
-    write_32(a, ops->keyid[0] );
-    write_32(a, ops->keyid[1] );
-    iobuf_put(a, ops->last );
+    write_header(out, ctb, 4 + 8 + 1);
 
-    write_header(out, ctb, iobuf_get_temp_length(a) );
-    rc = iobuf_write_temp( out, a );
+    iobuf_put (out, 3);  /* Version.  */
+    iobuf_put(out, ops->sig_class );
+    iobuf_put(out, ops->digest_algo );
+    iobuf_put(out, ops->pubkey_algo );
+    write_32(out, ops->keyid[0] );
+    write_32(out, ops->keyid[1] );
+    iobuf_put(out, ops->last );
 
-    iobuf_close(a);
-    return rc;
+    return 0;
 }
 
 
+/* Write a 16-bit quantity to OUT in big endian order.  */
 static int
 write_16(IOBUF out, u16 a)
 {
@@ -1204,6 +1462,7 @@ write_16(IOBUF out, u16 a)
     return 0;
 }
 
+/* Write a 32-bit quantity to OUT in big endian order.  */
 static int
 write_32(IOBUF out, u32 a)
 {
@@ -1215,14 +1474,18 @@ write_32(IOBUF out, u32 a)
 
 
 /****************
- * calculate the length of a header
+ * calculate the length of a header.
+ *
+ * LEN is the length of the packet's body.  NEW_CTB is whether we are
+ * using a new or old format packet.
+ *
+ * This function does not handle indeterminate lengths or partial body
+ * lengths.  (If you pass LEN as 0, then this function assumes you
+ * really mean an empty body.)
  */
 static int
 calc_header_length( u32 len, int new_ctb )
 {
-    if( !len )
-       return 1; /* only the ctb */
-
     if( new_ctb ) {
        if( len < 192 )
            return 2;
@@ -1263,36 +1526,73 @@ write_sign_packet_header (IOBUF out, int ctb, u32 len)
 }
 
 /****************
- * If HDRLEN is > 0, try to build a header of this length.  We need
- * this so that we can hash packets without reading them again.  If
- * len is 0, write a partial or indeterminate length header, unless
- * hdrlen is specified in which case write an actual zero length
- * (using the specified hdrlen).
+ * Write a packet header to OUT.
+ *
+ * CTB is the ctb.  It determines whether a new or old format packet
+ * header should be written.  The length field is adjusted, but the
+ * CTB is otherwise written out as is.
+ *
+ * LEN is the length of the packet's body.
+ *
+ * If HDRLEN is set, then we don't necessarily use the most efficient
+ * encoding to store LEN, but the specified length.  (If this is not
+ * possible, this is a bug.)  In this case, LEN=0 means a 0 length
+ * packet.  Note: setting HDRLEN is only supported for old format
+ * packets!
+ *
+ * If HDRLEN is not set, then the shortest encoding is used.  In this
+ * case, LEN=0 means the body has an indeterminate length and a
+ * partial body length header (if a new format packet) or an
+ * indeterminate length header (if an old format packet) is written
+ * out.  Further, if using partial body lengths, this enables partial
+ * body length mode on OUT.
  */
 static int
 write_header2( IOBUF out, int ctb, u32 len, int hdrlen )
 {
-  if( ctb & 0x40 )
+  if (ctb_new_format_p (ctb))
     return write_new_header( out, ctb, len, hdrlen );
 
-  if( hdrlen )
+  /* An old format packet.  Refer to RFC 4880, Section 4.2.1 to
+     understand how lengths are encoded in this case.  */
+
+  /* The length encoding is stored in the two least significant bits.
+     Make sure they are cleared.  */
+  log_assert ((ctb & 3) == 0);
+
+  log_assert (hdrlen == 0 || hdrlen == 2 || hdrlen == 3 || hdrlen == 5);
+
+  if (hdrlen)
+    /* Header length is given.  */
     {
       if( hdrlen == 2 && len < 256 )
+        /* 00 => 1 byte length.  */
        ;
       else if( hdrlen == 3 && len < 65536 )
+        /* 01 => 2 byte length.  If len < 256, this is not the most
+           compact encoding, but it is a correct encoding.  */
        ctb |= 1;
-      else
+      else if (hdrlen == 5)
+        /* 10 => 4 byte length.  If len < 65536, this is not the most
+           compact encoding, but it is a correct encoding.  */
        ctb |= 2;
+      else
+        log_bug ("Can't encode length=%d in a %d byte header!\n",
+                 len, hdrlen);
     }
   else
     {
       if( !len )
+        /* 11 => Indeterminate length.  */
        ctb |= 3;
       else if( len < 256 )
+        /* 00 => 1 byte length.  */
        ;
       else if( len < 65536 )
+        /* 01 => 2 byte length.  */
        ctb |= 1;
       else
+        /* 10 => 4 byte length.  */
        ctb |= 2;
     }
 
@@ -1321,6 +1621,20 @@ write_header2( IOBUF out, int ctb, u32 len, int hdrlen )
 }
 
 
+/* Write a new format header to OUT.
+
+   CTB is the ctb.
+
+   LEN is the length of the packet's body.  If LEN is 0, then enables
+   partial body length mode (i.e., the body is of an indeterminant
+   length) on OUT.  Note: this function cannot be used to generate a
+   header for a zero length packet.
+
+   HDRLEN is the length of the packet's header.  If HDRLEN is 0, the
+   shortest encoding is chosen based on the length of the packet's
+   body.  Currently, values other than 0 are not supported.
+
+   Returns 0 on success.  */
 static int
 write_new_header( IOBUF out, int ctb, u32 len, int hdrlen )
 {
@@ -1330,7 +1644,7 @@ write_new_header( IOBUF out, int ctb, u32 len, int hdrlen )
     if( iobuf_put(out, ctb ) )
        return -1;
     if( !len ) {
-       iobuf_set_partial_block_mode(out, 512 );
+       iobuf_set_partial_body_length_mode(out, 512 );
     }
     else {
        if( len < 192 ) {
index d9e4859..c5bd694 100644 (file)
@@ -25,7 +25,6 @@
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
-#include <assert.h>
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #endif
@@ -712,7 +711,7 @@ learn_status_cb (void *opaque, const char *line)
            && strchr("1234", keyword[11]))
     {
       int no = keyword[11] - '1';
-      assert (no >= 0 && no <= 3);
+      log_assert (no >= 0 && no <= 3);
       xfree (parm->private_do[no]);
       parm->private_do[no] = unescape_status_string (line);
     }
@@ -2133,7 +2132,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
   buf = get_membuf (&data, &len);
   if (!buf)
     return gpg_error_from_syserror ();
-  assert (len); /* (we forced Nul termination.)  */
+  log_assert (len); /* (we forced Nul termination.)  */
 
   if (*buf != '(')
     {
index e596533..d35a5cf 100644 (file)
@@ -25,7 +25,6 @@
 #include <errno.h>
 #include <unistd.h>
 #include <time.h>
-#include <assert.h>
 #ifdef HAVE_LOCALE_H
 # include <locale.h>
 #endif
@@ -261,7 +260,7 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
       if (dml)
         {
           /* Found an inactive local session - return that.  */
-          assert (!dml->is_active);
+          log_assert (!dml->is_active);
 
           /* But first do the per session init if not yet done.  */
           if (!dml->set_keyservers_done)
@@ -804,7 +803,7 @@ record_output (estream_t output,
       type_str = "sig";
       break;
     default:
-      assert (! "Unhandled type.");
+      log_assert (! "Unhandled type.");
     }
 
   if (pub_key_length > 0)
@@ -1064,7 +1063,7 @@ gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock)
 
 
 \f
-/* Data callback for the DNS_CERT command. */
+/* Data callback for the DNS_CERT and WKD_GET commands. */
 static gpg_error_t
 dns_cert_data_cb (void *opaque, const void *data, size_t datalen)
 {
@@ -1287,3 +1286,62 @@ gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
   close_context (ctrl, ctx);
   return err;
 }
+
+
+\f
+/* Ask the dirmngr to retrieve a key via the Web Key Directory
+ * protocol.  On success a new estream with the key is stored at
+ * R_KEY.
+ */
+gpg_error_t
+gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, estream_t *r_key)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  struct dns_cert_parm_s parm;
+  char *line = NULL;
+
+  memset (&parm, 0, sizeof parm);
+
+  err = open_context (ctrl, &ctx);
+  if (err)
+    return err;
+
+  line = es_bsprintf ("WKD_GET -- %s", name);
+  if (!line)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
+    {
+      err = gpg_error (GPG_ERR_TOO_LARGE);
+      goto leave;
+    }
+
+  parm.memfp = es_fopenmem (0, "rwb");
+  if (!parm.memfp)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = assuan_transact (ctx, line, dns_cert_data_cb, &parm,
+                         NULL, NULL, NULL, &parm);
+  if (err)
+    goto leave;
+
+  if (r_key)
+    {
+      es_rewind (parm.memfp);
+      *r_key = parm.memfp;
+      parm.memfp = NULL;
+    }
+
+ leave:
+  xfree (parm.fpr);
+  xfree (parm.url);
+  es_fclose (parm.memfp);
+  xfree (line);
+  close_context (ctrl, ctx);
+  return err;
+}
index cdad645..4dc1e30 100644 (file)
@@ -40,6 +40,8 @@ gpg_error_t gpg_dirmngr_dns_cert (ctrl_t ctrl,
 gpg_error_t gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid,
                                  unsigned char **r_fpr, size_t *r_fprlen,
                                  char **r_url);
+gpg_error_t gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name,
+                                 estream_t *r_key);
 
 
 #endif /*GNUPG_G10_CALL_DIRMNGR_H*/
index b48705b..be1a593 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #ifdef HAVE_LIBREADLINE
 # define GNUPG_LIBREADLINE_H_INCLUDED
 # include <readline/readline.h>
@@ -210,11 +209,12 @@ get_manufacturer (unsigned int no)
     case 0x0007: return "OpenKMS";
     case 0x0008: return "LogoEmail";
     case 0x0009: return "Fidesmo";
+    case 0x000A: return "Dangerous Things";
 
     case 0x002A: return "Magrathea";
 
     case 0x1337: return "Warsaw Hackerspace";
-
+    case 0x2342: return "warpzone"; /* hackerspace Muenster.  */
     case 0xF517: return "FSIJ";
 
       /* 0x0000 and 0xFFFF are defined as test cards per spec,
@@ -900,7 +900,7 @@ change_private_do (const char *args, int nr)
   int n;
   int rc;
 
-  assert (nr >= 1 && nr <= 4);
+  log_assert (nr >= 1 && nr <= 4);
   do_name[11] = '0' + nr;
 
   if (args && (args = strchr (args, '<')))  /* Read it from a file */
@@ -1246,7 +1246,7 @@ show_card_key_info (struct agent_card_info_s *info)
 static int
 replace_existing_key_p (struct agent_card_info_s *info, int keyno)
 {
-  assert (keyno >= 0 && keyno <= 3);
+  log_assert (keyno >= 0 && keyno <= 3);
 
   if ((keyno == 1 && info->fpr1valid)
       || (keyno == 2 && info->fpr2valid)
@@ -1537,8 +1537,8 @@ card_store_subkey (KBNODE node, int use)
   int rc;
   gnupg_isotime_t timebuf;
 
-  assert (node->pkt->pkttype == PKT_PUBLIC_KEY
-          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
+              || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
 
   pk = node->pkt->pkt.public_key;
 
index 41324c3..ae7ba17 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "status.h"
@@ -123,7 +122,7 @@ cipher_filter( void *opaque, int control,
        rc = -1; /* not yet used */
     }
     else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
-       assert(a);
+       log_assert(a);
        if( !cfx->header ) {
            write_header( cfx, a );
        }
@@ -139,7 +138,7 @@ cipher_filter( void *opaque, int control,
                                                  (cfx->mdc_hash));
            byte temp[22];
 
-           assert( hashlen == 20 );
+           log_assert( hashlen == 20 );
            /* We must hash the prefix of the MDC packet here. */
            temp[0] = 0xd3;
            temp[1] = 0x14;
index fd1ed6a..bdddef1 100644 (file)
@@ -29,7 +29,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <assert.h>
 #include <errno.h>
 #ifdef HAVE_ZIP
 # include <zlib.h>
index 3fdd57d..38c3a3c 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "status.h"
index 1380faf..96d2177 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -57,7 +56,7 @@ release_dfx_context (decode_filter_ctx_t dfx)
   if (!dfx)
     return;
 
-  assert (dfx->refcount);
+  log_assert (dfx->refcount);
   if ( !--dfx->refcount )
     {
       gcry_cipher_close (dfx->cipher_hd);
@@ -273,8 +272,8 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
          bytes are appended.  */
       int datalen = gcry_md_get_algo_dlen (ed->mdc_method);
 
-      assert (dfx->cipher_hd);
-      assert (dfx->mdc_hash);
+      log_assert (dfx->cipher_hd);
+      log_assert (dfx->mdc_hash);
       gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0);
       gcry_md_write (dfx->mdc_hash, dfx->defer, 2);
       gcry_md_final (dfx->mdc_hash);
@@ -320,8 +319,8 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
     }
   else if( control == IOBUFCTRL_UNDERFLOW )
     {
-      assert (a);
-      assert (size > 44); /* Our code requires at least this size.  */
+      log_assert (a);
+      log_assert (size > 44); /* Our code requires at least this size.  */
 
       /* Get at least 22 bytes and put it ahead in the buffer.  */
       if (dfx->partial)
@@ -414,7 +413,7 @@ mdc_decode_filter (void *opaque, int control, IOBUF a,
        }
       else
         {
-          assert ( dfx->eof_seen );
+          log_assert ( dfx->eof_seen );
           rc = -1; /* Return EOF.  */
        }
       *ret_len = n;
@@ -447,7 +446,7 @@ decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
     }
   else if ( control == IOBUFCTRL_UNDERFLOW )
     {
-      assert(a);
+      log_assert (a);
 
       if (fc->partial)
         {
index 068b64a..27f51f6 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
index 31ebbb6..1a879e3 100644 (file)
--- a/g10/dek.h
+++ b/g10/dek.h
 
 typedef struct
 {
+  /* The algorithm (e.g., CIPHER_ALGO_AES).  */
   int algo;
+  /* The length of the key (in bytes).  */
   int keylen;
+  /* Whether we've already printed information about this key.  This
+     is currently only used in decrypt_data() and only if we are in
+     verbose mode.  */
   int algo_info_printed;
   int use_mdc;
+  /* This key was read from a SK-ESK packet (see proc_symkey_enc).  */
   int symmetric;
   byte key[32]; /* This is the largest used keylen (256 bit). */
   char s2k_cacheid[1+16+1];
index 5d0c3df..f76277c 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
index a1b7ecf..af1d844 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -75,7 +74,7 @@ pk_ecdh_default_params (unsigned int qbits)
           break;
         }
     }
-  assert (i < DIM (kek_params_table));
+  log_assert (i < DIM (kek_params_table));
   if (DBG_CRYPTO)
     log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
 
@@ -134,7 +133,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
       }
 
     secret_x_size = (nbits+7)/8;
-    assert (nbytes >= secret_x_size);
+    log_assert (nbytes >= secret_x_size);
     if ((nbytes & 1))
       /* Remove the "04" prefix of non-compressed format.  */
       memmove (secret_x, secret_x+1, secret_x_size);
@@ -241,16 +240,16 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
 
     gcry_md_final (h);
 
-    assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
+    log_assert( gcry_md_get_algo_dlen (kdf_hash_algo) >= 32 );
 
     memcpy (secret_x, gcry_md_read (h, kdf_hash_algo),
             gcry_md_get_algo_dlen (kdf_hash_algo));
     gcry_md_close (h);
 
     old_size = secret_x_size;
-    assert( old_size >= gcry_cipher_get_algo_keylen( kdf_encr_algo ) );
+    log_assert( old_size >= gcry_cipher_get_algo_keylen( kdf_encr_algo ) );
     secret_x_size = gcry_cipher_get_algo_keylen( kdf_encr_algo );
-    assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) );
+    log_assert( secret_x_size <= gcry_md_get_algo_dlen (kdf_hash_algo) );
 
     /* We could have allocated more, so clean the tail before returning.  */
     memset (secret_x+secret_x_size, 0, old_size - secret_x_size);
index abd8002..57d24be 100644 (file)
@@ -1,6 +1,7 @@
 /* encrypt.c - Main encryption driver
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  *               2006, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -23,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -65,17 +65,24 @@ encrypt_store (const char *filename)
 }
 
 
-static void
+/* *SESKEY contains the unencrypted session key ((*SESKEY)->KEY) and
+   the algorithm that will be used to encrypt the contents of the SED
+   packet ((*SESKEY)->ALGO).  If *SESKEY is NULL, then a random
+   session key that is appropriate for DEK->ALGO is generated and
+   stored there.
+
+   Encrypt that session key using DEK and store the result in ENCKEY,
+   which must be large enough to hold (*SESKEY)->KEYLEN + 1 bytes.  */
+void
 encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey)
 {
   gcry_cipher_hd_t hd;
   byte buf[33];
 
-  assert ( dek->keylen <= 32 );
+  log_assert ( dek->keylen <= 32 );
   if (!*seskey)
     {
       *seskey=xmalloc_clear(sizeof(DEK));
-      (*seskey)->keylen=dek->keylen;
       (*seskey)->algo=dek->algo;
       make_session_key(*seskey);
       /*log_hexdump( "thekey", c->key, c->keylen );*/
@@ -326,7 +333,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
 
   if (!opt.no_literal)
     {
-      /* Note that PT has been initialized above in no_literal mode.  */
+      /* Note that PT has been initialized above in !no_literal mode.  */
       pt->timestamp = make_timestamp();
       pt->mode = opt.textmode? 't' : 'b';
       pt->len = filesize;
@@ -826,18 +833,18 @@ encrypt_filter (void *opaque, int control,
           if (rc)
             return rc;
 
-           if(efx->symkey_s2k && efx->symkey_dek)
-             {
-               rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
-                                   efx->cfx.dek,a);
-               if(rc)
-                 return rc;
-             }
+          if(efx->symkey_s2k && efx->symkey_dek)
+            {
+              rc=write_symkey_enc(efx->symkey_s2k,efx->symkey_dek,
+                                  efx->cfx.dek,a);
+              if(rc)
+                return rc;
+            }
 
-           iobuf_push_filter (a, cipher_filter, &efx->cfx);
+          iobuf_push_filter (a, cipher_filter, &efx->cfx);
 
-           efx->header_okay = 1;
-       }
+          efx->header_okay = 1;
+        }
       rc = iobuf_write (a, buf, size);
 
     }
@@ -855,81 +862,90 @@ encrypt_filter (void *opaque, int control,
 
 
 /*
- * Write pubkey-enc packets from the list of PKs to OUT.
+ * Write a pubkey-enc packet for the public key PK to OUT.
  */
-static int
-write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
+int
+write_pubkey_enc (PKT_public_key *pk, int throw_keyid, DEK *dek, iobuf_t out)
 {
   PACKET pkt;
-  PKT_public_key *pk;
-  PKT_pubkey_enc  *enc;
+  PKT_pubkey_enc *enc;
   int rc;
-
-  for ( ; pk_list; pk_list = pk_list->next )
+  gcry_mpi_t frame;
+
+  print_pubkey_algo_note ( pk->pubkey_algo );
+  enc = xmalloc_clear ( sizeof *enc );
+  enc->pubkey_algo = pk->pubkey_algo;
+  keyid_from_pk( pk, enc->keyid );
+  enc->throw_keyid = throw_keyid;
+
+  /* Okay, what's going on: We have the session key somewhere in
+   * the structure DEK and want to encode this session key in an
+   * integer value of n bits. pubkey_nbits gives us the number of
+   * bits we have to use.  We then encode the session key in some
+   * way and we get it back in the big intger value FRAME.  Then
+   * we use FRAME, the public key PK->PKEY and the algorithm
+   * number PK->PUBKEY_ALGO and pass it to pubkey_encrypt which
+   * returns the encrypted value in the array ENC->DATA.  This
+   * array has a size which depends on the used algorithm (e.g. 2
+   * for Elgamal).  We don't need frame anymore because we have
+   * everything now in enc->data which is the passed to
+   * build_packet().  */
+  frame = encode_session_key (pk->pubkey_algo, dek,
+                              pubkey_nbits (pk->pubkey_algo, pk->pkey));
+  rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
+  gcry_mpi_release (frame);
+  if (rc)
+    log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
+  else
     {
-      gcry_mpi_t frame;
-
-      pk = pk_list->pk;
-
-      print_pubkey_algo_note ( pk->pubkey_algo );
-      enc = xmalloc_clear ( sizeof *enc );
-      enc->pubkey_algo = pk->pubkey_algo;
-      keyid_from_pk( pk, enc->keyid );
-      enc->throw_keyid = (opt.throw_keyids || (pk_list->flags&1));
-
-      if (opt.throw_keyids && (PGP6 || PGP7 || PGP8))
+      if ( opt.verbose )
         {
-          log_info(_("you may not use %s while in %s mode\n"),
-                   "--throw-keyids",compliance_option_string());
-          compliance_failure();
+          char *ustr = get_user_id_string_native (enc->keyid);
+          log_info (_("%s/%s encrypted for: \"%s\"\n"),
+                    openpgp_pk_algo_name (enc->pubkey_algo),
+                    openpgp_cipher_algo_name (dek->algo),
+                    ustr );
+          xfree (ustr);
         }
-
-      /* Okay, what's going on: We have the session key somewhere in
-       * the structure DEK and want to encode this session key in an
-       * integer value of n bits. pubkey_nbits gives us the number of
-       * bits we have to use.  We then encode the session key in some
-       * way and we get it back in the big intger value FRAME.  Then
-       * we use FRAME, the public key PK->PKEY and the algorithm
-       * number PK->PUBKEY_ALGO and pass it to pubkey_encrypt which
-       * returns the encrypted value in the array ENC->DATA.  This
-       * array has a size which depends on the used algorithm (e.g. 2
-       * for Elgamal).  We don't need frame anymore because we have
-       * everything now in enc->data which is the passed to
-       * build_packet().  */
-      frame = encode_session_key (pk->pubkey_algo, dek,
-                                  pubkey_nbits (pk->pubkey_algo, pk->pkey));
-      rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
-      gcry_mpi_release (frame);
+      /* And write it. */
+      init_packet (&pkt);
+      pkt.pkttype = PKT_PUBKEY_ENC;
+      pkt.pkt.pubkey_enc = enc;
+      rc = build_packet (out, &pkt);
       if (rc)
-        log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
-      else
-        {
-          if ( opt.verbose )
-            {
-              char *ustr = get_user_id_string_native (enc->keyid);
-              log_info (_("%s/%s encrypted for: \"%s\"\n"),
-                        openpgp_pk_algo_name (enc->pubkey_algo),
-                        openpgp_cipher_algo_name (dek->algo),
-                        ustr );
-              xfree (ustr);
-           }
-          /* And write it. */
-          init_packet (&pkt);
-          pkt.pkttype = PKT_PUBKEY_ENC;
-          pkt.pkt.pubkey_enc = enc;
-          rc = build_packet (out, &pkt);
-          if (rc)
-            log_error ("build_packet(pubkey_enc) failed: %s\n",
-                       gpg_strerror (rc));
-       }
-      free_pubkey_enc(enc);
+        log_error ("build_packet(pubkey_enc) failed: %s\n",
+                   gpg_strerror (rc));
+    }
+  free_pubkey_enc(enc);
+  return rc;
+}
+
+
+/*
+ * Write pubkey-enc packets from the list of PKs to OUT.
+ */
+static int
+write_pubkey_enc_from_list (PK_LIST pk_list, DEK *dek, iobuf_t out)
+{
+  if (opt.throw_keyids && (PGP6 || PGP7 || PGP8))
+    {
+      log_info(_("you may not use %s while in %s mode\n"),
+               "--throw-keyids",compliance_option_string());
+      compliance_failure();
+    }
+
+  for ( ; pk_list; pk_list = pk_list->next )
+    {
+      PKT_public_key *pk = pk_list->pk;
+      int throw_keyid = (opt.throw_keyids || (pk_list->flags&1));
+      int rc = write_pubkey_enc (pk, throw_keyid, dek, out);
       if (rc)
         return rc;
     }
+
   return 0;
 }
 
-
 void
 encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
 {
index 3f06934..89604b4 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -781,10 +780,10 @@ transfer_format_to_openpgp (gcry_sexp_t s_pgp, PKT_public_key *pk)
   ski->algo = protect_algo;
   ski->s2k.mode = s2k_mode;
   ski->s2k.hash_algo = s2k_algo;
-  assert (sizeof ski->s2k.salt == sizeof s2k_salt);
+  log_assert (sizeof ski->s2k.salt == sizeof s2k_salt);
   memcpy (ski->s2k.salt, s2k_salt, sizeof s2k_salt);
   ski->s2k.count = s2k_count;
-  assert (ivlen <= sizeof ski->iv);
+  log_assert (ivlen <= sizeof ski->iv);
   memcpy (ski->iv, iv, ivlen);
   ski->ivlen = ivlen;
 
index 670f256..8176e36 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -302,7 +301,7 @@ free_attributes(PKT_user_id *uid)
 void
 free_user_id (PKT_user_id *uid)
 {
-    assert (uid->ref > 0);
+    log_assert (uid->ref > 0);
     if (--uid->ref)
         return;
 
index 74fa753..907007b 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
@@ -220,7 +219,7 @@ cache_public_key (PKT_public_key * pk)
               pk_cache_entries--;
             }
         }
-      assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
+      log_assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
     }
   pk_cache_entries++;
   ce = xmalloc (sizeof *ce);
@@ -659,8 +658,8 @@ pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
 
   (void) ctx;
 
-  assert (a->pkt->pkttype == PKT_PUBLIC_KEY
-         || a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  log_assert (a->pkt->pkttype == PKT_PUBLIC_KEY
+              || a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
 
   copy_public_key (pk, a->pkt->pkt.public_key);
 }
@@ -779,7 +778,7 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
   KBNODE keyblock;
   u32 pkid[2];
 
-  assert (pk);
+  log_assert (pk);
 #if MAX_PK_CACHE_ENTRIES
   {
     /* Try to get it from the cache */
@@ -817,8 +816,8 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
       return GPG_ERR_NO_PUBKEY;
     }
 
-  assert (keyblock && keyblock->pkt
-          && keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (keyblock && keyblock->pkt
+              && keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   /* We return the primary key.  If KEYID matched a subkey, then we
      return an error.  */
@@ -970,7 +969,7 @@ skip_unusable (void *dummy, u32 * keyid, int uid_no)
 
       /* If UID_NO is non-zero, then the keyblock better have at least
         that many UIDs.  */
-      assert (uids_seen == uid_no);
+      log_assert (uids_seen == uid_no);
     }
 
   if (!unusable)
@@ -1040,8 +1039,8 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
   if (retctx)
     {
       /* Reset the returned context in case of error.  */
-      assert (!ret_kdbhd); /* Not allowed because the handle is stored
-                             in the context.  */
+      log_assert (!ret_kdbhd); /* Not allowed because the handle is stored
+                                  in the context.  */
       *retctx = NULL;
     }
   if (ret_kdbhd)
@@ -1274,7 +1273,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
        {
          unsigned char *fpr = NULL;
          size_t fpr_len;
-         int did_key_byname = 0;
+         int did_akl_local = 0;
          int no_fingerprint = 0;
          const char *mechanism = "?";
 
@@ -1288,7 +1287,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
 
            case AKL_LOCAL:
              mechanism = "Local";
-             did_key_byname = 1;
+             did_akl_local = 1;
              if (retctx)
                {
                  getkey_end (*retctx);
@@ -1321,6 +1320,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
              glo_ctrl.in_auto_key_retrieve--;
              break;
 
+           case AKL_WKD:
+             mechanism = "WKD";
+             glo_ctrl.in_auto_key_retrieve++;
+             rc = keyserver_import_wkd (ctrl, name, &fpr, &fpr_len);
+             glo_ctrl.in_auto_key_retrieve--;
+             break;
+
            case AKL_LDAP:
              mechanism = "LDAP";
              glo_ctrl.in_auto_key_retrieve++;
@@ -1373,7 +1379,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
            {
              char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
 
-             assert (fpr_len <= MAX_FINGERPRINT_LEN);
+             log_assert (fpr_len <= MAX_FINGERPRINT_LEN);
 
              free_strlist (namelist);
              namelist = NULL;
@@ -1386,22 +1392,20 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
 
              add_to_strlist (&namelist, fpr_string);
            }
-         else if (!rc && !fpr && !did_key_byname)
-           /* The acquisition method said no failure occurred, but it
-              didn't return a fingerprint.  That's a failure.  */
-           {
-             no_fingerprint = 1;
+         else if (!rc && !fpr && !did_akl_local)
+            { /* The acquisition method said no failure occurred, but
+                 it didn't return a fingerprint.  That's a failure.  */
+              no_fingerprint = 1;
              rc = GPG_ERR_NO_PUBKEY;
            }
          xfree (fpr);
          fpr = NULL;
 
-         if (!rc && !did_key_byname)
-           /* There was no error and we didn't do a local lookup.
-              This means that we imported a key into the local
-              keyring.  Try to read the imported key from the
-              keyring.  */
-           {
+         if (!rc && !did_akl_local)
+            { /* There was no error and we didn't do a local lookup.
+                This means that we imported a key into the local
+                keyring.  Try to read the imported key from the
+                keyring.  */
              if (retctx)
                {
                  getkey_end (*retctx);
@@ -1435,7 +1439,7 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
 
   if (retctx && *retctx)
     {
-      assert (!(*retctx)->extra_list);
+      log_assert (!(*retctx)->extra_list);
       (*retctx)->extra_list = namelist;
     }
   else
@@ -1559,8 +1563,8 @@ get_pubkey_byfprint_fast (PKT_public_key * pk,
       return GPG_ERR_NO_PUBKEY;
     }
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
-         || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
+              || keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
   if (pk)
     copy_public_key (pk, keyblock->pkt->pkt.public_key);
   release_kbnode (keyblock);
@@ -1678,7 +1682,7 @@ parse_def_secret_key (ctrl_t ctrl)
         }
       else
         {
-          if (! warned)
+          if (! warned && ! opt.quiet)
             log_info (_("using \"%s\" as default secret key for signing\n"),
                       t->d);
           break;
@@ -3106,7 +3110,7 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
   PKT_public_key *pk;
 
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   if (ctx->exact)
     /* Get the key or subkey that matched the low-level search
@@ -3116,8 +3120,8 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
        {
          if ((k->flag & 1))
            {
-             assert (k->pkt->pkttype == PKT_PUBLIC_KEY
-                     || k->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+             log_assert (k->pkt->pkttype == PKT_PUBLIC_KEY
+                          || k->pkt->pkttype == PKT_PUBLIC_SUBKEY);
              foundk = k;
               pk = k->pkt->pkt.public_key;
               pk->flags.exact = 1;
@@ -3131,7 +3135,7 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
     {
       if ((k->flag & 2))
        {
-         assert (k->pkt->pkttype == PKT_USER_ID);
+         log_assert (k->pkt->pkttype == PKT_USER_ID);
          foundu = k->pkt->pkt.user_id;
          break;
        }
@@ -3195,6 +3199,7 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
              if (DBG_LOOKUP)
                log_debug ("\tsubkey has expired\n");
              continue;
+
            }
          if (pk->timestamp > curtime && !opt.ignore_valid_from)
            {
@@ -3769,6 +3774,8 @@ parse_auto_key_locate (char *options)
        akl->type = AKL_PKA;
       else if (ascii_strcasecmp (tok, "dane") == 0)
        akl->type = AKL_DANE;
+      else if (ascii_strcasecmp (tok, "wkd") == 0)
+       akl->type = AKL_WKD;
       else if ((akl->spec = parse_keyserver_uri (tok, 1)))
        akl->type = AKL_SPEC;
       else
@@ -3848,8 +3855,8 @@ have_secret_key_with_kid (u32 *keyid)
              match a single key or subkey.  */
          if ((node->flag & 1))
             {
-              assert (node->pkt->pkttype == PKT_PUBLIC_KEY
-                      || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+              log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
+                          || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
 
               if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
                result = 1; /* Secret key available.  */
index 56bbd0d..006c95b 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -26,7 +26,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
-#include <assert.h>
 #ifdef HAVE_STAT
 #include <sys/stat.h> /* for stat() */
 #endif
@@ -185,6 +184,7 @@ enum cmd_and_opt_values
     oWithICAOSpelling,
     oWithKeygrip,
     oWithSecret,
+    oWithWKDHash,
     oAnswerYes,
     oAnswerNo,
     oKeyring,
@@ -486,7 +486,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aGenRandom,"gen-random", "@" ),
   ARGPARSE_c (aServer,   "server",  N_("run in server mode")),
   ARGPARSE_c (aTOFUPolicy, "tofu-policy",
-             N_("|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)")),
+             N_("|VALUE|set the TOFU policy for a key")),
 
   ARGPARSE_group (301, N_("@\nOptions:\n ")),
 
@@ -681,7 +681,9 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
   ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
   ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */
+#ifndef NO_TRUST_MODELS
   ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
+#endif
   ARGPARSE_s_s (oTrustModel, "trust-model", "@"),
   ARGPARSE_s_s (oTOFUDefaultPolicy, "tofu-default-policy", "@"),
   ARGPARSE_s_s (oTOFUDBFormat, "tofu-db-format", "@"),
@@ -719,6 +721,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
   ARGPARSE_s_n (oWithKeygrip,     "with-keygrip", "@"),
   ARGPARSE_s_n (oWithSecret,      "with-secret", "@"),
+  ARGPARSE_s_n (oWithWKDHash,     "with-wkd-hash", "@"),
   ARGPARSE_s_s (oDisableCipherAlgo,  "disable-cipher-algo", "@"),
   ARGPARSE_s_s (oDisablePubkeyAlgo,  "disable-pubkey-algo", "@"),
   ARGPARSE_s_n (oAllowNonSelfsignedUID,      "allow-non-selfsigned-uid", "@"),
@@ -1385,7 +1388,7 @@ check_permissions (const char *path, int item)
   if(opt.no_perm_warn)
     return 0;
 
-  assert(item==0 || item==1 || item==2);
+  log_assert(item==0 || item==1 || item==2);
 
   /* extensions may attach a path */
   if(item==2 && path[0]!=DIRSEP_C)
@@ -2573,6 +2576,10 @@ main (int argc, char **argv)
             opt.with_secret = 1;
             break;
 
+         case oWithWKDHash:
+            opt.with_wkd_hash = 1;
+            break;
+
          case oSecretKeyring:
             /* Ignore this old option.  */
             break;
diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c
new file mode 100644 (file)
index 0000000..d6f0307
--- /dev/null
@@ -0,0 +1,3038 @@
+/* gpgcompose.c - Maintainer tool to create OpenPGP messages by hand.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <errno.h>
+
+#include "gpg.h"
+#include "packet.h"
+#include "keydb.h"
+#include "main.h"
+#include "options.h"
+
+static int do_debug;
+#define debug(fmt, ...) \
+  do { if (do_debug) log_debug (fmt, ##__VA_ARGS__); } while (0)
+\f
+/* --encryption, for instance, adds a filter in front of out.  There
+   is an operator (--encryption-pop) to end this.  We use the
+   following infrastructure to make it easy to pop the state.  */
+struct filter
+{
+  void *func;
+  void *context;
+  int pkttype;
+  int partial_block_mode;
+  struct filter *next;
+};
+
+static struct filter *filters;
+
+static void
+filter_push (iobuf_t out, void *func, void *context,
+             int type, int partial_block_mode)
+{
+  gpg_error_t err;
+  struct filter *f = xmalloc_clear (sizeof (*f));
+  f->next = filters;
+  f->func = func;
+  f->context = context;
+  f->pkttype = type;
+  f->partial_block_mode = partial_block_mode;
+
+  filters = f;
+
+  err = iobuf_push_filter (out, func, context);
+  if (err)
+    log_fatal ("Adding filter: %s\n", gpg_strerror (err));
+}
+
+static void
+filter_pop (iobuf_t out, int expected_type)
+{
+  gpg_error_t err;
+  struct filter *f = filters;
+
+  log_assert (f);
+
+  if (f->pkttype != expected_type)
+    log_fatal ("Attempted to pop a %s container, "
+               "but current container is a %s container.\n",
+               pkttype_str (f->pkttype), pkttype_str (expected_type));
+
+  if (f->pkttype == PKT_ENCRYPTED || f->pkttype == PKT_ENCRYPTED_MDC)
+    {
+      err = iobuf_pop_filter (out, f->func, f->context);
+      if (err)
+        log_fatal ("Popping encryption filter: %s\n", gpg_strerror (err));
+    }
+  else
+    log_fatal ("FILTERS appears to be corrupted.\n");
+
+  if (f->partial_block_mode)
+    iobuf_set_partial_body_length_mode (out, 0);
+
+  filters = f->next;
+  xfree (f);
+}
+\f
+/* Return if CIPHER_ID is a valid cipher.  */
+static int
+valid_cipher (int cipher_id)
+{
+  return (cipher_id == CIPHER_ALGO_IDEA
+          || cipher_id == CIPHER_ALGO_3DES
+          || cipher_id == CIPHER_ALGO_CAST5
+          || cipher_id == CIPHER_ALGO_BLOWFISH
+          || cipher_id == CIPHER_ALGO_AES
+          || cipher_id == CIPHER_ALGO_AES192
+          || cipher_id == CIPHER_ALGO_AES256
+          || cipher_id == CIPHER_ALGO_TWOFISH
+          || cipher_id == CIPHER_ALGO_CAMELLIA128
+          || cipher_id == CIPHER_ALGO_CAMELLIA192
+          || cipher_id == CIPHER_ALGO_CAMELLIA256);
+}
+\f
+/* Parse a session key encoded as a string of the form x:HEXDIGITS
+   where x is the algorithm id.  (This is the format emitted by gpg
+   --show-session-key.)  */
+struct session_key
+{
+  int algo;
+  int keylen;
+  char *key;
+};
+
+static struct session_key
+parse_session_key (const char *option, char *p, int require_algo)
+{
+  char *tail;
+  struct session_key sk;
+
+  memset (&sk, 0, sizeof (sk));
+
+  /* Check for the optional "cipher-id:" at the start of the
+     string.  */
+  errno = 0;
+  sk.algo = strtol (p, &tail, 10);
+  if (! errno && tail && *tail == ':')
+    {
+      if (! valid_cipher (sk.algo))
+        log_info ("%s: %d is not a known cipher (but using anyways)\n",
+                  option, sk.algo);
+      p = tail + 1;
+    }
+  else if (require_algo)
+    log_fatal ("%s: Session key must have the form algo:HEXCHARACTERS.\n",
+               option);
+  else
+    sk.algo = 0;
+
+  /* Ignore a leading 0x.  */
+  if (p[0] == '0' && p[1] == 'x')
+    p += 2;
+
+  if (strlen (p) % 2 != 0)
+    log_fatal ("%s: session key must consist of an even number of hexadecimal characters.\n",
+               option);
+
+  sk.keylen = strlen (p) / 2;
+  sk.key = xmalloc (sk.keylen);
+
+  if (hex2bin (p, sk.key, sk.keylen) == -1)
+    log_fatal ("%s: Session key must only contain hexadecimal characters\n",
+               option);
+
+  return sk;
+}
+\f
+/* A callback.
+
+   OPTION_STR is the option that was matched.  ARGC is the number of
+   arguments following the option and ARGV are those arguments.
+   (Thus, argv[0] is the first string following the option and
+   argv[-1] is the option.)
+
+   COOKIE is the opaque value passed to process_options.  */
+typedef int (*option_prcessor_t) (const char *option_str,
+                                  int argc, char *argv[],
+                                  void *cookie);
+
+struct option
+{
+  /* The option that this matches.  This must start with "--" or be
+     the empty string.  The empty string matches bare arguments.  */
+  const char *option;
+  /* The function to call to process this option.  */
+  option_prcessor_t func;
+  /* Documentation.  */
+  const char *help;
+};
+
+/* Merge two lists of options.  Note: this makes a shallow copy!  The
+   caller must xfree() the result.  */
+static struct option *
+merge_options (struct option a[], struct option b[])
+{
+  int i, j;
+  struct option *c;
+
+  for (i = 0; a[i].option; i ++)
+    ;
+  for (j = 0; b[j].option; j ++)
+    ;
+
+  c = xmalloc ((i + j + 1) * sizeof (struct option));
+  memcpy (c, a, i * sizeof (struct option));
+  memcpy (&c[i], b, j * sizeof (struct option));
+  c[i + j].option = NULL;
+
+  if (a[i].help && b[j].help)
+    c[i + j].help = xasprintf ("%s\n\n%s", a[i].help, b[j].help);
+  else if (a[i].help)
+    c[i + j].help = a[i].help;
+  else if (b[j].help)
+    c[i + j].help = b[j].help;
+
+  return c;
+}
+
+/* Returns whether ARG is an option.  All options start with --.  */
+static int
+is_option (const char *arg)
+{
+  return arg[0] == '-' && arg[1] == '-';
+}
+
+/* OPTIONS is a NULL terminated array of struct option:s.  Finds the
+   entry that is the same as ARG.  Returns -1 if no entry is found.
+   The empty string option matches bare arguments.  */
+static int
+match_option (const struct option options[], const char *arg)
+{
+  int i;
+  int bare_arg = ! is_option (arg);
+
+  for (i = 0; options[i].option; i ++)
+    if ((! bare_arg && strcmp (options[i].option, arg) == 0)
+        /* Non-options match the empty string.  */
+        || (bare_arg && options[i].option[0] == '\0'))
+      return i;
+
+  return -1;
+}
+
+static void
+show_help (struct option options[])
+{
+  int i;
+  int max_length = 0;
+  int space;
+
+  for (i = 0; options[i].option; i ++)
+    {
+      const char *option = options[i].option[0] ? options[i].option : "ARG";
+      int l = strlen (option);
+      if (l > max_length)
+        max_length = l;
+    }
+
+  space = 72 - (max_length + 2);
+  if (space < 40)
+    space = 40;
+
+  for (i = 0; ; i ++)
+    {
+      const char *option = options[i].option;
+      const char *help = options[i].help;
+
+      int l;
+      int j;
+      char *tmp;
+      char *formatted;
+      char *p;
+      char *newline;
+
+      if (! option && ! help)
+        break;
+
+      if (option)
+        {
+          const char *o = option[0] ? option : "ARG";
+          l = strlen (o);
+          fprintf (stderr, "%s", o);
+        }
+
+      if (! help)
+        {
+          fputc ('\n', stderr);
+          continue;
+        }
+
+      if (option)
+        for (j = l; j < max_length + 2; j ++)
+          fputc (' ', stderr);
+
+#define BOLD_START "\033[1m"
+#define NORMAL_RESTORE "\033[0m"
+#define BOLD(x) BOLD_START x NORMAL_RESTORE
+
+      if (! option || options[i].func)
+        tmp = (char *) help;
+      else
+        tmp = xasprintf ("%s " BOLD("(Unimplemented.)"), help);
+
+      if (! option)
+        space = 72;
+      formatted = format_text (tmp, 0, space, space + 4);
+
+      if (tmp != help)
+        xfree (tmp);
+
+      if (! option)
+        {
+          fprintf (stderr, "\n%s\n", formatted);
+          break;
+        }
+
+      for (p = formatted;
+           p && *p;
+           p = (*newline == '\0') ? newline : newline + 1)
+        {
+          newline = strchr (p, '\n');
+          if (! newline)
+            newline = &p[strlen (p)];
+
+          l = (size_t) newline - (size_t) p;
+
+          if (p != formatted)
+            for (j = 0; j < max_length + 2; j ++)
+              fputc (' ', stderr);
+
+          fwrite (p, l, 1, stderr);
+          fputc ('\n', stderr);
+        }
+
+      xfree (formatted);
+  }
+}
+
+/* Return value is number of consumed argv elements.  */
+static int
+process_options (const char *parent_option,
+                 struct option break_options[],
+                 struct option local_options[], void *lcookie,
+                 struct option global_options[], void *gcookie,
+                 int argc, char *argv[])
+{
+  int i;
+  for (i = 0; i < argc; i ++)
+    {
+      int j;
+      struct option *option;
+      void *cookie;
+      int bare_arg;
+      option_prcessor_t func;
+      int consumed;
+
+      if (break_options)
+        {
+          j = match_option (break_options, argv[i]);
+          if (j != -1)
+            /* Match.  Break out.  */
+            return i;
+        }
+
+      j = match_option (local_options, argv[i]);
+      if (j == -1)
+        {
+          if (global_options)
+            j = match_option (global_options, argv[i]);
+          if (j == -1)
+            {
+              if (strcmp (argv[i], "--help") == 0)
+                {
+                  if (! global_options)
+                    show_help (local_options);
+                  else
+                    {
+                      struct option *combined
+                        = merge_options (local_options, global_options);
+                      show_help (combined);
+                      xfree (combined);
+                    }
+                  g10_exit (0);
+                }
+
+              if (parent_option)
+                log_fatal ("%s: Unknown option: %s\n", parent_option, argv[i]);
+              else
+                log_fatal ("Unknown option: %s\n", argv[i]);
+            }
+
+          option = &global_options[j];
+          cookie = gcookie;
+        }
+      else
+        {
+          option = &local_options[j];
+          cookie = lcookie;
+        }
+
+      bare_arg = strcmp (option->option, "") == 0;
+
+      func = option->func;
+      if (! func)
+        {
+          if (bare_arg)
+            log_fatal ("Bare arguments unimplemented.\n");
+          else
+            log_fatal ("Unimplemented option: %s\n",
+                       option->option);
+        }
+
+      consumed = func (bare_arg ? parent_option : argv[i],
+                       argc - i - !bare_arg, &argv[i + !bare_arg],
+                       cookie);
+      i += consumed;
+      if (bare_arg)
+        i --;
+    }
+
+  return i;
+}
+\f
+/* The keys, subkeys, user ids and user attributes in the order that
+   they were added.  */
+PACKET components[20];
+/* The number of components.  */
+int ncomponents;
+
+static int
+add_component (int pkttype, void *component)
+{
+  int i = ncomponents ++;
+
+  log_assert (i < sizeof (components) / sizeof (components[0]));
+  log_assert (pkttype == PKT_PUBLIC_KEY
+              || pkttype == PKT_PUBLIC_SUBKEY
+              || pkttype == PKT_SECRET_KEY
+              || pkttype == PKT_SECRET_SUBKEY
+              || pkttype == PKT_USER_ID
+              || pkttype == PKT_ATTRIBUTE);
+
+  components[i].pkttype = pkttype;
+  components[i].pkt.generic = component;
+
+  return i;
+}
+
+static void
+dump_component (PACKET *pkt)
+{
+  struct kbnode_struct kbnode;
+
+  if (! do_debug)
+    return;
+
+  memset (&kbnode, 0, sizeof (kbnode));
+  kbnode.pkt = pkt;
+  dump_kbnode (&kbnode);
+}
+
+/* Returns the first primary key in COMPONENTS or NULL if there is
+   none.  */
+static PKT_public_key *
+primary_key (void)
+{
+  int i;
+  for (i = 0; i < ncomponents; i ++)
+    if (components[i].pkttype == PKT_PUBLIC_KEY)
+      return components[i].pkt.public_key;
+  return NULL;
+}
+\f
+/* The last session key (updated when adding a SK-ESK, PK-ESK or SED
+   packet.  */
+static DEK session_key;
+\f
+static int user_id (const char *option, int argc, char *argv[],
+                    void *cookie);
+static int public_key (const char *option, int argc, char *argv[],
+                       void *cookie);
+static int sk_esk (const char *option, int argc, char *argv[],
+                   void *cookie);
+static int pk_esk (const char *option, int argc, char *argv[],
+                   void *cookie);
+static int encrypted (const char *option, int argc, char *argv[],
+                      void *cookie);
+static int encrypted_pop (const char *option, int argc, char *argv[],
+                          void *cookie);
+static int literal (const char *option, int argc, char *argv[],
+                    void *cookie);
+static int signature (const char *option, int argc, char *argv[],
+                      void *cookie);
+static int copy (const char *option, int argc, char *argv[],
+                 void *cookie);
+
+static struct option major_options[] = {
+  { "--user-id", user_id, "Create a user id packet." },
+  { "--public-key", public_key, "Create a public key packet." },
+  { "--private-key", NULL, "Create a private key packet." },
+  { "--public-subkey", public_key, "Create a subkey packet." },
+  { "--private-subkey", NULL, "Create a private subkey packet." },
+  { "--sk-esk", sk_esk,
+    "Create a symmetric-key encrypted session key packet." },
+  { "--pk-esk", pk_esk,
+    "Create a public-key encrypted session key packet." },
+  { "--encrypted", encrypted, "Create a symmetrically encrypted data packet." },
+  { "--encrypted-mdc", encrypted,
+    "Create a symmetrically encrypted and integrity protected data packet." },
+  { "--encrypted-pop", encrypted_pop,
+    "Pop an encryption container." },
+  { "--compressed", NULL, "Create a compressed data packet." },
+  { "--literal", literal, "Create a literal (plaintext) data packet." },
+  { "--signature", signature, "Create a signature packet." },
+  { "--onepass-sig", NULL, "Create a one-pass signature packet." },
+  { "--copy", copy, "Copy the specified file." },
+  { NULL, NULL,
+    "To get more information about a given command, use:\n\n"
+    "  $ gpgcompose --command --help to list a command's options."},
+};
+\f
+static struct option global_options[] = {
+  { NULL, NULL, NULL },
+};
+\f
+/* Make our lives easier and use a static limit for the user name.
+   10k is way more than enough anyways... */
+const int user_id_max_len = 10 * 1024;
+
+static int
+user_id_name (const char *option, int argc, char *argv[], void *cookie)
+{
+  PKT_user_id *uid = cookie;
+  int l;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s USER_ID\n", option);
+
+  if (uid->len)
+    log_fatal ("Attempt to set user id multiple times.\n");
+
+  l = strlen (argv[0]);
+  if (l > user_id_max_len)
+    log_fatal ("user id too long (max: %d)\n", user_id_max_len);
+
+  memcpy (uid->name, argv[0], l);
+  uid->name[l] = 0;
+  uid->len = l;
+
+  return 1;
+}
+
+static struct option user_id_options[] = {
+  { "", user_id_name,
+    "Set the user id.  This is usually in the format "
+    "\"Name (comment) <email@example.org>\"" },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --user-id \"USERID\" | " GPG_NAME " --list-packets" }
+};
+
+static int
+user_id (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+  gpg_error_t err;
+  PKT_user_id *uid = xmalloc_clear (sizeof (*uid) + user_id_max_len);
+  int c = add_component (PKT_USER_ID, uid);
+  int processed;
+
+  processed = process_options (option,
+                               major_options,
+                               user_id_options, uid,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (! uid->len)
+    log_fatal ("%s: user id not given", option);
+
+  err = build_packet (out, &components[c]);
+  if (err)
+    log_fatal ("Serializing user id packet: %s\n", gpg_strerror (err));
+
+  debug ("Wrote user id packet:\n");
+  dump_component (&components[c]);
+
+  return processed;
+}
+\f
+static int
+pk_search_terms (const char *option, int argc, char *argv[], void *cookie)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE hd;
+  KEYDB_SEARCH_DESC desc;
+  kbnode_t kb;
+  PKT_public_key *pk = cookie;
+  PKT_public_key *pk_ref;
+  int i;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s KEYID\n", option);
+
+  if (pk->pubkey_algo)
+    log_fatal ("%s: multiple keys provided\n", option);
+
+  err = classify_user_id (argv[0], &desc, 0);
+  if (err)
+    log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
+
+  hd = keydb_new ();
+
+  err = keydb_search (hd, &desc, 1, NULL);
+  if (err)
+    log_fatal ("looking up '%s': %s\n", argv[0], gpg_strerror (err));
+
+  err = keydb_get_keyblock (hd, &kb);
+  if (err)
+    log_fatal ("retrieving keyblock for '%s': %s\n",
+               argv[0], gpg_strerror (err));
+
+  keydb_release (hd);
+
+  pk_ref = kb->pkt->pkt.public_key;
+
+  /* Copy the timestamp (if not already set), algo and public key
+     parameters.  */
+  if (! pk->timestamp)
+    pk->timestamp = pk_ref->timestamp;
+  pk->pubkey_algo = pk_ref->pubkey_algo;
+  for (i = 0; i < pubkey_get_npkey (pk->pubkey_algo); i ++)
+    pk->pkey[i] = gcry_mpi_copy (pk_ref->pkey[i]);
+
+  release_kbnode (kb);
+
+  return 1;
+}
+
+static int
+pk_timestamp (const char *option, int argc, char *argv[], void *cookie)
+{
+  PKT_public_key *pk = cookie;
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s TIMESTAMP\n", option);
+
+  errno = 0;
+  pk->timestamp = parse_timestamp (argv[0], &tail);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  return 1;
+}
+
+#define TIMESTAMP_HELP \
+  "Either as seconds since the epoch or as an ISO 8601 formatted " \
+  "string (yyyymmddThhmmss, where the T is a literal)."
+
+static struct option pk_options[] = {
+  { "--timestamp", pk_timestamp,
+    "The creation time.  " TIMESTAMP_HELP },
+  { "", pk_search_terms,
+    "The key to copy the creation time and public key parameters from."  },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --public-key $KEYID --user-id \"USERID\" \\\n"
+    "  | " GPG_NAME " --list-packets" }
+};
+
+static int
+public_key (const char *option, int argc, char *argv[], void *cookie)
+{
+  gpg_error_t err;
+  iobuf_t out = cookie;
+  PKT_public_key *pk;
+  int c;
+  int processed;
+  int t = (strcmp (option, "--public-key") == 0
+           ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY);
+
+  (void) option;
+
+  pk = xmalloc_clear (sizeof (*pk));
+  pk->version = 4;
+
+  c = add_component (t, pk);
+
+  processed = process_options (option,
+                               major_options,
+                               pk_options, pk,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (! pk->pubkey_algo)
+    log_fatal ("%s: key to extract public key parameters from not given",
+               option);
+
+  /* Clear the keyid in case we updated one of the relevant fields
+     after accessing it.  */
+  pk->keyid[0] = pk->keyid[1] = 0;
+
+  err = build_packet (out, &components[c]);
+  if (err)
+    log_fatal ("serializing %s packet: %s\n",
+               t == PKT_PUBLIC_KEY ? "public key" : "subkey",
+               gpg_strerror (err));
+
+  debug ("Wrote %s packet:\n",
+         t == PKT_PUBLIC_KEY ? "public key" : "subkey");
+  dump_component (&components[c]);
+
+  return processed;
+}
+\f
+struct siginfo
+{
+  /* Key with which to sign.  */
+  kbnode_t issuer_kb;
+  PKT_public_key *issuer_pk;
+
+  /* Overrides the issuer's key id.  */
+  u32 issuer_keyid[2];
+  /* Sets the issuer's keyid to the primary key's key id.  */
+  int issuer_keyid_self;
+
+  /* Key to sign.  */
+  PKT_public_key *pk;
+  /* Subkey to sign.  */
+  PKT_public_key *sk;
+  /* User id to sign.  */
+  PKT_user_id *uid;
+
+  int class;
+  int digest_algo;
+  u32 timestamp;
+  u32 key_expiration;
+
+  byte *cipher_algorithms;
+  int cipher_algorithms_len;
+  byte *digest_algorithms;
+  int digest_algorithms_len;
+  byte *compress_algorithms;
+  int compress_algorithms_len;
+
+  u32 expiration;
+
+  int exportable_set;
+  int exportable;
+
+  int revocable_set;
+  int revocable;
+
+  int trust_level_set;
+  byte trust_args[2];
+
+  char *trust_scope;
+
+  struct revocation_key *revocation_key;
+  int nrevocation_keys;
+
+  struct notation *notations;
+
+  byte *key_server_preferences;
+  int key_server_preferences_len;
+
+  char *key_server;
+
+  int primary_user_id_set;
+  int primary_user_id;
+
+  char *policy_uri;
+
+  byte *key_flags;
+  int key_flags_len;
+
+  char *signers_user_id;
+
+  byte reason_for_revocation_code;
+  char *reason_for_revocation;
+
+  byte *features;
+  int features_len;
+
+  /* Whether to corrupt the signature.  */
+  int corrupt;
+};
+
+static int
+sig_issuer (const char *option, int argc, char *argv[], void *cookie)
+{
+  gpg_error_t err;
+  KEYDB_HANDLE hd;
+  KEYDB_SEARCH_DESC desc;
+  struct siginfo *si = cookie;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s KEYID\n", option);
+
+  if (si->issuer_pk)
+    log_fatal ("%s: multiple keys provided\n", option);
+
+  err = classify_user_id (argv[0], &desc, 0);
+  if (err)
+    log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
+
+  hd = keydb_new ();
+
+  err = keydb_search (hd, &desc, 1, NULL);
+  if (err)
+    log_fatal ("looking up '%s': %s\n", argv[0], gpg_strerror (err));
+
+  err = keydb_get_keyblock (hd, &si->issuer_kb);
+  if (err)
+    log_fatal ("retrieving keyblock for '%s': %s\n",
+               argv[0], gpg_strerror (err));
+
+  keydb_release (hd);
+
+  si->issuer_pk = si->issuer_kb->pkt->pkt.public_key;
+
+  return 1;
+}
+
+static int
+sig_issuer_keyid (const char *option, int argc, char *argv[], void *cookie)
+{
+  gpg_error_t err;
+  KEYDB_SEARCH_DESC desc;
+  struct siginfo *si = cookie;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s KEYID|self\n", option);
+
+  if (si->issuer_keyid[0] || si->issuer_keyid[1] || si->issuer_keyid_self)
+    log_fatal ("%s given multiple times.\n", option);
+
+  if (strcasecmp (argv[0], "self") == 0)
+    {
+      si->issuer_keyid_self = 1;
+      return 1;
+    }
+
+  err = classify_user_id (argv[0], &desc, 0);
+  if (err)
+    log_fatal ("search terms '%s': %s\n", argv[0], gpg_strerror (err));
+
+  if (desc.mode != KEYDB_SEARCH_MODE_LONG_KID)
+    log_fatal ("%s is not a valid long key id.\n", argv[0]);
+
+  keyid_copy (si->issuer_keyid, desc.u.kid);
+
+  return 1;
+}
+
+static int
+sig_pk (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int i;
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s COMPONENT_INDEX\n", option);
+
+  errno = 0;
+  i = strtoul (argv[0], &tail, 10);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  if (i >= ncomponents)
+    log_fatal ("%d: No such component (have %d components so far)\n",
+               i, ncomponents);
+  if (! (components[i].pkttype == PKT_PUBLIC_KEY
+         || components[i].pkttype == PKT_PUBLIC_SUBKEY))
+    log_fatal ("Component %d is not a public key or a subkey.", i);
+
+  if (strcmp (option, "--pk") == 0)
+    {
+      if (si->pk)
+        log_fatal ("%s already given.\n", option);
+      si->pk = components[i].pkt.public_key;
+    }
+  else if (strcmp (option, "--sk") == 0)
+    {
+      if (si->sk)
+        log_fatal ("%s already given.\n", option);
+      si->sk = components[i].pkt.public_key;
+    }
+  else
+    log_fatal ("Cannot handle %s\n", option);
+
+  return 1;
+}
+
+static int
+sig_user_id (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int i;
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s COMPONENT_INDEX\n", option);
+  if (si->uid)
+    log_fatal ("%s already given.\n", option);
+
+  errno = 0;
+  i = strtoul (argv[0], &tail, 10);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  if (i >= ncomponents)
+    log_fatal ("%d: No such component (have %d components so far)\n",
+               i, ncomponents);
+  if (! (components[i].pkttype != PKT_USER_ID
+         || components[i].pkttype == PKT_ATTRIBUTE))
+    log_fatal ("Component %d is not a public key or a subkey.", i);
+
+  si->uid = components[i].pkt.user_id;
+
+  return 1;
+}
+
+static int
+sig_class (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int i;
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s CLASS\n", option);
+
+  errno = 0;
+  i = strtoul (argv[0], &tail, 0);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  si->class = i;
+
+  return 1;
+}
+
+static int
+sig_digest (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int i;
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s DIGEST_ALGO\n", option);
+
+  errno = 0;
+  i = strtoul (argv[0], &tail, 10);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  si->digest_algo = i;
+
+  return 1;
+}
+
+static int
+sig_timestamp (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s TIMESTAMP\n", option);
+
+  errno = 0;
+  si->timestamp = parse_timestamp (argv[0], &tail);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  return 1;
+}
+
+static int
+sig_expiration (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int is_expiration = strcmp (option, "--expiration") == 0;
+  u32 *i = is_expiration ? &si->expiration : &si->key_expiration;
+
+  if (! is_expiration)
+    log_assert (strcmp (option, "--key-expiration") == 0);
+
+  if (argc == 0)
+    log_fatal ("Usage: %s DURATION\n", option);
+
+  *i = parse_expire_string (argv[0]);
+  if (*i == (u32)-1)
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+
+  return 1;
+}
+
+static int
+sig_int_list (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int nvalues = 1;
+  char *values = xmalloc (nvalues * sizeof (values[0]));
+  char *tail = argv[0];
+  int i;
+  byte **a;
+  int *n;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s VALUE[,VALUE...]\n", option);
+
+  for (i = 0; tail && *tail; i ++)
+    {
+      int v;
+      char *old_tail = tail;
+
+      errno = 0;
+      v = strtol (tail, &tail, 0);
+      if (errno || old_tail == tail || (tail && !(*tail == ',' || *tail == 0)))
+        log_fatal ("Invalid value passed to %s (%s).  "
+                   "Expected a list of comma separated numbers\n",
+                   option, argv[0]);
+
+      if (! (0 <= v && v <= 255))
+        log_fatal ("%s: %d is out of range (Expected: 0-255)\n", option, v);
+
+      if (i == nvalues)
+        {
+          nvalues *= 2;
+          values = xrealloc (values, nvalues * sizeof (values[0]));
+        }
+
+      values[i] = v;
+
+      if (*tail == ',')
+        tail ++;
+      else
+        log_assert (*tail == 0);
+    }
+
+  if (strcmp ("--cipher-algos", option) == 0)
+    {
+      a = &si->cipher_algorithms;
+      n = &si->cipher_algorithms_len;
+    }
+  else if (strcmp ("--digest-algos", option) == 0)
+    {
+      a = &si->digest_algorithms;
+      n = &si->digest_algorithms_len;
+    }
+  else if (strcmp ("--compress-algos", option) == 0)
+    {
+      a = &si->compress_algorithms;
+      n = &si->compress_algorithms_len;
+    }
+  else
+    log_fatal ("Cannot handle %s\n", option);
+
+  if (*a)
+    log_fatal ("Option %s given multiple times.\n", option);
+
+  *a = values;
+  *n = i;
+
+  return 1;
+}
+
+static int
+sig_flag (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int range[2] = {0, 255};
+  char *tail;
+  int v;
+
+  if (strcmp (option, "--primary-user-id") == 0)
+    range[1] = 1;
+
+  if (argc <= 1)
+    {
+      if (range[0] == 0 && range[1] == 1)
+        log_fatal ("Usage: %s 0|1\n", option);
+      else
+        log_fatal ("Usage: %s %d-%d\n", option, range[0], range[1]);
+    }
+
+  errno = 0;
+  v = strtol (argv[0], &tail, 0);
+  if (errno || (tail && *tail) || !(range[0] <= v && v <= range[1]))
+    log_fatal ("Invalid value passed to %s (%s).  Expected %d-%d\n",
+               option, argv[0], range[0], range[1]);
+
+  if (strcmp (option, "--exportable") == 0)
+    {
+      si->exportable_set = 1;
+      si->exportable = v;
+    }
+  else if (strcmp (option, "--revocable") == 0)
+    {
+      si->revocable_set = 1;
+      si->revocable = v;
+    }
+  else if (strcmp (option, "--primary-user-id") == 0)
+    {
+      si->primary_user_id_set = 1;
+      si->primary_user_id = v;
+    }
+  else
+    log_fatal ("Cannot handle %s\n", option);
+
+  return 1;
+}
+
+static int
+sig_trust_level (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int i;
+  char *tail;
+
+  if (argc <= 1)
+    log_fatal ("Usage: %s DEPTH TRUST_AMOUNT\n", option);
+
+  for (i = 0; i < sizeof (si->trust_args) / sizeof (si->trust_args[0]); i ++)
+    {
+      int v;
+
+      errno = 0;
+      v = strtol (argv[i], &tail, 0);
+      if (errno || (tail && *tail) || !(0 <= v && v <= 255))
+        log_fatal ("Invalid value passed to %s (%s).  Expected 0-255\n",
+                   option, argv[i]);
+
+      si->trust_args[i] = v;
+    }
+
+  si->trust_level_set = 1;
+
+  return 2;
+}
+
+static int
+sig_string_arg (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  char *p = argv[0];
+  char **s;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s STRING\n", option);
+
+  if (strcmp (option, "--trust-scope") == 0)
+    s = &si->trust_scope;
+  else if (strcmp (option, "--key-server") == 0)
+    s = &si->key_server;
+  else if (strcmp (option, "--signers-user-id") == 0)
+    s = &si->signers_user_id;
+  else if (strcmp (option, "--policy-uri") == 0)
+    s = &si->policy_uri;
+  else
+    log_fatal ("Cannot handle %s\n", option);
+
+  if (*s)
+    log_fatal ("%s already given.\n", option);
+
+  *s = xstrdup (p);
+
+  return 1;
+}
+
+static int
+sig_revocation_key (const char *option, int argc, char *argv[], void *cookie)
+{
+  gpg_error_t err;
+  struct siginfo *si = cookie;
+  int v;
+  char *tail;
+  PKT_public_key pk;
+  struct revocation_key *revkey;
+
+  if (argc < 2)
+    log_fatal ("Usage: %s CLASS KEYID\n", option);
+
+  memset (&pk, 0, sizeof (pk));
+
+  errno = 0;
+  v = strtol (argv[0], &tail, 16);
+  if (errno || (tail && *tail) || !(0 <= v && v <= 255))
+    log_fatal ("%s: Invalid class value (%s).  Expected 0-255\n",
+               option, argv[0]);
+
+  pk.req_usage = PUBKEY_USAGE_SIG;
+  err = get_pubkey_byname (NULL, NULL, &pk, argv[1], NULL, NULL, 1, 1);
+  if (err)
+    log_fatal ("looking up key %s: %s\n", argv[1], gpg_strerror (err));
+
+  si->nrevocation_keys ++;
+  si->revocation_key = xrealloc (si->revocation_key,
+                                 si->nrevocation_keys
+                                 * sizeof (*si->revocation_key));
+  revkey = &si->revocation_key[si->nrevocation_keys - 1];
+
+  revkey->class = v;
+  revkey->algid = pk.pubkey_algo;
+  fingerprint_from_pk (&pk, revkey->fpr, NULL);
+
+  release_public_key_parts (&pk);
+
+  return 2;
+}
+
+static int
+sig_notation (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int is_blob = strcmp (option, "--notation") != 0;
+  struct notation *notation;
+  char *p = argv[0];
+  int p_free = 0;
+  char *data;
+  int data_size;
+  int data_len;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s [!<]name=value\n", option);
+
+  if ((p[0] == '!' && p[1] == '<') || p[0] == '<')
+    /* Read from a file.  */
+    {
+      char *filename = NULL;
+      iobuf_t in;
+      int prefix;
+
+      if (p[0] == '<')
+        p ++;
+      else
+        {
+          /* Remove the '<', which string_to_notation does not
+             understand, and preserve the '!'.  */
+          p = xstrdup (&p[1]);
+          p_free = 1;
+          p[0] = '!';
+        }
+
+      filename = strchr (p, '=');
+      if (! filename)
+        log_fatal ("No value specified.  Usage: %s [!<]name=value\n",
+                   option);
+      filename ++;
+
+      prefix = (size_t) filename - (size_t) p;
+
+      errno = 0;
+      in = iobuf_open (filename);
+      if (! in)
+        log_fatal ("Opening '%s': %s\n",
+                   filename, errno ? strerror (errno): "unknown error");
+
+      /* A notation can be at most about a few dozen bytes short of
+         64k.  Since this is relatively small, we just allocate that
+         much instead of trying to dynamically size a buffer.  */
+      data_size = 64 * 1024;
+      data = xmalloc (data_size);
+      log_assert (prefix <= data_size);
+      memcpy (data, p, prefix);
+
+      data_len = iobuf_read (in, &data[prefix], data_size - prefix - 1);
+      if (data_len == -1)
+        /* EOF => 0 bytes read.  */
+        data_len = 0;
+
+      if (data_len == data_size - prefix - 1)
+        /* Technically, we should do another read and check for EOF,
+           but what's one byte more or less?  */
+        log_fatal ("Notation data doesn't fit in the packet.\n");
+
+      iobuf_close (in);
+
+      /* NUL terminate it.  */
+      data[prefix + data_len] = 0;
+
+      if (p_free)
+        xfree (p);
+      p = data;
+      p_free = 1;
+      data = &p[prefix];
+
+      if (is_blob)
+        p[prefix - 1] = 0;
+    }
+  else if (is_blob)
+    {
+      data = strchr (p, '=');
+      if (! data)
+        {
+          data = p;
+          data_len = 0;
+        }
+      else
+        {
+          p = xstrdup (p);
+          p_free = 1;
+
+          data = strchr (p, '=');
+          log_assert (data);
+
+          /* NUL terminate the name.  */
+          *data = 0;
+          data ++;
+          data_len = strlen (data);
+        }
+    }
+
+  if (is_blob)
+    notation = blob_to_notation (p, data, data_len);
+  else
+    notation = string_to_notation (p, 1);
+  if (! notation)
+    log_fatal ("creating notation: an unknown error occured.\n");
+  notation->next = si->notations;
+  si->notations = notation;
+
+  if (p_free)
+    xfree (p);
+
+  return 1;
+}
+
+static int
+sig_big_endian_arg (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  char *p = argv[0];
+  int i;
+  int l;
+  char *bytes;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s HEXDIGITS\n", option);
+
+  /* Skip a leading "0x".  */
+  if (p[0] == '0' && p[1] == 'x')
+    p += 2;
+
+  for (i = 0; i < strlen (p); i ++)
+    if (!hexdigitp (&p[i]))
+      log_fatal ("%s: argument ('%s') must consist of hex digits.\n",
+                 option, p);
+  if (strlen (p) % 2 != 0)
+      log_fatal ("%s: argument ('%s') must contain an even number of hex digits.\n",
+                 option, p);
+
+  l = strlen (p) / 2;
+  bytes = xmalloc (l);
+  hex2bin (p, bytes, l);
+
+  if (strcmp (option, "--key-server-preferences") == 0)
+    {
+      if (si->key_server_preferences)
+        log_fatal ("%s given multiple times.\n", option);
+      si->key_server_preferences = bytes;
+      si->key_server_preferences_len = l;
+    }
+  else if (strcmp (option, "--key-flags") == 0)
+    {
+      if (si->key_flags)
+        log_fatal ("%s given multiple times.\n", option);
+      si->key_flags = bytes;
+      si->key_flags_len = l;
+    }
+  else if (strcmp (option, "--features") == 0)
+    {
+      if (si->features)
+        log_fatal ("%s given multiple times.\n", option);
+      si->features = bytes;
+      si->features_len = l;
+    }
+  else
+    log_fatal ("Cannot handle %s\n", option);
+
+  return 1;
+}
+
+static int
+sig_reason_for_revocation (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+  int v;
+  char *tail;
+
+  if (argc < 2)
+    log_fatal ("Usage: %s REASON_CODE REASON_STRING\n", option);
+
+  errno = 0;
+  v = strtol (argv[0], &tail, 16);
+  if (errno || (tail && *tail) || !(0 <= v && v <= 255))
+    log_fatal ("%s: Invalid reason code (%s).  Expected 0-255\n",
+               option, argv[0]);
+
+  if (si->reason_for_revocation)
+    log_fatal ("%s given multiple times.\n", option);
+
+  si->reason_for_revocation_code = v;
+  si->reason_for_revocation = xstrdup (argv[1]);
+
+  return 2;
+}
+
+static int
+sig_corrupt (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct siginfo *si = cookie;
+
+  (void) option;
+  (void) argc;
+  (void) argv;
+  (void) cookie;
+
+  si->corrupt = 1;
+
+  return 0;
+}
+
+static struct option sig_options[] = {
+  { "--issuer", sig_issuer,
+    "The key to use to generate the signature."},
+  { "--issuer-keyid", sig_issuer_keyid,
+    "Set the issuer's key id.  This is useful for creating a "
+    "self-signature.  As a special case, the value \"self\" refers "
+    "to the primary key's key id.  "
+    "(RFC 4880, Section 5.2.3.5)" },
+  { "--pk", sig_pk,
+    "The primary keyas an index into the components (keys and uids) "
+    "created so far where the first component has the index 0." },
+  { "--sk", sig_pk,
+    "The subkey as an index into the components (keys and uids) created "
+    "so far where the first component has the index 0.  Only needed for "
+    "0x18, 0x19, and 0x28 signatures." },
+  { "--user-id", sig_user_id,
+    "The user id as an index into the components (keys and uids) created "
+    "so far where the first component has the index 0.  Only needed for "
+    "0x10-0x13 and 0x30 signatures." },
+  { "--class", sig_class,
+    "The signature's class.  Valid values are "
+    "0x10-0x13 (user id and primary-key certification), "
+    "0x18 (subkey binding), "
+    "0x19 (primary key binding), "
+    "0x1f (direct primary key signature), "
+    "0x20 (key revocation), "
+    "0x28 (subkey revocation), and "
+    "0x30 (certification revocation)."
+  },
+  { "--digest", sig_digest, "The digest algorithm" },
+  { "--timestamp", sig_timestamp,
+    "The signature's creation time.  " TIMESTAMP_HELP "  0 means now.  "
+    "(RFC 4880, Section 5.2.3.4)" },
+  { "--key-expiration", sig_expiration,
+    "The number of days until the associated key expires.  To specify "
+    "seconds, prefix the value with \"seconds=\".  It is also possible "
+    "to use 'y', 'm' and 'w' as simple multipliers.  For instance, 2y "
+    "means 2 years, etc.  "
+    "(RFC 4880, Section 5.2.3.6)" },
+  { "--cipher-algos", sig_int_list,
+    "A comma separated list of the preferred cipher algorithms (identified by "
+    "their number, see RFC 4880, Section 9).  "
+    "(RFC 4880, Section 5.2.3.7)" },
+  { "--digest-algos", sig_int_list,
+    "A comma separated list of the preferred algorithms (identified by "
+    "their number, see RFC 4880, Section 9).  "
+    "(RFC 4880, Section 5.2.3.8)" },
+  { "--compress-algos", sig_int_list,
+    "A comma separated list of the preferred algorithms (identified by "
+    "their number, see RFC 4880, Section 9)."
+    "(RFC 4880, Section 5.2.3.9)" },
+  { "--expiration", sig_expiration,
+    "The number of days until the signature expires.  To specify seconds, "
+    "prefix the value with \"seconds=\".  It is also possible to use 'y', "
+    "'m' and 'w' as simple multipliers.  For instance, 2y means 2 years, "
+    "etc.  "
+    "(RFC 4880, Section 5.2.3.10)" },
+  { "--exportable", sig_flag,
+    "Mark this signature as exportable (1) or local (0).  "
+    "(RFC 4880, Section 5.2.3.11)" },
+  { "--revocable", sig_flag,
+    "Mark this signature as revocable (1, revocations are ignored) "
+    "or non-revocable (0).  "
+    "(RFC 4880, Section 5.2.3.12)" },
+  { "--trust-level", sig_trust_level,
+    "Set the trust level.  This takes two integer arguments (0-255): "
+    "the trusted-introducer level and the degree of trust.  "
+    "(RFC 4880, Section 5.2.3.13.)" },
+  { "--trust-scope", sig_string_arg,
+    "A regular expression that limits the scope of --trust-level.  "
+    "(RFC 4880, Section 5.2.3.14.)" },
+  { "--revocation-key", sig_revocation_key,
+    "Specify a designated revoker.  Takes two arguments: the class "
+    "(normally 0x80 or 0xC0 (sensitive)) and the key id of the "
+    "designatured revoker.  May be given multiple times.  "
+    "(RFC 4880, Section 5.2.3.15)" },
+  { "--notation", sig_notation,
+    "Add a human-readable notation of the form \"[!<]name=value\" where "
+    "\"!\" means that the critical flag should be set and \"<\" means "
+    "that VALUE is a file to read the data from.  "
+    "(RFC 4880, Section 5.2.3.16)" },
+  { "--notation-binary", sig_notation,
+    "Add a binary notation of the form \"[!<]name=value\" where "
+    "\"!\" means that the critical flag should be set and \"<\" means "
+    "that VALUE is a file to read the data from.  "
+    "(RFC 4880, Section 5.2.3.16)" },
+  { "--key-server-preferences", sig_big_endian_arg,
+    "Big-endian number encoding the key server preferences. "
+    "(RFC 4880, Section 5.2.3.17)" },
+  { "--key-server", sig_string_arg,
+    "The preferred key server.  (RFC 4880, Section 5.2.3.18)" },
+  { "--primary-user-id", sig_flag,
+    "Sets the primary user id flag.  (RFC 4880, Section 5.2.3.19)" },
+  { "--policy-uri", sig_string_arg,
+    "URI of a document that describes the issuer's signing policy.  "
+    "(RFC 4880, Section 5.2.3.20)" },
+  { "--key-flags", sig_big_endian_arg,
+    "Big-endian number encoding the key flags. "
+    "(RFC 4880, Section 5.2.3.21)" },
+  { "--signers-user-id", sig_string_arg,
+    "The user id (as a string) responsible for the signing.  "
+    "(RFC 4880, Section 5.2.3.22)" },
+  { "--reason-for-revocation", sig_reason_for_revocation,
+    "Takes two arguments: a reason for revocation code and a "
+    "user-provided string.  "
+    "(RFC 4880, Section 5.2.3.23)" },
+  { "--features", sig_big_endian_arg,
+    "Big-endian number encoding the feature flags. "
+    "(RFC 4880, Section 5.2.3.24)" },
+  { "--signature-target", NULL,
+    "Takes three arguments: the target signature's public key algorithm "
+    " (as an integer), the hash algorithm (as an integer) and the hash "
+    " (as a hexadecimal string).  "
+    "(RFC 4880, Section 5.2.3.25)" },
+  { "--embedded-signature", NULL,
+    "An embedded signature.  This must be immediately followed by a "
+    "signature packet (created using --signature ...) or a filename "
+    "containing the packet."
+    "(RFC 4880, Section 5.2.3.26)" },
+  { "--hashed", NULL,
+    "The following attributes will be placed in the hashed area of "
+    "the signature.  (This is the default and it reset at the end of"
+    "each signature.)" },
+  { "--unhashed", NULL,
+    "The following attributes will be placed in the unhashed area of "
+    "the signature (and thus not integrity protected)." },
+  { "--corrupt", sig_corrupt,
+    "Corrupt the signature." },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --public-key $KEYID --user-id USERID \\\n"
+    "  --signature --class 0x10 --issuer $KEYID --issuer-keyid self \\\n"
+    "  | " GPG_NAME " --list-packets"}
+};
+
+static int
+mksubpkt_callback (PKT_signature *sig, void *cookie)
+{
+  struct siginfo *si = cookie;
+  int i;
+
+  if (si->key_expiration)
+    {
+      char buf[4];
+      buf[0] = (si->key_expiration >> 24) & 0xff;
+      buf[1] = (si->key_expiration >> 16) & 0xff;
+      buf[2] = (si->key_expiration >>  8) & 0xff;
+      buf[3] = si->key_expiration & 0xff;
+      build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4);
+    }
+
+  if (si->cipher_algorithms)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM,
+                      si->cipher_algorithms,
+                      si->cipher_algorithms_len);
+
+  if (si->digest_algorithms)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH,
+                      si->digest_algorithms,
+                      si->digest_algorithms_len);
+
+  if (si->compress_algorithms)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR,
+                      si->compress_algorithms,
+                      si->compress_algorithms_len);
+
+  if (si->exportable_set)
+    {
+      char buf = si->exportable;
+      build_sig_subpkt (sig, SIGSUBPKT_EXPORTABLE, &buf, 1);
+    }
+
+  if (si->trust_level_set)
+    build_sig_subpkt (sig, SIGSUBPKT_TRUST,
+                      si->trust_args, sizeof (si->trust_args));
+
+  if (si->trust_scope)
+    build_sig_subpkt (sig, SIGSUBPKT_REGEXP,
+                      si->trust_scope, strlen (si->trust_scope));
+
+  for (i = 0; i < si->nrevocation_keys; i ++)
+    {
+      struct revocation_key *revkey = &si->revocation_key[i];
+      gpg_error_t err = keygen_add_revkey (sig, revkey);
+      if (err)
+        {
+          u32 keyid[2];
+          keyid_from_fingerprint (revkey->fpr, 20, keyid);
+          log_fatal ("adding revocation key %s: %s\n",
+                     keystr (keyid), gpg_strerror (err));
+        }
+    }
+
+  /* keygen_add_revkey sets revocable=0 so be sure to do this after
+     adding the rev keys.  */
+  if (si->revocable_set)
+    {
+      char buf = si->revocable;
+      build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, &buf, 1);
+    }
+
+  keygen_add_notations (sig, si->notations);
+
+  if (si->key_server_preferences)
+    build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS,
+                      si->key_server_preferences,
+                      si->key_server_preferences_len);
+
+  if (si->key_server)
+    build_sig_subpkt (sig, SIGSUBPKT_PREF_KS,
+                      si->key_server, strlen (si->key_server));
+
+  if (si->primary_user_id_set)
+    {
+      char buf = si->primary_user_id;
+      build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, &buf, 1);
+    }
+
+  if (si->policy_uri)
+    build_sig_subpkt (sig, SIGSUBPKT_POLICY,
+                      si->policy_uri, strlen (si->policy_uri));
+
+  if (si->key_flags)
+    build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS,
+                      si->key_flags, si->key_flags_len);
+
+  if (si->signers_user_id)
+    build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID,
+                      si->signers_user_id, strlen (si->signers_user_id));
+
+  if (si->reason_for_revocation)
+    {
+      int l = 1 + strlen (si->reason_for_revocation);
+      char buf[l];
+
+      buf[0] = si->reason_for_revocation_code;
+      memcpy (&buf[1], si->reason_for_revocation, l - 1);
+
+      build_sig_subpkt (sig, SIGSUBPKT_REVOC_REASON, buf, l);
+    }
+
+  if (si->features)
+    build_sig_subpkt (sig, SIGSUBPKT_FEATURES,
+                      si->features, si->features_len);
+
+  return 0;
+}
+
+static int
+signature (const char *option, int argc, char *argv[], void *cookie)
+{
+  gpg_error_t err;
+  iobuf_t out = cookie;
+  struct siginfo si;
+  int processed;
+  PKT_public_key *pk;
+  PKT_signature *sig;
+  PACKET pkt;
+  u32 keyid_orig[2], keyid[2];
+
+  (void) option;
+
+  memset (&si, 0, sizeof (si));
+  memset (&pkt, 0, sizeof (pkt));
+
+  processed = process_options (option,
+                               major_options,
+                               sig_options, &si,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (ncomponents)
+    {
+      int pkttype = components[ncomponents - 1].pkttype;
+
+      if (pkttype == PKT_PUBLIC_KEY)
+        {
+          if (! si.class)
+            /* Direct key sig.  */
+            si.class = 0x1F;
+        }
+      else if (pkttype == PKT_PUBLIC_SUBKEY)
+        {
+          if (! si.sk)
+            si.sk = components[ncomponents - 1].pkt.public_key;
+          if (! si.class)
+            /* Subkey binding sig.  */
+            si.class = 0x18;
+        }
+      else if (pkttype == PKT_USER_ID)
+        {
+          if (! si.uid)
+            si.uid = components[ncomponents - 1].pkt.user_id;
+          if (! si.class)
+            /* Certification of a user id and public key packet.  */
+            si.class = 0x10;
+        }
+    }
+
+  pk = NULL;
+  if (! si.pk || ! si.issuer_pk)
+    /* No primary key specified.  Default to the first one that we
+       find.  */
+    {
+      int i;
+      for (i = 0; i < ncomponents; i ++)
+        if (components[i].pkttype == PKT_PUBLIC_KEY)
+          {
+            pk = components[i].pkt.public_key;
+            break;
+          }
+    }
+
+  if (! si.pk)
+    {
+      if (! pk)
+        log_fatal ("%s: no primary key given and no primary key available",
+                   "--pk");
+      si.pk = pk;
+    }
+  if (! si.issuer_pk)
+    {
+      if (! pk)
+        log_fatal ("%s: no issuer key given and no primary key available",
+                   "--issuer");
+      si.issuer_pk = pk;
+    }
+
+  if (si.class == 0x18 || si.class == 0x19 || si.class == 0x28)
+    /* Requires the primary key and a subkey.  */
+    {
+      if (! si.sk)
+        log_fatal ("sig class 0x%x requires a subkey (--sk)\n", si.class);
+    }
+  else if (si.class == 0x10
+           || si.class == 0x11
+           || si.class == 0x12
+           || si.class == 0x13
+           || si.class == 0x30)
+    /* Requires the primary key and a user id.  */
+    {
+      if (! si.uid)
+        log_fatal ("sig class 0x%x requires a uid (--uid)\n", si.class);
+    }
+  else if (si.class == 0x1F || si.class == 0x20)
+    /* Just requires the primary key.  */
+    ;
+  else
+    log_fatal ("Unsupported signature class: 0x%x\n", si.class);
+
+  sig = xmalloc_clear (sizeof (*sig));
+
+  /* Save SI.ISSUER_PK->KEYID.  */
+  keyid_copy (keyid_orig, pk_keyid (si.issuer_pk));
+  if (si.issuer_keyid[0] || si.issuer_keyid[1])
+    keyid_copy (si.issuer_pk->keyid, si.issuer_keyid);
+  else if (si.issuer_keyid_self)
+    {
+      PKT_public_key *pripk = primary_key();
+      if (! pripk)
+        log_fatal ("--issuer-keyid self given, but no primary key available.\n");
+      keyid_copy (si.issuer_pk->keyid, pk_keyid (pripk));
+    }
+
+  /* Changing the issuer's key id is fragile.  Check to make sure
+     make_keysig_packet didn't recompute the keyid.  */
+  keyid_copy (keyid, si.issuer_pk->keyid);
+  err = make_keysig_packet (&sig, si.pk, si.uid, si.sk, si.issuer_pk,
+                            si.class, si.digest_algo,
+                            si.timestamp, si.expiration,
+                            mksubpkt_callback, &si, NULL);
+  log_assert (keyid_cmp (keyid, si.issuer_pk->keyid) == 0);
+  if (err)
+    log_fatal ("Generating signature: %s\n", gpg_strerror (err));
+
+  /* Restore SI.PK->KEYID.  */
+  keyid_copy (si.issuer_pk->keyid, keyid_orig);
+
+  if (si.corrupt)
+    {
+      /* Set the top 32-bits to 0xBAD0DEAD.  */
+      int bits = gcry_mpi_get_nbits (sig->data[0]);
+      gcry_mpi_t x = gcry_mpi_new (0);
+      gcry_mpi_add_ui (x, x, 0xBAD0DEAD);
+      gcry_mpi_lshift (x, x, bits > 32 ? bits - 32 : bits);
+      gcry_mpi_clear_highbit (sig->data[0], bits > 32 ? bits - 32 : 0);
+      gcry_mpi_add (sig->data[0], sig->data[0], x);
+      gcry_mpi_release (x);
+    }
+
+  pkt.pkttype = PKT_SIGNATURE;
+  pkt.pkt.signature = sig;
+
+  err = build_packet (out, &pkt);
+  if (err)
+    log_fatal ("serializing public key packet: %s\n", gpg_strerror (err));
+
+  debug ("Wrote signature packet:\n");
+  dump_component (&pkt);
+
+  xfree (sig);
+  release_kbnode (si.issuer_kb);
+  xfree (si.revocation_key);
+
+  return processed;
+}
+\f
+struct sk_esk_info
+{
+  /* The cipher used for encrypting the session key (when a session
+     key is used).  */
+  int cipher;
+  /* The cipher used for encryping the SED packet.  */
+  int sed_cipher;
+
+  /* S2K related data.  */
+  int hash;
+  int mode;
+  int mode_set;
+  byte salt[8];
+  int salt_set;
+  int iterations;
+
+  /* If applying the S2K function to the passphrase is the session key
+     or if it is the decryption key for the session key.  */
+  int s2k_is_session_key;
+  /* Generate a new, random session key.  */
+  int new_session_key;
+
+  /* The unencrypted session key.  */
+  int session_key_len;
+  char *session_key;
+
+  char *password;
+};
+
+static int
+sk_esk_cipher (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "integer|IDEA|3DES|CAST5|BLOWFISH|AES|AES192|AES256|CAMELLIA128|CAMELLIA192|CAMELLIA256";
+  int cipher;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (strcasecmp (argv[0], "IDEA") == 0)
+    cipher = CIPHER_ALGO_IDEA;
+  else if (strcasecmp (argv[0], "3DES") == 0)
+    cipher = CIPHER_ALGO_3DES;
+  else if (strcasecmp (argv[0], "CAST5") == 0)
+    cipher = CIPHER_ALGO_CAST5;
+  else if (strcasecmp (argv[0], "BLOWFISH") == 0)
+    cipher = CIPHER_ALGO_BLOWFISH;
+  else if (strcasecmp (argv[0], "AES") == 0)
+    cipher = CIPHER_ALGO_AES;
+  else if (strcasecmp (argv[0], "AES192") == 0)
+    cipher = CIPHER_ALGO_AES192;
+  else if (strcasecmp (argv[0], "TWOFISH") == 0)
+    cipher = CIPHER_ALGO_TWOFISH;
+  else if (strcasecmp (argv[0], "CAMELLIA128") == 0)
+    cipher = CIPHER_ALGO_CAMELLIA128;
+  else if (strcasecmp (argv[0], "CAMELLIA192") == 0)
+    cipher = CIPHER_ALGO_CAMELLIA192;
+  else if (strcasecmp (argv[0], "CAMELLIA256") == 0)
+    cipher = CIPHER_ALGO_CAMELLIA256;
+  else
+    {
+      char *tail;
+      int v;
+
+      errno = 0;
+      v = strtol (argv[0], &tail, 0);
+      if (errno || (tail && *tail) || ! valid_cipher (v))
+        log_fatal ("Invalid or unsupported value.  Usage: %s %s\n",
+                   option, usage);
+
+      cipher = v;
+    }
+
+  if (strcmp (option, "--cipher") == 0)
+    {
+      if (si->cipher)
+        log_fatal ("%s given multiple times.", option);
+      si->cipher = cipher;
+    }
+  else if (strcmp (option, "--sed-cipher") == 0)
+    {
+      if (si->sed_cipher)
+        log_fatal ("%s given multiple times.", option);
+      si->sed_cipher = cipher;
+    }
+
+  return 1;
+}
+
+static int
+sk_esk_mode (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "integer|simple|salted|iterated";
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (si->mode)
+    log_fatal ("%s given multiple times.", option);
+
+  if (strcasecmp (argv[0], "simple") == 0)
+    si->mode = 0;
+  else if (strcasecmp (argv[0], "salted") == 0)
+    si->mode = 1;
+  else if (strcasecmp (argv[0], "iterated") == 0)
+    si->mode = 3;
+  else
+    {
+      char *tail;
+      int v;
+
+      errno = 0;
+      v = strtol (argv[0], &tail, 0);
+      if (errno || (tail && *tail) || ! (v == 0 || v == 1 || v == 3))
+        log_fatal ("Invalid or unsupported value.  Usage: %s %s\n",
+                   option, usage);
+
+      si->mode = v;
+    }
+
+  si->mode_set = 1;
+
+  return 1;
+}
+
+static int
+sk_esk_hash_algorithm (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "integer|MD5|SHA1|RMD160|SHA256|SHA384|SHA512|SHA224";
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (si->hash)
+    log_fatal ("%s given multiple times.", option);
+
+  if (strcasecmp (argv[0], "MD5") == 0)
+    si->hash = DIGEST_ALGO_MD5;
+  else if (strcasecmp (argv[0], "SHA1") == 0)
+    si->hash = DIGEST_ALGO_SHA1;
+  else if (strcasecmp (argv[0], "RMD160") == 0)
+    si->hash = DIGEST_ALGO_RMD160;
+  else if (strcasecmp (argv[0], "SHA256") == 0)
+    si->hash = DIGEST_ALGO_SHA256;
+  else if (strcasecmp (argv[0], "SHA384") == 0)
+    si->hash = DIGEST_ALGO_SHA384;
+  else if (strcasecmp (argv[0], "SHA512") == 0)
+    si->hash = DIGEST_ALGO_SHA512;
+  else if (strcasecmp (argv[0], "SHA224") == 0)
+    si->hash = DIGEST_ALGO_SHA224;
+  else
+    {
+      char *tail;
+      int v;
+
+      errno = 0;
+      v = strtol (argv[0], &tail, 0);
+      if (errno || (tail && *tail)
+          || ! (v == DIGEST_ALGO_MD5
+                || v == DIGEST_ALGO_SHA1
+                || v == DIGEST_ALGO_RMD160
+                || v == DIGEST_ALGO_SHA256
+                || v == DIGEST_ALGO_SHA384
+                || v == DIGEST_ALGO_SHA512
+                || v == DIGEST_ALGO_SHA224))
+        log_fatal ("Invalid or unsupported value.  Usage: %s %s\n",
+                   option, usage);
+
+      si->hash = v;
+    }
+
+  return 1;
+}
+
+static int
+sk_esk_salt (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "16-HEX-CHARACTERS";
+  char *p = argv[0];
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (si->salt_set)
+    log_fatal ("%s given multiple times.", option);
+
+  if (p[0] == '0' && p[1] == 'x')
+    p += 2;
+
+  if (strlen (p) != 16)
+    log_fatal ("%s: Salt must be exactly 16 hexadecimal characters (have: %zd)\n",
+               option, strlen (p));
+
+  if (hex2bin (p, si->salt, sizeof (si->salt)) == -1)
+    log_fatal ("%s: Salt must only contain hexadecimal characters\n",
+               option);
+
+  si->salt_set = 1;
+
+  return 1;
+}
+
+static int
+sk_esk_iterations (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "ITERATION-COUNT";
+  char *tail;
+  int v;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  errno = 0;
+  v = strtol (argv[0], &tail, 0);
+  if (errno || (tail && *tail) || v < 0)
+    log_fatal ("%s: Non-negative integer expected.\n", option);
+
+  si->iterations = v;
+
+  return 1;
+}
+
+static int
+sk_esk_session_key (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "HEX-CHARACTERS|auto|none";
+  char *p = argv[0];
+  struct session_key sk;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (si->session_key || si->s2k_is_session_key
+      || si->new_session_key)
+    log_fatal ("%s given multiple times.", option);
+
+  if (strcasecmp (p, "none") == 0)
+    {
+      si->s2k_is_session_key = 1;
+      return 1;
+    }
+  if (strcasecmp (p, "new") == 0)
+    {
+      si->new_session_key = 1;
+      return 1;
+    }
+  if (strcasecmp (p, "auto") == 0)
+    return 1;
+
+  sk = parse_session_key (option, p, 0);
+
+  if (si->session_key)
+    log_fatal ("%s given multiple times.", option);
+
+  if (sk.algo)
+    si->sed_cipher = sk.algo;
+
+  si->session_key_len = sk.keylen;
+  si->session_key = sk.key;
+
+  return 1;
+}
+
+static int
+sk_esk_password (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct sk_esk_info *si = cookie;
+  char *usage = "PASSWORD";
+
+  if (argc == 0)
+    log_fatal ("Usage: --sk-esk %s\n", usage);
+
+  if (si->password)
+    log_fatal ("%s given multiple times.", option);
+
+  si->password = xstrdup (argv[0]);
+
+  return 1;
+}
+
+static struct option sk_esk_options[] = {
+  { "--cipher", sk_esk_cipher,
+    "The encryption algorithm for encrypting the session key.  "
+    "One of IDEA, 3DES, CAST5, BLOWFISH, AES (default), AES192, "
+    "AES256, TWOFISH, CAMELLIA128, CAMELLIA192, or CAMELLIA256." },
+  { "--sed-cipher", sk_esk_cipher,
+    "The encryption algorithm for encrypting the SED packet.  "
+    "One of IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, "
+    "AES256 (default), TWOFISH, CAMELLIA128, CAMELLIA192, or CAMELLIA256." },
+  { "--mode", sk_esk_mode,
+    "The S2K mode.  Either one of the strings \"simple\", \"salted\" "
+    "or \"iterated\" or an integer." },
+  { "--hash", sk_esk_hash_algorithm,
+    "The hash algorithm to used to derive the key.  One of "
+    "MD5, SHA1 (default), RMD160, SHA256, SHA384, SHA512, or SHA224." },
+  { "--salt", sk_esk_salt,
+    "The S2K salt encoded as 16 hexadecimal characters.  One needed "
+    "if the S2K function is in salted or iterated mode." },
+  { "--iterations", sk_esk_iterations,
+    "The iteration count.  If not provided, a reasonable value is chosen.  "
+    "Note: due to the encoding scheme, not every value is valid.  For "
+    "convenience, the provided value will be rounded appropriately.  "
+    "Only needed if the S2K function is in iterated mode." },
+  { "--session-key", sk_esk_session_key,
+    "The session key to be encrypted by the S2K function as a hexadecimal "
+    "string.  If this is \"new\", then a new session key is generated."
+    "If this is \"auto\", then either the last session key is "
+    "used, if the was none, one is generated.  If this is \"none\", then "
+    "the session key is the result of applying the S2K algorithms to the "
+    "password.  The session key may be prefaced with an integer and a colon "
+    "to indicate the cipher to use for the SED packet (making --sed-cipher "
+    "unnecessary and allowing the direct use of the result of "
+    "\"" GPG_NAME " --show-session-key\")." },
+  { "", sk_esk_password, "The password." },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --sk-esk foobar --encrypted \\\n"
+    "  --literal --value foo | " GPG_NAME " --list-packets" }
+};
+
+static int
+sk_esk (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+  gpg_error_t err;
+  int processed;
+  struct sk_esk_info si;
+  DEK sesdek;
+  DEK s2kdek;
+  PKT_symkey_enc *ske;
+  PACKET pkt;
+
+  memset (&si, 0, sizeof (si));
+
+  processed = process_options (option,
+                               major_options,
+                               sk_esk_options, &si,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (! si.password)
+    log_fatal ("%s: missing password.  Usage: %s PASSWORD", option, option);
+
+  /* Fill in defaults, if appropriate.  */
+  if (! si.cipher)
+    si.cipher = CIPHER_ALGO_AES;
+
+  if (! si.sed_cipher)
+    si.sed_cipher = CIPHER_ALGO_AES256;
+
+  if (! si.hash)
+    si.hash = DIGEST_ALGO_SHA1;
+
+  if (! si.mode_set)
+    /* Salted and iterated.  */
+    si.mode = 3;
+
+  if (si.mode != 0 && ! si.salt_set)
+    /* Generate a salt.  */
+    gcry_randomize (si.salt, 8, GCRY_STRONG_RANDOM);
+
+  if (si.mode == 0)
+    {
+      if (si.iterations)
+        log_info ("%s: --iterations provided, but not used for mode=0\n",
+                  option);
+      si.iterations = 0;
+    }
+  else if (! si.iterations)
+    si.iterations = 10000;
+
+  memset (&sesdek, 0, sizeof (sesdek));
+  /* The session key is used to encrypt the SED packet.  */
+  sesdek.algo = si.sed_cipher;
+  if (si.session_key)
+    /* Copy the unencrypted session key into SESDEK.  */
+    {
+      sesdek.keylen = openpgp_cipher_get_algo_keylen (sesdek.algo);
+      if (sesdek.keylen != si.session_key_len)
+        log_fatal ("%s: Cipher algorithm requires a %d byte session key, but provided session key is %d bytes.",
+                   option, sesdek.keylen, si.session_key_len);
+
+      log_assert (sesdek.keylen <= sizeof (sesdek.key));
+      memcpy (sesdek.key, si.session_key, sesdek.keylen);
+    }
+  else if (! si.s2k_is_session_key || si.new_session_key)
+    /* We need a session key, but one wasn't provided.  Generate it.  */
+    make_session_key (&sesdek);
+
+  /* The encrypted session key needs 1 + SESDEK.KEYLEN bytes of
+     space.  */
+  ske = xmalloc_clear (sizeof (*ske) + sesdek.keylen);
+
+  ske->version = 4;
+  ske->cipher_algo = si.cipher;
+
+  ske->s2k.mode = si.mode;
+  ske->s2k.hash_algo = si.hash;
+  log_assert (sizeof (si.salt) == sizeof (ske->s2k.salt));
+  memcpy (ske->s2k.salt, si.salt, sizeof (ske->s2k.salt));
+  if (! si.s2k_is_session_key)
+    /* 0 means get the default.  */
+    ske->s2k.count = encode_s2k_iterations (si.iterations);
+
+
+  /* Derive the symmetric key that is either the session key or the
+     key used to encrypt the session key.  */
+  memset (&s2kdek, 0, sizeof (s2kdek));
+
+  s2kdek.algo = si.cipher;
+  s2kdek.keylen = openpgp_cipher_get_algo_keylen (s2kdek.algo);
+
+  err = gcry_kdf_derive (si.password, strlen (si.password),
+                         ske->s2k.mode == 3 ? GCRY_KDF_ITERSALTED_S2K
+                         : ske->s2k.mode == 1 ? GCRY_KDF_SALTED_S2K
+                         : GCRY_KDF_SIMPLE_S2K,
+                         ske->s2k.hash_algo, ske->s2k.salt, 8,
+                         S2K_DECODE_COUNT (ske->s2k.count),
+                         /* The size of the desired key and its
+                            buffer.  */
+                         s2kdek.keylen, s2kdek.key);
+  if (err)
+    log_fatal ("gcry_kdf_derive failed: %s", gpg_strerror (err));
+
+
+  if (si.s2k_is_session_key)
+    {
+      ske->seskeylen = 0;
+      session_key = s2kdek;
+    }
+  else
+    /* Encrypt the session key using the s2k specifier.  */
+    {
+      DEK *sesdekp = &sesdek;
+
+      /* Now encrypt the session key (or rather, the algorithm used to
+         encrypt the SED plus the session key) using ENCKEY.  */
+      ske->seskeylen = 1 + sesdek.keylen;
+      encrypt_seskey (&s2kdek, &sesdekp, ske->seskey);
+
+      /* Save the session key for later.  */
+      session_key = sesdek;
+    }
+
+  pkt.pkttype = PKT_SYMKEY_ENC;
+  pkt.pkt.symkey_enc = ske;
+
+  err = build_packet (out, &pkt);
+  if (err)
+    log_fatal ("Serializing sym-key encrypted packet: %s\n",
+               gpg_strerror (err));
+
+  debug ("Wrote sym-key encrypted packet:\n");
+  dump_component (&pkt);
+
+  xfree (si.session_key);
+  xfree (si.password);
+  xfree (ske);
+
+  return processed;
+}
+\f
+struct pk_esk_info
+{
+  int session_key_set;
+
+  int new_session_key;
+
+  int sed_cipher;
+  int session_key_len;
+  char *session_key;
+
+  int throw_keyid;
+
+  char *keyid;
+};
+
+static int
+pk_esk_session_key (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct pk_esk_info *pi = cookie;
+  char *usage = "HEX-CHARACTERS|auto|none";
+  char *p = argv[0];
+  struct session_key sk;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (pi->session_key_set)
+    log_fatal ("%s given multiple times.", option);
+  pi->session_key_set = 1;
+
+  if (strcasecmp (p, "new") == 0)
+    {
+      pi->new_session_key = 1;
+      return 1;
+    }
+
+  if (strcasecmp (p, "auto") == 0)
+    return 1;
+
+  sk = parse_session_key (option, p, 0);
+
+  if (pi->session_key)
+    log_fatal ("%s given multiple times.", option);
+
+  if (sk.algo)
+    pi->sed_cipher = sk.algo;
+
+  pi->session_key_len = sk.keylen;
+  pi->session_key = sk.key;
+
+  return 1;
+}
+
+static int
+pk_esk_throw_keyid (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct pk_esk_info *pi = cookie;
+
+  (void) option;
+  (void) argc;
+  (void) argv;
+
+  pi->throw_keyid = 1;
+
+  return 0;
+}
+
+static int
+pk_esk_keyid (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct pk_esk_info *pi = cookie;
+  char *usage = "KEYID";
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (pi->keyid)
+    log_fatal ("Multiple key ids given, but only one is allowed.");
+
+  pi->keyid = xstrdup (argv[0]);
+
+  return 1;
+}
+
+static struct option pk_esk_options[] = {
+  { "--session-key", pk_esk_session_key,
+    "The session key to be encrypted by the S2K function as a hexadecimal "
+    "string.  If this is not given or is \"auto\", then the current "
+    "session key is used.  If there is no session key or this is \"new\", "
+    "then a new session key is generated.  The session key may be "
+    "prefaced with an integer and a colon to indicate the cipher to use "
+    "for the SED packet (making --sed-cipher unnecessary and allowing the "
+    "direct use of the result of \"" GPG_NAME " --show-session-key\")." },
+  { "--throw-keyid", pk_esk_throw_keyid,
+    "Throw the keyid." },
+  { "", pk_esk_keyid, "The key id." },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --pk-esk $KEYID --encrypted --literal --value foo \\\n"
+    "  | " GPG_NAME " --list-packets"}
+};
+
+static int
+pk_esk (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+  gpg_error_t err;
+  int processed;
+  struct pk_esk_info pi;
+  PKT_public_key pk;
+
+  memset (&pi, 0, sizeof (pi));
+
+  processed = process_options (option,
+                               major_options,
+                               pk_esk_options, &pi,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (! pi.keyid)
+    log_fatal ("%s: missing keyid.  Usage: %s KEYID", option, option);
+
+  memset (&pk, 0, sizeof (pk));
+  pk.req_usage = PUBKEY_USAGE_ENC;
+  err = get_pubkey_byname (NULL, NULL, &pk, pi.keyid, NULL, NULL, 1, 1);
+  if (err)
+    log_fatal ("%s: looking up key %s: %s\n",
+               option, pi.keyid, gpg_strerror (err));
+
+  if (pi.sed_cipher)
+    /* Have a session key.  */
+    {
+      session_key.algo = pi.sed_cipher;
+      session_key.keylen = pi.session_key_len;
+      log_assert (session_key.keylen <= sizeof (session_key.key));
+      memcpy (session_key.key, pi.session_key, session_key.keylen);
+    }
+
+  if (pi.new_session_key || ! session_key.algo)
+    {
+      if (! pi.new_session_key)
+        /* Default to AES256.  */
+        session_key.algo = CIPHER_ALGO_AES256;
+      make_session_key (&session_key);
+    }
+
+  err = write_pubkey_enc (&pk, pi.throw_keyid, &session_key, out);
+  if (err)
+    log_fatal ("%s: writing pk_esk packet for %s: %s\n",
+               option, pi.keyid, gpg_strerror (err));
+
+  debug ("Wrote pk_esk packet for %s\n", pi.keyid);
+
+  xfree (pi.keyid);
+  xfree (pi.session_key);
+
+  return processed;
+}
+\f
+struct encinfo
+{
+  int saw_session_key;
+};
+
+static int
+encrypted_session_key (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct encinfo *ei = cookie;
+  char *usage = "HEX-CHARACTERS|auto";
+  char *p = argv[0];
+  struct session_key sk;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s %s\n", option, usage);
+
+  if (ei->saw_session_key)
+    log_fatal ("%s given multiple times.", option);
+  ei->saw_session_key = 1;
+
+  if (strcasecmp (p, "auto") == 0)
+    return 1;
+
+  sk = parse_session_key (option, p, 1);
+
+  session_key.algo = sk.algo;
+  log_assert (sk.keylen <= sizeof (session_key.key));
+  memcpy (session_key.key, sk.key, sk.keylen);
+  xfree (sk.key);
+
+  return 1;
+}
+
+static struct option encrypted_options[] = {
+  { "--session-key", encrypted_session_key,
+    "The session key to be encrypted by the S2K function as a hexadecimal "
+    "string.  If this is not given or is \"auto\", then the last session key "
+    "is used.  If there was none, then an error is raised.  The session key "
+    "must be prefaced with an integer and a colon to indicate the cipher "
+    "to use (this is format used by \"" GPG_NAME " --show-session-key\")." },
+  { NULL, NULL,
+    "After creating the packet, this command clears the current "
+    "session key.\n\n"
+    "Example: nested encryption packets:\n\n"
+    "  $ gpgcompose --sk-esk foo --encrypted-mdc \\\n"
+    "  --sk-esk bar --encrypted-mdc \\\n"
+    "  --literal --value 123 --encrypted-pop --encrypted-pop | " GPG_NAME" -d" }
+};
+
+static int
+encrypted (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+  int processed;
+  struct encinfo ei;
+  PKT_encrypted e;
+  cipher_filter_context_t *cfx;
+
+  memset (&ei, 0, sizeof (ei));
+
+  processed = process_options (option,
+                               major_options,
+                               encrypted_options, &ei,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (! session_key.algo)
+    log_fatal ("%s: no session key configured.\n", option);
+
+  memset (&e, 0, sizeof (e));
+  /* We only need to set E->LEN, E->EXTRALEN (if E->LEN is not
+     0), and E->NEW_CTB.  */
+  e.len = 0;
+  e.new_ctb = 1;
+
+  /* Register the cipher filter. */
+
+  cfx = xmalloc_clear (sizeof (*cfx));
+
+  /* Copy the session key.  */
+  cfx->dek = xmalloc (sizeof (*cfx->dek));
+  *cfx->dek = session_key;
+
+  if (do_debug)
+    {
+      char buf[2 * session_key.keylen + 1];
+      debug ("session key: algo: %d; keylen: %d; key: %s\n",
+             session_key.algo, session_key.keylen,
+             bin2hex (session_key.key, session_key.keylen, buf));
+    }
+
+  if (strcmp (option, "--encrypted-mdc") == 0)
+    cfx->dek->use_mdc = 1;
+  else if (strcmp (option, "--encrypted") == 0)
+    cfx->dek->use_mdc = 0;
+  else
+    log_fatal ("%s: option not handled by this function!\n", option);
+
+  cfx->datalen = 0;
+
+  filter_push (out, cipher_filter, cfx, PKT_ENCRYPTED, cfx->datalen == 0);
+
+  debug ("Wrote encrypted packet:\n");
+
+  /* Clear the current session key.  */
+  memset (&session_key, 0, sizeof (session_key));
+
+  return processed;
+}
+\f
+static int
+encrypted_pop (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+
+  (void) argc;
+  (void) argv;
+
+  if (strcmp (option, "--encrypted-pop") == 0)
+    filter_pop (out, PKT_ENCRYPTED);
+  else if (strcmp (option, "--encrypted-mdc-pop") == 0)
+    filter_pop (out, PKT_ENCRYPTED_MDC);
+  else
+    log_fatal ("%s: option not handled by this function!\n", option);
+
+  debug ("Popped encryption container.\n");
+
+  return 0;
+}
+\f
+struct data
+{
+  int file;
+  union
+  {
+    char *data;
+    char *filename;
+  };
+  struct data *next;
+};
+
+/* This must be the first member of the struct to be able to use
+   add_value!  */
+struct datahead
+{
+  struct data *head;
+  struct data **last_next;
+};
+
+static int
+add_value (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct datahead *dh = cookie;
+  struct data *d = xmalloc_clear (sizeof (struct data));
+
+  d->file = strcmp ("--file", option) == 0;
+  if (! d->file)
+    log_assert (strcmp ("--value", option) == 0);
+
+  if (argc == 0)
+    {
+      if (d->file)
+        log_fatal ("Usage: %s FILENAME\n", option);
+      else
+        log_fatal ("Usage: %s STRING\n", option);
+    }
+
+  if (! dh->last_next)
+    /* First time through.  Initialize DH->LAST_NEXT.  */
+    {
+      log_assert (! dh->head);
+      dh->last_next = &dh->head;
+    }
+
+  if (d->file)
+    d->filename = argv[0];
+  else
+    d->data = argv[0];
+
+  /* Append it.  */
+  *dh->last_next = d;
+  dh->last_next = &d->next;
+
+  return 1;
+}
+\f
+struct litinfo
+{
+  /* This must be the first element for add_value to work!  */
+  struct datahead data;
+
+  int timestamp_set;
+  u32 timestamp;
+  char mode;
+  int partial_body_length_encoding;
+  char *name;
+};
+
+static int
+literal_timestamp (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct litinfo *li = cookie;
+
+  char *tail = NULL;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s TIMESTAMP\n", option);
+
+  errno = 0;
+  li->timestamp = parse_timestamp (argv[0], &tail);
+  if (errno || (tail && *tail))
+    log_fatal ("Invalid value passed to %s (%s)\n", option, argv[0]);
+  li->timestamp_set = 1;
+
+  return 1;
+}
+
+static int
+literal_mode (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct litinfo *li = cookie;
+
+  if (argc == 0
+      || ! (strcmp (argv[0], "b") == 0
+            || strcmp (argv[0], "t") == 0
+            || strcmp (argv[0], "u") == 0))
+    log_fatal ("Usage: %s [btu]\n", option);
+
+  li->mode = argv[0][0];
+
+  return 1;
+}
+
+static int
+literal_partial_body_length (const char *option, int argc, char *argv[],
+                             void *cookie)
+{
+  struct litinfo *li = cookie;
+  char *tail;
+  int v;
+  int range[2] = {0, 1};
+
+  if (argc <= 1)
+    log_fatal ("Usage: %s [0|1]\n", option);
+
+  errno = 0;
+  v = strtol (argv[0], &tail, 0);
+  if (errno || (tail && *tail) || !(range[0] <= v && v <= range[1]))
+    log_fatal ("Invalid value passed to %s (%s).  Expected %d-%d\n",
+               option, argv[0], range[0], range[1]);
+
+  li->partial_body_length_encoding = v;
+
+  return 1;
+}
+
+static int
+literal_name (const char *option, int argc, char *argv[], void *cookie)
+{
+  struct litinfo *li = cookie;
+
+  if (argc <= 1)
+    log_fatal ("Usage: %s NAME\n", option);
+
+  if (strlen (argv[0]) > 255)
+    log_fatal ("%s: name is too long (%zd > 255 characters).\n",
+               option, strlen (argv[0]));
+
+  li->name = argv[0];
+
+  return 1;
+}
+
+static struct option literal_options[] = {
+  { "--value", add_value,
+    "A string to store in the literal packet." },
+  { "--file", add_value,
+    "A file to copy into the literal packet." },
+  { "--timestamp", literal_timestamp,
+    "The literal packet's time stamp.  This defaults to the current time." },
+  { "--mode", literal_mode,
+    "The content's mode (normally 'b' (default), 't' or 'u')." },
+  { "--partial-body-length", literal_partial_body_length,
+    "Force partial body length encoding." },
+  { "--name", literal_name,
+    "The literal's name." },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --literal --value foobar | " GPG_NAME " -d"}
+};
+
+static int
+literal (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+  gpg_error_t err;
+  int processed;
+  struct litinfo li;
+  PKT_plaintext *pt;
+  PACKET pkt;
+  struct data *data;
+
+  memset (&li, 0, sizeof (li));
+
+  processed = process_options (option,
+                               major_options,
+                               literal_options, &li,
+                               global_options, NULL,
+                               argc, argv);
+
+  if (! li.data.head)
+    log_fatal ("%s: no data provided (use --value or --file)", option);
+
+  pt = xmalloc_clear (sizeof (*pt) + (li.name ? strlen (li.name) : 0));
+  pt->new_ctb = 1;
+
+  if (li.timestamp_set)
+    pt->timestamp = li.timestamp;
+  else
+    /* Default to the current time.  */
+    pt->timestamp = make_timestamp ();
+
+  pt->mode = li.mode;
+  if (! pt->mode)
+    /* Default to binary.  */
+    pt->mode = 'b';
+
+  if (li.name)
+    {
+      strcpy (pt->name, li.name);
+      pt->namelen = strlen (pt->name);
+    }
+
+  pkt.pkttype = PKT_PLAINTEXT;
+  pkt.pkt.plaintext = pt;
+
+  if (! li.partial_body_length_encoding)
+    /* Compute the amount of data.  */
+    {
+      pt->len = 0;
+      for (data = li.data.head; data; data = data->next)
+        {
+          if (data->file)
+            {
+              iobuf_t in;
+              int overflow;
+              off_t off;
+
+              in = iobuf_open (data->filename);
+              if (! in)
+                /* An error opening the file.  We do error handling
+                   below so just break here.  */
+                {
+                  pt->len = 0;
+                  break;
+                }
+
+              off = iobuf_get_filelength (in, &overflow);
+              iobuf_close (in);
+
+              if (overflow || off == 0)
+                /* Length is unknown or there was an error
+                   (unfortunately, iobuf_get_filelength doesn't
+                   distinguish between 0 length files and an error!).
+                   Fall back to partial body mode.  */
+                {
+                  pt->len = 0;
+                  break;
+                }
+
+              pt->len += off;
+            }
+          else
+            pt->len += strlen (data->data);
+        }
+    }
+
+  err = build_packet (out, &pkt);
+  if (err)
+    log_fatal ("Serializing literal packet: %s\n", gpg_strerror (err));
+
+  /* Write out the data.  */
+  for (data = li.data.head; data; data = data->next)
+    {
+      if (data->file)
+        {
+          iobuf_t in;
+          errno = 0;
+          in = iobuf_open (data->filename);
+          if (! in)
+            log_fatal ("Opening '%s': %s\n",
+                       data->filename,
+                       errno ? strerror (errno): "unknown error");
+
+          iobuf_copy (out, in);
+          if (iobuf_error (in))
+            log_fatal ("Reading from %s: %s\n",
+                       data->filename,
+                       gpg_strerror (iobuf_error (in)));
+          if (iobuf_error (out))
+            log_fatal ("Writing literal data from %s: %s\n",
+                       data->filename,
+                       gpg_strerror (iobuf_error (out)));
+
+          iobuf_close (in);
+        }
+      else
+        {
+          err = iobuf_write (out, data->data, strlen (data->data));
+          if (err)
+            log_fatal ("Writing literal data: %s\n", gpg_strerror (err));
+        }
+    }
+
+  if (! pt->len)
+    {
+      /* Disable partial body length mode.  */
+      log_assert (pt->new_ctb == 1);
+      iobuf_set_partial_body_length_mode (out, 0);
+    }
+
+  debug ("Wrote literal packet:\n");
+  dump_component (&pkt);
+
+  while (li.data.head)
+    {
+      data = li.data.head->next;
+      xfree (li.data.head);
+      li.data.head = data;
+    }
+  xfree (pt);
+
+  return processed;
+}
+\f
+static int
+copy_file (const char *option, int argc, char *argv[], void *cookie)
+{
+  char **filep = cookie;
+
+  if (argc == 0)
+    log_fatal ("Usage: %s FILENAME\n", option);
+
+  *filep = argv[0];
+
+  return 1;
+}
+
+static struct option copy_options[] = {
+  { "", copy_file, "Copy the specified file to stdout." },
+  { NULL, NULL,
+    "Example:\n\n"
+    "  $ gpgcompose --copy /etc/hostname\n\n"
+    "This is particularly useful when combined with gpgsplit." }
+};
+
+static int
+copy (const char *option, int argc, char *argv[], void *cookie)
+{
+  iobuf_t out = cookie;
+  char *file = NULL;
+  iobuf_t in;
+
+  int processed;
+
+  processed = process_options (option,
+                               major_options,
+                               copy_options, &file,
+                               global_options, NULL,
+                               argc, argv);
+  if (! file)
+    log_fatal ("Usage: %s FILE\n", option);
+
+  errno = 0;
+  in = iobuf_open (file);
+  if (! in)
+    log_fatal ("Error opening %s: %s.\n",
+               file, errno ? strerror (errno): "unknown error");
+
+  iobuf_copy (out, in);
+  if (iobuf_error (out))
+    log_fatal ("Copying data to destination: %s\n",
+               gpg_strerror (iobuf_error (out)));
+  if (iobuf_error (in))
+    log_fatal ("Reading data from %s: %s\n",
+               argv[0], gpg_strerror (iobuf_error (in)));
+
+  iobuf_close (in);
+
+  return processed;
+}
+\f
+int
+main (int argc, char *argv[])
+{
+  const char *filename = "-";
+  iobuf_t out;
+  int preprocessed = 1;
+  int processed;
+  ctrl_t ctrl;
+
+  opt.homedir = default_homedir ();
+  if (! opt.homedir)
+    opt.homedir = "";
+
+  opt.ignore_time_conflict = 1;
+  /* Allow notations in the IETF space, for instance.  */
+  opt.expert = 1;
+
+  ctrl = xcalloc (1, sizeof *ctrl);
+
+  keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
+                      KEYDB_RESOURCE_FLAG_DEFAULT);
+
+  if (argc == 1)
+    /* Nothing to do.  */
+    return 0;
+
+  if (strcmp (argv[1], "--output") == 0
+      || strcmp (argv[1], "-o") == 0)
+    {
+      filename = argv[2];
+      log_info ("Writing to %s\n", filename);
+      preprocessed += 2;
+    }
+
+  out = iobuf_create (filename, 0);
+  if (! out)
+    log_fatal ("Failed to open stdout for writing\n");
+
+  processed = process_options (NULL, NULL,
+                               major_options, out,
+                               global_options, NULL,
+                               argc - preprocessed, &argv[preprocessed]);
+  if (processed != argc - preprocessed)
+    log_fatal ("Didn't process %d options.\n", argc - preprocessed - processed);
+
+  iobuf_close (out);
+
+  return 0;
+}
+\f
+/* Stubs duplicated from gpg.c.  */
+
+int g10_errors_seen = 0;
+
+/* Note: This function is used by signal handlers!. */
+static void
+emergency_cleanup (void)
+{
+  gcry_control (GCRYCTL_TERM_SECMEM );
+}
+
+void
+g10_exit( int rc )
+{
+  gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE);
+
+  emergency_cleanup ();
+
+  rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;
+  exit (rc);
+}
+
+void
+keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
+             strlist_t commands, int quiet, int seckey_check)
+{
+  (void) ctrl;
+  (void) username;
+  (void) locusr;
+  (void) commands;
+  (void) quiet;
+  (void) seckey_check;
+}
+
+void
+show_basic_key_info (KBNODE keyblock)
+{
+  (void) keyblock;
+}
index 19a2ff6..2a53e69 100644 (file)
@@ -374,6 +374,17 @@ keyserver_import_pka (const char *name,unsigned char *fpr)
   return -1;
 }
 
+gpg_error_t
+keyserver_import_wkd (ctrl_t ctrl, const char *name,
+                      unsigned char **fpr, size_t *fpr_len)
+{
+  (void)ctrl;
+  (void)name;
+  (void)fpr;
+  (void)fpr_len;
+  return GPG_ERR_BUG;
+}
+
 int
 keyserver_import_name (const char *name,struct keyserver_spec *spec)
 {
index 369be35..6707797 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -1279,7 +1278,7 @@ import_one (ctrl_t ctrl,
         {
           xfree (*fpr);
           /* Note that we need to compare against 0 here because
-             COUNT gets only incremented after returning form this
+             COUNT gets only incremented after returning from this
              function.  */
           if (!stats->count)
             *fpr = fingerprint_from_pk (pk, NULL, fpr_len);
@@ -1835,9 +1834,9 @@ import_revoke_cert (const char *fname, kbnode_t node,
 
   (void)fname;
 
-  assert( !node->next );
-  assert( node->pkt->pkttype == PKT_SIGNATURE );
-  assert( node->pkt->pkt.signature->sig_class == 0x20 );
+  log_assert (!node->next );
+  log_assert (node->pkt->pkttype == PKT_SIGNATURE );
+  log_assert (node->pkt->pkt.signature->sig_class == 0x20 );
 
   keyid[0] = node->pkt->pkt.signature->keyid[0];
   keyid[1] = node->pkt->pkt.signature->keyid[1];
@@ -2720,7 +2719,7 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
   (void)fname;
   (void)keyid;
 
-  assert(node->pkt->pkttype == PKT_USER_ID );
+  log_assert (node->pkt->pkttype == PKT_USER_ID );
 
   /* find the position */
   for (n = keyblock; n; n_where = n, n = n->next)
@@ -2773,8 +2772,8 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
   (void)fname;
   (void)keyid;
 
-  assert(dst->pkt->pkttype == PKT_USER_ID );
-  assert(src->pkt->pkttype == PKT_USER_ID );
+  log_assert (dst->pkt->pkttype == PKT_USER_ID);
+  log_assert (src->pkt->pkttype == PKT_USER_ID);
 
   for (n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next)
     {
@@ -2821,8 +2820,8 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
   (void)fname;
   (void)keyid;
 
-  assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
-          || dst->pkt->pkttype == PKT_SECRET_SUBKEY);
+  log_assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || dst->pkt->pkttype == PKT_SECRET_SUBKEY);
 
   for (n=src->next; n ; n = n->next)
     {
@@ -2882,8 +2881,8 @@ append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
   (void)fname;
   (void)keyid;
 
-  assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
-          || node->pkt->pkttype == PKT_SECRET_SUBKEY );
+  log_assert (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+              || node->pkt->pkttype == PKT_SECRET_SUBKEY);
 
   while (node)
     {
index 3337e01..a1d1f3d 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
index 9604807..0164348 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -861,7 +860,7 @@ keydb_new (void)
   hd->saved_found = -1;
   hd->is_reset = 1;
 
-  assert (used_resources <= MAX_KEYDB_RESOURCES);
+  log_assert (used_resources <= MAX_KEYDB_RESOURCES);
   for (i=j=0; ! die && i < used_resources; i++)
     {
       switch (all_resources[i].type)
@@ -919,7 +918,7 @@ keydb_release (KEYDB_HANDLE hd)
 
   if (!hd)
     return;
-  assert (active_handles > 0);
+  log_assert (active_handles > 0);
   active_handles--;
 
   unlock_all (hd);
@@ -1521,8 +1520,8 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   KEYDB_SEARCH_DESC desc;
   size_t len;
 
-  assert (kb);
-  assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (kb);
+  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
   pk = kb->pkt->pkt.public_key;
 
   if (!hd)
@@ -1549,7 +1548,7 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
   err = keydb_search (hd, &desc, 1, NULL);
   if (err)
     return gpg_error (GPG_ERR_VALUE_NOT_FOUND);
-  assert (hd->found >= 0 && hd->found < hd->used);
+  log_assert (hd->found >= 0 && hd->found < hd->used);
 
   switch (hd->active[hd->found].type)
     {
index e679d94..8896eea 100644 (file)
@@ -1,7 +1,7 @@
 /* keydb.h - Key database
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  *               2006, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -22,8 +22,6 @@
 #ifndef G10_KEYDB_H
 #define G10_KEYDB_H
 
-#include <assuan.h>
-
 #include "types.h"
 #include "util.h"
 #include "packet.h"
@@ -248,8 +246,6 @@ gpg_error_t build_sk_list (ctrl_t ctrl, strlist_t locusr,
 
 /*-- passphrase.h --*/
 unsigned char encode_s2k_iterations (int iterations);
-assuan_context_t agent_open (int try, const char *orig_codeset);
-void agent_close (assuan_context_t ctx);
 int  have_static_passphrase(void);
 const char *get_static_passphrase (void);
 void set_passphrase_from_string(const char *pass);
@@ -399,13 +395,45 @@ char *pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize);
 #define PUBKEY_STRING_SIZE 32
 u32 v3_keyid (gcry_mpi_t a, u32 *ki);
 void hash_public_key( gcry_md_hd_t md, PKT_public_key *pk );
-const char *format_keyid (u32 *keyid, int format, char *buffer, int len);
+char *format_keyid (u32 *keyid, int format, char *buffer, int len);
+
+/* Return PK's keyid.  The memory is owned by PK.  */
+u32 *pk_keyid (PKT_public_key *pk);
+
+/* Return the keyid of the primary key associated with PK.  The memory
+   is owned by PK.  */
+u32 *pk_main_keyid (PKT_public_key *pk);
+
+/* Order A and B.  If A < B then return -1, if A == B then return 0,
+   and if A > B then return 1.  */
+static int GPGRT_ATTR_UNUSED
+keyid_cmp (const u32 *a, const u32 *b)
+{
+  if (a[0] < b[0])
+    return -1;
+  if (a[0] > b[0])
+    return 1;
+  if (a[1] < b[1])
+    return -1;
+  if (a[1] > b[1])
+    return 1;
+  return 0;
+}
+
+/* Copy the keyid in SRC to DEST and return DEST.  */
+u32 *keyid_copy (u32 *dest, const u32 *src);
+
 size_t keystrlen(void);
 const char *keystr(u32 *keyid);
 const char *keystr_with_sub (u32 *main_kid, u32 *sub_kid);
 const char *keystr_from_pk(PKT_public_key *pk);
 const char *keystr_from_pk_with_sub (PKT_public_key *main_pk,
                                      PKT_public_key *sub_pk);
+
+/* Return PK's key id as a string using the default format.  PK owns
+   the storage.  */
+const char *pk_keyid_str (PKT_public_key *pk);
+
 const char *keystr_from_desc(KEYDB_SEARCH_DESC *desc);
 u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid );
 u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
index 30f52a4..5461864 100644 (file)
@@ -1,7 +1,7 @@
 /* keyedit.c - Edit properties of a key
  * Copyright (C) 1998-2010 Free Software Foundation, Inc.
  * Copyright (C) 1998-2015 Werner Koch
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -24,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 #ifdef HAVE_LIBREADLINE
 # define GNUPG_LIBREADLINE_H_INCLUDED
@@ -70,6 +69,7 @@ static int menu_clean (KBNODE keyblock, int self_only);
 static void menu_delkey (KBNODE pub_keyblock);
 static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
 static int menu_expire (KBNODE pub_keyblock);
+static int menu_changeusage (kbnode_t keyblock);
 static int menu_backsign (KBNODE pub_keyblock);
 static int menu_set_primary_uid (KBNODE pub_keyblock);
 static int menu_set_preferences (KBNODE pub_keyblock);
@@ -188,24 +188,23 @@ print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node,
 
 
 /*
- * Print information about a signature, check it and return true if
- * the signature is okay.  NODE must be a signature packet.  With
- * EXTENDED set all possible signature list options will always be
- * printed.
+ * Print information about a signature (rc is its status), check it
+ * and return true if the signature is okay.  NODE must be a signature
+ * packet.  With EXTENDED set all possible signature list options will
+ * always be printed.
  */
 static int
-print_and_check_one_sig (KBNODE keyblock, KBNODE node,
-                        int *inv_sigs, int *no_key, int *oth_err,
-                        int *is_selfsig, int print_without_key, int extended)
+print_one_sig (int rc, KBNODE keyblock, KBNODE node,
+               int *inv_sigs, int *no_key, int *oth_err,
+               int is_selfsig, int print_without_key, int extended)
 {
   PKT_signature *sig = node->pkt->pkt.signature;
-  int rc, sigrc;
+  int sigrc;
   int is_rev = sig->sig_class == 0x30;
 
   /* TODO: Make sure a cached sig record here still has the pk that
      issued it.  See also keylist.c:list_keyblock_print */
 
-  rc = check_key_signature (keyblock, node, is_selfsig);
   switch (gpg_err_code (rc))
     {
     case 0:
@@ -256,7 +255,7 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
        tty_printf ("[%s] ", gpg_strerror (rc));
       else if (sigrc == '?')
        ;
-      else if (*is_selfsig)
+      else if (is_selfsig)
        {
          tty_printf (is_rev ? _("[revocation]") : _("[self-signature]"));
           if (extended && sig->flags.chosen_selfsig)
@@ -311,98 +310,611 @@ print_and_check_one_sig (KBNODE keyblock, KBNODE node,
 }
 
 
+static int
+print_and_check_one_sig (KBNODE keyblock, KBNODE node,
+                        int *inv_sigs, int *no_key, int *oth_err,
+                        int *is_selfsig, int print_without_key, int extended)
+{
+  int rc;
 
-/*
- * Check the keysigs and set the flags to indicate errors.
- * Returns true if error found.
- */
+  rc = check_key_signature (keyblock, node, is_selfsig);
+  return print_one_sig (rc,
+                        keyblock, node, inv_sigs, no_key, oth_err,
+                        *is_selfsig, print_without_key, extended);
+}
+
+
+
+/* Order two signatures.  The actual ordering isn't important.  Our
+   goal is to ensure that identical signatures occur together.  */
 static int
-check_all_keysigs (KBNODE keyblock, int only_selected, int only_selfsigs)
+sig_comparison (const void *av, const void *bv)
 {
-  KBNODE kbctx;
-  KBNODE node;
-  int inv_sigs = 0;
-  int no_key = 0;
-  int oth_err = 0;
-  int has_selfsig = 0;
-  int mis_selfsig = 0;
-  int selected = !only_selected;
-  int anyuid = 0;
-  u32 keyid[2];
+  const KBNODE an = *(const KBNODE *) av;
+  const KBNODE bn = *(const KBNODE *) bv;
+  const PKT_signature *a;
+  const PKT_signature *b;
+  int ndataa;
+  int ndatab;
+  int i;
 
-  for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
+  log_assert (an->pkt->pkttype == PKT_SIGNATURE);
+  log_assert (bn->pkt->pkttype == PKT_SIGNATURE);
+
+  a = an->pkt->pkt.signature;
+  b = bn->pkt->pkt.signature;
+
+  if (a->digest_algo < b->digest_algo)
+    return -1;
+  if (a->digest_algo > b->digest_algo)
+    return 1;
+
+  ndataa = pubkey_get_nsig (a->pubkey_algo);
+  ndatab = pubkey_get_nsig (a->pubkey_algo);
+  log_assert (ndataa == ndatab);
+
+  for (i = 0; i < ndataa; i ++)
     {
-      if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+      int c = gcry_mpi_cmp (a->data[i], b->data[i]);
+      if (c != 0)
+        return c;
+    }
+
+  /* Okay, they are equal.  */
+  return 0;
+}
+
+/* Perform a few sanity checks on a keyblock is okay and possibly
+   repair some damage.  Concretely:
+
+     - Detect duplicate signatures and remove them.
+
+     - Detect out of order signatures and relocate them (e.g., a sig
+       over user id X located under subkey Y).
+
+   Note: this function does not remove signatures that don't belong or
+   components that are not signed!  (Although it would be trivial to
+   do so.)
+
+   If ONLY_SELFSIGS is true, then this function only reorders self
+   signatures (it still checks all signatures for duplicates,
+   however).
+
+   Returns 1 if the keyblock was modified, 0 otherwise.  */
+static int
+check_all_keysigs (KBNODE kb, int only_selected, int only_selfsigs)
+{
+  gpg_error_t err;
+  PKT_public_key *pk;
+  KBNODE n, n_next, *n_prevp, n2;
+  char *pending_desc = NULL;
+  PKT_public_key *issuer;
+  KBNODE last_printed_component;
+  KBNODE current_component = NULL;
+  int dups = 0;
+  int missing_issuer = 0;
+  int reordered = 0;
+  int bad_signature = 0;
+  int missing_selfsig = 0;
+  int modified = 0;
+
+  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+  pk = kb->pkt->pkt.public_key;
+
+  /* First we look for duplicates.  */
+  {
+    int nsigs = 0;
+    KBNODE *sigs;
+    int i;
+    int last_i;
+
+    /* Count the sigs.  */
+    for (n = kb; n; n = n->next)
+      if (is_deleted_kbnode (n))
+        continue;
+      else if (n->pkt->pkttype == PKT_SIGNATURE)
+        nsigs ++;
+
+    /* Add them all to the SIGS array.  */
+    sigs = xmalloc_clear (sizeof (*sigs) * nsigs);
+
+    i = 0;
+    for (n = kb; n; n = n->next)
+      {
+        if (is_deleted_kbnode (n))
+          continue;
+
+        if (n->pkt->pkttype != PKT_SIGNATURE)
+          continue;
+
+        sigs[i] = n;
+        i ++;
+      }
+    log_assert (i == nsigs);
+
+    qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
+
+    last_i = 0;
+    for (i = 1; i < nsigs; i ++)
+      {
+        log_assert (sigs[last_i]);
+        log_assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
+        log_assert (sigs[i]);
+        log_assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
+
+        if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
+          /* They are the same.  Kill the latter.  */
+          {
+            if (DBG_PACKET)
+              {
+                PKT_signature *sig = sigs[i]->pkt->pkt.signature;
+
+                log_debug ("Signature appears multiple times, "
+                           "deleting duplicate:\n");
+                log_debug ("  sig: class 0x%x, issuer: %s,"
+                           " timestamp: %s (%lld), digest: %02x %02x\n",
+                           sig->sig_class, keystr (sig->keyid),
+                           isotimestamp (sig->timestamp),
+                           (long long) sig->timestamp,
+                           sig->digest_start[0], sig->digest_start[1]);
+              }
+
+            /* Remove sigs[i] from the keyblock.  */
+            {
+              KBNODE z, *prevp;
+              int to_kill = last_i;
+              last_i = i;
+
+              for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
+                if (z == sigs[to_kill])
+                  break;
+
+              *prevp = sigs[to_kill]->next;
+
+              sigs[to_kill]->next = NULL;
+              release_kbnode (sigs[to_kill]);
+              sigs[to_kill] = NULL;
+
+              dups ++;
+              modified = 1;
+            }
+          }
+        else
+          last_i = i;
+      }
+
+    xfree (sigs);
+  }
+
+  /* Make sure the sigs occur after the component (public key, subkey,
+     user id) that they sign.  */
+  issuer = NULL;
+  last_printed_component = NULL;
+  for (n_prevp = &kb, n = kb;
+       n;
+       /* If we moved n, then n_prevp is need valid.  */
+       n_prevp = (n->next == n_next ? &n->next : n_prevp), n = n_next)
+    {
+      PACKET *p;
+      int processed_current_component;
+      PKT_signature *sig;
+      int rc;
+      int dump_sig_params = 0;
+
+      n_next = n->next;
+
+      if (is_deleted_kbnode (n))
+        continue;
+
+      p = n->pkt;
+
+      if (issuer && issuer != pk)
         {
-          if (only_selfsigs)
-            keyid_from_pk (node->pkt->pkt.public_key, keyid);
+          free_public_key (issuer);
+          issuer = NULL;
         }
-      else if (node->pkt->pkttype == PKT_USER_ID)
-       {
-         PKT_user_id *uid = node->pkt->pkt.user_id;
 
-         if (only_selected)
-           selected = (node->flag & NODFLG_SELUID);
-         if (selected)
-           {
-             tty_printf ("uid  ");
-             tty_print_utf8_string (uid->name, uid->len);
-             tty_printf ("\n");
-             if (anyuid && !has_selfsig)
-               mis_selfsig++;
-             has_selfsig = 0;
-             anyuid = 1;
-           }
-       }
-      else if (selected && node->pkt->pkttype == PKT_SIGNATURE
-              && ((node->pkt->pkt.signature->sig_class & ~3) == 0x10
-                  || node->pkt->pkt.signature->sig_class == 0x30))
-       {
-         int selfsig;
-          PKT_signature *sig = node->pkt->pkt.signature;
+      xfree (pending_desc);
+      pending_desc = NULL;
 
-          if (only_selfsigs
-              && !(keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]))
+      switch (p->pkttype)
+        {
+        case PKT_PUBLIC_KEY:
+          log_assert (p->pkt.public_key == pk);
+          if (only_selected && ! (n->flag & NODFLG_SELKEY))
             {
-              /* Not a selfsig but we want only selfsigs - skip.  */
-              /* Static analyzer note: A claim that KEYID above has
-                 garbage is not correct because KEYID is set from the
-                 public key packet which is always the first packet in
-                 a keyblock and thus parsed before this signature.  */
+              current_component = NULL;
+              break;
             }
-         else if (print_and_check_one_sig (keyblock, node, &inv_sigs,
-                                            &no_key, &oth_err, &selfsig,
-                                            0, only_selfsigs))
-           {
-             if (selfsig)
-               has_selfsig = 1;
-           }
-         /* Hmmm: should we update the trustdb here? */
-       }
+
+          if (DBG_PACKET)
+            log_debug ("public key %s: timestamp: %s (%lld)\n",
+                       pk_keyid_str (pk),
+                       isotimestamp (pk->timestamp),
+                       (long long) pk->timestamp);
+          current_component = n;
+          break;
+        case PKT_PUBLIC_SUBKEY:
+          if (only_selected && ! (n->flag & NODFLG_SELKEY))
+            {
+              current_component = NULL;
+              break;
+            }
+
+          if (DBG_PACKET)
+            log_debug ("subkey %s: timestamp: %s (%lld)\n",
+                       pk_keyid_str (p->pkt.public_key),
+                       isotimestamp (p->pkt.public_key->timestamp),
+                       (long long) p->pkt.public_key->timestamp);
+          current_component = n;
+          break;
+        case PKT_USER_ID:
+          if (only_selected && ! (n->flag & NODFLG_SELUID))
+            {
+              current_component = NULL;
+              break;
+            }
+
+          if (DBG_PACKET)
+            log_debug ("user id: %s\n",
+                       p->pkt.user_id->attrib_data
+                       ? "[ photo id ]"
+                       : p->pkt.user_id->name);
+          current_component = n;
+          break;
+        case PKT_SIGNATURE:
+          if (! current_component)
+            /* The current component is not selected, don't check the
+               sigs under it.  */
+            break;
+
+          sig = n->pkt->pkt.signature;
+
+          pending_desc = xasprintf ("  sig: class: 0x%x, issuer: %s, timestamp: %s (%lld), digest: %02x %02x",
+                                    sig->sig_class,
+                                    keystr (sig->keyid),
+                                    isotimestamp (sig->timestamp),
+                                    (long long) sig->timestamp,
+                                    sig->digest_start[0], sig->digest_start[1]);
+
+
+          if (keyid_cmp (pk_keyid (pk), sig->keyid) == 0)
+            issuer = pk;
+          else
+            /* Issuer is a different key.  */
+            {
+              if (only_selfsigs)
+                continue;
+
+              issuer = xmalloc (sizeof (*issuer));
+              err = get_pubkey (issuer, sig->keyid);
+              if (err)
+                {
+                  xfree (issuer);
+                  issuer = NULL;
+                  if (DBG_PACKET)
+                    {
+                      if (pending_desc)
+                        log_debug ("%s", pending_desc);
+                      log_debug ("    Can't check signature allegedly issued by %s: %s\n",
+                                keystr (sig->keyid), gpg_strerror (err));
+                    }
+                  missing_issuer ++;
+                  break;
+                }
+            }
+
+          if ((err = openpgp_pk_test_algo (sig->pubkey_algo)))
+            {
+              if (DBG_PACKET && pending_desc)
+                log_debug ("%s", pending_desc);
+              tty_printf (_("can't check signature with unsupported"
+                            " public-key algorithm (%d): %s.\n"),
+                          sig->pubkey_algo, gpg_strerror (err));
+              break;
+            }
+          if ((err = openpgp_md_test_algo (sig->digest_algo)))
+            {
+              if (DBG_PACKET && pending_desc)
+                log_debug ("%s", pending_desc);
+              tty_printf (_("can't check signature with unsupported"
+                            " message-digest algorithm %d: %s.\n"),
+                          sig->digest_algo, gpg_strerror (err));
+              break;
+            }
+
+          /* We iterate over the keyblock.  Most likely, the matching
+             component is the current component so always try that
+             first.  */
+          processed_current_component = 0;
+          for (n2 = current_component;
+               n2;
+               n2 = (processed_current_component ? n2->next : kb),
+                 processed_current_component = 1)
+            if (is_deleted_kbnode (n2))
+              continue;
+            else if (processed_current_component && n2 == current_component)
+              /* Don't process it twice.  */
+              continue;
+            else
+              {
+                err = check_signature_over_key_or_uid (issuer, sig, kb, n2->pkt,
+                                                       NULL, NULL);
+                if (! err)
+                  break;
+              }
+
+          /* n/sig is a signature and n2 is the component (public key,
+             subkey or user id) that it signs, if any.
+             current_component is that component that it appears to
+             apply to (according to the ordering).  */
+
+          if (current_component == n2)
+            {
+              if (DBG_PACKET)
+                {
+                  log_debug ("%s", pending_desc);
+                  log_debug ("    Good signature over last key or uid!\n");
+                }
+
+              rc = 0;
+            }
+          else if (n2)
+            {
+              log_assert (n2->pkt->pkttype == PKT_USER_ID
+                          || n2->pkt->pkttype == PKT_PUBLIC_KEY
+                          || n2->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+
+              if (DBG_PACKET)
+                {
+                  log_debug ("%s", pending_desc);
+                  log_debug ("    Good signature out of order!"
+                             "  (Over %s (%d) '%s')\n",
+                             n2->pkt->pkttype == PKT_USER_ID
+                             ? "user id"
+                             : n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                             ? "subkey"
+                             : "primary key",
+                             n2->pkt->pkttype,
+                             n2->pkt->pkttype == PKT_USER_ID
+                             ? n2->pkt->pkt.user_id->name
+                             : pk_keyid_str (n2->pkt->pkt.public_key));
+                }
+
+              /* Reorder the packets: move the signature n to be just
+                 after n2.  */
+
+              /* Unlink the signature.  */
+              log_assert (n_prevp);
+              *n_prevp = n->next;
+
+              /* Insert the sig immediately after the component.  */
+              n->next = n2->next;
+              n2->next = n;
+
+              reordered ++;
+              modified = 1;
+
+              rc = 0;
+            }
+          else
+            {
+              if (DBG_PACKET)
+                {
+                  log_debug ("%s", pending_desc);
+                  log_debug ("    Bad signature.\n");
+                }
+
+              if (DBG_PACKET)
+                dump_sig_params = 1;
+
+              bad_signature ++;
+
+              rc = GPG_ERR_BAD_SIGNATURE;
+            }
+
+          /* We don't cache the result here, because we haven't
+             completely checked that the signature is legitimate.  For
+             instance, if we have a revocation certificate on Alice's
+             key signed by Bob, the signature may be good, but we
+             haven't checked that Bob is a designated revoker.  */
+          /* cache_sig_result (sig, rc); */
+
+          {
+            int has_selfsig = 0;
+            if (! rc && issuer == pk)
+              {
+                if (n2->pkt->pkttype == PKT_PUBLIC_KEY
+                    && (/* Direct key signature.  */
+                        sig->sig_class == 0x1f
+                        /* Key revocation signature.  */
+                        || sig->sig_class == 0x20))
+                  has_selfsig = 1;
+                if (n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                    && (/* Subkey binding sig.  */
+                        sig->sig_class == 0x18
+                        /* Subkey revocation sig.  */
+                        || sig->sig_class == 0x28))
+                  has_selfsig = 1;
+                if (n2->pkt->pkttype == PKT_USER_ID
+                    && (/* Certification sigs.  */
+                        sig->sig_class == 0x10
+                        || sig->sig_class == 0x11
+                        || sig->sig_class == 0x12
+                        || sig->sig_class == 0x13
+                        /* Certification revocation sig.  */
+                        || sig->sig_class == 0x30))
+                  has_selfsig = 1;
+              }
+
+            if ((n2 && n2 != last_printed_component)
+                || (! n2 && last_printed_component != current_component))
+              {
+                int is_reordered = n2 && n2 != current_component;
+                if (n2)
+                  last_printed_component = n2;
+                else
+                  last_printed_component = current_component;
+
+                if (!modified)
+                  ;
+                else if (last_printed_component->pkt->pkttype == PKT_USER_ID)
+                  {
+                    tty_printf ("uid  ");
+                    tty_print_utf8_string (last_printed_component
+                                           ->pkt->pkt.user_id->name,
+                                           last_printed_component
+                                           ->pkt->pkt.user_id->len);
+                  }
+                else if (last_printed_component->pkt->pkttype
+                         == PKT_PUBLIC_KEY)
+                  tty_printf ("pub  %s",
+                              pk_keyid_str (last_printed_component
+                                            ->pkt->pkt.public_key));
+                else
+                  tty_printf ("sub  %s",
+                              pk_keyid_str (last_printed_component
+                                            ->pkt->pkt.public_key));
+
+                if (modified)
+                  {
+                    if (is_reordered)
+                      tty_printf (_(" (reordered signatures follow)"));
+                    tty_printf ("\n");
+                  }
+              }
+
+            if (modified)
+              print_one_sig (rc, kb, n, NULL, NULL, NULL, has_selfsig,
+                             0, only_selfsigs);
+          }
+
+          if (dump_sig_params)
+            {
+              int i;
+
+              for (i = 0; i < pubkey_get_nsig (sig->pubkey_algo); i ++)
+                {
+                  char buffer[1024];
+                  size_t len;
+                  char *printable;
+                  gcry_mpi_print (GCRYMPI_FMT_USG,
+                                  buffer, sizeof (buffer), &len,
+                                  sig->data[i]);
+                  printable = bin2hex (buffer, len, NULL);
+                  log_info ("        %d: %s\n", i, printable);
+                  xfree (printable);
+                }
+            }
+          break;
+        default:
+          if (DBG_PACKET)
+            log_debug ("unhandled packet: %d\n", p->pkttype);
+          break;
+        }
     }
-  if (!has_selfsig)
-    mis_selfsig++;
 
-  if (inv_sigs)
-    tty_printf (ngettext("%d bad signature\n",
-                         "%d bad signatures\n", inv_sigs), inv_sigs);
+  xfree (pending_desc);
+  pending_desc = NULL;
 
-  if (no_key)
-    tty_printf (ngettext("%d signature not checked due to a missing key\n",
-                         "%d signatures not checked due to missing keys\n",
-                         no_key), no_key);
+  if (issuer != pk)
+    free_public_key (issuer);
+  issuer = NULL;
 
-  if (oth_err)
-    tty_printf (ngettext("%d signature not checked due to an error\n",
-                         "%d signatures not checked due to errors\n",
-                         oth_err), oth_err);
+  /* Identify keys / uids that don't have a self-sig.  */
+  {
+    int has_selfsig = 0;
+    PACKET *p;
+    PKT_signature *sig;
+
+    current_component = NULL;
+    for (n = kb; n; n = n->next)
+      {
+        if (is_deleted_kbnode (n))
+          continue;
 
-  if (mis_selfsig)
-    tty_printf (ngettext("%d user ID without valid self-signature detected\n",
-                         "%d user IDs without valid self-signatures detected\n",
-                         mis_selfsig), mis_selfsig);
+        p = n->pkt;
 
-  return inv_sigs || no_key || oth_err || mis_selfsig;
+        switch (p->pkttype)
+          {
+          case PKT_PUBLIC_KEY:
+          case PKT_PUBLIC_SUBKEY:
+          case PKT_USER_ID:
+            if (current_component && ! has_selfsig)
+              missing_selfsig ++;
+            current_component = n;
+            has_selfsig = 0;
+            break;
+
+          case PKT_SIGNATURE:
+            if (! current_component || has_selfsig)
+              break;
+
+            sig = n->pkt->pkt.signature;
+
+            if (! (sig->flags.checked && sig->flags.valid))
+              break;
+
+            if (keyid_cmp (pk_keyid (pk), sig->keyid) != 0)
+              /* Different issuer, couldn't be a self-sig.  */
+              break;
+
+            if (current_component->pkt->pkttype == PKT_PUBLIC_KEY
+                && (/* Direct key signature.  */
+                    sig->sig_class == 0x1f
+                    /* Key revocation signature.  */
+                    || sig->sig_class == 0x20))
+              has_selfsig = 1;
+            if (current_component->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                && (/* Subkey binding sig.  */
+                    sig->sig_class == 0x18
+                    /* Subkey revocation sig.  */
+                    || sig->sig_class == 0x28))
+              has_selfsig = 1;
+            if (current_component->pkt->pkttype == PKT_USER_ID
+                && (/* Certification sigs.  */
+                    sig->sig_class == 0x10
+                    || sig->sig_class == 0x11
+                    || sig->sig_class == 0x12
+                    || sig->sig_class == 0x13
+                    /* Certification revocation sig.  */
+                    || sig->sig_class == 0x30))
+              has_selfsig = 1;
+
+            break;
+
+          default:
+            if (current_component && ! has_selfsig)
+              missing_selfsig ++;
+            current_component = NULL;
+          }
+      }
+  }
+
+  if (dups || missing_issuer || bad_signature || reordered)
+    tty_printf (_("key %s:\n"), pk_keyid_str (pk));
+
+  if (dups)
+    tty_printf (ngettext ("%d duplicate signature removed\n",
+                          "%d duplicate signatures removed\n", dups), dups);
+  if (missing_issuer)
+    tty_printf (ngettext ("%d signature not checked due to a missing key\n",
+                          "%d signatures not checked due to missing keys\n",
+                          missing_issuer), missing_issuer);
+  if (bad_signature)
+    tty_printf (ngettext ("%d bad signature\n",
+                          "%d bad signatures\n",
+                          bad_signature), bad_signature);
+  if (reordered)
+    tty_printf (ngettext ("%d signature reordered\n",
+                          "%d signatures reordered\n",
+                          reordered), reordered);
+
+  if (only_selfsigs && (bad_signature || reordered))
+    tty_printf (_("Warning: errors found and only checked self-signatures,"
+                  " run '%s' to check all signatures.\n"), "check");
+
+  return modified;
 }
 
 
@@ -483,7 +995,8 @@ trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
   tty_printf ("\n");
 
   tty_printf (_("Please enter the depth of this trust signature.\n"
-               "A depth greater than 1 allows the key you are signing to make\n"
+               "A depth greater than 1 allows the key you are"
+                " signing to make\n"
                "trust signatures on your behalf.\n"));
   tty_printf ("\n");
 
@@ -1070,7 +1583,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
              PKT_signature *sig;
              struct sign_attrib attrib;
 
-             assert (primary_pk);
+             log_assert (primary_pk);
              memset (&attrib, 0, sizeof attrib);
              attrib.non_exportable = local;
              attrib.non_revocable = nonrevocable;
@@ -1237,54 +1750,6 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
 
 
 \f
-/*
- * There are some keys out (due to a bug in gnupg), where the sequence
- * of the packets is wrong.  This function fixes that.
- * Returns: true if the keyblock has been fixed.
- *
- * Note:  This function does not work if there is more than one user ID.
- */
-static int
-fix_key_signature_order (KBNODE keyblock)
-{
-  KBNODE node, last, subkey;
-  int fixed = 0;
-
-  /* Locate key signatures of class 0x10..0x13 behind sub key packets.  */
-  for (subkey = last = NULL, node = keyblock; node;
-       last = node, node = node->next)
-    {
-      switch (node->pkt->pkttype)
-       {
-       case PKT_PUBLIC_SUBKEY:
-       case PKT_SECRET_SUBKEY:
-         if (!subkey)
-           subkey = last; /* Actually it is the one before the subkey.  */
-         break;
-       case PKT_SIGNATURE:
-         if (subkey)
-           {
-             PKT_signature *sig = node->pkt->pkt.signature;
-             if (sig->sig_class >= 0x10 && sig->sig_class <= 0x13)
-               {
-                 log_info (_("moving a key signature to the correct place\n"));
-                 last->next = node->next;
-                 node->next = subkey->next;
-                 subkey->next = node;
-                 node = last;
-                 fixed = 1;
-               }
-           }
-         break;
-       default:
-         break;
-       }
-    }
-
-  return fixed;
-}
-
-
 /* Fix various problems in the keyblock.  Returns true if the keyblock
    was changed.  Note that a pointer to the keyblock must be given and
    the function may change it (i.e. replacing the first node).  */
@@ -1293,10 +1758,10 @@ fix_keyblock (kbnode_t *keyblockp)
 {
   int changed = 0;
 
-  if (fix_key_signature_order (*keyblockp))
-    changed++;
   if (collapse_uids (keyblockp))
     changed++;
+  if (check_all_keysigs (*keyblockp, 0, 1))
+    changed++;
   reorder_keyblock (*keyblockp);
   /* If we modified the keyblock, make sure the flags are right. */
   if (changed)
@@ -1362,7 +1827,7 @@ enum cmdids
   cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
   cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
   cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
-  cmdEXPIRE, cmdBACKSIGN,
+  cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN,
 #ifndef NO_TRUST_MODELS
   cmdENABLEKEY, cmdDISABLEKEY,
 #endif /*!NO_TRUST_MODELS*/
@@ -1393,6 +1858,7 @@ static struct
   { "key", cmdSELKEY, 0, N_("select subkey N")},
   { "check", cmdCHECK, 0, N_("check signatures")},
   { "c", cmdCHECK, 0, NULL},
+  { "change-usage", cmdCHANGEUSAGE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
   { "cross-certify", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
   { "backsign", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL},
   { "sign", cmdSIGN, KEYEDIT_NOT_SK | KEYEDIT_TAIL_MATCH,
@@ -2122,6 +2588,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            }
          break;
 
+       case cmdCHANGEUSAGE:
+         if (menu_changeusage (keyblock))
+           {
+             merge_keys_and_selfsig (keyblock);
+             modified = 1;
+             redisplay = 1;
+           }
+         break;
+
        case cmdBACKSIGN:
          if (menu_backsign (keyblock))
            {
@@ -2170,7 +2645,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdPREF:
          {
            int count = count_selected_uids (keyblock);
-           assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+           log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
            show_names (NULL, keyblock, keyblock->pkt->pkt.public_key,
                        count ? NODFLG_SELUID : 0, 1);
          }
@@ -2179,7 +2654,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
        case cmdSHOWPREF:
          {
            int count = count_selected_uids (keyblock);
-           assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+           log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
            show_names (NULL, keyblock, keyblock->pkt->pkt.public_key,
                        count ? NODFLG_SELUID : 0, 2);
          }
@@ -2458,12 +2933,11 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
 
 
 /* Unattended key signing function.  If the key specifified by FPR is
-   availabale and FPR is the primary fingerprint all user ids of the
-   user ids of the key are signed using the default signing key.  If
-   UIDS is an empty list all usable UIDs are signed, if it is not
-   empty, only those user ids matching one of the entries of the loist
-   are signed.  With LOCAL being true kthe signatures are marked as
-   non-exportable.  */
+   available and FPR is the primary fingerprint all user ids of the
+   key are signed using the default signing key.  If UIDS is an empty
+   list all usable UIDs are signed, if it is not empty, only those
+   user ids matching one of the entries of the list are signed.  With
+   LOCAL being true the signatures are marked as non-exportable.  */
 void
 keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
                     strlist_t locusr, int local)
@@ -2556,27 +3030,72 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
   menu_select_uid (keyblock, 0);   /* Better clear the flags first. */
   for (sl=uids; sl; sl = sl->next)
     {
+      const char *name = sl->d;
+      int count = 0;
+
+      sl->flags &= ~(1|2);  /* Clear flags used for error reporting.  */
+
       for (node = keyblock; node; node = node->next)
         {
           if (node->pkt->pkttype == PKT_USER_ID)
             {
               PKT_user_id *uid = node->pkt->pkt.user_id;
 
-              if (!uid->attrib_data
-                  && ascii_memistr (uid->name, uid->len, sl->d))
+              if (uid->attrib_data)
+                ;
+              else if (*name == '='
+                       && strlen (name+1) == uid->len
+                       && !memcmp (uid->name, name + 1, uid->len))
+                { /* Exact match - we don't do a check for ambiguity
+                   * in this case.  */
+                  node->flag |= NODFLG_SELUID;
+                  if (any != -1)
+                    {
+                      sl->flags |= 1;  /* Report as found.  */
+                      any = 1;
+                    }
+                }
+              else if (ascii_memistr (uid->name, uid->len,
+                                      *name == '*'? name+1:name))
                 {
                   node->flag |= NODFLG_SELUID;
-                  any = 1;
+                  if (any != -1)
+                    {
+                      sl->flags |= 1;  /* Report as found.  */
+                      any = 1;
+                    }
+                  count++;
                 }
             }
         }
+
+      if (count > 1)
+        {
+          any = -1;        /* Force failure at end.  */
+          sl->flags |= 2;  /* Report as ambiguous.  */
+        }
     }
 
-  if (uids && !any)
+  /* Check whether all given user ids were found.  */
+  for (sl=uids; sl; sl = sl->next)
+    if (!(sl->flags & 1))
+      any = -1;  /* That user id was not found.  */
+
+  /* Print an error if there was a problem with the user ids.  */
+  if (uids && any < 1)
     {
       if (!opt.verbose)
         show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
       es_fflush (es_stdout);
+      for (sl=uids; sl; sl = sl->next)
+        {
+          if ((sl->flags & 2))
+            log_info (_("Invalid user ID '%s': %s\n"),
+                      sl->d, gpg_strerror (GPG_ERR_AMBIGUOUS_NAME));
+          else if (!(sl->flags & 1))
+            log_info (_("Invalid user ID '%s': %s\n"),
+                      sl->d, gpg_strerror (GPG_ERR_NOT_FOUND));
+        }
       log_error ("%s  %s", _("No matching user IDs."), _("Nothing to sign.\n"));
       goto leave;
     }
@@ -3539,7 +4058,7 @@ menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name,
     }
   if (!node) /* No subkey.  */
     pub_where = NULL;
-  assert (pk);
+  log_assert (pk);
 
   if (photo)
     {
@@ -3836,7 +4355,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
   size_t fprlen;
   int rc;
 
-  assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   pk = pub_keyblock->pkt->pkt.public_key;
 
@@ -3942,8 +4461,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
                  log_error (_("this key has already been designated "
                               "as a revoker\n"));
 
-                 sprintf (buf, "%08lX%08lX",
-                          (ulong) pk->keyid[0], (ulong) pk->keyid[1]);
+                  format_keyid (pk_keyid (pk), KF_LONG, buf, sizeof (buf));
                  write_status_text (STATUS_ALREADY_SIGNED, buf);
 
                  break;
@@ -4110,6 +4628,112 @@ menu_expire (KBNODE pub_keyblock)
 }
 
 
+/* Change the capability of a selected key.  This command should only
+ * be used to rectify badly created keys and as such is not suggested
+ * for general use.  */
+static int
+menu_changeusage (kbnode_t keyblock)
+{
+  int n1, rc;
+  int mainkey = 0;
+  PKT_public_key *main_pk, *sub_pk;
+  PKT_user_id *uid;
+  kbnode_t node;
+  u32 keyid[2];
+
+  n1 = count_selected_keys (keyblock);
+  if (n1 > 1)
+    {
+      tty_printf (_("You must select exactly one key.\n"));
+      return 0;
+    }
+  else if (n1)
+    tty_printf ("Changing usage of a subkey.\n");
+  else
+    {
+      tty_printf ("Changing usage of the primary key.\n");
+      mainkey = 1;
+    }
+
+  /* Now we can actually change the self-signature(s) */
+  main_pk = sub_pk = NULL;
+  uid = NULL;
+  for (node = keyblock; node; node = node->next)
+    {
+      if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+       {
+         main_pk = node->pkt->pkt.public_key;
+         keyid_from_pk (main_pk, keyid);
+       }
+      else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+       {
+          if (node->flag & NODFLG_SELKEY)
+            sub_pk = node->pkt->pkt.public_key;
+          else
+            sub_pk = NULL;
+       }
+      else if (node->pkt->pkttype == PKT_USER_ID)
+       uid = node->pkt->pkt.user_id;
+      else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE
+              && (mainkey || sub_pk))
+       {
+         PKT_signature *sig = node->pkt->pkt.signature;
+         if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1]
+             && ((mainkey && uid
+                  && uid->created && (sig->sig_class & ~3) == 0x10)
+                 || (!mainkey && sig->sig_class == 0x18))
+             && sig->flags.chosen_selfsig)
+           {
+             /* This is the self-signature which is to be replaced.  */
+             PKT_signature *newsig;
+             PACKET *newpkt;
+
+             if ((mainkey && main_pk->version < 4)
+                 || (!mainkey && sub_pk->version < 4))
+               {
+                 log_info ("You can't change the capabilities of a v3 key\n");
+                 return 0;
+               }
+
+              if (mainkey)
+                main_pk->pubkey_usage = ask_key_flags (main_pk->pubkey_algo, 0,
+                                                       main_pk->pubkey_usage);
+              else
+                sub_pk->pubkey_usage  = ask_key_flags (sub_pk->pubkey_algo, 1,
+                                                       sub_pk->pubkey_usage);
+
+             if (mainkey)
+               rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL,
+                                          main_pk, keygen_add_key_flags,
+                                          main_pk);
+             else
+               rc =
+                 update_keysig_packet (&newsig, sig, main_pk, NULL, sub_pk,
+                                       main_pk, keygen_add_key_flags, sub_pk);
+             if (rc)
+               {
+                 log_error ("make_keysig_packet failed: %s\n",
+                            gpg_strerror (rc));
+                 return 0;
+               }
+
+             /* Replace the packet.  */
+             newpkt = xmalloc_clear (sizeof *newpkt);
+             newpkt->pkttype = PKT_SIGNATURE;
+             newpkt->pkt.signature = newsig;
+             free_packet (node->pkt);
+             xfree (node->pkt);
+             node->pkt = newpkt;
+             sub_pk = NULL;
+              break;
+           }
+       }
+    }
+
+  return 1;
+}
+
+
 static int
 menu_backsign (KBNODE pub_keyblock)
 {
@@ -4118,7 +4742,7 @@ menu_backsign (KBNODE pub_keyblock)
   KBNODE node;
   u32 timestamp;
 
-  assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   merge_keys_and_selfsig (pub_keyblock);
   main_pk = pub_keyblock->pkt->pkt.public_key;
@@ -4867,7 +5491,7 @@ menu_select_uid_namehash (KBNODE keyblock, const char *namehash)
   KBNODE node;
   int i;
 
-  assert (strlen (namehash) == NAMEHASH_LEN * 2);
+  log_assert (strlen (namehash) == NAMEHASH_LEN * 2);
 
   for (i = 0; i < NAMEHASH_LEN; i++)
     hash[i] = hextobyte (&namehash[i * 2]);
@@ -5201,7 +5825,7 @@ menu_revsig (KBNODE keyblock)
   int rc, any, skip = 1, all = !count_selected_uids (keyblock);
   struct revocation_reason_info *reason = NULL;
 
-  assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
   /* First check whether we have any signatures at all.  */
   any = 0;
@@ -5342,7 +5966,7 @@ reloop:                   /* (must use this, because we are modifing the list) */
          || node->pkt->pkttype != PKT_SIGNATURE)
        continue;
       unode = find_prev_kbnode (keyblock, node, PKT_USER_ID);
-      assert (unode);          /* we already checked this */
+      log_assert (unode); /* we already checked this */
 
       memset (&attrib, 0, sizeof attrib);
       attrib.reason = reason;
index 0f7a6a0..f9cbf21 100644 (file)
@@ -24,7 +24,6 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
@@ -252,6 +251,18 @@ keygen_add_key_expire (PKT_signature *sig, void *opaque)
 }
 
 
+/* Add the key usage (i.e. key flags) in SIG from the public keys
+ * pubkey_usage field.  OPAQUE has the public key.  */
+int
+keygen_add_key_flags (PKT_signature *sig, void *opaque)
+{
+  PKT_public_key *pk = opaque;
+
+  do_add_key_flags (sig, pk->pubkey_usage);
+  return 0;
+}
+
+
 static int
 keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
 {
@@ -1359,7 +1370,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
   char *keyparms;
   char nbitsstr[35];
 
-  assert (is_ELGAMAL (algo));
+  log_assert (is_ELGAMAL (algo));
 
   if (nbits < 1024)
     {
@@ -1501,9 +1512,9 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
   gpg_error_t err;
   char *keyparms;
 
-  assert (algo == PUBKEY_ALGO_ECDSA
-          || algo == PUBKEY_ALGO_EDDSA
-          || algo == PUBKEY_ALGO_ECDH);
+  log_assert (algo == PUBKEY_ALGO_ECDSA
+              || algo == PUBKEY_ALGO_EDDSA
+              || algo == PUBKEY_ALGO_ECDH);
 
   if (!curve || !*curve)
     return gpg_error (GPG_ERR_UNKNOWN_CURVE);
@@ -1559,7 +1570,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
   char nbitsstr[35];
   const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096);
 
-  assert (is_RSA(algo));
+  log_assert (is_RSA(algo));
 
   if (!nbits)
     nbits = DEFAULT_STD_KEYSIZE;
@@ -1646,9 +1657,10 @@ print_key_flags(int flags)
 }
 
 
-/* Returns the key flags */
-static unsigned int
-ask_key_flags(int algo,int subkey)
+/* Ask for the key flags and return them.  CURRENT gives the current
+ * usage which should normally be given as 0. */
+unsigned int
+ask_key_flags (int algo, int subkey, unsigned int current)
 {
   /* TRANSLATORS: Please use only plain ASCII characters for the
      translation.  If this is not possible use single digits.  The
@@ -1660,11 +1672,10 @@ ask_key_flags(int algo,int subkey)
        a = Toggle authentication capability
        q = Finish
   */
-  const char *togglers=_("SsEeAaQq");
-  char *answer=NULL;
+  const char *togglers = _("SsEeAaQq");
+  char *answer = NULL;
   const char *s;
-  unsigned int current=0;
-  unsigned int possible=openpgp_pk_algo_usage(algo);
+  unsigned int possible = openpgp_pk_algo_usage(algo);
 
   if ( strlen(togglers) != 8 )
     {
@@ -1678,14 +1689,20 @@ ask_key_flags(int algo,int subkey)
     possible&=~PUBKEY_USAGE_CERT;
 
   /* Preload the current set with the possible set, minus
-     authentication, since nobody really uses auth yet. */
-  current=possible&~PUBKEY_USAGE_AUTH;
+     authentication if CURRENT has been given as 0.  If CURRENT has
+     been has non-zero we mask with all possible usages. */
+  if (current)
+    current &= possible;
+  else
+    current = (possible&~PUBKEY_USAGE_AUTH);
 
   for(;;)
     {
       tty_printf("\n");
       tty_printf(_("Possible actions for a %s key: "),
-                openpgp_pk_algo_name (algo));
+                 (algo == PUBKEY_ALGO_ECDSA
+                  || algo == PUBKEY_ALGO_EDDSA)
+                 ? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
       print_key_flags(possible);
       tty_printf("\n");
       tty_printf(_("Current allowed actions: "));
@@ -1922,13 +1939,13 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
       else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_DSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_RSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else if ((algo == 9 || !strcmp (answer, "ecc+ecc"))
@@ -1947,7 +1964,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
       else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert)
         {
           algo = PUBKEY_ALGO_ECDSA;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else if ((algo == 12 || !strcmp (answer, "ecc/e"))
@@ -1985,7 +2002,7 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
           xfree (keygrip);
           keygrip = answer;
           answer = NULL;
-          *r_usage = ask_key_flags (algo, addmode);
+          *r_usage = ask_key_flags (algo, addmode, 0);
           break;
        }
       else
@@ -2127,26 +2144,32 @@ ask_keysize (int algo, unsigned int primary_keysize)
 static char *
 ask_curve (int *algo, int *subkey_algo)
 {
+  /* NB: We always use a complete algo list so that we have stable
+     numbers in the menu regardless on how Gpg was configured.  */
   struct {
     const char *name;
-    int available;
+    int available;   /* Available in Libycrypt (runtime checked) */
     int expert_only;
-    int fix_curve;
+    const char* eddsa_curve; /* Corresponding EdDSA curve.  */
     const char *pretty_name;
+    int supported;   /* Supported by gpg.  */
   } curves[] = {
-#if GPG_USE_EDDSA
-    { "Curve25519",      0, 0, 1, "Curve 25519" },
-#endif
 #if GPG_USE_ECDSA || GPG_USE_ECDH
-    { "NIST P-256",      0, 1, 0, },
-    { "NIST P-384",      0, 0, 0, },
-    { "NIST P-521",      0, 1, 0, },
-    { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" },
-    { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" },
-    { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" },
-    { "secp256k1",       0, 1, 0  },
+# define MY_USE_ECDSADH 1
+#else
+# define MY_USE_ECDSADH 0
 #endif
+    { "Curve25519",      0, 0, "Ed25519", "Curve 25519", GPG_USE_EDDSA  },
+    { "Curve448",        0, 1, "Ed448",   "Curve 448",   0/*reserved*/  },
+    { "NIST P-256",      0, 1, NULL, NULL,               MY_USE_ECDSADH },
+    { "NIST P-384",      0, 0, NULL, NULL,               MY_USE_ECDSADH },
+    { "NIST P-521",      0, 1, NULL, NULL,               MY_USE_ECDSADH },
+    { "brainpoolP256r1", 0, 1, NULL, "Brainpool P-256",  MY_USE_ECDSADH },
+    { "brainpoolP384r1", 0, 1, NULL, "Brainpool P-384",  MY_USE_ECDSADH },
+    { "brainpoolP512r1", 0, 1, NULL, "Brainpool P-512",  MY_USE_ECDSADH },
+    { "secp256k1",       0, 1, NULL, NULL,               MY_USE_ECDSADH },
   };
+#undef MY_USE_ECDSADH
   int idx;
   char *answer;
   char *result = NULL;
@@ -2154,32 +2177,32 @@ ask_curve (int *algo, int *subkey_algo)
 
   tty_printf (_("Please select which elliptic curve you want:\n"));
 
- again:
   keyparms = NULL;
   for (idx=0; idx < DIM(curves); idx++)
     {
       int rc;
 
       curves[idx].available = 0;
+      if (!curves[idx].supported)
+        continue;
       if (!opt.expert && curves[idx].expert_only)
         continue;
 
-      /* FIXME: The strcmp below is a temporary hack during
-         development.  It shall be removed as soon as we have proper
-         Curve25519 support in Libgcrypt.  */
+      /* We need to switch from the ECDH name of the curve to the
+         EDDSA name of the curve if we want a signing key.  */
       gcry_sexp_release (keyparms);
       rc = gcry_sexp_build (&keyparms, NULL,
                             "(public-key(ecc(curve %s)))",
-                            (!strcmp (curves[idx].name, "Curve25519")
-                             ? "Ed25519" : curves[idx].name));
+                            curves[idx].eddsa_curve? curves[idx].eddsa_curve
+                            /**/                   : curves[idx].name);
       if (rc)
         continue;
       if (!gcry_pk_get_curve (keyparms, 0, NULL))
         continue;
-      if (subkey_algo && curves[idx].fix_curve)
+      if (subkey_algo && curves[idx].eddsa_curve)
         {
-          /* Both Curve 25519 keys are to be created.  Check that
-             Libgcrypt also supports the real Curve25519.  */
+          /* Both Curve 25519 (or 448) keys are to be created.  Check that
+             Libgcrypt also supports the real Curve25519 (or 448).  */
           gcry_sexp_release (keyparms);
           rc = gcry_sexp_build (&keyparms, NULL,
                                 "(public-key(ecc(curve %s)))",
@@ -2226,25 +2249,15 @@ ask_curve (int *algo, int *subkey_algo)
         tty_printf (_("Invalid selection.\n"));
       else
         {
-          if (curves[idx].fix_curve)
-            {
-              log_info ("WARNING: Curve25519 is not yet part of the"
-                        " OpenPGP standard.\n");
-
-              if (!cpr_get_answer_is_yes("experimental_curve.override",
-                                         "Use this curve anyway? (y/N) ")  )
-                goto again;
-            }
-
           /* If the user selected a signing algorithm and Curve25519
-             we need to update the algo and and the curve name.  */
+             we need to set the algo to EdDSA and update the curve name. */
           if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
-              && curves[idx].fix_curve)
+              && curves[idx].eddsa_curve)
             {
               if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
                 *subkey_algo = PUBKEY_ALGO_EDDSA;
               *algo = PUBKEY_ALGO_EDDSA;
-              result = xstrdup ("Ed25519");
+              result = xstrdup (curves[idx].eddsa_curve);
             }
           else
             result = xstrdup (curves[idx].name);
@@ -2780,7 +2793,7 @@ generate_user_id (KBNODE keyblock, const char *uidstr)
 static void
 append_to_parameter (struct para_data_s *para, struct para_data_s *r)
 {
-  assert (para);
+  log_assert (para);
   while (para->next)
     para = para->next;
   para->next = r;
@@ -3765,7 +3778,12 @@ generate_keypair (ctrl_t ctrl, int full, const char *fname,
     {
       tty_printf ( _("Note: Use \"%s %s\""
                      " for a full featured key generation dialog.\n"),
-                   NAME_OF_INSTALLED_GPG, "--full-gen-key" );
+#if USE_GPG2_HACK
+                   GPG_NAME "2"
+#else
+                   GPG_NAME
+#endif
+                   , "--full-gen-key" );
       para = quickgen_set_para (para, 0,
                                 DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE,
                                 DEFAULT_STD_CURVE);
@@ -3824,15 +3842,15 @@ card_write_key_to_backup_file (PKT_public_key *sk, const char *backup_dir)
 {
   gpg_error_t err = 0;
   int rc;
+  char keyid_buffer[2 * 8 + 1];
   char name_buffer[50];
   char *fname;
   IOBUF fp;
   mode_t oldmask;
   PACKET *pkt = NULL;
 
-  keyid_from_pk (sk, NULL);
-  snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg",
-            (ulong)sk->keyid[0], (ulong)sk->keyid[1]);
+  format_keyid (pk_keyid (sk), KF_LONG, keyid_buffer, sizeof (keyid_buffer));
+  snprintf (name_buffer, sizeof name_buffer, "sk_%s.gpg", keyid_buffer);
 
   fname = make_filename (backup_dir, name_buffer, NULL);
   /* Note that the umask call is not anymore needed because
@@ -4015,7 +4033,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
               push_armor_filter (outctrl->pub.afx, outctrl->pub.stream);
             }
         }
-      assert( outctrl->pub.stream );
+      log_assert( outctrl->pub.stream );
       if (opt.verbose)
         log_info (_("writing public key to '%s'\n"), outctrl->pub.fname );
     }
@@ -4060,7 +4078,15 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
   if (!err)
     {
       pri_psk = pub_root->next->pkt->pkt.public_key;
-      assert (pri_psk);
+      log_assert (pri_psk);
+
+      /* Make sure a few fields are correctly set up before going
+         further.  */
+      pri_psk->flags.primary = 1;
+      keyid_from_pk (pri_psk, NULL);
+      /* We don't use pk_keyid to get keyid, because it also asserts
+         that main_keyid is set!  */
+      keyid_copy (pri_psk->main_keyid, pri_psk->keyid);
     }
 
   if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
@@ -4114,7 +4140,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
               for (node = pub_root; node; node = node->next)
                 if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
                   sub_psk = node->pkt->pkt.public_key;
-              assert (sub_psk);
+              log_assert (sub_psk);
 
               if (s)
                 err = card_store_key_with_backup (ctrl, sub_psk, opt.homedir);
@@ -4300,7 +4326,7 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock)
   xfree (hexgrip);
   hexgrip = NULL;
   algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip);
-  assert (algo);
+  log_assert (algo);
 
   if (hexgrip)
     nbits = 0;
@@ -4365,7 +4391,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
   u32 cur_time;
   struct para_data_s *para = NULL;
 
-  assert (keyno >= 1 && keyno <= 3);
+  log_assert (keyno >= 1 && keyno <= 3);
 
   para = xtrycalloc (1, sizeof *para + strlen (serialno) );
   if (!para)
@@ -4435,7 +4461,7 @@ generate_card_subkeypair (kbnode_t pub_keyblock,
       for (node = pub_keyblock; node; node = node->next)
         if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
           sub_pk = node->pkt->pkt.public_key;
-      assert (sub_pk);
+      log_assert (sub_pk);
       err = write_keybinding (pub_keyblock, pri_pk, sub_pk,
                               use, cur_time, NULL);
     }
index f684276..bd808d2 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 1998, 1999, 2000, 2001, 2003,
  *               2004, 2006, 2010 Free Software Foundation, Inc.
  * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -25,7 +26,6 @@
 #include <string.h>
 #include <errno.h>
 #include <time.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -274,12 +274,61 @@ v3_keyid (gcry_mpi_t a, u32 *ki)
 }
 
 
-const char *
+/* Return PK's keyid.  The memory is owned by PK.  */
+u32 *
+pk_keyid (PKT_public_key *pk)
+{
+  keyid_from_pk (pk, NULL);
+
+  /* Uncomment this for help tracking down bugs related to keyid or
+     main_keyid not being set correctly.  */
+#if 0
+  if (! (pk->main_keyid[0] || pk->main_keyid[1]))
+    log_bug ("pk->main_keyid not set!\n");
+  if (keyid_cmp (pk->keyid, pk->main_keyid) == 0
+      && ! pk->flags.primary)
+    log_bug ("keyid and main_keyid are the same, but primary flag not set!\n");
+  if (keyid_cmp (pk->keyid, pk->main_keyid) != 0
+      && pk->flags.primary)
+    log_bug ("keyid and main_keyid are different, but primary flag set!\n");
+#endif
+
+  return pk->keyid;
+}
+
+/* Return the keyid of the primary key associated with PK.  The memory
+   is owned by PK.  */
+u32 *
+pk_main_keyid (PKT_public_key *pk)
+{
+  /* Uncomment this for help tracking down bugs related to keyid or
+     main_keyid not being set correctly.  */
+#if 0
+  if (! (pk->main_keyid[0] || pk->main_keyid[1]))
+    log_bug ("pk->main_keyid not set!\n");
+#endif
+
+  return pk->main_keyid;
+}
+
+/* Copy the keyid in SRC to DEST and return DEST.  */
+u32 *
+keyid_copy (u32 *dest, const u32 *src)
+{
+  dest[0] = src[0];
+  dest[1] = src[1];
+  return dest;
+}
+
+char *
 format_keyid (u32 *keyid, int format, char *buffer, int len)
 {
   char tmp[KEYID_STR_SIZE];
   if (! buffer)
-    buffer = tmp;
+    {
+      buffer = tmp;
+      len = sizeof (tmp);
+    }
 
   if (format == KF_DEFAULT)
     format = opt.keyid_format;
@@ -393,6 +442,14 @@ keystr_from_pk_with_sub (PKT_public_key *main_pk, PKT_public_key *sub_pk)
 }
 
 
+/* Return PK's key id as a string using the default format.  PK owns
+   the storage.  */
+const char *
+pk_keyid_str (PKT_public_key *pk)
+{
+  return keystr (pk_keyid (pk));
+}
+
 
 const char *
 keystr_from_desc(KEYDB_SEARCH_DESC *desc)
@@ -709,7 +766,7 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
   md = do_fingerprint_md(pk);
   dp = gcry_md_read( md, 0 );
   len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
-  assert( len <= MAX_FINGERPRINT_LEN );
+  log_assert( len <= MAX_FINGERPRINT_LEN );
   if (!array)
     array = xmalloc ( len );
   memcpy (array, dp, len );
@@ -791,7 +848,7 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
           buffer[j ++] = fingerprint[i];
         }
       buffer[j ++] = 0;
-      assert (j == space);
+      log_assert (j == space);
     }
   else
     {
index d71bf4f..1649991 100644 (file)
@@ -24,9 +24,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #ifdef HAVE_DOSISH_SYSTEM
-#include <fcntl.h>             /* for setmode() */
+# include <fcntl.h>            /* for setmode() */
 #endif
 
 #include "gpg.h"
@@ -799,7 +798,7 @@ print_subpackets_colon (PKT_signature * sig)
 {
   byte *i;
 
-  assert (opt.show_subpackets);
+  log_assert (opt.show_subpackets);
 
   for (i = opt.show_subpackets; *i; i++)
     {
@@ -1116,6 +1115,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
       if (node->pkt->pkttype == PKT_USER_ID)
        {
          PKT_user_id *uid = node->pkt->pkt.user_id;
+          int indent;
 
          if ((uid->is_expired || uid->is_revoked)
              && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
@@ -1133,25 +1133,46 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr,
              || (opt.list_options & LIST_SHOW_UID_VALIDITY))
            {
              const char *validity;
-             int indent;
 
              validity = uid_trust_string_fixed (pk, uid);
-             indent =
-               (keystrlen () + (opt.legacy_list_mode? 9:11)) -
-               atoi (uid_trust_string_fixed (NULL, NULL));
-
+             indent = ((keystrlen () + (opt.legacy_list_mode? 9:11))
+                        - atoi (uid_trust_string_fixed (NULL, NULL)));
              if (indent < 0 || indent > 40)
                indent = 0;
 
              es_fprintf (es_stdout, "uid%*s%s ", indent, "", validity);
            }
          else
-           es_fprintf (es_stdout, "uid%*s",
-                        (int) keystrlen () + (opt.legacy_list_mode? 10:12), "");
+            {
+              indent = keystrlen () + (opt.legacy_list_mode? 10:12);
+              es_fprintf (es_stdout, "uid%*s", indent, "");
+            }
 
          print_utf8_buffer (es_stdout, uid->name, uid->len);
          es_putc ('\n', es_stdout);
 
+          if (opt.with_wkd_hash)
+            {
+              char *mbox, *hash, *p;
+              char hashbuf[32];
+
+              mbox = mailbox_from_userid (uid->name);
+              if (mbox && (p = strchr (mbox, '@')))
+                {
+                  *p++ = 0;
+                  gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf,
+                                       mbox, strlen (mbox));
+                  hash = zb32_encode (hashbuf, 8*20);
+                  if (hash)
+                    {
+                      es_fprintf (es_stdout, "   %*s%s@%s\n",
+                                  indent, "", hash, p);
+                      xfree (hash);
+                    }
+                }
+              xfree (mbox);
+            }
+
          if ((opt.list_options & LIST_SHOW_PHOTOS) && uid->attribs != NULL)
            show_photos (uid->attribs, uid->numattribs, pk, uid);
        }
@@ -1766,9 +1787,9 @@ do_reorder_keyblock (KBNODE keyblock, int attr)
       if (node->pkt->pkttype == PKT_USER_ID)
        break;
     }
-  assert (node);
-  assert (last);        /* The user ID is never the first packet.  */
-  assert (primary0);    /* Ditto (this is the node before primary).  */
+  log_assert (node);
+  log_assert (last);    /* The user ID is never the first packet.  */
+  log_assert (primary0); /* Ditto (this is the node before primary).  */
   if (node == primary)
     return; /* Already the first one.  */
 
index 7c7b355..843975e 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -243,7 +242,7 @@ keyring_new (void *token)
   KEYRING_HANDLE hd;
   KR_RESOURCE resource = token;
 
-  assert (resource);
+  log_assert (resource);
 
   hd = xtrycalloc (1, sizeof *hd);
   if (!hd)
@@ -258,7 +257,7 @@ keyring_release (KEYRING_HANDLE hd)
 {
     if (!hd)
         return;
-    assert (active_handles > 0);
+    log_assert (active_handles > 0);
     active_handles--;
     xfree (hd->word_match.name);
     xfree (hd->word_match.pattern);
@@ -691,7 +690,7 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
 int
 keyring_search_reset (KEYRING_HANDLE hd)
 {
-    assert (hd);
+    log_assert (hd);
 
     hd->current.kr = NULL;
     iobuf_close (hd->current.iobuf);
@@ -749,10 +748,10 @@ prepare_search (KEYRING_HANDLE hd)
         if (!hd->current.kr) {
           if (DBG_LOOKUP)
             log_debug ("%s: keyring not available!\n", __func__);
-            hd->current.eof = 1;
-            return -1; /* keyring not available */
+          hd->current.eof = 1;
+          return -1; /* keyring not available */
         }
-        assert (!hd->current.iobuf);
+        log_assert (!hd->current.iobuf);
     }
     else { /* EOF */
         if (DBG_LOOKUP)
@@ -1084,7 +1083,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
           if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
             name = desc[n].u.name;
         }
-      assert (name);
+      log_assert (name);
       if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
         {
           /* name changed */
@@ -1713,7 +1712,7 @@ do_copy (int mode, const char *fname, KBNODE root,
            goto leave;
        }
        /* skip this keyblock */
-       assert( n_packets );
+       log_assert( n_packets );
        rc = skip_some_packets( fp, n_packets );
        if( rc ) {
            log_error("%s: skipping %u packets failed: %s\n",
index 6f6f430..f57dcaa 100644 (file)
@@ -45,6 +45,8 @@ int keyserver_import_cert (ctrl_t ctrl, const char *name, int dane_mode,
                            unsigned char **fpr,size_t *fpr_len);
 gpg_error_t keyserver_import_pka (ctrl_t ctrl, const char *name,
                                   unsigned char **fpr,size_t *fpr_len);
+gpg_error_t keyserver_import_wkd (ctrl_t ctrl, const char *name,
+                                  unsigned char **fpr, size_t *fpr_len);
 int keyserver_import_name (ctrl_t ctrl,
                            const char *name,unsigned char **fpr,size_t *fpr_len,
                            struct keyserver_spec *keyserver);
index e9ccb58..3486abb 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <errno.h>
 
 #include "gpg.h"
@@ -243,7 +242,7 @@ parse_keyserver_uri (const char *string,int require_scheme)
   int count;
   char *uri,*options;
 
-  assert(string!=NULL);
+  log_assert (string);
 
   keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
 
@@ -2004,6 +2003,39 @@ keyserver_import_pka (ctrl_t ctrl, const char *name,
 }
 
 
+/* Import a key using the Web Key Directory protocol.  */
+gpg_error_t
+keyserver_import_wkd (ctrl_t ctrl, const char *name,
+                      unsigned char **fpr, size_t *fpr_len)
+{
+  gpg_error_t err;
+  estream_t key;
+
+  err = gpg_dirmngr_wkd_get (ctrl, name, &key);
+  if (err)
+    ;
+  else if (key)
+    {
+      int armor_status = opt.no_armor;
+
+      /* Keys returned via WKD are in binary format. */
+      opt.no_armor = 1;
+
+      err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
+                                   (opt.keyserver_options.import_options
+                                    | IMPORT_NO_SECKEY),
+                                   NULL, NULL);
+
+      opt.no_armor = armor_status;
+
+      es_fclose (key);
+      key = NULL;
+    }
+
+  return err;
+}
+
+
 /* Import a key by name using LDAP */
 int
 keyserver_import_ldap (ctrl_t ctrl,
index ec24426..5b5947e 100644 (file)
@@ -98,7 +98,6 @@ char *make_radix64_string( const byte *data, size_t len );
 
 /*-- misc.c --*/
 void trap_unaligned(void);
-int disable_core_dumps(void);
 void register_secured_file (const char *fname);
 void unregister_secured_file (const char *fname);
 int  is_secured_file (int fd);
@@ -221,6 +220,7 @@ void display_online_help( const char *keyword );
 
 /*-- encode.c --*/
 int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
+void encrypt_seskey (DEK *dek, DEK **seskey, byte *enckey);
 int use_mdc (pk_list_t pk_list,int algo);
 int encrypt_symmetric (const char *filename );
 int encrypt_store (const char *filename );
@@ -232,6 +232,8 @@ void encrypt_crypt_files (ctrl_t ctrl,
 int encrypt_filter (void *opaque, int control,
                    iobuf_t a, byte *buf, size_t *ret_len);
 
+int write_pubkey_enc (PKT_public_key *pk, int throw_keyid,
+                      DEK *dek, iobuf_t out);
 
 /*-- sign.c --*/
 int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
@@ -263,6 +265,19 @@ int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
                          PKT_public_key *ret_pk, int *is_selfsig,
                          u32 *r_expiredate, int *r_expired );
 
+/* Returns whether SIGNER generated the signature SIG over the packet
+   PACKET, which is a key, subkey or uid, and comes from the key block
+   KB.  If SIGNER is NULL, it is looked up based on the information in
+   SIG.  If not NULL, sets *IS_SELFSIG to indicate whether the
+   signature is a self-signature and *RET_PK to a copy of the signer's
+   key.  */
+gpg_error_t check_signature_over_key_or_uid (PKT_public_key *signer,
+                                             PKT_signature *sig,
+                                             KBNODE kb, PACKET *packet,
+                                             int *is_selfsig,
+                                             PKT_public_key *ret_pk);
+
+
 /*-- delkey.c --*/
 gpg_error_t delete_keys (strlist_t names, int secret, int allow_both);
 
@@ -280,12 +295,14 @@ void show_basic_key_info (KBNODE keyblock);
 u32 parse_expire_string(const char *string);
 u32 ask_expire_interval(int object,const char *def_expire);
 u32 ask_expiredate(void);
+unsigned int ask_key_flags (int algo, int subkey, unsigned int current);
 void quick_generate_keypair (ctrl_t ctrl, const char *uid);
 void generate_keypair (ctrl_t ctrl, int full, const char *fname,
                        const char *card_serialno, int card_backup_key);
 int keygen_set_std_prefs (const char *string,int personal);
 PKT_user_id *keygen_get_std_prefs (void);
 int keygen_add_key_expire( PKT_signature *sig, void *opaque );
+int keygen_add_key_flags (PKT_signature *sig, void *opaque);
 int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
 int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
 int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
index 5e6b40b..d56790b 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <time.h>
 
 #include "gpg.h"
@@ -855,7 +854,7 @@ do_check_sig (CTX c, kbnode_t node, int *is_selfsig,
   gcry_md_hd_t md_good = NULL;
   int algo, rc;
 
-  assert (node->pkt->pkttype == PKT_SIGNATURE);
+  log_assert (node->pkt->pkttype == PKT_SIGNATURE);
   if (is_selfsig)
     *is_selfsig = 0;
   sig = node->pkt->pkt.signature;
@@ -1523,7 +1522,7 @@ pka_uri_from_sig (CTX c, PKT_signature *sig)
 {
   if (!sig->flags.pka_tried)
     {
-      assert (!sig->pka_info);
+      log_assert (!sig->pka_info);
       sig->flags.pka_tried = 1;
       sig->pka_info = get_pka_address (sig);
       if (sig->pka_info)
@@ -1637,7 +1636,7 @@ check_sig_and_print (CTX c, kbnode_t node)
 /*     dump_kbnode (c->list); */
 
     n = c->list;
-    assert (n);
+    log_assert (n);
     if ( n->pkt->pkttype == PKT_SIGNATURE )
       {
         /* This is either "S{1,n}" case (detached signature) or
@@ -1864,7 +1863,7 @@ check_sig_and_print (CTX c, kbnode_t node)
           if (un->pkt->pkt.user_id->attrib_data)
             continue;
 
-          assert (pk);
+          log_assert (pk);
 
          /* Since this is just informational, don't actually ask the
             user to update any trust information.  (Note: we register
index 88b2ee1..0dbbc3c 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "status.h"
index 96ca5c2..f4881b4 100644 (file)
@@ -22,7 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
+#include <unistd.h>
 
 #include "gpg.h"
 #include "options.h"
index bdc4505..d2537cf 100644 (file)
@@ -69,8 +69,6 @@
 #include "i18n.h"
 #include "zb32.h"
 
-#include <assert.h>
-
 
 #ifdef ENABLE_SELINUX_HACKS
 /* A object and a global variable to keep track of files marked as
index 859090e..006ff35 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
index 1407b2f..0de0418 100644 (file)
@@ -73,6 +73,7 @@ struct
   int with_fingerprint; /* Option --with-fingerprint active.  */
   int with_keygrip;     /* Option --with-keygrip active.  */
   int with_secret;      /* Option --with-secret active.  */
+  int with_wkd_hash;    /* Option --with-wkd-hash.  */
   int fingerprint; /* list fingerprints */
   int list_sigs;   /* list signatures */
   int print_pka_records;
@@ -245,6 +246,7 @@ struct
       AKL_CERT,
       AKL_PKA,
       AKL_DANE,
+      AKL_WKD,
       AKL_LDAP,
       AKL_KEYSERVER,
       AKL_SPEC
index 16524f8..194c134 100644 (file)
@@ -29,6 +29,7 @@
 #include "filter.h"
 #include "../common/openpgpdefs.h"
 #include "../common/userids.h"
+#include "util.h"
 
 #define DEBUG_PARSE_PACKET 1
 
@@ -79,49 +80,91 @@ typedef struct {
     byte value;
 } prefitem_t;
 
+/* A string-to-key specifier as defined in RFC 4880, Section 3.7.  */
 typedef struct
 {
   int  mode;      /* Must be an integer due to the GNU modes 1001 et al.  */
   byte hash_algo;
   byte salt[8];
+  /* The *coded* (i.e., the serialized version) iteration count.  */
   u32  count;
 } STRING2KEY;
 
+/* A symmetric-key encrypted session key packet as defined in RFC
+   4880, Section 5.3.  All fields are serialized.  */
 typedef struct {
-    byte version;
-    byte cipher_algo;   /* cipher algorithm used */
-    STRING2KEY s2k;
-    byte seskeylen;   /* keylength in byte or 0 for no seskey */
-    byte seskey[1];
+  /* RFC 4880: this must be 4.  */
+  byte version;
+  /* The cipher algorithm used.  */
+  byte cipher_algo;
+  /* The string-to-key specifier.  */
+  STRING2KEY s2k;
+  /* The length of SESKEY in bytes or 0 if this packet does not
+     encrypt a session key.  (In the latter case, the results of the
+     S2K function on the password is the session key. See RFC 4880,
+     Section 5.3.)  */
+  byte seskeylen;
+  /* The session key as encrypted by the S2K specifier.  */
+  byte seskey[1];
 } PKT_symkey_enc;
 
+/* A public-key encrypted session key packet as defined in RFC 4880,
+   Section 5.1.  All fields are serialized.  */
 typedef struct {
-    u32     keyid[2];      /* 64 bit keyid */
-    byte    version;
-    byte    pubkey_algo;    /* algorithm used for public key scheme */
-    byte    throw_keyid;
-    gcry_mpi_t     data[PUBKEY_MAX_NENC];
+  /* The 64-bit keyid.  */
+  u32     keyid[2];
+  /* The packet's version.  Currently, only version 3 is defined.  */
+  byte    version;
+  /* The algorithm used for the public key encryption scheme.  */
+  byte    pubkey_algo;
+  /* Whether to hide the key id.  This value is not directly
+     serialized.  */
+  byte    throw_keyid;
+  /* The session key.  */
+  gcry_mpi_t     data[PUBKEY_MAX_NENC];
 } PKT_pubkey_enc;
 
 
+/* A one-pass signature packet as defined in RFC 4880, Section
+   5.4.  All fields are serialized.  */
 typedef struct {
-    u32     keyid[2];      /* 64 bit keyid */
-    byte    sig_class;     /* sig classification */
+    u32     keyid[2];      /* The 64-bit keyid */
+    /* The signature's classification (RFC 4880, Section 5.2.1).  */
+    byte    sig_class;
     byte    digest_algo;    /* algorithm used for digest */
     byte    pubkey_algo;    /* algorithm used for public key scheme */
-    byte    last;          /* a stupid flag */
+    /* A message can be signed by multiple keys.  In this case, there
+       are n one-pass signature packets before the message to sign and
+       n signatures packets after the message.  It is conceivable that
+       someone wants to not only sign the message, but all of the
+       signatures.  Now we need to distinguish between signing the
+       message and signing the message plus the surrounding
+       signatures.  This is the point of this flag.  If set, it means:
+       I sign all of the data starting at the next packet.  */
+    byte    last;
 } PKT_onepass_sig;
 
 
+/* A v4 OpenPGP signature has a hashed and unhashed area containing
+   co-called signature subpackets (RFC 4880, Section 5.2.3).  These
+   areas are described by this data structure.  Use enum_sig_subpkt to
+   parse this area.  */
 typedef struct {
     size_t size;  /* allocated */
-    size_t len;   /* used */
-    byte data[1];
+    size_t len;   /* used (serialized) */
+    byte data[1]; /* the serialized subpackes (serialized) */
 } subpktarea_t;
 
+/* The in-memory representation of a designated revoker signature
+   subpacket (RFC 4880, Section 5.2.3.15).  */
 struct revocation_key {
+  /* A bit field.  0x80 must be set.  0x40 means this information is
+     sensitive (and should not be uploaded to a keyserver by
+     default).  */
   byte class;
+  /* The public-key algorithm ID.  */
   byte algid;
+  /* The fingerprint of the authorized key.  */
   byte fpr[MAX_FINGERPRINT_LEN];
 };
 
@@ -139,7 +182,11 @@ typedef struct
 } pka_info_t;
 
 
-/* Object to keep information pertaining to a signature. */
+/* A signature packet (RFC 4880, Section 5.2).  Only a subset of these
+   fields are directly serialized (these are marked as such); the rest
+   are read from the subpackets, which are not synthesized when
+   serializing this data structure (i.e., when using build_packet()).
+   Instead, the subpackets must be created by hand.  */
 typedef struct
 {
   struct
@@ -156,14 +203,26 @@ typedef struct
     unsigned expired:1;
     unsigned pka_tried:1;   /* Set if we tried to retrieve the PKA record. */
   } flags;
-  u32     keyid[2];      /* 64 bit keyid */
-  u32     timestamp;     /* Signature made (seconds since Epoch). */
+  /* The key that allegedly generated this signature.  (Directly
+     serialized in v3 sigs; for v4 sigs, this must be explicitly added
+     as an issuer subpacket (5.2.3.5.)  */
+  u32     keyid[2];
+  /* When the signature was made (seconds since the Epoch).  (Directly
+     serialized in v3 sigs; for v4 sigs, this must be explicitly added
+     as a signature creation time subpacket (5.2.3.4).)  */
+  u32     timestamp;
   u32     expiredate;     /* Expires at this date or 0 if not at all. */
+  /* The serialization format used / to use.  If 0, then defaults to
+     version 3.  (Serialized.)  */
   byte    version;
-  byte    sig_class;     /* Sig classification, append for MD calculation. */
-  byte    pubkey_algo;    /* Algorithm used for public key scheme */
-                          /* (PUBKEY_ALGO_xxx) */
-  byte    digest_algo;    /* Algorithm used for digest (DIGEST_ALGO_xxxx). */
+  /* The signature type. (See RFC 4880, Section 5.2.1.)  */
+  byte    sig_class;
+  /* Algorithm used for public key scheme (e.g., PUBKEY_ALGO_RSA).
+     (Serialized.)  */
+  byte    pubkey_algo;
+  /* Algorithm used for digest (e.g., DIGEST_ALGO_SHA1).
+     (Serialized.)  */
+  byte    digest_algo;
   byte    trust_depth;
   byte    trust_value;
   const byte *trust_regexp;
@@ -173,7 +232,10 @@ typedef struct
                                 available.  See also flags.pka_tried. */
   subpktarea_t *hashed;      /* All subpackets with hashed data (v4 only). */
   subpktarea_t *unhashed;    /* Ditto for unhashed data. */
-  byte digest_start[2];      /* First 2 bytes of the digest. */
+  /* First 2 bytes of the digest.  (Serialized.  Note: this is not
+     automatically filled in when serializing a signature!)  */
+  byte digest_start[2];
+  /* The signature.  (Serialized.)  */
   gcry_mpi_t  data[PUBKEY_MAX_NSIG];
   /* The message digest and its length (in bytes).  Note the maximum
      digest length is 512 bits (64 bytes).  If DIGEST_LEN is 0, then
@@ -192,14 +254,21 @@ struct user_attribute {
 };
 
 
-/* (See also keybox-search-desc.h) */
-struct gpg_pkt_user_id_s
+/* A user id (RFC 4880, Section 5.11) or a user attribute packet (RFC
+   4880, Section 5.12).  Only a subset of these fields are directly
+   serialized (these are marked as such); the rest are read from the
+   self-signatures in merge_keys_and_selfsig()).  */
+typedef struct
 {
   int ref;              /* reference counter */
-  int len;             /* length of the name */
+  /* The length of NAME.  */
+  int len;
   struct user_attribute *attribs;
   int numattribs;
-  byte *attrib_data;    /* if this is not NULL, the packet is an attribute */
+  /* If this is not NULL, the packet is a user attribute rather than a
+     user id.  (Serialized.)  */
+  byte *attrib_data;
+  /* The length of ATTRIB_DATA.  */
   unsigned long attrib_len;
   byte *namehash;
   int help_key_usage;
@@ -220,9 +289,11 @@ struct gpg_pkt_user_id_s
     unsigned int ks_modify:1;
     unsigned int compacted:1;
   } flags;
+  /* The text contained in the user id packet, which is normally the
+     name and email address of the key holder (See RFC 4880 5.11).
+     (Serialized.)  */
   char name[1];
-};
-typedef struct gpg_pkt_user_id_s PKT_user_id;
+} PKT_user_id;
 
 
 
@@ -254,6 +325,14 @@ struct seckey_info
 
 
 /****************
+ * The in-memory representation of a public key (RFC 4880, Section
+ * 5.5).  Note: this structure contains significantly more information
+ * than is contained in an OpenPGP public key packet.  This
+ * information is derived from the self-signed signatures (by
+ * merge_keys_and_selfsig()) and is ignored when serializing the
+ * packet.  The fields that are actually written out when serializing
+ * this packet are marked as accordingly.
+ *
  * We assume that secret keys have the same number of parameters as
  * the public key and that the public parameters are the first items
  * in the PKEY array.  Thus NPKEY is always less than NSKEY and it is
@@ -268,19 +347,31 @@ struct seckey_info
  */
 typedef struct
 {
-  u32     timestamp;       /* key made */
+  /* When the key was created.  (Serialized.)  */
+  u32     timestamp;
   u32     expiredate;     /* expires at this date or 0 if not at all */
   u32     max_expiredate; /* must not expire past this date */
   struct revoke_info revoked;
-  byte    hdrbytes;        /* number of header bytes */
+  /* An OpenPGP packet consists of a header and a body.  This is the
+     size of the header.  If this is 0, an appropriate size is
+     automatically chosen based on the size of the body.
+     (Serialized.)  */
+  byte    hdrbytes;
+  /* The serialization format.  If 0, the default version (4) is used
+     when serializing.  (Serialized.)  */
   byte    version;
   byte    selfsigversion; /* highest version of all of the self-sigs */
-  byte    pubkey_algo;    /* algorithm used for public key scheme */
+  /* The public key algorithm.  (Serialized.)  */
+  byte    pubkey_algo;
   byte    pubkey_usage;   /* for now only used to pass it to getkey() */
   byte    req_usage;      /* hack to pass a request to getkey() */
   u32     has_expired;    /* set to the expiration date if expired */
-  u32     main_keyid[2];  /* keyid of the primary key */
-  u32     keyid[2];        /* calculated by keyid_from_pk() */
+  /* keyid of the primary key.  Never access this value directly.
+     Instead, use pk_main_keyid().  */
+  u32     main_keyid[2];
+  /* keyid of this key.  Never access this value directly!  Instead,
+     use pk_keyid().  */
+  u32     keyid[2];
   prefitem_t *prefs;      /* list of preferences (may be NULL) */
   struct
   {
@@ -310,9 +401,13 @@ typedef struct
   char    *serialno;      /* Malloced hex string or NULL if it is
                              likely not on a card.  See also
                              flags.serialno_valid.  */
-  struct seckey_info *seckey_info;  /* If not NULL this malloced
-                                       structure describes a secret
-                                       key.  */
+  /* If not NULL this malloced structure describes a secret key.
+     (Serialized.)  */
+  struct seckey_info *seckey_info;
+  /* The public key.  Contains pubkey_get_npkey (pubkey_algo) +
+     pubkey_get_nskey (pubkey_algo) MPIs.  (If pubkey_get_npkey
+     returns 0, then the algorithm is not understood and the PKEY
+     contains a single opaque MPI.)  (Serialized.)  */
   gcry_mpi_t  pkey[PUBKEY_MAX_NSKEY]; /* Right, NSKEY elements.  */
 } PKT_public_key;
 
@@ -328,20 +423,46 @@ typedef struct {
     char data[1];
 } PKT_comment;
 
+/* A compression packet (RFC 4880, Section 5.6).  */
 typedef struct {
-    u32  len;            /* reserved */
-    byte  new_ctb;
-    byte  algorithm;
-    iobuf_t buf;         /* IOBUF reference */
+  /* Not used.  */
+  u32 len;
+  /* Whether the serialized version of the packet used / should use
+     the new format.  */
+  byte  new_ctb;
+  /* The compression algorithm.  */
+  byte  algorithm;
+  /* An iobuf holding the data to be decompressed.  (This is not used
+     for compression!)  */
+  iobuf_t buf;
 } PKT_compressed;
 
+/* A symmetrically encrypted data packet (RFC 4880, Section 5.7) or a
+   symmetrically encrypted integrity protected data packet (Section
+   5.13) */
 typedef struct {
-    u32  len;            /* Remaining length of encrypted data. */
-    int  extralen;        /* This is (blocksize+2).  Used by build_packet. */
-    byte new_ctb;        /* uses a new CTB */
-    byte is_partial;      /* partial length encoded */
-    byte mdc_method;     /* > 0: integrity protected encrypted data packet */
-    iobuf_t buf;         /* IOBUF reference */
+  /* Remaining length of encrypted data. */
+  u32  len;
+  /* When encrypting, the first block size bytes of data are random
+     data and the following 2 bytes are copies of the last two bytes
+     of the random data (RFC 4880, Section 5.7).  This provides a
+     simple check that the key is correct.  extralen is the size of
+     this extra data.  This is used by build_packet when writing out
+     the packet's header. */
+  int  extralen;
+  /* Whether the serialized version of the packet used / should use
+     the new format.  */
+  byte new_ctb;
+  /* Whether the packet has an indeterminate length (old format) or
+     was encoded using partial body length headers (new format).
+     Note: this is ignored when encrypting.  */
+  byte is_partial;
+  /* If 0, MDC is disabled.  Otherwise, the MDC method that was used
+     (currently, only DIGEST_ALGO_SHA1 is supported).  */
+  byte mdc_method;
+  /* An iobuf holding the data to be decrypted.  (This is not used for
+     encryption!)  */
+  iobuf_t buf;
 } PKT_encrypted;
 
 typedef struct {
@@ -353,15 +474,22 @@ typedef struct {
     unsigned int sigcache;
 } PKT_ring_trust;
 
+/* A plaintext packet (see RFC 4880, 5.9).  */
 typedef struct {
-    u32  len;            /* length of encrypted data */
-    iobuf_t buf;         /* IOBUF reference */
-    byte new_ctb;
-    byte is_partial;      /* partial length encoded */
-    int mode;
-    u32 timestamp;
-    int  namelen;
-    char name[1];
+  /* The length of data in BUF or 0 if unknown.  */
+  u32  len;
+  /* A buffer containing the data stored in the packet's body.  */
+  iobuf_t buf;
+  byte new_ctb;
+  byte is_partial;      /* partial length encoded */
+  /* The data's formatting.  This is either 'b', 't', 'u', 'l' or '1'
+     (however, the last two are deprecated).  */
+  int mode;
+  u32 timestamp;
+  /* The name of the file.  This can be at most 255 characters long,
+     since namelen is just a byte in the serialized format.  */
+  int  namelen;
+  char name[1];
 } PKT_plaintext;
 
 typedef struct {
@@ -397,18 +525,38 @@ struct packet_struct {
                       } while(0)
 
 
+/* A notation.  See RFC 4880, Section 5.2.3.16.  */
 struct notation
 {
+  /* The notation's name.  */
   char *name;
+  /* If the notation is human readable, then the value is stored here
+     as a NUL-terminated string.  */
   char *value;
+  /* Sometimes we want to %-expand the value.  In these cases, we save
+     that transformed value here.  */
   char *altvalue;
+  /* If the notation is not human readable, then the value is strored
+     here.  */
   unsigned char *bdat;
+  /* The amount of data stored in BDAT.
+
+     Note: if this is 0 and BDAT is NULL, this does not necessarily
+     mean that the value is human readable.  It could be that we have
+     a 0-length value.  To determine whether the notation is human
+     readable, always check if VALUE is not NULL.  This works, because
+     if a human-readable value has a length of 0, we will still
+     allocate space for the NUL byte.  */
   size_t blen;
   struct
   {
+    /* The notation is critical.  */
     unsigned int critical:1;
+    /* The notation should be deleted.  */
     unsigned int ignore:1;
   } flags;
+
+  /* A field to facilitate creating a list of notations.  */
   struct notation *next;
 };
 
@@ -615,6 +763,8 @@ void build_attribute_subpkt(PKT_user_id *uid,byte type,
                            const void *buf,u32 buflen,
                            const void *header,u32 headerlen);
 struct notation *string_to_notation(const char *string,int is_utf8);
+struct notation *blob_to_notation(const char *name,
+                                  const char *data, size_t len);
 struct notation *sig_to_notation(PKT_signature *sig);
 void free_notation(struct notation *notation);
 
index 38cd8c9..c77e409 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -487,7 +486,7 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
   off_t pos;
 
   *skip = 0;
-  assert (!pkt->pkt.generic);
+  log_assert (!pkt->pkt.generic);
   if (retpos || list_mode)
     {
       pos = iobuf_tell (inp);
@@ -581,7 +580,7 @@ parse (IOBUF inp, PACKET * pkt, int onlykeypkts, off_t * retpos,
             case PKT_ENCRYPTED:
             case PKT_ENCRYPTED_MDC:
             case PKT_COMPRESSED:
-              iobuf_set_partial_block_mode (inp, c & 0xff);
+              iobuf_set_partial_body_length_mode (inp, c & 0xff);
               pktlen = 0;      /* To indicate partial length.  */
               partial = 1;
               break;
@@ -1114,7 +1113,7 @@ parse_symkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
        log_info (_("WARNING: potentially insecure symmetrically"
                    " encrypted session key\n"));
     }
-  assert (!pktlen);
+  log_assert (!pktlen);
 
   if (list_mode)
     {
@@ -1668,7 +1667,7 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
     }
   if (reqtype == SIGSUBPKT_TEST_CRITICAL)
     /* Returning NULL means we found a subpacket with the critical bit
-       set that we dn't grok.  We've iterated over all the subpackets
+       set that we don't grok.  We've iterated over all the subpackets
        and haven't found such a packet so we need to return a non-NULL
        value.  */
     return buffer;
@@ -2421,7 +2420,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
           * NOTE: if you change the ivlen above 16, don't forget to
           * enlarge temp.  */
          ski->ivlen = openpgp_cipher_blocklen (ski->algo);
-         assert (ski->ivlen <= sizeof (temp));
+         log_assert (ski->ivlen <= sizeof (temp));
 
          if (ski->s2k.mode == 1001)
            ski->ivlen = 0;
@@ -2660,7 +2659,7 @@ parse_user_id (IOBUF inp, int pkttype, unsigned long pktlen, PACKET * packet)
 void
 make_attribute_uidname (PKT_user_id * uid, size_t max_namelen)
 {
-  assert (max_namelen > 70);
+  log_assert (max_namelen > 70);
   if (uid->numattribs <= 0)
     sprintf (uid->name, "[bad attribute packet of size %lu]",
             uid->attrib_len);
index 5eb2562..b1d1a05 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-#include <assert.h>
 #include <errno.h>
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
@@ -425,7 +424,7 @@ passphrase_to_dek_ext (u32 *keyid, int pubkey_algo,
 
   if ( !s2k )
     {
-      assert (mode != 3 && mode != 4);
+      log_assert (mode != 3 && mode != 4);
       /* This is used for the old rfc1991 mode
        * Note: This must match the code in encode.c with opt.rfc1991 set */
       s2k = &help_s2k;
index d9ada59..de8897a 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -506,6 +505,22 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
 }
 
 
+/* Write a TRUST_foo status line inclduing the validation model.  */
+static void
+write_trust_status (int statuscode, int trustlevel)
+{
+  int tm;
+
+  /* For the combined tofu+pgp method, we return the trust model which
+   * was responsible for the trustlevel.  */
+  if (opt.trust_model == TM_TOFU_PGP)
+    tm = (trustlevel & TRUST_FLAG_TOFU_BASED)? TM_TOFU : TM_PGP;
+  else
+    tm = opt.trust_model;
+  write_status_strings (statuscode, "0 ", trust_model_string (tm), NULL);
+}
+
+
 /****************
  * Check whether we can trust this signature.
  * Returns an error code if we should not trust this signature.
@@ -627,7 +642,7 @@ check_signatures_trust( PKT_signature *sig )
       /* fall thru */
     case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
-      write_status( STATUS_TRUST_UNDEFINED );
+      write_trust_status (STATUS_TRUST_UNDEFINED, trustlevel);
       log_info(_("WARNING: This key is not certified with"
                  " a trusted signature!\n"));
       log_info(_("         There is no indication that the "
@@ -637,7 +652,7 @@ check_signatures_trust( PKT_signature *sig )
 
     case TRUST_NEVER:
       /* currently we won't get that status */
-      write_status( STATUS_TRUST_NEVER );
+      write_trust_status (STATUS_TRUST_NEVER, trustlevel);
       log_info(_("WARNING: We do NOT trust this key!\n"));
       log_info(_("         The signature is probably a FORGERY.\n"));
       if (opt.with_fingerprint)
@@ -646,7 +661,7 @@ check_signatures_trust( PKT_signature *sig )
       break;
 
     case TRUST_MARGINAL:
-      write_status( STATUS_TRUST_MARGINAL );
+      write_trust_status (STATUS_TRUST_MARGINAL, trustlevel);
       log_info(_("WARNING: This key is not certified with"
                  " sufficiently trusted signatures!\n"));
       log_info(_("         It is not certain that the"
@@ -655,13 +670,13 @@ check_signatures_trust( PKT_signature *sig )
       break;
 
     case TRUST_FULLY:
-      write_status( STATUS_TRUST_FULLY );
+      write_trust_status (STATUS_TRUST_FULLY, trustlevel);
       if (opt.with_fingerprint)
         print_fingerprint (NULL, pk, 1);
       break;
 
     case TRUST_ULTIMATE:
-      write_status( STATUS_TRUST_ULTIMATE );
+      write_trust_status (STATUS_TRUST_ULTIMATE, trustlevel);
       if (opt.with_fingerprint)
         print_fingerprint (NULL, pk, 1);
       break;
index c8a5d24..232c489 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -40,9 +39,9 @@ get_mpi_from_sexp (gcry_sexp_t sexp, const char *item, int mpifmt)
   gcry_mpi_t data;
 
   list = gcry_sexp_find_token (sexp, item, 0);
-  assert (list);
+  log_assert (list);
   data = gcry_sexp_nth_mpi (list, 1, mpifmt);
-  assert (data);
+  log_assert (data);
   gcry_sexp_release (list);
   return data;
 }
index 94ede07..e118f6b 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #ifdef HAVE_DOSISH_SYSTEM
 # include <fcntl.h> /* for setmode() */
@@ -636,7 +635,7 @@ ask_for_detached_datafile (gcry_md_hd_t md, gcry_md_hd_t md2,
       if (opt.verbose)
        log_info (_("reading stdin ...\n"));
       fp = iobuf_open (NULL);
-      assert (fp);
+      log_assert (fp);
     }
   do_hash (md, md2, fp, textmode);
   iobuf_close (fp);
index f4b4698..21810a4 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <config.h>
 #include <stdio.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "iobuf.h"
@@ -64,7 +63,7 @@ release_progress_context (progress_filter_context_t *pfx)
 {
   if (!pfx)
     return;
-  assert (pfx->refcount);
+  log_assert (pfx->refcount);
   if ( --pfx->refcount )
     return;
   xfree (pfx->what);
@@ -143,8 +142,8 @@ handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
   if (!pfx)
     return;
 
-  assert (opt.enable_progress_filter);
-  assert (is_status_enabled ());
+  log_assert (opt.enable_progress_filter);
+  log_assert (is_status_enabled ());
 
   if ( !iobuf_is_pipe_filename (name) && *name )
     filesize = iobuf_get_filelength (inp, NULL);
index 23a4473..0df9bfa 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -197,7 +196,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
   if (sk->pubkey_algo == PUBKEY_ALGO_ECDH)
     {
       fingerprint_from_pk (sk, fp, &fpn);
-      assert (fpn == 20);
+      log_assert (fpn == 20);
     }
 
   /* Decrypt. */
@@ -267,7 +266,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
           goto leave;
         }
       nframe -= frame[nframe-1]; /* Remove padding.  */
-      assert (!n); /* (used just below) */
+      log_assert (!n); /* (used just below) */
     }
   else
     {
index a8f7658..3c6e158 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <ctype.h>
 
 #include "gpg.h"
index 02dbb48..f61d21b 100644 (file)
@@ -24,7 +24,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
index 31e35a9..9ec263f 100644 (file)
@@ -32,6 +32,7 @@
 #include "util.h"
 #include "i18n.h"
 #include "options.h"
+#include "../common/server-help.h"
 #include "../common/sysutils.h"
 #include "status.h"
 
@@ -68,40 +69,6 @@ close_message_fd (ctrl_t ctrl)
     }
 }
 
-
-/* Skip over options.  Blanks after the options are also removed.  */
-static char *
-skip_options (const char *line)
-{
-  while (spacep (line))
-    line++;
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return (char*)line;
-}
-
-
-/* Check whether the option NAME appears in LINE.  */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return 0;
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-
-
-
 \f
 /* Called by libassuan for Assuan options.  See the Assuan manual for
    details. */
index e79faf8..c41a145 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
 #include "i18n.h"
 
 
-/****************
- * Make a session key and put it into DEK
- */
+/* Generate a new session key in *DEK that is appropriate for the
+ * algorithm DEK->ALGO (i.e., ensure that the key is not weak).
+ *
+ * This function overwrites DEK->KEYLEN, DEK->KEY.  The rest of the
+ * fields are left as is.  */
 void
 make_session_key( DEK *dek )
 {
@@ -67,11 +68,12 @@ make_session_key( DEK *dek )
 }
 
 
-/****************
- * Encode the session key. NBITS is the number of bits which should be used
- * for packing the session key.
- * returns: A mpi with the session key (caller must free)
- */
+/* Encode the session key stored in DEK as an MPI in preparation to
+ * encrypt it with the public key algorithm OPENPGP_PK_ALGO with a key
+ * whose length (the size of the public key) is NBITS.
+ *
+ * On success, returns an MPI, which the caller must free using
+ * gcry_mpi_release().  */
 gcry_mpi_t
 encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
 {
@@ -103,7 +105,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
                   + 7 ) & (~7));
 
       /* alg+key+csum fit and the size is congruent to 8.  */
-      assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 );
+      log_assert (!(nframe%8) && nframe > 1 + dek->keylen + 2 );
 
       frame = xmalloc_secure (nframe);
       n = 0;
@@ -114,7 +116,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
       frame[n++] = csum;
       i = nframe - n;         /* Number of padded bytes.  */
       memset (frame+n, i, i); /* Use it as the value of each padded byte.  */
-      assert (n+i == nframe);
+      log_assert (n+i == nframe);
 
       if (DBG_CRYPTO)
         log_debug ("encode_session_key: "
@@ -136,14 +138,15 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
     log_bug ("can't encode a %d bit key in a %d bits frame\n",
              dek->keylen*8, nbits );
 
-  /* We encode the session key in this way:
+  /* We encode the session key according to PKCS#1 v1.5 (see section
+   * 13.1.1 of RFC 4880):
    *
-   *      0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
+   *      0  2  RND(i bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
    *
    * (But how can we store the leading 0 - the external representaion
    *  of MPIs doesn't allow leading zeroes =:-)
    *
-   * RND are non-zero random bytes.
+   * RND are (at least 1) non-zero random bytes.
    * A   is the cipher algorithm
    * DEK is the encryption key (session key) length k depends on the
    *      cipher algorithm (20 is used with blowfish160).
@@ -154,8 +157,10 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
   n = 0;
   frame[n++] = 0;
   frame[n++] = 2;
+  /* The number of random bytes are the number of otherwise unused
+     bytes.  See diagram above.  */
   i = nframe - 6 - dek->keylen;
-  assert( i > 0 );
+  log_assert( i > 0 );
   p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
   /* Replace zero bytes by new values.  */
   for (;;)
@@ -189,7 +194,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
   n += dek->keylen;
   frame[n++] = csum >>8;
   frame[n++] = csum;
-  assert (n == nframe);
+  log_assert (n == nframe);
   if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe))
     BUG();
   xfree (frame);
@@ -221,12 +226,12 @@ do_encode_md( gcry_md_hd_t md, int algo, size_t len, unsigned nbits,
     frame[n++] = 0;
     frame[n++] = 1; /* block type */
     i = nframe - len - asnlen -3 ;
-    assert( i > 1 );
+    log_assert( i > 1 );
     memset( frame+n, 0xff, i ); n += i;
     frame[n++] = 0;
     memcpy( frame+n, asn, asnlen ); n += asnlen;
     memcpy( frame+n, gcry_md_read (md, algo), len ); n += len;
-    assert( n == nframe );
+    log_assert( n == nframe );
 
     if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, n, &nframe ))
        BUG();
@@ -257,8 +262,8 @@ encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo)
   gcry_mpi_t frame;
   size_t mdlen;
 
-  assert (hash_algo);
-  assert (pk);
+  log_assert (hash_algo);
+  log_assert (pk);
 
   if (pk->pubkey_algo == PUBKEY_ALGO_EDDSA)
     {
index 292adb9..290f19a 100644 (file)
@@ -1,7 +1,7 @@
 /* sig-check.c -  Check a signature
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
  *               2004, 2006 Free Software Foundation, Inc.
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -23,7 +23,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -40,6 +39,9 @@ static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
                                int *r_expired, int *r_revoked,
                                PKT_public_key *ret_pk);
 
+static int check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
+                                       gcry_md_hd_t digest);
+
 /* Check a signature.  This is shorthand for check_signature2 with
    the unnamed arguments passed as NULL.  */
 int
@@ -376,14 +378,32 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
                     gcry_md_hd_t digest,
                     int *r_expired, int *r_revoked, PKT_public_key *ret_pk)
 {
-    gcry_mpi_t result = NULL;
     int rc = 0;
-    const struct weakhash *weak;
 
     if ((rc = check_signature_metadata_validity (pk, sig,
                                                 r_expired, r_revoked)))
         return rc;
 
+    if ((rc = check_signature_end_simple (pk, sig, digest)))
+      return rc;
+
+    if(!rc && ret_pk)
+      copy_public_key(ret_pk,pk);
+
+    return rc;
+}
+
+/* This function is similar to check_signature_end, but it only checks
+   whether the signature was generated by PK.  It does not check
+   expiration, revocation, etc.  */
+static int
+check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
+                            gcry_md_hd_t digest)
+{
+    gcry_mpi_t result = NULL;
+    int rc = 0;
+    const struct weakhash *weak;
+
     if (!opt.flags.allow_weak_digest_algos)
       for (weak = opt.weak_digests; weak; weak = weak->next)
         if (sig->digest_algo == weak->algo)
@@ -453,9 +473,6 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
        rc = GPG_ERR_BAD_SIGNATURE;
       }
 
-    if(!rc && ret_pk)
-      copy_public_key(ret_pk,pk);
-
     return rc;
 }
 
@@ -463,11 +480,8 @@ check_signature_end (PKT_public_key *pk, PKT_signature *sig,
 /* Add a uid node to a hash context.  See section 5.2.4, paragraph 4
    of RFC 4880.  */
 static void
-hash_uid_node( KBNODE unode, gcry_md_hd_t md, PKT_signature *sig )
+hash_uid_packet (PKT_user_id *uid, gcry_md_hd_t md, PKT_signature *sig )
 {
-    PKT_user_id *uid = unode->pkt->pkt.user_id;
-
-    assert( unode->pkt->pkttype == PKT_USER_ID );
     if( uid->attrib_data ) {
        if( sig->version >=4 ) {
            byte buf[5];
@@ -548,8 +562,8 @@ check_revocation_keys (PKT_public_key *pk, PKT_signature *sig)
   int i;
   int rc = GPG_ERR_GENERAL;
 
-  assert(IS_KEY_REV(sig));
-  assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
+  log_assert (IS_KEY_REV(sig));
+  log_assert ((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
 
   /* Avoid infinite recursion.  Consider the following:
    *
@@ -673,6 +687,232 @@ check_key_signature (KBNODE root, KBNODE node, int *is_selfsig)
 }
 
 
+/* Returns whether SIGNER generated the signature SIG over the packet
+   PACKET, which is a key, subkey or uid, and comes from the key block
+   KB.  (KB is PACKET's corresponding keyblock; we don't assume that
+   SIG has been added to the keyblock.)
+
+   If SIGNER is set, then checks whether SIGNER generated the
+   signature.  Otherwise, uses SIG->KEYID to find the alleged signer.
+   This parameter can be used to effectively override the alleged
+   signer that is stored in SIG.
+
+   KB may be NULL if SIGNER is set.
+
+   Unlike check_key_signature, this function ignores any cached
+   results!  That is, it does not consider SIG->FLAGS.CHECKED and
+   SIG->FLAGS.VALID nor does it set them.
+
+   This doesn't check the signature's semantic mean.  Concretely, it
+   doesn't check whether a non-self signed revocation signature was
+   created by a designated revoker.  In fact, it doesn't return an
+   error for a binding generated by a completely different key!
+
+   Returns 0 if the signature is valid.  Returns GPG_ERR_SIG_CLASS if
+   this signature can't be over PACKET.  Returns GPG_ERR_NOT_FOUND if
+   the key that generated the signature (according to SIG) could not
+   be found.  Returns GPG_ERR_BAD_SIGNATURE if the signature is bad.
+   Other errors codes may be returned if something else goes wrong.
+
+   IF IS_SELFSIG is not NULL, sets *IS_SELFSIG to 1 if this is a
+   self-signature (by the key's primary key) or 0 if not.
+
+   If RET_PK is not NULL, returns a copy of the public key that
+   generated the signature (i.e., the signer) on success.  This must
+   be released by the caller using release_public_key_parts ().  */
+gpg_error_t
+check_signature_over_key_or_uid (PKT_public_key *signer,
+                                 PKT_signature *sig, KBNODE kb, PACKET *packet,
+                                 int *is_selfsig, PKT_public_key *ret_pk)
+{
+  int rc;
+  PKT_public_key *pripk = kb->pkt->pkt.public_key;
+  gcry_md_hd_t md;
+  int signer_alloced = 0;
+
+  rc = openpgp_pk_test_algo (sig->pubkey_algo);
+  if (rc)
+    return rc;
+  rc = openpgp_md_test_algo (sig->digest_algo);
+  if (rc)
+    return rc;
+
+  /* A signature's class indicates the type of packet that it
+     signs.  */
+  if (/* Primary key binding (made by a subkey).  */
+      sig->sig_class == 0x19
+      /* Direct key signature.  */
+      || sig->sig_class == 0x1f
+      /* Primary key revocation.  */
+      || sig->sig_class == 0x20)
+    {
+      if (packet->pkttype != PKT_PUBLIC_KEY)
+        /* Key revocations can only be over primary keys.  */
+        return gpg_error (GPG_ERR_SIG_CLASS);
+    }
+  else if (/* Subkey binding.  */
+           sig->sig_class == 0x18
+           /* Subkey revocation.  */
+           || sig->sig_class == 0x28)
+    {
+      if (packet->pkttype != PKT_PUBLIC_SUBKEY)
+        return gpg_error (GPG_ERR_SIG_CLASS);
+    }
+  else if (/* Certification.  */
+           sig->sig_class == 0x10
+           || sig->sig_class == 0x11
+           || sig->sig_class == 0x12
+           || sig->sig_class == 0x13
+           /* Certification revocation.  */
+           || sig->sig_class == 0x30)
+    {
+      if (packet->pkttype != PKT_USER_ID)
+        return gpg_error (GPG_ERR_SIG_CLASS);
+    }
+  else
+    return gpg_error (GPG_ERR_SIG_CLASS);
+
+  /* PACKET is the right type for SIG.  */
+
+  if (signer)
+    {
+      if (is_selfsig)
+        {
+          if (signer->keyid[0] == pripk->keyid[0]
+              && signer->keyid[1] == pripk->keyid[1])
+            *is_selfsig = 1;
+          else
+            *is_selfsig = 0;
+        }
+    }
+  else
+    {
+      /* Get the signer.  If possible, avoid a look up.  */
+      if (sig->keyid[0] == pripk->keyid[0]
+          && sig->keyid[1] == pripk->keyid[1])
+        /* Issued by the primary key.  */
+        {
+          signer = pripk;
+          if (is_selfsig)
+            *is_selfsig = 1;
+        }
+      else
+        /* See if one of the subkeys was the signer (although this is
+           extremely unlikely).  */
+        {
+          kbnode_t ctx = NULL;
+          kbnode_t n;
+
+          while ((n = walk_kbnode (kb, &ctx, PKT_PUBLIC_SUBKEY)))
+            {
+              PKT_public_key *subk = n->pkt->pkt.public_key;
+              if (sig->keyid[0] == subk->keyid[0]
+                  && sig->keyid[1] == subk->keyid[1])
+                /* Issued by a subkey.  */
+                {
+                  signer = subk;
+                  break;
+                }
+            }
+
+          if (! signer)
+            /* Signer by some other key.  */
+            {
+              if (is_selfsig)
+                *is_selfsig = 0;
+              if (ret_pk)
+                {
+                  signer = ret_pk;
+                  memset (signer, 0, sizeof (*signer));
+                  signer_alloced = 1;
+                }
+              else
+                {
+                  signer = xmalloc_clear (sizeof (*signer));
+                  signer_alloced = 2;
+                }
+
+              rc = get_pubkey (signer, sig->keyid);
+              if (rc)
+                {
+                  xfree (signer);
+                  signer = NULL;
+                  signer_alloced = 0;
+                  goto out;
+                }
+            }
+        }
+    }
+
+  /* We checked above that we supported this algo, so an error here is
+     a bug.  */
+  if (gcry_md_open (&md, sig->digest_algo, 0))
+    BUG ();
+
+  /* Hash the relevant data.  */
+
+  if (/* Direct key signature.  */
+      sig->sig_class == 0x1f
+      /* Primary key revocation.  */
+      || sig->sig_class == 0x20)
+    {
+      log_assert (packet->pkttype == PKT_PUBLIC_KEY);
+      hash_public_key (md, packet->pkt.public_key);
+      rc = check_signature_end_simple (signer, sig, md);
+    }
+  else if (/* Primary key binding (made by a subkey).  */
+      sig->sig_class == 0x19)
+    {
+      log_assert (packet->pkttype == PKT_PUBLIC_KEY);
+      hash_public_key (md, packet->pkt.public_key);
+      hash_public_key (md, signer);
+      rc = check_signature_end_simple (signer, sig, md);
+    }
+  else if (/* Subkey binding.  */
+           sig->sig_class == 0x18
+           /* Subkey revocation.  */
+           || sig->sig_class == 0x28)
+    {
+      log_assert (packet->pkttype == PKT_PUBLIC_SUBKEY);
+      hash_public_key (md, pripk);
+      hash_public_key (md, packet->pkt.public_key);
+      rc = check_signature_end_simple (signer, sig, md);
+    }
+  else if (/* Certification.  */
+           sig->sig_class == 0x10
+           || sig->sig_class == 0x11
+           || sig->sig_class == 0x12
+           || sig->sig_class == 0x13
+           /* Certification revocation.  */
+           || sig->sig_class == 0x30)
+    {
+      log_assert (packet->pkttype == PKT_USER_ID);
+      hash_public_key (md, pripk);
+      hash_uid_packet (packet->pkt.user_id, md, sig);
+      rc = check_signature_end_simple (signer, sig, md);
+    }
+  else
+    /* We should never get here.  (The first if above should have
+       already caught this error.)  */
+    BUG ();
+
+  gcry_md_close (md);
+
+ out:
+  if (! rc && ret_pk && (signer_alloced == -1 || ret_pk != signer))
+    copy_public_key (ret_pk, signer);
+  if (signer_alloced == 1)
+    /* We looked up SIGNER; it is not a pointer into KB.  */
+    {
+      release_public_key_parts (signer);
+      if (signer_alloced == 2)
+        /* We also allocated the memory.  */
+        xfree (signer);
+    }
+
+  return rc;
+}
+
 /* Check that a signature over a key (e.g., a key revocation, key
  * binding, user id certification, etc.) is valid.  If the function
  * detects a self-signature, it uses the public key from the specified
@@ -712,7 +952,6 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
                       PKT_public_key *ret_pk, int *is_selfsig,
                       u32 *r_expiredate, int *r_expired )
 {
-  gcry_md_hd_t md;
   PKT_public_key *pk;
   PKT_signature *sig;
   int algo;
@@ -724,8 +963,8 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
     *r_expiredate = 0;
   if (r_expired)
     *r_expired = 0;
-  assert (node->pkt->pkttype == PKT_SIGNATURE);
-  assert (root->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (node->pkt->pkttype == PKT_SIGNATURE);
+  log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY);
 
   pk = root->pkt->pkt.public_key;
   sig = node->pkt->pkt.signature;
@@ -773,114 +1012,69 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
         rc = check_revocation_keys (pk, sig);
       else
         {
-          if (gcry_md_open (&md, algo, 0))
-            BUG ();
-          hash_public_key (md, pk);
-          rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
-          cache_sig_result (sig, rc);
-          gcry_md_close (md);
+          rc = check_signature_metadata_validity (pk, sig,
+                                                  r_expired, NULL);
+          if (! rc)
+            rc = check_signature_over_key_or_uid (pk, sig, root, root->pkt,
+                                                  is_selfsig, ret_pk);
         }
     }
-  else if (sig->sig_class == 0x28) /* subkey revocation */
+  else if (sig->sig_class == 0x28  /* subkey revocation */
+           || sig->sig_class == 0x18) /* key binding */
     {
       kbnode_t snode = find_prev_kbnode (root, node, PKT_PUBLIC_SUBKEY);
 
       if (snode)
         {
-          if (gcry_md_open (&md, algo, 0))
-            BUG ();
-          hash_public_key (md, pk);
-          hash_public_key (md, snode->pkt->pkt.public_key);
-          rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
-          cache_sig_result (sig, rc);
-          gcry_md_close (md);
+          rc = check_signature_metadata_validity (pk, sig,
+                                                  r_expired, NULL);
+          if (! rc)
+            /* 0x28 must be a self-sig, but 0x18 needn't be.  */
+            rc = check_signature_over_key_or_uid (sig->sig_class == 0x18
+                                                  ? NULL : pk,
+                                                  sig, root, snode->pkt,
+                                                  is_selfsig, ret_pk);
        }
       else
         {
           if (opt.verbose)
-            log_info (_("key %s: no subkey for subkey"
-                        " revocation signature\n"), keystr_from_pk(pk));
+            {
+              if (sig->sig_class == 0x28)
+                log_info (_("key %s: no subkey for subkey"
+                            " revocation signature\n"), keystr_from_pk(pk));
+              else if (sig->sig_class == 0x18)
+                log_info(_("key %s: no subkey for subkey"
+                           " binding signature\n"), keystr_from_pk(pk));
+            }
           rc = GPG_ERR_SIG_CLASS;
         }
     }
-    else if (sig->sig_class == 0x18) /* key binding */
-      {
-       kbnode_t snode = find_prev_kbnode (root, node, PKT_PUBLIC_SUBKEY);
-
-       if (snode)
-          {
-           if (is_selfsig)
-              {
-                /* Does this make sense?  It should always be a
-                   selfsig.  Yes: We can't be sure about this and we
-                   need to be able to indicate that it is a selfsig.
-                   FIXME: The question is whether we should reject
-                   such a signature if it is not a selfsig.  */
-               u32 keyid[2];
-
-               keyid_from_pk (pk, keyid);
-               if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
-                  *is_selfsig = 1;
-              }
-           if (gcry_md_open (&md, algo, 0))
-              BUG ();
-           hash_public_key (md, pk);
-           hash_public_key (md, snode->pkt->pkt.public_key);
-           rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
-            cache_sig_result ( sig, rc );
-           gcry_md_close (md);
-          }
-       else
-         {
-            if (opt.verbose)
-             log_info(_("key %s: no subkey for subkey"
-                        " binding signature\n"), keystr_from_pk(pk));
-           rc = GPG_ERR_SIG_CLASS;
-         }
-      }
     else if (sig->sig_class == 0x1f) /* direct key signature */
       {
-        if (gcry_md_open (&md, algo, 0 ))
-          BUG ();
-       hash_public_key( md, pk );
-       rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
-        cache_sig_result (sig, rc);
-       gcry_md_close (md);
+        rc = check_signature_metadata_validity (pk, sig,
+                                                r_expired, NULL);
+        if (! rc)
+          rc = check_signature_over_key_or_uid (pk, sig, root, root->pkt,
+                                                is_selfsig, ret_pk);
       }
-    else /* all other classes */
+    else if (/* Certification.  */
+             sig->sig_class == 0x10
+             || sig->sig_class == 0x11
+             || sig->sig_class == 0x12
+             || sig->sig_class == 0x13
+             /* Certification revocation.  */
+             || sig->sig_class == 0x30)
       {
        kbnode_t unode = find_prev_kbnode (root, node, PKT_USER_ID);
 
        if (unode)
           {
-           u32 keyid[2];
-
-           keyid_from_pk (pk, keyid);
-           if (gcry_md_open (&md, algo, 0))
-              BUG ();
-           hash_public_key (md, pk);
-           hash_uid_node (unode, md, sig);
-           if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1])
-             { /* The primary key is the signing key.  */
-
-               if (is_selfsig)
-                 *is_selfsig = 1;
-               rc = check_signature_end (pk, sig, md, r_expired, NULL, ret_pk);
-             }
-           else if (check_pk)
-              { /* The caller specified a key.  Try that.  */
-
-                rc = check_signature_end (check_pk, sig, md,
-                                          r_expired, NULL, ret_pk);
-              }
-           else
-              { /* Look up the key.  */
-                rc = check_signature2 (sig, md, r_expiredate, r_expired,
-                                       NULL, ret_pk);
-              }
-
-            cache_sig_result  (sig, rc);
-           gcry_md_close (md);
+            rc = check_signature_metadata_validity (pk, sig, r_expired, NULL);
+            if (! rc)
+              /* If this is a self-sig, ignore check_pk.  */
+              rc = check_signature_over_key_or_uid
+                (keyid_cmp (pk_keyid (pk), sig->keyid) == 0 ? pk : check_pk,
+                 sig, root, unode->pkt, NULL, ret_pk);
           }
        else
          {
@@ -890,6 +1084,16 @@ check_key_signature2 (kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
            rc = GPG_ERR_SIG_CLASS;
          }
       }
+  else
+    {
+      log_info ("sig issued by %s with class %d (digest: %02x %02x)"
+                " is not valid over a user id or a key id, ignoring.\n",
+                keystr (sig->keyid), sig->sig_class,
+                sig->digest_start[0], sig->digest_start[1]);
+      rc = gpg_error (GPG_ERR_BAD_SIGNATURE);
+    }
+
+  cache_sig_result  (sig, rc);
 
   return rc;
 }
index c3ae028..364634a 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -66,7 +65,7 @@ mk_notation_policy_etc (PKT_signature *sig,
     struct notation *nd=NULL;
     struct expando_args args;
 
-    assert(sig->version>=4);
+    log_assert(sig->version>=4);
 
     memset(&args,0,sizeof(args));
     args.pk=pk;
@@ -1143,7 +1142,7 @@ clearsign_file (ctrl_t ctrl,
                }
            }
        }
-       assert(any);
+       log_assert(any);
        iobuf_writestr(out, LF );
     }
 
@@ -1377,9 +1376,9 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
     int sigversion;
     gcry_md_hd_t md;
 
-    assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
-           || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19
-           || sigclass == 0x30 || sigclass == 0x28 );
+    log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
+                || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x19
+                || sigclass == 0x30 || sigclass == 0x28 );
 
     sigversion = 4;
     if (sigversion < pksk->version)
index 1eb0633..4cd7f33 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
index 599a3ef..90490c2 100644 (file)
@@ -21,7 +21,6 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "util.h"
@@ -88,7 +87,7 @@ sqlite3_stepx (sqlite3 *db,
       stmt = *stmtp;
 
       /* Make sure this statement is associated with the supplied db.  */
-      assert (db == sqlite3_db_handle (stmt));
+      log_assert (db == sqlite3_db_handle (stmt));
 
 #if DEBUG_TOFU_CACHE
       prepares_saved ++;
@@ -171,7 +170,7 @@ sqlite3_stepx (sqlite3 *db,
 
     }
   t = va_arg (va, enum sqlite_arg_type);
-  assert (t == SQLITE_ARG_END);
+  log_assert (t == SQLITE_ARG_END);
   va_end (va);
 
   for (;;)
diff --git a/g10/t-stutter-data.asc b/g10/t-stutter-data.asc
new file mode 100644 (file)
index 0000000..ad8bfae
--- /dev/null
@@ -0,0 +1 @@
+É?Òéq`Hêhâ©\v\8aÅÒV½çxDI\172\12\8d\87\94O\9c¢*\12G\18û¨\97y¾Ia\1fª«l\9a{\92eîw\14ò{B\ 1»c1\87Bµ³
\ No newline at end of file
diff --git a/g10/t-stutter.c b/g10/t-stutter.c
new file mode 100644 (file)
index 0000000..9576027
--- /dev/null
@@ -0,0 +1,610 @@
+/* t-stutter.c - Test the stutter exploit.
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This test is based on the paper: "An Attack on CFB Mode Encryption
+ * as Used by OpenPGP."  This attack uses a padding oracle to decrypt
+ * the first two bytes of each block (which are normally 16 bytes
+ * large).  Concretely, if an attacker can use this attack if it can
+ * sense whether the quick integrity check failed.  See RFC 4880,
+ * Section 5.7 for an explanation of this quick check.
+ *
+ * The concrete attack, as described in the paper, only works for
+ * PKT_ENCRYPTED packets; it does not work for PKT_ENCRYPTED_MDC
+ * packets, which use a slightly different CFB mode (they don't
+ * include a sync after the IV).  But, small modifications should
+ * allow the attack to work for PKT_ENCRYPTED_MDC packets.
+ *
+ * The cost of this attack is 2^15 + i * 2^15 oracle queries, where i
+ * is the number of blocks the attack wants to decrypt.  This attack
+ * is completely unfeasible when gpg is used interactively, but it
+ * could work when used as a service.
+ *
+ * How to generate a test message:
+ *
+ *   $ echo 0123456789abcdefghijklmnopqrstuvwxyz | \
+ *         gpg --disable-mdc -z 0 -c  > msg.asc
+ *   $ gpg --list-packets msg.asc
+ *   # Make sure the encryption packet contains a literal packet (without
+ *   # any nesting).
+ *   $ gpgsplit msg.asc
+ *   $ gpg --show-session-key -d msg.asc
+ *   $ ./t-stutter --debug SESSION_KEY 000002-009.encrypted
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "gpg.h"
+#include "main.h"
+#include "../common/types.h"
+#include "util.h"
+#include "dek.h"
+#include "../common/logging.h"
+
+static void
+log_hexdump (byte *buffer, int length)
+{
+  int written = 0;
+
+  fprintf (stderr, "%d bytes:\n", length);
+  while (length > 0)
+    {
+      int have = length > 16 ? 16 : length;
+      int i;
+      char formatted[2 * have + 1];
+      char text[have + 1];
+
+      fprintf (stderr, "%-8d ", written);
+      bin2hex (buffer, have, formatted);
+      for (i = 0; i < 16; i ++)
+        {
+          if (i % 2 == 0)
+            fputc (' ', stderr);
+          if (i % 8 == 0)
+            fputc (' ', stderr);
+
+          if (i < have)
+            fwrite (&formatted[2 * i], 2, 1, stderr);
+          else
+            fwrite ("  ", 2, 1, stderr);
+        }
+
+      for (i = 0; i < have; i ++)
+        if (isprint (buffer[i]))
+          text[i] = buffer[i];
+        else
+          text[i] = '.';
+      text[i] = 0;
+
+      fprintf (stderr, "    ");
+      if (strlen (text) > 8)
+        {
+          fwrite (text, 8, 1, stderr);
+          fputc (' ', stderr);
+          fwrite (&text[8], strlen (text) - 8, 1, stderr);
+        }
+      else
+        fwrite (text, strlen (text), 1, stderr);
+      fputc ('\n', stderr);
+
+      buffer += have;
+      length -= have;
+      written += have;
+    }
+
+  return;
+}
+
+static char *
+hexstr (const byte *bytes)
+{
+  static int i;
+  static char bufs[100][7];
+
+  i ++;
+  if (i == 100)
+    i = 0;
+
+  sprintf (bufs[i], "0x%02X%02X", bytes[0], bytes[1]);
+  return bufs[i];
+}
+\f
+/* xor the two bytes starting at A with the two bytes starting at B
+   and return the result.  */
+static byte *
+bufxor2 (const byte *a, const byte *b)
+{
+  static int i;
+  static char bufs[100][2];
+
+  i ++;
+  if (i == 100)
+    i = 0;
+
+  bufs[i][0] = a[0] ^ b[0];
+  bufs[i][1] = a[1] ^ b[1];
+  return bufs[i];
+}
+\f
+/* The session key stays constant.  */
+static DEK dek;
+int blocksize;
+
+/* Decode the session key, which is in the format output by gpg
+   --show-session-key.  */
+static void
+parse_session_key (char *session_key)
+{
+  char *tail;
+  char *p = session_key;
+
+  errno = 0;
+  dek.algo = strtol (p, &tail, 10);
+  if (errno || (tail && *tail != ':'))
+    log_fatal ("Invalid session key specification.  "
+               "Expected: cipher-id:HEXADECIMAL-CHRACTERS\n");
+
+  /* Skip the ':'.  */
+  p = tail + 1;
+
+  if (strlen (p) % 2 != 0)
+    log_fatal ("Session key must consist of an even number of hexadecimal characters.\n");
+
+  dek.keylen = strlen (p) / 2;
+  log_assert (dek.keylen <= sizeof (dek.key));
+
+  if (hex2bin (p, dek.key, dek.keylen) == -1)
+    log_fatal ("Session key must only contain hexadecimal characters\n");
+
+  blocksize = openpgp_cipher_get_algo_blklen (dek.algo);
+  if ( !blocksize || blocksize > 16 )
+    log_fatal ("unsupported blocksize %u\n", blocksize );
+
+  return;
+}
+\f
+/* The ciphertext, the plaintext as decrypted by the good session key,
+   and the cfb stream (derived from the ciphertext and the
+   plaintext).  */
+static int msg_len;
+static byte *msg;
+static byte *msg_plaintext;
+static byte *msg_cfb;
+
+/* Whether we need to resynchronize the CFB after writing the random
+   data (this is the case for encrypted packets, but not encrypted and
+   integrity protected packets).  */
+static int sync;
+
+static int
+block_offset (int i)
+{
+  int extra = 0;
+
+  log_assert (i >= 1);
+  /* Make sure blocksize has been initialized.  */
+  log_assert (blocksize);
+
+  if (i > 2)
+    {
+      i -= 2;
+      extra = blocksize + 2;
+    }
+  return (i - 1) * blocksize + extra;
+}
+
+/* Return the ith block from TEXT.  The first block is labeled 1.
+   Note: consistent with the OpenPGP message format, the second block
+   (i=2) is just 2 bytes.  */
+static byte *
+block (byte *text, int len, int i)
+{
+  int offset = block_offset (i);
+
+  log_assert (offset < len);
+  return &text[offset];
+}
+\f
+/* Return true if the quick integrity check passes.  Also, if
+   PLAINTEXTP is not NULL, return the decrypted plaintext in
+   *PLAINTEXTP.  If CFBP is not NULL, return the CFB byte stream in
+   *CFBP.  */
+static int
+oracle (int debug, byte *ciphertext, int len, byte **plaintextp, byte **cfbp)
+{
+  int rc = 0;
+  unsigned nprefix;
+  gcry_cipher_hd_t cipher_hd = NULL;
+  byte *plaintext = NULL;
+  byte *cfb = NULL;
+
+  /* Make sure DEK was initialized.  */
+  log_assert (dek.algo);
+  log_assert (dek.keylen);
+  log_assert (blocksize);
+
+  nprefix = blocksize;
+  if (len < nprefix + 2)
+    {
+       /* An invalid message.  We can't check that during parsing
+          because we may not know the used cipher then.  */
+      rc = gpg_error (GPG_ERR_INV_PACKET);
+      goto leave;
+    }
+
+  rc = openpgp_cipher_open (&cipher_hd, dek.algo,
+                           GCRY_CIPHER_MODE_CFB,
+                           (! sync /* ed->mdc_method || dek.algo >= 100 */ ?
+                             0 : GCRY_CIPHER_ENABLE_SYNC));
+  if (rc)
+    log_fatal ("Failed to open cipher: %s\n", gpg_strerror (rc));
+
+  rc = gcry_cipher_setkey (cipher_hd, dek.key, dek.keylen);
+  if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
+    {
+      log_info ("WARNING: message was encrypted with"
+                " a weak key in the symmetric cipher.\n");
+      rc=0;
+    }
+  else if( rc )
+    log_fatal ("key setup failed: %s\n", gpg_strerror (rc));
+
+  gcry_cipher_setiv (cipher_hd, NULL, 0);
+
+  if (debug)
+    {
+      log_debug ("Encrypted data:\n");
+      log_hexdump(ciphertext, len);
+    }
+  plaintext = xmalloc_clear (len);
+  gcry_cipher_decrypt (cipher_hd, plaintext, blocksize + 2,
+                       ciphertext, blocksize + 2);
+  gcry_cipher_sync (cipher_hd);
+  if (len > blocksize+2)
+    gcry_cipher_decrypt (cipher_hd,
+                         &plaintext[blocksize+2], len-(blocksize+2),
+                         &ciphertext[blocksize+2], len-(blocksize+2));
+
+  if (debug)
+    {
+      log_debug ("Decrypted data:\n");
+      log_hexdump (plaintext, len);
+      log_debug ("R_{b-1,b} = %s\n", hexstr (&plaintext[blocksize - 2]));
+      log_debug ("R_{b+1,b+2} = %s\n", hexstr (&plaintext[blocksize]));
+    }
+
+  if (cfbp || debug)
+    {
+      int i;
+      cfb = xmalloc (len);
+      for (i = 0; i < len; i ++)
+        cfb[i] = plaintext[i] ^ ciphertext[i];
+
+      log_assert (len >= blocksize + 2);
+
+      if (debug)
+        {
+          log_debug ("cfb:\n");
+          log_hexdump (cfb, len);
+
+          log_debug ("E_k([C_1]_{1,2}) = C_2 xor R (%s xor %s) = %s\n",
+                    hexstr (&ciphertext[blocksize]),
+                    hexstr (&plaintext[blocksize]),
+                    hexstr (bufxor2 (&ciphertext[blocksize],
+                                     &plaintext[blocksize])));
+          if (len >= blocksize + 4)
+            log_debug ("D = Ek([C1]_{3-b} || C_2)_{1-2} (%s) xor C2 (%s) xor E_k(0)_{b-1,b} (%s) = %s\n",
+                       hexstr (&cfb[blocksize + 2]),
+                       hexstr (&ciphertext[blocksize]),
+                       hexstr (&cfb[blocksize - 2]),
+                       hexstr (bufxor2 (bufxor2 (&cfb[blocksize + 2],
+                                                 &ciphertext[blocksize]),
+                                        &cfb[blocksize - 2])));
+        }
+    }
+
+  if (plaintext[nprefix-2] != plaintext[nprefix]
+      || plaintext[nprefix-1] != plaintext[nprefix+1])
+    {
+      rc = gpg_error (GPG_ERR_BAD_KEY);
+      goto leave;
+    }
+
+ leave:
+  if (! rc && plaintextp)
+    *plaintextp = plaintext;
+  else
+    xfree (plaintext);
+
+  if (! rc && cfbp)
+    *cfbp = cfb;
+  else
+    xfree (cfb);
+
+  if (cipher_hd)
+    gcry_cipher_close (cipher_hd);
+  return rc;
+}
+
+/* Query the oracle with D=D for block B.  */
+static int
+oracle_test (unsigned int d, int b, int debug)
+{
+  byte probe[blocksize + 2];
+
+  log_assert (d < 256 * 256);
+
+  if (b == 1)
+    memcpy (probe, &msg[2], blocksize);
+  else
+    memcpy (probe, block (msg, msg_len, b), blocksize);
+
+  probe[blocksize] = d >> 8;
+  probe[blocksize + 1] = d & 0xff;
+
+  if (debug)
+    log_debug ("oracle (0x%04X):\n", d);
+
+  return oracle (debug, probe, blocksize + 2, NULL, NULL) == 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int i;
+  int debug = 0;
+  char *filename = NULL;
+  int help = 0;
+
+  byte *raw_data;
+  int raw_data_len;
+
+  int failed = 0;
+
+  for (i = 1; i < argc; i ++)
+    {
+      if (strcmp (argv[i], "--debug") == 0)
+        debug = 1;
+      else if (! blocksize)
+        parse_session_key (argv[i]);
+      else if (! filename)
+        filename = argv[i];
+      else
+        {
+          help = 1;
+          break;
+        }
+    }
+
+  if (! blocksize && ! filename && (filename = getenv ("srcdir")))
+    /* Try defaults.  */
+    {
+      parse_session_key ("9:9274A8EC128E850C6DDDF9EAC68BFA84FC7BC05F340DA41D78C93D0640C7C503");
+      filename = xasprintf ("%s/t-stutter-data.asc", filename);
+    }
+
+  if (help || ! blocksize || ! filename)
+    log_fatal ("Usage: %s [--debug] SESSION_KEY ENCRYPTED_PKT\n", argv[0]);
+
+  /* Don't read more than a KB.  */
+  raw_data_len = 1024;
+  raw_data = xmalloc (raw_data_len);
+
+  {
+    FILE *fp;
+    int r;
+
+    fp = fopen (filename, "r");
+    if (! fp)
+      log_fatal ("Opening %s: %s\n", filename, strerror (errno));
+    r = fread (raw_data, 1, raw_data_len, fp);
+    fclose (fp);
+
+    /* We need at least the random data, the encrypted and literal
+       packets' headers and some body.  */
+    if (r < (blocksize + 2 /* Random data.  */
+             + 2 * blocksize /* Header + some plaintext.  */))
+      log_fatal ("Not enough data (need at least %d bytes of plain text): %s.\n",
+                 blocksize + 2, strerror (errno));
+    raw_data_len = r;
+
+    if (debug)
+      {
+        log_debug ("First few bytes of the raw data:\n");
+        log_hexdump (raw_data, raw_data_len > 8 ? 8 : raw_data_len);
+      }
+  }
+
+  /* Parse the packet's header.  */
+  {
+    int ctb = raw_data[0];
+    int new_format = ctb & (1 << 7);
+    int pkttype = (ctb & ((1 << 5) - 1)) >> (new_format ? 0 : 2);
+    int hdrlen;
+
+    if (new_format)
+      {
+        if (debug)
+          log_debug ("len encoded: 0x%x (%d)\n", raw_data[1], raw_data[1]);
+        if (raw_data[1] < 192)
+          hdrlen = 2;
+        else if (raw_data[1] < 224)
+          hdrlen = 3;
+        else if (raw_data[1] == 255)
+          hdrlen = 5;
+        else
+          hdrlen = 2;
+      }
+    else
+      {
+        int lentype = ctb & 0x3;
+        if (lentype == 0)
+          hdrlen = 2;
+        else if (lentype == 1)
+          hdrlen = 3;
+        else if (lentype == 2)
+          hdrlen = 5;
+        else
+          /* Indeterminate.  */
+          hdrlen = 1;
+      }
+
+    if (debug)
+      log_debug ("ctb = %x; %s format, hdrlen: %d, packet: %s\n",
+                 ctb, new_format ? "new" : "old",
+                 hdrlen,
+                 pkttype_str (pkttype));
+
+    if (! (pkttype == PKT_ENCRYPTED || pkttype == PKT_ENCRYPTED_MDC))
+      log_fatal ("%s does not contain an encrypted packet, but a %s.\n",
+                 filename, pkttype_str (pkttype));
+
+    if (pkttype == PKT_ENCRYPTED_MDC)
+      {
+        /* The first byte following the header is the version, which
+           is 1.  */
+        log_assert (raw_data[hdrlen] == 1);
+        hdrlen ++;
+        sync = 0;
+      }
+    else
+      sync = 1;
+
+    msg = &raw_data[hdrlen];
+    msg_len = raw_data_len - hdrlen;
+  }
+
+  log_assert (msg_len >= blocksize + 2);
+
+  {
+    /* This can at least partially be guessed.  So we just assume that
+       it is known.  */
+    int d;
+    int found;
+    const byte *m1;
+    byte e_k_zero[2];
+
+    if (oracle (debug, msg, msg_len, &msg_plaintext, &msg_cfb) == 0)
+      {
+        if (debug)
+          log_debug ("Session key appears to be good.\n");
+      }
+    else
+      log_fatal ("Session key is bad!\n");
+
+    m1 = &msg_plaintext[blocksize + 2];
+    if (debug)
+      log_debug ("First two bytes of plaintext are: %02X (%c) %02X (%c)\n",
+                 m1[0], isprint (m1[0]) ? m1[0] : '?',
+                 m1[1], isprint (m1[1]) ? m1[1] : '?');
+
+    for (d = 0; d < 256 * 256; d ++)
+      if ((found = oracle_test (d, 1, 0)))
+        break;
+
+    if (! found)
+      log_fatal ("Failed to find d!\n");
+
+    if (debug)
+      oracle_test (d, 1, 1);
+
+    if (debug)
+      log_debug ("D = %d (%x) looks good.\n", d, d);
+
+    {
+      byte *c2 = block (msg, msg_len, 2);
+      byte D[2] = { d >> 8, d & 0xFF };
+      byte *c3 = block (msg, msg_len, 3);
+
+      memcpy (e_k_zero,
+              bufxor2 (bufxor2 (c2, D),
+                       bufxor2 (c3, m1)),
+              sizeof (e_k_zero));
+
+      if (debug)
+        {
+          log_debug ("C2 = %s\n", hexstr (c2));
+          log_debug ("D = %s\n", hexstr (D));
+          log_debug ("C3 = %s\n", hexstr (c3));
+          log_debug ("M = %s\n", hexstr (m1));
+          log_debug ("E_k([C1]_{3-b} || C_2) = C3 xor M1 = %s\n",
+                     hexstr (bufxor2 (c3, m1)));
+          log_debug ("E_k(0)_{b-1,b} = %s\n", hexstr (e_k_zero));
+        }
+    }
+
+    /* Figure out the first 2 bytes of M2... (offset 16 & 17 of the
+       plain text assuming the blocksize == 16 or bytes 34 & 35 of the
+       decrypted cipher text, i.e., C4).  */
+    for (i = 1; block_offset (i + 3) + 2 <= msg_len; i ++)
+      {
+        byte e_k_prime[2];
+        byte m[2];
+        byte *ct = block (msg, msg_len, i + 2);
+        byte *pt = block (msg_plaintext, msg_len, 2 + i + 1);
+
+        for (d = 0; d < 256 * 256; d ++)
+          if (oracle_test (d, i + 2, 0))
+            {
+              found = 1;
+              break;
+            }
+
+        if (! found)
+          log_fatal ("Failed to find a valid d for block %d\n", i);
+
+        if (debug)
+          log_debug ("Block %d: oracle: D = %04X passes integrity check\n",
+                     i, d);
+
+        {
+          byte D[2] = { d >> 8, d & 0xFF };
+          memcpy (e_k_prime,
+                  bufxor2 (bufxor2 (&ct[blocksize - 2], D), e_k_zero),
+                  sizeof (e_k_prime));
+
+          memcpy (m, bufxor2 (e_k_prime, block (msg, msg_len, i + 3)),
+                  sizeof (m));
+        }
+
+        if (debug)
+          log_debug ("=> block %d starting at %zd starts with: "
+                     "%s (%c%c)\n",
+                     i, (size_t) pt - (size_t) msg_plaintext,
+                     hexstr (m),
+                     isprint (m[0]) ? m[0] : '?', isprint (m[1]) ? m[1] : '?');
+
+        if (m[0] != pt[0] || m[1] != pt[1])
+          {
+            log_debug ("oracle attack failed!  Expected %s (%c%c), got %s\n",
+                       hexstr (pt),
+                       isprint (pt[0]) ? pt[0] : '?',
+                       isprint (pt[1]) ? pt[1] : '?',
+                       hexstr (m));
+            failed = 1;
+          }
+      }
+
+    if (i == 1)
+      log_fatal ("Message is too short, nothing to test.\n");
+  }
+
+  return failed;
+}
index 893c982..4c3d7a8 100644 (file)
@@ -23,7 +23,6 @@
 #include <string.h>
 #include <errno.h>
 #include <ctype.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
index 3cc8bd3..5fdd946 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -317,7 +316,7 @@ put_record_into_cache (ulong recno, const char *data)
        }
 
       /* Now put into the cache.  */
-      assert (unused);
+      log_assert (unused);
       r = unused;
       r->flags.used = 1;
       r->recno = recno;
@@ -383,7 +382,7 @@ put_record_into_cache (ulong recno, const char *data)
       release_write_lock ();
 
       /* Now put into the cache.  */
-      assert (unused);
+      log_assert (unused);
       r = unused;
       r->flags.used = 1;
       r->recno = recno;
@@ -603,9 +602,10 @@ create_version_record (void)
 int
 tdbio_set_dbname (const char *new_dbname, int create, int *r_nofile)
 {
-  char *fname;
+  char *fname, *p;
   struct stat statbuf;
   static int initialized = 0;
+  int save_slash;
 
   if (!initialized)
     {
@@ -643,11 +643,48 @@ tdbio_set_dbname (const char *new_dbname, int create, int *r_nofile)
       /* OK, we have the valid trustdb.gpg already.  */
       return 0;
     }
+  else if (!create)
+    {
+      *r_nofile = 1;
+      return 0;
+    }
+
+  /* Here comes: No valid trustdb.gpg AND CREATE==1 */
+
+  /*
+   * Make sure the directory exists.  This should be done before
+   * acquiring the lock, which assumes the existence of the directory.
+   */
+  p = strrchr (fname, DIRSEP_C);
+#if HAVE_W32_SYSTEM
+  {
+    /* Windows may either have a slash or a backslash.  Take
+       care of it.  */
+    char *pp = strrchr (fname, '/');
+    if (!p || pp > p)
+      p = pp;
+  }
+#endif /*HAVE_W32_SYSTEM*/
+  log_assert (p);
+  save_slash = *p;
+  *p = 0;
+  if (access (fname, F_OK))
+    {
+      try_make_homedir (fname);
+      if (access (fname, F_OK))
+        log_fatal (_("%s: directory does not exist!\n"), fname);
+    }
+  *p = save_slash;
 
   take_write_lock ();
 
   if (access (fname, R_OK))
     {
+      FILE *fp;
+      TRUSTREC rec;
+      int rc;
+      mode_t oldmask;
+
 #ifdef HAVE_W32CE_SYSTEM
       /* We know how the cegcc implementation of access works ;-). */
       if (GetLastError () == ERROR_FILE_NOT_FOUND)
@@ -658,66 +695,34 @@ tdbio_set_dbname (const char *new_dbname, int create, int *r_nofile)
       if (errno != ENOENT)
         log_fatal ( _("can't access '%s': %s\n"), fname, strerror (errno));
 
-      if (!create)
-        *r_nofile = 1;
-      else
+      oldmask = umask (077);
+      if (is_secured_filename (fname))
         {
-          FILE *fp;
-          TRUSTREC rec;
-          int rc;
-          char *p = strrchr (fname, DIRSEP_C);
-          mode_t oldmask;
-          int save_slash;
-
-#if HAVE_W32_SYSTEM
-          {
-            /* Windows may either have a slash or a backslash.  Take
-               care of it.  */
-            char *pp = strrchr (fname, '/');
-            if (!p || pp > p)
-              p = pp;
-          }
-#endif /*HAVE_W32_SYSTEM*/
-          assert (p);
-          save_slash = *p;
-          *p = 0;
-          if (access (fname, F_OK))
-            {
-              try_make_homedir (fname);
-              if (access (fname, F_OK))
-                log_fatal (_("%s: directory does not exist!\n"), fname);
-           }
-          *p = save_slash;
-
-          oldmask = umask (077);
-          if (is_secured_filename (fname))
-            {
-              fp = NULL;
-              gpg_err_set_errno (EPERM);
-            }
-          else
-            fp = fopen (fname, "wb");
-          umask(oldmask);
-          if (!fp)
-            log_fatal (_("can't create '%s': %s\n"), fname, strerror (errno));
-          fclose (fp);
+          fp = NULL;
+          gpg_err_set_errno (EPERM);
+        }
+      else
+        fp = fopen (fname, "wb");
+      umask(oldmask);
+      if (!fp)
+        log_fatal (_("can't create '%s': %s\n"), fname, strerror (errno));
+      fclose (fp);
 
-          db_fd = open (db_name, O_RDWR | MY_O_BINARY);
-          if (db_fd == -1)
-            log_fatal (_("can't open '%s': %s\n"), db_name, strerror (errno));
+      db_fd = open (db_name, O_RDWR | MY_O_BINARY);
+      if (db_fd == -1)
+        log_fatal (_("can't open '%s': %s\n"), db_name, strerror (errno));
 
-          rc = create_version_record ();
-          if (rc)
-            log_fatal (_("%s: failed to create version record: %s"),
-                       fname, gpg_strerror (rc));
+      rc = create_version_record ();
+      if (rc)
+        log_fatal (_("%s: failed to create version record: %s"),
+                   fname, gpg_strerror (rc));
 
-          /* Read again to check that we are okay. */
-          if (tdbio_read_record (0, &rec, RECTYPE_VER))
-            log_fatal (_("%s: invalid trustdb created\n"), db_name);
+      /* Read again to check that we are okay. */
+      if (tdbio_read_record (0, &rec, RECTYPE_VER))
+        log_fatal (_("%s: invalid trustdb created\n"), db_name);
 
-          if (!opt.quiet)
-            log_info (_("%s: trustdb created\n"), db_name);
-       }
+      if (!opt.quiet)
+        log_info (_("%s: trustdb created\n"), db_name);
     }
 
   release_write_lock ();
@@ -745,7 +750,7 @@ open_db ()
 {
   TRUSTREC rec;
 
-  assert( db_fd == -1 );
+  log_assert( db_fd == -1 );
 
 #ifdef HAVE_W32CE_SYSTEM
   {
@@ -805,7 +810,7 @@ create_hashtable( TRUSTREC *vr, int type )
   if (offset == -1)
     log_fatal ("trustdb: lseek to end failed: %s\n", strerror(errno));
   recnum = offset / TRUST_RECORD_LEN;
-  assert (recnum); /* This is will never be the first record. */
+  log_assert (recnum); /* This is will never be the first record. */
 
   if (!type)
     vr->r.ver.trusthashtbl = recnum;
@@ -1764,7 +1769,7 @@ tdbio_new_recnum ()
       if (offset == (off_t)(-1))
         log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno));
       recnum = offset / TRUST_RECORD_LEN;
-      assert (recnum); /* this is will never be the first record */
+      log_assert (recnum); /* this is will never be the first record */
       /* We must write a record, so that the next call to this
        * function returns another recnum.  */
       memset (&rec, 0, sizeof rec);
index 74b6bf7..2edae18 100644 (file)
@@ -186,6 +186,17 @@ keyserver_import_pka (const char *name,unsigned char *fpr)
   return -1;
 }
 
+gpg_error_t
+keyserver_import_wkd (ctrl_t ctrl, const char *name,
+                      unsigned char **fpr, size_t *fpr_len)
+{
+  (void)ctrl;
+  (void)name;
+  (void)fpr;
+  (void)fpr_len;
+  return GPG_ERR_BUG;
+}
+
 int
 keyserver_import_name (const char *name,struct keyserver_spec *spec)
 {
index 39d5945..e9e2074 100644 (file)
@@ -74,10 +74,13 @@ static int verbose;
                                                \
     if (test_result == expected_result)                \
       {                                                \
-        printf (" ok.\n");                     \
+        if (verbose) printf (" ok.\n");         \
       }                                                \
     else                                       \
       {                                                \
+        if (!verbose)                           \
+          printf ("%d. Checking %s...",         \
+                  tests, (description) ?: "");  \
        printf (" failed.\n");                  \
        printf ("  %s == %s failed.\n",         \
                STRINGIFY(test),                \
@@ -125,7 +128,8 @@ exit_tests (int force)
 {
   if (tests_failed == 0)
     {
-      printf ("All %d tests passed.\n", tests);
+      if (verbose)
+        printf ("All %d tests passed.\n", tests);
       exit (!!force);
     }
   else
index da303c4..5929c5f 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "status.h"
@@ -70,7 +69,7 @@ standard( text_filter_context_t *tfx, IOBUF a,
     size_t len = 0;
     unsigned maxlen;
 
-    assert( size > 10 );
+    log_assert( size > 10 );
     size -= 2; /* reserve 2 bytes to append CR,LF */
     while( !rc && len < size ) {
        int lf_seen;
index 6a88172..e591aa5 100644 (file)
@@ -1,5 +1,5 @@
 /* tofu.c - TOFU trust model.
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
@@ -26,9 +26,7 @@
 #include <config.h>
 #include <stdio.h>
 #include <sys/stat.h>
-#include <assert.h>
 #include <stdarg.h>
-#include <sched.h>
 #include <sqlite3.h>
 
 #include "gpg.h"
 #include "trustdb.h"
 #include "mkdir_p.h"
 #include "sqlite.h"
+#include "status.h"
 
 #include "tofu.h"
 
 
 #define CONTROL_L ('L' - 'A' + 1)
 
+/* Number of signed messages required to indicate that enough history
+ * is available for basic trust.  */
+#define BASIC_TRUST_THRESHOLD  10
+/* Number of signed messages required to indicate that a lot of
+ * history is available.  */
+#define FULL_TRUST_THRESHOLD  100
+
 
 #define DEBUG_TOFU_CACHE 0
 #if DEBUG_TOFU_CACHE
@@ -240,7 +246,7 @@ begin_transaction (struct db *db, int only_batch)
       batch_update_started = gnupg_get_time ();
 
       /* Yield to allow another process a chance to run.  */
-      sched_yield ();
+      gpgrt_yield ();
     }
 
   /* XXX: In split mode, this can end in deadlock.
@@ -389,7 +395,7 @@ tofu_begin_batch_update (void)
 void
 tofu_end_batch_update (void)
 {
-  assert (batch_update > 0);
+  log_assert (batch_update > 0);
   batch_update --;
 
   if (batch_update == 0)
@@ -400,7 +406,66 @@ tofu_end_batch_update (void)
         end_transaction (db, 1);
     }
 }
+
+
+
 \f
+/* Wrapper around strtol which prints a warning in case of a
+ * conversion error.  On success the converted value is stored at
+ * R_VALUE and 0 is returned; on error FALLBACK is stored at R_VALUE
+ * and an error code is returned.  */
+static gpg_error_t
+string_to_long (long *r_value, const char *string, long fallback, int line)
+{
+  gpg_error_t err;
+  char *tail = NULL;
+
+  gpg_err_set_errno (0);
+  *r_value = strtol (string, &tail, 0);
+  if (errno || !(!strcmp (tail, ".0") || !*tail))
+    {
+      err = errno? gpg_error_from_errno (errno) : gpg_error (GPG_ERR_BAD_DATA);
+      log_debug ("%s:%d: "
+                 "strtol failed for DB returned string (tail=%.10s): %s\n",
+                 __FILE__, line, tail, gpg_strerror (err));
+      *r_value = fallback;
+    }
+  else
+    err = 0;
+
+  return err;
+}
+
+
+/* Wrapper around strtoul which prints a warning in case of a
+ * conversion error.  On success the converted value is stored at
+ * R_VALUE and 0 is returned; on error FALLBACK is stored at R_VALUE
+ * and an error code is returned.  */
+static gpg_error_t
+string_to_ulong (unsigned long *r_value, const char *string,
+                 unsigned long fallback, int line)
+{
+  gpg_error_t err;
+  char *tail = NULL;
+
+  gpg_err_set_errno (0);
+  *r_value = strtoul (string, &tail, 0);
+  if (errno || !(!strcmp (tail, ".0") || !*tail))
+    {
+      err = errno? gpg_error_from_errno (errno) : gpg_error (GPG_ERR_BAD_DATA);
+      log_debug ("%s:%d: "
+                 "strtoul failed for DB returned string (tail=%.10s): %s\n",
+                 __FILE__, line, tail, gpg_strerror (err));
+      *r_value = fallback;
+    }
+  else
+    err = 0;
+
+  return err;
+}
+
+
+
 /* Collect results of a select count (*) ...; style query.  Aborts if
    the argument is not a valid integer (or real of the form X.0).  */
 static int
@@ -408,17 +473,13 @@ get_single_unsigned_long_cb (void *cookie, int argc, char **argv,
                             char **azColName)
 {
   unsigned long int *count = cookie;
-  char *tail = NULL;
 
   (void) azColName;
 
-  assert (argc == 1);
+  log_assert (argc == 1);
 
-  errno = 0;
-  *count = strtoul (argv[0], &tail, 0);
-  if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
-    /* Abort.  */
-    return 1;
+  if (string_to_ulong (count, argv[0], 0, __LINE__))
+    return 1; /* Abort.  */
   return 0;
 }
 
@@ -683,16 +744,16 @@ opendb (char *filename, enum db_type type)
 
   if (opt.tofu_db_format == TOFU_DB_FLAT)
     {
-      assert (! filename);
-      assert (type == DB_COMBINED);
+      log_assert (! filename);
+      log_assert (type == DB_COMBINED);
 
       filename = make_filename (opt.homedir, "tofu.db", NULL);
       filename_free = 1;
     }
   else
-    assert (type == DB_EMAIL || type == DB_KEY);
+    log_assert (type == DB_EMAIL || type == DB_KEY);
 
-  assert (filename);
+  log_assert (filename);
 
   rc = sqlite3_open (filename, &db);
   if (rc)
@@ -706,7 +767,8 @@ opendb (char *filename, enum db_type type)
 
   /* If a DB is locked wait up to 5 seconds for the lock to be cleared
      before failing.  */
-  sqlite3_busy_timeout (db, 5 * 1000);
+  if (db)
+    sqlite3_busy_timeout (db, 5 * 1000);
 
   if (filename_free)
     xfree (filename);
@@ -762,9 +824,9 @@ getdb (struct dbs *dbs, const char *name, enum db_type type)
   sqlite3 *sqlitedb = NULL;
   gpg_error_t rc;
 
-  assert (dbs);
-  assert (name);
-  assert (type == DB_EMAIL || type == DB_KEY);
+  log_assert (dbs);
+  log_assert (name);
+  log_assert (type == DB_EMAIL || type == DB_KEY);
 
   if (opt.tofu_db_format == TOFU_DB_FLAT)
     /* When using the flat format, we only have a single DB, the
@@ -772,8 +834,8 @@ getdb (struct dbs *dbs, const char *name, enum db_type type)
     {
       if (dbs->db)
         {
-          assert (dbs->db->type == DB_COMBINED);
-          assert (! dbs->db->next);
+          log_assert (dbs->db->type == DB_COMBINED);
+          log_assert (! dbs->db->next);
           return dbs->db;
         }
 
@@ -814,7 +876,7 @@ getdb (struct dbs *dbs, const char *name, enum db_type type)
         goto out;
       }
 
-  assert (db_cache_count == count);
+  log_assert (db_cache_count == count);
 
   if (type == DB_COMBINED)
     filename = NULL;
@@ -883,18 +945,18 @@ closedb (struct db *db)
   if (opt.tofu_db_format == TOFU_DB_FLAT)
     /* If we are using the flat format, then there is only ever the
        combined DB.  */
-    assert (! db->next);
+    log_assert (! db->next);
 
   if (db->type == DB_COMBINED)
     {
-      assert (opt.tofu_db_format == TOFU_DB_FLAT);
-      assert (! db->name[0]);
+      log_assert (opt.tofu_db_format == TOFU_DB_FLAT);
+      log_assert (! db->name[0]);
     }
   else
     {
-      assert (opt.tofu_db_format == TOFU_DB_SPLIT);
-      assert (db->type != DB_COMBINED);
-      assert (db->name[0]);
+      log_assert (opt.tofu_db_format == TOFU_DB_SPLIT);
+      log_assert (db->type != DB_COMBINED);
+      log_assert (db->name[0]);
     }
 
   if (db->batch_update)
@@ -1002,10 +1064,10 @@ closedbs (struct dbs *dbs)
           /* When we leave batch mode we leave batch mode on any
              cached connections.  */
           if (! batch_update)
-            assert (! db->batch_update);
+            log_assert (! db->batch_update);
         }
       if (! batch_update)
-        assert (! db->batch_update);
+        log_assert (! db->batch_update);
 
       /* Join the two lists.  */
       db->next = db_cache;
@@ -1056,17 +1118,14 @@ static int
 get_single_long_cb (void *cookie, int argc, char **argv, char **azColName)
 {
   long *count = cookie;
-  char *tail = NULL;
 
   (void) azColName;
 
-  assert (argc == 1);
+  log_assert (argc == 1);
+
+  if (string_to_long (count, argv[0], 0, __LINE__))
+    return 1; /* Abort.  */
 
-  errno = 0;
-  *count = strtol (argv[0], &tail, 0);
-  if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
-    /* Abort.  */
-    return 1;
   return 0;
 }
 
@@ -1154,7 +1213,7 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
        {
          log_debug ("TOFU: Error reading from binding database"
                     " (reading policy for <%s, %s>): %s\n",
-                    fingerprint_pp, email, err);
+                    fingerprint, email, err);
          sqlite3_free (err);
        }
     }
@@ -1164,12 +1223,12 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
       if (policy_old != TOFU_POLICY_NONE)
        log_debug ("Changing TOFU trust policy for binding <%s, %s>"
                   " from %s to %s.\n",
-                  fingerprint_pp, email,
+                  fingerprint, email,
                   tofu_policy_str (policy_old),
                   tofu_policy_str (policy));
       else
        log_debug ("Set TOFU trust policy for binding <%s, %s> to %s.\n",
-                  fingerprint_pp, email,
+                  fingerprint, email,
                   tofu_policy_str (policy));
     }
 
@@ -1177,6 +1236,12 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
     /* Nothing to do.  */
     goto out;
 
+  if (opt.dry_run)
+    {
+      log_info ("TOFU database update skipped due to --dry-run\n");
+      goto out;
+    }
+
   rc = sqlite3_stepx
     (db_email->db, &db_email->s.record_binding_update, NULL, NULL, &err,
      "insert or replace into bindings\n"
@@ -1195,7 +1260,7 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
     {
       log_error (_("error updating TOFU database: %s\n"), err);
       print_further_info (" insert bindings <%s, %s> = %s",
-                          fingerprint_pp, email, tofu_policy_str (policy));
+                          fingerprint, email, tofu_policy_str (policy));
       sqlite3_free (err);
       goto out;
     }
@@ -1203,7 +1268,7 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
   if (db_key)
     /* We also need to update the key DB.  */
     {
-      assert (opt.tofu_db_format == TOFU_DB_SPLIT);
+      log_assert (opt.tofu_db_format == TOFU_DB_SPLIT);
 
       rc = sqlite3_stepx
        (db_key->db, &db_key->s.record_binding_update2, NULL, NULL, &err,
@@ -1222,13 +1287,13 @@ record_binding (struct dbs *dbs, const char *fingerprint, const char *email,
        {
          log_error (_("error updating TOFU database: %s\n"), err);
           print_further_info ("insert bindings <%s, %s>",
-                              fingerprint_pp, email);
+                              fingerprint, email);
          sqlite3_free (err);
          goto out;
        }
     }
   else
-    assert (opt.tofu_db_format == TOFU_DB_FLAT);
+    log_assert (opt.tofu_db_format == TOFU_DB_FLAT);
 
  out:
   if (opt.tofu_db_format == TOFU_DB_SPLIT)
@@ -1357,43 +1422,28 @@ signature_stats_collect_cb (void *cookie, int argc, char **argv,
                            char **azColName, sqlite3_stmt *stmt)
 {
   struct signature_stats **statsp = cookie;
-  char *tail;
   int i = 0;
   enum tofu_policy policy;
   long time_ago;
   unsigned long count;
+  long along;
 
   (void) azColName;
   (void) stmt;
 
   i ++;
 
-  tail = NULL;
-  errno = 0;
-  policy = strtol (argv[i], &tail, 0);
-  if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
-    {
-      /* Abort.  */
-      log_error ("%s: Error converting %s to an integer (tail = '%s')\n",
-                __func__, argv[i], tail);
-      return 1;
-    }
+  if (string_to_long (&along, argv[i], 0, __LINE__))
+    return 1;  /* Abort */
+  policy = along;
   i ++;
 
   if (! argv[i])
     time_ago = 0;
   else
     {
-      tail = NULL;
-      errno = 0;
-      time_ago = strtol (argv[i], &tail, 0);
-      if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
-        {
-          /* Abort.  */
-          log_error ("%s: Error converting %s to an integer (tail = '%s')\n",
-                     __func__, argv[i], tail);
-          return 1;
-        }
+      if (string_to_long (&time_ago, argv[i], 0, __LINE__))
+        return 1; /* Abort.  */
     }
   i ++;
 
@@ -1403,20 +1453,12 @@ signature_stats_collect_cb (void *cookie, int argc, char **argv,
     count = 0;
   else
     {
-      tail = NULL;
-      errno = 0;
-      count = strtoul (argv[i], &tail, 0);
-      if (errno || ! (strcmp (tail, ".0") == 0 || *tail == '\0'))
-        {
-          /* Abort.  */
-          log_error ("%s: Error converting %s to an integer (tail = '%s')\n",
-                     __func__, argv[i], tail);
-          return 1;
-        }
+      if (string_to_ulong (&count, argv[i], 0, __LINE__))
+        return 1; /* Abort */
     }
   i ++;
 
-  assert (argc == i);
+  log_assert (argc == i);
 
   signature_stats_prepend (statsp, argv[0], policy, time_ago, count);
 
@@ -1450,8 +1492,8 @@ get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
   int rc;
   char *err = NULL;
   strlist_t strlist = NULL;
-  char *tail = NULL;
   enum tofu_policy policy = _tofu_GET_POLICY_ERROR;
+  long along;
 
   db = getdb (dbs, email, DB_EMAIL);
   if (! db)
@@ -1495,15 +1537,14 @@ get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
 
   /* The result has the right form.  */
 
-  errno = 0;
-  policy = strtol (strlist->d, &tail, 0);
-  if (errno || *tail != '\0')
+  if (string_to_long (&along, strlist->d, 0, __LINE__))
     {
       log_error (_("error reading TOFU database: %s\n"),
                  gpg_strerror (GPG_ERR_BAD_DATA));
       print_further_info ("bad value for policy: %s", strlist->d);
       goto out;
     }
+  policy = along;
 
   if (! (policy == TOFU_POLICY_AUTO
         || policy == TOFU_POLICY_GOOD
@@ -1531,13 +1572,13 @@ get_policy (struct dbs *dbs, const char *fingerprint, const char *email,
     }
 
  out:
-  assert (policy == _tofu_GET_POLICY_ERROR
-         || policy == TOFU_POLICY_NONE
-         || policy == TOFU_POLICY_AUTO
-         || policy == TOFU_POLICY_GOOD
-         || policy == TOFU_POLICY_UNKNOWN
-         || policy == TOFU_POLICY_BAD
-         || policy == TOFU_POLICY_ASK);
+  log_assert (policy == _tofu_GET_POLICY_ERROR
+              || policy == TOFU_POLICY_NONE
+              || policy == TOFU_POLICY_AUTO
+              || policy == TOFU_POLICY_GOOD
+              || policy == TOFU_POLICY_UNKNOWN
+              || policy == TOFU_POLICY_BAD
+              || policy == TOFU_POLICY_ASK);
 
   free_strlist (strlist);
 
@@ -1576,13 +1617,13 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
 
   /* Make sure _tofu_GET_TRUST_ERROR isn't equal to any of the trust
      levels.  */
-  assert (_tofu_GET_TRUST_ERROR != TRUST_UNKNOWN
-         && _tofu_GET_TRUST_ERROR != TRUST_EXPIRED
-         && _tofu_GET_TRUST_ERROR != TRUST_UNDEFINED
-         && _tofu_GET_TRUST_ERROR != TRUST_NEVER
-         && _tofu_GET_TRUST_ERROR != TRUST_MARGINAL
-         && _tofu_GET_TRUST_ERROR != TRUST_FULLY
-         && _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
+  log_assert (_tofu_GET_TRUST_ERROR != TRUST_UNKNOWN
+              && _tofu_GET_TRUST_ERROR != TRUST_EXPIRED
+              && _tofu_GET_TRUST_ERROR != TRUST_UNDEFINED
+              && _tofu_GET_TRUST_ERROR != TRUST_NEVER
+              && _tofu_GET_TRUST_ERROR != TRUST_MARGINAL
+              && _tofu_GET_TRUST_ERROR != TRUST_FULLY
+              && _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
 
   db = getdb (dbs, email, DB_EMAIL);
   if (! db)
@@ -1653,7 +1694,7 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
       policy = opt.tofu_default_policy;
       if (DBG_TRUST)
        log_debug ("TOFU: binding <%s, %s>'s policy is auto (default: %s).\n",
-                  fingerprint_pp, email,
+                  fingerprint, email,
                   tofu_policy_str (opt.tofu_default_policy));
     }
   switch (policy)
@@ -1666,7 +1707,7 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
         We don't need to ask the user anything.  */
       if (DBG_TRUST)
        log_debug ("TOFU: Known binding <%s, %s>'s policy: %s\n",
-                  fingerprint_pp, email, tofu_policy_str (policy));
+                  fingerprint, email, tofu_policy_str (policy));
       trust_level = tofu_policy_to_trust_level (policy);
       goto out;
 
@@ -1740,11 +1781,11 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
     {
       /* If we've seen this binding, then we've seen this email and
         policy couldn't possibly be TOFU_POLICY_NONE.  */
-      assert (policy == TOFU_POLICY_NONE);
+      log_assert (policy == TOFU_POLICY_NONE);
 
       if (DBG_TRUST)
        log_debug ("TOFU: New binding <%s, %s>, no conflict.\n",
-                  email, fingerprint_pp);
+                  email, fingerprint);
 
       if (record_binding (dbs, fingerprint, email, user_id,
                          TOFU_POLICY_AUTO, 0) != 0)
@@ -1772,7 +1813,7 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
        there is a conflict.  (If the policy was ask (cases #1 and #2)
        and we weren't allowed to ask, we'd have already exited).  */
     {
-      assert (policy == TOFU_POLICY_NONE);
+      log_assert (policy == TOFU_POLICY_NONE);
 
       if (record_binding (dbs, fingerprint, email, user_id,
                          TOFU_POLICY_ASK, 0) != 0)
@@ -1801,8 +1842,6 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
       ((policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0)
        || (policy == TOFU_POLICY_ASK && conflict));
     estream_t fp;
-    char *binding;
-    int binding_shown;
     strlist_t other_user_ids = NULL;
     struct signature_stats *stats = NULL;
     struct signature_stats *stats_iter = NULL;
@@ -1811,43 +1850,65 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
 
     fp = es_fopenmem (0, "rw,samethread");
     if (! fp)
-      log_fatal ("Error creating memory stream\n");
+      log_fatal ("error creating memory stream: %s\n",
+                 gpg_strerror (gpg_error_from_syserror()));
 
-    binding = xasprintf ("<%s, %s>", fingerprint_pp, email);
-    binding_shown = 0;
+    /* Format the first part of the message.  */
+    {
+      estream_t fp1;
+      char *binding = xasprintf ("<%s, %s>", fingerprint, email);
+      int binding_shown = 0;
+      char *tmpstr, *text;
 
-    if (policy == TOFU_POLICY_NONE)
-      {
-       es_fprintf (fp, _("The binding %s is NOT known."), binding);
-        es_fputs ("  ", fp);
-       binding_shown = 1;
-      }
-    else if (policy == TOFU_POLICY_ASK
-            /* If there the conflict is with itself, then don't
-               display this message.  */
-            && conflict && strcmp (conflict, fingerprint) != 0)
-      {
-        char *conflict_pp = format_hexfingerprint (conflict, NULL, 0);
-       es_fprintf (fp,
-                   _("The key %s raised a conflict with this binding (%s)."
-                      "  Since this binding's policy was 'auto', it was "
-                      "changed to 'ask'."),
-                   conflict_pp, binding);
-        es_fputs ("  ", fp);
-        xfree (conflict_pp);
-       binding_shown = 1;
-      }
-    /* TRANSLATORS: The %s%s is replaced by either a fingerprint and a
-       blank or by two empty strings.  */
-    es_fprintf (fp,
-               _("Please indicate whether you believe the binding %s%s"
-                 "is legitimate (the key belongs to the stated owner) "
-                 "or a forgery (bad)."),
-               binding_shown ? "" : binding,
-               binding_shown ? "" : " ");
-    es_fputs ("\n\n", fp);
-
-    xfree (binding);
+      fp1 = es_fopenmem (0, "rw,samethread");
+      if (!fp1)
+        log_fatal ("error creating memory stream: %s\n",
+                   gpg_strerror (gpg_error_from_syserror()));
+
+      if (policy == TOFU_POLICY_NONE)
+        {
+          es_fprintf (fp1, _("The binding %s is NOT known."), binding);
+          es_fputs ("  ", fp1);
+          binding_shown = 1;
+        }
+      else if (policy == TOFU_POLICY_ASK
+               /* If there the conflict is with itself, then don't
+                  display this message.  */
+               && conflict && strcmp (conflict, fingerprint) != 0)
+        {
+          es_fprintf (fp1,
+                      _("The key with fingerprint %s raised a conflict "
+                        "with the binding %s."
+                        "  Since this binding's policy was 'auto', it was "
+                        "changed to 'ask'."),
+                      conflict, binding);
+          es_fputs ("  ", fp1);
+          binding_shown = 1;
+        }
+
+      /* TRANSLATORS: The %s%s is replaced by either a fingerprint and a
+         blank or by two empty strings.  */
+      es_fprintf (fp1,
+                  _("Please indicate whether you believe the binding %s%s"
+                    "is legitimate (the key belongs to the stated owner) "
+                    "or a forgery (bad)."),
+                  binding_shown ? "" : binding,
+                  binding_shown ? "" : " ");
+      es_fputc ('\n', fp1);
+
+      xfree (binding);
+
+      es_fputc (0, fp1);
+      if (es_fclose_snatch (fp1, (void **)&tmpstr, NULL))
+        log_fatal ("error snatching memory stream\n");
+      text = format_text (tmpstr, 0, 72, 80);
+      es_free (tmpstr);
+
+      es_fputs (text, fp);
+      xfree (text);
+    }
+
+    es_fputc ('\n', fp);
 
     /* Find other user ids associated with this key and whether the
        bindings are marked as good or bad.  */
@@ -1893,7 +1954,7 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
            char *other_thing;
            enum tofu_policy other_policy;
 
-           assert (strlist_iter->next);
+           log_assert (strlist_iter->next);
            strlist_iter = strlist_iter->next;
            other_thing = strlist_iter->d;
 
@@ -2040,7 +2101,8 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
        /* TRANSLATORS: Please translate the text found in the source
           file below.  We don't directly internationalize that text
           so that we can tweak it without breaking translations.  */
-       char *text = _("TOFU detected a binding conflict");
+       const char *text = _("TOFU detected a binding conflict");
+        char *textbuf;
        if (strcmp (text, "TOFU detected a binding conflict") == 0)
          /* No translation.  Use the English text.  */
          text =
@@ -2050,9 +2112,9 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
            "Alternatively, a new key may indicate a man-in-the-middle "
            "attack!  Before accepting this key, you should talk to or "
            "call the person to make sure this new key is legitimate.";
-        text = format_text (text, 0, 72, 80);
+        textbuf = format_text (text, 0, 72, 80);
        es_fprintf (fp, "\n%s\n", text);
-        xfree (text);
+        xfree (textbuf);
       }
 
     es_fputc ('\n', fp);
@@ -2175,7 +2237,8 @@ get_trust (struct dbs *dbs, const char *fingerprint, const char *email,
 
 /* Return a malloced string of the form
  *    "7 months, 1 day, 5 minutes, 0 seconds"
- * The caller must free that string.
+ * The caller should replace all '~' in the returned string by a space
+ * and also free the returned string.
  *
  * This is actually a bad hack which may not work correctly with all
  * languages.
@@ -2249,7 +2312,9 @@ time_ago_str (long long int t)
 
   if (years)
     {
-      es_fprintf (fp, ngettext("%d year", "%d years", years), years);
+      /* TRANSLATORS: The tilde ('~') is used here to indicate a
+       * non-breakable space  */
+      es_fprintf (fp, ngettext("%d~year", "%d~years", years), years);
       count ++;
       first = i;
     }
@@ -2258,7 +2323,7 @@ time_ago_str (long long int t)
     {
       if (count)
         es_fprintf (fp, ", ");
-      es_fprintf (fp, ngettext("%d month", "%d months", months), months);
+      es_fprintf (fp, ngettext("%d~month", "%d~months", months), months);
       count ++;
       first = i;
     }
@@ -2267,7 +2332,7 @@ time_ago_str (long long int t)
     {
       if (count)
         es_fprintf (fp, ", ");
-      es_fprintf (fp, ngettext("%d day", "%d days", days), days);
+      es_fprintf (fp, ngettext("%d~day", "%d~days", days), days);
       count ++;
       first = i;
     }
@@ -2276,7 +2341,7 @@ time_ago_str (long long int t)
     {
       if (count)
         es_fprintf (fp, ", ");
-      es_fprintf (fp, ngettext("%d hour", "%d hours", hours), hours);
+      es_fprintf (fp, ngettext("%d~hour", "%d~hours", hours), hours);
       count ++;
       first = i;
     }
@@ -2285,7 +2350,7 @@ time_ago_str (long long int t)
     {
       if (count)
         es_fprintf (fp, ", ");
-      es_fprintf (fp, ngettext("%d minute", "%d minutes", minutes), minutes);
+      es_fprintf (fp, ngettext("%d~minute", "%d~minutes", minutes), minutes);
       count ++;
       first = i;
     }
@@ -2294,7 +2359,7 @@ time_ago_str (long long int t)
     {
       if (count)
         es_fprintf (fp, ", ");
-      es_fprintf (fp, ngettext("%d second", "%d seconds", seconds), seconds);
+      es_fprintf (fp, ngettext("%d~second", "%d~seconds", seconds), seconds);
     }
 
   es_fputc (0, fp);
@@ -2305,6 +2370,40 @@ time_ago_str (long long int t)
 }
 
 
+/* Write TOFU_STATS status line.  */
+static void
+write_stats_status (long messages, enum tofu_policy policy,
+                    long first_seen_ago, long most_recent_seen_ago)
+{
+  char numbuf1[35];
+  char numbuf2[35];
+  char numbuf3[35];
+  const char *validity;
+
+  if (messages < 1)
+    validity = "1"; /* Key without history.  */
+  else if (messages < BASIC_TRUST_THRESHOLD)
+    validity = "2"; /* Key with too little history.  */
+  else if (messages < FULL_TRUST_THRESHOLD)
+    validity = "3"; /* Key with enough history for basic trust.  */
+  else
+    validity = "4"; /* Key with a lot of history.  */
+
+  snprintf (numbuf1, sizeof numbuf1, " %ld", messages);
+  *numbuf2 = *numbuf3 = 0;
+  if (first_seen_ago >= 0 && most_recent_seen_ago >= 0)
+    {
+      snprintf (numbuf2, sizeof numbuf2, " %ld", first_seen_ago);
+      snprintf (numbuf3, sizeof numbuf3, " %ld", most_recent_seen_ago);
+    }
+
+  write_status_strings (STATUS_TOFU_STATS,
+                        validity, numbuf1, " 0",
+                        " ", tofu_policy_str (policy),
+                        numbuf2, numbuf3,
+                        NULL);
+}
+
 static void
 show_statistics (struct dbs *dbs, const char *fingerprint,
                 const char *email, const char *user_id,
@@ -2343,120 +2442,125 @@ show_statistics (struct dbs *dbs, const char *fingerprint,
       goto out;
     }
 
+  write_status_text_and_buffer (STATUS_TOFU_USER, fingerprint,
+                                email, strlen (email), 0);
+
   if (! strlist)
-    log_info (_("Have never verified a message signed by key %s!\n"),
-              fingerprint_pp);
+    {
+      log_info (_("Have never verified a message signed by key %s!\n"),
+                fingerprint_pp);
+      write_stats_status (0,  TOFU_POLICY_NONE, -1, -1);
+    }
   else
     {
-      char *tail = NULL;
       signed long messages;
       signed long first_seen_ago;
       signed long most_recent_seen_ago;
 
-      assert (strlist_length (strlist) == 3);
+      log_assert (strlist_length (strlist) == 3);
 
-      errno = 0;
-      messages = strtol (strlist->d, &tail, 0);
-      if (errno || *tail != '\0')
-       /* Abort.  */
-       {
-         log_debug ("%s:%d: Couldn't convert %s (messages) to an int: %s.\n",
-                    __func__, __LINE__, strlist->d, strerror (errno));
-         messages = -1;
-       }
+      string_to_long (&messages, strlist->d, -1, __LINE__);
 
       if (messages == 0 && *strlist->next->d == '\0')
-       /* min(NULL) => NULL => "".  */
-        {
+        { /* min(NULL) => NULL => "".  */
           first_seen_ago = -1;
           most_recent_seen_ago = -1;
         }
       else
        {
-         errno = 0;
-         first_seen_ago = strtol (strlist->next->d, &tail, 0);
-         if (errno || *tail != '\0')
-           /* Abort.  */
-           {
-             log_debug ("%s:%d: Couldn't convert %s (first_seen) to an int: %s.\n",
-                        __func__, __LINE__,
-                        strlist->next->d, strerror (errno));
-             first_seen_ago = 0;
-           }
-
-         errno = 0;
-         most_recent_seen_ago = strtol (strlist->next->next->d, &tail, 0);
-         if (errno || *tail != '\0')
-           /* Abort.  */
-           {
-             log_debug ("%s:%d: Couldn't convert %s (most_recent_seen) to an int: %s.\n",
-                        __func__, __LINE__,
-                        strlist->next->next->d, strerror (errno));
-             most_recent_seen_ago = 0;
-           }
+          string_to_long (&first_seen_ago, strlist->next->d, 0, __LINE__);
+         string_to_long (&most_recent_seen_ago, strlist->next->next->d, 0,
+                          __LINE__);
        }
 
       if (messages == -1 || first_seen_ago == 0)
-        log_info (_("Failed to collect signature statistics"
-                    " for \"%s\" (key %s)\n"),
-                  user_id, fingerprint_pp);
+        {
+          write_stats_status (0, TOFU_POLICY_NONE, -1, -1);
+          log_info (_("Failed to collect signature statistics for \"%s\"\n"
+                      "(key %s)\n"),
+                    user_id, fingerprint_pp);
+        }
       else
        {
          enum tofu_policy policy = get_policy (dbs, fingerprint, email, NULL);
          estream_t fp;
          char *msg;
 
+          write_stats_status (messages, policy,
+                              first_seen_ago, most_recent_seen_ago);
+
          fp = es_fopenmem (0, "rw,samethread");
          if (! fp)
-           log_fatal ("error creating memory stream\n");
+            log_fatal ("error creating memory stream: %s\n",
+                       gpg_strerror (gpg_error_from_syserror()));
 
          if (messages == 0)
-            es_fprintf (fp,
-                        _("Verified 0 messages signed by \"%s\""
-                          " (key: %s, policy: %s)."),
-                        user_id, fingerprint_pp, tofu_policy_str (policy));
+            {
+              es_fprintf (fp, _("Verified %ld messages signed by \"%s\"."),
+                          0L, user_id);
+              es_fputc ('\n', fp);
+            }
          else
            {
-              char *first_seen_ago_str =
-                time_ago_str (first_seen_ago);
-              char *most_recent_seen_ago_str =
-                time_ago_str (most_recent_seen_ago);
+              char *first_seen_ago_str = time_ago_str (first_seen_ago);
 
               /* TRANSLATORS: The final %s is replaced by a string like
                  "7 months, 1 day, 5 minutes, 0 seconds". */
-             es_fprintf (fp, ngettext("Verified %ld message signed by \"%s\""
-                                       " (key: %s, policy: %s) in the past %s.",
-                                       "Verified %ld messages signed by \"%s\""
-                                       " (key: %s, policy: %s) in the past %s.",
-                                       messages),
-                         messages, user_id,
-                         fingerprint_pp, tofu_policy_str (policy),
-                          first_seen_ago_str);
+             es_fprintf (fp,
+                          ngettext("Verified %ld message signed by \"%s\"\n"
+                                   "in the past %s.",
+                                   "Verified %ld messages signed by \"%s\"\n"
+                                   "in the past %s.",
+                                   messages),
+                         messages, user_id, first_seen_ago_str);
 
               if (messages > 1)
                 {
+                  char *tmpstr = time_ago_str (most_recent_seen_ago);
                   es_fputs ("  ", fp);
-                  es_fprintf (fp,
-                              _("The most recent message was verified %s ago."),
-                              most_recent_seen_ago_str);
+                  es_fprintf (fp, _("The most recent message was"
+                                    " verified %s ago."), tmpstr);
+                  xfree (tmpstr);
                 }
-
               xfree (first_seen_ago_str);
-              xfree (most_recent_seen_ago_str);
+
+              if (opt.verbose)
+                {
+                  es_fputs ("  ", fp);
+                  es_fputc ('(', fp);
+                  es_fprintf (fp, _("policy: %s"), tofu_policy_str (policy));
+                  es_fputs (")\n", fp);
+                }
+              else
+                es_fputs ("\n", fp);
             }
 
-         es_fputc (0, fp);
-         if (es_fclose_snatch (fp, (void **) &msg, NULL))
-           log_fatal ("error snatching memory stream\n");
+          {
+            char *tmpmsg, *p;
+            es_fputc (0, fp);
+            if (es_fclose_snatch (fp, (void **) &tmpmsg, NULL))
+              log_fatal ("error snatching memory stream\n");
+            msg = format_text (tmpmsg, 0, 72, 80);
+            es_free (tmpmsg);
+            for (p=msg; *p; p++)
+              if (*p == '~')
+                *p = ' ';
+
+            /* Print a status line but suppress the trailing LF.
+             * Spaces are not percent escaped. */
+            if (*msg)
+              write_status_buffer (STATUS_TOFU_STATS_LONG,
+                                   msg, strlen (msg)-1, -1);
+          }
 
-         log_info ("%s\n", msg);
+         log_string (GPGRT_LOG_INFO, msg);
           xfree (msg);
 
-         if (policy == TOFU_POLICY_AUTO && messages < 10)
+         if (policy == TOFU_POLICY_AUTO && messages < BASIC_TRUST_THRESHOLD)
            {
              char *set_policy_command;
              char *text;
-              char *tmp;
+              char *tmpmsg;
 
              if (messages == 0)
                log_info (_("Warning: we've have yet to see"
@@ -2466,35 +2570,30 @@ show_statistics (struct dbs *dbs, const char *fingerprint,
                             " single message signed by this key!\n"));
 
              set_policy_command =
-               xasprintf ("gpg --tofu-policy bad \"%s\"", fingerprint);
-             /* TRANSLATORS: translate the below text.  We don't
-                directly internationalize that text so that we can
-                tweak it without breaking translations.  */
-             text = ngettext("TOFU: few signatures %d message %s",
-                              "TOFU: few signatures %d messages %s", 1);
-             if (strcmp (text, "TOFU: few signatures %d message %s") == 0)
-                {
-                  text =
-                    (messages == 1?
-                     "Warning: if you think you've seen more than %d message "
-                     "signed by this key, then this key might be a forgery!  "
-                     "Carefully examine the email address for small variations "
-                     "(e.g., additional white space).  If the key is suspect, "
-                     "then use '%s' to mark it as being bad.\n"
-                     :
-                     "Warning: if you think you've seen more than %d messages "
-                     "signed by this key, then this key might be a forgery!  "
-                     "Carefully examine the email address for small variations "
-                     "(e.g., additional white space).  If the key is suspect, "
-                     "then use '%s' to mark it as being bad.\n");
-                }
-
-              tmp = xasprintf (text, messages, set_policy_command);
-              text = format_text (tmp, 0, 72, 80);
-              xfree (tmp);
-             log_info ("%s", text);
+               xasprintf ("gpg --tofu-policy bad %s", fingerprint);
+
+              tmpmsg = xasprintf
+                (ngettext
+                 ("Warning: if you think you've seen more than %ld message "
+                  "signed by this key, then this key might be a forgery!  "
+                  "Carefully examine the email address for small "
+                  "variations.  If the key is suspect, then use\n"
+                  "  %s\n"
+                  "to mark it as being bad.\n",
+                  "Warning: if you think you've seen more than %ld messages "
+                  "signed by this key, then this key might be a forgery!  "
+                      "Carefully examine the email address for small "
+                  "variations.  If the key is suspect, then use\n"
+                  "  %s\n"
+                  "to mark it as being bad.\n",
+                  messages),
+                  messages, set_policy_command);
+              text = format_text (tmpmsg, 0, 72, 80);
+              xfree (tmpmsg);
+             log_string (GPGRT_LOG_INFO, text);
               xfree (text);
-             free (set_policy_command);
+
+             es_free (set_policy_command);
            }
        }
     }
@@ -2635,28 +2734,32 @@ tofu_register (PKT_public_key *pk, const char *user_id,
        because <fingerprint, email, sig_time, sig_digest> is the
        primary key!  */
     log_debug ("SIGNATURES DB contains duplicate records"
-              " <key: %s, %s, time: 0x%lx, sig: %s, %s>."
+              " <%s, %s, 0x%lx, %s, %s>."
               "  Please report.\n",
-              fingerprint_pp, email, (unsigned long) sig_time,
+              fingerprint, email, (unsigned long) sig_time,
               sig_digest, origin);
   else if (c == 1)
     {
       already_verified = 1;
       if (DBG_TRUST)
        log_debug ("Already observed the signature"
-                  " <key: %s, %s, time: 0x%lx, sig: %s, %s>\n",
-                  fingerprint_pp, email, (unsigned long) sig_time,
+                  " <%s, %s, 0x%lx, %s, %s>\n",
+                  fingerprint, email, (unsigned long) sig_time,
                   sig_digest, origin);
     }
+  else if (opt.dry_run)
+    {
+      log_info ("TOFU database update skipped due to --dry-run\n");
+    }
   else
     /* This is the first time that we've seen this signature.
        Record it.  */
     {
       if (DBG_TRUST)
        log_debug ("TOFU: Saving signature <%s, %s, %s>\n",
-                  fingerprint_pp, email, sig_digest);
+                  fingerprint, email, sig_digest);
 
-      assert (c == 0);
+      log_assert (c == 0);
 
       rc = sqlite3_stepx
        (db->db, &db->s.register_insert, NULL, NULL, &err,
@@ -2720,20 +2823,20 @@ tofu_wot_trust_combine (int tofu_base, int wot_base)
   int wot = wot_base & TRUST_MASK;
   int upper = (tofu_base & ~TRUST_MASK) | (wot_base & ~TRUST_MASK);
 
-  assert (tofu == TRUST_UNKNOWN
-         || tofu == TRUST_EXPIRED
-         || tofu == TRUST_UNDEFINED
-         || tofu == TRUST_NEVER
-         || tofu == TRUST_MARGINAL
-         || tofu == TRUST_FULLY
-         || tofu == TRUST_ULTIMATE);
-  assert (wot == TRUST_UNKNOWN
-         || wot == TRUST_EXPIRED
-         || wot == TRUST_UNDEFINED
-         || wot == TRUST_NEVER
-         || wot == TRUST_MARGINAL
-         || wot == TRUST_FULLY
-         || wot == TRUST_ULTIMATE);
+  log_assert (tofu == TRUST_UNKNOWN
+              || tofu == TRUST_EXPIRED
+              || tofu == TRUST_UNDEFINED
+              || tofu == TRUST_NEVER
+              || tofu == TRUST_MARGINAL
+              || tofu == TRUST_FULLY
+              || tofu == TRUST_ULTIMATE);
+  log_assert (wot == TRUST_UNKNOWN
+              || wot == TRUST_EXPIRED
+              || wot == TRUST_UNDEFINED
+              || wot == TRUST_NEVER
+              || wot == TRUST_MARGINAL
+              || wot == TRUST_FULLY
+              || wot == TRUST_ULTIMATE);
 
   /* We first consider negative trust policys.  These trump positive
      trust policies.  */
@@ -2746,17 +2849,30 @@ tofu_wot_trust_combine (int tofu_base, int wot_base)
 
   /* Now we only have positive or neutral trust policies.  We take
      the max.  */
-  if (tofu == TRUST_ULTIMATE || wot == TRUST_ULTIMATE)
+  if (tofu == TRUST_ULTIMATE)
+    return upper | TRUST_ULTIMATE | TRUST_FLAG_TOFU_BASED;
+  if (wot == TRUST_ULTIMATE)
     return upper | TRUST_ULTIMATE;
-  if (tofu == TRUST_FULLY || wot == TRUST_FULLY)
+
+  if (tofu == TRUST_FULLY)
+    return upper | TRUST_FULLY | TRUST_FLAG_TOFU_BASED;
+  if (wot == TRUST_FULLY)
     return upper | TRUST_FULLY;
-  if (tofu == TRUST_MARGINAL || wot == TRUST_MARGINAL)
+
+  if (tofu == TRUST_MARGINAL)
+    return upper | TRUST_MARGINAL | TRUST_FLAG_TOFU_BASED;
+  if (wot == TRUST_MARGINAL)
     return upper | TRUST_MARGINAL;
-  if (tofu == TRUST_UNDEFINED || wot == TRUST_UNDEFINED)
+
+  if (tofu == TRUST_UNDEFINED)
+    return upper | TRUST_UNDEFINED | TRUST_FLAG_TOFU_BASED;
+  if (wot == TRUST_UNDEFINED)
     return upper | TRUST_UNDEFINED;
+
   return upper | TRUST_UNKNOWN;
 }
 
+
 /* Return the validity (TRUST_NEVER, etc.) of the binding
    <FINGERPRINT, USER_ID>.
 
@@ -2826,7 +2942,7 @@ tofu_set_policy (kbnode_t kb, enum tofu_policy policy)
   PKT_public_key *pk;
   char *fingerprint = NULL;
 
-  assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
+  log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
   pk = kb->pkt->pkt.public_key;
 
   dbs = opendbs ();
@@ -2906,8 +3022,8 @@ tofu_get_policy (PKT_public_key *pk, PKT_user_id *user_id,
   char *email;
 
   /* Make sure PK is a primary key.  */
-  assert (pk->main_keyid[0] == pk->keyid[0]
-         && pk->main_keyid[1] == pk->keyid[1]);
+  log_assert (pk->main_keyid[0] == pk->keyid[0]
+              && pk->main_keyid[1] == pk->keyid[1]);
 
   dbs = opendbs ();
   if (! dbs)
index f46aeea..82de7cb 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "keydb.h"
@@ -561,7 +560,7 @@ clean_sigs_from_uid (kbnode_t keyblock, kbnode_t uidnode,
   kbnode_t node;
   u32 keyid[2];
 
-  assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  log_assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
 
   keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
 
@@ -654,8 +653,8 @@ clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
   PKT_user_id *uid = uidnode->pkt->pkt.user_id;
   int deleted = 0;
 
-  assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
-  assert (uidnode->pkt->pkttype==PKT_USER_ID);
+  log_assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
 
   /* Skip valid user IDs, compacted user IDs, and non-self-signed user
      IDs if --allow-non-selfsigned-uid is set. */
@@ -706,8 +705,8 @@ clean_one_uid (kbnode_t keyblock, kbnode_t uidnode, int noisy, int self_only,
 {
   int dummy = 0;
 
-  assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
-  assert (uidnode->pkt->pkttype==PKT_USER_ID);
+  log_assert (keyblock->pkt->pkttype==PKT_PUBLIC_KEY);
+  log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
 
   if (!uids_cleaned)
     uids_cleaned = &dummy;
index 8f2b2cb..195a006 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 #ifndef DISABLE_REGEX
 #include <sys/types.h>
@@ -379,16 +378,16 @@ do_sync(void)
       }
 }
 
-static const char *
-trust_model_string(void)
+const char *
+trust_model_string (int model)
 {
-  switch(opt.trust_model)
+  switch (model)
     {
     case TM_CLASSIC:  return "classic";
-    case TM_PGP:      return "PGP";
+    case TM_PGP:      return "pgp";
     case TM_EXTERNAL: return "external";
-    case TM_TOFU:     return "TOFU";
-    case TM_TOFU_PGP: return "TOFU+PGP";
+    case TM_TOFU:     return "tofu";
+    case TM_TOFU_PGP: return "tofu+pgp";
     case TM_ALWAYS:   return "always";
     case TM_DIRECT:   return "direct";
     default:          return "unknown";
@@ -421,13 +420,13 @@ how_to_fix_the_trustdb ()
 
   log_info (_("You may try to re-create the trustdb using the commands:\n"));
   log_info ("  cd %s\n", default_homedir ());
-  log_info ("  gpg2 --export-ownertrust > otrust.tmp\n");
+  log_info ("  %s --export-ownertrust > otrust.tmp\n", GPG_NAME);
 #ifdef HAVE_W32_SYSTEM
   log_info ("  del %s\n", name);
 #else
   log_info ("  rm %s\n", name);
 #endif
-  log_info ("  gpg2 --import-ownertrust < otrust.tmp\n");
+  log_info ("  %s --import-ownertrust < otrust.tmp\n", GPG_NAME);
   log_info (_("If that does not work, please consult the manual\n"));
 }
 
@@ -471,7 +470,8 @@ init_trustdb ()
        }
 
       if(opt.verbose)
-       log_info(_("using %s trust model\n"),trust_model_string());
+       log_info(_("using %s trust model\n"),
+                 trust_model_string (opt.trust_model));
     }
 
   if (opt.trust_model==TM_PGP || opt.trust_model==TM_CLASSIC
@@ -523,7 +523,7 @@ check_trustdb ()
     }
   else
     log_info (_("no need for a trustdb check with '%s' trust model\n"),
-             trust_model_string());
+             trust_model_string(opt.trust_model));
 }
 
 
@@ -539,7 +539,7 @@ update_trustdb()
     validate_keys (1);
   else
     log_info (_("no need for a trustdb update with '%s' trust model\n"),
-             trust_model_string());
+             trust_model_string(opt.trust_model));
 }
 
 void
@@ -1079,9 +1079,9 @@ tdb_get_validity_core (PKT_public_key *pk, PKT_user_id *uid,
            tofu_validity = TRUST_NEVER;
          else
            {
-             assert (tl == TRUST_MARGINAL
-                     || tl == TRUST_FULLY
-                     || tl == TRUST_ULTIMATE);
+             log_assert (tl == TRUST_MARGINAL
+                          || tl == TRUST_FULLY
+                          || tl == TRUST_ULTIMATE);
 
              if (tl > tofu_validity)
                /* XXX: We we really want the max?  */
@@ -1962,8 +1962,10 @@ validate_keys (int interactive)
 
   klist = utk_list;
 
-  log_info ("marginals needed: %d  completes needed: %d  trust model: %s\n",
-            opt.marginals_needed, opt.completes_needed, trust_model_string ());
+  if (!opt.quiet)
+    log_info ("marginals needed: %d  completes needed: %d  trust model: %s\n",
+              opt.marginals_needed, opt.completes_needed,
+              trust_model_string (opt.trust_model));
 
   for (depth=0; depth < opt.max_cert_depth; depth++)
     {
@@ -2048,10 +2050,11 @@ validate_keys (int interactive)
       for (kar=keys; kar->keyblock; kar++)
           store_validation_status (depth, kar->keyblock, stored);
 
-      log_info (_("depth: %d  valid: %3d  signed: %3d"
-                  "  trust: %d-, %dq, %dn, %dm, %df, %du\n"),
-                depth, valids, key_count, ot_unknown, ot_undefined,
-                ot_never, ot_marginal, ot_full, ot_ultimate );
+      if (!opt.quiet)
+        log_info (_("depth: %d  valid: %3d  signed: %3d"
+                    "  trust: %d-, %dq, %dn, %dm, %df, %du\n"),
+                  depth, valids, key_count, ot_unknown, ot_undefined,
+                  ot_never, ot_marginal, ot_full, ot_ultimate );
 
       /* Build a new kdlist from all fully valid keys in KEYS */
       if (klist != utk_list)
@@ -2120,8 +2123,9 @@ validate_keys (int interactive)
       else
         {
           tdbio_write_nextcheck (next_expire);
-          log_info (_("next trustdb check due at %s\n"),
-                    strtimestamp (next_expire));
+          if (!opt.quiet)
+            log_info (_("next trustdb check due at %s\n"),
+                      strtimestamp (next_expire));
         }
 
       rc2 = tdbio_update_version_record ();
index 718f779..7e1307d 100644 (file)
@@ -21,7 +21,7 @@
 #ifndef G10_TRUSTDB_H
 #define G10_TRUSTDB_H
 
-/* Trust values must be sorted in ascending order */
+/* Trust values must be sorted in ascending order! */
 #define TRUST_MASK      15
 #define TRUST_UNKNOWN    0  /* o: not yet calculated/assigned */
 #define TRUST_EXPIRED    1  /* e: calculation may be invalid */
 #define TRUST_MARGINAL   4  /* m: marginally trusted */
 #define TRUST_FULLY      5  /* f: fully trusted      */
 #define TRUST_ULTIMATE   6  /* u: ultimately trusted */
-/* trust values not covered by the mask */
-#define TRUST_FLAG_REVOKED 32 /* r: revoked */
-#define TRUST_FLAG_SUB_REVOKED 64 /* r: revoked but for subkeys */
-#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */
+/* Trust values not covered by the mask. */
+#define TRUST_FLAG_REVOKED        32 /* r: revoked */
+#define TRUST_FLAG_SUB_REVOKED    64 /* r: revoked but for subkeys */
+#define TRUST_FLAG_DISABLED      128 /* d: key/uid disabled */
 #define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */
+#define TRUST_FLAG_TOFU_BASED    512 /* The trust value is based on
+                                      * the TOFU information.  */
 
 /* Private value used in tofu.c - must be different from the trust
    values.  */
@@ -117,6 +119,7 @@ void check_trustdb (void);
 void update_trustdb (void);
 int setup_trustdb( int level, const char *dbname );
 void how_to_fix_the_trustdb (void);
+const char *trust_model_string (int model);
 void init_trustdb( void );
 void tdb_check_trustdb_stale (void);
 void sync_trustdb( void );
index 2efc89d..5cd0bd7 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
index e17d099..05963c8 100644 (file)
 EXTRA_DIST = ChangeLog-2011
 
 bin_PROGRAMS = g13
+sbin_PROGRAMS = g13-syshelp
+
+noinst_PROGRAMS = $(module_tests)
+TESTS = $(module_tests)
 
 AM_CPPFLAGS = -I$(top_srcdir)/common
 
@@ -31,17 +35,45 @@ AM_CFLAGS =  $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(NPTH_CFLAGS)
 g13_SOURCES = \
        g13.c g13.h \
        g13-common.c g13-common.h \
-       keyblob.h \
-       utils.c utils.h \
+       keyblob.c keyblob.h \
+       g13tuple.c g13tuple.h \
        server.c server.h \
        create.c create.h \
        mount.c mount.h \
+       suspend.c suspend.h \
        mountinfo.c mountinfo.h \
+       call-syshelp.c call-syshelp.h \
        runner.c runner.h \
        backend.c backend.h \
        be-encfs.c be-encfs.h \
-       be-truecrypt.c be-truecrypt.h
+       be-truecrypt.c be-truecrypt.h \
+       be-dmcrypt.c be-dmcrypt.h
 
 g13_LDADD = $(libcommonpth) \
        $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
        $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
+
+
+g13_syshelp_SOURCES = \
+       g13-syshelp.c g13-syshelp.h \
+       g13-common.c g13-common.h \
+       keyblob.h \
+       g13tuple.c g13tuple.h \
+       sh-cmd.c \
+       sh-blockdev.c \
+       sh-dmcrypt.c
+
+g13_syshelp_LDADD = $(libcommon) \
+       $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \
+       $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
+
+
+module_tests = t-g13tuple
+t_common_ldadd = $(libcommon) $(LIBGCRYPT_LIBS) \
+                $(LIBASSUAN_LIBS)
+
+t_g13tuple_SOURCES = t-g13tuple.c g13tuple.c
+t_g13tuple_LDADD = $(t_common_ldadd)
+
+
+$(PROGRAMS) : $(libcommon) $(libcommonpth)
index 7b08cd5..dd21768 100644 (file)
@@ -23,6 +23,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <sys/stat.h>
 
 #include "g13.h"
 #include "i18n.h"
 #include "backend.h"
 #include "be-encfs.h"
 #include "be-truecrypt.h"
+#include "be-dmcrypt.h"
+#include "call-syshelp.h"
 
-
+#define no_such_backend(a) _no_such_backend ((a), __func__)
 static gpg_error_t
-no_such_backend (int conttype)
+_no_such_backend (int conttype, const char *func)
 {
-  log_error ("invalid backend %d given - this is most likely a bug\n",
-             conttype);
+  log_error ("invalid backend %d given in %s - this is most likely a bug\n",
+             conttype, func);
   return gpg_error (GPG_ERR_INTERNAL);
 }
 
 
+/* Parse NAME and return the corresponding content type.  If the name
+   is not known, a error message is printed and zero returned.  If
+   NAME is NULL the supported backend types are listed and 0 is
+   returned. */
+int
+be_parse_conttype_name (const char *name)
+{
+  static struct { const char *name; int conttype; } names[] = {
+    { "encfs",    CONTTYPE_ENCFS },
+    { "dm-crypt", CONTTYPE_DM_CRYPT }
+  };
+  int i;
+
+  if (!name)
+    {
+      log_info ("Known backend types:\n");
+      for (i=0; i < DIM (names); i++)
+        log_info ("    %s\n", names[i].name);
+      return 0;
+    }
+
+  for (i=0; i < DIM (names); i++)
+    {
+      if (!strcmp (names[i].name, name))
+        return names[i].conttype;
+    }
+
+  log_error ("invalid backend type '%s' given\n", name);
+  return 0;
+}
+
+
 /* Return true if CONTTYPE is supported by us.  */
 int
 be_is_supported_conttype (int conttype)
@@ -48,6 +83,7 @@ be_is_supported_conttype (int conttype)
   switch (conttype)
     {
     case CONTTYPE_ENCFS:
+    case CONTTYPE_DM_CRYPT:
       return 1;
 
     default:
@@ -56,6 +92,64 @@ be_is_supported_conttype (int conttype)
 }
 
 
+/* Create a lock file for the container FNAME and store the lock at
+ * R_LOCK and return 0.  On error return an error code and store NULL
+ * at R_LOCK.  */
+gpg_error_t
+be_take_lock_for_create (ctrl_t ctrl, const char *fname, dotlock_t *r_lock)
+{
+  gpg_error_t err;
+  dotlock_t lock = NULL;
+  struct stat sb;
+
+  *r_lock = NULL;
+
+  /* A DM-crypt container requires special treatment by using the
+     syshelper fucntions.  */
+  if (ctrl->conttype == CONTTYPE_DM_CRYPT)
+    {
+      /*  */
+      err = call_syshelp_set_device (ctrl, fname);
+      goto leave;
+    }
+
+
+  /* A quick check to see that no container with that name already
+     exists.  */
+  if (!access (fname, F_OK))
+    {
+      err = gpg_error (GPG_ERR_EEXIST);
+      goto leave;
+    }
+
+  /* Take a lock and proceed with the creation.  If there is a lock we
+     immediately return an error because for creation it does not make
+     sense to wait.  */
+  lock = dotlock_create (fname, 0);
+  if (!lock)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (dotlock_take (lock, 0))
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Check again that the file does not exist.  */
+  err = stat (fname, &sb)? 0 : gpg_error (GPG_ERR_EEXIST);
+
+ leave:
+  if (!err)
+    {
+      *r_lock = lock;
+      lock = NULL;
+    }
+  dotlock_destroy (lock);
+  return err;
+}
+
 
 /* If the backend requires a separate file or directory for the
    container, return its name by computing it from FNAME which gives
@@ -75,6 +169,9 @@ be_get_detached_name (int conttype, const char *fname,
     case CONTTYPE_ENCFS:
       return be_encfs_get_detached_name (fname, r_name, r_isdir);
 
+    case CONTTYPE_DM_CRYPT:
+      return 0;
+
     default:
       return no_such_backend (conttype);
     }
@@ -92,13 +189,16 @@ be_create_new_keys (int conttype, membuf_t *mb)
     case CONTTYPE_TRUECRYPT:
       return be_truecrypt_create_new_keys (mb);
 
+    case CONTTYPE_DM_CRYPT:
+      return 0;
+
     default:
       return no_such_backend (conttype);
     }
 }
 
 
-/*  Dispatcher to the backend's create function.  */
+/* Dispatcher to the backend's create function.  */
 gpg_error_t
 be_create_container (ctrl_t ctrl, int conttype,
                      const char *fname, int fd, tupledesc_t tuples,
@@ -111,13 +211,16 @@ be_create_container (ctrl_t ctrl, int conttype,
     case CONTTYPE_ENCFS:
       return be_encfs_create_container (ctrl, fname, tuples, r_id);
 
+    case CONTTYPE_DM_CRYPT:
+      return be_dmcrypt_create_container (ctrl);
+
     default:
       return no_such_backend (conttype);
     }
 }
 
 
-/*  Dispatcher to the backend's mount function.  */
+/* Dispatcher to the backend's mount function.  */
 gpg_error_t
 be_mount_container (ctrl_t ctrl, int conttype,
                     const char *fname,  const char *mountpoint,
@@ -128,6 +231,46 @@ be_mount_container (ctrl_t ctrl, int conttype,
     case CONTTYPE_ENCFS:
       return be_encfs_mount_container (ctrl, fname, mountpoint, tuples, r_id);
 
+    case CONTTYPE_DM_CRYPT:
+      return be_dmcrypt_mount_container (ctrl, fname, mountpoint, tuples);
+
+    default:
+      return no_such_backend (conttype);
+    }
+}
+
+
+/* Dispatcher to the backend's suspend function.  */
+gpg_error_t
+be_suspend_container (ctrl_t ctrl, int conttype, const char *fname)
+{
+  switch (conttype)
+    {
+    case CONTTYPE_ENCFS:
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+    case CONTTYPE_DM_CRYPT:
+      return be_dmcrypt_suspend_container (ctrl, fname);
+
+    default:
+      return no_such_backend (conttype);
+    }
+}
+
+
+/* Dispatcher to the backend's resume function.  */
+gpg_error_t
+be_resume_container (ctrl_t ctrl, int conttype, const char *fname,
+                     tupledesc_t tuples)
+{
+  switch (conttype)
+    {
+    case CONTTYPE_ENCFS:
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+    case CONTTYPE_DM_CRYPT:
+      return be_dmcrypt_resume_container (ctrl, fname, tuples);
+
     default:
       return no_such_backend (conttype);
     }
index 20d2966..66d9cd5 100644 (file)
 #define G13_BACKEND_H
 
 #include "../common/membuf.h"
-#include "utils.h"  /* For tupledesc_t */
+#include "g13tuple.h"
 
-int         be_is_supported_conttype (int conttype);
+int be_parse_conttype_name (const char *name);
+int be_is_supported_conttype (int conttype);
+gpg_error_t be_take_lock_for_create (ctrl_t ctrl, const char *fname,
+                                     dotlock_t *r_lock);
 gpg_error_t be_get_detached_name (int conttype, const char *fname,
                                   char **r_name, int *r_isdir);
 gpg_error_t be_create_new_keys (int conttype, membuf_t *mb);
@@ -36,6 +39,10 @@ gpg_error_t be_mount_container (ctrl_t ctrl, int conttype,
                                 const char *fname, const char *mountpoint,
                                 tupledesc_t tuples,
                                 unsigned int *r_id);
+gpg_error_t be_suspend_container (ctrl_t ctrl, int conttype,
+                                  const char *fname);
+gpg_error_t be_resume_container (ctrl_t ctrl, int conttype,
+                                 const char *fname, tupledesc_t tuples);
 
 
 #endif /*G13_BACKEND_H*/
diff --git a/g13/be-dmcrypt.c b/g13/be-dmcrypt.c
new file mode 100644 (file)
index 0000000..e5e9b33
--- /dev/null
@@ -0,0 +1,99 @@
+/* be-dmcrypt.c - The DM-Crypt based backend
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "g13.h"
+#include "i18n.h"
+#include "keyblob.h"
+#include "call-syshelp.h"
+#include "be-dmcrypt.h"
+
+
+/* Create the container using the current device.
+ * information in TUPLES. */
+gpg_error_t
+be_dmcrypt_create_container (ctrl_t ctrl)
+{
+  gpg_error_t err;
+
+  err = call_syshelp_run_create (ctrl, CONTTYPE_DM_CRYPT);
+
+  return err;
+}
+
+
+/* Mount the container described by the filename FNAME and the keyblob
+ * information in TUPLES.  On success the runner id is stored at R_ID. */
+gpg_error_t
+be_dmcrypt_mount_container (ctrl_t ctrl,
+                            const char *fname, const char *mountpoint,
+                            tupledesc_t tuples)
+{
+  gpg_error_t err;
+
+  err = call_syshelp_set_device (ctrl, fname);
+  if (err)
+    goto leave;
+
+  err = call_syshelp_run_mount (ctrl, CONTTYPE_DM_CRYPT, mountpoint, tuples);
+
+ leave:
+  return err;
+}
+
+
+/* Suspend the container described by the filename FNAME.  */
+gpg_error_t
+be_dmcrypt_suspend_container (ctrl_t ctrl, const char *fname)
+{
+  gpg_error_t err;
+
+  err = call_syshelp_set_device (ctrl, fname);
+  if (err)
+    goto leave;
+
+  err = call_syshelp_run_suspend (ctrl, CONTTYPE_DM_CRYPT);
+
+ leave:
+  return err;
+}
+
+
+/* Resume the container described by the filename FNAME and the keyblob
+ * information in TUPLES.  */
+gpg_error_t
+be_dmcrypt_resume_container (ctrl_t ctrl, const char *fname, tupledesc_t tuples)
+{
+  gpg_error_t err;
+
+  err = call_syshelp_set_device (ctrl, fname);
+  if (err)
+    goto leave;
+
+  err = call_syshelp_run_resume (ctrl, CONTTYPE_DM_CRYPT, tuples);
+
+ leave:
+  return err;
+}
diff --git a/g13/be-dmcrypt.h b/g13/be-dmcrypt.h
new file mode 100644 (file)
index 0000000..d74e09f
--- /dev/null
@@ -0,0 +1,35 @@
+/* be-dmcrypt.h - Public defs for the DM-Crypt based backend
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef G13_BE_DMCRYPT_H
+#define G13_BE_DMCRYPT_H
+
+#include "backend.h"
+
+gpg_error_t be_dmcrypt_create_container (ctrl_t ctrl);
+gpg_error_t be_dmcrypt_mount_container (ctrl_t ctrl,
+                                        const char *fname,
+                                        const char *mountpoint,
+                                        tupledesc_t tuples);
+gpg_error_t be_dmcrypt_suspend_container (ctrl_t ctrl, const char *fname);
+gpg_error_t be_dmcrypt_resume_container (ctrl_t ctrl, const char *fname,
+                                         tupledesc_t tuples);
+
+
+#endif /*G13_BE_DMCRYPT_H*/
diff --git a/g13/call-syshelp.c b/g13/call-syshelp.c
new file mode 100644 (file)
index 0000000..bc93d20
--- /dev/null
@@ -0,0 +1,488 @@
+/* call-syshelp.c - Communication with g13-syshelp
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <assert.h>
+#include <npth.h>
+
+#include "g13.h"
+#include <assuan.h>
+#include "i18n.h"
+#include "g13tuple.h"
+#include "keyblob.h"
+#include "membuf.h"
+#include "create.h"
+
+
+/* Local data for this module.  A pointer to this is stored in the
+   CTRL object of each connection.  */
+struct call_syshelp_s
+{
+  assuan_context_t assctx;  /* The Assuan context for the current
+                               g13-syshep connection.  */
+};
+
+
+/* Parameter used with the CREATE command.  */
+struct create_parm_s
+{
+  assuan_context_t ctx;
+  ctrl_t ctrl;
+  membuf_t plaintext;
+  unsigned int expect_plaintext:1;
+  unsigned int got_plaintext:1;
+};
+
+
+/* Parameter used with the MOUNT command.  */
+struct mount_parm_s
+{
+  assuan_context_t ctx;
+  ctrl_t ctrl;
+  const void *keyblob;
+  size_t keybloblen;
+};
+
+
+
+
+\f
+/* Fork off the syshelp tool if this has not already been done.  On
+   success stores the current Assuan context for the syshelp tool at
+   R_CTX.  */
+static gpg_error_t
+start_syshelp (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  assuan_fd_t no_close_list[3];
+  int i;
+
+  *r_ctx = NULL;
+
+  if (ctrl->syshelp_local && (*r_ctx = ctrl->syshelp_local->assctx))
+    return 0; /* Already set.  */
+
+  if (opt.verbose)
+    log_info ("starting a new syshelp\n");
+
+  if (!ctrl->syshelp_local)
+    {
+      ctrl->syshelp_local = xtrycalloc (1, sizeof *ctrl->syshelp_local);
+      if (!ctrl->syshelp_local)
+        return gpg_error_from_syserror ();
+    }
+
+  if (es_fflush (NULL))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error flushing pending output: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  i = 0;
+  if (log_get_fd () != -1)
+    no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
+  no_close_list[i++] = assuan_fd_from_posix_fd (es_fileno (es_stderr));
+  no_close_list[i] = ASSUAN_INVALID_FD;
+
+  err = assuan_new (&ctx);
+  if (err)
+    {
+      log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
+      return err;
+    }
+
+  /* Call userv to start g13-syshelp.  This userv script needs to be
+   * installed under the name "gnupg-g13-syshelp":
+   *
+   *   if ( glob service-user root
+   *      )
+   *       reset
+   *       suppress-args
+   *       execute /home/wk/b/gnupg/g13/g13-syshelp -v
+   *   else
+   *       error Nothing to do for this service-user
+   *   fi
+   *   quit
+   */
+  {
+    const char *argv[4];
+
+    argv[0] = "userv";
+    argv[1] = "root";
+    argv[2] = "gnupg-g13-syshelp";
+    argv[3] = NULL;
+
+    err = assuan_pipe_connect (ctx, "/usr/bin/userv", argv,
+                               no_close_list, NULL, NULL, 0);
+  }
+  if (err)
+    {
+      log_error ("can't connect to '%s': %s %s\n",
+                 "g13-syshelp", gpg_strerror (err), gpg_strsource (err));
+      log_info ("(is userv and its gnupg-g13-syshelp script installed?)\n");
+      assuan_release (ctx);
+      return err;
+    }
+
+  *r_ctx = ctrl->syshelp_local->assctx = ctx;
+
+  if (DBG_IPC)
+    log_debug ("connection to g13-syshelp established\n");
+
+  return 0;
+}
+
+
+/* Release local resources associated with CTRL.  */
+void
+call_syshelp_release (ctrl_t ctrl)
+{
+  if (!ctrl)
+    return;
+  if (ctrl->syshelp_local)
+    {
+      assuan_release (ctrl->syshelp_local->assctx);
+      ctrl->syshelp_local->assctx = NULL;
+      xfree (ctrl->syshelp_local);
+      ctrl->syshelp_local = NULL;
+    }
+}
+
+
+/* Send the DEVICE command to the syshelper.  FNAME is the name of the
+   device.  */
+gpg_error_t
+call_syshelp_set_device (ctrl_t ctrl, const char *fname)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  char *line = NULL;
+
+  err = start_syshelp (ctrl, &ctx);
+  if (err)
+    goto leave;
+
+  line = xtryasprintf ("DEVICE %s", fname);
+  if (!line)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+
+ leave:
+  xfree (line);
+  return err;
+}
+
+
+\f
+static gpg_error_t
+create_status_cb (void *opaque, const char *line)
+{
+  struct create_parm_s *parm = opaque;
+
+  if (has_leading_keyword (line, "PLAINTEXT_FOLLOWS"))
+    parm->expect_plaintext = 1;
+
+  return 0;
+}
+
+
+static gpg_error_t
+create_data_cb (void *opaque, const void *data, size_t datalen)
+{
+  struct create_parm_s *parm = opaque;
+  gpg_error_t err = 0;
+
+  if (!parm->expect_plaintext)
+    {
+      log_error ("status line for data missing\n");
+      err = gpg_error (GPG_ERR_UNEXPECTED);
+    }
+  else if (data)
+    {
+      put_membuf (&parm->plaintext, data, datalen);
+    }
+  else
+    {
+      parm->expect_plaintext = 0;
+      parm->got_plaintext = 1;
+    }
+
+  return err;
+}
+
+
+static gpg_error_t
+create_inq_cb (void *opaque, const char *line)
+{
+  struct create_parm_s *parm = opaque;
+  gpg_error_t err;
+
+  if (has_leading_keyword (line, "ENCKEYBLOB"))
+    {
+      void *plaintext;
+      size_t plaintextlen;
+
+      if (!parm->got_plaintext)
+        err = gpg_error (GPG_ERR_UNEXPECTED);
+      else if (!(plaintext = get_membuf (&parm->plaintext, &plaintextlen)))
+        err = gpg_error_from_syserror ();
+      else
+        {
+          void *ciphertext;
+          size_t ciphertextlen;
+
+          log_printhex ("plain", plaintext, plaintextlen);
+          err = g13_encrypt_keyblob (parm->ctrl,
+                                     plaintext, plaintextlen,
+                                     &ciphertext, &ciphertextlen);
+          wipememory (plaintext, plaintextlen);
+          xfree (plaintext);
+          if (err)
+            log_error ("error encrypting keyblob: %s\n", gpg_strerror (err));
+          else
+            {
+              err = assuan_send_data (parm->ctx, ciphertext, ciphertextlen);
+              xfree (ciphertext);
+              if (err)
+                log_error ("sending ciphertext to g13-syshelp failed: %s\n",
+                           gpg_strerror (err));
+            }
+        }
+    }
+  else
+    err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
+
+  return err;
+}
+
+
+/* Run the CREATE command on the current device.  CONTTYPES gives the
+   requested content type for the new container.  */
+gpg_error_t
+call_syshelp_run_create (ctrl_t ctrl, int conttype)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  struct create_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+
+  err = start_syshelp (ctrl, &ctx);
+  if (err)
+    goto leave;
+
+  /* tty_get ("waiting for debugger"); */
+  /* tty_kill_prompt (); */
+
+  parm.ctx = ctx;
+  parm.ctrl = ctrl;
+  init_membuf (&parm.plaintext, 512);
+  if (conttype == CONTTYPE_DM_CRYPT)
+    {
+      err = assuan_transact (ctx, "CREATE dm-crypt",
+                             create_data_cb, &parm,
+                             create_inq_cb, &parm,
+                             create_status_cb, &parm);
+    }
+  else
+    {
+      log_error ("invalid backend type %d given\n", conttype);
+      err = GPG_ERR_INTERNAL;
+      goto leave;
+    }
+
+ leave:
+  xfree (get_membuf (&parm.plaintext, NULL));
+  return err;
+}
+
+
+\f
+static gpg_error_t
+mount_status_cb (void *opaque, const char *line)
+{
+  struct mount_parm_s *parm = opaque;
+
+  /* Nothing right now.  */
+  (void)parm;
+  (void)line;
+
+  return 0;
+}
+
+
+/* Inquire callback for MOUNT and RESUME.  */
+static gpg_error_t
+mount_inq_cb (void *opaque, const char *line)
+{
+  struct mount_parm_s *parm = opaque;
+  gpg_error_t err;
+
+  if (has_leading_keyword (line, "KEYBLOB"))
+    {
+      int setconfidential = !assuan_get_flag (parm->ctx, ASSUAN_CONFIDENTIAL);
+
+      if (setconfidential)
+        assuan_begin_confidential (parm->ctx);
+      err = assuan_send_data (parm->ctx, parm->keyblob, parm->keybloblen);
+      if (setconfidential)
+        assuan_end_confidential (parm->ctx);
+      if (err)
+        log_error ("sending keyblob to g13-syshelp failed: %s\n",
+                   gpg_strerror (err));
+    }
+  else
+    err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
+
+  return err;
+}
+
+
+/*
+ * Run the MOUNT command on the current device.  CONTTYPES gives the
+ * requested content type for the new container.  MOUNTPOINT the
+ * desired mount point or NULL for default.
+ */
+gpg_error_t
+call_syshelp_run_mount (ctrl_t ctrl, int conttype, const char *mountpoint,
+                        tupledesc_t tuples)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  struct mount_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+
+  err = start_syshelp (ctrl, &ctx);
+  if (err)
+    goto leave;
+
+  /* tty_get ("waiting for debugger"); */
+  /* tty_kill_prompt (); */
+
+  parm.ctx = ctx;
+  parm.ctrl = ctrl;
+  if (conttype == CONTTYPE_DM_CRYPT)
+    {
+      ref_tupledesc (tuples);
+      parm.keyblob = get_tupledesc_data (tuples, &parm.keybloblen);
+      err = assuan_transact (ctx, "MOUNT dm-crypt",
+                             NULL, NULL,
+                             mount_inq_cb, &parm,
+                             mount_status_cb, &parm);
+      unref_tupledesc (tuples);
+    }
+  else
+    {
+      (void)mountpoint; /* Not used.  */
+      log_error ("invalid backend type %d given\n", conttype);
+      err = GPG_ERR_INTERNAL;
+      goto leave;
+    }
+
+ leave:
+  return err;
+}
+
+
+\f
+/*
+ * Run the SUSPEND command on the current device.  CONTTYPES gives the
+ * requested content type for the new container.
+ */
+gpg_error_t
+call_syshelp_run_suspend (ctrl_t ctrl, int conttype)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+
+  err = start_syshelp (ctrl, &ctx);
+  if (err)
+    goto leave;
+
+  if (conttype == CONTTYPE_DM_CRYPT)
+    {
+      err = assuan_transact (ctx, "SUSPEND dm-crypt",
+                             NULL, NULL,
+                             NULL, NULL,
+                             NULL, NULL);
+    }
+  else
+    {
+      log_error ("invalid backend type %d given\n", conttype);
+      err = GPG_ERR_INTERNAL;
+      goto leave;
+    }
+
+ leave:
+  return err;
+}
+
+
+\f
+/* Run the RESUME command on the current device.  CONTTYPES gives the
+   requested content type for the container.  */
+gpg_error_t
+call_syshelp_run_resume (ctrl_t ctrl, int conttype, tupledesc_t tuples)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  struct mount_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+
+  err = start_syshelp (ctrl, &ctx);
+  if (err)
+    goto leave;
+
+  /* tty_get ("waiting for debugger"); */
+  /* tty_kill_prompt (); */
+
+  parm.ctx = ctx;
+  parm.ctrl = ctrl;
+  if (conttype == CONTTYPE_DM_CRYPT)
+    {
+      ref_tupledesc (tuples);
+      parm.keyblob = get_tupledesc_data (tuples, &parm.keybloblen);
+      err = assuan_transact (ctx, "RESUME dm-crypt",
+                             NULL, NULL,
+                             mount_inq_cb, &parm,
+                             NULL, NULL);
+      unref_tupledesc (tuples);
+    }
+  else
+    {
+      log_error ("invalid backend type %d given\n", conttype);
+      err = GPG_ERR_INTERNAL;
+      goto leave;
+    }
+
+ leave:
+  return err;
+}
diff --git a/g13/call-syshelp.h b/g13/call-syshelp.h
new file mode 100644 (file)
index 0000000..c2578f2
--- /dev/null
@@ -0,0 +1,36 @@
+/* call-syshelp.h - Communication with g13-syshelp
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_G13_CALL_SYSHELP_H
+#define GNUPG_G13_CALL_SYSHELP_H
+
+#include "g13tuple.h"
+
+void call_syshelp_release (ctrl_t ctrl);
+gpg_error_t call_syshelp_set_device (ctrl_t ctrl, const char *fname);
+gpg_error_t call_syshelp_run_create (ctrl_t ctrl, int conttype);
+gpg_error_t call_syshelp_run_mount (ctrl_t ctrl, int conttype,
+                                    const char *mountpoint,
+                                    tupledesc_t tuples);
+gpg_error_t call_syshelp_run_suspend (ctrl_t ctrl, int conttype);
+gpg_error_t call_syshelp_run_resume (ctrl_t ctrl, int conttype,
+                                     tupledesc_t tuples);
+
+
+#endif /*GNUPG_G13_CALL_SYSHELP_H*/
index 91b290c..0126f5b 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "keyblob.h"
 #include "backend.h"
-#include "utils.h"
+#include "g13tuple.h"
 #include "../common/call-gpg.h"
 
 /* Create a new blob with all the session keys and other meta
@@ -103,17 +103,16 @@ create_new_keyblob (ctrl_t ctrl, int is_detached,
    CTRL the result is a single OpenPGP binary message, a single
    special OpenPGP packet encapsulating a CMS message or a
    concatenation of both with the CMS packet being the last.  */
-static gpg_error_t
-encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen,
-                 strlist_t keys,
-                 void **r_encblob, size_t *r_encbloblen)
+gpg_error_t
+g13_encrypt_keyblob (ctrl_t ctrl, void *keyblob, size_t keybloblen,
+                     void **r_encblob, size_t *r_encbloblen)
 {
   gpg_error_t err;
 
   /* FIXME:  For now we only implement OpenPGP.  */
   err = gpg_encrypt_blob (ctrl, opt.gpg_program, opt.gpg_arguments,
                           keyblob, keybloblen,
-                          keys,
+                          ctrl->recipients,
                           r_encblob, r_encbloblen);
 
   return err;
@@ -219,11 +218,10 @@ write_keyblob (const char *filename,
 
 
 /* Create a new container under the name FILENAME and intialize it
-   using the current settings.  KEYS is a list of public keys to which
-   the container will be encrypted.  If the file already exists an
-   error is returned.  */
+   using the current settings.  If the file already exists an error is
+   returned.  */
 gpg_error_t
-g13_create_container (ctrl_t ctrl, const char *filename, strlist_t keys)
+g13_create_container (ctrl_t ctrl, const char *filename)
 {
   gpg_error_t err;
   dotlock_t lock;
@@ -236,38 +234,13 @@ g13_create_container (ctrl_t ctrl, const char *filename, strlist_t keys)
   tupledesc_t tuples = NULL;
   unsigned int dummy_rid;
 
-  if (!keys)
+  if (!ctrl->recipients)
     return gpg_error (GPG_ERR_NO_PUBKEY);
 
-  /* A quick check to see that no container with that name already
-     exists.  */
-  if (!access (filename, F_OK))
-    return gpg_error (GPG_ERR_EEXIST);
-
-  /* Take a lock and proceed with the creation.  If there is a lock we
-     immediately return an error because for creation it does not make
-     sense to wait.  */
-  lock = dotlock_create (filename, 0);
-  if (!lock)
-    return gpg_error_from_syserror ();
-  if (dotlock_take (lock, 0))
-    {
-      err = gpg_error_from_syserror ();
-      goto leave;
-    }
-  else
-    err = 0;
-
-  /* Check again that the file does not exist.  */
-  {
-      struct stat sb;
+  err = be_take_lock_for_create (ctrl, filename, &lock);
+  if (err)
+    goto leave;
 
-      if (!stat (filename, &sb))
-        {
-          err = gpg_error (GPG_ERR_EEXIST);
-          goto leave;
-        }
-  }
   /* And a possible detached file or directory may not exist either.  */
   err = be_get_detached_name (ctrl->conttype, filename,
                               &detachedname, &detachedisdir);
@@ -284,29 +257,32 @@ g13_create_container (ctrl_t ctrl, const char *filename, strlist_t keys)
         }
     }
 
-  /* Create a new keyblob.  */
-  err = create_new_keyblob (ctrl, !!detachedname, &keyblob, &keybloblen);
-  if (err)
-    goto leave;
-
-  /* Encrypt that keyblob.  */
-  err = encrypt_keyblob (ctrl, keyblob, keybloblen, keys,
-                         &enckeyblob, &enckeybloblen);
-  if (err)
-    goto leave;
-
-  /* Put a copy of the keyblob into a tuple structure.  */
-  err = create_tupledesc (&tuples, keyblob, keybloblen);
-  if (err)
-    goto leave;
-  keyblob = NULL;
-  /* if (opt.verbose) */
-  /*   dump_keyblob (tuples); */
-
-  /* Write out the header, the encrypted keyblob and some padding. */
-  err = write_keyblob (filename, enckeyblob, enckeybloblen);
-  if (err)
-    goto leave;
+  if (ctrl->conttype != CONTTYPE_DM_CRYPT)
+    {
+      /* Create a new keyblob.  */
+      err = create_new_keyblob (ctrl, !!detachedname, &keyblob, &keybloblen);
+      if (err)
+        goto leave;
+
+      /* Encrypt that keyblob.  */
+      err = g13_encrypt_keyblob (ctrl, keyblob, keybloblen,
+                                 &enckeyblob, &enckeybloblen);
+      if (err)
+        goto leave;
+
+      /* Put a copy of the keyblob into a tuple structure.  */
+      err = create_tupledesc (&tuples, keyblob, keybloblen);
+      if (err)
+        goto leave;
+      keyblob = NULL;
+      /* if (opt.verbose) */
+      /*   dump_keyblob (tuples); */
+
+      /* Write out the header, the encrypted keyblob and some padding. */
+      err = write_keyblob (filename, enckeyblob, enckeybloblen);
+      if (err)
+        goto leave;
+    }
 
   /* Create and append the container.  FIXME: We should pass the
      estream object in addition to the filename, so that the backend
index cc4ddfd..ec4224c 100644 (file)
 #ifndef G13_CREATE_H
 #define G13_CREATE_H
 
-gpg_error_t g13_create_container (ctrl_t ctrl, const char *filename,
-                                  strlist_t keys);
+gpg_error_t g13_encrypt_keyblob (ctrl_t ctrl,
+                                 void *keyblob, size_t keybloblen,
+                                 void **r_encblob, size_t *r_encbloblen);
+gpg_error_t g13_create_container (ctrl_t ctrl, const char *filename);
 
 
 #endif /*G13_CREATE_H*/
diff --git a/g13/g13-syshelp.c b/g13/g13-syshelp.c
new file mode 100644 (file)
index 0000000..645730f
--- /dev/null
@@ -0,0 +1,753 @@
+/* g13-syshelp.c - Helper for disk key management with GnuPG
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#include <unistd.h>
+
+#include "g13-syshelp.h"
+
+#include <gcrypt.h>
+#include <assuan.h>
+
+#include "i18n.h"
+#include "sysutils.h"
+#include "asshelp.h"
+#include "../common/init.h"
+#include "keyblob.h"
+
+
+enum cmd_and_opt_values {
+  aNull = 0,
+  oQuiet       = 'q',
+  oVerbose     = 'v',
+  oRecipient   = 'r',
+
+  aGPGConfList  = 500,
+
+  oDebug,
+  oDebugLevel,
+  oDebugAll,
+  oDebugNone,
+  oDebugWait,
+  oDebugAllowCoreDump,
+  oLogFile,
+  oNoLogFile,
+  oAuditLog,
+
+  oOutput,
+
+  oAgentProgram,
+  oGpgProgram,
+  oType,
+
+  oDisplay,
+  oTTYname,
+  oTTYtype,
+  oLCctype,
+  oLCmessages,
+  oXauthority,
+
+  oStatusFD,
+  oLoggerFD,
+
+  oNoVerbose,
+  oNoSecmemWarn,
+  oHomedir,
+  oDryRun,
+  oNoDetach,
+
+  oNoRandomSeedFile,
+  oFakedSystemTime
+ };
+
+
+static ARGPARSE_OPTS opts[] = {
+
+  ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
+
+  ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
+  ARGPARSE_s_n (oQuiet,        "quiet",  N_("be somewhat more quiet")),
+
+  ARGPARSE_s_s (oDebug, "debug", "@"),
+  ARGPARSE_s_s (oDebugLevel, "debug-level",
+                N_("|LEVEL|set the debugging level to LEVEL")),
+  ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+  ARGPARSE_s_n (oDebugNone, "debug-none", "@"),
+  ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
+  ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
+
+  ARGPARSE_end ()
+};
+
+
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_MOUNT_VALUE  , "mount"  },
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { 0, NULL }
+  };
+
+
+/* The timer tick interval used by the idle task.  */
+#define TIMERTICK_INTERVAL_SEC     (1)
+
+/* It is possible that we are currently running under setuid permissions.  */
+static int maybe_setuid = 1;
+
+/* Helper to implement --debug-level and --debug.  */
+static const char *debug_level;
+static unsigned int debug_value;
+
+
+/* Local prototypes.  */
+static void g13_syshelp_deinit_default_ctrl (ctrl_t ctrl);
+static void release_tab_items (tab_item_t tab);
+static tab_item_t parse_g13tab (const char *username);
+
+
+\f
+static const char *
+my_strusage( int level )
+{
+  const char *p;
+
+  switch (level)
+    {
+    case 11: p = "@G13@-syshelp (@GNUPG@)";
+      break;
+    case 13: p = VERSION; break;
+    case 17: p = PRINTABLE_OS_NAME; break;
+    case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
+      break;
+    case 1:
+    case 40: p = _("Usage: @G13@-syshelp [options] [files] (-h for help)");
+      break;
+    case 41:
+      p = _("Syntax: @G13@-syshelp [options] [files]\n"
+            "Helper to perform root-only tasks for g13\n");
+      break;
+
+    case 31: p = "\nHome: "; break;
+    case 32: p = opt.homedir; break;
+
+    default: p = NULL; break;
+    }
+  return p;
+}
+
+
+/* Setup the debugging.  With a DEBUG_LEVEL of NULL only the active
+   debug flags are propagated to the subsystems.  With DEBUG_LEVEL
+   set, a specific set of debug flags is set; and individual debugging
+   flags will be added on top.  */
+static void
+set_debug (void)
+{
+  int numok = (debug_level && digitp (debug_level));
+  int numlvl = numok? atoi (debug_level) : 0;
+
+  if (!debug_level)
+    ;
+  else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
+    opt.debug = 0;
+  else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
+    opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
+  else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
+    opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
+  else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
+    opt.debug = (DBG_IPC_VALUE|DBG_MOUNT_VALUE|DBG_CRYPTO_VALUE);
+  else if (!strcmp (debug_level, "guru") || numok)
+    {
+      opt.debug = ~0;
+      /* if (numok) */
+      /*   opt.debug &= ~(DBG_HASHING_VALUE); */
+    }
+  else
+    {
+      log_error (_("invalid debug-level '%s' given\n"), debug_level);
+      g13_exit(2);
+    }
+
+  opt.debug |= debug_value;
+
+  if (opt.debug && !opt.verbose)
+    opt.verbose = 1;
+  if (opt.debug)
+    opt.quiet = 0;
+
+  if (opt.debug & DBG_CRYPTO_VALUE )
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
+  gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+
+  if (opt.debug)
+    parse_debug_flag (NULL, &opt.debug, debug_flags);
+}
+
+
+int
+main ( int argc, char **argv)
+{
+  ARGPARSE_ARGS pargs;
+  int orig_argc;
+  char **orig_argv;
+  gpg_error_t err = 0;
+  /* const char *fname; */
+  int may_coredump;
+  FILE *configfp = NULL;
+  char *configname = NULL;
+  unsigned configlineno;
+  int parse_debug = 0;
+  int no_more_options = 0;
+  int default_config =1;
+  char *logfile = NULL;
+  /* int debug_wait = 0; */
+  int use_random_seed = 1;
+  /* int nodetach = 0; */
+  /* int nokeysetup = 0; */
+  struct server_control_s ctrl;
+
+  /*mtrace();*/
+
+  early_system_init ();
+  gnupg_reopen_std (G13_NAME "-syshelp");
+  set_strusage (my_strusage);
+  gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+
+  log_set_prefix (G13_NAME "-syshelp", 1);
+
+  /* Make sure that our subsystems are ready.  */
+  i18n_init ();
+  init_common_subsystems (&argc, &argv);
+
+  /* Check that the Libgcrypt is suitable.  */
+  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
+    log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
+               NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
+
+  /* Take extra care of the random pool.  */
+  gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
+
+  may_coredump = disable_core_dumps ();
+
+  g13_init_signals ();
+
+  dotlock_create (NULL, 0); /* Register locking cleanup.  */
+
+  opt.session_env = session_env_new ();
+  if (!opt.session_env)
+    log_fatal ("error allocating session environment block: %s\n",
+               strerror (errno));
+
+  opt.homedir = default_homedir ();
+  /* Fixme: We enable verbose mode here because there is currently no
+     way to do this when starting g13-syshelp.  To fix that we should
+     add a g13-syshelp.conf file in /etc/gnupg.  */
+  opt.verbose = 1;
+
+  /* First check whether we have a debug option on the commandline.  */
+  orig_argc = argc;
+  orig_argv = argv;
+  pargs.argc = &argc;
+  pargs.argv = &argv;
+  pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
+  while (arg_parse( &pargs, opts))
+    {
+      if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
+        parse_debug++;
+    }
+
+  /* Initialize the secure memory. */
+  gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+  maybe_setuid = 0;
+
+  /*
+     Now we are now working under our real uid
+  */
+
+  /* Setup malloc hooks. */
+  {
+    struct assuan_malloc_hooks malloc_hooks;
+
+    malloc_hooks.malloc = gcry_malloc;
+    malloc_hooks.realloc = gcry_realloc;
+    malloc_hooks.free = gcry_free;
+    assuan_set_malloc_hooks (&malloc_hooks);
+  }
+
+  /* Prepare libassuan.  */
+  assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+  /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/
+  setup_libassuan_logging (&opt.debug);
+
+  /* Setup a default control structure for command line mode.  */
+  memset (&ctrl, 0, sizeof ctrl);
+  g13_syshelp_init_default_ctrl (&ctrl);
+  ctrl.no_server = 1;
+  ctrl.status_fd = -1; /* No status output. */
+
+  if (default_config )
+    configname = make_filename (gnupg_sysconfdir (),
+                                G13_NAME"-syshelp.conf", NULL);
+
+  argc        = orig_argc;
+  argv        = orig_argv;
+  pargs.argc  = &argc;
+  pargs.argv  = &argv;
+  pargs.flags =  1;  /* Do not remove the args.  */
+
+ next_pass:
+  if (configname)
+    {
+      configlineno = 0;
+      configfp = fopen (configname, "r");
+      if (!configfp)
+        {
+          if (default_config)
+            {
+              if (parse_debug)
+                log_info (_("NOTE: no default option file '%s'\n"), configname);
+            }
+          else
+            {
+              log_error (_("option file '%s': %s\n"),
+                         configname, strerror(errno));
+              g13_exit(2);
+            }
+          xfree (configname);
+          configname = NULL;
+        }
+      if (parse_debug && configname)
+        log_info (_("reading options from '%s'\n"), configname);
+      default_config = 0;
+    }
+
+  while (!no_more_options
+         && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
+    {
+      switch (pargs.r_opt)
+        {
+        case oQuiet: opt.quiet = 1; break;
+
+        case oDryRun: opt.dry_run = 1; break;
+
+        case oVerbose:
+          opt.verbose++;
+          gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+          break;
+        case oNoVerbose:
+          opt.verbose = 0;
+          gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+          break;
+
+        case oLogFile: logfile = pargs.r.ret_str; break;
+        case oNoLogFile: logfile = NULL; break;
+
+        case oNoDetach: /*nodetach = 1; */break;
+
+        case oDebug:
+          if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
+            {
+              pargs.r_opt = ARGPARSE_INVALID_ARG;
+              pargs.err = ARGPARSE_PRINT_ERROR;
+            }
+            break;
+        case oDebugAll: debug_value = ~0; break;
+        case oDebugNone: debug_value = 0; break;
+        case oDebugLevel: debug_level = pargs.r.ret_str; break;
+        case oDebugWait: /*debug_wait = pargs.r.ret_int; */break;
+        case oDebugAllowCoreDump:
+          may_coredump = enable_core_dumps ();
+          break;
+
+        case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
+        case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
+
+        case oHomedir: opt.homedir = pargs.r.ret_str; break;
+
+        case oFakedSystemTime:
+          {
+            time_t faked_time = isotime2epoch (pargs.r.ret_str);
+            if (faked_time == (time_t)(-1))
+              faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
+            gnupg_set_time (faked_time, 0);
+          }
+          break;
+
+        case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;
+
+        case oNoRandomSeedFile: use_random_seed = 0; break;
+
+        default:
+          pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
+          break;
+       }
+    }
+
+  if (configfp)
+    {
+      fclose (configfp);
+      configfp = NULL;
+      /* Keep a copy of the config filename. */
+      opt.config_filename = configname;
+      configname = NULL;
+      goto next_pass;
+    }
+  xfree (configname);
+  configname = NULL;
+
+  if (!opt.config_filename)
+    opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);
+
+  if (log_get_errorcount(0))
+    g13_exit(2);
+
+  /* Now that we have the options parsed we need to update the default
+     control structure.  */
+  g13_syshelp_init_default_ctrl (&ctrl);
+
+  if (may_coredump && !opt.quiet)
+    log_info (_("WARNING: program may create a core file!\n"));
+
+  if (logfile)
+    {
+      log_set_file (logfile);
+      log_set_prefix (NULL, 1|2|4);
+    }
+
+  if (gnupg_faked_time_p ())
+    {
+      gnupg_isotime_t tbuf;
+
+      log_info (_("WARNING: running with faked system time: "));
+      gnupg_get_isotime (tbuf);
+      dump_isotime (tbuf);
+      log_printf ("\n");
+    }
+
+  /* Print any pending secure memory warnings.  */
+  gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+
+  /* Setup the debug flags for all subsystems.  */
+  set_debug ();
+
+  /* Install a regular exit handler to make real sure that the secure
+     memory gets wiped out.  */
+  g13_install_emergency_cleanup ();
+
+  /* Terminate if we found any error until now.  */
+  if (log_get_errorcount(0))
+    g13_exit (2);
+
+  /* Set the standard GnuPG random seed file.  */
+  if (use_random_seed)
+    {
+      char *p = make_filename (opt.homedir, "random_seed", NULL);
+      gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
+      xfree(p);
+    }
+
+  /* Get the UID of the caller.  */
+#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+  {
+    const char *uidstr;
+    struct passwd *pwd = NULL;
+
+    uidstr = getenv ("USERV_UID");
+
+    /* Print a quick note if we are not started via userv.  */
+    if (!uidstr)
+      {
+        if (getuid ())
+          {
+            log_info ("WARNING: Not started via userv\n");
+            ctrl.fail_all_cmds = 1;
+          }
+        ctrl.client.uid = getuid ();
+      }
+    else
+      {
+        unsigned long myuid;
+
+        errno = 0;
+        myuid = strtoul (uidstr, NULL, 10);
+        if (myuid == ULONG_MAX && errno)
+          {
+            log_info ("WARNING: Started via broken userv: %s\n",
+                      strerror (errno));
+            ctrl.fail_all_cmds = 1;
+            ctrl.client.uid = getuid ();
+          }
+        else
+          ctrl.client.uid = (uid_t)myuid;
+      }
+
+    pwd = getpwuid (ctrl.client.uid);
+    if (!pwd || !*pwd->pw_name)
+      {
+        log_info ("WARNING: Name for UID not found: %s\n", strerror (errno));
+        ctrl.fail_all_cmds = 1;
+        ctrl.client.uname = xstrdup ("?");
+      }
+    else
+      ctrl.client.uname = xstrdup (pwd->pw_name);
+
+    /* Check that the user name does not contain a directory
+       separator. */
+    if (strchr (ctrl.client.uname, '/'))
+      {
+        log_info ("WARNING: Invalid user name passed\n");
+        ctrl.fail_all_cmds = 1;
+      }
+  }
+#else /*!HAVE_PWD_H || !HAVE_GETPWUID*/
+  log_info ("WARNING: System does not support required syscalls\n");
+  ctrl.fail_all_cmds = 1;
+  ctrl.client.uid = getuid ();
+  ctrl.client.uname = xstrdup ("?");
+#endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/
+
+  /* Read the table entries for this user.  */
+  if (!ctrl.fail_all_cmds
+      && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname)))
+    ctrl.fail_all_cmds = 1;
+
+  /* Start the server.  */
+  err = syshelp_server (&ctrl);
+  if (err)
+    log_error ("server exited with error: %s <%s>\n",
+               gpg_strerror (err), gpg_strsource (err));
+
+  /* Cleanup.  */
+  g13_syshelp_deinit_default_ctrl (&ctrl);
+  g13_exit (0);
+  return 8; /*NOTREACHED*/
+}
+
+
+/* Store defaults into the per-connection CTRL object.  */
+void
+g13_syshelp_init_default_ctrl (ctrl_t ctrl)
+{
+  ctrl->conttype = CONTTYPE_DM_CRYPT;
+}
+
+/* Release all resources allocated by default in the CTRl object.  */
+static void
+g13_syshelp_deinit_default_ctrl (ctrl_t ctrl)
+{
+  xfree (ctrl->client.uname);
+  release_tab_items (ctrl->client.tab);
+}
+
+
+/* Release the list of g13tab itejms at TAB.  */
+static void
+release_tab_items (tab_item_t tab)
+{
+  while (tab)
+    {
+      tab_item_t next = tab->next;
+      xfree (tab->mountpoint);
+      xfree (tab);
+      tab = next;
+    }
+}
+
+
+void
+g13_syshelp_i_know_what_i_am_doing (void)
+{
+  const char * const yesfile = "Yes-g13-I-know-what-I-am-doing";
+  char *fname;
+
+  fname = make_filename (gnupg_sysconfdir (), yesfile, NULL);
+  if (access (fname, F_OK))
+    {
+      log_info ("*******************************************************\n");
+      log_info ("* The G13 support for DM-Crypt is new and not matured.\n");
+      log_info ("* Bugs or improper use may delete all your disks!\n");
+      log_info ("* To confirm that you are ware of this risk, create\n");
+      log_info ("* the file '%s'.\n", fname);
+      log_info ("*******************************************************\n");
+      exit (1);
+    }
+  xfree (fname);
+}
+
+
+/* Parse the /etc/gnupg/g13tab for user USERNAME.  Return a table for
+   the user on success.  Return NULL on error and print
+   diagnostics. */
+static tab_item_t
+parse_g13tab (const char *username)
+{
+  gpg_error_t err;
+  int c, n;
+  char line[512];
+  char *p;
+  char *fname;
+  estream_t fp;
+  int lnr;
+  char **words = NULL;
+  tab_item_t table = NULL;
+  tab_item_t *tabletail, ti;
+
+  fname = make_filename (gnupg_sysconfdir (), G13_NAME"tab", NULL);
+  fp = es_fopen (fname, "r");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
+      goto leave;
+    }
+
+  tabletail = &table;
+  err = 0;
+  lnr = 0;
+  while (es_fgets (line, DIM(line)-1, fp))
+    {
+      lnr++;
+      n = strlen (line);
+      if (!n || line[n-1] != '\n')
+        {
+          /* Eat until end of line. */
+          while ((c=es_getc (fp)) != EOF && c != '\n')
+            ;
+          err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
+                           : GPG_ERR_INCOMPLETE_LINE);
+          log_error (_("file '%s', line %d: %s\n"),
+                     fname, lnr, gpg_strerror (err));
+          continue;
+        }
+      line[--n] = 0; /* Chop the LF. */
+      if (n && line[n-1] == '\r')
+        line[--n] = 0; /* Chop an optional CR. */
+
+      /* Allow for empty lines and spaces */
+      for (p=line; spacep (p); p++)
+        ;
+      if (!*p || *p == '#')
+        continue;
+
+      /* Parse the line.  The format is
+       * <username> <blockdev> [<label>|"-" [<mountpoint>]]
+       */
+      xfree (words);
+      words = strtokenize (p, " \t");
+      if (!words)
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      if (!words[0] || !words[1])
+        {
+          log_error (_("file '%s', line %d: %s\n"),
+                     fname, lnr, gpg_strerror (GPG_ERR_SYNTAX));
+          continue;
+        }
+      if (!(*words[1] == '/'
+            || !strncmp (words[1], "PARTUUID=", 9)
+            || !strncmp (words[1], "partuuid=", 9)))
+        {
+          log_error (_("file '%s', line %d: %s\n"),
+                     fname, lnr, "Invalid block device syntax");
+          continue;
+        }
+      if (words[2])
+        {
+          if (strlen (words[2]) > 16 || strchr (words[2], '/'))
+            {
+              log_error (_("file '%s', line %d: %s\n"),
+                         fname, lnr, "Label too long or invalid syntax");
+              continue;
+            }
+
+          if (words[3] && *words[3] != '/')
+            {
+              log_error (_("file '%s', line %d: %s\n"),
+                         fname, lnr, "Invalid mountpoint syntax");
+              continue;
+            }
+        }
+      if (strcmp (words[0], username))
+        continue; /* Skip entries for other usernames!  */
+
+      ti = xtrymalloc (sizeof *ti + strlen (words[1]));
+      if (!ti)
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      ti->next = NULL;
+      ti->label = NULL;
+      ti->mountpoint = NULL;
+      strcpy (ti->blockdev, *words[1]=='/'? words[1] : words[1]+9);
+      if (words[2])
+        {
+          if (strcmp (words[2], "-")
+              && !(ti->label = xtrystrdup (words[2])))
+            {
+              err = gpg_error_from_syserror ();
+              xfree (ti);
+              break;
+            }
+          if (words[3] && !(ti->mountpoint = xtrystrdup (words[3])))
+            {
+              err = gpg_error_from_syserror ();
+              xfree (ti->label);
+              xfree (ti);
+              break;
+            }
+        }
+      *tabletail = ti;
+      tabletail = &ti->next;
+    }
+
+  if (!err && !es_feof (fp))
+    err = gpg_error_from_syserror ();
+  if (err)
+    log_error (_("error reading '%s', line %d: %s\n"),
+               fname, lnr, gpg_strerror (err));
+
+ leave:
+  xfree (words);
+  es_fclose (fp);
+  xfree (fname);
+  if (err)
+    {
+      release_tab_items (table);
+      return NULL;
+    }
+  return table;
+}
diff --git a/g13/g13-syshelp.h b/g13/g13-syshelp.h
new file mode 100644 (file)
index 0000000..dae2bd0
--- /dev/null
@@ -0,0 +1,95 @@
+/* g130syshelp.h - Global definitions for G13-SYSHELP.
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef G13_SYSHELP_H
+#define G13_SYSHELP_H
+
+#include "g13-common.h"
+#include "g13tuple.h"
+
+struct tab_item_s;
+typedef struct tab_item_s *tab_item_t;
+
+struct tab_item_s
+{
+  tab_item_t next;
+  char *label;       /* Optional malloced label for that entry.  */
+  char *mountpoint;  /* NULL or a malloced mountpoint.  */
+  char blockdev[1];  /* String with the name of the block device.  If
+                        it starts with a slash is is a regular device
+                        name, otherwise it is a PARTUUID.  */
+};
+
+
+
+/* Forward declaration for an object defined in g13-sh-cmd.c.  */
+struct server_local_s;
+
+/* Session control object.  This object is passed down to most
+   functions.  The default values for it are set by
+   g13_syshelp_init_default_ctrl(). */
+struct server_control_s
+{
+  int no_server;      /* We are not running under server control */
+  int  status_fd;     /* Only for non-server mode */
+  struct server_local_s *server_local;
+
+  struct {
+    uid_t uid;     /* UID of the client calling use.  */
+    char *uname;
+    tab_item_t tab;/* Linked list with the g13tab items for this user.  */
+  } client;
+
+  /* Flag indicating that we should fail all commands.  */
+  int fail_all_cmds;
+
+  /* Type of the current container.  See the CONTTYPE_ constants.  */
+  int conttype;
+
+  /* A pointer into client.tab with the selected tab line or NULL. */
+  tab_item_t devti;
+};
+
+
+/*-- g13-syshelp.c --*/
+void g13_syshelp_init_default_ctrl (struct server_control_s *ctrl);
+void g13_syshelp_i_know_what_i_am_doing (void);
+
+/*-- sh-cmd.c --*/
+gpg_error_t syshelp_server (ctrl_t ctrl);
+gpg_error_t sh_encrypt_keyblob (ctrl_t ctrl,
+                                const void *keyblob, size_t keybloblen,
+                                char **r_enckeyblob, size_t *r_enckeybloblen);
+
+/*-- sh-blockdev.c --*/
+gpg_error_t sh_blockdev_getsz (const char *name, unsigned long long *r_nblocks);
+gpg_error_t sh_is_empty_partition (const char *name);
+
+/*-- sh-dmcrypt.c --*/
+gpg_error_t sh_dmcrypt_create_container (ctrl_t ctrl, const char *devname,
+                                         estream_t devfp);
+gpg_error_t sh_dmcrypt_mount_container (ctrl_t ctrl, const char *devname,
+                                        tupledesc_t keyblob);
+gpg_error_t sh_dmcrypt_suspend_container (ctrl_t ctrl, const char *devname);
+gpg_error_t sh_dmcrypt_resume_container (ctrl_t ctrl, const char *devname,
+                                         tupledesc_t keyblob);
+
+
+
+#endif /*G13_SYSHELP_H*/
index 7a8d775..4489b2f 100644 (file)
--- a/g13/g13.c
+++ b/g13/g13.c
 #include "runner.h"
 #include "create.h"
 #include "mount.h"
+#include "suspend.h"
 #include "mountinfo.h"
+#include "backend.h"
+#include "call-syshelp.h"
 
 
 enum cmd_and_opt_values {
@@ -56,6 +59,8 @@ enum cmd_and_opt_values {
   aCreate,
   aMount,
   aUmount,
+  aSuspend,
+  aResume,
   aServer,
 
   oOptions,
@@ -73,6 +78,7 @@ enum cmd_and_opt_values {
 
   oAgentProgram,
   oGpgProgram,
+  oType,
 
   oDisplay,
   oTTYname,
@@ -106,6 +112,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aCreate, "create", N_("Create a new file system container")),
   ARGPARSE_c (aMount,  "mount",  N_("Mount a file system container") ),
   ARGPARSE_c (aUmount, "umount", N_("Unmount a file system container") ),
+  ARGPARSE_c (aSuspend, "suspend", N_("Suspend a file system container") ),
+  ARGPARSE_c (aResume,  "resume",  N_("Resume a file system container") ),
   ARGPARSE_c (aServer, "server", N_("Run in server mode")),
 
   ARGPARSE_c (aGPGConfList, "gpgconf-list", "@"),
@@ -114,6 +122,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_group (301, N_("@\nOptions:\n ")),
 
   ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
+  ARGPARSE_s_s (oType, "type", N_("|NAME|use container format NAME")),
 
   ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")),
   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
@@ -455,7 +464,7 @@ main ( int argc, char **argv)
           if (default_config)
             {
               if (parse_debug)
-                log_info (_("NOTE: no default option file '%s'\n"), configname);
+                log_info (_("Note: no default option file '%s'\n"), configname);
             }
           else
             {
@@ -486,7 +495,8 @@ main ( int argc, char **argv)
         case aServer:
         case aMount:
         case aUmount:
-          /* nokeysetup = 1; */
+        case aSuspend:
+        case aResume:
         case aCreate:
           set_cmd (&cmd, pargs.r_opt);
           break;
@@ -570,6 +580,19 @@ main ( int argc, char **argv)
           add_to_strlist (&recipients, pargs.r.ret_str);
           break;
 
+        case oType:
+          if (!strcmp (pargs.r.ret_str, "help"))
+            {
+              be_parse_conttype_name (NULL);
+              g13_exit (0);
+            }
+          cmdline_conttype = be_parse_conttype_name (pargs.r.ret_str);
+          if (!cmdline_conttype)
+            {
+              pargs.r_opt = ARGPARSE_INVALID_ARG;
+              pargs.err = ARGPARSE_PRINT_ERROR;
+            }
+          break;
 
         default:
           pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
@@ -608,6 +631,8 @@ main ( int argc, char **argv)
   /* Now that we have the options parsed we need to update the default
      control structure.  */
   g13_init_default_ctrl (&ctrl);
+  ctrl.recipients = recipients;
+  recipients = NULL;
 
   if (nogreeting)
     greeting = 0;
@@ -629,7 +654,7 @@ main ( int argc, char **argv)
 
       for (i=0; i < argc; i++)
         if (argv[i][0] == '-' && argv[i][1] == '-')
-          log_info (_("NOTE: '%s' is not considered an option\n"), argv[i]);
+          log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
     }
 
 
@@ -681,7 +706,7 @@ main ( int argc, char **argv)
       strlist_t sl;
       int failed = 0;
 
-      for (sl = recipients; sl; sl = sl->next)
+      for (sl = ctrl->recipients; sl; sl = sl->next)
         if (check_encryption_key ())
           failed = 1;
       if (failed)
@@ -721,7 +746,7 @@ main ( int argc, char **argv)
           log_error ("server exited with error: %s <%s>\n",
                      gpg_strerror (err), gpg_strsource (err));
         else
-          shutdown_pending++;
+          g13_request_shutdown ();
       }
       break;
 
@@ -730,12 +755,12 @@ main ( int argc, char **argv)
         if (argc != 1)
           wrong_args ("--create filename");
         start_idle_task ();
-        err = g13_create_container (&ctrl, argv[0], recipients);
+        err = g13_create_container (&ctrl, argv[0]);
         if (err)
           log_error ("error creating a new container: %s <%s>\n",
                      gpg_strerror (err), gpg_strsource (err));
         else
-          shutdown_pending++;
+          g13_request_shutdown ();
       }
       break;
 
@@ -751,11 +776,47 @@ main ( int argc, char **argv)
       }
       break;
 
+    case aUmount: /* Unmount a mounted container.  */
+      {
+        if (argc != 1)
+          wrong_args ("--umount filename");
+        err = GPG_ERR_NOT_IMPLEMENTED;
+        log_error ("error unmounting container '%s': %s <%s>\n",
+                   *argv, gpg_strerror (err), gpg_strsource (err));
+      }
+      break;
+
+    case aSuspend: /* Suspend a container. */
+      {
+        /* Fixme: Should we add a suspend all container option?  */
+        if (argc != 1)
+          wrong_args ("--suspend filename");
+        err = g13_suspend_container (&ctrl, argv[0]);
+        if (err)
+          log_error ("error suspending container '%s': %s <%s>\n",
+                     *argv, gpg_strerror (err), gpg_strsource (err));
+      }
+      break;
+
+    case aResume: /* Resume a suspended container. */
+      {
+        /* Fixme: Should we add a resume all container option?  */
+        if (argc != 1)
+          wrong_args ("--resume filename");
+        err = g13_resume_container (&ctrl, argv[0]);
+        if (err)
+          log_error ("error resuming container '%s': %s <%s>\n",
+                     *argv, gpg_strerror (err), gpg_strsource (err));
+      }
+      break;
+
     default:
       log_error (_("invalid command (there is no implicit command)\n"));
       break;
     }
 
+  g13_deinit_default_ctrl (&ctrl);
+
   if (!err)
     join_idle_task ();
 
@@ -767,12 +828,30 @@ main ( int argc, char **argv)
 
 /* Store defaults into the per-connection CTRL object.  */
 void
-g13_init_default_ctrl (struct server_control_s *ctrl)
+g13_init_default_ctrl (ctrl_t ctrl)
 {
   ctrl->conttype = cmdline_conttype? cmdline_conttype : CONTTYPE_ENCFS;
 }
 
 
+/* Release remaining resources allocated in the CTRL object.  */
+void
+g13_deinit_default_ctrl (ctrl_t ctrl)
+{
+  call_syshelp_release (ctrl);
+  FREE_STRLIST (ctrl->recipients);
+}
+
+
+/* Request a shutdown.  This can be used when the process should
+ * finish instead of running the idle task.  */
+void
+g13_request_shutdown (void)
+{
+  shutdown_pending++;
+}
+
+
 /* This function is called for each signal we catch.  It is run in the
    main context or the one of a NPth thread and thus it is not
    restricted in what it may do.  */
@@ -905,9 +984,11 @@ idle_task (void *dummy_arg)
        }
 
       if (ret <= 0)
-       /* Interrupt or timeout.  Will be handled when calculating the
-          next timeout.  */
-       continue;
+        {
+          /* Interrupt or timeout.  Will be handled when calculating the
+             next timeout.  */
+          continue;
+        }
 
       /* Here one would add processing of file descriptors.  */
     }
index 303c84b..e694890 100644 (file)
--- a/g13/g13.h
+++ b/g13/g13.h
@@ -25,6 +25,9 @@
 
 /* Forward declaration for an object defined in server.c.  */
 struct server_local_s;
+/* Forward declaration for an object defined in call-syshelp.c.  */
+struct call_syshelp_s;
+
 
 /* Session control object.  This object is passed down to most
    functions.  The default values for it are set by
@@ -34,6 +37,7 @@ struct server_control_s
   int no_server;      /* We are not running under server control */
   int  status_fd;     /* Only for non-server mode */
   struct server_local_s *server_local;
+  struct call_syshelp_s *syshelp_local;
 
   int agent_seen;     /* Flag indicating that the gpg-agent has been
                          accessed.  */
@@ -43,10 +47,14 @@ struct server_control_s
   /* Type of the current container.  See the CONTTYPE_ constants.  */
   int conttype;
 
+  strlist_t recipients; /* List of recipients.  */
+
 };
 
 
 /*-- g13.c --*/
-void g13_init_default_ctrl (struct server_control_s *ctrl);
+void g13_init_default_ctrl (ctrl_t ctrl);
+void g13_deinit_default_ctrl (ctrl_t ctrl);
+void g13_request_shutdown (void);
 
 #endif /*G13_H*/
similarity index 51%
rename from g13/utils.c
rename to g13/g13tuple.c
index 4ab4799..fc6644c 100644 (file)
@@ -1,5 +1,6 @@
-/* utils.c - Utility functions
+/* g13tuple.c - Tuple handling
  * Copyright (C) 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2009, 2015, 2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -25,7 +26,8 @@
 #include <assert.h>
 
 #include "g13.h"
-#include "utils.h"
+#include "g13tuple.h"
+#include "keyblob.h"  /* Required for dump_tupledesc.  */
 
 
 /* Definition of the tuple descriptor object.  */
@@ -61,10 +63,45 @@ append_tuple (membuf_t *membuf, int tag, const void *value, size_t length)
 }
 
 
+/* Append the unsigned integer VALUE under TAG to MEMBUF.  We make
+ * sure that the most significant bit is always cleared to explicitly
+ * flag the value as unsigned.  */
+void
+append_tuple_uint (membuf_t *membuf, int tag, unsigned long long value)
+{
+  unsigned char buf[16];
+  unsigned char *p;
+  unsigned int len;
+
+  p = buf + sizeof buf;
+  len = 0;
+  do
+    {
+      if (p == buf)
+        BUG () ;
+      *--p = (value & 0xff);
+      value >>= 8;
+      len++;
+    }
+  while (value);
+
+  /* Prepend a zero byte if the first byte has its MSB set.  */
+  if ((*p & 0x80))
+    {
+      if (p == buf)
+        BUG () ;
+      *--p = 0;
+      len++;
+    }
+
+  append_tuple (membuf, tag, p, len);
+}
+
+
 /* Create a tuple object by moving the ownership of (DATA,DATALEN) to
  a new object.  Returns 0 on success and stores the new object at
  R_TUPLEHD.  The return object must be released using
  destroy_tuples().  */
* a new object.  Returns 0 on success and stores the new object at
* R_TUPLEHD.  The return object must be released using
* destroy_tuples().  */
 gpg_error_t
 create_tupledesc (tupledesc_t *r_desc, void *data, size_t datalen)
 {
@@ -106,9 +143,21 @@ ref_tupledesc (tupledesc_t tupledesc)
 }
 
 
+/* Return a pointer to the memory used to store the tuples.  This is
+ * the data originally provided to create_tupledesc.  It is higly
+ * recommended that the callers uses ref_tupledesc before calling this
+ * function and unref_tupledesc when the return data will not anymore
+ * be used.  */
+const void *
+get_tupledesc_data (tupledesc_t tupledesc, size_t *r_datalen)
+{
+  *r_datalen = tupledesc->datalen;
+  return tupledesc->data;
+}
+
 /* Find the first tuple with tag TAG.  On success return a pointer to
    its value and store the length of the value at R_LENGTH.  If no
-   tuple was return NULL.  For future use by next_tupe, the last
+   tuple was found return NULL.  For use by next_tuple, the last
    position is stored in the descriptor.  */
 const void *
 find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length)
@@ -147,6 +196,51 @@ find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length)
 }
 
 
+/* Helper for find_tuple_uint and others.  */
+static gpg_error_t
+convert_uint (const unsigned char *s, size_t n, unsigned long long *r_value)
+{
+  unsigned long long value = 0;
+
+  *r_value = 0;
+
+  if (!s)
+    return gpg_error (GPG_ERR_NOT_FOUND);
+  if (!n || (*s & 0x80)) /* No bytes or negative.  */
+    return gpg_error (GPG_ERR_ERANGE);
+  if (n && !*s) /* Skip a leading zero.  */
+    {
+      n--;
+      s++;
+    }
+  if (n > sizeof value)
+    return gpg_error (GPG_ERR_ERANGE);
+  for (; n; n--, s++)
+    {
+      value <<= 8;
+      value |= *s;
+    }
+  *r_value = value;
+  return 0;
+}
+
+
+/* Similar to find-tuple but expects an unsigned int value and stores
+ * that at R_VALUE.  If the tag was not found GPG_ERR_NOT_FOUND is
+ * returned and 0 stored at R_VALUE.  If the value cannot be converted
+ * to an unsigned integer GPG_ERR_ERANGE is returned.  */
+gpg_error_t
+find_tuple_uint (tupledesc_t tupledesc, unsigned int tag,
+                 unsigned long long *r_value)
+{
+  const unsigned char *s;
+  size_t n;
+
+  s = find_tuple (tupledesc, tag, &n);
+  return convert_uint (s, n, r_value);
+}
+
+
 const void *
 next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
 {
@@ -179,3 +273,68 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
 
   return NULL;
 }
+
+
+/* Return true if BUF has only printable characters.  */
+static int
+all_printable (const void *buf, size_t buflen)
+{
+  const unsigned char *s;
+
+  for (s=buf ; buflen; s++, buflen--)
+    if (*s < 32 && *s > 126)
+      return 0;
+  return 1;
+}
+
+
+/* Print information about TUPLES to the log stream.  */
+void
+dump_tupledesc (tupledesc_t tuples)
+{
+  size_t n;
+  unsigned int tag;
+  const void *value;
+  unsigned long long uint;
+
+  log_info ("keyblob dump:\n");
+  tag = KEYBLOB_TAG_BLOBVERSION;
+  value = find_tuple (tuples, tag, &n);
+  while (value)
+    {
+      log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
+      if (!n)
+        log_printf ("[none]\n");
+      else
+        {
+          switch (tag)
+            {
+            case KEYBLOB_TAG_ENCKEY:
+            case KEYBLOB_TAG_MACKEY:
+              log_printf ("[confidential]\n");
+              break;
+
+            case KEYBLOB_TAG_ALGOSTR:
+              if (n < 100 && all_printable (value, n))
+                log_printf ("%.*s\n", (int)n, (const char*)value);
+              else
+                log_printhex ("", value, n);
+              break;
+
+            case KEYBLOB_TAG_CONT_NSEC:
+            case KEYBLOB_TAG_ENC_NSEC:
+            case KEYBLOB_TAG_ENC_OFF:
+              if (!convert_uint (value, n, &uint))
+                log_printf ("%llu\n", uint);
+              else
+                log_printhex ("", value, n);
+              break;
+
+            default:
+              log_printhex ("", value, n);
+              break;
+            }
+        }
+      value = next_tuple (tuples, &tag, &n);
+    }
+}
similarity index 74%
rename from g13/utils.h
rename to g13/g13tuple.h
index 914b2cf..c9dfb47 100644 (file)
@@ -1,4 +1,4 @@
-/* utils.h - Defs for utility fucthe dispatcher to the various backends.ntions
+/* g13tuple.h - Tuple handling
  * Copyright (C) 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef G13_UTILS_H
-#define G13_UTILS_H
+#ifndef G13_G13TUPLE_H
+#define G13_G13TUPLE_H
 
 #include "../common/membuf.h"
 
 /* Append a new tuple to a memory buffer.  */
 void append_tuple (membuf_t *membuf,
                    int tag, const void *value, size_t length);
+void append_tuple_uint (membuf_t *membuf, int tag,
+                        unsigned long long value);
 
 /* The tuple descriptor object. */
 struct tupledesc_s;
@@ -34,10 +36,17 @@ gpg_error_t create_tupledesc (tupledesc_t *r_tupledesc,
                               void *data, size_t datalen);
 void destroy_tupledesc (tupledesc_t tupledesc);
 tupledesc_t ref_tupledesc (tupledesc_t tupledesc);
+#define unref_tupledesc(a) destroy_tupledesc ((a))
+const void *get_tupledesc_data (tupledesc_t tupledesc, size_t *r_datalen);
+
 const void *find_tuple (tupledesc_t tupledesc,
                         unsigned int tag, size_t *r_length);
+gpg_error_t find_tuple_uint (tupledesc_t tupledesc, unsigned int tag,
+                             unsigned long long *r_value);
 const void *next_tuple (tupledesc_t tupledesc,
                         unsigned int *r_tag, size_t *r_length);
 
+void dump_tupledesc (tupledesc_t tuples);
+
 
-#endif /*G13_UTILS_H*/
+#endif /*G13_G13TUPLE_H*/
diff --git a/g13/keyblob.c b/g13/keyblob.c
new file mode 100644 (file)
index 0000000..cad0c4f
--- /dev/null
@@ -0,0 +1,229 @@
+/* keyblob.c - Keyblob parser and builder.
+ * Copyright (C) 2009 Free Software Foundation, Inc.
+ * Copyright (C) 2015-2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "g13.h"
+#include "i18n.h"
+#include "mount.h"
+
+#include "keyblob.h"
+#include "../common/sysutils.h"
+#include "../common/call-gpg.h"
+#include "host2net.h"
+
+
+/* Parse the header prefix and return the length of the entire header.  */
+static gpg_error_t
+parse_header (const char *filename,
+              const unsigned char *packet, size_t packetlen,
+              size_t *r_headerlen)
+{
+  unsigned int len;
+
+  if (packetlen != 32)
+    return gpg_error (GPG_ERR_BUG);
+
+  len = buf32_to_uint (packet+2);
+  if (packet[0] != (0xc0|61) || len < 26
+      || memcmp (packet+6, "GnuPG/G13", 10))
+    {
+      log_error ("file '%s' is not valid container\n", filename);
+      return gpg_error (GPG_ERR_INV_OBJ);
+    }
+  if (packet[16] != 1)
+    {
+      log_error ("unknown version %u of container '%s'\n",
+                 (unsigned int)packet[16], filename);
+      return gpg_error (GPG_ERR_INV_OBJ);
+    }
+  if (packet[17] || packet[18]
+      || packet[26] || packet[27] || packet[28] || packet[29]
+      || packet[30] || packet[31])
+    log_info ("WARNING: unknown meta information in '%s'\n", filename);
+  if (packet[19])
+    log_info ("WARNING: OS flag is not supported in '%s'\n", filename);
+  if (packet[24] > 1 )
+    log_info ("Note: meta data copies in '%s' are ignored\n", filename);
+
+  len = buf32_to_uint (packet+20);
+
+  /* Do a basic sanity check on the length.  */
+  if (len < 32 || len > 1024*1024)
+    {
+      log_error ("bad length given in container '%s'\n", filename);
+      return gpg_error (GPG_ERR_INV_OBJ);
+    }
+
+  *r_headerlen = len;
+  return 0;
+}
+
+
+/* Read the prefix of the keyblob and do some basic parsing.  On
+   success returns an open estream file at R_FP and the length of the
+   header at R_HEADERLEN.  */
+static gpg_error_t
+read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
+{
+  gpg_error_t err;
+  estream_t fp;
+  unsigned char packet[32];
+
+  *r_fp = NULL;
+
+  fp = es_fopen (filename, "rb");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error reading '%s': %s\n", filename, gpg_strerror (err));
+      return err;
+    }
+
+  /* Read the header.  It is defined as 32 bytes thus we read it in one go.  */
+  if (es_fread (packet, 32, 1, fp) != 1)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error reading the header of '%s': %s\n",
+                 filename, gpg_strerror (err));
+      es_fclose (fp);
+      return err;
+    }
+
+  err = parse_header (filename, packet, 32, r_headerlen);
+  if (err)
+    es_fclose (fp);
+  else
+    *r_fp = fp;
+
+  return err;
+}
+
+
+\f
+/*
+ * Test whether the container with name FILENAME is a suitable G13
+ * container.  This function may even be called on a mounted
+ * container.
+ */
+gpg_error_t
+g13_is_container (ctrl_t ctrl, const char *filename)
+{
+  gpg_error_t err;
+  estream_t fp = NULL;
+  size_t dummy;
+
+  (void)ctrl;
+
+  /* Read just the prefix of the header.  */
+  err = read_keyblob_prefix (filename, &fp, &dummy);
+  if (!err)
+    es_fclose (fp);
+  return err;
+}
+
+
+/*
+ * Read the keyblob at FILENAME.  The caller should have acquired a
+ * lockfile and checked that the file exists.
+ */
+gpg_error_t
+g13_keyblob_read (const char *filename,
+                  void **r_enckeyblob, size_t *r_enckeybloblen)
+{
+  gpg_error_t err;
+  estream_t fp = NULL;
+  size_t headerlen = 0;
+  size_t msglen;
+  void *msg = NULL;
+
+  *r_enckeyblob = NULL;
+  *r_enckeybloblen = 0;
+
+  err = read_keyblob_prefix (filename, &fp, &headerlen);
+  if (err)
+    goto leave;
+
+  if (opt.verbose)
+    log_info ("header length of '%s' is %zu\n", filename, headerlen);
+
+  /* Read everything including the padding.  We should eventually do a
+     regular OpenPGP parsing to detect the padding packet and pass
+     only the actual used OpenPGP data to the engine.  This is in
+     particular required when supporting CMS which will be
+     encapsulated in an OpenPGP packet.  */
+  assert (headerlen >= 32);
+  msglen = headerlen - 32;
+  if (!msglen)
+    {
+      err = gpg_error (GPG_ERR_NO_DATA);
+      goto leave;
+    }
+  msg = xtrymalloc (msglen);
+  if (!msglen)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (es_fread (msg, msglen, 1, fp) != 1)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error reading keyblob of '%s': %s\n",
+                 filename, gpg_strerror (err));
+      goto leave;
+    }
+
+  *r_enckeyblob = msg;
+  msg = NULL;
+  *r_enckeybloblen = msglen;
+
+ leave:
+  xfree (msg);
+  es_fclose (fp);
+
+  return err;
+}
+
+
+/*
+ * Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result
+ * at (R_KEYBLOB, R_KEYBLOBLEN).  Returns 0 on success or an error
+ * code.  On error R_KEYBLOB is set to NULL.
+ */
+gpg_error_t
+g13_keyblob_decrypt (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
+                     void **r_keyblob, size_t *r_keybloblen)
+{
+  gpg_error_t err;
+
+  /* FIXME:  For now we only implement OpenPGP.  */
+  err = gpg_decrypt_blob (ctrl, opt.gpg_program, opt.gpg_arguments,
+                          enckeyblob, enckeybloblen,
+                          r_keyblob, r_keybloblen);
+
+  return err;
+}
index 5c3e74e..3415e9a 100644 (file)
@@ -20,7 +20,8 @@
 #ifndef G13_KEYBLOB_H
 #define G13_KEYBLOB_H
 
-/* The header block is the actual core of G13.  Here is the format:
+/* The setup area (header block) is the actual core of G13.  Here is
+   the format:
 
    u8   Packet type.  Value is 61 (0x3d).
    u8   Constant value 255 (0xff).
@@ -29,7 +30,7 @@
           u8   Version.  Value is 1.
           u8   reserved
           u8   reserved
-          u8   OS Flag:  reserved, should be 0.
+          u8   OS Flag:  0 = unspecified, 1 = Linux
           u32  Length of the entire header.  This includes all bytes
                starting at the packet type and ending with the last
                padding byte of the header.
@@ -37,9 +38,9 @@
           u8   Number of copies of this header at the end of the
                container (usually 0).
           b6   reserved
-   n bytes: OpenPGP encrypted and optionally signed message.
-   n bytes: CMS encrypted and optionally signed packet.  Such a CMS
-            packet will be enclosed in a private flagged OpenPGP
+   n bytes: OpenPGP encrypted and optionally signed keyblob.
+   n bytes: CMS encrypted and optionally signed keyblob.  Such a CMS
+            packet will be enclosed in a private flagged OpenPGP
             packet.  Either the OpenPGP encrypted packet as described
             above, the CMS encrypted or both packets must exist.  The
             encapsulation packet has this structure:
@@ -54,6 +55,8 @@
                 u32  Length of the following structure
                 b10  Value: "GnuPG/PAD\x00".
                 b(n) Padding stuff.
+                     (repeat the above value
+                      or if the remaining N < 10, all 0x00).
             Given this structure the minimum padding is 16 bytes.
 
    n bytes: File system container.
    keyblob.  If a value is given it is expected to be the GUID of the
    partition.  */
 
+#define KEYBLOB_TAG_CREATED  3
+/* This is an ISO 8601 time string with the date the container was
+   created.  */
+
+#define KEYBLOB_TAG_CONT_NSEC 7
+/* Number of 512-byte sectors of the entire container including all
+   copies of the setup area.  */
+
+#define KEYBLOB_TAG_ENC_NSEC  8
+#define KEYBLOB_TAG_ENC_OFF   9
+/* Number of 512-byte sectors used for the encrypted data and its
+   start offset in 512-byte sectors from the begin of the container.
+   Note that these information can also be deduced from the
+   unencrypted part of the setup area.  */
+
+#define KEYBLOB_TAG_ALGOSTR 10
+/* For a dm-crypt container this is the used algorithm string.  For
+   example: "aes-cbc-essiv:sha256".  */
+
 #define KEYBLOB_TAG_KEYNO  16
 /* This tag indicates a new key.  The value is a 4 byte big endian
    integer giving the key number.  If the container type does only
    The value is the key used for MACing.  */
 
 
+#define KEYBLOB_TAG_HDRCOPY 21
+/* The value of this tag is a copy of the setup area prefix header
+   block (packet 61 with marker "GnuPG/G13\x00".  We use it to allow
+   signing of that cleartext data.  */
+
 #define KEYBLOB_TAG_FILLER   0xffff
-/* This tag may be used for alignment and padding porposes.  The value
+/* This tag may be used for alignment and padding purposes.  The value
    has no meaning.  */
 
 
    possible to prepend a truecrypt container with our keyblob.  */
 
 
+\f
+/*-- keyblob.c --*/
+gpg_error_t g13_is_container (ctrl_t ctrl, const char *filename);
+gpg_error_t g13_keyblob_read (const char *filename,
+                              void **r_enckeyblob, size_t *r_enckeybloblen);
+gpg_error_t g13_keyblob_decrypt (ctrl_t ctrl,
+                                 const void *enckeyblob, size_t enckeybloblen,
+                                 void **r_keyblob, size_t *r_keybloblen);
+
 
 #endif /*G13_KEYBLOB_H*/
index e9b9c1b..272cd77 100644 (file)
 
 #include "keyblob.h"
 #include "backend.h"
-#include "utils.h"
-#include "../common/sysutils.h"
-#include "../common/call-gpg.h"
+#include "g13tuple.h"
 #include "mountinfo.h"
 #include "runner.h"
 #include "host2net.h"
-
-
-/* Parse the header prefix and return the length of the entire header.  */
-static gpg_error_t
-parse_header (const char *filename,
-              const unsigned char *packet, size_t packetlen,
-              size_t *r_headerlen)
-{
-  unsigned int len;
-
-  if (packetlen != 32)
-    return gpg_error (GPG_ERR_BUG);
-
-  len = buf32_to_uint (packet+2);
-  if (packet[0] != (0xc0|61) || len < 26
-      || memcmp (packet+6, "GnuPG/G13", 10))
-    {
-      log_error ("file '%s' is not valid container\n", filename);
-      return gpg_error (GPG_ERR_INV_OBJ);
-    }
-  if (packet[16] != 1)
-    {
-      log_error ("unknown version %u of container '%s'\n",
-                 (unsigned int)packet[16], filename);
-      return gpg_error (GPG_ERR_INV_OBJ);
-    }
-  if (packet[17] || packet[18]
-      || packet[26] || packet[27] || packet[28] || packet[29]
-      || packet[30] || packet[31])
-    log_info ("WARNING: unknown meta information in '%s'\n", filename);
-  if (packet[19])
-    log_info ("WARNING: OS flag is not supported in '%s'\n", filename);
-  if (packet[24] != 1 || packet[25] != 0)
-    {
-      log_error ("meta data copies in '%s' are not supported\n", filename);
-      return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-    }
-
-  len = buf32_to_uint (packet+20);
-
-  /* Do a basic sanity check on the length.  */
-  if (len < 32 || len > 1024*1024)
-    {
-      log_error ("bad length given in container '%s'\n", filename);
-      return gpg_error (GPG_ERR_INV_OBJ);
-    }
-
-  *r_headerlen = len;
-  return 0;
-}
-
-
-/* Read the prefix of the keyblob and do some basic parsing.  On
-   success returns an open estream file at R_FP and the length of the
-   header at R_HEADERLEN.  */
-static gpg_error_t
-read_keyblob_prefix (const char *filename, estream_t *r_fp, size_t *r_headerlen)
-{
-  gpg_error_t err;
-  estream_t fp;
-  unsigned char packet[32];
-
-  *r_fp = NULL;
-
-  fp = es_fopen (filename, "rb");
-  if (!fp)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error reading '%s': %s\n", filename, gpg_strerror (err));
-      return err;
-    }
-
-  /* Read the header.  It is defined as 32 bytes thus we read it in one go.  */
-  if (es_fread (packet, 32, 1, fp) != 1)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error reading the header of '%s': %s\n",
-                 filename, gpg_strerror (err));
-      es_fclose (fp);
-      return err;
-    }
-
-  err = parse_header (filename, packet, 32, r_headerlen);
-  if (err)
-    es_fclose (fp);
-  else
-    *r_fp = fp;
-
-  return err;
-}
-
-
-/* Read the keyblob at FILENAME.  The caller should have acquired a
-   lockfile and checked that the file exists.  */
-static gpg_error_t
-read_keyblob (const char *filename,
-              void **r_enckeyblob, size_t *r_enckeybloblen)
-{
-  gpg_error_t err;
-  estream_t fp = NULL;
-  size_t headerlen = 0;
-  size_t msglen;
-  void *msg = NULL;
-
-  *r_enckeyblob = NULL;
-  *r_enckeybloblen = 0;
-
-  err = read_keyblob_prefix (filename, &fp, &headerlen);
-  if (err)
-    goto leave;
-
-  if (opt.verbose)
-    log_info ("header length of '%s' is %zu\n", filename, headerlen);
-
-  /* Read everything including the padding.  We should eventually do a
-     regular OpenPGP parsing to detect the padding packet and pass
-     only the actual used OpenPGP data to the engine.  This is in
-     particular required when supporting CMS which will be
-     encapsulated in an OpenPGP packet.  */
-  assert (headerlen >= 32);
-  msglen = headerlen - 32;
-  if (!msglen)
-    {
-      err = gpg_error (GPG_ERR_NO_DATA);
-      goto leave;
-    }
-  msg = xtrymalloc (msglen);
-  if (!msglen)
-    {
-      err = gpg_error_from_syserror ();
-      goto leave;
-    }
-  if (es_fread (msg, msglen, 1, fp) != 1)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("error reading keyblob of '%s': %s\n",
-                 filename, gpg_strerror (err));
-      goto leave;
-    }
-
-  *r_enckeyblob = msg;
-  msg = NULL;
-  *r_enckeybloblen = msglen;
-
- leave:
-  xfree (msg);
-  es_fclose (fp);
-
-  return err;
-}
-
-
-
-
-/* Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result at
-   (R_KEYBLOB, R_KEYBLOBLEN).  Returns 0 on success or an error code.
-   On error R_KEYBLOB is set to NULL.  */
-static gpg_error_t
-decrypt_keyblob (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
-                 void **r_keyblob, size_t *r_keybloblen)
-{
-  gpg_error_t err;
-
-  /* FIXME:  For now we only implement OpenPGP.  */
-  err = gpg_decrypt_blob (ctrl, opt.gpg_program, opt.gpg_arguments,
-                          enckeyblob, enckeybloblen,
-                          r_keyblob, r_keybloblen);
-
-  return err;
-}
-
-
-static void
-dump_keyblob (tupledesc_t tuples)
-{
-  size_t n;
-  unsigned int tag;
-  const void *value;
-
-  log_info ("keyblob dump:\n");
-  tag = KEYBLOB_TAG_BLOBVERSION;
-  value = find_tuple (tuples, tag, &n);
-  while (value)
-    {
-      log_info ("   tag: %-5u len: %-2u value: ", tag, (unsigned int)n);
-      if (tag == KEYBLOB_TAG_ENCKEY
-          ||  tag == KEYBLOB_TAG_MACKEY)
-        log_printf ("[confidential]\n");
-      else if (!n)
-        log_printf ("[none]\n");
-      else
-        log_printhex ("", value, n);
-      value = next_tuple (tuples, &tag, &n);
-    }
-}
-
+#include "../common/sysutils.h"
 
 
 /* Mount the container with name FILENAME at MOUNTPOINT.  */
@@ -242,6 +45,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
 {
   gpg_error_t err;
   dotlock_t lock;
+  int needs_syshelp;
   void *enckeyblob = NULL;
   size_t enckeybloblen;
   void *keyblob = NULL;
@@ -257,6 +61,12 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
   if (access (filename, R_OK))
     return gpg_error_from_syserror ();
 
+  /* Decide whether we need to use the g13-syshelp because we can't
+     use lock files for them.  This is most likely the case for device
+     files; thus we test for this.  FIXME: The correct solution would
+     be to call g13-syshelp to match the file against the g13tab.  */
+  needs_syshelp = !strncmp (filename, "/dev/", 5);
+
   if (!mountpoint)
     {
       mountpoint_buffer = xtrystrdup ("/tmp/g13-XXXXXX");
@@ -273,21 +83,25 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       mountpoint = mountpoint_buffer;
     }
 
-  /* Try to take a lock.  */
-  lock = dotlock_create (filename, 0);
-  if (!lock)
+  err = 0;
+  if (needs_syshelp)
+    lock = NULL;
+  else
     {
-      xfree (mountpoint_buffer);
-      return gpg_error_from_syserror ();
-    }
+      /* Try to take a lock.  */
+      lock = dotlock_create (filename, 0);
+      if (!lock)
+        {
+          xfree (mountpoint_buffer);
+          return gpg_error_from_syserror ();
+        }
 
-  if (dotlock_take (lock, 0))
-    {
-      err = gpg_error_from_syserror ();
-      goto leave;
+      if (dotlock_take (lock, 0))
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
     }
-  else
-    err = 0;
 
   /* Check again that the file exists.  */
   {
@@ -301,13 +115,15 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
   }
 
   /* Read the encrypted keyblob.  */
-  err = read_keyblob (filename, &enckeyblob, &enckeybloblen);
+  /* Fixme: Should we move this to syshelp for dm-crypt or do we
+     assume that the encrypted device is world readable?  */
+  err = g13_keyblob_read (filename, &enckeyblob, &enckeybloblen);
   if (err)
     goto leave;
 
   /* Decrypt that keyblob and store it in a tuple descriptor.  */
-  err = decrypt_keyblob (ctrl, enckeyblob, enckeybloblen,
-                         &keyblob, &keybloblen);
+  err = g13_keyblob_decrypt (ctrl, enckeyblob, enckeybloblen,
+                             &keyblob, &keybloblen);
   if (err)
     goto leave;
   xfree (enckeyblob);
@@ -323,7 +139,7 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       goto leave;
     }
   if (opt.verbose)
-    dump_keyblob (tuples);
+    dump_tupledesc (tuples);
 
   value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
   if (!value || n != 2)
@@ -337,8 +153,15 @@ g13_mount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
       goto leave;
     }
   err = be_mount_container (ctrl, conttype, filename, mountpoint, tuples, &rid);
-  if (!err)
+  if (err)
+    ;
+  else if (conttype == CONTTYPE_DM_CRYPT)
+    g13_request_shutdown ();
+  else
     {
+      /* Unless this is a DM-CRYPT mount we put it into our mounttable
+         so that we can manage the mounts ourselves.  For dm-crypt we
+         do not keep a process to monitor he mounts (for now).  */
       err = mountinfo_add_mount (filename, mountpoint, conttype, rid,
                                  !!mountpoint_buffer);
       /* Fixme: What shall we do if this fails?  Add a provisional
@@ -395,23 +218,3 @@ g13_umount_container (ctrl_t ctrl, const char *filename, const char *mountpoint)
 
   return 0;
 }
-
-
-/* Test whether the container with name FILENAME is a suitable G13
-   container.  This function may even be called on a mounted
-   container.  */
-gpg_error_t
-g13_is_container (ctrl_t ctrl, const char *filename)
-{
-  gpg_error_t err;
-  estream_t fp = NULL;
-  size_t dummy;
-
-  (void)ctrl;
-
-  /* Read just the prefix of the header.  */
-  err = read_keyblob_prefix (filename, &fp, &dummy);
-  if (!err)
-    es_fclose (fp);
-  return err;
-}
index b2fe99e..0037682 100644 (file)
@@ -27,7 +27,5 @@ gpg_error_t g13_umount_container (ctrl_t ctrl,
                                   const char *filename,
                                   const char *mountpoint);
 
-gpg_error_t g13_is_container (ctrl_t ctrl, const char *filename);
-
 
 #endif /*G13_MOUNT_H*/
index 085fb86..1c4894d 100644 (file)
@@ -31,7 +31,7 @@
 #include "mountinfo.h"
 
 #include "keyblob.h"
-#include "utils.h"
+#include "g13tuple.h"
 
 
 
index 07b74f8..33885d6 100644 (file)
 #include "i18n.h"
 #include "keyblob.h"
 #include "server.h"
-#include "mount.h"
 #include "create.h"
-
+#include "mount.h"
+#include "suspend.h"
+#include "../common/server-help.h"
 
 /* The filepointer for status message used in non-server mode */
 static FILE *statusfp;
@@ -45,8 +46,6 @@ struct server_local_s
   assuan_context_t assuan_ctx;
 
   char *containername;  /* Malloced active containername.  */
-
-  strlist_t recipients; /* List of recipients.  */
 };
 
 
@@ -66,37 +65,6 @@ static int command_has_option (const char *cmd, const char *cmdopt);
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
 
-/* Skip over options.  Blanks after the options are also removed.  */
-static char *
-skip_options (const char *line)
-{
-  while (spacep (line))
-    line++;
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return (char*)line;
-}
-
-
-/* Check whether the option NAME appears in LINE.  */
-/* static int */
-/* has_option (const char *line, const char *name) */
-/* { */
-/*   const char *s; */
-/*   int n = strlen (name); */
-
-/*   s = strstr (line, name); */
-/*   if (s && s >= skip_options (line)) */
-/*     return 0; */
-/*   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
-/* } */
-
-
 /* Helper to print a message while leaving a command.  */
 static gpg_error_t
 leave_cmd (assuan_context_t ctx, gpg_error_t err)
@@ -194,7 +162,7 @@ reset_notify (assuan_context_t ctx, char *line)
   xfree (ctrl->server_local->containername);
   ctrl->server_local->containername = NULL;
 
-  FREE_STRLIST (ctrl->server_local->recipients);
+  FREE_STRLIST (ctrl->recipients);
 
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
@@ -358,6 +326,56 @@ cmd_umount (assuan_context_t ctx, char *line)
 }
 
 
+static const char hlp_suspend[] =
+  "SUSPEND\n"
+  "\n"
+  "Suspend the currently set device.";
+static gpg_error_t
+cmd_suspend (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  line = skip_options (line);
+  if (*line)
+    {
+      err = gpg_error (GPG_ERR_ASS_SYNTAX);
+      goto leave;
+    }
+
+  /* Perform the suspend operation.  */
+  err = g13_suspend_container (ctrl, ctrl->server_local->containername);
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_resume[] =
+  "RESUME\n"
+  "\n"
+  "Resume the currently set device.";
+static gpg_error_t
+cmd_resume (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  line = skip_options (line);
+  if (*line)
+    {
+      err = gpg_error (GPG_ERR_ASS_SYNTAX);
+      goto leave;
+    }
+
+  /* Perform the suspend operation.  */
+  err = g13_resume_container (ctrl, ctrl->server_local->containername);
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
 static const char hlp_recipient[] =
   "RECIPIENT <userID>\n"
   "\n"
@@ -372,7 +390,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
 
   line = skip_options (line);
 
-  if (!add_to_strlist_try (&ctrl->server_local->recipients, line))
+  if (!add_to_strlist_try (&ctrl->recipients, line))
     err = gpg_error_from_syserror ();
 
   return leave_cmd (ctx, err);
@@ -438,11 +456,11 @@ cmd_create (assuan_context_t ctx, char *line)
     }
 
   /* Create container.  */
-  err = g13_create_container (ctrl, line, ctrl->server_local->recipients);
+  err = g13_create_container (ctrl, line);
 
   if (!err)
     {
-      FREE_STRLIST (ctrl->server_local->recipients);
+      FREE_STRLIST (ctrl->recipients);
 
       /* Store the filename.  */
       ctrl->server_local->containername = xtrystrdup (line);
@@ -545,6 +563,8 @@ register_commands (assuan_context_t ctx)
     { "OPEN",          cmd_open,   hlp_open },
     { "MOUNT",         cmd_mount,  hlp_mount},
     { "UMOUNT",        cmd_umount, hlp_umount },
+    { "SUSPEND",       cmd_suspend, hlp_suspend },
+    { "RESUME",        cmd_resume,  hlp_resume },
     { "RECIPIENT",     cmd_recipient, hlp_recipient },
     { "SIGNER",        cmd_signer, hlp_signer },
     { "CREATE",        cmd_create, hlp_create },
diff --git a/g13/sh-blockdev.c b/g13/sh-blockdev.c
new file mode 100644 (file)
index 0000000..4b4dde4
--- /dev/null
@@ -0,0 +1,152 @@
+/* sh-blockdev.c - Block device functions for g13-syshelp
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <limits.h>
+
+#include "g13-syshelp.h"
+#include <assuan.h>
+#include "i18n.h"
+#include "exectool.h"
+#include "keyblob.h"
+
+#ifndef HAVE_STRTOULL
+# error building this tool requires strtoull(3)
+#endif
+#ifndef ULLONG_MAX
+# error ULLONG_MAX missing
+#endif
+
+
+/* Return the size measured in the number of 512 byte sectors for the
+   block device NAME.  */
+gpg_error_t
+sh_blockdev_getsz (const char *name, unsigned long long *r_nblocks)
+{
+  gpg_error_t err;
+  const char *argv[3];
+  char *result;
+
+  *r_nblocks = 0;
+  argv[0] = "--getsz";
+  argv[1] = name;
+  argv[2] = NULL;
+  err = gnupg_exec_tool ("/sbin/blockdev", argv, NULL, &result, NULL);
+  if (!err)
+    {
+      gpg_err_set_errno (0);
+      *r_nblocks = strtoull (result, NULL, 10);
+      if (*r_nblocks == ULLONG_MAX && errno)
+        {
+          err = gpg_error_from_syserror ();
+          *r_nblocks = 0;
+        }
+      xfree (result);
+    }
+  return err;
+}
+
+
+/* Return 0 if the device NAME looks like an empty partition. */
+gpg_error_t
+sh_is_empty_partition (const char *name)
+{
+  gpg_error_t err;
+  const char *argv[6];
+  char *buffer;
+  estream_t fp;
+  char *p;
+  size_t nread;
+
+  argv[0] = "-o";
+  argv[1] = "value";
+  argv[2] = "-s";
+  argv[3] = "UUID";
+  argv[4] = name;
+  argv[5] = NULL;
+  err = gnupg_exec_tool ("/sbin/blkid", argv, NULL, &buffer, NULL);
+  if (err)
+    return gpg_error (GPG_ERR_FALSE);
+  if (*buffer)
+    {
+      /* There seems to be an UUID - thus we have a file system.  */
+      xfree (buffer);
+      return gpg_error (GPG_ERR_FALSE);
+    }
+  xfree (buffer);
+
+  argv[0] = "-o";
+  argv[1] = "value";
+  argv[2] = "-s";
+  argv[3] = "PARTUUID";
+  argv[4] = name;
+  argv[5] = NULL;
+  err = gnupg_exec_tool ("/sbin/blkid", argv, NULL, &buffer, NULL);
+  if (err)
+    return gpg_error (GPG_ERR_FALSE);
+  if (!*buffer)
+    {
+      /* If there is no PARTUUID we assume that name has already a
+         mapped partition.  */
+      xfree (buffer);
+      return gpg_error (GPG_ERR_FALSE);
+    }
+  xfree (buffer);
+
+  /* As a safeguard we require that the first 32k of a partition are
+     all zero before we assume the partition is empty.  */
+  buffer = xtrymalloc (32 * 1024);
+  if (!buffer)
+    return gpg_error_from_syserror ();
+  fp = es_fopen (name, "rb,samethread");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error opening '%s': %s\n", name, gpg_strerror (err));
+      xfree (buffer);
+      return gpg_error (GPG_ERR_FALSE);
+    }
+  if (es_read (fp, buffer, 32 * 1024, &nread))
+    err = gpg_error_from_syserror ();
+  else if (nread != 32 *1024)
+    err = gpg_error (GPG_ERR_TOO_SHORT);
+  else
+    err = 0;
+  es_fclose (fp);
+  if (err)
+    {
+      log_error ("error reading the first 32 KiB from '%s': %s\n",
+                 name, gpg_strerror (err));
+      xfree (buffer);
+      return err;
+    }
+  for (p=buffer; nread && !*p; nread--, p++)
+    ;
+  xfree (buffer);
+  if (nread)
+    return gpg_error (GPG_ERR_FALSE);  /* No all zeroes.  */
+
+  return 0;
+}
diff --git a/g13/sh-cmd.c b/g13/sh-cmd.c
new file mode 100644 (file)
index 0000000..fe596f4
--- /dev/null
@@ -0,0 +1,780 @@
+/* sh-cmd.c - The Assuan server for g13-syshelp
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "g13-syshelp.h"
+#include <assuan.h>
+#include "i18n.h"
+#include "keyblob.h"
+
+
+/* Local data for this server module.  A pointer to this is stored in
+   the CTRL object of each connection.  */
+struct server_local_s
+{
+  /* The Assuan contect we are working on.  */
+  assuan_context_t assuan_ctx;
+
+  /* The malloced name of the device.  */
+  char *devicename;
+
+  /* A stream open for read of the device set by the DEVICE command or
+     NULL if no DEVICE command has been used.  */
+  estream_t devicefp;
+};
+
+
+
+\f
+/* Local prototypes.  */
+
+
+
+\f
+/*
+   Helper functions.
+ */
+
+/* Set an error and a description.  */
+#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
+#define set_error_fail_cmd() set_error (GPG_ERR_NOT_INITIALIZED, \
+                                        "not called via userv or unknown user")
+
+
+/* Skip over options.  Blanks after the options are also removed.  */
+static char *
+skip_options (const char *line)
+{
+  while (spacep (line))
+    line++;
+  while ( *line == '-' && line[1] == '-' )
+    {
+      while (*line && !spacep (line))
+        line++;
+      while (spacep (line))
+        line++;
+    }
+  return (char*)line;
+}
+
+
+/* Check whether the option NAME appears in LINE.  */
+/* static int */
+/* has_option (const char *line, const char *name) */
+/* { */
+/*   const char *s; */
+/*   int n = strlen (name); */
+
+/*   s = strstr (line, name); */
+/*   if (s && s >= skip_options (line)) */
+/*     return 0; */
+/*   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
+/* } */
+
+
+/* Helper to print a message while leaving a command.  */
+static gpg_error_t
+leave_cmd (assuan_context_t ctx, gpg_error_t err)
+{
+  if (err)
+    {
+      const char *name = assuan_get_command_name (ctx);
+      if (!name)
+        name = "?";
+      if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
+        log_error ("command '%s' failed: %s\n", name,
+                   gpg_strerror (err));
+      else
+        log_error ("command '%s' failed: %s <%s>\n", name,
+                   gpg_strerror (err), gpg_strsource (err));
+    }
+  return err;
+}
+
+
+
+\f
+/* The handler for Assuan OPTION commands.  */
+static gpg_error_t
+option_handler (assuan_context_t ctx, const char *key, const char *value)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+
+  (void)ctrl;
+  (void)key;
+  (void)value;
+
+  if (ctrl->fail_all_cmds)
+    err = set_error_fail_cmd ();
+  else
+    err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
+
+  return err;
+}
+
+
+/* The handler for an Assuan RESET command.  */
+static gpg_error_t
+reset_notify (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+
+  (void)line;
+
+  xfree (ctrl->server_local->devicename);
+  ctrl->server_local->devicename = NULL;
+  es_fclose (ctrl->server_local->devicefp);
+  ctrl->server_local->devicefp = NULL;
+  ctrl->devti = NULL;
+
+  assuan_close_input_fd (ctx);
+  assuan_close_output_fd (ctx);
+  return 0;
+}
+
+
+static const char hlp_device[] =
+  "DEVICE <name>\n"
+  "\n"
+  "Set the device used by further commands.\n"
+  "A device name or a PARTUUID string may be used.\n"
+  "Access to that device (by the g13 system) is locked\n"
+  "until a new DEVICE command or end of this process\n";
+static gpg_error_t
+cmd_device (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  tab_item_t ti;
+  estream_t fp = NULL;
+
+  line = skip_options (line);
+
+/* # warning hardwired to /dev/sdb1 ! */
+/*   if (strcmp (line, "/dev/sdb1")) */
+/*     { */
+/*       err = gpg_error (GPG_ERR_ENOENT); */
+/*       goto leave; */
+/*     } */
+
+  /* Always close an open device stream of this session. */
+  xfree (ctrl->server_local->devicename);
+  ctrl->server_local->devicename = NULL;
+  es_fclose (ctrl->server_local->devicefp);
+  ctrl->server_local->devicefp = NULL;
+
+  /* Are we allowed to use the given device?  */
+  for (ti=ctrl->client.tab; ti; ti = ti->next)
+    if (!strcmp (line, ti->blockdev))
+      break;
+  if (!ti)
+    {
+      err = set_error (GPG_ERR_EACCES, "device not configured for user");
+      goto leave;
+    }
+
+  ctrl->server_local->devicename = xtrystrdup (line);
+  if (!ctrl->server_local->devicename)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+
+  /* Check whether we have permissions to open the device and keep an
+     FD open.  */
+  fp = es_fopen (ctrl->server_local->devicename, "rb");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error opening '%s': %s\n",
+                 ctrl->server_local->devicename, gpg_strerror (err));
+      goto leave;
+    }
+
+  es_fclose (ctrl->server_local->devicefp);
+  ctrl->server_local->devicefp = fp;
+  fp = NULL;
+  ctrl->devti = ti;
+
+  /* Fixme: Take some kind of lock.  */
+
+ leave:
+  es_fclose (fp);
+  if (err)
+    {
+      xfree (ctrl->server_local->devicename);
+      ctrl->server_local->devicename = NULL;
+      ctrl->devti = NULL;
+    }
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_create[] =
+  "CREATE <type>\n"
+  "\n"
+  "Create a new encrypted partition on the current device.\n"
+  "<type> must be \"dm-crypt\" for now.";
+static gpg_error_t
+cmd_create (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  estream_t fp = NULL;
+
+  line = skip_options (line);
+  if (strcmp (line, "dm-crypt"))
+    {
+      err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
+      goto leave;
+    }
+
+  if (!ctrl->server_local->devicename
+      || !ctrl->server_local->devicefp
+      || !ctrl->devti)
+    {
+      err = set_error (GPG_ERR_ENOENT, "No device has been set");
+      goto leave;
+    }
+
+  err = sh_is_empty_partition (ctrl->server_local->devicename);
+  if (err)
+    {
+      if (gpg_err_code (err) == GPG_ERR_FALSE)
+        err = gpg_error (GPG_ERR_CONFLICT);
+      err = assuan_set_error (ctx, err, "Partition is not empty");
+      goto leave;
+    }
+
+  /* We need a writeable stream to create the container.  */
+  fp = es_fopen (ctrl->server_local->devicename, "r+b");
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error opening '%s': %s\n",
+                 ctrl->server_local->devicename, gpg_strerror (err));
+      goto leave;
+    }
+  if (es_setvbuf (fp, NULL, _IONBF, 0))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error setting '%s' to _IONBF: %s\n",
+                 ctrl->server_local->devicename, gpg_strerror (err));
+      goto leave;
+    }
+
+  err = sh_dmcrypt_create_container (ctrl,
+                                     ctrl->server_local->devicename,
+                                     fp);
+  if (es_fclose (fp))
+    {
+      gpg_error_t err2 = gpg_error_from_syserror ();
+      log_error ("error closing '%s': %s\n",
+                 ctrl->server_local->devicename, gpg_strerror (err2));
+      if (!err)
+        err = err2;
+    }
+  fp = NULL;
+
+ leave:
+  es_fclose (fp);
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_mount[] =
+  "MOUNT <type>\n"
+  "\n"
+  "Mount an encrypted partition on the current device.\n"
+  "<type> must be \"dm-crypt\" for now.";
+static gpg_error_t
+cmd_mount (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  unsigned char *keyblob = NULL;
+  size_t keybloblen;
+  tupledesc_t tuples = NULL;
+
+  line = skip_options (line);
+
+  if (strcmp (line, "dm-crypt"))
+    {
+      err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
+      goto leave;
+    }
+
+  if (!ctrl->server_local->devicename
+      || !ctrl->server_local->devicefp
+      || !ctrl->devti)
+    {
+      err = set_error (GPG_ERR_ENOENT, "No device has been set");
+      goto leave;
+    }
+
+  err = sh_is_empty_partition (ctrl->server_local->devicename);
+  if (!err)
+    {
+      err = gpg_error (GPG_ERR_ENODEV);
+      assuan_set_error (ctx, err, "Partition is empty");
+      goto leave;
+    }
+  err = 0;
+
+  /* We expect that the client already decrypted the keyblob.
+   * Eventually we should move reading of the keyblob to here and ask
+   * the client to decrypt it.  */
+  assuan_begin_confidential (ctx);
+  err = assuan_inquire (ctx, "KEYBLOB",
+                        &keyblob, &keybloblen, 4 * 1024);
+  assuan_end_confidential (ctx);
+  if (err)
+    {
+      log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
+      goto leave;
+    }
+  err = create_tupledesc (&tuples, keyblob, keybloblen);
+  if (!err)
+    keyblob = NULL;
+  else
+    {
+      if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
+        log_error ("unknown keyblob version received\n");
+      goto leave;
+    }
+
+  err = sh_dmcrypt_mount_container (ctrl,
+                                    ctrl->server_local->devicename,
+                                    tuples);
+
+ leave:
+  xfree (tuples);
+  destroy_tupledesc (tuples);
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_suspend[] =
+  "SUSPEND <type>\n"
+  "\n"
+  "Suspend an encrypted partition and wipe the key.\n"
+  "<type> must be \"dm-crypt\" for now.";
+static gpg_error_t
+cmd_suspend (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+
+  line = skip_options (line);
+
+  if (strcmp (line, "dm-crypt"))
+    {
+      err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
+      goto leave;
+    }
+
+  if (!ctrl->server_local->devicename
+      || !ctrl->server_local->devicefp
+      || !ctrl->devti)
+    {
+      err = set_error (GPG_ERR_ENOENT, "No device has been set");
+      goto leave;
+    }
+
+  err = sh_is_empty_partition (ctrl->server_local->devicename);
+  if (!err)
+    {
+      err = gpg_error (GPG_ERR_ENODEV);
+      assuan_set_error (ctx, err, "Partition is empty");
+      goto leave;
+    }
+  err = 0;
+
+  err = sh_dmcrypt_suspend_container (ctrl, ctrl->server_local->devicename);
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_resume[] =
+  "RESUME <type>\n"
+  "\n"
+  "Resume an encrypted partition and set the key.\n"
+  "<type> must be \"dm-crypt\" for now.";
+static gpg_error_t
+cmd_resume (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  unsigned char *keyblob = NULL;
+  size_t keybloblen;
+  tupledesc_t tuples = NULL;
+
+  line = skip_options (line);
+
+  if (strcmp (line, "dm-crypt"))
+    {
+      err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
+      goto leave;
+    }
+
+  if (!ctrl->server_local->devicename
+      || !ctrl->server_local->devicefp
+      || !ctrl->devti)
+    {
+      err = set_error (GPG_ERR_ENOENT, "No device has been set");
+      goto leave;
+    }
+
+  err = sh_is_empty_partition (ctrl->server_local->devicename);
+  if (!err)
+    {
+      err = gpg_error (GPG_ERR_ENODEV);
+      assuan_set_error (ctx, err, "Partition is empty");
+      goto leave;
+    }
+  err = 0;
+
+  /* We expect that the client already decrypted the keyblob.
+   * Eventually we should move reading of the keyblob to here and ask
+   * the client to decrypt it.  */
+  assuan_begin_confidential (ctx);
+  err = assuan_inquire (ctx, "KEYBLOB",
+                        &keyblob, &keybloblen, 4 * 1024);
+  assuan_end_confidential (ctx);
+  if (err)
+    {
+      log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
+      goto leave;
+    }
+  err = create_tupledesc (&tuples, keyblob, keybloblen);
+  if (!err)
+    keyblob = NULL;
+  else
+    {
+      if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
+        log_error ("unknown keyblob version received\n");
+      goto leave;
+    }
+
+  err = sh_dmcrypt_resume_container (ctrl,
+                                     ctrl->server_local->devicename,
+                                     tuples);
+
+ leave:
+  xfree (tuples);
+  destroy_tupledesc (tuples);
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_getinfo[] =
+  "GETINFO <what>\n"
+  "\n"
+  "Multipurpose function to return a variety of information.\n"
+  "Supported values for WHAT are:\n"
+  "\n"
+  "  version     - Return the version of the program.\n"
+  "  pid         - Return the process id of the server.\n"
+  "  showtab     - Show the table for the user.";
+static gpg_error_t
+cmd_getinfo (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err = 0;
+  char *buf;
+
+  if (!strcmp (line, "version"))
+    {
+      const char *s = PACKAGE_VERSION;
+      err = assuan_send_data (ctx, s, strlen (s));
+    }
+  else if (!strcmp (line, "pid"))
+    {
+      char numbuf[50];
+
+      snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
+      err = assuan_send_data (ctx, numbuf, strlen (numbuf));
+    }
+  else if (!strncmp (line, "getsz", 5))
+    {
+      unsigned long long nblocks;
+      err = sh_blockdev_getsz (line+6, &nblocks);
+      if (!err)
+        log_debug ("getsz=%llu\n", nblocks);
+    }
+  else if (!strcmp (line, "showtab"))
+    {
+      tab_item_t ti;
+
+      for (ti=ctrl->client.tab; !err && ti; ti = ti->next)
+        {
+          buf = es_bsprintf ("%s %s%s %s %s%s\n",
+                             ctrl->client.uname,
+                             *ti->blockdev=='/'? "":"partuuid=",
+                             ti->blockdev,
+                             ti->label? ti->label : "-",
+                             ti->mountpoint? " ":"",
+                             ti->mountpoint? ti->mountpoint:"");
+          if (!buf)
+            err = gpg_error_from_syserror ();
+          else
+            {
+              err = assuan_send_data (ctx, buf, strlen (buf));
+              if (!err)
+                err = assuan_send_data (ctx, NULL, 0); /* Flush  */
+            }
+          xfree (buf);
+        }
+    }
+  else
+    err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
+
+  return leave_cmd (ctx, err);
+}
+
+
+/* This command handler is used for all commands if this process has
+   not been started as expected.  */
+static gpg_error_t
+fail_command (assuan_context_t ctx, char *line)
+{
+  gpg_error_t err;
+  const char *name = assuan_get_command_name (ctx);
+
+  (void)line;
+
+  if (!name)
+    name = "?";
+
+  err = set_error_fail_cmd ();
+  log_error ("command '%s' failed: %s\n", name, gpg_strerror (err));
+  return err;
+}
+
+
+/* Tell the Assuan library about our commands.  */
+static int
+register_commands (assuan_context_t ctx, int fail_all)
+{
+  static struct {
+    const char *name;
+    assuan_handler_t handler;
+    const char * const help;
+  } table[] =  {
+    { "DEVICE",        cmd_device, hlp_device },
+    { "CREATE",        cmd_create, hlp_create },
+    { "MOUNT",         cmd_mount,  hlp_mount  },
+    { "SUSPEND",       cmd_suspend,hlp_suspend},
+    { "RESUME",        cmd_resume, hlp_resume },
+    { "INPUT",         NULL },
+    { "OUTPUT",        NULL },
+    { "GETINFO",       cmd_getinfo, hlp_getinfo },
+    { NULL }
+  };
+  gpg_error_t err;
+  int i;
+
+  for (i=0; table[i].name; i++)
+    {
+      err = assuan_register_command (ctx, table[i].name,
+                                     fail_all ? fail_command : table[i].handler,
+                                     table[i].help);
+      if (err)
+        return err;
+    }
+  return 0;
+}
+
+
+/* Startup the server.  */
+gpg_error_t
+syshelp_server (ctrl_t ctrl)
+{
+  gpg_error_t err;
+  assuan_fd_t filedes[2];
+  assuan_context_t ctx = NULL;
+
+  /* We use a pipe based server so that we can work from scripts.
+     assuan_init_pipe_server will automagically detect when we are
+     called with a socketpair and ignore FILEDES in this case. */
+  filedes[0] = assuan_fdopen (0);
+  filedes[1] = assuan_fdopen (1);
+  err = assuan_new (&ctx);
+  if (err)
+    {
+      log_error ("failed to allocate an Assuan context: %s\n",
+                 gpg_strerror (err));
+      goto leave;
+    }
+
+  err = assuan_init_pipe_server (ctx, filedes);
+  if (err)
+    {
+      log_error ("failed to initialize the server: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+
+  err = register_commands (ctx, 0 /*FIXME:ctrl->fail_all_cmds*/);
+  if (err)
+    {
+      log_error ("failed to the register commands with Assuan: %s\n",
+                 gpg_strerror (err));
+      goto leave;
+    }
+
+  assuan_set_pointer (ctx, ctrl);
+
+  {
+    char *tmp = xtryasprintf ("G13-syshelp %s ready to serve requests "
+                              "from %lu(%s)",
+                              PACKAGE_VERSION,
+                              (unsigned long)ctrl->client.uid,
+                              ctrl->client.uname);
+    if (tmp)
+      {
+        assuan_set_hello_line (ctx, tmp);
+        xfree (tmp);
+      }
+  }
+
+  assuan_register_reset_notify (ctx, reset_notify);
+  assuan_register_option_handler (ctx, option_handler);
+
+  ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
+  if (!ctrl->server_local)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  ctrl->server_local->assuan_ctx = ctx;
+
+  while ( !(err = assuan_accept (ctx)) )
+    {
+      err = assuan_process (ctx);
+      if (err)
+        log_info ("Assuan processing failed: %s\n", gpg_strerror (err));
+    }
+  if (err == -1)
+    err = 0;
+  else
+    log_info ("Assuan accept problem: %s\n", gpg_strerror (err));
+
+ leave:
+  reset_notify (ctx, NULL);  /* Release all items hold by SERVER_LOCAL.  */
+  if (ctrl->server_local)
+    {
+      xfree (ctrl->server_local);
+      ctrl->server_local = NULL;
+    }
+
+  assuan_release (ctx);
+  return err;
+}
+
+
+gpg_error_t
+sh_encrypt_keyblob (ctrl_t ctrl, const void *keyblob, size_t keybloblen,
+                    char **r_enckeyblob, size_t *r_enckeybloblen)
+{
+  assuan_context_t ctx = ctrl->server_local->assuan_ctx;
+  gpg_error_t err;
+  unsigned char *enckeyblob;
+  size_t enckeybloblen;
+
+  *r_enckeyblob = NULL;
+
+  /* Send the plaintext.  */
+  err = g13_status (ctrl, STATUS_PLAINTEXT_FOLLOWS, NULL);
+  if (err)
+    return err;
+  assuan_begin_confidential (ctx);
+  err = assuan_send_data (ctx, keyblob, keybloblen);
+  if (!err)
+    err = assuan_send_data (ctx, NULL, 0);
+  assuan_end_confidential (ctx);
+  if (!err)
+    err = assuan_write_line (ctx, "END");
+  if (err)
+    {
+      log_error (_("error sending data: %s\n"), gpg_strerror (err));
+      return err;
+    }
+
+  /* Inquire the ciphertext.  */
+  err = assuan_inquire (ctx, "ENCKEYBLOB",
+                        &enckeyblob, &enckeybloblen, 16 * 1024);
+  if (err)
+    {
+      log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
+      return err;
+    }
+
+  *r_enckeyblob = enckeyblob;
+  *r_enckeybloblen = enckeybloblen;
+  return 0;
+}
+
+
+/* Send a status line with status ID NO.  The arguments are a list of
+   strings terminated by a NULL argument.  */
+gpg_error_t
+g13_status (ctrl_t ctrl, int no, ...)
+{
+  gpg_error_t err = 0;
+  va_list arg_ptr;
+  const char *text;
+
+  va_start (arg_ptr, no);
+
+  if (1)
+    {
+      assuan_context_t ctx = ctrl->server_local->assuan_ctx;
+      char buf[950], *p;
+      size_t n;
+
+      p = buf;
+      n = 0;
+      while ( (text = va_arg (arg_ptr, const char *)) )
+        {
+          if (n)
+            {
+              *p++ = ' ';
+              n++;
+            }
+          for ( ; *text && n < DIM (buf)-2; n++)
+            *p++ = *text++;
+        }
+      *p = 0;
+      err = assuan_write_status (ctx, get_status_string (no), buf);
+    }
+
+  va_end (arg_ptr);
+  return err;
+}
diff --git a/g13/sh-dmcrypt.c b/g13/sh-dmcrypt.c
new file mode 100644 (file)
index 0000000..e0cd2e1
--- /dev/null
@@ -0,0 +1,943 @@
+/* sh-dmcrypt.c - The DM-Crypt part for g13-syshelp
+ * Copyright (C) 2015, 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+#include <unistd.h>
+
+#include "g13-syshelp.h"
+#include <assuan.h>
+#include "i18n.h"
+#include "g13tuple.h"
+#include "exectool.h"
+#include "keyblob.h"
+
+/* The standard disk block size (logical).  */
+#define SECTOR_SIZE 512
+
+/* The physical block size used by modern devices.  */
+#define PHY_SECTOR_SIZE  (SECTOR_SIZE*8)  /* 4 KiB */
+
+/* The length of the crypto setup area in sectors.  16 KiB is a nice
+   multiple of a modern block size and should be sufficient for all
+   kind of extra public key encryption packets.  */
+#define SETUP_AREA_SECTORS 32  /* 16 KiB */
+
+/* The number of header block copies stored at the begin and end of
+   the device.  */
+#define HEADER_SETUP_AREA_COPIES 2
+#define FOOTER_SETUP_AREA_COPIES 2
+
+/* The length in blocks of the space we put at the start and at the
+   end of the device.  This space is used to store N copies of the
+   setup area for the actual encrypted container inbetween.  */
+#define HEADER_SECTORS (SETUP_AREA_SECTORS * HEADER_SETUP_AREA_COPIES)
+#define FOOTER_SECTORS (SETUP_AREA_SECTORS * FOOTER_SETUP_AREA_COPIES)
+
+/* Minimim size of the encrypted space in blocks.  This is more or
+   less an arbitrary value.  */
+#define MIN_ENCRYPTED_SPACE 32
+
+/* Some consistency checks for the above constants.  */
+#if (PHY_SECTOR_SIZE % SECTOR_SIZE)
+# error the physical secotor size should be a multiple of 512
+#endif
+#if ((SETUP_AREA_SECTORS*SECTOR_SIZE) % PHY_SECTOR_SIZE)
+# error The setup area size should be a multiple of the phy. sector size.
+#endif
+
+
+/*
+ * Check whether the block device DEVNAME is used by device mapper.
+ * If EXPECT_BUSY is set no error message is printed if the device is
+ * busy.  Returns: 0 if the device is good and not yet used by DM.
+ */
+static gpg_error_t
+check_blockdev (const char *devname, int expect_busy)
+{
+  gpg_error_t err;
+  struct stat sb;
+  unsigned int devmajor, devminor;
+  char *result = NULL;
+  char **lines = NULL;
+  char **fields = NULL;
+  int lno, count;
+
+  if (stat (devname, &sb))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error stating '%s': %s\n", devname, gpg_strerror (err));
+      return err;
+    }
+  if (!S_ISBLK (sb.st_mode))
+    {
+      err = gpg_error (GPG_ERR_ENOTBLK);
+      log_error ("can't use '%s': %s\n", devname, gpg_strerror (err));
+      return err;
+    }
+  devmajor = major (sb.st_rdev);
+  devminor = minor (sb.st_rdev);
+
+  {
+    const char *argv[2];
+
+    argv[0] = "deps";
+    argv[1] = NULL;
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, NULL, &result, NULL);
+  }
+  if (err)
+    {
+      log_error ("error running '%s' to search for '%s': %s\n",
+                 "dmsetup deps", devname, gpg_strerror (err));
+      goto leave;
+    }
+  lines = strsplit (result, '\n', 0, NULL);
+  if (!lines)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  if (lines[0] && !strcmp (lines[0], "No devices found"))
+    ;
+  else
+    {
+      for (lno=0; lines[lno]; lno++)
+        {
+          unsigned int xmajor, xminor;
+
+          if (!*lines[lno])
+            continue;
+          xfree (fields);
+          fields = strsplit (lines[lno], ':', 0, &count);
+          if (!fields)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          if (count < 3
+              || sscanf (fields[2], " (%u,%u)", &xmajor, &xminor) != 2)
+            {
+              log_error ("error running '%s' to search for '%s': %s\n",
+                         "dmsetup deps", devname, "unexpected output");
+              err = gpg_error (GPG_ERR_INV_VALUE);
+              goto leave;
+            }
+
+          if (xmajor == devmajor && xminor == devminor)
+            {
+              if (!expect_busy)
+                log_error ("device '%s' (%u:%u)"
+                           " already in use by device mapper\n",
+                           devname, devmajor, devminor);
+              err = gpg_error (GPG_ERR_EBUSY);
+              goto leave;
+            }
+        }
+    }
+
+
+ leave:
+  xfree (fields);
+  xfree (lines);
+  xfree (result);
+  return err;
+}
+
+
+/* Return a malloced buffer with the prefix of the setup area.  This
+   is the data written right before the encrypted keyblob.  Return NULL
+   on error and sets ERRNO.  */
+static void *
+mk_setup_area_prefix (size_t *r_length)
+{
+  unsigned char *packet;
+  size_t setuparealen;
+
+  packet = xtrymalloc (32);
+  if (!packet)
+    return NULL;
+  *r_length = 32;
+
+  setuparealen = SETUP_AREA_SECTORS * SECTOR_SIZE;
+
+  packet[0] = (0xc0|61); /* CTB for the private packet type 0x61.  */
+  packet[1] = 0xff;      /* 5 byte length packet, value 20.  */
+  packet[2] = 0;
+  packet[3] = 0;
+  packet[4] = 0;
+  packet[5] = 26;
+  memcpy (packet+6, "GnuPG/G13", 10); /* Packet subtype.  */
+  packet[16] = 1;   /* G13 packet format version.  */
+  packet[17] = 0;   /* Reserved.  */
+  packet[18] = 0;   /* Reserved.  */
+  packet[19] = 1;   /* OS Flag = Linux  */
+  packet[20] = (setuparealen >> 24);  /* Total length of header.  */
+  packet[21] = (setuparealen >> 16);
+  packet[22] = (setuparealen >> 8);
+  packet[23] = (setuparealen);
+  packet[24] = HEADER_SETUP_AREA_COPIES;
+  packet[25] = FOOTER_SETUP_AREA_COPIES;
+  packet[26] = 0;   /* Reserved.  */
+  packet[27] = 0;   /* Reserved.  */
+  packet[28] = 0;   /* Reserved.  */
+  packet[29] = 0;   /* Reserved.  */
+  packet[30] = 0;   /* Reserved.  */
+  packet[31] = 0;   /* Reserved.  */
+
+  return packet;
+}
+
+
+/* Create a new g13 styloe DM-Crypt container on devoce DEVNAME.  */
+gpg_error_t
+sh_dmcrypt_create_container (ctrl_t ctrl, const char *devname, estream_t devfp)
+{
+  gpg_error_t err;
+  char *header_space;
+  size_t header_space_size, header_space_used;
+  size_t paddinglen;
+  char *targetname = NULL;
+  size_t nread;
+  char *p;
+  char hexkey[16*2+1];
+  char *table = NULL;
+  unsigned long long nblocks;
+  char *result = NULL;
+  unsigned char twobyte[2];
+  membuf_t keyblob;
+  void  *keyblob_buf = NULL;
+  size_t keyblob_len;
+  size_t n;
+  const char *s;
+  unsigned char *packet;
+  int copy;
+
+  if (!ctrl->devti)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  g13_syshelp_i_know_what_i_am_doing ();
+
+  header_space_size = SETUP_AREA_SECTORS * SECTOR_SIZE;
+  header_space = xtrymalloc (header_space_size);
+  if (!header_space)
+    return gpg_error_from_syserror ();
+
+  /* Start building the keyblob.  */
+  init_membuf (&keyblob, 512);
+  append_tuple (&keyblob, KEYBLOB_TAG_BLOBVERSION, "\x01", 1);
+  n = CONTTYPE_DM_CRYPT;
+  twobyte[0] = (n >> 8);
+  twobyte[1] = n;
+  append_tuple (&keyblob, KEYBLOB_TAG_CONTTYPE, twobyte, 2);
+  {
+    gnupg_isotime_t tbuf;
+
+    gnupg_get_isotime (tbuf);
+    append_tuple (&keyblob, KEYBLOB_TAG_CREATED, tbuf, strlen (tbuf));
+  }
+
+  /* Rewind device stream.  */
+  if (es_fseeko (devfp, 0, SEEK_SET))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error seeking to begin of '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  es_clearerr (devfp);
+
+  /* Extra check that the device is empty.  */
+  if (es_read (devfp, header_space, header_space_size, &nread))
+    err = gpg_error_from_syserror ();
+  else if (nread != header_space_size)
+    err = gpg_error (GPG_ERR_TOO_SHORT);
+  else
+    err = 0;
+  if (err)
+    {
+      log_error ("error reading header space of '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  for (p=header_space; nread && !*p; nread--, p++)
+    ;
+  if (nread)
+    {
+      log_error ("header space of '%s' already used - use %s to override\n",
+                 devname, "--force");
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      goto leave;
+    }
+
+  /* Check that the device is not used by device mapper. */
+  err = check_blockdev (devname, 0);
+  if (err)
+    goto leave;
+
+  /* Compute the number of blocks.  */
+  err = sh_blockdev_getsz (devname, &nblocks);
+  if (err)
+    {
+      log_error ("error getting size of '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  if (nblocks <= HEADER_SECTORS + MIN_ENCRYPTED_SPACE + FOOTER_SECTORS)
+    {
+      log_error ("device '%s' is too small (min=%d blocks)\n",
+                 devname,
+                 HEADER_SECTORS + MIN_ENCRYPTED_SPACE + FOOTER_SECTORS);
+      err = gpg_error (GPG_ERR_TOO_SHORT);
+      goto leave;
+    }
+  append_tuple_uint (&keyblob, KEYBLOB_TAG_CONT_NSEC, nblocks);
+  nblocks -= HEADER_SECTORS + FOOTER_SECTORS;
+  append_tuple_uint (&keyblob, KEYBLOB_TAG_ENC_NSEC, nblocks);
+  append_tuple_uint (&keyblob, KEYBLOB_TAG_ENC_OFF, HEADER_SECTORS);
+
+  /* Device mapper needs a name for the device: Take it from the label
+     or use "0".  */
+  targetname = strconcat ("g13-", ctrl->client.uname, "-",
+                          ctrl->devti->label? ctrl->devti->label : "0",
+                          NULL);
+  if (!targetname)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Create the key.  */
+  {
+    char key[16];
+    gcry_randomize (key, sizeof key, GCRY_STRONG_RANDOM);
+    append_tuple (&keyblob, KEYBLOB_TAG_ENCKEY, key, sizeof key);
+    bin2hex (key, 16, hexkey);
+    wipememory (key, 16);
+    /* Add a 2*(4+16) byte filler to conceal the fact that we use
+       AES-128.  If we ever want to switch to 256 bit we can resize
+       that filler to keep the keyblob at the same size.  */
+    append_tuple (&keyblob, KEYBLOB_TAG_FILLER, key, sizeof key);
+    append_tuple (&keyblob, KEYBLOB_TAG_FILLER, key, sizeof key);
+  }
+
+  /* Build dmcrypt table. */
+  s = "aes-cbc-essiv:sha256";
+  append_tuple (&keyblob, KEYBLOB_TAG_ALGOSTR, s, strlen (s));
+  table = es_bsprintf ("0 %llu crypt %s %s 0 %s %d",
+                       nblocks, s, hexkey, devname, HEADER_SECTORS);
+  if (!table)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  wipememory (hexkey, sizeof hexkey);
+
+  /* Add a copy of the setup area prefix to the keyblob.  */
+  p = mk_setup_area_prefix (&n);
+  if (!p)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  append_tuple (&keyblob, KEYBLOB_TAG_HDRCOPY, p, n);
+  assert (n < header_space_size);
+  memcpy (header_space, p, n);
+  header_space_used = n;
+
+  /* Turn the keyblob into a buffer and callback to encrypt it.  */
+  keyblob_buf = get_membuf (&keyblob, &keyblob_len);
+  if (!keyblob_buf)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  err = sh_encrypt_keyblob (ctrl, keyblob_buf, keyblob_len, &p, &n);
+  if (err)
+    {
+      log_error ("encrypting the keyblob failed: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+  log_debug ("plain setuparea=%p %zu bytes\n", keyblob_buf, keyblob_len);
+  wipememory (keyblob_buf, keyblob_len);
+  xfree (keyblob_buf);
+  keyblob_buf = NULL;
+
+  log_debug ("encry setuparea=%p %zu bytes\n", p, n);
+  if (n >= header_space_size || (header_space_used + n) >= header_space_size)
+    {
+      err = gpg_error (GPG_ERR_TOO_LARGE);
+      log_error ("setup area would overflow: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+  memcpy (header_space + header_space_used, p, n);
+  header_space_used += n;
+
+  /* Write the padding.  */
+  packet = header_space + header_space_used;
+  paddinglen = header_space_size - header_space_used;
+  if (paddinglen < 16)
+    {
+      err = gpg_error (GPG_ERR_TOO_LARGE);
+      log_error ("setup area too short for padding: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+  packet[0] = (0xc0|61); /* CTB for Private packet type 0x61.  */
+  packet[1] = 0xff;      /* 5 byte length packet, value 20.  */
+  packet[2] = (paddinglen-6) >> 24;
+  packet[3] = (paddinglen-6) >> 16;
+  packet[4] = (paddinglen-6) >> 8;
+  packet[5] = (paddinglen-6);
+  packet += 6;
+  paddinglen -= 6;
+  header_space_used += 6;
+  for ( ;paddinglen >= 10;
+        paddinglen -= 10, packet += 10, header_space_used += 10)
+    memcpy (packet, "GnuPG/PAD", 10);
+  for ( ;paddinglen; paddinglen--, packet++, header_space_used++)
+    *packet = 0;
+
+  if (header_space_used != header_space_size)
+    BUG ();
+
+  /* Create the container.  */
+  {
+    const char *argv[3];
+
+    argv[0] = "create";
+    argv[1] = targetname;
+    argv[2] = NULL;
+    log_debug ("now running \"dmsetup create %s\"\n", targetname);
+    log_debug ("  with table='%s'\"\n", table);
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, table, &result, NULL);
+  }
+  if (err)
+    {
+      log_error ("error running dmsetup for '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  if (result && *result)
+    log_debug ("dmsetup result: %s\n", result);
+
+  /* Write the setup area.  */
+  if (es_fseeko (devfp, 0, SEEK_SET))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error seeking to begin of '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  es_clearerr (devfp);
+
+  for (copy = 0; copy < HEADER_SETUP_AREA_COPIES; copy++)
+    {
+      size_t nwritten;
+
+      if (es_write (devfp, header_space, header_space_size, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      else if (nwritten != header_space_size)
+        {
+          err = gpg_error (GPG_ERR_TOO_SHORT);
+          break;
+        }
+    }
+  if (err)
+    {
+      log_error ("error writing header space copy %d of '%s': %s\n",
+                 copy, devname, gpg_strerror (err));
+      goto leave;
+    }
+
+  if (es_fseeko (devfp,
+                 (- header_space_size * FOOTER_SETUP_AREA_COPIES), SEEK_END))
+    {
+      err = gpg_error_from_syserror ();
+      log_error ("error seeking to end of '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  es_clearerr (devfp);
+
+  for (copy = 0; copy < FOOTER_SETUP_AREA_COPIES; copy++)
+    {
+      size_t nwritten;
+
+      if (es_write (devfp, header_space, header_space_size, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          break;
+        }
+      else if (nwritten != header_space_size)
+        {
+          err = gpg_error (GPG_ERR_TOO_SHORT);
+          break;
+        }
+    }
+  if (!err && es_fflush (devfp))
+    err = gpg_error_from_syserror ();
+  if (err)
+    {
+      log_error ("error writing footer space copy %d of '%s': %s\n",
+                 copy, devname, gpg_strerror (err));
+      goto leave;
+    }
+
+ leave:
+  wipememory (hexkey, sizeof hexkey);
+  if (table)
+    {
+      wipememory (table, strlen (table));
+      xfree (table);
+    }
+  if (keyblob_buf)
+    {
+      wipememory (keyblob_buf, keyblob_len);
+      xfree (keyblob_buf);
+    }
+  xfree (get_membuf (&keyblob, NULL));
+  xfree (targetname);
+  xfree (result);
+  xfree (header_space);
+  return err;
+}
+
+
+/* Mount a DM-Crypt container on device DEVNAME taking keys and other
+ * meta data from KEYBLOB.  */
+gpg_error_t
+sh_dmcrypt_mount_container (ctrl_t ctrl, const char *devname,
+                            tupledesc_t keyblob)
+{
+  gpg_error_t err;
+  char *targetname_abs = NULL;
+  const char *targetname;
+  char hexkey[16*2+1];
+  char *table = NULL;
+  unsigned long long nblocks, nblocks2;
+  char *result = NULL;
+  size_t n;
+  const char *s;
+  const char *algostr;
+  size_t algostrlen;
+
+  if (!ctrl->devti)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  g13_syshelp_i_know_what_i_am_doing ();
+
+  /* Check that the device is not yet used by device mapper. */
+  err = check_blockdev (devname, 0);
+  if (err)
+    goto leave;
+
+  /* Compute the number of blocks and compare them to the value
+     provided as meta data.  */
+  err = sh_blockdev_getsz (devname, &nblocks);
+  if (err)
+    {
+      log_error ("error getting size of '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  err = find_tuple_uint (keyblob, KEYBLOB_TAG_CONT_NSEC, &nblocks2);
+  if (err)
+    {
+      log_error ("error getting size from keyblob: %s\n", gpg_strerror (err));
+      goto leave;
+    }
+  if (nblocks != nblocks2)
+    {
+      log_error ("inconsistent size of container: expected==%llu got=%llu\n",
+                 nblocks2, nblocks);
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  if (nblocks <= HEADER_SECTORS + MIN_ENCRYPTED_SPACE + FOOTER_SECTORS)
+    {
+      log_error ("device '%s' is too small (min=%d blocks)\n",
+                 devname,
+                 HEADER_SECTORS + MIN_ENCRYPTED_SPACE + FOOTER_SECTORS);
+      err = gpg_error (GPG_ERR_TOO_SHORT);
+      goto leave;
+    }
+  nblocks -= HEADER_SECTORS + FOOTER_SECTORS;
+  err = find_tuple_uint (keyblob, KEYBLOB_TAG_ENC_NSEC, &nblocks2);
+  if (err)
+    {
+      log_error ("error getting enc size from keyblob: %s\n",
+                 gpg_strerror (err));
+      goto leave;
+    }
+  if (nblocks != nblocks2)
+    {
+      log_error ("inconsistent size of enc data: expected==%llu got=%llu\n",
+                 nblocks2, nblocks);
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+  /* Check that the offset is consistent.  */
+  err = find_tuple_uint (keyblob, KEYBLOB_TAG_ENC_OFF, &nblocks2);
+  if (err)
+    {
+      log_error ("error getting enc offset from keyblob: %s\n",
+                 gpg_strerror (err));
+      goto leave;
+    }
+  if (nblocks2 != HEADER_SECTORS)
+    {
+      log_error ("inconsistent offset of enc data: expected==%llu got=%d\n",
+                 nblocks2, HEADER_SECTORS);
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+
+  /* Device mapper needs a name for the device: Take it from the label
+     or use "0".  */
+  targetname_abs = strconcat ("/dev/mapper/",
+                              "g13-", ctrl->client.uname, "-",
+                              ctrl->devti->label? ctrl->devti->label : "0",
+                              NULL);
+  if (!targetname_abs)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  targetname = strrchr (targetname_abs, '/');
+  if (!targetname)
+    BUG ();
+  targetname++;
+
+  /* Get the algorithm string.  */
+  algostr = find_tuple (keyblob, KEYBLOB_TAG_ALGOSTR, &algostrlen);
+  if (!algostr || algostrlen > 100)
+    {
+      log_error ("algo string not found in keyblob or too long\n");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+
+  /* Get the key.  */
+  s = find_tuple (keyblob, KEYBLOB_TAG_ENCKEY, &n);
+  if (!s || n != 16)
+    {
+      if (!s)
+        log_error ("no key found in keyblob\n");
+      else
+        log_error ("unexpected size of key (%zu)\n", n);
+      err = gpg_error (GPG_ERR_INV_KEYLEN);
+      goto leave;
+    }
+  bin2hex (s, 16, hexkey);
+
+  /* Build dmcrypt table. */
+  table = es_bsprintf ("0 %llu crypt %.*s %s 0 %s %d",
+                       nblocks, (int)algostrlen, algostr,
+                       hexkey, devname, HEADER_SECTORS);
+  wipememory (hexkey, sizeof hexkey);
+  if (!table)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Load the table.  */
+  {
+    const char *argv[3];
+
+    argv[0] = "create";
+    argv[1] = targetname;
+    argv[2] = NULL;
+    log_debug ("now running \"dmsetup create %s\"\n", targetname);
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, table, &result, NULL);
+  }
+  if (err)
+    {
+      log_error ("error running dmsetup for '%s': %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  if (result && *result)
+    log_debug ("dmsetup result: %s\n", result);
+  xfree (result);
+  result = NULL;
+
+  /* Mount if a mountpoint has been given.  */
+  if (ctrl->devti->mountpoint)
+    {
+      const char *argv[3];
+
+      argv[0] = targetname_abs;
+      argv[1] = ctrl->devti->mountpoint;
+      argv[2] = NULL;
+      log_debug ("now running \"mount %s %s\"\n",
+                 targetname_abs, ctrl->devti->mountpoint);
+      err = gnupg_exec_tool ("/bin/mount", argv, NULL, &result, NULL);
+      if (err)
+        {
+          log_error ("error running mount: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+      if (result && *result)  /* (We should not see output to stdout).  */
+        log_info ("WARNING: mount returned data on stdout! (%s)\n", result);
+    }
+
+
+ leave:
+  wipememory (hexkey, sizeof hexkey);
+  if (table)
+    {
+      wipememory (table, strlen (table));
+      xfree (table);
+    }
+  xfree (targetname_abs);
+  xfree (result);
+  return err;
+}
+
+
+/* Suspend a DM-Crypt container on device DEVNAME and wipe the keys.  */
+gpg_error_t
+sh_dmcrypt_suspend_container (ctrl_t ctrl, const char *devname)
+{
+  gpg_error_t err;
+  char *targetname_abs = NULL;
+  const char *targetname;
+  char *result = NULL;
+
+  if (!ctrl->devti)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  g13_syshelp_i_know_what_i_am_doing ();
+
+  /* Check that the device is used by device mapper. */
+  err = check_blockdev (devname, 1);
+  if (gpg_err_code (err) != GPG_ERR_EBUSY)
+    {
+      log_error ("device '%s' is not used by the device mapper: %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Fixme: Check that this is really a g13 partition.  */
+
+  /* Device mapper needs a name for the device: Take it from the label
+     or use "0".  */
+  targetname_abs = strconcat ("/dev/mapper/",
+                              "g13-", ctrl->client.uname, "-",
+                              ctrl->devti->label? ctrl->devti->label : "0",
+                              NULL);
+  if (!targetname_abs)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  targetname = strrchr (targetname_abs, '/');
+  if (!targetname)
+    BUG ();
+  targetname++;
+
+  /* Send the suspend command.  */
+  {
+    const char *argv[3];
+
+    argv[0] = "suspend";
+    argv[1] = targetname;
+    argv[2] = NULL;
+    log_debug ("now running \"dmsetup suspend %s\"\n", targetname);
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, NULL, &result, NULL);
+  }
+  if (err)
+    {
+      log_error ("error running \"dmsetup suspend %s\": %s\n",
+                 targetname, gpg_strerror (err));
+      goto leave;
+    }
+  if (result && *result)
+    log_debug ("dmsetup result: %s\n", result);
+  xfree (result);
+  result = NULL;
+
+  /* Send the wipe key command.  */
+  {
+    const char *argv[5];
+
+    argv[0] = "message";
+    argv[1] = targetname;
+    argv[2] = "0";
+    argv[3] = "key wipe";
+    argv[4] = NULL;
+    log_debug ("now running \"dmsetup message %s 0 key wipe\"\n", targetname);
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, NULL, &result, NULL);
+  }
+  if (err)
+    {
+      log_error ("error running \"dmsetup message %s 0 key wipe\": %s\n",
+                 targetname, gpg_strerror (err));
+      goto leave;
+    }
+  if (result && *result)
+    log_debug ("dmsetup result: %s\n", result);
+  xfree (result);
+  result = NULL;
+
+
+ leave:
+  xfree (targetname_abs);
+  xfree (result);
+  return err;
+}
+
+
+/* Resume a DM-Crypt container on device DEVNAME taking keys and other
+ * meta data from KEYBLOB.  */
+gpg_error_t
+sh_dmcrypt_resume_container (ctrl_t ctrl, const char *devname,
+                             tupledesc_t keyblob)
+{
+  gpg_error_t err;
+  char *targetname_abs = NULL;
+  const char *targetname;
+  char hexkey[8+16*2+1]; /* 8 is used to prepend "key set ".  */
+  char *table = NULL;
+  char *result = NULL;
+  size_t n;
+  const char *s;
+  const char *algostr;
+  size_t algostrlen;
+
+  if (!ctrl->devti)
+    return gpg_error (GPG_ERR_INV_ARG);
+
+  g13_syshelp_i_know_what_i_am_doing ();
+
+  /* Check that the device is used by device mapper. */
+  err = check_blockdev (devname, 1);
+  if (gpg_err_code (err) != GPG_ERR_EBUSY)
+    {
+      log_error ("device '%s' is not used by the device mapper: %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+
+  /* Device mapper needs a name for the device: Take it from the label
+     or use "0".  */
+  targetname_abs = strconcat ("/dev/mapper/",
+                              "g13-", ctrl->client.uname, "-",
+                              ctrl->devti->label? ctrl->devti->label : "0",
+                              NULL);
+  if (!targetname_abs)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  targetname = strrchr (targetname_abs, '/');
+  if (!targetname)
+    BUG ();
+  targetname++;
+
+  /* Get the algorithm string.  */
+  algostr = find_tuple (keyblob, KEYBLOB_TAG_ALGOSTR, &algostrlen);
+  if (!algostr || algostrlen > 100)
+    {
+      log_error ("algo string not found in keyblob or too long\n");
+      err = gpg_error (GPG_ERR_INV_DATA);
+      goto leave;
+    }
+
+  /* Get the key.  */
+  s = find_tuple (keyblob, KEYBLOB_TAG_ENCKEY, &n);
+  if (!s || n != 16)
+    {
+      if (!s)
+        log_error ("no key found in keyblob\n");
+      else
+        log_error ("unexpected size of key (%zu)\n", n);
+      err = gpg_error (GPG_ERR_INV_KEYLEN);
+      goto leave;
+    }
+  strcpy (hexkey, "key set ");
+  bin2hex (s, 16, hexkey+8);
+
+  /* Send the key */
+  {
+    const char *argv[4];
+
+    argv[0] = "message";
+    argv[1] = targetname;
+    argv[2] = "0";
+    argv[3] = NULL;
+    log_debug ("now running \"dmsetup message %s 0 [key set]\"\n", targetname);
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, hexkey, &result, NULL);
+  }
+  wipememory (hexkey, sizeof hexkey);
+  if (err)
+    {
+      log_error ("error running \"dmsetup message %s 0 [key set]\": %s\n",
+                 devname, gpg_strerror (err));
+      goto leave;
+    }
+  if (result && *result)
+    log_debug ("dmsetup result: %s\n", result);
+  xfree (result);
+  result = NULL;
+
+  /* Send the resume command. */
+  {
+    const char *argv[3];
+
+    argv[0] = "resume";
+    argv[1] = targetname;
+    argv[2] = NULL;
+    log_debug ("now running \"dmsetup resume %s\"\n", targetname);
+    err = gnupg_exec_tool ("/sbin/dmsetup", argv, NULL, &result, NULL);
+  }
+  if (err)
+    {
+      log_error ("error running \"dmsetup resume %s\": %s\n",
+                 targetname, gpg_strerror (err));
+      goto leave;
+    }
+  if (result && *result)
+    log_debug ("dmsetup result: %s\n", result);
+  xfree (result);
+  result = NULL;
+
+ leave:
+  wipememory (hexkey, sizeof hexkey);
+  if (table)
+    {
+      wipememory (table, strlen (table));
+      xfree (table);
+    }
+  xfree (targetname_abs);
+  xfree (result);
+  return err;
+}
diff --git a/g13/suspend.c b/g13/suspend.c
new file mode 100644 (file)
index 0000000..0532c8b
--- /dev/null
@@ -0,0 +1,143 @@
+/* suspend.c - Suspend/Resume a crypto container
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "g13.h"
+#include "i18n.h"
+#include "suspend.h"
+
+#include "keyblob.h"
+#include "backend.h"
+#include "g13tuple.h"
+
+
+
+/* Suspend the container with name FILENAME.  */
+gpg_error_t
+g13_suspend_container (ctrl_t ctrl, const char *filename)
+{
+  gpg_error_t err;
+  int needs_syshelp;
+
+  /* A quick check to see whether the container exists.  */
+  if (access (filename, R_OK))
+    return gpg_error_from_syserror ();
+
+  /* Decide whether we need to use the g13-syshelp because we can't
+     use lock files for them.  This is most likely the case for device
+     files; thus we test for this.  FIXME: The correct solution would
+     be to call g13-syshelp to match the file against the g13tab.  */
+  needs_syshelp = !strncmp (filename, "/dev/", 5);
+
+  if (!needs_syshelp)
+    err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+  else
+    err = be_suspend_container (ctrl, CONTTYPE_DM_CRYPT, filename);
+
+  return err;
+}
+
+
+/* Resume the container with name FILENAME.  */
+gpg_error_t
+g13_resume_container (ctrl_t ctrl, const char *filename)
+{
+  gpg_error_t err;
+  int needs_syshelp;
+  void *enckeyblob = NULL;
+  size_t enckeybloblen;
+  void *keyblob = NULL;
+  size_t keybloblen;
+  tupledesc_t tuples = NULL;
+  size_t n;
+  const unsigned char *value;
+  int conttype;
+  char *mountpoint_buffer = NULL;
+
+  /* A quick check to see whether the container exists.  */
+  if (access (filename, R_OK))
+    return gpg_error_from_syserror ();
+
+  /* Decide whether we need to use the g13-syshelp because we can't
+     use lock files for them.  This is most likely the case for device
+     files; thus we test for this.  FIXME: The correct solution would
+     be to call g13-syshelp to match the file against the g13tab.  */
+  needs_syshelp = !strncmp (filename, "/dev/", 5);
+
+  if (!needs_syshelp)
+    {
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      goto leave;
+    }
+
+  /* Read the encrypted keyblob.  */
+  /* Fixme: Should we move this to syshelp for dm-crypt or do we
+     assume that the encrypted device is world readable?  */
+  err = g13_keyblob_read (filename, &enckeyblob, &enckeybloblen);
+  if (err)
+    goto leave;
+
+  /* Decrypt that keyblob and store it in a tuple descriptor.  */
+  err = g13_keyblob_decrypt (ctrl, enckeyblob, enckeybloblen,
+                             &keyblob, &keybloblen);
+  if (err)
+    goto leave;
+  xfree (enckeyblob);
+  enckeyblob = NULL;
+
+  err = create_tupledesc (&tuples, keyblob, keybloblen);
+  if (!err)
+    keyblob = NULL;
+  else
+    {
+      if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
+        log_error ("unknown keyblob version\n");
+      goto leave;
+    }
+  if (opt.verbose)
+    dump_tupledesc (tuples);
+
+  value = find_tuple (tuples, KEYBLOB_TAG_CONTTYPE, &n);
+  if (!value || n != 2)
+    conttype = 0;
+  else
+    conttype = (value[0] << 8 | value[1]);
+  if (!be_is_supported_conttype (conttype))
+    {
+      log_error ("content type %d is not supported\n", conttype);
+      err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+      goto leave;
+    }
+  err = be_resume_container (ctrl, conttype, filename, tuples);
+
+ leave:
+  destroy_tupledesc (tuples);
+  xfree (keyblob);
+  xfree (enckeyblob);
+  xfree (mountpoint_buffer);
+  return err;
+}
diff --git a/g13/suspend.h b/g13/suspend.h
new file mode 100644 (file)
index 0000000..91702eb
--- /dev/null
@@ -0,0 +1,26 @@
+/* suspend.h - Suspend/Resume a crypto container.
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef G13_SUSPEND_H
+#define G13_SUSPEND_H
+
+gpg_error_t g13_suspend_container (ctrl_t ctrl, const char *filename);
+gpg_error_t g13_resume_container (ctrl_t ctrl, const char *filename);
+
+#endif /*G13_SUSPEND_H*/
diff --git a/g13/t-g13tuple.c b/g13/t-g13tuple.c
new file mode 100644 (file)
index 0000000..f986efa
--- /dev/null
@@ -0,0 +1,223 @@
+/* t-g13tuple.c - Module test for g13tuple.c
+ * Copyright (C) 2016 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+
+#include "util.h"
+#include "keyblob.h"
+#include "g13tuple.h"
+
+#define PGM "t-g13tuple"
+
+static int verbose;
+static int debug;
+static int errcount;
+
+/* Test for the functions append_tuple_uint and find_tuple_unit.  */
+static void
+test_tuple_uint (void)
+{
+  static struct {
+    int tag;
+    int len;
+    char *data;
+    unsigned long long val;
+    gpg_err_code_t ec;
+  } tv[] = {
+    { 1, 0, "",     0, GPG_ERR_ERANGE },
+    { 2, 1, "\x00", 0, 0},
+    { 3, 1, "\x7f", 127ull, 0},
+    { 4, 1, "\x80", 0, GPG_ERR_ERANGE },
+    { 5, 1, "\x81", 0, GPG_ERR_ERANGE },
+    { 6, 2, "\x80\x01", 0, GPG_ERR_ERANGE },
+    { 7, 2, "\x00\x80", 128ull, 0 },
+    { 8, 1, "\x01", 1, 0 },
+    { 9, 1, "\x40", 64, 0 },
+    { 10, 2, "\x40\x00", 16384, 0 },
+    { 11, 8, "\x7f\xff\xff\xff\xff\xff\xff\xff", 0x7fffffffffffffffull, 0 },
+    { 12, 9, "\x00\xff\xff\xff\xff\xff\xff\xff\xff", 0xffffffffffffffffull, 0},
+    { 13, 9, "\x01\xff\xff\xff\xff\xff\xff\xff\xff", 0, GPG_ERR_ERANGE }
+  };
+  int tidx;
+  gpg_error_t err;
+  membuf_t mb, mb2;
+  void *p;
+  const void *s;
+  size_t n;
+  tupledesc_t tuples;
+  tupledesc_t tuples2;
+  unsigned long long value;
+  int i;
+
+  init_membuf (&mb, 512);
+  init_membuf (&mb2, 512);
+  append_tuple (&mb, KEYBLOB_TAG_BLOBVERSION, "\x01", 1);
+  append_tuple (&mb2, KEYBLOB_TAG_BLOBVERSION, "\x01", 1);
+  for (tidx=0; tidx < DIM (tv); tidx++)
+    {
+      append_tuple (&mb, tv[tidx].tag, tv[tidx].data, tv[tidx].len);
+      if (!tv[tidx].ec)
+        append_tuple_uint (&mb2, tv[tidx].tag, tv[tidx].val);
+    }
+
+  p = get_membuf (&mb, &n);
+  if (!p)
+    {
+      err = gpg_error_from_syserror ();
+      fprintf (stderr, PGM ":%s: get_membuf failed: %s\n",
+               __func__, gpg_strerror (err));
+      exit (1);
+    }
+  err = create_tupledesc (&tuples, p, n);
+  if (err)
+    {
+      fprintf (stderr, PGM ":%s: create_tupledesc failed: %s\n",
+               __func__, gpg_strerror (err));
+      exit (1);
+    }
+  p = get_membuf (&mb2, &n);
+  if (!p)
+    {
+      err = gpg_error_from_syserror ();
+      fprintf (stderr, PGM ":%s: get_membuf failed: %s\n",
+               __func__, gpg_strerror (err));
+      exit (1);
+    }
+  err = create_tupledesc (&tuples2, p, n);
+  if (err)
+    {
+      fprintf (stderr, PGM ":%s: create_tupledesc failed: %s\n",
+               __func__, gpg_strerror (err));
+      exit (1);
+    }
+
+  for (tidx=0; tidx < DIM (tv); tidx++)
+    {
+      err = find_tuple_uint (tuples, tv[tidx].tag, &value);
+      if (tv[tidx].ec != gpg_err_code (err))
+        {
+          fprintf (stderr, PGM ":%s:tidx=%d: wrong error returned; "
+                   "expected(%s) got(%s)\n",
+                   __func__, tidx,
+                   gpg_strerror (tv[tidx].ec), gpg_strerror (err));
+          errcount++;
+        }
+      else if (!err && tv[tidx].val != value)
+        {
+          fprintf (stderr, PGM ":%s:tidx=%d: wrong value returned; "
+                   "expected(%llx) got(%llx)\n",
+                   __func__, tidx, tv[tidx].val, value);
+          errcount++;
+        }
+
+      err = find_tuple_uint (tuples2, tv[tidx].tag, &value);
+      if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+        {
+          if (!tv[tidx].ec)
+            {
+              fprintf (stderr, PGM ":%s:tidx=%d: find_tuple failed: %s\n",
+                       __func__, tidx, gpg_strerror (err));
+              errcount++;
+            }
+        }
+      else if (tv[tidx].ec != gpg_err_code (err))
+        {
+          fprintf (stderr, PGM ":%s:tidx=%d: wrong error returned (2); "
+                   "expected(%s) got(%s)\n",
+                   __func__, tidx,
+                   gpg_strerror (tv[tidx].ec), gpg_strerror (err));
+          errcount++;
+        }
+      else if (!err && tv[tidx].val != value)
+        {
+          fprintf (stderr, PGM ":%s:tidx=%d: wrong value returned (2); "
+                   "expected(%llx) got(%llx)\n",
+                   __func__, tidx, tv[tidx].val, value);
+          errcount++;
+        }
+
+      s = find_tuple (tuples2, tv[tidx].tag, &n);
+      if (!s)
+        ;
+      else if (tv[tidx].len != n)
+        {
+          fprintf (stderr, PGM ":%s:tidx=%d: wrong string length returned; "
+                   "expected(%d) got(%zu)\n",
+                   __func__, tidx, tv[tidx].len, n);
+          errcount++;
+            }
+      else if (memcmp (tv[tidx].data, s, n))
+        {
+          fprintf (stderr, PGM ":%s:tidx=%d: wrong string returned:",
+                   __func__, tidx);
+          for (i=0; i < n; i++)
+            fprintf (stderr, " %02x", ((unsigned char*)s)[i]);
+          fputc ('\n', stderr);
+          errcount++;
+        }
+    }
+
+  destroy_tupledesc (tuples);
+  destroy_tupledesc (tuples2);
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+
+  gpgrt_init ();
+  if (argc)
+    { argc--; argv++; }
+  while (argc && last_argc != argc )
+    {
+      last_argc = argc;
+      if (!strcmp (*argv, "--"))
+        {
+          argc--; argv++;
+          break;
+        }
+      else if (!strcmp (*argv, "--verbose"))
+        {
+          verbose++;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--debug"))
+        {
+          verbose += 2;
+          debug++;
+          argc--; argv++;
+        }
+      else if (!strncmp (*argv, "--", 2))
+        {
+          fprintf (stderr, PGM ": unknown option '%s'\n", *argv);
+          exit (1);
+        }
+    }
+
+  test_tuple_uint ();
+
+  return !!errcount;
+}
index eaf7565..59dfe0c 100644 (file)
@@ -77,7 +77,7 @@ _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted)
       return gpg_error_from_syserror ();
     }
 
-  imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
+  imagelen = ((unsigned int) c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
   if (imagelen < 5)
     return gpg_error (GPG_ERR_TOO_SHORT);
 
index e70ad36..0a64bc4 100644 (file)
--- a/po/ca.po
+++ b/po/ca.po
@@ -405,7 +405,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "error en la creació de la contrasenya: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -509,6 +509,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: s'ha creat el directori\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVÍS: els permissos són insegurs en %s «%s»\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "base de dades de confiança: ha fallat la lectura (n=%d): %s\n"
 
@@ -763,9 +767,9 @@ msgstr "error en la creació de la contrasenya: %s\n"
 msgid "error forking process: %s\n"
 msgstr "error en la lectura de «%s»: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "ha fallat l'actualització: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -783,6 +787,10 @@ msgstr "error en la lectura de «%s»: %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "s'ha produït un error mentre s'escrivia l'anell secret «%s»: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -803,6 +811,10 @@ msgstr "s'ha cancel·lat per l'usuari\n"
 msgid "problem with the agent\n"
 msgstr "hi ha un problema amb l'agent: l'agent ha tornat 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "hi ha un problema amb l'agent: l'agent ha tornat 0x%lx\n"
+
 # bolcats de memòria?  ivb
 #, c-format
 msgid "can't disable core dumps: %s\n"
@@ -862,6 +874,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "error en crear l'anell «%s»: %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1161,10 +1177,6 @@ msgstr "no forçat"
 msgid "invalid option \"%.50s\"\n"
 msgstr "opcions d'importació no vàlides\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "heu trobat un bug... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "no s'ha pogut crear l'armadura: %s\n"
@@ -1271,6 +1283,11 @@ msgstr ""
 "hi ha un caràcter «quoted printable» en l'armadura - probablement s'ha "
 "utilitzat un MTA amb errors\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "no llegible per humans"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1288,12 +1305,22 @@ msgstr "un nom de notació d'usuari no pot contenir el caràcter «@»\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "un valor de notació no pot utilitzar cap caràcter de control\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "un nom de notació d'usuari no pot contenir el caràcter «@»\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"un nom de notació només pot tenir caràcters imprimibles o espais i acabar "
+"amb el signe «=»\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "AVÍS: s'hi han trobat dades de notació invàlides\n"
 
-msgid "not human readable"
-msgstr "no llegible per humans"
-
 #, fuzzy, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "no s'ha pogut posar «%s» en la base de dades de confiança - %s\n"
@@ -1393,10 +1420,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "error en crear l'anell «%s»: %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "error en la lectura de «%s»: %s\n"
@@ -1737,14 +1760,14 @@ msgstr ""
 "forçar el xifrat asimètric %s (%d) viola les preferències del destinatari\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "no podeu usar %s mentre esteu en mode %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s xifrat per a: «%s»\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "no podeu usar %s mentre esteu en mode %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "dades xifrades amb %s\n"
 
@@ -2044,7 +2067,7 @@ msgstr "|algo [fitxers]|imprimeix resums de missatges"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3075,11 +3098,27 @@ msgid "[self-signature]"
 msgstr "[autosignatura]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d signatures errònies\n"
-msgstr[1] "%d signatures errònies\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "clau %08lX: l'algoritme de clau pública no és suportat\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "signatura %s, algorisme de resum %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Signatura correcta de \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "es descarta «%s»: %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "L'ID d'usuari «%s» està revocat."
+msgstr[1] "L'ID d'usuari «%s» està revocat."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3089,18 +3128,23 @@ msgstr[0] "1 signatura no comprovada per falta de clau\n"
 msgstr[1] "1 signatura no comprovada per falta de clau\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 signatura no comprovada a causa d'un error\n"
-msgstr[1] "1 signatura no comprovada a causa d'un error\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d signatures errònies\n"
+msgstr[1] "%d signatures errònies\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "Han estat detectats %d IDs sense autosignatura vàlida\n"
-msgstr[1] "Han estat detectats %d IDs sense autosignatura vàlida\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Signatura correcta de \""
+msgstr[1] "Signatura correcta de \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3321,9 +3365,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "error en la creació de la contrasenya: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "s'està posant la signatura al lloc correcte\n"
-
 msgid "save and quit"
 msgstr "desa i ix"
 
@@ -3616,6 +3657,11 @@ msgstr "error: l'empremta digital és invàlida\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "no s'ha pogut emmagatzemar l'empremta digital: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "el valor no és vàlid\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4461,6 +4507,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d signatures errònies\n"
 msgstr[1] "%d signatures errònies\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 signatura no comprovada a causa d'un error\n"
+msgstr[1] "1 signatura no comprovada a causa d'un error\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5715,16 +5768,16 @@ msgstr ""
 msgid "trustdb transaction too large\n"
 msgstr "la transacció de la base de dades de confiança és massa gran\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: el directori no existeix!\n"
+
 # No em passe! ;)  ivb
 #, fuzzy, c-format
 msgid "can't access '%s': %s\n"
 msgstr "no s'ha pogut tancar «%s»: %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: el directori no existeix!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: no s'ha pogut crear un registre de versió: %s"
 
@@ -5874,8 +5927,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5964,39 +6017,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "error en la creació de la contrasenya: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -6005,20 +6060,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [fitxers]|imprimeix resums de missatges"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -6032,12 +6089,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8979,6 +9043,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "heu trobat un bug... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "Han estat detectats %d IDs sense autosignatura vàlida\n"
+#~ msgstr[1] "Han estat detectats %d IDs sense autosignatura vàlida\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "s'està posant la signatura al lloc correcte\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d signatures no comprovades per falta de clau\n"
 
@@ -9074,11 +9151,6 @@ msgstr ""
 #~ msgstr "no s'ha pogut obrir «%s»: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "el valor no és vàlid\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "error en llegir el bloc de claus secretes «%s»: %s\n"
 
index 6ebfe07..535f74c 100644 (file)
--- a/po/cs.po
+++ b/po/cs.po
@@ -389,7 +389,9 @@ msgstr "nedovolit klientům označovat klíče za „důvěryhodné“"
 msgid "allow presetting passphrase"
 msgstr "umožnit přednastavení hesla"
 
-msgid "allow caller to override the pinentry"
+#, fuzzy
+#| msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr "umožnit volajícímu přebít pinentry"
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -478,6 +480,12 @@ msgstr "nelze vytvořit adresář „%s“: %s\n"
 msgid "directory '%s' created\n"
 msgstr "adresář „%s“ vytvořen\n"
 
+# TODO: i18n of first %s
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Varování: přístupová práva %s „%s“ nejsou bezpečná\n"
+
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "volání stat() na „%s“ selhalo: %s\n"
@@ -732,8 +740,9 @@ msgstr "chyba při vytváření proudu pro rouru: %s\n"
 msgid "error forking process: %s\n"
 msgstr "chyba při rozdvojování procesu: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "čekání na konec procesu %d se nezdařilo: %s\n"
 
 #, c-format
@@ -753,6 +762,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "chyba při získání návratového kódu procesu %d: %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "čekání na konec procesu %d se nezdařilo: %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "nelze se připojit k „%s“: %s\n"
 
@@ -768,6 +781,11 @@ msgstr "zrušeno uživatelem\n"
 msgid "problem with the agent\n"
 msgstr "problém s agentem\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problém s agentem: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "nemohu vypnout vytváření core souborů: %s\n"
@@ -826,6 +844,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "při pokusu alokovat %lu bajtů došla paměť"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "chyba při alokování dostatečného množství paměti: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: zastaralý parametr „%s“ – neúčinkuje\n"
 
@@ -1065,10 +1087,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "neplatný parametr „%.50s“\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "našli jste chybu… (%s:%d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "převod z „%s“ na „%s“ není k dispozici\n"
 
@@ -1168,6 +1186,11 @@ msgstr ""
 "neplatný znak (quoted-printable) v ASCII kódování – pravděpodobně byl použit "
 "špatný MTA\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "není v přímo čitelném formátu"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1184,12 +1207,23 @@ msgstr "jméno uživatele nesmí obsahovat více než jeden znak „@“\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "hodnota nemůže obsahovat žádné kontrolní znaky\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "jméno uživatele nesmí obsahovat více než jeden znak „@“\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"symbolické jméno smí obsahovat pouze písmena, číslice, tečky nebo podtržítka "
+"a musí končit znakem „=“\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "VAROVÁNÍ: nalezen neplatný formát zápisu data\n"
 
-msgid "not human readable"
-msgstr "není v přímo čitelném formátu"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "předání dotazu %s klientovi se nezdařilo\n"
@@ -1276,10 +1310,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Chyba: URL je příliš dlouhé (limit je %d znaků).\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "chyba při alokování dostatečného množství paměti: %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "chyba při čtení „%s“: %s\n"
 
@@ -1595,14 +1625,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "vyžádaná symetrická šifra %s (%d) nevyhovuje předvolbám příjemce\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "použití %s není v módu %s dovoleno\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s zašifrovaný pro: „%s“\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "použití %s není v módu %s dovoleno\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s zašifrovaná data\n"
 
@@ -1872,7 +1902,9 @@ msgstr "vypsat hash zprávy"
 msgid "run in server mode"
 msgstr "pracovat v režimu serveru"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+#, fuzzy
+#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 "|HODNOTA|nastavit TOFU politiku klíči (good [dobrý], unknown [neznámý], bad "
 "[špatný], ask [zeptat se], auto)"
@@ -2848,12 +2880,33 @@ msgid "[self-signature]"
 msgstr "[podpis klíče jím samým]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d špatných podpisů\n"
-msgstr[1] "%d špatných podpisů\n"
-msgstr[2] "%d špatných podpisů\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "klíč %s: nepodporovaný algoritmus veřejného klíče\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "karta nepodporuje hashovací algoritmus %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Dobrý podpis od"
+
+#, fuzzy, c-format
+#| msgid "key %s: %s\n"
+msgid "key %s:\n"
+msgstr "klíč %s: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Uživatelské ID „%s“: %d podpisů odstraněno\n"
+msgstr[1] "Uživatelské ID „%s“: %d podpisů odstraněno\n"
+msgstr[2] "Uživatelské ID „%s“: %d podpisů odstraněno\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2864,23 +2917,26 @@ msgstr[1] "1 podpis neověřen, protože chybí klíč\n"
 msgstr[2] "1 podpis neověřen, protože chybí klíč\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 podpis neověřen, protože vznikla chyba\n"
-msgstr[1] "1 podpis neověřen, protože vznikla chyba\n"
-msgstr[2] "1 podpis neověřen, protože vznikla chyba\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d špatných podpisů\n"
+msgstr[1] "%d špatných podpisů\n"
+msgstr[2] "%d špatných podpisů\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] ""
-"objeveno %d identifikátorů uživatele bez platného podpisu jím samým\n"
-msgstr[1] ""
-"objeveno %d identifikátorů uživatele bez platného podpisu jím samým\n"
-msgstr[2] ""
-"objeveno %d identifikátorů uživatele bez platného podpisu jím samým\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Dobrý podpis od"
+msgstr[1] "Dobrý podpis od"
+msgstr[2] "Dobrý podpis od"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3080,9 +3136,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "klíč %s: chyba při měnění hesla: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "přesunuji podpis klíče na správné místo\n"
-
 msgid "save and quit"
 msgstr "uložit a ukončit"
 
@@ -3328,6 +3381,11 @@ msgstr "„%s“ není otisk\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "„%s“ není primární otisk\n"
 
+#, fuzzy, c-format
+#| msgid "read error in '%s': %s\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "chyba při čtení v „%s“: %s\n"
+
 msgid "No matching user IDs."
 msgstr "Žádný identifikátor uživatele neodpovídá."
 
@@ -4115,6 +4173,14 @@ msgstr[1] "%d dobrých podpisů\n"
 msgstr[2] "%d dobrých podpisů\n"
 
 #, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 podpis neověřen, protože vznikla chyba\n"
+msgstr[1] "1 podpis neověřen, protože vznikla chyba\n"
+msgstr[2] "1 podpis neověřen, protože vznikla chyba\n"
+
+#, fuzzy, c-format
 #| msgid "Warning: %lu key(s) skipped due to their large size\n"
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5328,14 +5394,14 @@ msgid "trustdb transaction too large\n"
 msgstr "transakce s databází důvěry je příliš dlouhá\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "k „%s“ nelze přistoupit: %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: adresář neexistuje!\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "k „%s“ nelze přistoupit: %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: nepodařilo se vytvořit záznam verze: %s"
 
@@ -5481,8 +5547,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5581,44 +5647,46 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "chyba při vytváření roury: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -5628,20 +5696,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "vypsat hash zprávy"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -5656,12 +5727,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -8454,6 +8532,23 @@ msgstr ""
 "Syntaxe: gpg-check-pattern [volby] soubor_se_vzorem\n"
 "Prověří heslo zadané na vstupu proti souboru se vzory\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "našli jste chybu… (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] ""
+#~ "objeveno %d identifikátorů uživatele bez platného podpisu jím samým\n"
+#~ msgstr[1] ""
+#~ "objeveno %d identifikátorů uživatele bez platného podpisu jím samým\n"
+#~ msgstr[2] ""
+#~ "objeveno %d identifikátorů uživatele bez platného podpisu jím samým\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "přesunuji podpis klíče na správné místo\n"
+
 #~ msgid "key specification '%s' is ambiguous\n"
 #~ msgstr "výběr klíče pomocí „%s“ není jednoznačné\n"
 
index 4e2680a..7e6ff4b 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -414,7 +414,7 @@ msgstr "tillad klienter at markere nøgler som »trusted« (troværdige)"
 msgid "allow presetting passphrase"
 msgstr "tillad forhåndsindstilling af adgangsfrase"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -519,6 +519,11 @@ msgid "directory '%s' created\n"
 msgstr "mappe »%s« oprettet\n"
 
 #, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Advarsel: usikre rettigheder på %s »%s«\n"
+
+#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat() mislykkedes for »%s«: %s\n"
@@ -792,8 +797,9 @@ msgstr "fejl ved oprettelse af datakanal: %s\n"
 msgid "error forking process: %s\n"
 msgstr "fejl ved forgrening af proces: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "ventning på at proces %d skulle terminere mislykkedes: %s\n"
 
 #, fuzzy, c-format
@@ -815,6 +821,10 @@ msgstr "fejl ved kørsel af »%s«: termineret\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "fejl ved indhentelse af afslutningskode for proces %d: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "ventning på at proces %d skulle terminere mislykkedes: %s\n"
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -832,6 +842,11 @@ msgstr "afbrudt af brugeren\n"
 msgid "problem with the agent\n"
 msgstr "problem med agenten\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problem med agenten: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "kan ikke slå kernedump fra: %s\n"
@@ -888,6 +903,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "ikke nok kerne under allokering af %lu byte"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "fejl ved allokering af nok hukommelse: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: forældet indstilling »%s« - den har ingen effekt\n"
 
@@ -1138,10 +1157,6 @@ msgstr "uden for kerne\n"
 msgid "invalid option \"%.50s\"\n"
 msgstr "ugyldigt tilvalg »%.50s«\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "du fandt en fejl ... (%s:%d)\n"
-
 #, fuzzy, c-format
 #| msgid "conversion from `%s' to `%s' not available\n"
 msgid "conversion from '%s' to '%s' not available\n"
@@ -1246,6 +1261,11 @@ msgid ""
 msgstr ""
 "citeret udskrivingstegn i panser - måske på grund af en fejlbehæftet MTA\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "kan ikke læses af mennesker"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1262,12 +1282,23 @@ msgstr "et notationsnavn må ikke indeholde mere end et »@«-tegn\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "en notationsværdi må ikke bruge nogen kontroltegn\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "et notationsnavn må ikke indeholde mere end et »@«-tegn\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"et notationsnavn må kun have udskrivningstegn eller mellemrum og skal "
+"sluttes med et »=«\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "ADVARSEL: Ingen notationsdata fundet\n"
 
-msgid "not human readable"
-msgstr "kan ikke læses af mennesker"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "kunne ikke proxy %s-forespørgsel til klient\n"
@@ -1355,10 +1386,6 @@ msgstr "Adresse hvor offentlig nøgle skal hentes: "
 msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Fejl: Adresse er for lang (begrænsningen er %d tegn).\n"
 
-#, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "fejl ved allokering af nok hukommelse: %s\n"
-
 #, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
@@ -1701,14 +1728,14 @@ msgstr ""
 "tvang for symmetrisk chiffer %s (%d) overtræder modtagerens præferencer\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "du kan ikke bruge %s i tilstanden %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s krypteret for: »%s«\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "du kan ikke bruge %s i tilstanden %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s krypterede data\n"
 
@@ -1991,7 +2018,7 @@ msgstr "vis beskedsammendrag"
 msgid "run in server mode"
 msgstr "kør i servertilstand"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3011,11 +3038,32 @@ msgid "[self-signature]"
 msgstr "[egenunderskrift]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d ugyldige underskrifter\n"
-msgstr[1] "%d ugyldige underskrifter\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "nøgle %s: ikke understøttet offentlig nøglealgoritme\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "kort understøtter ikke sammendragsalgoritme %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "God underskrift fra"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "udelod »%s«: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Bruger-id »%s«: %d underskrift fjernet\n"
+msgstr[1] "Bruger-id »%s«: %d underskrift fjernet\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3025,18 +3073,24 @@ msgstr[0] "1 underskrift er ikke kontrolleret på grund af en manglende nøgle\n
 msgstr[1] "1 underskrift er ikke kontrolleret på grund af en manglende nøgle\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 underskrift er ikke kontrolleret på grund af en fejl\n"
-msgstr[1] "1 underskrift er ikke kontrolleret på grund af en fejl\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d ugyldige underskrifter\n"
+msgstr[1] "%d ugyldige underskrifter\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d bruger-id'er uden gyldige egenunderskrifter detekteret\n"
-msgstr[1] "%d bruger-id'er uden gyldige egenunderskrifter detekteret\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "God underskrift fra"
+msgstr[1] "God underskrift fra"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3244,9 +3298,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "fejl ved oprettelse af adgangsfrase: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "flytter en nøgleunderskrift til det korrekte sted\n"
-
 msgid "save and quit"
 msgstr "gem og afslut"
 
@@ -3516,6 +3567,11 @@ msgstr "ugyldig fingeraftryk"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "kunne ikke indhente fingeraftrykket\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "ugyldig værdi\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4341,6 +4397,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d ugyldige underskrifter\n"
 msgstr[1] "%d ugyldige underskrifter\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 underskrift er ikke kontrolleret på grund af en fejl\n"
+msgstr[1] "1 underskrift er ikke kontrolleret på grund af en fejl\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5577,16 +5640,16 @@ msgstr "trustdb rec %lu: skrivning mislykkedes (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "transaktion for trustdb er for stor\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: mappe findes ikke!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "kan ikke tilgå »%s«: %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: mappe findes ikke!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: kunne ikke oprette versionspost: %s"
 
@@ -5734,8 +5797,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5828,39 +5891,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "fejl ved oprettelse af datakanal: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5869,20 +5934,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "vis beskedsammendrag"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5896,12 +5964,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8995,6 +9070,19 @@ msgstr ""
 "Syntaks: gpg-check-pattern [tilvalg] mønsterfil\n"
 "Kontroller en adgangsfrase angivet på stdin mod mønsterfilen\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "du fandt en fejl ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d bruger-id'er uden gyldige egenunderskrifter detekteret\n"
+#~ msgstr[1] "%d bruger-id'er uden gyldige egenunderskrifter detekteret\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "flytter en nøgleunderskrift til det korrekte sted\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -9097,11 +9185,6 @@ msgstr ""
 #~ msgstr "kan ikke åbne »%s«: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "ugyldig værdi\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "fejl ved læsning af hemmelig nøgleblok »%s«: %s\n"
index 3dad2a2..f5886ef 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -9,7 +9,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gnupg-2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2016-01-26 13:18+0100\n"
+"PO-Revision-Date: 2016-05-04 11:03+0200\n"
 "Last-Translator: Werner Koch <wk@gnupg.org>\n"
 "Language-Team: German <de@li.org>\n"
 "Language: de\n"
@@ -299,7 +299,7 @@ msgstr ""
 
 msgid "Warning: You have entered an insecure passphrase."
 msgstr ""
-"WARNUNG:  Sie haben eine offensichtlich unsichere%%0APassphrase eingegeben."
+"WARNUNG:  Sie haben eine offensichtlich unsichere%0APassphrase eingegeben."
 
 #, c-format
 msgid "Please enter the passphrase to%0Aprotect your new key"
@@ -378,8 +378,8 @@ msgstr "Verbiete Aufrufern Schlüssel als \"vertrauenswürdig\" zu markieren"
 msgid "allow presetting passphrase"
 msgstr "Erlaube ein \"preset\" von Passphrases"
 
-msgid "allow caller to override the pinentry"
-msgstr "Aufrufer darf das Pinentry ersetzen"
+msgid "disallow caller to override the pinentry"
+msgstr "Aufrufer darf das Pinentry nicht ersetzen"
 
 msgid "allow passphrase to be prompted through Emacs"
 msgstr "Erlaube die Eingabe einer Passphrase über Emacs"
@@ -467,6 +467,10 @@ msgid "directory '%s' created\n"
 msgstr "Verzeichnis `%s' erzeugt\n"
 
 #, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Zugriffsrechte für '%s' können nicht gesetzt werden: %s\n"
+
+#, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat()-Aufruf für `%s' fehlgeschlagen: %s\n"
 
@@ -734,8 +738,8 @@ msgid "error forking process: %s\n"
 msgstr "Fehler beim \"Forken\" des Prozess: %s\n"
 
 #, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr "Das Warten auf die Beendigung des Prozesses %d schlug fehl: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "Das Warten auf die Beendigung von Prozessen schlug fehl: %s\n"
 
 #, c-format
 msgid "error running '%s': probably not installed\n"
@@ -754,6 +758,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "Fehler beim Holen des Exitwerte des Prozesses %d: %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "Das Warten auf die Beendigung des Prozesses %d schlug fehl: %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "Verbindung zu '%s' kann nicht aufgebaut werden: %s\n"
 
@@ -770,6 +778,10 @@ msgid "problem with the agent\n"
 msgstr "Problem mit dem Agenten\n"
 
 #, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "Problem mit dem Agenten (unerwartete Antwort \"%s\")\n"
+
+#, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "core-dump-Dateierzeugung kann nicht abgeschaltet werden: %s\n"
 
@@ -826,6 +838,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "Kein Speicher mehr vorhanden, als %lu Byte zugewiesen werden sollten"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "Fehler beim Zuteilen genügenden Speichers: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: Die Option \"%s\" is veraltet - sie hat keine Wirkung\n"
 
@@ -1064,10 +1080,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "Ungültige Option \"%.50s\"\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "Sie haben einen Bug (Programmfehler) gefunden ... (%s:%d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "Umwandlung von `%s' in `%s' ist nicht verfügbar\n"
 
@@ -1167,6 +1179,10 @@ msgstr ""
 "\"quoted printable\" Zeichen in der ASCII-Hülle gefunden - möglicherweise\n"
 " war ein fehlerhafter Email-Transporter(\"MTA\") die Ursache\n"
 
+#, c-format
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "[ Nicht als Klartext darstellbar (%zu bytes: %s%s) ]"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1183,12 +1199,17 @@ msgstr "Ein \"notation\"-Wert darf das '@'-Zeichen maximal einmal verwenden\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "Ein \"notation\"-Wert darf keine Kontrollzeichen verwenden\n"
 
+msgid "a notation name may not contain an '=' character\n"
+msgstr "Ein \"notation\"-Wert darf das '='-Zeichen nicht verwenden\n"
+
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"Ein \"notation\"-Name darf nur Buchstaben, Zahlen, Punkte oder Unterstriche "
+"enthalten\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "WARNUNG: Ungültige \"Notation\"-Daten gefunden\n"
 
-msgid "not human readable"
-msgstr "nicht als Klartext darstellbar"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "Die %s \"inquiry\" konnte nicht an den Client weitergeleitet werden\n"
@@ -1274,10 +1295,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Fehler: URL ist zu lang (Grenze beträgt %d Zeichen).\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "Fehler beim Zuteilen genügenden Speichers: %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "Fehler beim Lesen von `%s': %s\n"
 
@@ -1604,14 +1621,14 @@ msgstr ""
 "verletzt die Empfängervoreinstellungen\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "Die Benutzung von %s ist im %s-Modus nicht erlaubt.\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s verschlüsselt für: %s\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "Die Benutzung von %s ist im %s-Modus nicht erlaubt.\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s verschlüsselte Daten\n"
 
@@ -1877,10 +1894,8 @@ msgstr "Hashwerte für die Dateien ausgeben"
 msgid "run in server mode"
 msgstr "Im Server Modus ausführen"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
-msgstr ""
-"|WERT|Setze die TOFU-Politik für einen Schlüssel (good, unknown, bad, ask, "
-"auto)"
+msgid "|VALUE|set the TOFU policy for a key"
+msgstr "|WERT|Setze die TOFU-Politik für einen Schlüssel"
 
 msgid "create ascii armored output"
 msgstr "Ausgabe mit ASCII-Hülle versehen"
@@ -2868,10 +2883,30 @@ msgid "[self-signature]"
 msgstr "[Eigenbeglaubigung]"
 
 #, c-format
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d falsche Beglaubigung\n"
-msgstr[1] "%d falsche Beglaubigungen\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr ""
+"Die Signatur mit den nicht unterstützten Public-Key-Verfahren (%d) kann "
+"nicht geprüft werden: %s\n"
+
+#, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr ""
+"Die Signatur mit der nicht unterstützten Hashmethode (%d) kann nicht\n"
+"geprüft werden: %s.\n"
+
+msgid " (reordered signatures follow)"
+msgstr " (neu geordnete Signaturen folgen)"
+
+#, c-format
+msgid "key %s:\n"
+msgstr "Schlüssel %s:\n"
+
+#, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "%d doppelte Signatur entfernt\n"
+msgstr[1] "%d doppelte Signaturen entfernt\n"
 
 #, c-format
 msgid "%d signature not checked due to a missing key\n"
@@ -2880,16 +2915,24 @@ msgstr[0] "%d Beglaubigung wegen fehlendem Schlüssel nicht geprüft\n"
 msgstr[1] "%d Beglaubigungen wegen fehlender Schlüssel nicht geprüft\n"
 
 #, c-format
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "%d Beglaubigung aufgrund eines Fehlers nicht geprüft\n"
-msgstr[1] "%d Beglaubigungen aufgrund von Fehlern nicht geprüft\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d falsche Beglaubigung\n"
+msgstr[1] "%d falsche Beglaubigungen\n"
 
 #, c-format
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d User-ID ohne gültige Eigenbeglaubigung entdeckt\n"
-msgstr[1] "%d User-IDs ohne gültige Eigenbeglaubigungen entdeckt\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "%d Signatur neu eingeordnet\n"
+msgstr[1] "%d Signaturen neu eingeordnet\n"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
+"WARNUNG: Es wurden Fehler gefunden aber nur Eigenbeglaubigungen geprüft; um "
+"alle Beglaubigungen zu prüfen das Kommando '%s' verwenden.\n"
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3093,9 +3136,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "Schlüssel %s: Fehler beim Ändern der Passphrase: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "schiebe eine Beglaubigung an die richtige Stelle\n"
-
 msgid "save and quit"
 msgstr "speichern und Menü verlassen"
 
@@ -3351,6 +3391,10 @@ msgstr "\"%s\" ist kein Fingerabdruck\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "\"%s\" ist nicht der Fingerabdruck des Hauptschlüssels\n"
 
+#, c-format
+msgid "Invalid user ID '%s': %s\n"
+msgstr "Ungültige User-ID '%s': %s\n"
+
 msgid "No matching user IDs."
 msgstr "Keine passende User-ID"
 
@@ -3381,8 +3425,7 @@ msgstr "Der folgende Schlüssel wurde am %s von %s Schlüssel %s widerrufen\n"
 
 #, c-format
 msgid "This key may be revoked by %s key %s"
-msgstr ""
-"Dieser Schlüssel könnte durch %s mit Schlüssel %s  widerrufen worden sein"
+msgstr "Dieser Schlüssel kann von %s-Schlüssel %s widerrufen werden"
 
 msgid "(sensitive)"
 msgstr "(empfindlich)"
@@ -4142,6 +4185,12 @@ msgstr[0] "%d korrekte Signatur\n"
 msgstr[1] "%d korrekte Signaturen\n"
 
 #, c-format
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "%d Beglaubigung aufgrund eines Fehlers nicht geprüft\n"
+msgstr[1] "%d Beglaubigungen aufgrund von Fehlern nicht geprüft\n"
+
+#, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
 msgstr[0] "WARNUNG: %lu Schlüssel übersprungen, da er zu groß ist\n"
@@ -5370,14 +5419,14 @@ msgid "trustdb transaction too large\n"
 msgstr "trustdb Transaktion zu groß\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "kann auf `%s' nicht zugreifen: %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: Verzeichnis existiert nicht!\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "kann auf `%s' nicht zugreifen: %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: Fehler beim Erzeugen des Versionsatzes: %s"
 
@@ -5517,11 +5566,12 @@ msgstr "Die Bindung %s ist NICHT bekannt."
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
-"Der Schlüssel %s steht im Konflikt mit der Bindung (%s).  Die Richtlinie "
-"dieser Bindung wurde deswegen von 'auto' auf 'ask' geändert."
+"Der Schlüssel mit dem Fingerabdruck %s steht im Konflikt mit der Bindung "
+"(%s).  Die Richtlinie dieser Bindung wurde deswegen von 'auto' auf 'ask' "
+"geändert."
 
 #, c-format
 msgid ""
@@ -5616,70 +5666,73 @@ msgstr "(G)ut, einmal (A)kzeptieren, (U)nbekannt, einmal ab(L)ehnen, (F)alsch?"
 msgid "error changing TOFU policy: %s\n"
 msgstr "Fehler beim Ändern der TOFU Richtlinie: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
-msgstr[0] "%d Jahr"
-msgstr[1] "%d Jahre"
+msgid "%d~year"
+msgid_plural "%d~years"
+msgstr[0] "%d~Jahr"
+msgstr[1] "%d~Jahre"
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
-msgstr[0] "%d Monat"
-msgstr[1] "%d Monate"
+msgid "%d~month"
+msgid_plural "%d~months"
+msgstr[0] "%d~Monat"
+msgstr[1] "%d~Monate"
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
-msgstr[0] "%d Tag"
-msgstr[1] "%d Tage"
+msgid "%d~day"
+msgid_plural "%d~days"
+msgstr[0] "%d~Tag"
+msgstr[1] "%d~Tage"
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
-msgstr[0] "%d Stunde"
-msgstr[1] "%d Stunden"
+msgid "%d~hour"
+msgid_plural "%d~hours"
+msgstr[0] "%d~Stunde"
+msgstr[1] "%d~Stunden"
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
-msgstr[0] "%d Minute"
-msgstr[1] "%d Minuten"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
+msgstr[0] "%d~Minute"
+msgstr[1] "%d~Minuten"
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
-msgstr[0] "%d Sekunde"
-msgstr[1] "%d Sekunden"
+msgid "%d~second"
+msgid_plural "%d~seconds"
+msgstr[0] "%d~Sekunde"
+msgstr[1] "%d~Sekunden"
 
 #, c-format
 msgid "Have never verified a message signed by key %s!\n"
 msgstr "Es wurde noch keine Nachricht mit dem Schlüssel %s überprüft!\n"
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 "Signaturstatistiken für \"%s\" (Schlüssel %s) konnten nicht gesammelt "
 "werden\n"
 
 #, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
-"Keine von \"%s\" signierten Nachrichten überprüft (Schl.: %s, Richtl.: %s)."
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "%ld überprüfte Nachrichten von \"%s\"."
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
-"%ld von \"%s\" (Schl.: %s, Richtl.: %s) signierte Nachricht in den letzten "
-"%s überprüft."
+"%ld überprüfte Nachricht von \"%s\"\n"
+"in den letzten %s."
 msgstr[1] ""
-"%ld von \"%s\" (Schl.: %s, Richtl.: %s) signierte Nachrichten in den letzten "
-"%s überprüft."
+"%ld überprüfte Nachrichten von \"%s\"\n"
+"in den letzten %s."
 
 #, c-format
 msgid "The most recent message was verified %s ago."
@@ -5695,26 +5748,33 @@ msgstr ""
 "WARNUNG: Wir haben nur eine einzige mit diesem Schlüssel signierte Nachricht "
 "gesehen.\n"
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
-"WARNUNG: Falls sie glauben, mehr als %d mit diesem Schlüssel signierte\n"
-"Nachricht erhalten zu haben, so kann es sich bei diesem Schlüssel um\n"
-"eine Fälschung handeln!  Prüfen Sie die Email-Adresse genau auf kleine\n"
-"Variationen (z.B. zusätzliche Leerzeichen).  Falls Ihnen der Schlüssel\n"
-"suspekt erscheint, so benutzen Sie '%s' um den Schlüssel als Fälschung\n"
-"zu markieren."
+"WARNUNG: Falls sie glauben, mehr als %ld mit diesem Schlüssel signierte "
+"Nachricht erhalten zu haben, so kann es sich bei diesem Schlüssel um eine "
+"Fälschung handeln!  Prüfen Sie die Email-Adresse genau auf kleine "
+"Variationen.  Falls Ihnen der Schlüssel suspekt erscheint, so benutzen Sie\n"
+"  %s\n"
+"um den Schlüssel als Fälschung zu markieren.\n"
 msgstr[1] ""
-"WARNUNG: Falls sie glauben, mehr als %d mit diesem Schlüssel signierte\n"
-"Nachrichten erhalten zu haben, so kann es sich bei diesem Schlüssel um\n"
-"eine Fälschung handeln!  Prüfen Sie die Email-Adresse genau auf kleine\n"
-"Variationen (z.B. zusätzliche Leerzeichen).  Falls Ihnen der Schlüssel\n"
-"suspekt erscheint, so benutzen Sie '%s' um den Schlüssel als Fälschung\n"
-"zu markieren."
+"WARNUNG: Falls sie glauben, mehr als %ld mit diesem Schlüssel signierte "
+"Nachrichten erhalten zu haben, so kann es sich bei diesem Schlüssel um eine "
+"Fälschung handeln!  Prüfen Sie die Email-Adresse genau auf kleine "
+"Variationen.  Falls Ihnen der Schlüssel suspekt erscheint, so benutzen Sie\n"
+"  %s\n"
+"um den Schlüssel als Fälschung zu markieren.\n"
 
 #, c-format
 msgid "error opening TOFU database: %s\n"
@@ -8545,6 +8605,39 @@ msgstr ""
 "Syntax: gpg-check-pattern [optionen] Musterdatei\n"
 "Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "Sie haben einen Bug (Programmfehler) gefunden ... (%s:%d)\n"
+
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d User-ID ohne gültige Eigenbeglaubigung entdeckt\n"
+#~ msgstr[1] "%d User-IDs ohne gültige Eigenbeglaubigungen entdeckt\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "schiebe eine Beglaubigung an die richtige Stelle\n"
+
+#~ msgid "%d day"
+#~ msgid_plural "%d days"
+#~ msgstr[0] "%d Tag"
+#~ msgstr[1] "%d Tage"
+
+#~ msgid "TOFU: few signatures %d message %s"
+#~ msgid_plural "TOFU: few signatures %d messages %s"
+#~ msgstr[0] ""
+#~ "WARNUNG: Falls sie glauben, mehr als %d mit diesem Schlüssel signierte\n"
+#~ "Nachricht erhalten zu haben, so kann es sich bei diesem Schlüssel um\n"
+#~ "eine Fälschung handeln!  Prüfen Sie die Email-Adresse genau auf kleine\n"
+#~ "Variationen (z.B. zusätzliche Leerzeichen).  Falls Ihnen der Schlüssel\n"
+#~ "suspekt erscheint, so benutzen Sie '%s' um den Schlüssel als Fälschung\n"
+#~ "zu markieren."
+#~ msgstr[1] ""
+#~ "WARNUNG: Falls sie glauben, mehr als %d mit diesem Schlüssel signierte\n"
+#~ "Nachrichten erhalten zu haben, so kann es sich bei diesem Schlüssel um\n"
+#~ "eine Fälschung handeln!  Prüfen Sie die Email-Adresse genau auf kleine\n"
+#~ "Variationen (z.B. zusätzliche Leerzeichen).  Falls Ihnen der Schlüssel\n"
+#~ "suspekt erscheint, so benutzen Sie '%s' um den Schlüssel als Fälschung\n"
+#~ "zu markieren."
+
 #~ msgid "sending key %s to %s server %s\n"
 #~ msgstr "sende Schlüssel %s auf den %s-Server %s\n"
 
@@ -8699,10 +8792,6 @@ msgstr ""
 #~ msgid "Failed to parse '%s'.\n"
 #~ msgstr "Datei `%s' kann nicht gescannt werden\n"
 
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "Ungültiger Wert '%s'\n"
-
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "Fehler beim Nachschlagen der geheimen Schlüssels \"%s\": %s\n"
index ed66200..d4316dd 100644 (file)
--- a/po/el.po
+++ b/po/el.po
@@ -381,7 +381,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "óöÜëìá óôç äçìéïõñãßá ôçò öñÜóçò êëåéäß: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -479,6 +479,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: êáôÜëïãïò äçìéïõñãÞèçêå\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: ìç áóöáëåßò Üäåéåò óôï %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: read áðÝôõ÷å (n=%d): %s\n"
 
@@ -731,9 +735,9 @@ msgstr "
 msgid "error forking process: %s\n"
 msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "ç åíçìÝñùóç áðÝôõ÷å: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -751,6 +755,10 @@ msgstr "
 msgid "error getting exit code of process %d: %s\n"
 msgstr "áäõíáìßá åããñáöÞò ìõóôéêÞò êëåéäïèÞêçò `%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -771,6 +779,10 @@ msgstr "
 msgid "problem with the agent\n"
 msgstr "ðñüâëçìá ìå ôïí agent: agent åðéóôñÝöåé 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "ðñüâëçìá ìå ôïí agent: agent åðéóôñÝöåé 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "áäõíáìßá áðåíåñãïðïßçóçò ôùí core dump: %s\n"
@@ -827,6 +839,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "áäõíáìßá äçìéïõñãßáò ôçò êëåéäïèÞêçò `%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1103,10 +1119,6 @@ msgstr "
 msgid "invalid option \"%.50s\"\n"
 msgstr "ìç Ýãêõñåò åðéëïãÝò åéãáãùãÞò\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "âñÞêáôå Ýíá bug ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "èùñÜêéóç áðÝôõ÷å: %s\n"
@@ -1210,6 +1222,11 @@ msgstr ""
 "åêôõðþóéìïò, óå åéóáãùãéêÜ, ÷áñáêôÞñáò óôç èùñÜêéóç - ßóùò Ýãéíå ÷ñÞóç "
 "ðñïâëçìáôéêïý MTA\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "ìç áíáãíþóéìï"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1227,12 +1244,22 @@ msgstr "
 msgid "a notation value must not use any control characters\n"
 msgstr "ç ôéìÞ óçìåßùóçò ðñÝðåé íá ìç ÷ñçóéìïðïéåß ÷áñáêôÞñåò control\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "ôï üíïìá óçìåßùóçò ÷ñÞóôç ðñÝðåé íá ðåñéÝ÷åé ôï '@' ÷áñáêôÞñá\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"Ýíá üíïìá óçìåßùóçò ìðïñåß íá ðåñéÝ÷åé ìüíï åêôõðþóéìïõò ÷áñáêôÞñåò êáé êåíÜ "
+"êáé íá ëÞãåé ìå Ýíá '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "ÐÑÏÅÉÄÏÐÏÉÇÓÇ: âñÝèçêáí ìç Ýãêõñá äåäïìÝíá óçìåßùóçò\n"
 
-msgid "not human readable"
-msgstr "ìç áíáãíþóéìï"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1327,10 +1354,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "áäõíáìßá äçìéïõñãßáò ôçò êëåéäïèÞêçò `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ `%s': %s\n"
@@ -1673,14 +1696,14 @@ msgstr ""
 "åðéëïãÝò ôïõ ðáñáëÞðôç\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "áðáãïñåýåôå ç ÷ñÞóç ôïõ %s óôçí êáôÜóôáóç %s.\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s êñõðôïãñáöÞèçêå ãéá: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "áðáãïñåýåôå ç ÷ñÞóç ôïõ %s óôçí êáôÜóôáóç %s.\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s êñõðôïãñáöçìÝíá äåäïìÝíá\n"
 
@@ -1974,7 +1997,7 @@ msgstr "|
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2989,11 +3012,27 @@ msgid "[self-signature]"
 msgstr "[éäéï-õðïãñáöÞ]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d êáêÝò õðïãñáöÝò\n"
-msgstr[1] "%d êáêÝò õðïãñáöÝò\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "êëåéäß %08lX: ìç õðïóôçñéæüìåíïò áëãüñéèìïò äçìïóßïõ êëåéäéïý\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%s õðïãñáöÞ, áëãüñéèìïò ðåñßëçøçò %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "ÊáëÞ õðïãñáöÞ áðü \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "ðáñáëåßöèçêå `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Ôï user ID \"%s\" áíáêáëåßôå."
+msgstr[1] "Ôï user ID \"%s\" áíáêáëåßôå."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3003,18 +3042,23 @@ msgstr[0] "1 
 msgstr[1] "1 õðïãñáöÞ äåí åëÝã÷èçêå ëüãù ÷áìÝíïõ êëåéäéïý\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 õðïãñáöÞ äåí åëÝã÷èçêå ëüãï åíüò óöÜëìáôïò\n"
-msgstr[1] "1 õðïãñáöÞ äåí åëÝã÷èçêå ëüãï åíüò óöÜëìáôïò\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d êáêÝò õðïãñáöÝò\n"
+msgstr[1] "%d êáêÝò õðïãñáöÝò\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d user ID áíé÷íåýèçêáí ÷ùñßò Ýãêõñåò éäéï-õðïãñáöÝò\n"
-msgstr[1] "%d user ID áíé÷íåýèçêáí ÷ùñßò Ýãêõñåò éäéï-õðïãñáöÝò\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "ÊáëÞ õðïãñáöÞ áðü \""
+msgstr[1] "ÊáëÞ õðïãñáöÞ áðü \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3237,9 +3281,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "óöÜëìá óôç äçìéïõñãßá ôçò öñÜóçò êëåéäß: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "ìåôáêßíçóç õðïãñáöÞò êëåéäéïý óôç óùóôÞ èÝóç\n"
-
 msgid "save and quit"
 msgstr "áðïèÞêåõóç êáé Ýîïäïò"
 
@@ -3522,6 +3563,11 @@ msgstr "
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "áðïôõ÷ßá áñ÷éêïðïßçóçò ôçò TrustDB: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "ìç Ýãêõñç ôéìÞ\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4358,6 +4404,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d êáêÝò õðïãñáöÝò\n"
 msgstr[1] "%d êáêÝò õðïãñáöÝò\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 õðïãñáöÞ äåí åëÝã÷èçêå ëüãï åíüò óöÜëìáôïò\n"
+msgstr[1] "1 õðïãñáöÞ äåí åëÝã÷èçêå ëüãï åíüò óöÜëìáôïò\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5586,14 +5639,14 @@ msgstr "trustdb rec %lu: 
 msgid "trustdb transaction too large\n"
 msgstr "ðïëý ìåãÜëç óõíáëëáãÞ trustdb\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "áäõíáìßá êëåéóßìáôïò ôïõ `%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: ï öÜêåëïò äåí õðÜñ÷åé!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "áäõíáìßá êëåéóßìáôïò ôïõ `%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: áðïôõ÷ßá äçìéïõñãßáò ìéáò åããñáöÞò Ýêäïóçò: %s"
@@ -5739,8 +5792,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5829,39 +5882,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "óöÜëìá óôç äçìéïõñãßá ôçò öñÜóçò êëåéäß: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5870,20 +5925,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|áëãüñ [áñ÷åßá]| áðåéêüíéóç ðåñéëÞøåùí ôùí ìçíõìÜôùí"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5897,12 +5954,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8795,6 +8859,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "âñÞêáôå Ýíá bug ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d user ID áíé÷íåýèçêáí ÷ùñßò Ýãêõñåò éäéï-õðïãñáöÝò\n"
+#~ msgstr[1] "%d user ID áíé÷íåýèçêáí ÷ùñßò Ýãêõñåò éäéï-õðïãñáöÝò\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "ìåôáêßíçóç õðïãñáöÞò êëåéäéïý óôç óùóôÞ èÝóç\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d õðïãñáöÝò äåí åëÝã÷èçêáí ëüãù ÷áìÝíùí êëåéäéþí\n"
 
@@ -8889,11 +8966,6 @@ msgstr ""
 #~ msgstr "áäõíáìßá ðñüóâáóçò óôï `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "ìç Ýãêõñç ôéìÞ\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "óöÜëìá êáôÜ ôçí áíÜãíùóç ìõóôéêïý ìðëïê êëåéäéïý `%s': %s\n"
 
index f6e30db..43b29a8 100644 (file)
--- a/po/eo.po
+++ b/po/eo.po
@@ -383,7 +383,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "eraro dum kreado de pasfrazo: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -479,6 +479,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: dosierujo kreita\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Averto: malsekuraj permesoj sur %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fido-datenaro: lego malsukcesis (n=%d): %s\n"
 
@@ -731,9 +735,9 @@ msgstr "eraro dum kreado de pasfrazo: %s\n"
 msgid "error forking process: %s\n"
 msgstr "eraro dum legado de '%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "aktualigo malsukcesis: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -751,6 +755,10 @@ msgstr "eraro dum legado de '%s': %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "eraro dum skribado de sekreta þlosilaro '%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -771,6 +779,10 @@ msgstr "nuligita de uzanto\n"
 msgid "problem with the agent\n"
 msgstr "problemo kun agento: agento redonas 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problemo kun agento: agento redonas 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "ne povas malþalti kreadon de core-dosieroj: %s\n"
@@ -828,6 +840,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "eraro dum kreado de þlosilaro '%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1108,10 +1124,6 @@ msgstr "ne traktita"
 msgid "invalid option \"%.50s\"\n"
 msgstr "nevalida kiraso"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "vi trovis cimon ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "enkirasigo malsukcesis: %s\n"
@@ -1215,6 +1227,11 @@ msgstr ""
 "quoted-printable-signo en kiraso - verþajne cima poþtotransendilo estis "
 "uzata\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "ne homlegebla"
+
 #, fuzzy
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
@@ -1234,12 +1251,19 @@ msgstr "notacia valoro ne povas enhavi stirsignojn\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "notacia valoro ne povas enhavi stirsignojn\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "notacia valoro ne povas enhavi stirsignojn\n"
+
+#, fuzzy
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"notacia nomo devas enhavi nur literojn, ciferojn, punktojn aý substrekojn "
+"kaj fini per '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "AVERTO: nevalida notacia dateno trovita\n"
 
-msgid "not human readable"
-msgstr "ne homlegebla"
-
 #, fuzzy, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "malsukcesis meti '%s' en fido-datenaron: %s\n"
@@ -1334,10 +1358,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "eraro dum kreado de þlosilaro '%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "eraro dum legado de '%s': %s\n"
@@ -1672,13 +1692,13 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "Tiu komando ne eblas en la reøimo %s.\n"
-
-#, fuzzy, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s-æifrita por: %s\n"
 
+#, fuzzy, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "Tiu komando ne eblas en la reøimo %s.\n"
+
 #, c-format
 msgid "%s encrypted data\n"
 msgstr "%s-æifritaj datenoj\n"
@@ -1963,7 +1983,7 @@ msgstr "|metodo [dosieroj]|presi mesa
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2967,11 +2987,27 @@ msgid "[self-signature]"
 msgstr "[mem-subskribo]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d malbonaj subskriboj\n"
-msgstr[1] "%d malbonaj subskriboj\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "þlosilo %08lX: nerealigita publikþlosila metodo\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%s-subskribo de: %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Bona subskribo de \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "ignoris '%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Uzantidentigilo \"%s\" estas revokita.\n"
+msgstr[1] "Uzantidentigilo \"%s\" estas revokita.\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2981,18 +3017,23 @@ msgstr[0] "1 subskribo ne kontrolita pro manko de 
 msgstr[1] "1 subskribo ne kontrolita pro manko de þlosilo\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 subskribo ne kontrolita pro eraro\n"
-msgstr[1] "1 subskribo ne kontrolita pro eraro\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d malbonaj subskriboj\n"
+msgstr[1] "%d malbonaj subskriboj\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d uzantidentigiloj sen valida mem-subskribo estis trovitaj\n"
-msgstr[1] "%d uzantidentigiloj sen valida mem-subskribo estis trovitaj\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Bona subskribo de \""
+msgstr[1] "Bona subskribo de \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3229,9 +3270,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "eraro dum kreado de pasfrazo: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "movas þlosilsubskribon al la øusta loko\n"
-
 msgid "save and quit"
 msgstr "skribi kaj fini"
 
@@ -3512,6 +3550,11 @@ msgstr "%s: nevalida dosiero-versio %d\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "malsukcesis doni komencajn valorojn al fido-datenaro: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "nevalida valoro\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4334,6 +4377,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d malbonaj subskriboj\n"
 msgstr[1] "%d malbonaj subskriboj\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 subskribo ne kontrolita pro eraro\n"
+msgstr[1] "1 subskribo ne kontrolita pro eraro\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5536,14 +5586,14 @@ msgstr "fido-datenaro loko %lu: skribo malsukcesis (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "fido-datenaro-transakcio tro granda\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "ne povas fermi '%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: dosierujo ne ekzistas!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "ne povas fermi '%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: malsukcesis krei versiregistron: %s"
@@ -5688,8 +5738,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5778,39 +5828,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "eraro dum kreado de pasfrazo: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5819,20 +5871,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|metodo [dosieroj]|presi mesaøo-kompendiojn"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5846,12 +5900,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8741,6 +8802,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "vi trovis cimon ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d uzantidentigiloj sen valida mem-subskribo estis trovitaj\n"
+#~ msgstr[1] "%d uzantidentigiloj sen valida mem-subskribo estis trovitaj\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "movas þlosilsubskribon al la øusta loko\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d subskriboj ne kontrolitaj pro manko de þlosiloj\n"
 
@@ -8834,11 +8908,6 @@ msgstr ""
 #~ msgstr "ne povas malfermi '%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "nevalida valoro\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "eraro dum legado de sekreta þlosilbloko '%s': %s\n"
 
index d1915dc..09fc298 100644 (file)
--- a/po/es.po
+++ b/po/es.po
@@ -428,7 +428,7 @@ msgstr "permitir que los clientes marquen claves como \"fiables\""
 msgid "allow presetting passphrase"
 msgstr "permitir preestablecer frase contraseña"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -535,6 +535,11 @@ msgid "directory '%s' created\n"
 msgstr "directorio `%s' creado\n"
 
 #, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Aviso: permisos inseguros en %s \"%s\"\n"
+
+#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat() falló para `%s': %s\n"
@@ -811,8 +816,9 @@ msgstr "error creando tuber
 msgid "error forking process: %s\n"
 msgstr "error bifurcando procesos: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "fallo esperando que el proceso %d terminara: %s\n"
 
 #, fuzzy, c-format
@@ -834,6 +840,10 @@ msgstr "error ejecutando `%s': terminado\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "error obteniendo código de finalización del proceso: %d %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "fallo esperando que el proceso %d terminara: %s\n"
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -851,6 +861,11 @@ msgstr "cancelado por el usuario\n"
 msgid "problem with the agent\n"
 msgstr "problema con el agente\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problema con el agente: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "no se pueden desactivar los volcados de core: %s\n"
@@ -907,6 +922,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "error de memoria reservando %lu bytes"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "error reservando memoria: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: opción obsoleta \"%s\" - no tiene efecto\n"
 
@@ -1157,10 +1176,6 @@ msgstr "memoria desbordada\n"
 msgid "invalid option \"%.50s\"\n"
 msgstr "opción inválida \"%.50s\"\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "ha encontrado un error... (%s:%d)\n"
-
 #, fuzzy, c-format
 #| msgid "conversion from `%s' to `%s' not available\n"
 msgid "conversion from '%s' to '%s' not available\n"
@@ -1266,6 +1281,11 @@ msgstr ""
 "caracter \"quoted printable\" en la armadura - probablemente se usó\n"
 "un MTA defectuoso\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "ilegible"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1282,12 +1302,23 @@ msgstr "un nombre de notaci
 msgid "a notation value must not use any control characters\n"
 msgstr "un valor de notación no debe usar ningún caracter de control\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "un nombre de notación no debe contener más de un caracter '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"un nombre de notación debe tener sólo caracteres imprimibles o espacios, y "
+"acabar con un '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "ATENCIÓN: encontrados datos de notación inválidos\n"
 
-msgid "not human readable"
-msgstr "ilegible"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "fallo al hacer la petición proxy %s al cliente\n"
@@ -1373,10 +1404,6 @@ msgstr "URL de donde recuperar la clave p
 msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Error: URL demasiado larga (el máximo son %d caracteres).\n"
 
-#, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "error reservando memoria: %s\n"
-
 #, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
@@ -1720,14 +1747,14 @@ msgstr ""
 "del destinatario\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "no puede usar %s en modo %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s cifrado para: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "no puede usar %s en modo %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "datos cifrados %s\n"
 
@@ -2010,7 +2037,7 @@ msgstr "imprime res
 msgid "run in server mode"
 msgstr "ejecutar en modo servidor"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3040,11 +3067,32 @@ msgid "[self-signature]"
 msgstr "[autofirma]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d firmas incorrectas\n"
-msgstr[1] "%d firmas incorrectas\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "clave %s: algoritmo de clave pública no disponible\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "la tarjeta no permite usar el algoritmo de resumen %s\n"
+
+#, fuzzy
+#| msgid "revoke signatures"
+msgid " (reordered signatures follow)"
+msgstr "revoca firmas"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "omitido \"%s\": %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "ID de usuario \"%s\": %d firma borrada\n"
+msgstr[1] "ID de usuario \"%s\": %d firma borrada\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3054,18 +3102,24 @@ msgstr[0] "1 firma no comprobada por falta de clave\n"
 msgstr[1] "1 firma no comprobada por falta de clave\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 firma no comprobada por causa de un error\n"
-msgstr[1] "1 firma no comprobada por causa de un error\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d firmas incorrectas\n"
+msgstr[1] "%d firmas incorrectas\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "Detectados %d identificadores de usuario sin autofirma válida\n"
-msgstr[1] "Detectados %d identificadores de usuario sin autofirma válida\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Firma correcta de"
+msgstr[1] "Firma correcta de"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3264,9 +3318,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "error creando frase contraseña: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "moviendo la firma de la clave al lugar correcto\n"
-
 msgid "save and quit"
 msgstr "graba y sale"
 
@@ -3528,6 +3579,11 @@ msgstr "huella dactilar no v
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "fallo obteniendo huella digital\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "valor inválido\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4340,6 +4396,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d firmas incorrectas\n"
 msgstr[1] "%d firmas incorrectas\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 firma no comprobada por causa de un error\n"
+msgstr[1] "1 firma no comprobada por causa de un error\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5570,16 +5633,16 @@ msgstr ""
 msgid "trustdb transaction too large\n"
 msgstr "transacción en la base de datos de confianza demasiado grande\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: ¡el directorio no existe!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "no se puede acceder a `%s': %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: ¡el directorio no existe!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: fallo en la creación del registro de versión: %s"
 
@@ -5727,8 +5790,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5821,40 +5884,42 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "error creando tubería: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, fuzzy, c-format
 #| msgid "second"
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] "segundo"
 msgstr[1] "segundo"
 
@@ -5863,20 +5928,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "imprime resúmenes de mensaje"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5890,12 +5958,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -9036,6 +9111,19 @@ msgstr ""
 "Compara frase contraseña dada en entrada estándar con un fichero de "
 "patrones\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "ha encontrado un error... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "Detectados %d identificadores de usuario sin autofirma válida\n"
+#~ msgstr[1] "Detectados %d identificadores de usuario sin autofirma válida\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "moviendo la firma de la clave al lugar correcto\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -9148,11 +9236,6 @@ msgstr ""
 #~ msgstr "fallo abriendo `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "valor inválido\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "error leyendo bloque de clave secreta \"%s\": %s\n"
@@ -10530,9 +10613,6 @@ msgstr ""
 #~ msgid "revsig"
 #~ msgstr "revfir"
 
-#~ msgid "revoke signatures"
-#~ msgstr "revoca firmas"
-
 #~ msgid "revuid"
 #~ msgstr "revidu"
 
index 49df7cc..ccd011b 100644 (file)
--- a/po/et.po
+++ b/po/et.po
@@ -379,7 +379,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "viga parooli loomisel: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -477,6 +477,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: kataloog on loodud\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "HOIATUS: ebaturvalised õigused %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: lugemine ebaõnnestus (n=%d): %s\n"
 
@@ -729,9 +733,9 @@ msgstr "viga parooli loomisel: %s\n"
 msgid "error forking process: %s\n"
 msgstr "viga `%s' lugemisel: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "uuendamine ebaõnnestus: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -749,6 +753,10 @@ msgstr "viga `%s' lugemisel: %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "viga salajase võtme võtmehoidlasse `%s' kirjutamisel: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -769,6 +777,10 @@ msgstr "katkestatud kasutaja poolt\n"
 msgid "problem with the agent\n"
 msgstr "probleem agendiga: agent tagastas 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "probleem agendiga: agent tagastas 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "ei õnnestu blokeerida mälupildi salvestamist: %s\n"
@@ -825,6 +837,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "viga võtmehoidla `%s' loomisel: %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1101,10 +1117,6 @@ msgstr "ei t
 msgid "invalid option \"%.50s\"\n"
 msgstr "vigased impordi võtmed\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "te leidsite vea ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "pakendamine ebaõnnestus: %s\n"
@@ -1207,6 +1219,11 @@ msgid ""
 msgstr ""
 "kvooditud sümbol pakendis - tõenäoliselt on kasutatud vigast MTA programmi\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "pole inimese poolt loetav"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1224,12 +1241,22 @@ msgstr "kasutaja noteerimise nimi peab sisaldama '@' m
 msgid "a notation value must not use any control characters\n"
 msgstr "noteerimise väärtus ei või sisaldada kontroll sümboleid\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "kasutaja noteerimise nimi peab sisaldama '@' märki\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"noteerimise nimes võivad olla ainult trükitavad sümbolid või tühikud\n"
+"ning lõpus peab olema '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "HOIATUS: leidsin vigased noteerimise andmed\n"
 
-msgid "not human readable"
-msgstr "pole inimese poolt loetav"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1324,10 +1351,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "viga võtmehoidla `%s' loomisel: %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "viga `%s' lugemisel: %s\n"
@@ -1666,14 +1689,14 @@ msgstr ""
 "sümmetrilise ¨ifri %s (%d) kasutamine on vastuolus saaja eelistustega\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "%s ei ole moodis %s lubatud.\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s krüptitud kasutajale: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "%s ei ole moodis %s lubatud.\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s krüpteeritud andmed\n"
 
@@ -1967,7 +1990,7 @@ msgstr "|algo [failid]|tr
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2968,11 +2991,27 @@ msgid "[self-signature]"
 msgstr "[iseenda allkiri]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d halba allkirja\n"
-msgstr[1] "%d halba allkirja\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "võti %08lX: mittetoetatud avaliku võtme algoritm\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%s allkiri, sõnumilühendi algoritm %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Korrektne allkiri kasutajalt \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "`%s' jätsin vahele: %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Kasutaja ID \"%s\" on tühistatud."
+msgstr[1] "Kasutaja ID \"%s\" on tühistatud."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2982,18 +3021,23 @@ msgstr[0] "1 allkiri j
 msgstr[1] "1 allkiri jäi testimata, kuna võti puudub\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 allkiri jäi vea tõttu kontrollimata\n"
-msgstr[1] "1 allkiri jäi vea tõttu kontrollimata\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d halba allkirja\n"
+msgstr[1] "%d halba allkirja\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "tuvastasin %d kehtiva iseenda allkirjata kasutaja IDd\n"
-msgstr[1] "tuvastasin %d kehtiva iseenda allkirjata kasutaja IDd\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Korrektne allkiri kasutajalt \""
+msgstr[1] "Korrektne allkiri kasutajalt \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3214,9 +3258,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "viga parooli loomisel: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "tõstan võtme allkirja õigesse kohta\n"
-
 msgid "save and quit"
 msgstr "salvesta ja välju"
 
@@ -3495,6 +3536,11 @@ msgstr "viga: vigane s
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "TrustDB initsialiseerimine ebaõnnestus: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "vigane väärtus\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4311,6 +4357,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d halba allkirja\n"
 msgstr[1] "%d halba allkirja\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 allkiri jäi vea tõttu kontrollimata\n"
+msgstr[1] "1 allkiri jäi vea tõttu kontrollimata\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5511,14 +5564,14 @@ msgstr "trustdb rec %lu: write failed (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "trustdb transaktsioon on liiga suur\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "`%s' ei õnnestu sulgeda: %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: kataloogi ei ole!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "`%s' ei õnnestu sulgeda: %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: versioonikirje loomine ei õnnestu: %s"
@@ -5664,8 +5717,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5754,39 +5807,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "viga parooli loomisel: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5795,20 +5850,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [failid]|trüki teatelühendid"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5822,12 +5879,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8712,6 +8776,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "te leidsite vea ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "tuvastasin %d kehtiva iseenda allkirjata kasutaja IDd\n"
+#~ msgstr[1] "tuvastasin %d kehtiva iseenda allkirjata kasutaja IDd\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "tõstan võtme allkirja õigesse kohta\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d allkirja jäi testimata, kuna võtmed puuduvad\n"
 
@@ -8803,11 +8880,6 @@ msgstr ""
 #~ msgstr "`%s' ei õnnestu avada: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "vigane väärtus\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "viga salajase võtmebloki `%s' lugemisel: %s\n"
 
index 681d891..48b8b2e 100644 (file)
--- a/po/fi.po
+++ b/po/fi.po
@@ -395,7 +395,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "virhe luotaessa salasanaa: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -494,6 +494,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: hakemisto luotu\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "VAROITUS: oikeudet kohteessa %s \"%s\" eivät ole turvallisia\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: luku epäonnistui (n=%d): %s\n"
 
@@ -746,9 +750,9 @@ msgstr "virhe luotaessa salasanaa: %s\n"
 msgid "error forking process: %s\n"
 msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "päivitys epäonnistui: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -766,6 +770,10 @@ msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "virhe kirjoitettaessa salaiseen avainrenkaaseen \"%s\": %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -786,6 +794,10 @@ msgstr "käyttäjän peruma\n"
 msgid "problem with the agent\n"
 msgstr "agentin käytössä on ongelmia: agentti vastaa 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "agentin käytössä on ongelmia: agentti vastaa 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "core-tiedostojen luontia ei voi estää: %s\n"
@@ -842,6 +854,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "virhe luotaessa avainrengasta \"%s\": %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1118,10 +1134,6 @@ msgstr "ei käsitelty"
 msgid "invalid option \"%.50s\"\n"
 msgstr "virheelliset tuontivalitsimet\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "olet löytänyt ohjelmistovian ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "ascii-koodaaminen epäonnistui: %s\n"
@@ -1226,6 +1238,11 @@ msgstr ""
 "viallista\n"
 "MTA:ta on käytetty\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "ei ihmisten luettavissa"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1243,12 +1260,22 @@ msgstr "käyttäjänotaatin täytyy sisältää \"@\"-merkki\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "notaatiosssa ei saa olla erikoismerkkejä\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "käyttäjänotaatin täytyy sisältää \"@\"-merkki\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"notaation nimen täytyy sisältää vain tulostettavia merkkejä tai "
+"välilyöntejä, ja sen täytyy loppua merkkiin \"=\"\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "VAROITUS: löydettiin väärin muotoiltua notaatiodataa\n"
 
-msgid "not human readable"
-msgstr "ei ihmisten luettavissa"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1343,10 +1370,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "virhe luotaessa avainrengasta \"%s\": %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "virhe luettaessa tiedostoa \"%s\": %s\n"
@@ -1682,14 +1705,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "valittu symmetrinen salain %s (%d) ei ole vastaanottajan suosima\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "valitsinta %s ei voi käyttää %s-tilassa\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s salattu vastaanottajalle: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "valitsinta %s ei voi käyttää %s-tilassa\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s salattua dataa\n"
 
@@ -1982,7 +2005,7 @@ msgstr "|algo [tiedostot]|tulosta viestien tiivisteet"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2987,11 +3010,28 @@ msgid "[self-signature]"
 msgstr "[oma-allekirjoitus]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d väärää allekirjoitusta\n"
-msgstr[1] "%d väärää allekirjoitusta\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "avain %08lX: julkisen avaimen algoritmia ei tueta\n"
+
+# Ensimmäinen %s on binary, textmode tai unknown, ks. alla
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%sallekirjoitus, tiivistealgoritmi %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Allekirjoitus täsmää lähettäjään \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "ohitetaan \"%s\": %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Käyttäjätunnus \"%s\" on mitätöity."
+msgstr[1] "Käyttäjätunnus \"%s\" on mitätöity."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3001,20 +3041,23 @@ msgstr[0] "1 allekirjoitus jätetty tarkistamatta puuttuvan avaimen vuoksi\n"
 msgstr[1] "1 allekirjoitus jätetty tarkistamatta puuttuvan avaimen vuoksi\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 allekirjoitus jätetty tarkistamatta virheen vuoksi\n"
-msgstr[1] "1 allekirjoitus jätetty tarkistamatta virheen vuoksi\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d väärää allekirjoitusta\n"
+msgstr[1] "%d väärää allekirjoitusta\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] ""
-"havaittiin %d käyttäjätunnusta ilman voimassaolevaa oma-allekirjoitusta\n"
-msgstr[1] ""
-"havaittiin %d käyttäjätunnusta ilman voimassaolevaa oma-allekirjoitusta\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Allekirjoitus täsmää lähettäjään \""
+msgstr[1] "Allekirjoitus täsmää lähettäjään \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3236,9 +3279,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "virhe luotaessa salasanaa: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "siirretään avaimen allekirjoitus oikealle paikalle\n"
-
 msgid "save and quit"
 msgstr "tallenna ja lopeta"
 
@@ -3517,6 +3557,11 @@ msgstr "virhe: sormenjälki on väärä\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "TrustDB:n alustaminen ei onnistu: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "arvo ei kelpaa\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4343,6 +4388,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d väärää allekirjoitusta\n"
 msgstr[1] "%d väärää allekirjoitusta\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 allekirjoitus jätetty tarkistamatta virheen vuoksi\n"
+msgstr[1] "1 allekirjoitus jätetty tarkistamatta virheen vuoksi\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5570,14 +5622,14 @@ msgstr "trustdb rec %lu: kirjoittaminen epäonnistuin (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "trustdb-tapahtuma on liian suuri\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "tiedostoa \"%s\" ei voi sulkea: %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: hakemistoa ei ole olemassa!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "tiedostoa \"%s\" ei voi sulkea: %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: versiotietueen luonti epäonnistui: %s"
@@ -5723,8 +5775,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5813,39 +5865,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "virhe luotaessa salasanaa: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5854,20 +5908,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [tiedostot]|tulosta viestien tiivisteet"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5881,12 +5937,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8776,6 +8839,21 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "olet löytänyt ohjelmistovian ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] ""
+#~ "havaittiin %d käyttäjätunnusta ilman voimassaolevaa oma-allekirjoitusta\n"
+#~ msgstr[1] ""
+#~ "havaittiin %d käyttäjätunnusta ilman voimassaolevaa oma-allekirjoitusta\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "siirretään avaimen allekirjoitus oikealle paikalle\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr ""
 #~ "%d allekirjoitusta jätetty tarkistamatta puuttuvien avainten vuoksi\n"
@@ -8871,11 +8949,6 @@ msgstr ""
 #~ msgstr "tiedostoa \"%s\" ei voi avata: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "arvo ei kelpaa\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "virhe luettaessa salaista avainlohkoa \"%s\": %s\n"
 
index b5fce4f..33eea36 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -386,7 +386,7 @@ msgstr "ne pas marquer les clefs comme de confiance"
 msgid "allow presetting passphrase"
 msgstr "permettre de préconfigurer la phrase secrète"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -477,6 +477,11 @@ msgstr "impossible de créer le répertoire « %s » : %s\n"
 msgid "directory '%s' created\n"
 msgstr "répertoire « %s » créé\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Avertissement : les droits de %s ne sont pas sûrs « %s »\n"
+
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "échec de stat() pour « %s » : %s\n"
@@ -743,8 +748,9 @@ msgstr "erreur de création d'un flux pour un tube : %s\n"
 msgid "error forking process: %s\n"
 msgstr "erreur de création de processus fils : %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "échec d'attente de fin du processus %d : %s\n"
 
 #, c-format
@@ -764,6 +770,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "erreur de lecture du code de retour du processus %d : %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "échec d'attente de fin du processus %d : %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "impossible de se connecter à « %s » : %s\n"
 
@@ -779,6 +789,11 @@ msgstr "annulé par l'utilisateur\n"
 msgid "problem with the agent\n"
 msgstr "problème avec l'agent\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problème avec l'agent : %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "impossible d'empêcher la génération de fichiers « core » : %s\n"
@@ -835,6 +850,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "hors limite lors de l'allocation de %lu octets"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "erreur d'allocation de suffisamment de mémoire : %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s : %u : option « %s » obsolète — non prise en compte\n"
 
@@ -1076,10 +1095,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "option « %.50s » incorrecte\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "vous avez trouvé un bogue… (%s : %d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "conversion de « %s » vers « %s » non disponible\n"
 
@@ -1179,6 +1194,11 @@ msgstr ""
 "caractère Quoted-Printable dans l'armure provenant sans\n"
 "doute d'un serveur de courriers électroniques défectueux\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "non lisible par l'utilisateur"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1195,12 +1215,23 @@ msgstr "un nom de notation ne doit pas contenir plus d'un caractère « @ »\n
 msgid "a notation value must not use any control characters\n"
 msgstr "une valeur de notation ne doit utiliser aucun caractère de contrôle\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "un nom de notation ne doit pas contenir plus d'un caractère « @ »\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"un nom de notation ne doit contenir que des caractères imprimables ou des "
+"espaces, et se terminer avec « = »\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "Attention : des données de notation incorrectes ont été trouvées.\n"
 
-msgid "not human readable"
-msgstr "non lisible par l'utilisateur"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "échec de transfert de la demande %s au client\n"
@@ -1287,10 +1318,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Erreur : URL trop longue (limitée à %d caractères).\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "erreur d'allocation de suffisamment de mémoire : %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "erreur de lecture de « %s » : %s\n"
 
@@ -1620,14 +1647,14 @@ msgstr ""
 "avec les préférences du destinataire\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "impossible d'utiliser %s en mode %s.\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s chiffré pour : « %s »\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "impossible d'utiliser %s en mode %s.\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "données chiffrées avec %s\n"
 
@@ -1904,7 +1931,7 @@ msgstr "indiquer les fonctions de hachage"
 msgid "run in server mode"
 msgstr "exécuter en mode serveur"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2903,11 +2930,32 @@ msgid "[self-signature]"
 msgstr "[autosignature]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d mauvaises signatures\n"
-msgstr[1] "%d mauvaises signatures\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "clef %s : algorithme à clef publique non pris en charge\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "la carte ne gère pas l'algorithme de hachage %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Bonne signature de"
+
+#, fuzzy, c-format
+#| msgid "key %s: %s\n"
+msgid "key %s:\n"
+msgstr "clef %s : %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Identité « %s » : %d signature supprimée\n"
+msgstr[1] "Identité « %s » : %d signature supprimée\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2917,18 +2965,24 @@ msgstr[0] "1 signature non vérifiée à cause d'une clef manquante\n"
 msgstr[1] "1 signature non vérifiée à cause d'une clef manquante\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 signature non vérifiée à cause d'une erreur\n"
-msgstr[1] "1 signature non vérifiée à cause d'une erreur\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d mauvaises signatures\n"
+msgstr[1] "%d mauvaises signatures\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d identités sans autosignature valable détecté\n"
-msgstr[1] "%d identités sans autosignature valable détecté\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Bonne signature de"
+msgstr[1] "Bonne signature de"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3126,9 +3180,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "clef %s : erreur de modification de la phrase secrète : %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "déplacement d'une signature de clef au bon endroit\n"
-
 msgid "save and quit"
 msgstr "enregistrer et quitter"
 
@@ -3388,6 +3439,11 @@ msgstr "« %s » n’est pas une empreinte\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "« %s » n’est pas l’empreinte principale\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "valeur incorrecte\n"
+
 msgid "No matching user IDs."
 msgstr "Pas d’identités correspondantes."
 
@@ -4201,6 +4257,13 @@ msgstr[0] "%d mauvaises signatures\n"
 msgstr[1] "%d mauvaises signatures\n"
 
 #, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 signature non vérifiée à cause d'une erreur\n"
+msgstr[1] "1 signature non vérifiée à cause d'une erreur\n"
+
+#, fuzzy, c-format
 #| msgid "Warning: %lu key(s) skipped due to their large size\n"
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5467,14 +5530,14 @@ msgid "trustdb transaction too large\n"
 msgstr "transaction de base de confiance trop grande\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "impossible d'accéder à « %s » : %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s : le répertoire n'existe pas.\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "impossible d'accéder à « %s » : %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s : impossible de créer un enregistrement de version : %s"
 
@@ -5620,8 +5683,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5714,39 +5777,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "erreur de création d'un tube : %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5755,20 +5820,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "indiquer les fonctions de hachage"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5782,12 +5850,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8697,6 +8772,19 @@ msgstr ""
 "Vérifier une phrase secrète donnée sur l'entrée standard par rapport à "
 "ficmotif\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "vous avez trouvé un bogue… (%s : %d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d identités sans autosignature valable détecté\n"
+#~ msgstr[1] "%d identités sans autosignature valable détecté\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "déplacement d'une signature de clef au bon endroit\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -8799,11 +8887,6 @@ msgstr ""
 #~ msgstr "échec d'ouverture de « %s » : %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "valeur incorrecte\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "erreur de lecture du bloc de clef secrète « %s » : %s\n"
index 49ba220..7ea0c18 100644 (file)
--- a/po/gl.po
+++ b/po/gl.po
@@ -381,7 +381,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "erro ao crea-lo contrasinal: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -481,6 +481,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: directorio creado\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVISO: permisos inseguros en %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "base de datos de confianza: fallou a lectura (n=%d): %s\n"
 
@@ -733,9 +737,9 @@ msgstr "erro ao crea-lo contrasinal: %s\n"
 msgid "error forking process: %s\n"
 msgstr "erro lendo `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "a actualización fallou: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -753,6 +757,10 @@ msgstr "erro lendo `%s': %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "erro escribindo no chaveiro secreto `%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -773,6 +781,10 @@ msgstr "cancelado polo usuario\n"
 msgid "problem with the agent\n"
 msgstr "problema co axente: o axente voltou coa resposta 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problema co axente: o axente voltou coa resposta 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "non é posible deshabilita-los volcados de 'core': %s\n"
@@ -829,6 +841,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "erro ao crea-lo chaveiro `%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1109,10 +1125,6 @@ msgstr "non procesado"
 msgid "invalid option \"%.50s\"\n"
 msgstr "opcións de importación non válidas\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "atopou un erro ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "non se puido poñe-la armadura: %s\n"
@@ -1216,6 +1228,11 @@ msgstr ""
 "carácter quoted-printable na armadura - seguramente empregouse un MTA con "
 "erros\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "non lexible por humanos"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1233,12 +1250,22 @@ msgstr "un nome de notaci
 msgid "a notation value must not use any control characters\n"
 msgstr "un valor de notación non pode empregar ningún carácter de control\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "un nome de notación de usuario debe conte-lo carácter '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"un nome de notación só debe ter caracteres imprimibles ou espacios, e debe "
+"rematar en '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "AVISO: atopáronse datos de notación non válidos\n"
 
-msgid "not human readable"
-msgstr "non lexible por humanos"
-
 #, fuzzy, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "erro ao pór '%s' na base de datos de confianza: %s\n"
@@ -1333,10 +1360,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "erro ao crea-lo chaveiro `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "erro lendo `%s': %s\n"
@@ -1677,14 +1700,14 @@ msgstr ""
 "forza-la cifra simétrica %s (%d) viola as preferencias do destinatario\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "non se pode empregar %s no modo %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s cifrado para: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "non se pode empregar %s no modo %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "datos cifrados con %s\n"
 
@@ -1975,7 +1998,7 @@ msgstr "|algo [ficheiros]|visualizar resumos de mensaxes"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2989,11 +3012,27 @@ msgid "[self-signature]"
 msgstr "[auto-sinatura]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d sinaturas erróneas\n"
-msgstr[1] "%d sinaturas erróneas\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "chave %08lX: algoritmo de chave pública non soportado\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "Sinatura %s, algoritmo de resumo %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Sinatura correcta de \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "omítese `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "O ID de usuario \"%s\" está revocado."
+msgstr[1] "O ID de usuario \"%s\" está revocado."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3003,18 +3042,23 @@ msgstr[0] "1 sinatura non verificada debido a unha chave que falta\n"
 msgstr[1] "1 sinatura non verificada debido a unha chave que falta\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 sinatura non verificada debido a un erro\n"
-msgstr[1] "1 sinatura non verificada debido a un erro\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d sinaturas erróneas\n"
+msgstr[1] "%d sinaturas erróneas\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "detectados %d IDs de usuario sin auto-sinatura válida\n"
-msgstr[1] "detectados %d IDs de usuario sin auto-sinatura válida\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Sinatura correcta de \""
+msgstr[1] "Sinatura correcta de \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3232,9 +3276,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "erro ao crea-lo contrasinal: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "movendo a sinatura dunha chave ó seu sitio\n"
-
 msgid "save and quit"
 msgstr "gardar e saír"
 
@@ -3521,6 +3562,11 @@ msgstr "erro: pegada dactilar non v
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "non se puido inicializa-la base de datos de confianzas: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "valor non válido\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4356,6 +4402,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d sinaturas erróneas\n"
 msgstr[1] "%d sinaturas erróneas\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 sinatura non verificada debido a un erro\n"
+msgstr[1] "1 sinatura non verificada debido a un erro\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5575,14 +5628,14 @@ msgstr ""
 msgid "trustdb transaction too large\n"
 msgstr "transacción da base de datos de confianza demasiado grande\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "non se pode pechar `%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: ¡o directorio non existe!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "non se pode pechar `%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: non se puido crea-lo rexistro de versión: %s"
@@ -5728,8 +5781,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5818,39 +5871,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "erro ao crea-lo contrasinal: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5859,20 +5914,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [ficheiros]|visualizar resumos de mensaxes"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5886,12 +5943,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8801,6 +8865,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "atopou un erro ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "detectados %d IDs de usuario sin auto-sinatura válida\n"
+#~ msgstr[1] "detectados %d IDs de usuario sin auto-sinatura válida\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "movendo a sinatura dunha chave ó seu sitio\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d sinaturas non verificadas debido a chaves que faltan\n"
 
@@ -8894,11 +8971,6 @@ msgstr ""
 #~ msgstr "non se puido abrir `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "valor non válido\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "erro ao le-lo bloque de chave secreta `%s': %s\n"
 
index 20846d2..539aa00 100644 (file)
--- a/po/hu.po
+++ b/po/hu.po
@@ -379,7 +379,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "Hiba a jelszó létrehozásakor: %s.\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -477,6 +477,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: Könyvtárat létrehoztam.\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "FIGYELEM: nem biztonságos engedélyek: %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "Bizalmi adatbázis: olvasás sikertelen (n=%d): %s.\n"
 
@@ -729,9 +733,9 @@ msgstr "Hiba a jelsz
 msgid "error forking process: %s\n"
 msgstr "Hiba \"%s\" olvasásakor: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "Frissítés sikertelen: %s.\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -749,6 +753,10 @@ msgstr "Hiba \"%s\" olvas
 msgid "error getting exit code of process %d: %s\n"
 msgstr "Hiba a(z) \"%s\" titkoskulcs-karika írásakor: %s.\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -769,6 +777,10 @@ msgstr "A felhaszn
 msgid "problem with the agent\n"
 msgstr "Probléma az ügynökkel: ügynök válasza: 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "Probléma az ügynökkel: ügynök válasza: 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "Nem tudom letiltani a core fájlokat: %s.\n"
@@ -825,6 +837,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "Hiba a(z) \"%s\" kulcskarika létrehozásakor: %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1101,10 +1117,6 @@ msgstr "nem feldolgozott"
 msgid "invalid option \"%.50s\"\n"
 msgstr "Érvénytelen import opciók!\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "Talált egy programhibát... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "Páncélozás nem sikerült: %s\n"
@@ -1207,6 +1219,11 @@ msgid ""
 msgstr ""
 "quoted printable karakter a páncélban - valószínûleg egy bugos MTA bûne.\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "nem olvasható forma"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1224,12 +1241,22 @@ msgstr "Egy felhaszn
 msgid "a notation value must not use any control characters\n"
 msgstr "Egy jelölés értékében nem szerepelhet vezérlõkarakter!\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "Egy felhasználójelölésnek tartalmaznia kell a \"@\" karaktert!\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"Egy jelölés neve csak nyomtatható karaktereket és szóközt tartalmazhat, és = "
+"jellel kell befejezõdjön.\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "FIGYELEM: Érvénytelen jelölõ adatot találtam.\n"
 
-msgid "not human readable"
-msgstr "nem olvasható forma"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1324,10 +1351,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "Hiba a(z) \"%s\" kulcskarika létrehozásakor: %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "Hiba \"%s\" olvasásakor: %s\n"
@@ -1663,14 +1686,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "A %s (%d) rejtjelezõ használata sérti a címzett preferenciáit!\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "Lehet, hogy nem használhatja %s-t %s módban!\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s titkosítva \"%s\" számára\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "Lehet, hogy nem használhatja %s-t %s módban!\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s titkosított adat.\n"
 
@@ -1963,7 +1986,7 @@ msgstr "|algo [f
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2969,11 +2992,27 @@ msgid "[self-signature]"
 msgstr "[önaláírás]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d rossz aláírás.\n"
-msgstr[1] "%d rossz aláírás.\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "%08lX kulcs: Nem támogatott nyilvános kulcsú algoritmus!\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%s aláírás, %s kivonatoló algoritmus.\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Jó aláírás a következõtõl: \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "Kihagytam \"%s\"-t: %s.\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "\"%s\" felhasználói azonosítót visszavonták."
+msgstr[1] "\"%s\" felhasználói azonosítót visszavonták."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2983,18 +3022,23 @@ msgstr[0] "1 al
 msgstr[1] "1 aláírást nem ellenõriztem hiányzó kulcs miatt.\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 aláírást nem ellenõriztem hiba miatt.\n"
-msgstr[1] "1 aláírást nem ellenõriztem hiba miatt.\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d rossz aláírás.\n"
+msgstr[1] "%d rossz aláírás.\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d felhasználóazonosítót találtam érvényes önaláírás nélkül.\n"
-msgstr[1] "%d felhasználóazonosítót találtam érvényes önaláírás nélkül.\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Jó aláírás a következõtõl: \""
+msgstr[1] "Jó aláírás a következõtõl: \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3213,9 +3257,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "Hiba a jelszó létrehozásakor: %s.\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "Átrakom a kulcsaláírást a megfelelõ helyre.\n"
-
 msgid "save and quit"
 msgstr "mentés és kilépés"
 
@@ -3494,6 +3535,11 @@ msgstr "Hiba: 
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "Bizalmi adatbázis (%s) inicializálása sikertelen!\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "Érvénytelen érték!\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4321,6 +4367,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d rossz aláírás.\n"
 msgstr[1] "%d rossz aláírás.\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 aláírást nem ellenõriztem hiba miatt.\n"
+msgstr[1] "1 aláírást nem ellenõriztem hiba miatt.\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5542,14 +5595,14 @@ msgstr "Bizalmi adatb
 msgid "trustdb transaction too large\n"
 msgstr "Bizalmi adatbázis tranzakciója túl nagy.\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "Nem tudom bezárni a(z) \"%s\" állományt: %s.\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: Könyvtár nem létezik!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "Nem tudom bezárni a(z) \"%s\" állományt: %s.\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: Nem sikerült verziórekordot létrehoznom: %s"
@@ -5695,8 +5748,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5785,39 +5838,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "Hiba a jelszó létrehozásakor: %s.\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5826,20 +5881,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [fájlok]|üzenet kivonatának kiírása"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5853,12 +5910,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8745,6 +8809,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "Talált egy programhibát... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d felhasználóazonosítót találtam érvényes önaláírás nélkül.\n"
+#~ msgstr[1] "%d felhasználóazonosítót találtam érvényes önaláírás nélkül.\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "Átrakom a kulcsaláírást a megfelelõ helyre.\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d aláírást nem ellenõriztem hiányzó kulcs miatt.\n"
 
@@ -8838,11 +8915,6 @@ msgstr ""
 #~ msgstr "Nem tudom megnyitni a(z) \"%s\" állományt: %s.\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "Érvénytelen érték!\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "Hiba \"%s\" titkoskulcs-blokk olvasásakor: %s.\n"
 
index 679bd20..c017cd4 100644 (file)
--- a/po/id.po
+++ b/po/id.po
@@ -384,7 +384,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "kesalahan penciptaan passphrase: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -482,6 +482,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: direktori tercipta\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Peringatan: permisi tidak aman pada %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: read failed (n=%d): %s\n"
 
@@ -734,9 +738,9 @@ msgstr "kesalahan penciptaan passphrase: %s\n"
 msgid "error forking process: %s\n"
 msgstr "kesalahan membaca `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "gagal memperbarui: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -754,6 +758,10 @@ msgstr "kesalahan membaca `%s': %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "kesalahan menulis keyring rahasia `%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -774,6 +782,10 @@ msgstr "dibatalkan oleh user\n"
 msgid "problem with the agent\n"
 msgstr "masalah dengan agen: agen mengembalikan 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "masalah dengan agen: agen mengembalikan 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "tidak dapat meniadakan core dump: %s\n"
@@ -830,6 +842,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "kesalahan menulis keyring `%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1106,10 +1122,6 @@ msgstr "tidak diproses"
 msgid "invalid option \"%.50s\"\n"
 msgstr "opsi impor tidak valid\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "anda menemukan kesalahan ...(%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "gagal enarmoring: %s\n"
@@ -1213,6 +1225,11 @@ msgstr ""
 "karakter yang dapat dicetak dalam armor - mungkin telah digunakan MTA yang "
 "mengandung bug\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "tidak dapat dibaca manusia"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1230,12 +1247,22 @@ msgstr "nama notasi pengguna tidak boleh mengandung karakter '@'\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "nilai notasi tidak boleh menggunakan karakter kendali\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "nama notasi pengguna tidak boleh mengandung karakter '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"nama notasi harus hanya terdiri dari karakter yang dapat dicetak atau spasi, "
+"dan diakhiri dengan sebuah '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "PERINGATAN: ditemukan notasi data tidak valid\n"
 
-msgid "not human readable"
-msgstr "tidak dapat dibaca manusia"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1330,10 +1357,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "kesalahan menulis keyring `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "kesalahan membaca `%s': %s\n"
@@ -1669,14 +1692,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "memaksa cipher simetrik %s (%d) melanggar preferensi penerima\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "anda tidak boleh menggunakan %s saat dalam mode %s.\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s dienkripsi untuk: %s\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "anda tidak boleh menggunakan %s saat dalam mode %s.\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s data terenkripsi\n"
 
@@ -1966,7 +1989,7 @@ msgstr "|algo [file]|cetak digest pesan"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2971,11 +2994,27 @@ msgid "[self-signature]"
 msgstr "[self-signature]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d signature yang buruk\n"
-msgstr[1] "%d signature yang buruk\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "kunci %08lX: algoritma publik key tidak didukung\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%s signature, algoritma digest %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Signature baik dari \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "melewati `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "User ID \"%s\" dibatalkan."
+msgstr[1] "User ID \"%s\" dibatalkan."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2985,18 +3024,23 @@ msgstr[0] "1 signature tidak diperiksa karena tidak ada kunci\n"
 msgstr[1] "1 signature tidak diperiksa karena tidak ada kunci\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 signature tidak diperiksa karena kesalahan\n"
-msgstr[1] "1 signature tidak diperiksa karena kesalahan\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d signature yang buruk\n"
+msgstr[1] "%d signature yang buruk\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "terdeteksi ID %d user tanpa self-signature yang valid\n"
-msgstr[1] "terdeteksi ID %d user tanpa self-signature yang valid\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Signature baik dari \""
+msgstr[1] "Signature baik dari \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3218,9 +3262,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "kesalahan penciptaan passphrase: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "memindahkan signature kunci ke tempat yang tepat\n"
-
 msgid "save and quit"
 msgstr "simpan dan berhenti"
 
@@ -3499,6 +3540,11 @@ msgstr "kesalahan: fingerprint tidak valid\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "gagal inisialisasi TrustDB: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "nilai yang tidak valid\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4325,6 +4371,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d signature yang buruk\n"
 msgstr[1] "%d signature yang buruk\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 signature tidak diperiksa karena kesalahan\n"
+msgstr[1] "1 signature tidak diperiksa karena kesalahan\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5532,14 +5585,14 @@ msgstr "trustdb rec %lu: write failed (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "transaksi trustdb terlalu besar\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "tidak dapat menutup `%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: direktori tidak ada!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "tidak dapat menutup `%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: gagal membuat catatan versi: %s"
@@ -5685,8 +5738,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5775,39 +5828,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "kesalahan penciptaan passphrase: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5816,20 +5871,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [file]|cetak digest pesan"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5843,12 +5900,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8734,6 +8798,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "anda menemukan kesalahan ...(%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "terdeteksi ID %d user tanpa self-signature yang valid\n"
+#~ msgstr[1] "terdeteksi ID %d user tanpa self-signature yang valid\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "memindahkan signature kunci ke tempat yang tepat\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d signature tidak diperiksa karena tidak ada kunci\n"
 
@@ -8828,11 +8905,6 @@ msgstr ""
 #~ msgstr "tidak dapat membuka `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "nilai yang tidak valid\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "kesalahan membaca keyblock rahasia `%s': %s\n"
 
index 573f0f3..6b30fbd 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -379,7 +379,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "errore nella creazione della passhprase: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -477,6 +477,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: directory creata\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "ATTENZIONE: i permessi \"%s\" di %s sono insicuri\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "trustdb: read fallita (n=%d): %s\n"
 
@@ -729,9 +733,9 @@ msgstr "errore nella creazione della passhprase: %s\n"
 msgid "error forking process: %s\n"
 msgstr "errore leggendo `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "aggiornamento fallito: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -749,6 +753,10 @@ msgstr "errore leggendo `%s': %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "errore scrivendo il portachiavi segreto `%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -769,6 +777,10 @@ msgstr "interrotto dall'utente\n"
 msgid "problem with the agent\n"
 msgstr "problema con l'agent: ha restituito 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problema con l'agent: ha restituito 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "impossibile disabilitare i core dump: %s\n"
@@ -825,6 +837,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "errore creando il portachiavi `%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1103,10 +1119,6 @@ msgstr "non esaminato"
 msgid "invalid option \"%.50s\"\n"
 msgstr "opzioni di importazione non valide\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "hai trovato un bug... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "creazione dell'armatura fallita: %s\n"
@@ -1210,6 +1222,11 @@ msgstr ""
 "carattere quoted printable nell'armatura - probabilmente è stato usato\n"
 "un MTA buggato\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "non leggibile"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1227,12 +1244,22 @@ msgstr "il valore di una nota dell'utente deve contenere il carattere '@'\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "il valore di una nota non deve usare caratteri di controllo\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "il valore di una nota dell'utente deve contenere il carattere '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"il nome di una nota deve essere formato solo da caratteri stampabili o\n"
+"spazi e terminare con un '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "ATTENZIONE: trovati dati di una nota non validi\n"
 
-msgid "not human readable"
-msgstr "non leggibile"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1328,10 +1355,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "errore creando il portachiavi `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "errore leggendo `%s': %s\n"
@@ -1674,14 +1697,14 @@ msgstr ""
 "del destinatario\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "non è possibile usare %s in modalità %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s cifrato per: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "non è possibile usare %s in modalità %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "dati cifrati con %s\n"
 
@@ -1973,7 +1996,7 @@ msgstr "|algo [files]|stampa tutti i message digests"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2980,11 +3003,27 @@ msgid "[self-signature]"
 msgstr "[autofirma]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d firme non corrette\n"
-msgstr[1] "%d firme non corrette\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "chiave %08lX: algoritmo a chiave pubblica non gestito\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "Firma %s, algoritmo di digest %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Firma valida da \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "saltata `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "L'user ID \"%s\" è stato revocato."
+msgstr[1] "L'user ID \"%s\" è stato revocato."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2994,18 +3033,23 @@ msgstr[0] "una firma non controllata per mancanza della chiave\n"
 msgstr[1] "una firma non controllata per mancanza della chiave\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "una firma non controllata a causa di un errore\n"
-msgstr[1] "una firma non controllata a causa di un errore\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d firme non corrette\n"
+msgstr[1] "%d firme non corrette\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "Trovati %d user ID senza autofirme valide\n"
-msgstr[1] "Trovati %d user ID senza autofirme valide\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Firma valida da \""
+msgstr[1] "Firma valida da \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3225,9 +3269,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "errore nella creazione della passhprase: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "spostamento della firma di una chiave nel posto corretto\n"
-
 msgid "save and quit"
 msgstr "salva ed esci"
 
@@ -3506,6 +3547,11 @@ msgstr "errore: impronta digitale non valida\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "inizializzazione del trustdb fallita: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "valore non valido\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4342,6 +4388,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d firme non corrette\n"
 msgstr[1] "%d firme non corrette\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "una firma non controllata a causa di un errore\n"
+msgstr[1] "una firma non controllata a causa di un errore\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5573,14 +5626,14 @@ msgstr "trustdb rec %lu: scrittura fallita (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "transazione del trustdb troppo grande\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "impossibile chiudere `%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: la directory non esiste!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "impossibile chiudere `%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: creazione del record della versione fallita: %s"
@@ -5726,8 +5779,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5816,39 +5869,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "errore nella creazione della passhprase: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5857,20 +5912,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [files]|stampa tutti i message digests"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5884,12 +5941,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8778,6 +8842,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "hai trovato un bug... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "Trovati %d user ID senza autofirme valide\n"
+#~ msgstr[1] "Trovati %d user ID senza autofirme valide\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "spostamento della firma di una chiave nel posto corretto\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d firme non controllate per mancanza delle chiavi\n"
 
@@ -8873,11 +8950,6 @@ msgstr ""
 #~ msgstr "impossibile aprire `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "valore non valido\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "errore leggendo il keyblock segreto `%s': %s\n"
 
index d78cca2..e138ede 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -361,7 +361,9 @@ msgstr "クライアントが鍵に\"trusted\"マークをつけることを認
 msgid "allow presetting passphrase"
 msgstr "パスフレーズの事前設定を認める"
 
-msgid "allow caller to override the pinentry"
+#, fuzzy
+#| msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr "pinentryより優先してパスフレーズ入力を認める"
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -447,6 +449,11 @@ msgstr "ディレクトリ'%s'が作成できません: %s\n"
 msgid "directory '%s' created\n"
 msgstr "ディレクトリ'%s'が作成されました\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "警告: '%s'の安全でない許可 \"%s\"\n"
+
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "'%s'でstat()が失敗しました: %s\n"
@@ -702,8 +709,9 @@ msgstr "パイプのストリーム作成エラー: %s\n"
 msgid "error forking process: %s\n"
 msgstr "プロセスforkエラー: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "プロセス%dの終了待ちが失敗: %s\n"
 
 #, c-format
@@ -723,6 +731,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "プロセス %d のexitコード取得エラー: %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "プロセス%dの終了待ちが失敗: %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "'%s'へ接続できません: %s\n"
 
@@ -738,6 +750,11 @@ msgstr "ユーザによる取消し\n"
 msgid "problem with the agent\n"
 msgstr "エージェントに障害\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "エージェントに問題: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "コア・ダンプを無効にできません: %s\n"
@@ -794,6 +811,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "%luバイトの確保においてメモリが足りません"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "十分なメモリの確保のエラー: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
 "%s:%u: \"%s\"は、使われなくなったオプションです - なんの効果もありません\n"
@@ -1034,10 +1055,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "無効なオプション \"%.50s\"\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "あなたはバグを発見しました ... (%s:%d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "'%s'から'%s'への変換は利用できません\n"
 
@@ -1137,6 +1154,11 @@ msgstr ""
 "外装の中にquoted printable文字があります。おそらくバグのあるMTAが使われたので"
 "しょう\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "人には読めません"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1152,12 +1174,22 @@ msgstr "ユーザ注釈名は、一つより大きい'@'文字を含んではな
 msgid "a notation value must not use any control characters\n"
 msgstr "注釈名の値に制御文字を使ってはいけません\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "ユーザ注釈名は、一つより大きい'@'文字を含んではなりません\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"注釈名には印字可能な文字か空白のみを使い、'='で終わらなければなりません\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "*警告*: 無効な注釈データを発見\n"
 
-msgid "not human readable"
-msgstr "人には読めません"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "プロキシ%sのクライアントへの問い合わせが失敗しました\n"
@@ -1244,10 +1276,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "エラー: URLが長すぎます (上限%d文字)。\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "十分なメモリの確保のエラー: %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "'%s'の読み込みエラー: %s\n"
 
@@ -1556,14 +1584,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "共通鍵暗号方式 %s (%d) の強制が、受取人の優先指定をそむきます\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "%sを%sモードで使うことはできません\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s暗号化 受信者:\"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "%sを%sモードで使うことはできません\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s暗号化済みデータ\n"
 
@@ -1831,7 +1859,9 @@ msgstr "メッセージ・ダイジェストを表示"
 msgid "run in server mode"
 msgstr "サーバ・モードで実行"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+#, fuzzy
+#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr "|VALUE|TOFUポリシーを鍵に設定する(good, unknown, bad, ask, auto)"
 
 msgid "create ascii armored output"
@@ -2782,10 +2812,31 @@ msgid "[self-signature]"
 msgstr "[自己署名]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "不正な署名%d個\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "鍵%s: サポートしていない公開鍵アルゴリズムです\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "カードはダイジェスト・アルゴリズム %s をサポートしていません\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "正しい署名"
+
+#, fuzzy, c-format
+#| msgid "key %s: %s\n"
+msgid "key %s:\n"
+msgstr "鍵  %s: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "ユーザID \"%s\": %d の署名が除去されました\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2794,16 +2845,22 @@ msgid_plural "%d signatures not checked due to missing keys\n"
 msgstr[0] "鍵がないため1個の署名を検査しません\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "エラーのため1個の署名を検査しません\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "不正な署名%d個\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "有効な自己署名のないユーザIDを%d個検出\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "正しい署名"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -2996,9 +3053,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "鍵 %s: パスフレーズの変更エラー: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "鍵の署名を正しい場所に移動します\n"
-
 msgid "save and quit"
 msgstr "保存して終了"
 
@@ -3242,6 +3296,11 @@ msgstr "\"%s\"はフィンガープリントではありません\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "\"%s\" はプライマリ・フィンガープリントではありません\n"
 
+#, fuzzy, c-format
+#| msgid "read error in '%s': %s\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "'%s'で読み込みエラー: %s\n"
+
 msgid "No matching user IDs."
 msgstr "マッチするユーザIDはありません。"
 
@@ -4014,6 +4073,12 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "正しい署名%d個\n"
 
 #, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "エラーのため1個の署名を検査しません\n"
+
+#, fuzzy, c-format
 #| msgid "Warning: %lu key(s) skipped due to their large size\n"
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5180,14 +5245,14 @@ msgid "trustdb transaction too large\n"
 msgstr "信用データベースのトランザクションが大きすぎます\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "'%s'にアクセスできません: %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: ディレクトリがありません!\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "'%s'にアクセスできません: %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: バージョン・レコードの作成に失敗しました: %s"
 
@@ -5333,8 +5398,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5421,34 +5486,36 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "パイプの作成エラー: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 
 #, c-format
@@ -5456,20 +5523,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "メッセージ・ダイジェストを表示"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 
 #, c-format
@@ -5482,12 +5552,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 
 #, fuzzy, c-format
@@ -8244,6 +8321,18 @@ msgstr ""
 "形式: gpg-check-pattern [オプション] パターンファイル\n"
 "パターンファイルに対して標準入力のパスフレーズを確認する\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "あなたはバグを発見しました ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "有効な自己署名のないユーザIDを%d個検出\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "鍵の署名を正しい場所に移動します\n"
+
 #~ msgid "key specification '%s' is ambiguous\n"
 #~ msgstr "鍵の指定'%s'はあいまいです\n"
 
index d48d38a..970241e 100644 (file)
--- a/po/nb.po
+++ b/po/nb.po
@@ -391,7 +391,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "feil ved opprettelse av passfrase: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -484,6 +484,10 @@ msgid "directory '%s' created\n"
 msgstr "katalogen «%s» ble opprettet\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "ADVARSEL: utrygge rettigheter på utvidelsen «%s»\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fstat(%d) mislyktes in %s: %s\n"
 
@@ -731,9 +735,9 @@ msgstr "feil ved opprettelse av passfrase: %s\n"
 msgid "error forking process: %s\n"
 msgstr "feil ved lesing av «%s»: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "oppdatering mislyktes: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -751,6 +755,10 @@ msgstr "feil ved lesing av 
 msgid "error getting exit code of process %d: %s\n"
 msgstr "feil ved henting av nåværende nøkkelinfo: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't close `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -769,6 +777,10 @@ msgid "problem with the agent\n"
 msgstr ""
 
 #, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr ""
+
+#, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr ""
 
@@ -823,6 +835,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1099,10 +1115,6 @@ msgstr "ikke tvunget"
 msgid "invalid option \"%.50s\"\n"
 msgstr "ugyldige listevalg\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "du fant en feil ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "omdøping fra «%s» til «%s» mislyktes: %s\n"
@@ -1203,6 +1215,10 @@ msgid ""
 msgstr ""
 "quoted printable-tegn i armor - antakelig har en MTA med feil blitt brukt\n"
 
+#, c-format
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr ""
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1217,13 +1233,16 @@ msgstr ""
 msgid "a notation value must not use any control characters\n"
 msgstr ""
 
+msgid "a notation name may not contain an '=' character\n"
+msgstr ""
+
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+
 #, fuzzy
 msgid "WARNING: invalid notation data found\n"
 msgstr "ingen gyldig OpenPGP-data funnet.\n"
 
-msgid "not human readable"
-msgstr ""
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1311,10 +1330,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Feil: URL er for lang (grensa går ved %d tegn).\n"
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "feil ved opprettelse av nøkkelknippet «%s»: %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "feil ved lesing av «%s»: %s\n"
@@ -1643,14 +1658,14 @@ msgstr ""
 "påtvinging av symmetrisk cipher %s (%d) bryter med mottakerens preferanser\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "du kan ikke bruke %s i %s modus\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s kryptert for: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "du kan ikke bruke %s i %s modus\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s krypterte data\n"
 
@@ -1934,7 +1949,7 @@ msgstr "|algo [filer]|skrive meldingsdigester"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2952,11 +2967,30 @@ msgid "[self-signature]"
 msgstr "[selvsignatur]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d ubrukelige signaturer\n"
-msgstr[1] "%d ubrukelige signaturer\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "nøkkel %s: ustøttet offentlig nøkkelalgoritme\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "kortet støtter ikke digestalgoritme %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "God signatur fra «%s»"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "hoppet over «%s»: %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "nøkkel: %s: «%s» %d nye signaturer\n"
+msgstr[1] "nøkkel: %s: «%s» %d nye signaturer\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2966,18 +3000,23 @@ msgstr[0] "1 signatur ble ikke sjekket p
 msgstr[1] "1 signatur ble ikke sjekket på grunn av en manglende nøkkel\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 signatur ble ikke sjekket på grunn av en feil\n"
-msgstr[1] "1 signatur ble ikke sjekket på grunn av en feil\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d ubrukelige signaturer\n"
+msgstr[1] "%d ubrukelige signaturer\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d brukerider uten gyldige selvsignaturer ble oppdaget\n"
-msgstr[1] "%d brukerider uten gyldige selvsignaturer ble oppdaget\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "God signatur fra «%s»"
+msgstr[1] "God signatur fra «%s»"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3170,9 +3209,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "feil ved opprettelse av passfrase: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "flytter en nøkkelsignatur til den rette plassen\n"
-
 msgid "save and quit"
 msgstr "lagre og avslutte"
 
@@ -3420,6 +3456,11 @@ msgstr "ugyldig fingeravtrykk"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "klarte ikke å lagre fingeravtrykket: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "ugyldig verdi\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4225,6 +4266,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d ubrukelige signaturer\n"
 msgstr[1] "%d ubrukelige signaturer\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 signatur ble ikke sjekket på grunn av en feil\n"
+msgstr[1] "1 signatur ble ikke sjekket på grunn av en feil\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5418,16 +5466,16 @@ msgstr ""
 msgid "trustdb transaction too large\n"
 msgstr ""
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "kan ikke aksere «%s»: %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr ""
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr ""
 
@@ -5569,8 +5617,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5660,39 +5708,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "feil ved opprettelse av passfrase: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5701,20 +5751,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [filer]|skrive meldingsdigester"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5728,12 +5780,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8616,6 +8675,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "du fant en feil ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d brukerider uten gyldige selvsignaturer ble oppdaget\n"
+#~ msgstr[1] "%d brukerider uten gyldige selvsignaturer ble oppdaget\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "flytter en nøkkelsignatur til den rette plassen\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d signaturer ble ikke sjekket på grunn av manglende nøkler\n"
 
@@ -8701,11 +8773,6 @@ msgstr ""
 #~ msgstr "Kan ikke åpne «%s»: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "ugyldig verdi\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "feil ved lesing av hemmelig nøkkelblokk «%s»: %s\n"
index 9936e87..2b8c12c 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -405,7 +405,7 @@ msgstr "zezwolenie klientom na oznaczanie kluczy jako \"zaufanych\""
 msgid "allow presetting passphrase"
 msgstr "zezwolenie na predefiniowane has³o"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -508,6 +508,11 @@ msgid "directory '%s' created\n"
 msgstr "katalog ,,%s'' utworzony\n"
 
 #, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Ostrze¿enie: niebezpieczne prawa dostêpu do %s ,,%s''\n"
+
+#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "stat() nie powiod³o siê dla ,,%s'': %s\n"
@@ -778,8 +783,9 @@ msgstr "b
 msgid "error forking process: %s\n"
 msgstr "b³±d podczas tworzenia procesu: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "oczekiwanie na zakoñczenie procesu %d nie powiod³o siê: %s\n"
 
 #, fuzzy, c-format
@@ -801,6 +807,10 @@ msgstr "b
 msgid "error getting exit code of process %d: %s\n"
 msgstr "b³±d odczytu kodu zakoñczenia procesu %d: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "oczekiwanie na zakoñczenie procesu %d nie powiod³o siê: %s\n"
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -818,6 +828,11 @@ msgstr "anulowano przez u
 msgid "problem with the agent\n"
 msgstr "problem z agentem\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problem z agentem: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "nie mo¿na wy³±czyæ zrzutów pamiêci: %s\n"
@@ -874,6 +889,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "brak miejsca podczas przydzielania %lu bajtów"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "b³±d przydzielania wystarczaj±cej ilo¶ci pamiêci: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: przestarza³a opcja ,,%s'' - nie ma efektu\n"
 
@@ -1124,10 +1143,6 @@ msgstr "brak pami
 msgid "invalid option \"%.50s\"\n"
 msgstr "b³êdna opcja ,,%.50s''\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "znalaz³e¶(a¶) b³±d w programie ... (%s:%d)\n"
-
 #, fuzzy, c-format
 #| msgid "conversion from `%s' to `%s' not available\n"
 msgid "conversion from '%s' to '%s' not available\n"
@@ -1233,6 +1248,11 @@ msgstr ""
 "znak kodowania quoted-printable w opakowaniu ASCII - prawdopodobnie\n"
 "przek³amanie wprowadzone przez serwer pocztowy\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "nieczytelne dla cz³owieka"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1249,12 +1269,23 @@ msgstr "nazwa adnotacjinie mo
 msgid "a notation value must not use any control characters\n"
 msgstr "warto¶æ adnotacji nie mo¿e zawieraæ ¿adnych znaków steruj±cych\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "nazwa adnotacjinie mo¿e zawieraæ wiêcej ni¿ jednego znaku ,,@''\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"nazwa adnotacji musi zawieraæ tylko znaki drukowalne lub spacje i koñczyæ "
+"siê znakiem ,,=''\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "OSTRZE¯ENIE: napotkano b³êdne dane adnotacji\n"
 
-msgid "not human readable"
-msgstr "nieczytelne dla cz³owieka"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "nie uda³o siê przekazaæ zapytania %s do klienta\n"
@@ -1342,10 +1373,6 @@ msgstr "URL do odczytania klucza publicznego: "
 msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "B³±d: URL zbyt d³ugi (limit to %d znaków).\n"
 
-#, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "b³±d przydzielania wystarczaj±cej ilo¶ci pamiêci: %s\n"
-
 #, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
@@ -1686,14 +1713,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "wymuszone u¿ycie szyfru %s (%d) k³óci siê z ustawieniami adresata\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "%s nie jest dostêpne w trybie %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s zaszyfrowany dla: ,,%s''\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "%s nie jest dostêpne w trybie %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "dane zaszyfrowano za pomoc± %s\n"
 
@@ -1976,7 +2003,7 @@ msgstr "wypisanie skr
 msgid "run in server mode"
 msgstr "uruchomienie w trybie serwera"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3021,12 +3048,33 @@ msgid "[self-signature]"
 msgstr "[podpis klucza nim samym]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d niepoprawnych podpisów\n"
-msgstr[1] "%d niepoprawnych podpisów\n"
-msgstr[2] "%d niepoprawnych podpisów\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "klucz %s: nieobs³ugiwany algorytm asymetryczny\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "karta nie obs³uguje algorytmu skrótu %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Poprawny podpis z³o¿ony przez"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "pominiêty ,,%s'': %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Identyfikator u¿ytkownika ,,%s'': %d podpis wyczyszczony\n"
+msgstr[1] "Identyfikator u¿ytkownika ,,%s'': %d podpis wyczyszczony\n"
+msgstr[2] "Identyfikator u¿ytkownika ,,%s'': %d podpis wyczyszczony\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3037,23 +3085,26 @@ msgstr[1] "1 podpis nie zosta
 msgstr[2] "1 podpis nie zosta³ sprawdzony z powodu braku klucza\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 podpis nie zosta³ sprawdzony z powodu b³êdu\n"
-msgstr[1] "1 podpis nie zosta³ sprawdzony z powodu b³êdu\n"
-msgstr[2] "1 podpis nie zosta³ sprawdzony z powodu b³êdu\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d niepoprawnych podpisów\n"
+msgstr[1] "%d niepoprawnych podpisów\n"
+msgstr[2] "%d niepoprawnych podpisów\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] ""
-"wykryto %d identyfikatorów u¿ytkownika niepodpisanych tym samym kluczem\n"
-msgstr[1] ""
-"wykryto %d identyfikatorów u¿ytkownika niepodpisanych tym samym kluczem\n"
-msgstr[2] ""
-"wykryto %d identyfikatorów u¿ytkownika niepodpisanych tym samym kluczem\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Poprawny podpis z³o¿ony przez"
+msgstr[1] "Poprawny podpis z³o¿ony przez"
+msgstr[2] "Poprawny podpis z³o¿ony przez"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3255,9 +3306,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "b³±d podczas tworzenia has³a: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "przenoszê podpis klucza na w³a¶ciwe miejsce\n"
-
 msgid "save and quit"
 msgstr "zapis zmian i wyj¶cie"
 
@@ -3535,6 +3583,11 @@ msgstr "niew
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "nie uda³o siê pobraæ odcisku\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "niepoprawna warto¶æ\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4367,6 +4420,14 @@ msgstr[0] "%d niepoprawnych podpis
 msgstr[1] "%d niepoprawnych podpisów\n"
 msgstr[2] "%d niepoprawnych podpisów\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 podpis nie zosta³ sprawdzony z powodu b³êdu\n"
+msgstr[1] "1 podpis nie zosta³ sprawdzony z powodu b³êdu\n"
+msgstr[2] "1 podpis nie zosta³ sprawdzony z powodu b³êdu\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5621,16 +5682,16 @@ msgstr "baza zaufania, wpis %lu: zapis nie powi
 msgid "trustdb transaction too large\n"
 msgstr "zbyt du¿e zlecenie dla bazy zaufania\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: katalog nie istnieje!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "nie mo¿na dostaæ siê do ,,%s'': %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: katalog nie istnieje!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: stworzenie zapisu o wersji nie powiod³o siê: %s"
 
@@ -5778,8 +5839,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5878,44 +5939,46 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "b³±d tworzenia potoku: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -5925,20 +5988,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "wypisanie skrótów wiadomo¶ci"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -5953,12 +6019,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -9063,6 +9136,23 @@ msgstr ""
 "Sk³adnia: gpg-check-pattern [opcje] plik-wzorców\n"
 "Sprawdzanie has³a ze standardowego wej¶cia wzglêdem pliku wzorców\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "znalaz³e¶(a¶) b³±d w programie ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] ""
+#~ "wykryto %d identyfikatorów u¿ytkownika niepodpisanych tym samym kluczem\n"
+#~ msgstr[1] ""
+#~ "wykryto %d identyfikatorów u¿ytkownika niepodpisanych tym samym kluczem\n"
+#~ msgstr[2] ""
+#~ "wykryto %d identyfikatorów u¿ytkownika niepodpisanych tym samym kluczem\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "przenoszê podpis klucza na w³a¶ciwe miejsce\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -9164,11 +9254,6 @@ msgstr ""
 #~ msgstr "nie uda³o siê otworzyæ ,,%s'': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "niepoprawna warto¶æ\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "b³±d odczytu bloku klucza tajnego ,,%s'': %s\n"
index bfdfdf1..c271492 100644 (file)
--- a/po/pt.po
+++ b/po/pt.po
@@ -384,7 +384,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "erro na criação da frase secreta: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -481,6 +481,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: directoria criada\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVISO: permissões pouco seguras em %s \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "base de dados de confiança: leitura falhou (n=%d): %s\n"
 
@@ -733,9 +737,9 @@ msgstr "erro na cria
 msgid "error forking process: %s\n"
 msgstr "erro na leitura de `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "actualização falhou: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -753,6 +757,10 @@ msgstr "erro na leitura de `%s': %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "erro ao escrever no porta-chaves secreto `%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -773,6 +781,10 @@ msgstr "cancelado pelo utilizador\n"
 msgid "problem with the agent\n"
 msgstr "problema com o agente: o agente returnou 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problema com o agente: o agente returnou 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "impossível desactivar core dumps: %s\n"
@@ -830,6 +842,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "erro ao criar porta-chaves `%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1106,10 +1122,6 @@ msgstr "n
 msgid "invalid option \"%.50s\"\n"
 msgstr "opções de importação inválidas\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "você encontrou um bug ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "criação de armadura falhou: %s\n"
@@ -1213,6 +1225,11 @@ msgstr ""
 "caracter \"quoted printable\" na armadura - provavelmente um MTA com bugs "
 "foi usado\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "não legível por humanos"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1230,12 +1247,22 @@ msgstr "um valor de nota
 msgid "a notation value must not use any control characters\n"
 msgstr "um valor de notação não deve usar caracteres de controle\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "um valor de notação de utilizador não deve conter o caracter '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"um nome de notação deve ter apenas caracteres imprimíveis ou espaços, e "
+"terminar com um '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "AVISO: dados de notação inválidos encontrados\n"
 
-msgid "not human readable"
-msgstr "não legível por humanos"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1330,10 +1357,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "erro ao criar porta-chaves `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "erro na leitura de `%s': %s\n"
@@ -1673,14 +1696,14 @@ msgstr ""
 "ao forçar a cifra simétrica %s (%d) viola as preferências do destinatário\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "não pode utilizar %s enquanto estiver no modo %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s cifrado para: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "não pode utilizar %s enquanto estiver no modo %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "dados cifrados com %s\n"
 
@@ -1965,7 +1988,7 @@ msgstr "|algo [ficheiros]|imprimir \"digests\" de mensagens"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2975,11 +2998,27 @@ msgid "[self-signature]"
 msgstr "[auto-assinatura]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d assinaturas incorrectas\n"
-msgstr[1] "%d assinaturas incorrectas\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "chave %08lX: algoritmo de chave pública não suportado\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "assinatura %s de: \"%s\"\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Assinatura correcta de \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "ignorado `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Utilizador \"%s\" está revocado."
+msgstr[1] "Utilizador \"%s\" está revocado."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2989,18 +3028,23 @@ msgstr[0] "1 assinatura n
 msgstr[1] "1 assinatura não verificada por falta de chave\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 assinatura não verificada devido a um erro\n"
-msgstr[1] "1 assinatura não verificada devido a um erro\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d assinaturas incorrectas\n"
+msgstr[1] "%d assinaturas incorrectas\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d IDs de utilizadores sem auto-assinaturas válidas detectados\n"
-msgstr[1] "%d IDs de utilizadores sem auto-assinaturas válidas detectados\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Assinatura correcta de \""
+msgstr[1] "Assinatura correcta de \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3222,9 +3266,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "erro na criação da frase secreta: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "a mover a assinatura da chave para o local correcto\n"
-
 msgid "save and quit"
 msgstr "gravar e sair"
 
@@ -3507,6 +3548,11 @@ msgstr "%s: vers
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "falha ao inicializar a base de dados de confiança: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "valor inválido\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4332,6 +4378,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d assinaturas incorrectas\n"
 msgstr[1] "%d assinaturas incorrectas\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 assinatura não verificada devido a um erro\n"
+msgstr[1] "1 assinatura não verificada devido a um erro\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5542,14 +5595,14 @@ msgstr "base de dados de confian
 msgid "trustdb transaction too large\n"
 msgstr "transação de base de dados de confiança muito grande\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "impossível fechar `%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: diretoria inexistente!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "impossível fechar `%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: falha ao criar registo de versão: %s"
@@ -5695,8 +5748,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5785,39 +5838,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "erro na criação da frase secreta: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5826,20 +5881,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [ficheiros]|imprimir \"digests\" de mensagens"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5853,12 +5910,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8749,6 +8813,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "você encontrou um bug ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d IDs de utilizadores sem auto-assinaturas válidas detectados\n"
+#~ msgstr[1] "%d IDs de utilizadores sem auto-assinaturas válidas detectados\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "a mover a assinatura da chave para o local correcto\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d assinaturas não verificadas por falta de chaves\n"
 
@@ -8842,11 +8919,6 @@ msgstr ""
 #~ msgstr "impossível abrir `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "valor inválido\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "erro na leitura do bloco de chave secreto `%s': %s\n"
 
index a8b2be4..79d9bae 100644 (file)
--- a/po/ro.po
+++ b/po/ro.po
@@ -394,7 +394,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "eroare la crearea frazei-parolã: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -493,6 +493,10 @@ msgid "directory '%s' created\n"
 msgstr "director `%s' creat\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "AVERTISMENT: permisiuni nesigure (unsafe) pentru extensia `%s'\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fstat(%d) a eºuat în %s: %s\n"
 
@@ -750,9 +754,9 @@ msgstr "eroare la crearea frazei-parol
 msgid "error forking process: %s\n"
 msgstr "eroare la citire `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "actualizarea a eºuat: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -770,6 +774,10 @@ msgstr "eroare la citire `%s': %s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "eroare la obþinerea informaþiei pentru cheia curentã: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -790,6 +798,10 @@ msgstr "anulat
 msgid "problem with the agent\n"
 msgstr "problemã cu agentul: agentul returneazã 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problemã cu agentul: agentul returneazã 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "nu pot deactiva generarea fiºierelor core: %s\n"
@@ -845,6 +857,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "eroare la crearea inelului de chei `%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1123,10 +1139,6 @@ msgstr "nefor
 msgid "invalid option \"%.50s\"\n"
 msgstr "opþiuni enumerare invalide\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "aþi gãsit un bug ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "redenumirea `%s' ca `%s' a eºuat: %s\n"
@@ -1228,6 +1240,11 @@ msgstr ""
 "caracter printabil în ghilimele în armurã - probabil a fost folosit un MTA "
 "cu bug-uri\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "ilizibil"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1245,12 +1262,23 @@ msgid "a notation value must not use any control characters\n"
 msgstr ""
 "o valoare de notaþie trebuie sã nu foloseascã nici un caracter de control\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "un nume de notaþie trebuie sã nu conþinã mai mult de un caracter '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"un nume de notaþie trebuie sã conþinã numai caractere imprimabile sau spaþii "
+"ºi sã se termine cu un '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "AVERTISMENT: am gãsit date de notare invalide\n"
 
-msgid "not human readable"
-msgstr "ilizibil"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1339,10 +1367,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Eroare: URL prea lung (limita este de %d caractere).\n"
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "eroare la crearea inelului de chei `%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "eroare la citire `%s': %s\n"
@@ -1670,14 +1694,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "forþând cifrul simetric %s (%d) violaþi preferinþele destinatarului\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "nu puteþi folosi %s câtã vreme în modul %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s cifrat pentru: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "nu puteþi folosi %s câtã vreme în modul %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s date cifrate\n"
 
@@ -1964,7 +1988,7 @@ msgstr "|algo [fi
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3004,11 +3028,30 @@ msgid "[self-signature]"
 msgstr "[auto-semnãturã]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d semnãturi incorecte\n"
-msgstr[1] "%d semnãturi incorecte\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "cheia %s: algoritm cu cheie publicã nesuportat\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "semnãturã %s, algoritm rezumat %s\n"
+
+#, fuzzy
+#| msgid "revoke signatures"
+msgid " (reordered signatures follow)"
+msgstr "revocã semnãturi"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "sãritã \"%s\": %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "ID utilizator \"%s\" a fost revocat."
+msgstr[1] "ID utilizator \"%s\" a fost revocat."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3018,18 +3061,23 @@ msgstr[0] "1 semn
 msgstr[1] "1 semnãturã nu a fost verificatã din cauza unei chei lipsã\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 semnãturã nu a fost verificatã din cauza unei erori\n"
-msgstr[1] "1 semnãturã nu a fost verificatã din cauza unei erori\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d semnãturi incorecte\n"
+msgstr[1] "%d semnãturi incorecte\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "am gãsit %d ID-uri utilizator fãrã auto-semnãturi valide\n"
-msgstr[1] "am gãsit %d ID-uri utilizator fãrã auto-semnãturi valide\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Semnãturã bunã din \"%s\""
+msgstr[1] "Semnãturã bunã din \"%s\""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3231,9 +3279,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "eroare la crearea frazei-parolã: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "mut o semnãturã de cheie în locul corect\n"
-
 msgid "save and quit"
 msgstr "salveazã ºi terminã"
 
@@ -3502,6 +3547,11 @@ msgstr "amprent
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "am eºuat sã stochez amprenta: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "valoare invalidã\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4324,6 +4374,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d semnãturi incorecte\n"
 msgstr[1] "%d semnãturi incorecte\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 semnãturã nu a fost verificatã din cauza unei erori\n"
+msgstr[1] "1 semnãturã nu a fost verificatã din cauza unei erori\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5556,16 +5613,16 @@ msgstr "trustdb rec %lu: scrierea a e
 msgid "trustdb transaction too large\n"
 msgstr "tranzacþia trustdb prea mare\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: directorul nu existã!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "nu pot accesa `%s': %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: directorul nu existã!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: am eºuat sã creez înregistrare versiune: %s"
 
@@ -5710,8 +5767,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5801,39 +5858,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "eroare la crearea frazei-parolã: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5842,20 +5901,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [fiºiere]|afiºeazã rezumate mesaje"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5869,12 +5930,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8802,6 +8870,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "aþi gãsit un bug ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "am gãsit %d ID-uri utilizator fãrã auto-semnãturi valide\n"
+#~ msgstr[1] "am gãsit %d ID-uri utilizator fãrã auto-semnãturi valide\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "mut o semnãturã de cheie în locul corect\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d semnãturi nu au fost verificate din cauza unor chei lipsã\n"
 
@@ -8895,11 +8976,6 @@ msgstr ""
 #~ msgstr "Nu pot deschide `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "valoare invalidã\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "eroare la citire keyblock secret \"%s\": %s\n"
@@ -10219,9 +10295,6 @@ msgstr ""
 #~ msgid "revsig"
 #~ msgstr "revsem"
 
-#~ msgid "revoke signatures"
-#~ msgstr "revocã semnãturi"
-
 #~ msgid "revuid"
 #~ msgstr "revuid"
 
index 5c79639..f311cd1 100644 (file)
--- a/po/ru.po
+++ b/po/ru.po
@@ -4,14 +4,14 @@
 #              !-- no such user (2011-01-11)
 # Thanks Pawel I. Shajdo <pshajdo@gmail.com>.
 # Thanks Cmecb for the inspiration.
-# Ineiev <ineiev@gnu.org>, 2014, 2015
+# Ineiev <ineiev@gnu.org>, 2014, 2015, 2016
 #
 # Designated-Translator: none
 msgid ""
 msgstr ""
 "Project-Id-Version: GnuPG 2.1.0\n"
 "Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2015-08-12 17:17+0000\n"
+"PO-Revision-Date: 2016-01-27 17:17+0000\n"
 "Last-Translator: Ineiev <ineiev@gnu.org>\n"
 "Language-Team: Russian <gnupg-ru@gnupg.org>\n"
 "Language: ru\n"
@@ -371,7 +371,9 @@ msgstr "не позволять клиентам помечать ключи к
 msgid "allow presetting passphrase"
 msgstr "разрешить предустанавливать фразу-пароль"
 
-msgid "allow caller to override the pinentry"
+#, fuzzy
+#| msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr "разрешить клиентам замещать собой pinentry"
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -457,6 +459,11 @@ msgstr "не могу создать каталог '%s': %s\n"
 msgid "directory '%s' created\n"
 msgstr "создан каталог '%s'\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Внимание: небезопасные права доступа %s \"%s\"\n"
+
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "сбой stat() для '%s': %s\n"
@@ -712,8 +719,9 @@ msgstr "ошибка при создании потока для канала к
 msgid "error forking process: %s\n"
 msgstr "ошибка при дублировании процесса: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "сбой при ожидании завершения процесса %d: %s\n"
 
 #, c-format
@@ -733,6 +741,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "ошибка получения кода возврата процесса %d: %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "сбой при ожидании завершения процесса %d: %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "не могу подключиться к '%s': %s\n"
 
@@ -748,6 +760,11 @@ msgstr "прервано пользователем\n"
 msgid "problem with the agent\n"
 msgstr "проблема с агентом\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "проблема с агентом: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "не могу отключить создание файла образа памяти: %s\n"
@@ -804,6 +821,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "выход за границы при размещении %lu байтов"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "ошибка выделения достаточной памяти: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: устаревший параметр \"%s\" - игнорируется\n"
 
@@ -1042,10 +1063,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "недопустимый параметр \"%.50s\"\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "Вы нашли ошибку в программе ... (%s:%d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "преобразование из '%s' в '%s' недоступно\n"
 
@@ -1145,6 +1162,11 @@ msgstr ""
 "символ quoted printable в текстовом формате - испорчено почтовой "
 "программой?\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "не для чтения человеком"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1162,12 +1184,24 @@ msgstr ""
 msgid "a notation value must not use any control characters\n"
 msgstr "в значении примечания не должно быть управляющих символов\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr ""
+"имя примечания пользователя не должно содержать более одного символа '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"имя примечания должно содержать только печатные символы или пробелы и "
+"заканчиваться знаком '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "Внимание: найдена недопустимая форма записи примечания\n"
 
-msgid "not human readable"
-msgstr "не для чтения человеком"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "сбой при трансляции запроса %s клиенту\n"
@@ -1175,19 +1209,17 @@ msgstr "сбой при трансляции запроса %s клиенту\n"
 msgid "Enter passphrase: "
 msgstr "Введите фразу-пароль:"
 
-#, fuzzy, c-format
-#| msgid "error creating keyring '%s': %s\n"
+#, c-format
 msgid "error getting version from '%s': %s\n"
-msgstr "ошибка создания таблицы ключей '%s': %s\n"
+msgstr "ошибка получения версии из '%s': %s\n"
 
 #, c-format
 msgid "server '%s' is older than us (%s < %s)"
-msgstr ""
+msgstr "сервер '%s' старше нас (%s < %s)"
 
-#, fuzzy, c-format
-#| msgid "WARNING: %s overrides %s\n"
+#, c-format
 msgid "WARNING: %s\n"
-msgstr "Внимание: %s отменяет %s\n"
+msgstr "Внимание: %s\n"
 
 #, c-format
 msgid "OpenPGP card not available: %s\n"
@@ -1254,10 +1286,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Ошибка: Слишком длинный URL (предел - %d символов).\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "ошибка выделения достаточной памяти: %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "ошибка чтения '%s': %s\n"
 
@@ -1569,14 +1597,14 @@ msgstr ""
 "предпочтения получателя\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "нельзя использовать %s в режиме %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s зашифровано для: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "нельзя использовать %s в режиме %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "данные зашифрованы алгоритмом %s\n"
 
@@ -1678,24 +1706,19 @@ msgstr "[ID пользователя не найден]"
 msgid "(check argument of option '%s')\n"
 msgstr "(проверьте аргумент параметра '%s')\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "Warning: value '%s' for option '%s' should be a long key ID or a "
-#| "fingerprint\n"
+#, c-format
 msgid "Warning: '%s' should be a long key ID or a fingerprint\n"
 msgstr ""
-"Внимание: значение '%s' параметра '%s' должно быть длинным идентификатором "
-"или Ð¾Ñ\82пеÑ\87аÑ\82ком ÐºÐ»Ñ\8eÑ\87а\n"
+"Внимание: '%s' должно быть должно быть длинным идентификатором или "
+"отпечатком ключа\n"
 
-#, fuzzy, c-format
-#| msgid "error closing %s: %s\n"
+#, c-format
 msgid "error looking up: %s\n"
-msgstr "оÑ\88ибка Ð·Ð°ÐºÑ\80Ñ\8bÑ\82иÑ\8f %s: %s\n"
+msgstr "оÑ\88ибка Ð¿Ð¾Ð¸Ñ\81ка: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error searching the keyring: %s\n"
+#, c-format
 msgid "Warning: %s appears in the keyring %d times\n"
-msgstr "оÑ\88ибка Ð¿Ð¾Ð¸Ñ\81ка Ð² Ñ\82аблиÑ\86е ÐºÐ»Ñ\8eÑ\87ей %s\n"
+msgstr "Ð\92нимание: %s Ð²ÐºÐ»Ñ\8eÑ\87ено Ð² Ñ\82аблиÑ\86Ñ\83 ÐºÐ»Ñ\8eÑ\87ей %d Ñ\80аз\n"
 
 #, c-format
 msgid "automatically retrieved '%s' via %s\n"
@@ -1712,19 +1735,18 @@ msgstr "Нет отпечатка"
 msgid "secret key \"%s\" not found: %s\n"
 msgstr "секретный ключ \"%s\" не найден: %s\n"
 
-#, fuzzy, c-format
-#| msgid "using \"%s\" as default secret key\n"
+#, c-format
 msgid "Warning: not using '%s' as default key: %s\n"
-msgstr "\"%s\" используется в качестве основного секретного ключа\n"
+msgstr "Внимание: '%s' не используется в качестве основного ключа: %s\n"
 
-#, fuzzy, c-format
-#| msgid "using \"%s\" as default secret key\n"
+#, c-format
 msgid "using \"%s\" as default secret key for signing\n"
-msgstr "\"%s\" используется в качестве основного секретного ключа\n"
+msgstr ""
+"\"%s\" используется в качестве основного секретного ключа для подписи\n"
 
 #, c-format
 msgid "all values passed to '%s' ignored\n"
-msgstr ""
+msgstr "все значения, переданные в '%s', игнорируются\n"
 
 #, c-format
 msgid "Invalid key %s made valid by --allow-non-selfsigned-uid\n"
@@ -1847,7 +1869,9 @@ msgstr "вывести хэши сообщений"
 msgid "run in server mode"
 msgstr "запуск в режиме сервера"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+#, fuzzy
+#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 "|VALUE|установить правила TOFU для ключа (good - хороший, unknown - "
 "неизвестно, bad - плохой, ask - спрашивать, auto - автоматически)"
@@ -2333,10 +2357,9 @@ msgstr "сбой при получении с сервера ключей: %s\n"
 msgid "key export failed: %s\n"
 msgstr "сбой при экспорте ключа: %s\n"
 
-#, fuzzy, c-format
-#| msgid "key export failed: %s\n"
+#, c-format
 msgid "export as ssh key failed: %s\n"
-msgstr "Ñ\81бой Ð¿Ñ\80и Ñ\8dкÑ\81поÑ\80Ñ\82е ÐºÐ»Ñ\8eÑ\87а: %s\n"
+msgstr "Ñ\81бой Ð¿Ñ\80и Ñ\8dкÑ\81поÑ\80Ñ\82е Ð² Ð²Ð¸Ð´Ðµ ÐºÐ»Ñ\8eÑ\87а ssh: %s\n"
 
 #, c-format
 msgid "keyserver search failed: %s\n"
@@ -2816,36 +2839,62 @@ msgid "[self-signature]"
 msgstr "[самоподпись]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d плохих подписей\n"
-msgstr[1] "%d плохих подписей\n"
-msgstr[2] "%d плохих подписей\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "ключ %s: алгоритм с открытым ключом не поддерживается\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "карта не поддерживает хэш-функцию %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Хорошая подпись пользователя"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to a missing key\n"
+#| msgid "key %s: %s\n"
+msgid "key %s:\n"
+msgstr "ключ %s: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+#| msgid_plural "User ID \"%s\": %d signatures removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "ID пользователя \"%s\": %d подпись удалена\n"
+msgstr[1] "ID пользователя \"%s\": %d подписи удалены\n"
+msgstr[2] "ID пользователя \"%s\": %d подписей удалено\n"
+
+#, c-format
 msgid "%d signature not checked due to a missing key\n"
 msgid_plural "%d signatures not checked due to missing keys\n"
-msgstr[0] "1 подпись не проверена за отсутствием ключа\n"
-msgstr[1] "1 подпись не проверена за отсутствием ключа\n"
-msgstr[2] "1 подпись не проверена за отсутствием ключа\n"
+msgstr[0] "%d подпись не проверена за отсутствием ключа\n"
+msgstr[1] "%d подписи не проверены за отсутствием ключа\n"
+msgstr[2] "%d подписей не проверено за отсутствием ключа\n"
 
-#, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 подпись не проверена из-за ошибки\n"
-msgstr[1] "1 подпись не проверена из-за ошибки\n"
-msgstr[2] "1 подпись не проверена из-за ошибки\n"
+#, c-format
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d плохая подпись\n"
+msgstr[1] "%d плохих подписи\n"
+msgstr[2] "%d плохих подписей\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "обнаружено %d ID пользователя без действительной самоподписи\n"
-msgstr[1] "обнаружено %d ID пользователя без действительной самоподписи\n"
-msgstr[2] "обнаружено %d ID пользователя без действительной самоподписи\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Хорошая подпись пользователя"
+msgstr[1] "Хорошая подпись пользователя"
+msgstr[2] "Хорошая подпись пользователя"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3042,9 +3091,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "ключ %s: ошибка изменения фразы-пароля: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "перемещение подписи ключа в нужное место\n"
-
 msgid "save and quit"
 msgstr "сохранить и выйти"
 
@@ -3292,6 +3338,11 @@ msgstr "\"%s\" - не отпечаток\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "\"%s\" - не первичный отпечаток\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "недопустимое значение\n"
+
 msgid "No matching user IDs."
 msgstr "Нет подходящих ID пользователей."
 
@@ -3421,13 +3472,12 @@ msgstr "Удалить данную неизвестную подпись? (y/N/
 msgid "Really delete this self-signature? (y/N)"
 msgstr "Действительно удалить данную самоподпись? (y/N)"
 
-#, fuzzy, c-format
-#| msgid "Deleted %d signature.\n"
+#, c-format
 msgid "Deleted %d signature.\n"
 msgid_plural "Deleted %d signatures.\n"
 msgstr[0] "Удалена %d подпись.\n"
-msgstr[1] "Удалена %d подпись.\n"
-msgstr[2] "Удалена %d Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c.\n"
+msgstr[1] "Удалены %d подписи.\n"
+msgstr[2] "Удалено %d Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей.\n"
 
 msgid "Nothing deleted.\n"
 msgstr "Ничего не удалено.\n"
@@ -3439,13 +3489,12 @@ msgstr "недопустимый"
 msgid "User ID \"%s\" compacted: %s\n"
 msgstr "ID пользователя \"%s\" сжат: %s\n"
 
-#, fuzzy, c-format
-#| msgid "User ID \"%s\": %d signature removed\n"
+#, c-format
 msgid "User ID \"%s\": %d signature removed\n"
 msgid_plural "User ID \"%s\": %d signatures removed\n"
 msgstr[0] "ID пользователя \"%s\": %d подпись удалена\n"
-msgstr[1] "ID пользователя \"%s\": %d подпись удалена\n"
-msgstr[2] "ID пользователя \"%s\": %d подпись удалена\n"
+msgstr[1] "ID пользователя \"%s\": %d подписи удалены\n"
+msgstr[2] "ID пользователя \"%s\": %d подписей удалено\n"
 
 #, c-format
 msgid "User ID \"%s\": already minimized\n"
@@ -3874,8 +3923,8 @@ msgstr ""
 "\n"
 "Для идентификации Вашего ключа необходим ID пользователя. Программа создаст "
 "его\n"
-"из Ð\92аÑ\88его Ð¸Ð¼ÐµÐ½Ð¸, ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ\82аÑ\80ия и адреса электронной почты в виде:\n"
-"    \"Baba Yaga (pensioner) <yaga@deepforest.ru>\"\n"
+"из Ð\92аÑ\88его Ð¸Ð¼ÐµÐ½Ð¸, Ð¿Ñ\80имеÑ\87ания и адреса электронной почты в виде:\n"
+"    \"Вася Пушкин (персонаж) <vp@test.ru>\"\n"
 "\n"
 
 msgid "Real name: "
@@ -3901,10 +3950,10 @@ msgid "Not a valid email address\n"
 msgstr "Неправильный адрес электронной почты\n"
 
 msgid "Comment: "
-msgstr "Ð\9aомменÑ\82аÑ\80ий: "
+msgstr "Ð\9fÑ\80имеÑ\87ание: "
 
 msgid "Invalid character in comment\n"
-msgstr "Ð\9dедопÑ\83Ñ\81Ñ\82имÑ\8bй Ñ\81имвол Ð² ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ\82аÑ\80ии\n"
+msgstr "Ð\9dедопÑ\83Ñ\81Ñ\82имÑ\8bй Ñ\81имвол Ð² Ð¿Ñ\80имеÑ\87ании\n"
 
 #, c-format
 msgid "You are using the '%s' character set.\n"
@@ -3922,7 +3971,7 @@ msgstr ""
 
 msgid "Please don't put the email address into the real name or the comment\n"
 msgstr ""
-"Ð\9dе Ð²Ñ\81Ñ\82авлÑ\8fйÑ\82е Ð°Ð´Ñ\80еÑ\81 Ñ\8dлекÑ\82Ñ\80онной Ð¿Ð¾Ñ\87Ñ\82Ñ\8b Ð² Ð¸Ð¼Ñ\8f Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f Ð¸Ð»Ð¸ ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ\82аÑ\80ий\n"
+"Ð\9dе Ð²Ñ\81Ñ\82авлÑ\8fйÑ\82е Ð°Ð´Ñ\80еÑ\81 Ñ\8dлекÑ\82Ñ\80онной Ð¿Ð¾Ñ\87Ñ\82Ñ\8b Ð² Ð¸Ð¼Ñ\8f Ð¿Ð¾Ð»Ñ\8cзоваÑ\82елÑ\8f Ð¸Ð»Ð¸ Ð¿Ñ\80имеÑ\87ание\n"
 
 #. TRANSLATORS: These are the allowed answers in
 #. lower and uppercase.  Below you will find the matching
@@ -3939,10 +3988,10 @@ msgid "NnCcEeOoQq"
 msgstr "NnCcEeOoQq"
 
 msgid "Change (N)ame, (C)omment, (E)mail or (Q)uit? "
-msgstr "СмениÑ\82Ñ\8c (N)Ð\98мÑ\8f, (C)Ð\9aомменÑ\82аÑ\80ий, (E)Адрес или (Q)Выход? "
+msgstr "СмениÑ\82Ñ\8c (N)Ð\98мÑ\8f, (C)Ð\9fÑ\80имеÑ\87ание, (E)Адрес или (Q)Выход? "
 
 msgid "Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "
-msgstr "СмениÑ\82Ñ\8c (N)Ð\98мÑ\8f, (C)Ð\9aомменÑ\82аÑ\80ий, (E)Адрес или (O)Принять/(Q)Выход? "
+msgstr "СмениÑ\82Ñ\8c (N)Ð\98мÑ\8f, (C)Ð\9fÑ\80имеÑ\87ание, (E)Адрес или (O)Принять/(Q)Выход? "
 
 msgid "Change (N)ame, (E)mail, or (Q)uit? "
 msgstr "Сменить (N)Имя, (E)Адрес или (Q)Выход? "
@@ -4074,20 +4123,25 @@ msgstr "Критическое примечание к подписи: "
 msgid "Signature notation: "
 msgstr "Примечание к подписи: "
 
-#, fuzzy, c-format
-#| msgid "%d good signatures\n"
+#, c-format
 msgid "%d good signature\n"
 msgid_plural "%d good signatures\n"
-msgstr[0] "%d Ñ\85оÑ\80оÑ\88иÑ\85 Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей\n"
-msgstr[1] "%d Ñ\85оÑ\80оÑ\88иÑ\85 Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей\n"
+msgstr[0] "%d Ñ\85оÑ\80оÑ\88аÑ\8f Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81Ñ\8c\n"
+msgstr[1] "%d Ñ\85оÑ\80оÑ\88иÑ\85 Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81и\n"
 msgstr[2] "%d хороших подписей\n"
 
-#, fuzzy, c-format
-#| msgid "Warning: %lu key(s) skipped due to their large size\n"
+#, c-format
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "%d подпись не проверена из-за ошибки\n"
+msgstr[1] "%d подписи не проверены из-за ошибки\n"
+msgstr[2] "%d подписей не проверено из-за ошибки\n"
+
+#, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
-msgstr[0] "Внимание: %lu ключей пропущено из-за большого размера\n"
-msgstr[1] "Ð\92нимание: %lu ÐºÐ»Ñ\8eÑ\87ей Ð¿Ñ\80опÑ\83Ñ\89ено из-за большого размера\n"
+msgstr[0] "Внимание: %lu ключ пропущен из-за большого размера\n"
+msgstr[1] "Ð\92нимание: %lu ÐºÐ»Ñ\8eÑ\87а Ð¿Ñ\80опÑ\83Ñ\89енÑ\8b из-за большого размера\n"
 msgstr[2] "Внимание: %lu ключей пропущено из-за большого размера\n"
 
 msgid "Keyring"
@@ -4121,29 +4175,26 @@ msgstr " серийный номер карты ="
 msgid "caching keyring '%s'\n"
 msgstr "занесение таблицы ключей '%s' в буфер\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys cached so far (%lu signatures)\n"
+#, c-format
 msgid "%lu keys cached so far (%lu signature)\n"
 msgid_plural "%lu keys cached so far (%lu signatures)\n"
-msgstr[0] "пока в буфер помещено %lu ключей (%lu подписей)\n"
-msgstr[1] "пока Ð² Ð±Ñ\83Ñ\84еÑ\80 Ð¿Ð¾Ð¼ÐµÑ\89ено %lu ÐºÐ»Ñ\8eÑ\87ей (%lu Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81ей)\n"
+msgstr[0] "пока в буфер помещено %lu ключей (%lu подпись)\n"
+msgstr[1] "пока Ð² Ð±Ñ\83Ñ\84еÑ\80 Ð¿Ð¾Ð¼ÐµÑ\89ено %lu ÐºÐ»Ñ\8eÑ\87ей (%lu Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81и)\n"
 msgstr[2] "пока в буфер помещено %lu ключей (%lu подписей)\n"
 
-#, fuzzy, c-format
-#| msgid "flush the cache"
+#, c-format
 msgid "%lu key cached"
 msgid_plural "%lu keys cached"
-msgstr[0] "запиÑ\81аÑ\82Ñ\8c Ð±Ñ\83Ñ\84еÑ\80 Ð½Ð° Ð´Ð¸Ñ\81к"
-msgstr[1] "запиÑ\81аÑ\82Ñ\8c Ð±Ñ\83Ñ\84еÑ\80 Ð½Ð° Ð´Ð¸Ñ\81к"
-msgstr[2] "запиÑ\81аÑ\82Ñ\8c Ð±Ñ\83Ñ\84еÑ\80 Ð½Ð° Ð´Ð¸Ñ\81к"
+msgstr[0] "в Ð±Ñ\83Ñ\84еÑ\80 Ð·Ð°Ð¿Ð¸Ñ\81ан %lu ÐºÐ»Ñ\8eÑ\87"
+msgstr[1] "в Ð±Ñ\83Ñ\84еÑ\80 Ð·Ð°Ð¿Ð¸Ñ\81анÑ\8b %lu ÐºÐ»Ñ\8eÑ\87а"
+msgstr[2] "в Ð±Ñ\83Ñ\84еÑ\80 Ð·Ð°Ð¿Ð¸Ñ\81ано %lu ÐºÐ»Ñ\8eÑ\87ей"
 
-#, fuzzy, c-format
-#| msgid "1 bad signature\n"
+#, c-format
 msgid " (%lu signature)\n"
 msgid_plural " (%lu signatures)\n"
-msgstr[0] "1 плохая подпись\n"
-msgstr[1] "1 плохая подпись\n"
-msgstr[2] "1 плохая подпись\n"
+msgstr[0] "(%lu подпись)\n"
+msgstr[1] "(%lu подписи)\n"
+msgstr[2] "(%lu подписей)\n"
 
 #, c-format
 msgid "%s: keyring created\n"
@@ -4184,11 +4235,10 @@ msgstr "недопустимый протокол сервера ключей (
 msgid "\"%s\" not a key ID: skipping\n"
 msgstr "\"%s\" - не ID ключа: пропущен\n"
 
-#, fuzzy, c-format
-#| msgid "refreshing %d keys from %s\n"
+#, c-format
 msgid "refreshing %d key from %s\n"
 msgid_plural "refreshing %d keys from %s\n"
-msgstr[0] "обновление %d ÐºÐ»Ñ\8eÑ\87ей из %s\n"
+msgstr[0] "обновление %d ÐºÐ»Ñ\8eÑ\87а из %s\n"
 msgstr[1] "обновление %d ключей из %s\n"
 msgstr[2] "обновление %d ключей из %s\n"
 
@@ -4214,10 +4264,8 @@ msgstr "запрашиваю ключ %s с сервера %s %s\n"
 msgid "requesting key %s from %s\n"
 msgstr "получение ключа %s с %s\n"
 
-#, fuzzy
-#| msgid "invalid keyserver options\n"
 msgid "no keyserver known\n"
-msgstr "недопÑ\83Ñ\81Ñ\82имÑ\8bе Ð¿Ð°Ñ\80амеÑ\82Ñ\80Ñ\8b Ñ\81еÑ\80веÑ\80а ÐºÐ»Ñ\8eÑ\87ей\n"
+msgstr "ни Ð¾Ð´Ð¸Ð½ Ñ\81еÑ\80веÑ\80 ÐºÐ»Ñ\8eÑ\87ей Ð½Ðµ Ð¸Ð·Ð²ÐµÑ\81Ñ\82ен\n"
 
 #, c-format
 msgid "sending key %s to %s\n"
@@ -4432,18 +4480,16 @@ msgstr "Внимание: хэш-функция %s не рекомендуетс
 msgid "Note: signatures using the %s algorithm are rejected\n"
 msgstr "Замечание: подписи с хэш-функцией %s игнорируются\n"
 
-#, fuzzy, c-format
-#| msgid "%s:%u: read error: %s\n"
+#, c-format
 msgid "(reported error: %s)\n"
-msgstr "%s:%u: ошибка чтения: %s\n"
+msgstr "(сообщенная ошибка: %s)\n"
 
-#, fuzzy, c-format
-#| msgid "read error in '%s': %s\n"
+#, c-format
 msgid "(reported error: %s <%s>)\n"
-msgstr "ошибка чтения в '%s': %s\n"
+msgstr "(сообщенная ошибка: %s <%s>)\n"
 
 msgid "(further info: "
-msgstr ""
+msgstr "(дальнейшие сведения: "
 
 #, c-format
 msgid "%s:%d: deprecated option \"%s\"\n"
@@ -4835,10 +4881,9 @@ msgstr "%s: пропущено: открытый ключ отключен\n"
 msgid "%s: skipped: public key already present\n"
 msgstr "%s: пропущено: открытый ключ уже существует\n"
 
-#, fuzzy, c-format
-#| msgid "can't connect to '%s': %s\n"
+#, c-format
 msgid "can't encrypt to '%s'\n"
-msgstr "не Ð¼Ð¾Ð³Ñ\83 Ð¿Ð¾Ð´ÐºÐ»Ñ\8eÑ\87иÑ\82Ñ\8cÑ\81Ñ\8f Ðº '%s': %s\n"
+msgstr "не Ð¼Ð¾Ð³Ñ\83 Ð·Ð°Ñ\88иÑ\84Ñ\80оваÑ\82Ñ\8c Ð´Ð»Ñ\8f '%s'\n"
 
 #, c-format
 msgid "option '%s' given, but no valid default keys given\n"
@@ -4979,13 +5024,10 @@ msgid ""
 "declare that a key shall not anymore be used.  It is not possible\n"
 "to retract such a revocation certificate once it has been published."
 msgstr ""
+"Сертификат отзыва - своего рода \"уничтожитель\", с его помощью можно\n"
+"публично объявить, что ключ больше не должен применяться. После публикации\n"
+"такой сертификат взять назад невозможно."
 
-#, fuzzy
-#| msgid ""
-#| "Use it to revoke this key in case of a compromise or loss of\n"
-#| "the secret key.  However, if the secret key is still accessible,\n"
-#| "it is better to generate a new revocation certificate and give\n"
-#| "a reason for the revocation."
 msgid ""
 "Use it to revoke this key in case of a compromise or loss of\n"
 "the secret key.  However, if the secret key is still accessible,\n"
@@ -4995,13 +5037,9 @@ msgid ""
 msgstr ""
 "Пользуйтесь им для отзыва этого ключа в случае раскрытия или потери\n"
 "секретного ключа. Однако, если секретный ключ доступен, лучше создать\n"
-"новый сертификат с указанием причины отзыва."
+"новый сертификат с указанием причины отзыва. Подробности см. в описании\n"
+"команды gpg \"--gen-revoke\" в руководстве по GnuPG."
 
-#, fuzzy
-#| msgid ""
-#| "To avoid an accidental use of this file, a colon has been inserted\n"
-#| "before the 5 dashes below.  Remove this colon with a text editor\n"
-#| "before making use of this revocation certificate."
 msgid ""
 "To avoid an accidental use of this file, a colon has been inserted\n"
 "before the 5 dashes below.  Remove this colon with a text editor\n"
@@ -5009,12 +5047,11 @@ msgid ""
 msgstr ""
 "Чтобы избежать случайного применения этого файла, перед 5 дефисами\n"
 "вставлено двоеточие. Удалите это двоеточие в текстовом редакторе\n"
-"перед использованием этого сертификата отзыва."
+"перед импортированием и публикацией этого сертификата отзыва."
 
-#, fuzzy, c-format
-#| msgid "Revocation certificate created.\n"
+#, c-format
 msgid "revocation certificate stored as '%s.rev'\n"
-msgstr "Сертификат отзыва создан.\n"
+msgstr "сертификат отзыва записан в '%s.rev'.\n"
 
 #, c-format
 msgid "secret key \"%s\" not found\n"
@@ -5106,25 +5143,21 @@ msgstr "за подробностями обращайтесь к %s\n"
 msgid "WARNING: signing subkey %s has an invalid cross-certification\n"
 msgstr "Внимание: подписывающий подключ %s неправильно перекрестно заверен\n"
 
-#, fuzzy, c-format
-#| msgid "public key %s is %lu second newer than the signature\n"
+#, c-format
 msgid "public key %s is %lu second newer than the signature\n"
 msgid_plural "public key %s is %lu seconds newer than the signature\n"
 msgstr[0] "открытый ключ %s на %lu секунду новее подписи\n"
-msgstr[1] "оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8bй ÐºÐ»Ñ\8eÑ\87 %s Ð½Ð° %lu Ñ\81екÑ\83ндÑ\83 новее подписи\n"
-msgstr[2] "открытый ключ %s на %lu секунду новее подписи\n"
+msgstr[1] "оÑ\82кÑ\80Ñ\8bÑ\82Ñ\8bй ÐºÐ»Ñ\8eÑ\87 %s Ð½Ð° %lu Ñ\81екÑ\83ндÑ\8b новее подписи\n"
+msgstr[2] "открытый ключ %s на %lu секунд новее подписи\n"
 
-#, fuzzy, c-format
-#| msgid "public key %s is %lu second newer than the signature\n"
+#, c-format
 msgid "public key %s is %lu day newer than the signature\n"
 msgid_plural "public key %s is %lu days newer than the signature\n"
-msgstr[0] "открытый ключ %s на %lu секунду новее подписи\n"
-msgstr[1] "открытый ключ %s на %lu секунду новее подписи\n"
-msgstr[2] "открытый ключ %s на %lu секунду новее подписи\n"
+msgstr[0] "открытый ключ %s на %lu день новее подписи\n"
+msgstr[1] "открытый ключ %s на %lu дня новее подписи\n"
+msgstr[2] "открытый ключ %s на %lu дней новее подписи\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid ""
 "key %s was created %lu second in the future (time warp or clock problem)\n"
 msgid_plural ""
@@ -5133,26 +5166,24 @@ msgstr[0] ""
 "ключ %s создан на %lu секунду в будущем (петля во времени или проблемы с "
 "часами)\n"
 msgstr[1] ""
-"клÑ\8eÑ\87 %s Ñ\81оздан Ð½Ð° %lu Ñ\81екÑ\83ндÑ\83 в будущем (петля во времени или проблемы с "
+"клÑ\8eÑ\87 %s Ñ\81оздан Ð½Ð° %lu Ñ\81екÑ\83ндÑ\8b в будущем (петля во времени или проблемы с "
 "часами)\n"
 msgstr[2] ""
-"ключ %s создан на %lu секунду в будущем (петля во времени или проблемы с "
+"ключ %s создан на %lu секунд в будущем (петля во времени или проблемы с "
 "часами)\n"
 
-#, fuzzy, c-format
-#| msgid ""
-#| "key %s was created %lu second in the future (time warp or clock problem)\n"
+#, c-format
 msgid "key %s was created %lu day in the future (time warp or clock problem)\n"
 msgid_plural ""
 "key %s was created %lu days in the future (time warp or clock problem)\n"
 msgstr[0] ""
-"ключ %s создан на %lu секунду в будущем (петля во времени или проблемы с "
+"ключ %s создан на %lu день в будущем (петля во времени или проблемы с "
 "часами)\n"
 msgstr[1] ""
-"ключ %s создан на %lu секунду в будущем (петля во времени или проблемы с "
+"ключ %s создан на %lu дня в будущем (петля во времени или проблемы с "
 "часами)\n"
 msgstr[2] ""
-"ключ %s создан на %lu секунду в будущем (петля во времени или проблемы с "
+"ключ %s создан на %lu дней в будущем (петля во времени или проблемы с "
 "часами)\n"
 
 #, c-format
@@ -5291,14 +5322,14 @@ msgid "trustdb transaction too large\n"
 msgstr "слишком большая операция над таблицей доверия\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "нет доступа к '%s': %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: каталог не существует!\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "нет доступа к '%s': %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: сбой создания записи о версии: %s"
 
@@ -5380,259 +5411,293 @@ msgstr "не могу обработать строки текста длинн
 msgid "input line longer than %d characters\n"
 msgstr "строка ввода длиннее %d символов\n"
 
-#, fuzzy, c-format
-#| msgid "error sending standard options: %s\n"
+#, c-format
 msgid "error beginning transaction on TOFU database: %s\n"
-msgstr "оÑ\88ибка Ð¾Ñ\82пÑ\80авки Ñ\81Ñ\82андаÑ\80Ñ\82нÑ\8bÑ\85 Ð¿Ð°Ñ\80амеÑ\82Ñ\80ов: %s\n"
+msgstr "оÑ\88ибка Ð² Ð½Ð°Ñ\87але Ð¾Ð¿ÐµÑ\80аÑ\86ии Ñ\81 Ð±Ð°Ð·Ð¾Ð¹ Ð´Ð°Ð½Ð½Ñ\8bÑ\85 TOFU: %s\n"
 
 #, c-format
 msgid "error committing transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "ошибка записи изменения в базе данных TOFU: %s\n"
 
 #, c-format
 msgid "error rolling back transaction on TOFU database: %s\n"
-msgstr ""
+msgstr "ошибка отката назад изменения в базе данных TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "unsupported algorithm: %s"
+#, c-format
 msgid "unsupported TOFU database version: %s\n"
-msgstr "алгоÑ\80иÑ\82м (не Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f): %s"
+msgstr "веÑ\80Ñ\81иÑ\8f Ð±Ð°Ð·Ñ\8b Ð´Ð°Ð½Ð½Ñ\8bÑ\85 TOFU (не Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f): %s\n"
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error reading TOFU database: %s\n"
-msgstr "ошибка отправки данных: %s\n"
+msgstr "ошибка чтения базы данных TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error writing base64 encoding: %s\n"
+#, c-format
 msgid "error determining TOFU database's version: %s\n"
-msgstr "оÑ\88ибка Ð·Ð°Ð¿Ð¸Ñ\81и Ð² ÐºÐ¾Ð´Ð¸Ñ\80овке base64: %s\n"
+msgstr "оÑ\88ибка Ð¾Ð¿Ñ\80еделениÑ\8f Ð²ÐµÑ\80Ñ\81ии Ð±Ð°Ð·Ñ\8b Ð´Ð°Ð½Ð½Ñ\8bÑ\85 TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error initializing reader object: %s\n"
+#, c-format
 msgid "error initializing TOFU database: %s\n"
-msgstr "оÑ\88ибка Ð¸Ð½Ð¸Ñ\86иализаÑ\86ии Ð¾Ð±Ñ\8aекÑ\82а Ñ\83Ñ\81Ñ\82Ñ\80ойÑ\81Ñ\82ва Ñ\87Ñ\82ениÑ\8f: %s\n"
+msgstr "оÑ\88ибка Ð¸Ð½Ð¸Ñ\86иализаÑ\86ии Ð±Ð°Ð·Ñ\8b Ð´Ð°Ð½Ð½Ñ\8bÑ\85 TOFU: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error opening '%s': %s\n"
+#, c-format
 msgid "error opening TOFU database '%s': %s\n"
-msgstr "ошибка открытия '%s': %s\n"
+msgstr "ошибка открытия базы данных TOFU '%s': %s\n"
 
 msgid "Warning: Home directory contains both tofu.db and tofu.d.\n"
-msgstr ""
+msgstr "Внимание: Домашний каталог содержит как tofu.db, так и tofu.d\n"
 
 msgid "Using split format for TOFU database\n"
-msgstr ""
+msgstr "Используется разделенный формат базы данных TOFU\n"
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error updating TOFU database: %s\n"
-msgstr "ошибка отправки данных: %s\n"
+msgstr "ошибка обновления базы данных TOFU: %s\n"
 
 #, c-format
 msgid "public key %s not found: %s\n"
 msgstr "открытый ключ %s не найден: %s\n"
 
-#, fuzzy, c-format
-#| msgid "error setting OCSP target: %s\n"
+#, c-format
 msgid "error setting TOFU binding's trust level to %s\n"
-msgstr "оÑ\88ибка Ñ\83Ñ\81Ñ\82ановки Ñ\86ели OCSP: %s\n"
+msgstr "оÑ\88ибка Ñ\83Ñ\81Ñ\82ановки Ñ\83Ñ\80овнÑ\8f Ð´Ð¾Ð²ÐµÑ\80иÑ\8f Ð¿Ñ\80ивÑ\8fзки TOFU Ð² %s\n"
 
 #, c-format
 msgid "The binding %s is NOT known."
-msgstr ""
+msgstr "Привязка %s неизвестна."
 
-#, c-format
+#, fuzzy, c-format
+#| msgid ""
+#| "The key %s raised a conflict with this binding (%s).  Since this "
+#| "binding's policy was 'auto', it was changed to 'ask'."
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
+"Ключ %s противоречит этой привязке (%s). Поскольку правило привязки было "
+"'автоматически', оно изменилось на 'спрашивать'."
 
 #, c-format
 msgid ""
 "Please indicate whether you believe the binding %s%sis legitimate (the key "
 "belongs to the stated owner) or a forgery (bad)."
 msgstr ""
+"Укажите, считаете ли Вы привязку %s%sправомерной (ключ принадлежит "
+"заявленному владельцу) или поддельной (плохой)."
 
-#, fuzzy, c-format
-#| msgid "error getting responder ID: %s\n"
+#, c-format
 msgid "error gathering other user IDs: %s\n"
-msgstr "ошибка при получении ID ответчика: %s\n"
+msgstr "ошибка при сборе ID других пользователей: %s\n"
 
 msgid "Known user IDs associated with this key:\n"
-msgstr ""
+msgstr "Известные ID пользователя, связанные с этим ключом:\n"
 
-#, fuzzy, c-format
-#| msgid "validity: %s"
+#, c-format
 msgid "policy: %s"
-msgstr "доÑ\81Ñ\82овеÑ\80ноÑ\81Ñ\82Ñ\8c: %s"
+msgstr "пÑ\80авило: %s"
 
-#, fuzzy, c-format
-#| msgid "error getting stored flags: %s\n"
+#, c-format
 msgid "error gathering signature stats: %s\n"
-msgstr "ошибка получения сохраненных признаков: %s\n"
+msgstr "ошибка сбора статистики подписей: %s\n"
 
 #, c-format
 msgid "The email address \"%s\" is associated with %d key:\n"
 msgid_plural "The email address \"%s\" is associated with %d keys:\n"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "Адрес электронной почты \"%s\" связан с %d ключом:\n"
+msgstr[1] "Адрес электронной почты \"%s\" связан с %d ключами:\n"
+msgstr[2] "Адрес электронной почты \"%s\" связан с %d ключами:\n"
 
 #, c-format
 msgid "Statistics for keys with the email address \"%s\":\n"
-msgstr ""
+msgstr "Статистика ключей с адресом электронной почты \"%s\":\n"
 
-#, fuzzy
-#| msgid "list keys"
 msgid "this key"
-msgstr "вывести список ключей"
+msgstr "этот ключ"
 
 #, c-format
 msgid "%ld message signed in the future."
 msgid_plural "%ld messages signed in the future."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] "%ld сообщение подписано в будущем."
+msgstr[1] "%ld сообщения подписаны в будущем."
+msgstr[2] "%ld сообщений подписано в будущем."
 
-#, fuzzy, c-format
-#| msgid "print message digests"
+#, c-format
 msgid "%ld message signed"
 msgid_plural "%ld messages signed"
-msgstr[0] "вывести хэши сообщений"
-msgstr[1] "вывести хэши сообщений"
-msgstr[2] "вывести хэши сообщений"
+msgstr[0] "%ld сообщение подписано"
+msgstr[1] "%ld сообщения подписаны"
+msgstr[2] "%ld сообщений подписано"
 
 #, c-format
 msgid " over the past %ld day."
 msgid_plural " over the past %ld days."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] " за %ld прошедший день."
+msgstr[1] " за %ld прошедших дня."
+msgstr[2] " за %ld прошедших дней."
 
 #, c-format
 msgid " over the past %ld week."
 msgid_plural " over the past %ld weeks."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] " за %ld прошедшую неделю."
+msgstr[1] " за %ld прошедших недели."
+msgstr[2] " за %ld прошедших недель."
 
 #, c-format
 msgid " over the past %ld month."
 msgid_plural " over the past %ld months."
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+msgstr[0] " за %ld прошедший месяц."
+msgstr[1] " за %ld прошедших месяца."
+msgstr[2] " за %ld прошедших месяцев."
 
 #. TRANSLATORS: Please translate the text found in the source
 #. file below.  We don't directly internationalize that text
 #. so that we can tweak it without breaking translations.
 msgid "TOFU detected a binding conflict"
 msgstr ""
+"Обычно с конкретным адресом электронной почты связан только один ключ. "
+"Однако иногда создают новый ключ, например, если ключ слишком стар или "
+"владелец считает, что ключ может быть раскрыт. В противном случае новый ключ "
+"может означать атаку \"человек посередине\"! Перед тем как принять этот "
+"ключ, следует связаться с владельцем и убедиться, что этот новый ключ "
+"правомерен."
 
 #. TRANSLATORS: Two letters (normally the lower and upper case
 #. version of the hotkey) for each of the five choices.  If
 #. there is only one choice in your language, repeat it.
 msgid "gGaAuUrRbB"
-msgstr ""
+msgstr "gGaAuUrRbB"
 
 msgid "(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "
 msgstr ""
+"(G)Хороший, (A)Пока принять, (U)Неясно, (R)Пока отвергнуть, (B)Плохой? "
 
-#, fuzzy, c-format
-#| msgid "error creating a pipe: %s\n"
+#, c-format
 msgid "error changing TOFU policy: %s\n"
-msgstr "оÑ\88ибка Ð¿Ñ\80и Ñ\81оздании ÐºÐ°Ð½Ð°Ð»Ð° ÐºÐ¾Ð½Ð²ÐµÐ¹ÐµÑ\80а: %s\n"
+msgstr "оÑ\88ибка Ð¿Ñ\80и Ñ\81мене Ð¿Ñ\80авила TOFU: %s\n"
 
-#, c-format
-msgid "%d year"
-msgid_plural "%d years"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
+#, fuzzy, c-format
+#| msgid "%d year"
+#| msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
+msgstr[0] "%d год"
+msgstr[1] "%d года"
+msgstr[2] "%d лет"
 
-#, c-format
-msgid "%d month"
-msgid_plural "%d months"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+#, fuzzy, c-format
+#| msgid "%d month"
+#| msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
+msgstr[0] "%d месяц"
+msgstr[1] "%d месяца"
+msgstr[2] "%d месяцев"
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
-#, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+#, fuzzy, c-format
+#| msgid "%d hour"
+#| msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
+msgstr[0] "%d час"
+msgstr[1] "%d часа"
+msgstr[2] "%d часов"
 
-#, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+#, fuzzy, c-format
+#| msgid "%d minute"
+#| msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
+msgstr[0] "%d минута"
+msgstr[1] "%d минуты"
+msgstr[2] "%d минут"
 
-#, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
+#, fuzzy, c-format
+#| msgid "%d second"
+#| msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
+msgstr[0] "%d секунда"
+msgstr[1] "%d секунды"
+msgstr[2] "%d секунд"
 
 #, c-format
 msgid "Have never verified a message signed by key %s!\n"
-msgstr ""
+msgstr "Сообщения, подписанные ключом %s, никогда не проверялись!\n"
 
-#, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
-msgstr ""
+#, fuzzy, c-format
+#| msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
+msgstr "Не удалось собрать статистику для \"%s\" (ключ %s)\n"
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "Проверено 0 сообщений, подписанных \"%s\" (ключ: %s, правило: %s)."
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
-#, c-format
+#, fuzzy, c-format
+#| msgid ""
+#| "Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past "
+#| "%s."
+#| msgid_plural ""
+#| "Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past "
+#| "%s."
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
+"Проверено %ld сообщение, подписанное \"%s\" (ключ: %s, правило: %s) за %s."
 msgstr[1] ""
+"Проверены %ld сообщения, подписанные \"%s\" (ключ: %s, правило: %s) за %s."
 msgstr[2] ""
+"Проверено %ld сообщений, подписанных \"%s\" (ключ: %s, правило: %s) за %s."
 
 #, c-format
 msgid "The most recent message was verified %s ago."
-msgstr ""
+msgstr "Последнее сообщение проверено %s назад."
 
 msgid "Warning: we've have yet to see a message signed by this key!\n"
 msgstr ""
+"Внимание: мы до сих пор не видели ни одного сообщения, подписанного этим "
+"ключом!\n"
 
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
+"Внимание: мы до сих пор видели только одно сообщение, подписанное этим "
+"ключом!\n"
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
-#, fuzzy, c-format
-#| msgid "error sending data: %s\n"
+#, c-format
 msgid "error opening TOFU database: %s\n"
-msgstr "оÑ\88ибка Ð¾Ñ\82пÑ\80авки Ð´Ð°Ð½Ð½Ñ\8bÑ\85: %s\n"
+msgstr "оÑ\88ибка Ð¿Ñ\80и Ð¾Ñ\82кÑ\80Ñ\8bÑ\82ии Ð±Ð°Ð·Ñ\8b Ð´Ð°Ð½Ð½Ñ\8bÑ\85 TOFU: %s\n"
 
 #, c-format
 msgid "'%s' is not a valid long keyID\n"
@@ -5698,21 +5763,19 @@ msgstr "выполните --check-trustdb, пожалуйста\n"
 msgid "checking the trustdb\n"
 msgstr "проверка таблицы доверия\n"
 
-#, fuzzy, c-format
-#| msgid "%lu keys processed so far\n"
+#, c-format
 msgid "%d key processed"
 msgid_plural "%d keys processed"
-msgstr[0] "обработано %lu ключей\n"
-msgstr[1] "обработано %lu ключей\n"
-msgstr[2] "обработано %lu ключей\n"
+msgstr[0] "обработан %d ключ"
+msgstr[1] "обработаны %d ключа"
+msgstr[2] "обработано %d ключей"
 
-#, fuzzy, c-format
-#| msgid "%d keys processed (%d validity counts cleared)\n"
+#, c-format
 msgid " (%d validity count cleared)\n"
 msgid_plural " (%d validity counts cleared)\n"
-msgstr[0] "обработано %d ключей (сброшено %d счетчиков достоверности)\n"
-msgstr[1] "обработано %d ключей (сброшено %d счетчиков достоверности)\n"
-msgstr[2] "обработано %d ключей (сброшено %d счетчиков достоверности)\n"
+msgstr[0] " (сброшен %d счетчик достоверности)\n"
+msgstr[1] " (сброшены %d счетчика достоверности)\n"
+msgstr[2] " (сброшено %d счетчиков достоверности)\n"
 
 msgid "no ultimately trusted keys found\n"
 msgstr "абсолютно доверенных ключей не найдено\n"
@@ -5919,15 +5982,14 @@ msgstr "ошибка получения статуса CHV с карты\n"
 msgid "card is permanently locked!\n"
 msgstr "карта окончательно заблокирована!\n"
 
-#, fuzzy, c-format
-#| msgid "%d Admin PIN attempts remaining before card is permanently locked\n"
+#, c-format
 msgid "%d Admin PIN attempt remaining before card is permanently locked\n"
 msgid_plural ""
 "%d Admin PIN attempts remaining before card is permanently locked\n"
 msgstr[0] ""
-"оÑ\81Ñ\82алоÑ\81Ñ\8c %d Ð¿Ð¾Ð¿Ñ\8bÑ\82ок ввода административного PIN перед блокировкой карты\n"
+"оÑ\81Ñ\82алаÑ\81Ñ\8c %d Ð¿Ð¾Ð¿Ñ\8bÑ\82ка ввода административного PIN перед блокировкой карты\n"
 msgstr[1] ""
-"оÑ\81Ñ\82алоÑ\81Ñ\8c %d Ð¿Ð¾Ð¿Ñ\8bÑ\82ок ввода административного PIN перед блокировкой карты\n"
+"оÑ\81Ñ\82алиÑ\81Ñ\8c %d Ð¿Ð¾Ð¿Ñ\8bÑ\82ки ввода административного PIN перед блокировкой карты\n"
 msgstr[2] ""
 "осталось %d попыток ввода административного PIN перед блокировкой карты\n"
 
@@ -6006,12 +6068,11 @@ msgstr "пожалуйста, подождите, пока будет генер
 msgid "generating key failed\n"
 msgstr "сбой при генерации ключа\n"
 
-#, fuzzy, c-format
-#| msgid "key generation completed (%d seconds)\n"
+#, c-format
 msgid "key generation completed (%d second)\n"
 msgid_plural "key generation completed (%d seconds)\n"
-msgstr[0] "создание ключа завершено (%d секунд)\n"
-msgstr[1] "создание ключа завершено (%d секунд)\n"
+msgstr[0] "создание ключа завершено (%d секунда)\n"
+msgstr[1] "создание ключа завершено (%d секунды)\n"
 msgstr[2] "создание ключа завершено (%d секунд)\n"
 
 msgid "invalid structure of OpenPGP card (DO 0x93)\n"
@@ -8144,10 +8205,8 @@ msgstr "|N|считать фразу-пароль устаревшей чере
 msgid "do not allow the reuse of old passphrases"
 msgstr "не разрешать повторное использование старых фраз-паролей"
 
-#, fuzzy
-#| msgid "|N|set LDAP timeout to N seconds"
 msgid "|N|set the Pinentry timeout to N seconds"
-msgstr "|N|установить время ожидания LDAP N секунд"
+msgstr "|N|установить время ожидания ввода PIN N секунд"
 
 msgid "|NAME|use NAME as default secret key"
 msgstr "|NAME|использовать NAME как основной секретный ключ"
@@ -8439,6 +8498,50 @@ msgstr ""
 "Синтаксис: gpg-check-pattern [параметры] файл_образцов\n"
 "Проверить фразу-пароль, поступающую из stdin, по файлу образцов\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "Вы нашли ошибку в программе ... (%s:%d)\n"
+
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "обнаружен %d ID пользователя без действительной самоподписи\n"
+#~ msgstr[1] "обнаружены %d ID пользователя без действительной самоподписи\n"
+#~ msgstr[2] "обнаружено %d ID пользователя без действительной самоподписи\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "перемещение подписи ключа в нужное место\n"
+
+#~ msgid "%d day"
+#~ msgid_plural "%d days"
+#~ msgstr[0] "%d день"
+#~ msgstr[1] "%d дня"
+#~ msgstr[2] "%d дней"
+
+#  I believe the translation produces an equivalent Russian output
+#  for that code snippet in g10/tofu.c -- ineiev
+#~ msgid "TOFU: few signatures %d message %s"
+#~ msgid_plural "TOFU: few signatures %d messages %s"
+#~ msgstr[0] ""
+#~ "Внимание: если Вы думаете, что видели больше %d сообщения, подписанного "
+#~ "этим ключом, то этот ключ может быть подделкой! Проверьте внимательно, не "
+#~ "внесены ли в адрес электронной почты небольшие изменения (напр., "
+#~ "дополнительные пробелы). В случае подозрений отметьте его как плохой с "
+#~ "помощью '%s'.\n"
+#~ " "
+#~ msgstr[1] ""
+#~ "Внимание: если Вы думаете, что видели больше %d сообщений, подписанных "
+#~ "этим ключом, то этот ключ может быть подделкой! Проверьте внимательно, не "
+#~ "внесены ли в адрес электронной почты небольшие изменения (напр., "
+#~ "дополнительные пробелы). В случае подозрений отметьте его как плохой с "
+#~ "помощью '%s'.\n"
+#~ " "
+#~ msgstr[2] ""
+#~ "Внимание: если Вы думаете, что видели больше %d сообщений, подписанных "
+#~ "этим ключом, то этот ключ может быть подделкой! Проверьте внимательно, не "
+#~ "внесены ли в адрес электронной почты небольшие изменения (напр., "
+#~ "дополнительные пробелы). В случае подозрений отметьте его как плохой с "
+#~ "помощью '%s'.\n"
+#~ " "
+
 #~ msgid "key specification '%s' is ambiguous\n"
 #~ msgstr "спецификация ключа '%s' неоднозначна\n"
 
@@ -8537,11 +8640,6 @@ msgstr ""
 #~ msgstr "не могу открыть '%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "недопустимое значение\n"
-
-#, fuzzy
 #~| msgid "error locking keybox: %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "ошибка блокировки щита с ключами: %s\n"
index 65742d5..3bf2c2b 100644 (file)
--- a/po/sk.po
+++ b/po/sk.po
@@ -382,7 +382,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "chyba pri vytváraní hesla: %s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -482,6 +482,10 @@ msgid "directory '%s' created\n"
 msgstr "%s: adresár vytvorený\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "VAROVANIE: prístupové práva pre %s nie sú nastavené bezpeène \"%s\"\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "databáza dôvery: procedúra read() (n=%d) zlyhala: %s\n"
 
@@ -734,9 +738,9 @@ msgstr "chyba pri vytv
 msgid "error forking process: %s\n"
 msgstr "chyba pri èítaní `%s': %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "aktualizácia zlyhala: %s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -754,6 +758,10 @@ msgstr "chyba pri 
 msgid "error getting exit code of process %d: %s\n"
 msgstr "chyba pri zápise do súboru tajných kµúèov `%s': %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -774,6 +782,10 @@ msgstr "zru
 msgid "problem with the agent\n"
 msgstr "problém s agentom: agent vracia 0x%lx\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problém s agentom: agent vracia 0x%lx\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "nemô¾em vypnú» vytváranie core súborov: %s\n"
@@ -830,6 +842,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "chyba pri vytváraní súboru kµúèov (keyring)`%s': %s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1106,10 +1122,6 @@ msgstr "nespracovan
 msgid "invalid option \"%.50s\"\n"
 msgstr "neplatný parameter pre import\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "nájdená chyba v programe ... (%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "kódovanie do ASCII formátu zlyhalo: %s\n"
@@ -1213,6 +1225,11 @@ msgstr ""
 "neplatný znak (quoted-printable) v ASCII kódovaní - pravdepodobne bol "
 "pou¾itý nesprávny MTA\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "nie je v priamo èitateµnom formáte"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1230,12 +1247,22 @@ msgstr "hodnota mus
 msgid "a notation value must not use any control characters\n"
 msgstr "hodnota nesmie obsahova» ¾iadne kontrolné znaky\n"
 
+#, fuzzy
+msgid "a notation name may not contain an '=' character\n"
+msgstr "hodnota musí obsahova» znak '@'\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"meno mô¾e obsahova» len písmená, èíslice, bodky, podèiarníky alebo medzery a "
+"konèi» s '='\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "VAROVANIE: nájdený neplatný formát zápisu dátumu\n"
 
-msgid "not human readable"
-msgstr "nie je v priamo èitateµnom formáte"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1330,10 +1357,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr ""
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "chyba pri vytváraní súboru kµúèov (keyring)`%s': %s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "chyba pri èítaní `%s': %s\n"
@@ -1670,16 +1693,16 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "vy¾iadaná symetrická ¹ifra %s (%d) nevyhovuje predvoµbám príjemcu\n"
 
 #, c-format
+msgid "%s/%s encrypted for: \"%s\"\n"
+msgstr "%s/%s za¹ifrovaný pre: %s\n"
+
+#, c-format
 msgid "you may not use %s while in %s mode\n"
 msgstr ""
 "pou¾itie %s nie je v móde %s dovolené\n"
 "\n"
 
 #, c-format
-msgid "%s/%s encrypted for: \"%s\"\n"
-msgstr "%s/%s za¹ifrovaný pre: %s\n"
-
-#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s za¹ifrované dáta\n"
 
@@ -1971,7 +1994,7 @@ msgstr "|algo [s
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2989,11 +3012,27 @@ msgid "[self-signature]"
 msgstr "[podpis kµúèa ním samým]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d zlých podpisov\n"
-msgstr[1] "%d zlých podpisov\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "kµúè %08lX: nepodporovaný algoritmus verejného kµúèa\n"
+
+#, fuzzy, c-format
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "%s podpis, hashovací algoritmus %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "Dobrý podpis od \""
+
+#, fuzzy, c-format
+msgid "key %s:\n"
+msgstr "preskoèený `%s': %s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "U¾ívateµské ID \"%s\" je revokované."
+msgstr[1] "U¾ívateµské ID \"%s\" je revokované."
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3003,20 +3042,23 @@ msgstr[0] "1 podpis neoveren
 msgstr[1] "1 podpis neoverený, preto¾e chýba kµúè\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 podpis neoverený, preto¾e vznikla chyba\n"
-msgstr[1] "1 podpis neoverený, preto¾e vznikla chyba\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d zlých podpisov\n"
+msgstr[1] "%d zlých podpisov\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] ""
-"zistených %d identifikátorov u¾ívateµa bez platného podpisu ním samým\n"
-msgstr[1] ""
-"zistených %d identifikátorov u¾ívateµa bez platného podpisu ním samým\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Dobrý podpis od \""
+msgstr[1] "Dobrý podpis od \""
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 #, fuzzy
 msgid ""
@@ -3239,9 +3281,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "chyba pri vytváraní hesla: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "presúvam podpis kµúèa na správne miesto\n"
-
 msgid "save and quit"
 msgstr "ulo¾i» a ukonèi»"
 
@@ -3520,6 +3559,11 @@ msgstr "chyba: neplatn
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "nemô¾em inicializova» databázu dôvery: %s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "neplatná hodnota\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4339,6 +4383,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d zlých podpisov\n"
 msgstr[1] "%d zlých podpisov\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 podpis neoverený, preto¾e vznikla chyba\n"
+msgstr[1] "1 podpis neoverený, preto¾e vznikla chyba\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5559,14 +5610,14 @@ msgstr "z
 msgid "trustdb transaction too large\n"
 msgstr "transakcia s databázou dôvery je príli¹ dlhá\n"
 
-#, fuzzy, c-format
-msgid "can't access '%s': %s\n"
-msgstr "nemô¾em zavrie» `%s': %s\n"
-
 #, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: adresár neexistuje!\n"
 
+#, fuzzy, c-format
+msgid "can't access '%s': %s\n"
+msgstr "nemô¾em zavrie» `%s': %s\n"
+
 #, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: nepodarilo sa vytvori» záznam verzie: %s"
@@ -5712,8 +5763,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5802,39 +5853,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "chyba pri vytváraní hesla: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5843,20 +5896,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|algo [súbory]|vypí¹ hash"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5870,12 +5925,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8766,6 +8828,21 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "nájdená chyba v programe ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] ""
+#~ "zistených %d identifikátorov u¾ívateµa bez platného podpisu ním samým\n"
+#~ msgstr[1] ""
+#~ "zistených %d identifikátorov u¾ívateµa bez platného podpisu ním samým\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "presúvam podpis kµúèa na správne miesto\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "%d podpisov neoverených, preto¾e chýba kµúè\n"
 
@@ -8860,11 +8937,6 @@ msgstr ""
 #~ msgstr "nemô¾em otvori» `%s': %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "neplatná hodnota\n"
-
-#, fuzzy
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "chyba pri èítaní bloku tajného kµúèa `%s': %s\n"
 
index 93aad23..a88dd81 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -428,7 +428,7 @@ msgstr "tillåt klienter att markera nycklar som \"trusted\""
 msgid "allow presetting passphrase"
 msgstr "tillåt förinställning av lösenfras"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -535,6 +535,12 @@ msgstr "%s: kan inte skapa katalog: %s\n"
 msgid "directory '%s' created\n"
 msgstr "katalogen \"%s\" skapades\n"
 
+# Extension är vad? FIXME
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Varning: osäkra rättigheter på %s \"%s\"\n"
+
 #, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
@@ -811,8 +817,9 @@ msgstr "fel när ett rör skapades: %s\n"
 msgid "error forking process: %s\n"
 msgstr "fel vid grening av process: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "misslyckades med att vänta på att processen %d skulle avslutas: %s\n"
 
 #, fuzzy, c-format
@@ -834,6 +841,10 @@ msgstr "fel vid körning av \"%s\": avslutades\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "fel vid hämtning av avslutskod för processen %d: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "misslyckades med att vänta på att processen %d skulle avslutas: %s\n"
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -851,6 +862,11 @@ msgstr "avbruten av användaren\n"
 msgid "problem with the agent\n"
 msgstr "problem med agenten\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "problem med agenten: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "kan inte stänga av minnesutskrifter: %s\n"
@@ -908,6 +924,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "slut på kärna vid allokering av %lu byte"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "fel vid allokering av tillräckligt mycket minne: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: föråldrad flagga \"%s\" - den har ingen effekt\n"
 
@@ -1158,10 +1178,6 @@ msgstr "slut på minne\n"
 msgid "invalid option \"%.50s\"\n"
 msgstr "ogiltig flagga \"%.50s\"\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "du har hittat ett fel i programmet ... (%s:%d)\n"
-
 #, fuzzy, c-format
 #| msgid "conversion from `%s' to `%s' not available\n"
 msgid "conversion from '%s' to '%s' not available\n"
@@ -1272,6 +1288,11 @@ msgstr ""
 "beror sannolikt på att en felaktig e-postserver eller e-postklient har "
 "använts\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "inte läsbart"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1288,12 +1309,23 @@ msgstr "ett notationsnamn får inte innehålla fler än ett \"@\"-tecken\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "ett notationsvärde får inte använda några styrtecken\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "ett notationsnamn får inte innehålla fler än ett \"@\"-tecken\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"ett notationsnamn får endast innehålla skrivbara tecken eller blanksteg, och "
+"sluta med ett \"'=\"\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "VARNING: ogiltig notationsdata hittades\n"
 
-msgid "not human readable"
-msgstr "inte läsbart"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "misslyckades med att förmedla %s-begäran till klient\n"
@@ -1381,10 +1413,6 @@ msgstr "Url för att hämta publik nyckel: "
 msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Fel: URL:en är för lång (gränsen är %d tecken).\n"
 
-#, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "fel vid allokering av tillräckligt mycket minne: %s\n"
-
 #, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
@@ -1731,14 +1759,14 @@ msgstr ""
 "tvinga symmetriskt chiffer med %s (%d) strider mot mottagarinställningarna\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "du kan inte använda %s när du är i %s-läget\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s krypterad för: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "du kan inte använda %s när du är i %s-läget\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s-krypterad data\n"
 
@@ -2024,7 +2052,7 @@ msgstr "skriv ut kontrollsummor"
 msgid "run in server mode"
 msgstr "kör i serverläge"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3074,11 +3102,32 @@ msgid "[self-signature]"
 msgstr "[självsignatur]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d felaktiga signaturer\n"
-msgstr[1] "%d felaktiga signaturer\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "nyckel %s: algoritmen för publika nycklar stöds inte\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "kortet har inte stöd för sammandragsalgoritmen %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Korrekt signatur från"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "hoppade över \"%s\": %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Användaridentitet \"%s\": %d signaturer borttagna\n"
+msgstr[1] "Användaridentitet \"%s\": %d signaturer borttagna\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3088,18 +3137,24 @@ msgstr[0] "1 signatur validerades inte eftersom nyckeln saknades\n"
 msgstr[1] "1 signatur validerades inte eftersom nyckeln saknades\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 signatur validerades inte eftersom ett fel uppstod\n"
-msgstr[1] "1 signatur validerades inte eftersom ett fel uppstod\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d felaktiga signaturer\n"
+msgstr[1] "%d felaktiga signaturer\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d användaridentiteter utan giltiga självsignaturer hittades\n"
-msgstr[1] "%d användaridentiteter utan giltiga självsignaturer hittades\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Korrekt signatur från"
+msgstr[1] "Korrekt signatur från"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3300,9 +3355,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "fel när lösenfras skapades: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "flyttar en nyckelsignatur till den rätta platsen\n"
-
 msgid "save and quit"
 msgstr "spara och avsluta"
 
@@ -3574,6 +3626,11 @@ msgstr "ogiltigt fingeravtryck"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "misslyckades med att få fingeravtrycket\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "ogiltigt värde\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4412,6 +4469,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d felaktiga signaturer\n"
 msgstr[1] "%d felaktiga signaturer\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 signatur validerades inte eftersom ett fel uppstod\n"
+msgstr[1] "1 signatur validerades inte eftersom ett fel uppstod\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5675,16 +5739,16 @@ msgstr "tillitsdatabasposten %lu: skrivning misslyckades (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "tillitsdatabastransaktion för stor\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: katalogen finns inte!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "kan inte komma åt \"%s\": %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: katalogen finns inte!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: misslyckades med att skapa versionspost: %s"
 
@@ -5832,8 +5896,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5926,39 +5990,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "fel när ett rör skapades: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5967,20 +6033,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "skriv ut kontrollsummor"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5994,12 +6063,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -9139,6 +9215,19 @@ msgstr ""
 "Syntax: gpg-check-pattern [flaggor] mönsterfil\n"
 "Kontrollera en lösenfras angiven på standard in mot mönsterfilen\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "du har hittat ett fel i programmet ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d användaridentiteter utan giltiga självsignaturer hittades\n"
+#~ msgstr[1] "%d användaridentiteter utan giltiga självsignaturer hittades\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "flyttar en nyckelsignatur till den rätta platsen\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -9241,11 +9330,6 @@ msgstr ""
 #~ msgstr "misslyckades med att öppna \"%s\": %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "ogiltigt värde\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "fel vid läsning av hemligt nyckelblock \"%s\": %s\n"
index d41d2b2..c9417fb 100644 (file)
--- a/po/tr.po
+++ b/po/tr.po
@@ -397,7 +397,7 @@ msgstr "istemcilerin anahtarları \"güvenilir\" olarak imlemesine izin verilir"
 msgid "allow presetting passphrase"
 msgstr "anahtar parolasının önceden atanmasına izin verilir"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -503,6 +503,11 @@ msgid "directory '%s' created\n"
 msgstr "dizin `%s' oluşturuldu\n"
 
 #, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "UYARI: %s üzerinde izinler güvensiz: \"%s\"\n"
+
+#, fuzzy, c-format
 #| msgid "stat() failed for `%s': %s\n"
 msgid "stat() failed for '%s': %s\n"
 msgstr "%s için stat() başarısız oldu: %s\n"
@@ -777,8 +782,9 @@ msgstr "boru oluşturulurken hata: %s\n"
 msgid "error forking process: %s\n"
 msgstr "süreç çatallanırken hata: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "süreç %d sonlanacak diye beklerken başarısızlık: %s\n"
 
 #, fuzzy, c-format
@@ -800,6 +806,10 @@ msgstr "`%s' çalışırken hata: sonlandırıldı\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "süreç %d çıkış kodu alınırken hata: %s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "süreç %d sonlanacak diye beklerken başarısızlık: %s\n"
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -817,6 +827,11 @@ msgstr "kullanıcı tarafından iptal edildi\n"
 msgid "problem with the agent\n"
 msgstr "aracı ile sorun var\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "aracı ile sorun var: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "\"core\" oluşumu iptal edilemedi: %s\n"
@@ -873,6 +888,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "%lu bayt ayrılırken nüve dışına çıkıldı"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "yeterli bellek ayrılırken hata: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: eskimiş seçenek \"%s\" - artık etkisiz\n"
 
@@ -1129,10 +1148,6 @@ msgstr "nüve dışında\n"
 msgid "invalid option \"%.50s\"\n"
 msgstr "geçersiz seçenekler \"%.50s\"\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "bir yazılım hatası buldunuz ... (%s:%d)\n"
-
 #, fuzzy, c-format
 #| msgid "conversion from `%s' to `%s' not available\n"
 msgid "conversion from '%s' to '%s' not available\n"
@@ -1238,6 +1253,11 @@ msgstr ""
 "zırh içinde uluslararası karakterler - büyük olasılıkla hatalı bir e-posta "
 "sunucusu kullanılmış\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "insan okuyabilir değil"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1254,12 +1274,23 @@ msgstr "bir simgelem isminin birden fazla '@' karakteri içermemesi gerekir\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "bir simgelem değerinde kontrol karakterleri kullanılamaz\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "bir simgelem isminin birden fazla '@' karakteri içermemesi gerekir\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"bir simgelem ismi sadece harfler, rakamlar ve altçizgiler içerebilir ve "
+"sonuna bir '=' gelir.\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "UYARI: geçersiz simgelem verisi bulundu\n"
 
-msgid "not human readable"
-msgstr "insan okuyabilir değil"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1347,10 +1378,6 @@ msgstr "genel anahtarın alınacağı URL: "
 msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Hata: URL çok uzun (sınır: %d karakter).\n"
 
-#, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "yeterli bellek ayrılırken hata: %s\n"
-
 #, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
@@ -1680,14 +1707,14 @@ msgstr ""
 "alıcının tercihleriyle çelişen %s (%d) simetrik şifre kullanımı zorlanıyor\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "%2$s kipindeyken %1$s kullanılamayabilir.\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s \"%s\" için şifrelendi\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "%2$s kipindeyken %1$s kullanılamayabilir.\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s şifreli veri\n"
 
@@ -1970,7 +1997,7 @@ msgstr "ileti özetlerini gösterir"
 msgid "run in server mode"
 msgstr "sunucu kipinde çalışır"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -3007,11 +3034,32 @@ msgid "[self-signature]"
 msgstr "[öz-imza]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d kötü imza\n"
-msgstr[1] "%d kötü imza\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "anahtar %s: genel anahtar algoritması desteklenmiyor\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "kart %s özet algoritmasını desteklemiyor\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Buradaki imzeler iyi:"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "\"%s\" atlandı: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Kullanıcı kimliği \"%s\": %d imza temizlendi\n"
+msgstr[1] "Kullanıcı kimliği \"%s\": %d imza temizlendi\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -3021,18 +3069,24 @@ msgstr[0] "1 imza kayıp bir anahtar yüzünden kontrol edilmedi\n"
 msgstr[1] "1 imza kayıp bir anahtar yüzünden kontrol edilmedi\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 imza bir hata yüzünden kontrol edilmedi\n"
-msgstr[1] "1 imza bir hata yüzünden kontrol edilmedi\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d kötü imza\n"
+msgstr[1] "%d kötü imza\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "%d öz-imzası geçersiz kullanıcı kimliği saptandı\n"
-msgstr[1] "%d öz-imzası geçersiz kullanıcı kimliği saptandı\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Buradaki imzeler iyi:"
+msgstr[1] "Buradaki imzeler iyi:"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3236,9 +3290,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "anahtar parolası oluşturulurken hata: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "bir anahtar imzası doğru yere taşınıyor\n"
-
 msgid "save and quit"
 msgstr "kaydet ve çık"
 
@@ -3521,6 +3572,11 @@ msgstr "parmakizi geçersiz"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "parmakizinin alınması başarısız oldu\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "değer hatalı\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4363,6 +4419,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d kötü imza\n"
 msgstr[1] "%d kötü imza\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 imza bir hata yüzünden kontrol edilmedi\n"
+msgstr[1] "1 imza bir hata yüzünden kontrol edilmedi\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5601,16 +5664,16 @@ msgstr "güvence veritabanı %lu kaydı: yazma başarısız (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "güvence veritabanı işlemi çok uzun\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s: dizin yok!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "'%s' erişilemiyor: %s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s: dizin yok!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: sürüm kaydı oluşturmada başarısız: %s"
 
@@ -5759,8 +5822,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5853,39 +5916,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "boru oluşturulurken hata: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5894,20 +5959,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "ileti özetlerini gösterir"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5921,12 +5989,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -9045,6 +9120,19 @@ msgstr ""
 "Standart girdiden verilen anahtar parolasını örüntü dosyasıyla "
 "karşılaştırır\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "bir yazılım hatası buldunuz ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "%d öz-imzası geçersiz kullanıcı kimliği saptandı\n"
+#~ msgstr[1] "%d öz-imzası geçersiz kullanıcı kimliği saptandı\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "bir anahtar imzası doğru yere taşınıyor\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -9145,11 +9233,6 @@ msgstr ""
 #~ msgstr "`%s' açılamadı: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "değer hatalı\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "gizli anahtar bloğu \"%s\" okunurken hata oluştu: %s\n"
index 269de99..b2d6860 100644 (file)
--- a/po/uk.po
+++ b/po/uk.po
@@ -366,7 +366,9 @@ msgstr "заборонити клієнтам позначати ключі як
 msgid "allow presetting passphrase"
 msgstr "дозволити попереднє встановлення пароля"
 
-msgid "allow caller to override the pinentry"
+#, fuzzy
+#| msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr "дозволити функції виклику перевизначати pinentry"
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -452,6 +454,11 @@ msgstr "не вдалося створити каталог «%s»: %s\n"
 msgid "directory '%s' created\n"
 msgstr "створено каталог «%s»\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "Увага: визначення прав доступу не є безпечним для %s — «%s»\n"
+
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "помилка stat() щодо «%s»: %s\n"
@@ -714,8 +721,9 @@ msgstr "помилка під час спроби створення поток
 msgid "error forking process: %s\n"
 msgstr "помилка під час спроби розгалужування процесу: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "не вдалося дочекатися завершення процесу %d: %s\n"
 
 #, c-format
@@ -736,6 +744,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "помилка під час спроби отримання коду виходу процесу %d: %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "не вдалося дочекатися завершення процесу %d: %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "не вдалося встановити з’єднання з «%s»: %s\n"
 
@@ -751,6 +763,11 @@ msgstr "скасовано користувачем\n"
 msgid "problem with the agent\n"
 msgstr "проблема з агентом\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "проблема з агентом: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "не вдалося вимкнути створення дампів образів у пам’яті: %s\n"
@@ -808,6 +825,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "вихід за межі області під час спроби отримання %lu байтів"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "помилка під час спроби розподілу пам’яті: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: застарілий параметр «%s» — він не працюватиме\n"
 
@@ -1046,10 +1067,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "некоректний параметр «%.50s»\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "ви виявили ваду… (%s:%d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "перетворення з «%s» у «%s» недоступне\n"
 
@@ -1149,6 +1166,11 @@ msgstr ""
 "символи quoted printable у кодуванні ASCII — ймовірно, використано "
 "помилковий MTA\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "незручне для читання"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1165,12 +1187,23 @@ msgstr "назва примітки не повинна містити біль
 msgid "a notation value must not use any control characters\n"
 msgstr "у значенні примітки не повинно міститися керівних символів\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "назва примітки не повинна містити більше за один символ «@»\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+"назва примітки має складатися з друкованих символів або пробілів і "
+"завершуватися символом «=»\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "УВАГА: виявлено некоректні дані примітки\n"
 
-msgid "not human readable"
-msgstr "незручне для читання"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "не вдалося пропустити через проксі запит %s до клієнта\n"
@@ -1258,10 +1291,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "Помилка: адреса є занадто довгою (максимум — %d символів).\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "помилка під час спроби розподілу пам’яті: %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "помилка під час спроби читання «%s»: %s\n"
 
@@ -1583,14 +1612,14 @@ msgstr ""
 "отримувача\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "не можна використовувати %s у режимі %s\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s зашифровано для «%s»\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "не можна використовувати %s у режимі %s\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "Дані, зашифровані за алгоритмом %s\n"
 
@@ -1861,7 +1890,9 @@ msgstr "показати контрольні суми повідомлень"
 msgid "run in server mode"
 msgstr "запустити у режимі сервера"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+#, fuzzy
+#| msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr "встановити правила TOFU для ключа (good, unknown, bad, ask, auto)"
 
 msgid "create ascii armored output"
@@ -2862,12 +2893,33 @@ msgid "[self-signature]"
 msgstr "[самопідпис]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d помилкових підписів\n"
-msgstr[1] "%d помилкових підписів\n"
-msgstr[2] "%d помилкових підписів\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "ключ %s: непідтримуваний алгоритм створення відкритого ключа\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "карткою не підтримується алгоритм контрольних сум %s\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "Правильний підпис від"
+
+#, fuzzy, c-format
+#| msgid "key %s: %s\n"
+msgid "key %s:\n"
+msgstr "ключ %s: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "Ідентифікатор користувача «%s»: вилучено %d підпис\n"
+msgstr[1] "Ідентифікатор користувача «%s»: вилучено %d підпис\n"
+msgstr[2] "Ідентифікатор користувача «%s»: вилучено %d підпис\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2878,23 +2930,26 @@ msgstr[1] "1 підпис не перевірено через те, що нем
 msgstr[2] "1 підпис не перевірено через те, що немає ключа\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "1 підпис не перевірено через помилку\n"
-msgstr[1] "1 підпис не перевірено через помилку\n"
-msgstr[2] "1 підпис не перевірено через помилку\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d помилкових підписів\n"
+msgstr[1] "%d помилкових підписів\n"
+msgstr[2] "%d помилкових підписів\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] ""
-"виявлено %d ідентифікаторів користувачів без коректних самопідписів\n"
-msgstr[1] ""
-"виявлено %d ідентифікаторів користувачів без коректних самопідписів\n"
-msgstr[2] ""
-"виявлено %d ідентифікаторів користувачів без коректних самопідписів\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "Правильний підпис від"
+msgstr[1] "Правильний підпис від"
+msgstr[2] "Правильний підпис від"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3093,9 +3148,6 @@ msgstr ""
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "ключ %s: помилка під час спроби зміни пароля: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "пересування підпису ключа у належне місце\n"
-
 msgid "save and quit"
 msgstr "зберегти і вийти"
 
@@ -3353,6 +3405,11 @@ msgstr "«%s» не є відбитком\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "«%s» не є основним відбитком\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "некоректне значення\n"
+
 msgid "No matching user IDs."
 msgstr "Немає відповідних ідентифікаторів користувачів."
 
@@ -4160,6 +4217,14 @@ msgstr[1] "%d добрих підписів\n"
 msgstr[2] "%d добрих підписів\n"
 
 #, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "1 підпис не перевірено через помилку\n"
+msgstr[1] "1 підпис не перевірено через помилку\n"
+msgstr[2] "1 підпис не перевірено через помилку\n"
+
+#, fuzzy, c-format
 #| msgid "Warning: %lu key(s) skipped due to their large size\n"
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5398,14 +5463,14 @@ msgid "trustdb transaction too large\n"
 msgstr "занадто велика операція trustdb\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "немає доступу до «%s»: %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: каталогу не існує!\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "немає доступу до «%s»: %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: не вдалося створити запис щодо версії: %s"
 
@@ -5552,8 +5617,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5652,44 +5717,46 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "помилка під час спроби створення каналу: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -5699,20 +5766,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "показати контрольні суми повідомлень"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -5727,12 +5797,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
@@ -8555,6 +8632,23 @@ msgstr ""
 "Синтаксис: gpg-check-pattern [параметри] файл_шаблонів\n"
 "Перевірити пароль, вказаний у stdin, за допомогою файла_шаблонів\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "ви виявили ваду… (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] ""
+#~ "виявлено %d ідентифікаторів користувачів без коректних самопідписів\n"
+#~ msgstr[1] ""
+#~ "виявлено %d ідентифікаторів користувачів без коректних самопідписів\n"
+#~ msgstr[2] ""
+#~ "виявлено %d ідентифікаторів користувачів без коректних самопідписів\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "пересування підпису ключа у належне місце\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -8662,11 +8756,6 @@ msgstr ""
 #~ msgstr "текстовий пароль кешовано з ідентифікатором: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "некоректне значення\n"
-
-#, fuzzy
 #~| msgid "error locking keybox: %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "помилка під час блокування сховища ключів: %s\n"
index c33a05d..3d5f8bc 100644 (file)
@@ -391,7 +391,7 @@ msgstr ""
 msgid "allow presetting passphrase"
 msgstr "生成密码的时候发生错误:%s\n"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -491,6 +491,10 @@ msgid "directory '%s' created\n"
 msgstr "已创建目录‘%s’\n"
 
 #, fuzzy, c-format
+msgid "can't set permissions of '%s': %s\n"
+msgstr "警告:扩展模块‘%s’权限不安全\n"
+
+#, fuzzy, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "fstat(%d) 在 %s 中出错:%s\n"
 
@@ -745,9 +749,9 @@ msgstr "生成密码的时候发生错误:%s\n"
 msgid "error forking process: %s\n"
 msgstr "读取‘%s’时出错:%s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
-msgstr ""
+#, fuzzy, c-format
+msgid "waiting for processes to terminate failed: %s\n"
+msgstr "更新失败:%s\n"
 
 #, fuzzy, c-format
 msgid "error running '%s': probably not installed\n"
@@ -765,6 +769,10 @@ msgstr "读取‘%s’时出错:%s\n"
 msgid "error getting exit code of process %d: %s\n"
 msgstr "取得当前密钥信息时出错:%s\n"
 
+#, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr ""
+
 #, fuzzy, c-format
 #| msgid "can't connect to `%s': %s\n"
 msgid "can't connect to '%s': %s\n"
@@ -784,6 +792,10 @@ msgstr "用户取消\n"
 msgid "problem with the agent\n"
 msgstr "代理程序有问题――正在停用代理程序\n"
 
+#, fuzzy, c-format
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "代理程序有问题――正在停用代理程序\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "无法禁用核心内存转储:%s\n"
@@ -839,6 +851,10 @@ msgstr ""
 msgid "out of core while allocating %lu bytes"
 msgstr ""
 
+#, fuzzy, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "建立钥匙环‘%s’时发生错误:%s\n"
+
 #, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr ""
@@ -1117,10 +1133,6 @@ msgstr "可选"
 msgid "invalid option \"%.50s\"\n"
 msgstr "无效的列表选项\n"
 
-#, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "您找到一个程序缺陷了……(%s:%d)\n"
-
 #, fuzzy, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "将‘%s’重命名为‘%s’时失败:%s\n"
@@ -1220,6 +1232,10 @@ msgid ""
 "quoted printable character in armor - probably a buggy MTA has been used\n"
 msgstr "封装里出现括上的可打印字符――可能是有缺陷的信件传输程序造成的\n"
 
+#, c-format
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr ""
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1234,13 +1250,16 @@ msgstr ""
 msgid "a notation value must not use any control characters\n"
 msgstr ""
 
+msgid "a notation name may not contain an '=' character\n"
+msgstr ""
+
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr ""
+
 #, fuzzy
 msgid "WARNING: invalid notation data found\n"
 msgstr "找不到有效的 OpenPGP 数据。\n"
 
-msgid "not human readable"
-msgstr ""
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr ""
@@ -1329,10 +1348,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "错误:URL 太长(至多 %d 个字符)\n"
 
 #, fuzzy, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "建立钥匙环‘%s’时发生错误:%s\n"
-
-#, fuzzy, c-format
 #| msgid "error reading `%s': %s\n"
 msgid "error reading '%s': %s\n"
 msgstr "读取‘%s’时出错:%s\n"
@@ -1656,14 +1671,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "强行使用的 %s (%d)对称加密算法不在收件者的首选项中\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "您不该将 %s 用于 %s 模式中\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s 已经加密给:“%s”\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "您不该将 %s 用于 %s 模式中\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s 加密过的数据\n"
 
@@ -1943,7 +1958,7 @@ msgstr "|算法 [文件]|使用指定的散列算法打印报文散列值"
 msgid "run in server mode"
 msgstr ""
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2953,11 +2968,30 @@ msgid "[self-signature]"
 msgstr "[自身签名]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d 个损坏的签名\n"
-msgstr[1] "%d 个损坏的签名\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "密钥 %s:不支持的公钥算法\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "卡不支持散列算法 %s\n"
+
+#, fuzzy
+msgid " (reordered signatures follow)"
+msgstr "完好的签名,来自于“%s”"
+
+#, fuzzy, c-format
+#| msgid "skipped \"%s\": %s\n"
+msgid "key %s:\n"
+msgstr "“%s”已跳过:%s\n"
+
+#, fuzzy, c-format
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "密钥 %s:“%s”%d 个签名被清除\n"
+msgstr[1] "密钥 %s:“%s”%d 个签名被清除\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2967,18 +3001,23 @@ msgstr[0] "有 1 份签名因为遗失密钥而未被检查\n"
 msgstr[1] "有 1 份签名因为遗失密钥而未被检查\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "有 1 份签名因为某个错误而未被检查\n"
-msgstr[1] "有 1 份签名因为某个错误而未被检查\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d 个损坏的签名\n"
+msgstr[1] "%d 个损坏的签名\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "检测到 %d 个没有有效自身签名的用户标识\n"
-msgstr[1] "检测到 %d 个没有有效自身签名的用户标识\n"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "完好的签名,来自于“%s”"
+msgstr[1] "完好的签名,来自于“%s”"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3168,9 +3207,6 @@ msgstr "只有占位密钥,或者密钥存储在卡上——没有密码可以
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "生成密码的时候发生错误:%s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "正在把密钥的签名移动到正确的位置去\n"
-
 msgid "save and quit"
 msgstr "保存并离开"
 
@@ -3428,6 +3464,11 @@ msgstr "指纹无效"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "无法存储指纹:%s\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "无效的数值\n"
+
 #, fuzzy
 #| msgid "No such user ID.\n"
 msgid "No matching user IDs."
@@ -4229,6 +4270,13 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d 个损坏的签名\n"
 msgstr[1] "%d 个损坏的签名\n"
 
+#, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "有 1 份签名因为某个错误而未被检查\n"
+msgstr[1] "有 1 份签名因为某个错误而未被检查\n"
+
 #, c-format
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5410,16 +5458,16 @@ msgstr "信任度数据库记录 %lu:write 失败 (n=%d): %s\n"
 msgid "trustdb transaction too large\n"
 msgstr "信任度数据库处理量过大\n"
 
+#, c-format
+msgid "%s: directory does not exist!\n"
+msgstr "%s:目录不存在!\n"
+
 #, fuzzy, c-format
 #| msgid "can't access `%s': %s\n"
 msgid "can't access '%s': %s\n"
 msgstr "无法存取‘%s’:%s\n"
 
 #, c-format
-msgid "%s: directory does not exist!\n"
-msgstr "%s:目录不存在!\n"
-
-#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s:建立版本记录失败:%s"
 
@@ -5564,8 +5612,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5655,39 +5703,41 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "生成密码的时候发生错误:%s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 msgstr[1] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5696,20 +5746,22 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "|算法 [文件]|使用指定的散列算法打印报文散列值"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 msgstr[1] ""
 
@@ -5723,12 +5775,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 msgstr[1] ""
 
@@ -8634,6 +8693,19 @@ msgid ""
 "Check a passphrase given on stdin against the patternfile\n"
 msgstr ""
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "您找到一个程序缺陷了……(%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "检测到 %d 个没有有效自身签名的用户标识\n"
+#~ msgstr[1] "检测到 %d 个没有有效自身签名的用户标识\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "正在把密钥的签名移动到正确的位置去\n"
+
 #~ msgid "%d signatures not checked due to missing keys\n"
 #~ msgstr "有 %d 份签名因为遗失密钥而未被检查\n"
 
@@ -8723,11 +8795,6 @@ msgstr ""
 #~ msgstr "无法打开‘%s’:%s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "无效的数值\n"
-
-#, fuzzy
 #~| msgid "error reading secret keyblock \"%s\": %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "读取私钥区块“%s”时出错:%s\n"
index a0879c1..22aebfa 100644 (file)
@@ -370,7 +370,7 @@ msgstr "不允許用戶端將金鑰標記為 \"已信任\""
 msgid "allow presetting passphrase"
 msgstr "允許預先設定密語"
 
-msgid "allow caller to override the pinentry"
+msgid "disallow caller to override the pinentry"
 msgstr ""
 
 msgid "allow passphrase to be prompted through Emacs"
@@ -456,6 +456,11 @@ msgstr "無法建立目錄 '%s': %s\n"
 msgid "directory '%s' created\n"
 msgstr "目錄 '%s' 已建立\n"
 
+#, fuzzy, c-format
+#| msgid "Warning: unsafe permissions on %s \"%s\"\n"
+msgid "can't set permissions of '%s': %s\n"
+msgstr "警告: %s 的權限 \"%s\" 並不安全\n"
+
 #, c-format
 msgid "stat() failed for '%s': %s\n"
 msgstr "'%s' 的 stat() 失敗: %s\n"
@@ -705,8 +710,9 @@ msgstr "建立管道串流時出錯: %s\n"
 msgid "error forking process: %s\n"
 msgstr "衍生執行程序時出錯: %s\n"
 
-#, c-format
-msgid "waiting for process %d to terminate failed: %s\n"
+#, fuzzy, c-format
+#| msgid "waiting for process %d to terminate failed: %s\n"
+msgid "waiting for processes to terminate failed: %s\n"
 msgstr "等候 %d 處理程序終止時失敗: %s\n"
 
 #, c-format
@@ -726,6 +732,10 @@ msgid "error getting exit code of process %d: %s\n"
 msgstr "取得 %d 執行程序結束碼時出錯: %s\n"
 
 #, c-format
+msgid "waiting for process %d to terminate failed: %s\n"
+msgstr "等候 %d 處理程序終止時失敗: %s\n"
+
+#, c-format
 msgid "can't connect to '%s': %s\n"
 msgstr "無法連接至 '%s': %s\n"
 
@@ -741,6 +751,11 @@ msgstr "由使用者取消\n"
 msgid "problem with the agent\n"
 msgstr "代理程式的問題\n"
 
+#, fuzzy, c-format
+#| msgid "problem with the agent: %s\n"
+msgid "problem with the agent (unexpected response \"%s\")\n"
+msgstr "代理程式的問題: %s\n"
+
 #, c-format
 msgid "can't disable core dumps: %s\n"
 msgstr "無法讓系統停止傾印核心檔: %s\n"
@@ -797,6 +812,10 @@ msgid "out of core while allocating %lu bytes"
 msgstr "配置 %lu 位元組時超出核心"
 
 #, c-format
+msgid "error allocating enough memory: %s\n"
+msgstr "配置足夠的記憶體時出錯: %s\n"
+
+#, c-format
 msgid "%s:%u: obsolete option \"%s\" - it has no effect\n"
 msgstr "%s:%u: 廢棄的 \"%s\" 選項 - 沒有任何影響\n"
 
@@ -1037,10 +1056,6 @@ msgid "invalid option \"%.50s\"\n"
 msgstr "無效的選項 \"%.50s\"\n"
 
 #, c-format
-msgid "you found a bug ... (%s:%d)\n"
-msgstr "你找到一個瑕疵了 ... (%s:%d)\n"
-
-#, c-format
 msgid "conversion from '%s' to '%s' not available\n"
 msgstr "沒有從 '%s' 到 '%s' 之間的轉換可用\n"
 
@@ -1138,6 +1153,11 @@ msgid ""
 "quoted printable character in armor - probably a buggy MTA has been used\n"
 msgstr "封裝裡出現被引號括住的可列印字符 - 可能是有瑕疵的送信程式造成的\n"
 
+#, fuzzy, c-format
+#| msgid "not human readable"
+msgid "[ not human readable (%zu bytes: %s%s) ]"
+msgstr "不是人類能讀得懂的"
+
 msgid ""
 "a notation name must have only printable characters or spaces, and end with "
 "an '='\n"
@@ -1152,12 +1172,21 @@ msgstr "使用者標記名稱不得含有兩個或更多的 '@' 字符\n"
 msgid "a notation value must not use any control characters\n"
 msgstr "標記值一定不能使用任何的控制字符\n"
 
+#, fuzzy
+#| msgid "a notation name must not contain more than one '@' character\n"
+msgid "a notation name may not contain an '=' character\n"
+msgstr "使用者標記名稱不得含有兩個或更多的 '@' 字符\n"
+
+#, fuzzy
+#| msgid ""
+#| "a notation name must have only printable characters or spaces, and end "
+#| "with an '='\n"
+msgid "a notation name must have only printable characters or spaces\n"
+msgstr "標記名稱一定要採用可印出的字符或空白, 並以一個 '=' 來結尾\n"
+
 msgid "WARNING: invalid notation data found\n"
 msgstr "警告: 找到無效的標記資料\n"
 
-msgid "not human readable"
-msgstr "不是人類能讀得懂的"
-
 #, c-format
 msgid "failed to proxy %s inquiry to client\n"
 msgstr "以 %s 代理伺服器查詢用戶端時失敗\n"
@@ -1244,10 +1273,6 @@ msgid "Error: URL too long (limit is %d characters).\n"
 msgstr "錯誤: URL 太長 (上限是 %d 個字符).\n"
 
 #, c-format
-msgid "error allocating enough memory: %s\n"
-msgstr "配置足夠的記憶體時出錯: %s\n"
-
-#, c-format
 msgid "error reading '%s': %s\n"
 msgstr "讀取 '%s' 時出錯: %s\n"
 
@@ -1561,14 +1586,14 @@ msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
 msgstr "強迫使用 %s (%d) 對稱式編密法會違反收件者偏好設定\n"
 
 #, c-format
-msgid "you may not use %s while in %s mode\n"
-msgstr "你不能夠將 %s 用於 %s 模式中\n"
-
-#, c-format
 msgid "%s/%s encrypted for: \"%s\"\n"
 msgstr "%s/%s 已加密給: \"%s\"\n"
 
 #, c-format
+msgid "you may not use %s while in %s mode\n"
+msgstr "你不能夠將 %s 用於 %s 模式中\n"
+
+#, c-format
 msgid "%s encrypted data\n"
 msgstr "%s 已加密的資料\n"
 
@@ -1831,7 +1856,7 @@ msgstr "印出訊息摘要"
 msgid "run in server mode"
 msgstr "以伺服器模式執行"
 
-msgid "|VALUE|set the TOFU policy for a key (good, unknown, bad, ask, auto)"
+msgid "|VALUE|set the TOFU policy for a key"
 msgstr ""
 
 msgid "create ascii armored output"
@@ -2791,10 +2816,31 @@ msgid "[self-signature]"
 msgstr "[自我簽章]"
 
 #, fuzzy, c-format
-#| msgid "%d bad signatures\n"
-msgid "%d bad signature\n"
-msgid_plural "%d bad signatures\n"
-msgstr[0] "%d 份損壞的簽章\n"
+#| msgid "key %s: unsupported public key algorithm\n"
+msgid "can't check signature with unsupported public-key algorithm (%d): %s.\n"
+msgstr "金鑰 %s: 未支援的公鑰演算法\n"
+
+#, fuzzy, c-format
+#| msgid "card does not support digest algorithm %s\n"
+msgid ""
+"can't check signature with unsupported message-digest algorithm %d: %s.\n"
+msgstr "卡片不支援 %s 摘要演算法\n"
+
+#, fuzzy
+#| msgid "Good signature from"
+msgid " (reordered signatures follow)"
+msgstr "完好的簽章來自於"
+
+#, fuzzy, c-format
+#| msgid "key %s: %s\n"
+msgid "key %s:\n"
+msgstr "金鑰 %s: %s\n"
+
+#, fuzzy, c-format
+#| msgid "User ID \"%s\": %d signature removed\n"
+msgid "%d duplicate signature removed\n"
+msgid_plural "%d duplicate signatures removed\n"
+msgstr[0] "使用者 ID \"%s\": 已移除 %d 份簽章\n"
 
 #, fuzzy, c-format
 #| msgid "1 signature not checked due to a missing key\n"
@@ -2803,16 +2849,22 @@ msgid_plural "%d signatures not checked due to missing keys\n"
 msgstr[0] "有 1 份簽章因為遺失金鑰而未被檢查\n"
 
 #, fuzzy, c-format
-#| msgid "1 signature not checked due to an error\n"
-msgid "%d signature not checked due to an error\n"
-msgid_plural "%d signatures not checked due to errors\n"
-msgstr[0] "有 1 份簽章因錯誤而未被檢查\n"
+#| msgid "%d bad signatures\n"
+msgid "%d bad signature\n"
+msgid_plural "%d bad signatures\n"
+msgstr[0] "%d 份損壞的簽章\n"
 
 #, fuzzy, c-format
-#| msgid "%d user IDs without valid self-signatures detected\n"
-msgid "%d user ID without valid self-signature detected\n"
-msgid_plural "%d user IDs without valid self-signatures detected\n"
-msgstr[0] "偵測到 %d 個沒有有效自我簽章的使用者 ID\n"
+#| msgid "Good signature from"
+msgid "%d signature reordered\n"
+msgid_plural "%d signatures reordered\n"
+msgstr[0] "完好的簽章來自於"
+
+#, c-format
+msgid ""
+"Warning: errors found and only checked self-signatures, run '%s' to check "
+"all signatures.\n"
+msgstr ""
 
 msgid ""
 "Please decide how far you trust this user to correctly verify other users' "
@@ -3003,9 +3055,6 @@ msgstr "金鑰祇剩下殘骸或者祇含有卡上金鑰項目 - 沒有可變更
 msgid "key %s: error changing passphrase: %s\n"
 msgstr "金鑰 %s: 變更密語時出錯: %s\n"
 
-msgid "moving a key signature to the correct place\n"
-msgstr "正在把金鑰的簽章搬移到正確的位置去\n"
-
 msgid "save and quit"
 msgstr "儲存並離開"
 
@@ -3252,6 +3301,11 @@ msgstr "\"%s\" 不是指紋\n"
 msgid "\"%s\" is not the primary fingerprint\n"
 msgstr "\"%s\" 不是主要指紋\n"
 
+#, fuzzy, c-format
+#| msgid "invalid value\n"
+msgid "Invalid user ID '%s': %s\n"
+msgstr "無效的數值\n"
+
 msgid "No matching user IDs."
 msgstr "沒有相符的使用者 ID."
 
@@ -4028,6 +4082,12 @@ msgid_plural "%d good signatures\n"
 msgstr[0] "%d 份損壞的簽章\n"
 
 #, fuzzy, c-format
+#| msgid "1 signature not checked due to an error\n"
+msgid "%d signature not checked due to an error\n"
+msgid_plural "%d signatures not checked due to errors\n"
+msgstr[0] "有 1 份簽章因錯誤而未被檢查\n"
+
+#, fuzzy, c-format
 #| msgid "Warning: %lu key(s) skipped due to their large size\n"
 msgid "Warning: %lu key skipped due to its large size\n"
 msgid_plural "Warning: %lu keys skipped due to their large sizes\n"
@@ -5191,14 +5251,14 @@ msgid "trustdb transaction too large\n"
 msgstr "信任資料庫更動量過大\n"
 
 #, c-format
-msgid "can't access '%s': %s\n"
-msgstr "無法存取 '%s': %s\n"
-
-#, c-format
 msgid "%s: directory does not exist!\n"
 msgstr "%s: 目錄不存在!\n"
 
 #, c-format
+msgid "can't access '%s': %s\n"
+msgstr "無法存取 '%s': %s\n"
+
+#, c-format
 msgid "%s: failed to create version record: %s"
 msgstr "%s: 建立版本記錄失敗: %s"
 
@@ -5344,8 +5404,8 @@ msgstr ""
 
 #, c-format
 msgid ""
-"The key %s raised a conflict with this binding (%s).  Since this binding's "
-"policy was 'auto', it was changed to 'ask'."
+"The key with fingerprint %s raised a conflict with the binding %s.  Since "
+"this binding's policy was 'auto', it was changed to 'ask'."
 msgstr ""
 
 #, c-format
@@ -5432,34 +5492,36 @@ msgstr ""
 msgid "error changing TOFU policy: %s\n"
 msgstr "建立管道時出錯: %s\n"
 
+#. TRANSLATORS: The tilde ('~') is used here to indicate a
+#. * non-breakable space
 #, c-format
-msgid "%d year"
-msgid_plural "%d years"
+msgid "%d~year"
+msgid_plural "%d~years"
 msgstr[0] ""
 
 #, c-format
-msgid "%d month"
-msgid_plural "%d months"
+msgid "%d~month"
+msgid_plural "%d~months"
 msgstr[0] ""
 
 #, c-format
-msgid "%d day"
-msgid_plural "%d days"
+msgid "%d~day"
+msgid_plural "%d~days"
 msgstr[0] ""
 
 #, c-format
-msgid "%d hour"
-msgid_plural "%d hours"
+msgid "%d~hour"
+msgid_plural "%d~hours"
 msgstr[0] ""
 
 #, c-format
-msgid "%d minute"
-msgid_plural "%d minutes"
+msgid "%d~minute"
+msgid_plural "%d~minutes"
 msgstr[0] ""
 
 #, c-format
-msgid "%d second"
-msgid_plural "%d seconds"
+msgid "%d~second"
+msgid_plural "%d~seconds"
 msgstr[0] ""
 
 #, c-format
@@ -5467,20 +5529,23 @@ msgid "Have never verified a message signed by key %s!\n"
 msgstr ""
 
 #, c-format
-msgid "Failed to collect signature statistics for \"%s\" (key %s)\n"
+msgid ""
+"Failed to collect signature statistics for \"%s\"\n"
+"(key %s)\n"
 msgstr ""
 
-#, c-format
-msgid "Verified 0 messages signed by \"%s\" (key: %s, policy: %s)."
-msgstr ""
+#, fuzzy, c-format
+#| msgid "print message digests"
+msgid "Verified %ld messages signed by \"%s\"."
+msgstr "印出訊息摘要"
 
-#. TRANSLATORS: The final %s is replaced by a string like
-#. "7 months, 1 day, 5 minutes, 0 seconds".
 #, c-format
 msgid ""
-"Verified %ld message signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld message signed by \"%s\"\n"
+"in the past %s."
 msgid_plural ""
-"Verified %ld messages signed by \"%s\" (key: %s, policy: %s) in the past %s."
+"Verified %ld messages signed by \"%s\"\n"
+"in the past %s."
 msgstr[0] ""
 
 #, c-format
@@ -5493,12 +5558,19 @@ msgstr ""
 msgid "Warning: we've only seen a single message signed by this key!\n"
 msgstr ""
 
-#. TRANSLATORS: translate the below text.  We don't
-#. directly internationalize that text so that we can
-#. tweak it without breaking translations.
 #, c-format
-msgid "TOFU: few signatures %d message %s"
-msgid_plural "TOFU: few signatures %d messages %s"
+msgid ""
+"Warning: if you think you've seen more than %ld message signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
+msgid_plural ""
+"Warning: if you think you've seen more than %ld messages signed by this key, "
+"then this key might be a forgery!  Carefully examine the email address for "
+"small variations.  If the key is suspect, then use\n"
+"  %s\n"
+"to mark it as being bad.\n"
 msgstr[0] ""
 
 #, fuzzy, c-format
@@ -8244,6 +8316,18 @@ msgstr ""
 "語法: gpg-check-pattern [選項] 樣式檔案\n"
 "用樣式檔案來檢查由標準輸入給定的密語\n"
 
+#~ msgid "you found a bug ... (%s:%d)\n"
+#~ msgstr "你找到一個瑕疵了 ... (%s:%d)\n"
+
+#, fuzzy
+#~| msgid "%d user IDs without valid self-signatures detected\n"
+#~ msgid "%d user ID without valid self-signature detected\n"
+#~ msgid_plural "%d user IDs without valid self-signatures detected\n"
+#~ msgstr[0] "偵測到 %d 個沒有有效自我簽章的使用者 ID\n"
+
+#~ msgid "moving a key signature to the correct place\n"
+#~ msgstr "正在把金鑰的簽章搬移到正確的位置去\n"
+
 #, fuzzy
 #~| msgid "option \"%.50s\" is ambiguous\n"
 #~ msgid "key specification '%s' is ambiguous\n"
@@ -8339,11 +8423,6 @@ msgstr ""
 #~ msgstr "開啟 '%s' 失敗: %s\n"
 
 #, fuzzy
-#~| msgid "invalid value\n"
-#~ msgid "invalid value '%s'\n"
-#~ msgstr "無效的數值\n"
-
-#, fuzzy
 #~| msgid "error locking keybox: %s\n"
 #~ msgid "error looking up secret key \"%s\": %s\n"
 #~ msgstr "鎖住金鑰鑰匙盒時出錯: %s\n"
index 80e4c0f..f160244 100644 (file)
@@ -21,7 +21,7 @@ EXTRA_DIST = ChangeLog-2011 scdaemon-w32info.rc
 
 libexec_PROGRAMS = scdaemon
 
-AM_CPPFLAGS = -I$(top_srcdir)/common
+AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBUSB_CPPFLAGS)
 
 include $(top_srcdir)/am/cmacros.am
 
index 7f83f80..985404f 100644 (file)
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <time.h>
+#include <unistd.h>
 #ifdef HAVE_NPTH
 # include <npth.h>
 #endif /*HAVE_NPTH*/
 
-#include <usb.h>
+#include <libusb.h>
 
 #include "scdaemon.h"
 #include "iso7816.h"
@@ -237,7 +238,7 @@ static struct
    structure is used as handle for most functions. */
 struct ccid_driver_s
 {
-  usb_dev_handle *idev;
+  libusb_device_handle *idev;
   char *rid;
   int dev_fd;  /* -1 for USB transport or file descriptor of the
                    transport device. */
@@ -985,7 +986,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
 
 
 static char *
-get_escaped_usb_string (usb_dev_handle *idev, int idx,
+get_escaped_usb_string (libusb_device_handle *idev, int idx,
                         const char *prefix, const char *suffix)
 {
   int rc;
@@ -1005,18 +1006,20 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
   /* First get the list of supported languages and use the first one.
      If we do don't find it we try to use English.  Note that this is
      all in a 2 bute Unicode encoding using little endian. */
-  rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
-                        (USB_DT_STRING << 8), 0,
-                        (char*)buf, sizeof buf, 1000 /* ms timeout */);
+  rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN,
+                                LIBUSB_REQUEST_GET_DESCRIPTOR,
+                                (LIBUSB_DT_STRING << 8), 0,
+                                (char*)buf, sizeof buf, 1000 /* ms timeout */);
   if (rc < 4)
     langid = 0x0409; /* English.  */
   else
     langid = (buf[3] << 8) | buf[2];
 
-  rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
-                        (USB_DT_STRING << 8) + idx, langid,
-                        (char*)buf, sizeof buf, 1000 /* ms timeout */);
-  if (rc < 2 || buf[1] != USB_DT_STRING)
+  rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN,
+                                LIBUSB_REQUEST_GET_DESCRIPTOR,
+                                (LIBUSB_DT_STRING << 8) + idx, langid,
+                                (char*)buf, sizeof buf, 1000 /* ms timeout */);
+  if (rc < 2 || buf[1] != LIBUSB_DT_STRING)
     return NULL; /* Error or not a string. */
   len = buf[0];
   if (len > rc)
@@ -1059,7 +1062,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
    physical reader after a reset.  It returns an allocated and possibly
    percent escaped string or NULL if not enough memory is available. */
 static char *
-make_reader_id (usb_dev_handle *idev,
+make_reader_id (libusb_device_handle *idev,
                 unsigned int vendor, unsigned int product,
                 unsigned char serialno_index)
 {
@@ -1082,7 +1085,7 @@ make_reader_id (usb_dev_handle *idev,
 
 /* Helper to find the endpoint from an interface descriptor.  */
 static int
-find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
+find_endpoint (const struct libusb_interface_descriptor *ifcdesc, int mode)
 {
   int no;
   int want_bulk_in = 0;
@@ -1091,21 +1094,21 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
     want_bulk_in = 0x80;
   for (no=0; no < ifcdesc->bNumEndpoints; no++)
     {
-      struct usb_endpoint_descriptor *ep = ifcdesc->endpoint + no;
-      if (ep->bDescriptorType != USB_DT_ENDPOINT)
+      const struct libusb_endpoint_descriptor *ep = ifcdesc->endpoint + no;
+      if (ep->bDescriptorType != LIBUSB_DT_ENDPOINT)
         ;
       else if (mode == 2
-          && ((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
-              == USB_ENDPOINT_TYPE_INTERRUPT)
-          && (ep->bEndpointAddress & 0x80))
-        return (ep->bEndpointAddress & 0x0f);
-      else if (((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
-                == USB_ENDPOINT_TYPE_BULK)
+               && ((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+                   == LIBUSB_TRANSFER_TYPE_INTERRUPT)
+               && (ep->bEndpointAddress & 0x80))
+        return ep->bEndpointAddress;
+      else if (((ep->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK)
+                == LIBUSB_TRANSFER_TYPE_BULK)
                && (ep->bEndpointAddress & 0x80) == want_bulk_in)
-        return (ep->bEndpointAddress & 0x0f);
+        return ep->bEndpointAddress;
     }
-  /* Should never happen.  */
-  return mode == 2? 0x83 : mode == 1? 0x82 :1;
+
+  return -1;
 }
 
 
@@ -1116,10 +1119,10 @@ static int
 scan_or_find_usb_device (int scan_mode,
                          int *readerno, int *count, char **rid_list,
                          const char *readerid,
-                         struct usb_device *dev,
+                         struct libusb_device *dev,
                          char **r_rid,
-                         struct usb_device **r_dev,
-                         usb_dev_handle **r_idev,
+                         struct libusb_device_descriptor *desc,
+                         libusb_device_handle **r_idev,
                          unsigned char **ifcdesc_extra,
                          size_t *ifcdesc_extra_len,
                          int *interface_number,
@@ -1128,29 +1131,35 @@ scan_or_find_usb_device (int scan_mode,
   int cfg_no;
   int ifc_no;
   int set_no;
-  struct usb_config_descriptor *config;
-  struct usb_interface *interface;
-  struct usb_interface_descriptor *ifcdesc;
+  const struct libusb_interface_descriptor *ifcdesc;
   char *rid;
-  usb_dev_handle *idev;
+  libusb_device_handle *idev;
+  int err;
+
+  err = libusb_get_device_descriptor (dev, desc);
+  if (err < 0)
+    return err;
 
   *r_idev = NULL;
 
-  for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
+  for (cfg_no=0; cfg_no < desc->bNumConfigurations; cfg_no++)
     {
-      config = dev->config + cfg_no;
-      if(!config)
-        continue;
+      struct libusb_config_descriptor *config;
 
-      for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
+      err = libusb_get_config_descriptor (dev, cfg_no, &config);
+      if (err < 0)
         {
-          interface = config->interface + ifc_no;
-          if (!interface)
-            continue;
+          if (err == LIBUSB_ERROR_NO_MEM)
+            return err;
+          continue;
+        }
 
-          for (set_no=0; set_no < interface->num_altsetting; set_no++)
+      for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
+        {
+          for (set_no=0; set_no < config->interface[ifc_no].num_altsetting;
+               set_no++)
             {
-              ifcdesc = (interface->altsetting + set_no);
+              ifcdesc = (config->interface[ifc_no].altsetting + set_no);
               /* The second condition is for older SCM SPR 532 who did
                  not know about the assigned CCID class.  The third
                  condition does the same for a Cherry SmartTerminal
@@ -1161,24 +1170,24 @@ scan_or_find_usb_device (int scan_mode,
                        && ifcdesc->bInterfaceSubClass == 0
                        && ifcdesc->bInterfaceProtocol == 0)
                       || (ifcdesc->bInterfaceClass == 255
-                          && dev->descriptor.idVendor == VENDOR_SCM
-                          && dev->descriptor.idProduct == SCM_SPR532)
+                          && desc->idVendor == VENDOR_SCM
+                          && desc->idProduct == SCM_SPR532)
                       || (ifcdesc->bInterfaceClass == 255
-                          && dev->descriptor.idVendor == VENDOR_CHERRY
-                          && dev->descriptor.idProduct == CHERRY_ST2000)))
+                          && desc->idVendor == VENDOR_CHERRY
+                          && desc->idProduct == CHERRY_ST2000)))
                 {
-                  idev = usb_open (dev);
-                  if (!idev)
+                  err = libusb_open (dev, &idev);
+                  if (err < 0)
                     {
                       DEBUGOUT_1 ("usb_open failed: %s\n",
-                                  strerror (errno));
+                                  libusb_error_name (err));
                       continue; /* with next setting. */
                     }
 
                   rid = make_reader_id (idev,
-                                        dev->descriptor.idVendor,
-                                        dev->descriptor.idProduct,
-                                        dev->descriptor.iSerialNumber);
+                                        desc->idVendor,
+                                        desc->idProduct,
+                                        desc->iSerialNumber);
                   if (rid)
                     {
                       if (scan_mode)
@@ -1219,16 +1228,17 @@ scan_or_find_usb_device (int scan_mode,
                           if (ifcdesc_extra && ifcdesc_extra_len)
                             {
                               *ifcdesc_extra = malloc (ifcdesc
-                                                       ->extralen);
+                                                       ->extra_length);
                               if (!*ifcdesc_extra)
                                 {
-                                  usb_close (idev);
+                                  libusb_close (idev);
                                   free (rid);
+                                  libusb_free_config_descriptor (config);
                                   return 1; /* Out of core. */
                                 }
                               memcpy (*ifcdesc_extra, ifcdesc->extra,
-                                      ifcdesc->extralen);
-                              *ifcdesc_extra_len = ifcdesc->extralen;
+                                      ifcdesc->extra_length);
+                              *ifcdesc_extra_len = ifcdesc->extra_length;
                             }
 
                           if (interface_number)
@@ -1241,8 +1251,6 @@ scan_or_find_usb_device (int scan_mode,
                           if (ep_intr)
                             *ep_intr = find_endpoint (ifcdesc, 2);
 
-                          if (r_dev)
-                            *r_dev = dev;
                           if (r_rid)
                             {
                               *r_rid = rid;
@@ -1252,6 +1260,7 @@ scan_or_find_usb_device (int scan_mode,
                             free (rid);
 
                           *r_idev = idev;
+                          libusb_free_config_descriptor (config);
                           return 1; /* Found requested device. */
                         }
                       else
@@ -1265,12 +1274,15 @@ scan_or_find_usb_device (int scan_mode,
                       free (rid);
                     }
 
-                  usb_close (idev);
+                  libusb_close (idev);
                   idev = NULL;
+                  libusb_free_config_descriptor (config);
                   return 0;
                 }
             }
         }
+
+      libusb_free_config_descriptor (config);
     }
 
   return 0;
@@ -1316,27 +1328,27 @@ scan_or_find_usb_device (int scan_mode,
 static int
 scan_or_find_devices (int readerno, const char *readerid,
                       char **r_rid,
-                      struct usb_device **r_dev,
+                      struct libusb_device_descriptor *r_desc,
                       unsigned char **ifcdesc_extra,
                       size_t *ifcdesc_extra_len,
                       int *interface_number,
                       int *ep_bulk_out, int *ep_bulk_in, int *ep_intr,
-                      usb_dev_handle **r_idev,
+                      libusb_device_handle **r_idev,
                       int *r_fd)
 {
   char *rid_list = NULL;
   int count = 0;
-  struct usb_bus *busses, *bus;
-  struct usb_device *dev = NULL;
-  usb_dev_handle *idev = NULL;
+  libusb_device **dev_list = NULL;
+  libusb_device *dev;
+  libusb_device_handle *idev = NULL;
   int scan_mode = (readerno == -1 && !readerid);
   int i;
+  ssize_t n;
+  struct libusb_device_descriptor desc;
 
   /* Set return values to a default. */
   if (r_rid)
     *r_rid = NULL;
-  if (r_dev)
-    *r_dev = NULL;
   if (ifcdesc_extra)
     *ifcdesc_extra = NULL;
   if (ifcdesc_extra_len)
@@ -1354,42 +1366,38 @@ scan_or_find_devices (int readerno, const char *readerid,
       assert (r_rid);
     }
 
-  usb_find_busses();
-  usb_find_devices();
+  n = libusb_get_device_list (NULL, &dev_list);
 
-#ifdef HAVE_USB_GET_BUSSES
-  busses = usb_get_busses();
-#else
-  busses = usb_busses;
-#endif
-
-  for (bus = busses; bus; bus = bus->next)
+  for (i = 0; i < n; i++)
     {
-      for (dev = bus->devices; dev; dev = dev->next)
+      dev = dev_list[i];
+      if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list,
+                                   readerid,
+                                   dev,
+                                   r_rid,
+                                   &desc,
+                                   &idev,
+                                   ifcdesc_extra,
+                                   ifcdesc_extra_len,
+                                   interface_number,
+                                   ep_bulk_out, ep_bulk_in, ep_intr))
         {
-          if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list,
-                                       readerid,
-                                       dev,
-                                       r_rid,
-                                       r_dev,
-                                       &idev,
-                                       ifcdesc_extra,
-                                       ifcdesc_extra_len,
-                                       interface_number,
-                                       ep_bulk_out, ep_bulk_in, ep_intr))
+          libusb_free_device_list (dev_list, 1);
+          /* Found requested device or out of core. */
+          if (!idev)
             {
-              /* Found requested device or out of core. */
-              if (!idev)
-                {
-                  free (rid_list);
-                  return -1; /* error */
-                }
-              *r_idev = idev;
-              return 0;
+              free (rid_list);
+              return -1; /* error */
             }
+          *r_idev = idev;
+          if (r_desc)
+            memcpy (r_desc, &desc, sizeof (struct libusb_device_descriptor));
+          return 0;
         }
     }
 
+  libusb_free_device_list (dev_list, 1);
+
   /* Now check whether there are any devices with special transport types. */
   for (i=0; transports[i].name; i++)
     {
@@ -1501,7 +1509,7 @@ ccid_get_reader_list (void)
 
   if (!initialized_usb)
     {
-      usb_init ();
+      libusb_init (NULL);
       initialized_usb = 1;
     }
 
@@ -1546,20 +1554,20 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
                   const char **rdrname_p)
 {
   int rc = 0;
-  struct usb_device *dev = NULL;
-  usb_dev_handle *idev = NULL;
+  libusb_device_handle *idev = NULL;
   int dev_fd = -1;
   char *rid = NULL;
   unsigned char *ifcdesc_extra = NULL;
   size_t ifcdesc_extra_len;
   int readerno;
   int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
+  struct libusb_device_descriptor desc;
 
   *handle = NULL;
 
   if (!initialized_usb)
     {
-      usb_init ();
+      libusb_init (NULL);
       initialized_usb = 1;
     }
 
@@ -1581,7 +1589,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
   else
     readerno = 0;  /* Default. */
 
-  if (scan_or_find_devices (readerno, readerid, &rid, &dev,
+  if (scan_or_find_devices (readerno, readerid, &rid, &desc,
                             &ifcdesc_extra, &ifcdesc_extra_len,
                             &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
                             &idev, &dev_fd) )
@@ -1607,9 +1615,9 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
     {
       (*handle)->idev = idev;
       (*handle)->dev_fd = -1;
-      (*handle)->id_vendor = dev->descriptor.idVendor;
-      (*handle)->id_product = dev->descriptor.idProduct;
-      (*handle)->bcd_device = dev->descriptor.bcdDevice;
+      (*handle)->id_vendor = desc.idVendor;
+      (*handle)->id_product = desc.idProduct;
+      (*handle)->bcd_device = desc.bcdDevice;
       (*handle)->ifc_no = ifc_no;
       (*handle)->ep_bulk_out = ep_bulk_out;
       (*handle)->ep_bulk_in = ep_bulk_in;
@@ -1639,8 +1647,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
           goto leave;
         }
 
-      rc = usb_claim_interface (idev, ifc_no);
-      if (rc)
+      rc = libusb_claim_interface (idev, ifc_no);
+      if (rc < 0)
         {
           DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
           rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -1656,7 +1664,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
     {
       free (rid);
       if (idev)
-        usb_close (idev);
+        libusb_close (idev);
       if (dev_fd != -1)
         close (dev_fd);
       free (*handle);
@@ -1697,8 +1705,8 @@ do_close_reader (ccid_driver_t handle)
     }
   if (handle->idev)
     {
-      usb_release_interface (handle->idev, handle->ifc_no);
-      usb_close (handle->idev);
+      libusb_release_interface (handle->idev, handle->ifc_no);
+      libusb_close (handle->idev);
       handle->idev = NULL;
     }
   if (handle->dev_fd != -1)
@@ -1721,8 +1729,7 @@ int
 ccid_shutdown_reader (ccid_driver_t handle)
 {
   int rc = 0;
-  struct usb_device *dev = NULL;
-  usb_dev_handle *idev = NULL;
+  libusb_device_handle *idev = NULL;
   unsigned char *ifcdesc_extra = NULL;
   size_t ifcdesc_extra_len;
   int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
@@ -1732,7 +1739,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
 
   do_close_reader (handle);
 
-  if (scan_or_find_devices (-1, handle->rid, NULL, &dev,
+  if (scan_or_find_devices (-1, handle->rid, NULL, NULL,
                             &ifcdesc_extra, &ifcdesc_extra_len,
                             &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
                             &idev, NULL) || !idev)
@@ -1756,7 +1763,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
           goto leave;
         }
 
-      rc = usb_claim_interface (idev, ifc_no);
+      rc = libusb_claim_interface (idev, ifc_no);
       if (rc)
         {
           DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
@@ -1770,7 +1777,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
   if (rc)
     {
       if (handle->idev)
-        usb_close (handle->idev);
+        libusb_close (handle->idev);
       handle->idev = NULL;
       if (handle->dev_fd != -1)
         close (handle->dev_fd);
@@ -1843,11 +1850,6 @@ writen (int fd, const void *buf, size_t nbytes)
   return 0;
 }
 
-#if defined(ENXIO) && !defined(LIBUSB_PATH_MAX) && defined(__GNU_LIBRARY__)
-#define LIBUSB_ERRNO_NO_SUCH_DEVICE ENXIO       /* libusb-compat */
-#elif defined(ENODEV)
-#define LIBUSB_ERRNO_NO_SUCH_DEVICE ENODEV      /* Original libusb */
-#endif
 
 /* Write a MSG of length MSGLEN to the designated bulk out endpoint.
    Returns 0 on success. */
@@ -1916,35 +1918,23 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
 
   if (handle->idev)
     {
-      rc = usb_bulk_write (handle->idev,
-                           handle->ep_bulk_out,
-                           (char*)msg, msglen,
-                           5000 /* ms timeout */);
-      if (rc == msglen)
+      int transferred;
+
+      rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out,
+                                 (char*)msg, msglen, &transferred,
+                                 5000 /* ms timeout */);
+      if (rc == 0 && transferred == msglen)
         return 0;
-#ifdef LIBUSB_ERRNO_NO_SUCH_DEVICE
-      if (rc == -(LIBUSB_ERRNO_NO_SUCH_DEVICE))
-        {
-          /* The Linux libusb returns a negative error value.  Catch
-             the most important one.  */
-          errno = LIBUSB_ERRNO_NO_SUCH_DEVICE;
-          rc = -1;
-        }
-#endif /*LIBUSB_ERRNO_NO_SUCH_DEVICE*/
 
-      if (rc == -1)
+      if (rc < 0)
         {
-          DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
-#ifdef LIBUSB_ERRNO_NO_SUCH_DEVICE
-          if (errno == LIBUSB_ERRNO_NO_SUCH_DEVICE)
+          DEBUGOUT_1 ("usb_bulk_write error: %s\n", libusb_error_name (rc));
+          if (rc == LIBUSB_ERROR_NO_DEVICE)
             {
               handle->enodev_seen = 1;
               return CCID_DRIVER_ERR_NO_READER;
             }
-#endif /*LIBUSB_ERRNO_NO_SUCH_DEVICE*/
         }
-      else
-        DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
     }
   else
     {
@@ -1972,7 +1962,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
          int no_debug)
 {
   int rc;
-  size_t msglen;
+  int msglen;
   int eagain_retries = 0;
 
   /* Fixme: The next line for the current Valgrind without support
@@ -1981,22 +1971,22 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
  retry:
   if (handle->idev)
     {
-      rc = usb_bulk_read (handle->idev,
-                          handle->ep_bulk_in,
-                          (char*)buffer, length,
-                          timeout);
+      rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
+                                 (char*)buffer, length, &msglen, timeout);
       if (rc < 0)
         {
-          rc = errno;
-          DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (rc));
-          if (rc == EAGAIN && eagain_retries++ < 3)
+          DEBUGOUT_1 ("usb_bulk_read error: %s\n", libusb_error_name (rc));
+          if (rc == LIBUSB_ERROR_NO_DEVICE)
             {
-              my_sleep (1);
-              goto retry;
+              handle->enodev_seen = 1;
+              return CCID_DRIVER_ERR_NO_READER;
             }
+
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
-      *nread = msglen = rc;
+      if (msglen < 0)
+        return CCID_DRIVER_ERR_INV_VALUE;  /* Faulty libusb.  */
+      *nread = msglen;
     }
   else
     {
@@ -2104,7 +2094,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
   int rc;
   char dummybuf[8];
   unsigned char msg[100];
-  size_t msglen;
+  int msglen;
 
   if (!handle->idev)
     {
@@ -2117,17 +2107,17 @@ abort_cmd (ccid_driver_t handle, int seqno)
   /* Send the abort command to the control pipe.  Note that we don't
      need to keep track of sent abort commands because there should
      never be another thread using the same slot concurrently.  */
-  rc = usb_control_msg (handle->idev,
-                        0x21,/* bmRequestType: host-to-device,
-                                class specific, to interface.  */
-                        1,   /* ABORT */
-                        (seqno << 8 | 0 /* slot */),
-                        handle->ifc_no,
-                        dummybuf, 0,
-                        1000 /* ms timeout */);
+  rc = libusb_control_transfer (handle->idev,
+                                0x21,/* bmRequestType: host-to-device,
+                                        class specific, to interface.  */
+                                1,   /* ABORT */
+                                (seqno << 8 | 0 /* slot */),
+                                handle->ifc_no,
+                                dummybuf, 0,
+                                1000 /* ms timeout */);
   if (rc < 0)
     {
-      DEBUGOUT_1 ("usb_control_msg error: %s\n", strerror (errno));
+      DEBUGOUT_1 ("usb_control_msg error: %s\n", libusb_error_name (rc));
       return CCID_DRIVER_ERR_CARD_IO_ERROR;
     }
 
@@ -2137,6 +2127,8 @@ abort_cmd (ccid_driver_t handle, int seqno)
   seqno--;  /* Adjust for next increment.  */
   do
     {
+      int transferred;
+
       seqno++;
       msg[0] = PC_to_RDR_Abort;
       msg[5] = 0; /* slot */
@@ -2147,32 +2139,27 @@ abort_cmd (ccid_driver_t handle, int seqno)
       msglen = 10;
       set_msg_len (msg, 0);
 
-      rc = usb_bulk_write (handle->idev,
-                           handle->ep_bulk_out,
-                           (char*)msg, msglen,
-                           5000 /* ms timeout */);
-      if (rc == msglen)
+      rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out,
+                                 (char*)msg, msglen, &transferred,
+                                 5000 /* ms timeout */);
+      if (rc == 0 && transferred == msglen)
         rc = 0;
-      else if (rc == -1)
+      else if (rc < 0)
         DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n",
-                    strerror (errno));
-      else
-        DEBUGOUT_1 ("usb_bulk_write failed in abort_cmd: %d\n", rc);
+                    libusb_error_name (rc));
 
       if (rc)
         return rc;
 
-      rc = usb_bulk_read (handle->idev,
-                          handle->ep_bulk_in,
-                          (char*)msg, sizeof msg,
-                          5000 /*ms timeout*/);
+      rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
+                                 (char*)msg, sizeof msg, &msglen,
+                                 5000 /*ms timeout*/);
       if (rc < 0)
         {
           DEBUGOUT_1 ("usb_bulk_read error in abort_cmd: %s\n",
-                      strerror (errno));
+                      libusb_error_name (rc));
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
-      msglen = rc;
 
       if (msglen < 10)
         {
@@ -2278,16 +2265,15 @@ ccid_poll (ccid_driver_t handle)
 {
   int rc;
   unsigned char msg[10];
-  size_t msglen;
+  int msglen;
   int i, j;
 
   if (handle->idev)
     {
-      rc = usb_bulk_read (handle->idev,
-                          handle->ep_intr,
-                          (char*)msg, sizeof msg,
-                          0 /* ms timeout */ );
-      if (rc < 0 && errno == ETIMEDOUT)
+      rc = libusb_bulk_transfer (handle->idev, handle->ep_intr,
+                                 (char*)msg, sizeof msg, &msglen,
+                                 0 /* ms timeout */ );
+      if (rc == LIBUSB_ERROR_TIMEOUT)
         return 0;
     }
   else
@@ -2295,13 +2281,10 @@ ccid_poll (ccid_driver_t handle)
 
   if (rc < 0)
     {
-      DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
+      DEBUGOUT_1 ("usb_intr_read error: %s\n", libusb_error_name (rc));
       return CCID_DRIVER_ERR_CARD_IO_ERROR;
     }
 
-  msglen = rc;
-  rc = 0;
-
   if (msglen < 1)
     {
       DEBUGOUT ("intr-in msg too short\n");
@@ -2365,8 +2348,8 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
       if (!retries)
         {
           DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n");
-          usb_clear_halt (handle->idev, handle->ep_bulk_in);
-          usb_clear_halt (handle->idev, handle->ep_bulk_out);
+          libusb_clear_halt (handle->idev, handle->ep_bulk_in);
+          libusb_clear_halt (handle->idev, handle->ep_bulk_out);
         }
       else
           DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n");
@@ -3112,7 +3095,7 @@ ccid_transceive (ccid_driver_t handle,
 
       if (tpdulen < 4)
         {
-          usb_clear_halt (handle->idev, handle->ep_bulk_in);
+          libusb_clear_halt (handle->idev, handle->ep_bulk_in);
           return CCID_DRIVER_ERR_ABORTED;
         }
 
@@ -3546,7 +3529,7 @@ ccid_transceive_secure (ccid_driver_t handle,
 
   if (tpdulen < 4)
     {
-      usb_clear_halt (handle->idev, handle->ep_bulk_in);
+      libusb_clear_halt (handle->idev, handle->ep_bulk_in);
       return CCID_DRIVER_ERR_ABORTED;
     }
   if (debug_level > 1)
index ba830de..72ff132 100644 (file)
@@ -42,6 +42,7 @@
 #include "ccid-driver.h"
 #endif
 #include "asshelp.h"
+#include "server-help.h"
 
 /* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
 #define MAXLEN_PIN 100
@@ -219,53 +220,6 @@ update_card_removed (int vrdr, int value)
 }
 
 
-/* Check whether the option NAME appears in LINE.  Returns 1 or 0. */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-/* Same as has_option but does only test for the name of the option
-   and ignores an argument, i.e. with NAME being "--hash" it would
-   return a pointer for "--hash" as well as for "--hash=foo".  If
-   there is no such option NULL is returned.  The pointer returned
-   points right behind the option name, this may be an equal sign, Nul
-   or a space.  */
-static const char *
-has_option_name (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  return (s && (s == line || spacep (s-1))
-          && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL;
-}
-
-
-/* Skip over options.  It is assumed that leading spaces have been
-   removed (this is the case for lines passed to a handler from
-   assuan).  Blanks after the options are also removed. */
-static char *
-skip_options (char *line)
-{
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return line;
-}
-
-
-
 /* Convert the STRING into a newly allocated buffer while translating
    the hex numbers.  Stops at the first invalid character.  Blanks and
    colons are allowed to separate the hex digits.  Returns NULL on
@@ -515,8 +469,8 @@ open_card (ctrl_t ctrl, const char *apptype)
           else if (sw == SW_HOST_CARD_INACTIVE)
             err = gpg_error (GPG_ERR_CARD_RESET);
           else
-            err = gpg_error (GPG_ERR_CARD);
-       }
+            err = gpg_error (GPG_ERR_ENODEV);
+        }
       else
         err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
     }
index 43e3598..11f86e9 100644 (file)
@@ -54,7 +54,8 @@ gpgsm_SOURCES = \
        certreqgen.c \
        certreqgen-ui.c \
        minip12.c minip12.h \
-       qualified.c
+       qualified.c \
+       passphrase.c passphrase.h
 
 
 common_libs = ../kbx/libkeybox509.a $(libcommon)
index c7d4c5a..8c1c727 100644 (file)
@@ -37,6 +37,8 @@
 #include "asshelp.h"
 #include "keydb.h" /* fixme: Move this to import.c */
 #include "membuf.h"
+#include "shareddefs.h"
+#include "passphrase.h"
 
 
 static assuan_context_t agent_ctx = NULL;
@@ -74,6 +76,11 @@ struct import_key_parm_s
   size_t keylen;
 };
 
+struct default_inq_parm_s
+{
+  ctrl_t ctrl;
+  assuan_context_t ctx;
+};
 
 \f
 /* Print a warning if the server's version number is less than our
@@ -151,6 +158,20 @@ start_agent (ctrl_t ctrl)
              agents.  */
           assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
                            NULL, NULL, NULL, NULL, NULL, NULL);
+
+          /* Pass on the pinentry mode.  */
+          if (opt.pinentry_mode)
+            {
+              char *tmp = xasprintf ("OPTION pinentry-mode=%s",
+                                     str_pinentry_mode (opt.pinentry_mode));
+              rc = assuan_transact (agent_ctx, tmp,
+                               NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (tmp);
+              if (rc)
+                log_error ("setting pinentry mode '%s' failed: %s\n",
+                           str_pinentry_mode (opt.pinentry_mode),
+                           gpg_strerror (rc));
+            }
         }
     }
 
@@ -163,14 +184,14 @@ start_agent (ctrl_t ctrl)
   return rc;
 }
 
-
 /* This is the default inquiry callback.  It mainly handles the
    Pinentry notifications.  */
 static gpg_error_t
 default_inq_cb (void *opaque, const char *line)
 {
-  gpg_error_t err;
-  ctrl_t ctrl = opaque;
+  gpg_error_t err = 0;
+  struct default_inq_parm_s *parm = opaque;
+  ctrl_t ctrl = parm->ctrl;
 
   if (has_leading_keyword (line, "PINENTRY_LAUNCHED"))
     {
@@ -180,10 +201,18 @@ default_inq_cb (void *opaque, const char *line)
                    "PINENTRY_LAUNCHED");
       /* We do not pass errors to avoid breaking other code.  */
     }
+  else if ((has_leading_keyword (line, "PASSPHRASE")
+            || has_leading_keyword (line, "NEW_PASSPHRASE"))
+           && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK
+           && have_static_passphrase ())
+    {
+      const char *s = get_static_passphrase ();
+      err = assuan_send_data (parm->ctx, s, strlen (s));
+    }
   else
     log_error ("ignoring gpg-agent inquiry '%s'\n", line);
 
-  return 0;
+  return err;
 }
 
 
@@ -200,6 +229,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
   char *p, line[ASSUAN_LINELENGTH];
   membuf_t data;
   size_t len;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_buf = NULL;
   rc = start_agent (ctrl);
@@ -239,7 +269,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, "PKSIGN",
-                        put_membuf_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -272,6 +302,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   const char *hashopt;
   unsigned char *sigbuf;
   size_t sigbuflen;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   (void)desc;
 
@@ -306,7 +337,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
   line[DIM(line)-1] = 0;
   rc = assuan_transact (agent_ctx, line,
-                        put_membuf_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -356,7 +387,10 @@ inq_ciphertext_cb (void *opaque, const char *line)
       assuan_end_confidential (parm->ctx);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      rc = default_inq_cb (&inq_parm, line);
+    }
 
   return rc;
 }
@@ -476,7 +510,10 @@ inq_genkey_parms (void *opaque, const char *line)
       rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      rc = default_inq_cb (&inq_parm, line);
+    }
 
   return rc;
 }
@@ -544,6 +581,7 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_pubkey = NULL;
   rc = start_agent (ctrl);
@@ -561,7 +599,7 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, line,
                         put_membuf_cb, &data,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -631,6 +669,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 {
   int rc;
   char *serialno = NULL;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_serialno = NULL;
   rc = start_agent (ctrl);
@@ -639,7 +678,7 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 
   rc = assuan_transact (agent_ctx, "SCD SERIALNO",
                         NULL, NULL,
-                        default_inq_cb, ctrl,
+                        default_inq_cb, &inq_parm,
                         scd_serialno_status_cb, &serialno);
   if (!rc && !serialno)
     rc = gpg_error (GPG_ERR_INTERNAL);
@@ -700,6 +739,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
 {
   int rc;
   strlist_t list = NULL;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_list = NULL;
   rc = start_agent (ctrl);
@@ -708,7 +748,7 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
 
   rc = assuan_transact (agent_ctx, "SCD LEARN --force",
                         NULL, NULL,
-                        default_inq_cb, ctrl,
+                        default_inq_cb, &inq_parm,
                         scd_keypairinfo_status_cb, &list);
   if (!rc && !list)
     rc = gpg_error (GPG_ERR_NO_DATA);
@@ -797,6 +837,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
   int rc;
   char *fpr, *dn, *dnfmt;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   rc = start_agent (ctrl);
   if (rc)
@@ -825,7 +866,7 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
   xfree (fpr);
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -983,6 +1024,7 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   rc = start_agent (ctrl);
   if (rc)
@@ -1005,7 +1047,7 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
   line[DIM(line)-1] = 0;
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -1018,6 +1060,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   rc = start_agent (ctrl);
   if (rc)
@@ -1027,7 +1070,7 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
   line[DIM(line)-1] = 0;
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -1128,6 +1171,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
   char line[ASSUAN_LINELENGTH];
   char *arg4 = NULL;
   membuf_t data;
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_passphrase = NULL;
 
@@ -1146,7 +1190,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, NULL, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
 
   if (err)
     xfree (get_membuf (&data, NULL));
@@ -1174,6 +1218,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_kek = NULL;
   err = start_agent (ctrl);
@@ -1186,7 +1231,7 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
@@ -1217,7 +1262,10 @@ inq_import_key_parms (void *opaque, const char *line)
       assuan_end_confidential (parm->ctx);
     }
   else
-    err = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      err = default_inq_cb (&inq_parm, line);
+    }
 
   return err;
 }
@@ -1259,6 +1307,7 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm = { ctrl, agent_ctx };
 
   *r_result = NULL;
 
@@ -1280,7 +1329,7 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
   init_membuf_secure (&data, 1024);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
index a0b7038..fc6d1c7 100644 (file)
@@ -32,6 +32,8 @@
 #include <gcrypt.h>
 #include <assuan.h> /* malloc hooks */
 
+#include "passphrase.h"
+#include "../common/shareddefs.h"
 #include "../kbx/keybox.h" /* malloc hooks */
 #include "i18n.h"
 #include "keydb.h"
@@ -99,7 +101,6 @@ enum cmd_and_opt_values {
   oDebugAllowCoreDump,
   oDebugNoChainValidation,
   oDebugIgnoreExpiration,
-  oFixedPassphrase,
   oLogFile,
   oNoLogFile,
   oAuditLog,
@@ -121,6 +122,8 @@ enum cmd_and_opt_values {
   oProtectToolProgram,
   oFakedSystemTime,
 
+  oPassphraseFD,
+  oPinentryMode,
 
   oAssumeArmor,
   oAssumeBase64,
@@ -244,6 +247,9 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oP12Charset, "p12-charset", "@"),
 
+  ARGPARSE_s_i (oPassphraseFD,    "passphrase-fd", "@"),
+  ARGPARSE_s_s (oPinentryMode,    "pinentry-mode", "@"),
+
   ARGPARSE_s_n (oAssumeArmor, "assume-armor",
                 N_("assume input is in PEM format")),
   ARGPARSE_s_n (oAssumeBase64, "assume-base64",
@@ -332,7 +338,6 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
   ARGPARSE_s_n (oDebugNoChainValidation, "debug-no-chain-validation", "@"),
   ARGPARSE_s_n (oDebugIgnoreExpiration,  "debug-ignore-expiration", "@"),
-  ARGPARSE_s_s (oFixedPassphrase, "fixed-passphrase", "@"),
 
   ARGPARSE_s_i (oStatusFD, "status-fd",
                 N_("|FD|write status info to this FD")),
@@ -912,7 +917,7 @@ main ( int argc, char **argv)
   estream_t auditfp = NULL;
   estream_t htmlauditfp = NULL;
   struct assuan_malloc_hooks malloc_hooks;
-
+  int pwfd = -1;
   /*mtrace();*/
 
   early_system_init ();
@@ -1152,6 +1157,16 @@ main ( int argc, char **argv)
           opt.p12_charset = pargs.r.ret_str;
           break;
 
+        case oPassphraseFD:
+         pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
+         break;
+
+        case oPinentryMode:
+         opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str);
+         if (opt.pinentry_mode == -1)
+            log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
+         break;
+
           /* Input encoding selection.  */
         case oAssumeArmor:
           ctrl.autodetect_encoding = 0;
@@ -1264,7 +1279,6 @@ main ( int argc, char **argv)
           break;
         case oDebugNoChainValidation: opt.no_chain_validation = 1; break;
         case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break;
-        case oFixedPassphrase: opt.fixed_passphrase = pargs.r.ret_str; break;
 
         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
@@ -1461,6 +1475,9 @@ main ( int argc, char **argv)
   if (log_get_errorcount(0))
     gpgsm_exit(2);
 
+  if (pwfd != -1)      /* Read the passphrase now.  */
+    read_passphrase_from_fd (pwfd);
+
   /* Now that we have the options parsed we need to update the default
      control structure.  */
   gpgsm_init_default_ctrl (&ctrl);
index 30e4fb3..5aad4b1 100644 (file)
@@ -84,6 +84,8 @@ struct
 
   int with_keygrip; /* Option --with-keygrip active.  */
 
+  int pinentry_mode;
+
   int armor;        /* force base64 armoring (see also ctrl.with_base64) */
   int no_armor;     /* don't try to figure out whether data is base64 armored*/
 
@@ -125,7 +127,6 @@ struct
   int no_policy_check;      /* ignore certificate policies */
   int no_chain_validation;  /* Bypass all cert chain validity tests */
   int ignore_expiration;    /* Ignore the notAfter validity checks. */
-  char *fixed_passphrase;   /* Passphrase used by regression tests.  */
 
   int auto_issuer_key_retrieve; /* try to retrieve a missing issuer key. */
 
index f5705cb..495eb49 100644 (file)
@@ -213,6 +213,18 @@ maybe_create_keybox (char *filename, int force, int *r_created)
     }
   umask (oldmask);
 
+  /* Make sure that at least one record is in a new keybox file, so
+     that the detection magic for OpenPGP keyboxes works the next time
+     it is used.  */
+  rc = _keybox_write_header_blob (fp, 0);
+  if (rc)
+    {
+      fclose (fp);
+      log_error (_("error creating keybox '%s': %s\n"),
+                 filename, gpg_strerror (rc));
+      goto leave;
+    }
+
   if (!opt.quiet)
     log_info (_("keybox '%s' created\n"), filename);
   if (r_created)
diff --git a/sm/passphrase.c b/sm/passphrase.c
new file mode 100644 (file)
index 0000000..6ad2b0a
--- /dev/null
@@ -0,0 +1,90 @@
+/* passphrase.c -  Get a passphrase
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+ *               2005, 2006, 2007, 2009, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <unistd.h>
+
+#include "passphrase.h"
+#include "gpgsm.h"
+#include "../common/shareddefs.h"
+#include "../common/ttyio.h"
+
+static char *fd_passwd = NULL;
+
+int
+have_static_passphrase ()
+{
+  return (!!fd_passwd
+          && (opt.batch || opt.pinentry_mode == PINENTRY_MODE_LOOPBACK));
+}
+
+/* Return a static passphrase.  The returned value is only valid as
+   long as no other passphrase related function is called.  NULL may
+   be returned if no passphrase has been set; better use
+   have_static_passphrase first.  */
+const char *
+get_static_passphrase (void)
+{
+  return fd_passwd;
+}
+
+void
+read_passphrase_from_fd (int fd)
+{
+  int i, len;
+  char *pw;
+
+  if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
+    { /* Not used but we have to do a dummy read, so that it won't end
+         up at the begin of the message if the quite usual trick to
+         prepend the passphtrase to the message is used. */
+      char buf[1];
+
+      while (!(read (fd, buf, 1) != 1 || *buf == '\n'))
+        ;
+      *buf = 0;
+      return;
+    }
+
+  for (pw = NULL, i = len = 100; ; i++)
+    {
+      if (i >= len-1)
+        {
+          char *pw2 = pw;
+          len += 100;
+          pw = xmalloc_secure (len);
+          if (pw2)
+            {
+              memcpy (pw, pw2, i);
+              xfree (pw2);
+            }
+          else
+            i = 0;
+       }
+      if (read (fd, pw+i, 1) != 1 || pw[i] == '\n')
+        break;
+    }
+  pw[i] = 0;
+  if (!opt.batch && opt.pinentry_mode != PINENTRY_MODE_LOOPBACK)
+    tty_printf("\b\b\b   \n" );
+
+  xfree (fd_passwd);
+  fd_passwd = pw;
+}
diff --git a/sm/passphrase.h b/sm/passphrase.h
new file mode 100644 (file)
index 0000000..3401a0b
--- /dev/null
@@ -0,0 +1,27 @@
+/* passphrase.h -  Get a passphrase
+ * Copyright (C) 2016 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef        GPGSM_PASSPHRASE_H
+#define        GPGSM_PASSPHRASE_H
+
+int have_static_passphrase (void);
+const char *get_static_passphrase (void);
+void read_passphrase_from_fd (int fd);
+
+#endif /* GPGSM_PASSPHRASE_H */
index e21c6a4..a43ff34 100644 (file)
@@ -30,6 +30,7 @@
 #include "gpgsm.h"
 #include <assuan.h>
 #include "sysutils.h"
+#include "server-help.h"
 
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
@@ -95,38 +96,6 @@ strcpy_escaped_plus (char *d, const char *s)
 }
 
 
-/* Skip over options.
-   Blanks after the options are also removed. */
-static char *
-skip_options (const char *line)
-{
-  while (spacep (line))
-    line++;
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return (char*)line;
-}
-
-
-/* Check whether the option NAME appears in LINE */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return 0;
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-
 /* A write handler used by es_fopencookie to write assuan data
    lines.  */
 static gpgrt_ssize_t
diff --git a/tests/migrations/Makefile.am b/tests/migrations/Makefile.am
new file mode 100644 (file)
index 0000000..0f581c2
--- /dev/null
@@ -0,0 +1,57 @@
+# Makefile.am - For tests/openpgp
+# Copyright (C) 2016 g10 Code GmbH
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+# Process this file with automake to create Makefile.in
+
+
+# Programs required before we can run these tests.
+required_pgms = ../../g10/gpg$(EXEEXT) ../../agent/gpg-agent$(EXEEXT)
+
+AM_CPPFLAGS = -I$(top_srcdir)/common
+include $(top_srcdir)/am/cmacros.am
+
+AM_CFLAGS =
+
+TESTS_ENVIRONMENT = GPG_AGENT_INFO= LC_ALL=C
+
+TESTS = from-classic.test \
+       extended-private-key-format.test
+
+TEST_FILES = from-classic.gpghome/pubring.gpg.asc \
+            from-classic.gpghome/secring.gpg.asc \
+            from-classic.gpghome/trustdb.gpg.asc \
+            extended-private-key-format.gpghome/trustdb.gpg.asc \
+            extended-private-key-format.gpghome/pubring.kbx.asc \
+            extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc \
+            extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc \
+            extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc
+
+EXTRA_DIST = $(TESTS) $(TEST_FILES)
+
+CLEANFILES = prepared.stamp x y yy z out err  $(data_files) \
+            plain-1 plain-2 plain-3 trustdb.gpg *.lock .\#lk* \
+            *.test.log gpg_dearmor gpg.conf gpg-agent.conf S.gpg-agent \
+            pubring.gpg pubring.gpg~ pubring.kbx pubring.kbx~ \
+            secring.gpg pubring.pkr secring.skr \
+            gnupg-test.stop random_seed gpg-agent.log tofu.db
+
+clean-local:
+       -rm -rf from-classic.gpghome/*.gpg
+
+# We need to depend on a couple of programs so that the tests don't
+# start before all programs are built.
+all-local: $(required_pgms)
diff --git a/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc b/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/13FDB8809B17C5547779F9D205C45F47CE0217CE.key.asc
new file mode 100644 (file)
index 0000000..d9192b1
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+S2V5OiAocHJpdmF0ZS1rZXkgKHJzYSAobiAjMDBBODUyNTY3NkVDRTRENzVGRTZE
+MDA3M0YyQkY5OUE2RjQ5MzNDRUJERDQKIDUyOEFGNTZFNEM2MUUyRjczMTI0NzM5
+MzY0NUREQUY1OEVBREQ1NjUyOUMyNTM5Nzc4MjM2NDYzREYyRDQ1ODUyMEU4MEUK
+IDM0QzA1ODI0MkIzRkY4OEREMzlBODgzQjQ3NUI2NkNFQUFCQkM5OTg5RkYwMUZG
+RTczNzY2MEU5QjYxQkI5REM5MTIwNUQKIDQyOEZGRkU4RjY3NUZBRUY2MTM2NThD
+NzJEQTZENzUwQzBFQkM0MEFGNjIzRDIwNjY5MkM4MjUxNEM0MDREODgyNUFCNzAK
+IDEwMDEjKShlICMwMTAxIykoZCAjMDBCQ0EwMDE0NDg1RkI3NkQ1MEU5QjZDQkE1
+NzIxQUMxMTIxMzkwRjg2MDhENDA4NEIKIEQwNDVBODc2REYzODEwRjExNEJDMkQ2
+OEVCNTUyRTYxQjAxRURCQzI0ODFGMDhDODI4MzJFMDBFMjc5RDY3QTg1MzA1NUQK
+IENBRTVDMjM1Njg1MUNCRTM2RDYxMEM0RDJBQjQzRkE2NTU5ODVDNDQ2OUQxRDkx
+MUUxQUZEODE3RUFBNUZFRTBGRjI2NTcKIDRDMzU5RTE3NTI4NzA1MjE5NDUzQjUx
+QUVDMTBEQkY3NTYyQjA2MUQ1QzY2QzM1QkIzRjlGMEIyMjJCOUQxOTZCOSMpKHAK
+ICAjMDBDMzNDNTgwNjM5OTZCRDU5NzUyQUFCREZEQUNEQUE3QjRCNjZBQTE3NTRF
+RTBEODlCNzc5NEYwREU4RkY3MjRDNTQKIDlGRjExMkEzMzI5MkJCOUQ3QkNFRTc5
+NEYwODAyNEMzRTU1RkQ4MjMzRjUwNzlFRDQ5OTFDNERGMjYxOEQ5IykocSAjMDAK
+IERDQjU5NDVGMDBGMUFGNDM4QkQ0QzMxMUI4QkFDQTNEOURCMEFEMTY1MTk4NjUz
+NDIwMzBGMURGMzA1N0U1NTMyQzQ3RjUKIDhEMzMwM0NCQTNDOEEyOTgxNEY2MTdC
+N0IzREVFOThGQUFBQUVFODExQjQ5OEZBQUYyMTc3Qjc3NjkjKSh1ICMyOUZCMkQK
+IEY2OUIyMzVBNDlBOTA2QjEwRUY3RDhGODFBQUVBOEFEODFFN0NEREUxRjRBNzlD
+RTI0NEJGOEZDRTZERDVFQjE4MTFCMEIKIEQ1RTUxNjVCOTU3MDg1MDM2OTAxREQy
+ODVBNjI4QzI5N0E3ODJEQTgxNTczQTQzRDFDMDkjKSkpCg==
+=laTh
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc b/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/343D8AF79796EE107D645A2787A9D9252F924E6F.key.asc
new file mode 100644 (file)
index 0000000..1eede1c
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+KDExOnByaXZhdGUta2V5KDM6ZHNhKDE6cDEyOToArHGqWD0rP0Nn/c3nYELTD4m1
+gqR7f2+l1ZUMdHcweYwn/fVjaJKmbR+9GzeHWP398FWYs5mCU1DIfrZLF0nJnAJ6
+WRnN9TL+oub1BqqLvCmDSngRuZZ2gUX8DVmD8xTsPnDnG74QDUnvtnpDIAs32sg5
+dnusstrriXD8xXgt0g8pKDE6cTIxOgC449htJbbp5rkJHvBDs4YxEIkk5ykoMTpn
+MTI4Ol+ITxpSMOT5R67Bu4XWoYU7nVeYURpb6LJ8LK2CV7ygECwFdRFdukiGFB+a
+TP8nF6xtuXalaBuerkKp4QXVKqOIkp7MWN2TAOOg9eERHPT//whryf49meNYMPLv
+KAe60udHY76Glm+Zso+24WnEwXX2od1PHVV3CItWRb7YmhgGKSgxOnkxMjg6AgXt
+40h2lpiIHTjbu6fiCBzbr5j2eQX3cNoydkRphJ66bqD+DsPW/Ag0WBCQxgRaLgMr
+db64fQT+fyjbTBLbC8ytt5hpCbm/q5x3TTXDAUNjoB3CnA/tQItBy7qqq/A0d3FZ
+grr6AixK58uZ4wauy8LRZCph67UZ8akcgwJkmVkpKDE6eDIwOn/Y1rjZASGMK9IG
+b1y/ZDKT0zkTKSkp
+=muRa
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc b/tests/migrations/extended-private-key-format.gpghome/private-keys-v1.d/8B5ABF3EF9EB8D96B91A0B8C2C4401C91C834C34.key.asc
new file mode 100644 (file)
index 0000000..7083673
--- /dev/null
@@ -0,0 +1,20 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+S2V5OiAocHJpdmF0ZS1rZXkgKGVsZyAocCAjMDBDQ0Q4QjFGOURBQzc0RDgwOEND
+NTJGMEQ4OTQ2NERBNTU0QzY5RDY3RjMKIDMyM0M0MkE5NUM5OTYyREY0MjEyNkVD
+MEUwOTcxRjQ5QjgxMTUyOUE2QTJBRTlGMEFERUI4MzlBNjM0NjE1Q0Q1NkZBNTQK
+IEY1QTBCN0VGMjVBMEUyRkU4NDNGQTJFNkUwMjFDQUI0MTE5RTYwMzk0QzlENkEz
+RjdBRDRGNTc3OTZEMzY2NjlBNTEyNjYKIEMyN0E4RDFDNUE2QjQxNDFENUM4MzFF
+ODQ1NDFGM0M4MTFFODkwNzg5ODAzMzgyOTVGODJCN0Y3RkQ0MzMzRUZEOTMzMTIK
+IEYyQUIjKShnICMwNiMpKHkgIzM3NzNBNkQ5RUM4ODlENzZFMzI0RDZFNUVDMjFC
+RDQ1Njk5ODMxQUU0RkQwQUUwMzc4MjAKIDVCQUU1QjhDRTg1RkFEQUJEN0U2QjdD
+NzMwMjVDQjNENzMwRDVDNTgyOTAzNEQ3NkJFMDg1NUMyRTlGRjdBNDkyM0VGRkEK
+IEYxNkE5NjY2OTQ0REJDNjI5NDgzOEZDM0YwOUZGOTY0QThEMDIzQ0I4RUJBMzMy
+RkIwNTFFQTAyODIwRUU2MTIwRkZCRTYKIDJCMzZBMjAyQjNDNzUyRjlEQTc2QjJF
+QzExQTY3RDJFMzVFNjZFQzEwNjM1ODdCMjI1MDBFOEE0NkQxNTdCNzUjKSh4ICMK
+IDY5MTVDNkNFRDI1ODE0M0Y4OTM3QjEzMzVGNDg4N0YwMDQyQjdDNjMwMDUzOThG
+OTM5NkJCODUzMjM4Q0I2IykpKQo=
+=6fkh
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/pubring.kbx.asc b/tests/migrations/extended-private-key-format.gpghome/pubring.kbx.asc
new file mode 100644 (file)
index 0000000..5012371
--- /dev/null
@@ -0,0 +1,39 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+AAAAIAEBAAJLQlhmAAAAAFcYtiNXGLYjAAAAAAAAAAAAAAQXAgEAAAAAAH4AAAOF
+AAIAHMHeuzTqi3EAnq+kdJc9UOHED97PAAAAIAAAAADNPQ9XAcv8rLKkkHMFo3iH
+snkHqgAAADwAAAAAAAAAAQAMAAACJQAAACIAAAAAAAIABP//////////AAAAAAAA
+AAAAAAAAVxi2IwAAAACZAaIEP/JSaxEEAKxxqlg9Kz9DZ/3N52BC0w+JtYKke39v
+pdWVDHR3MHmMJ/31Y2iSpm0fvRs3h1j9/fBVmLOZglNQyH62SxdJyZwCelkZzfUy
+/qLm9Qaqi7wpg0p4EbmWdoFF/A1Zg/MU7D5w5xu+EA1J77Z6QyALN9rIOXZ7rLLa
+64lw/MV4LdIPAKC449htJbbp5rkJHvBDs4YxEIkk5wP/X4hPGlIw5PlHrsG7hdah
+hTudV5hRGlvosnwsrYJXvKAQLAV1EV26SIYUH5pM/ycXrG25dqVoG56uQqnhBdUq
+o4iSnsxY3ZMA46D14REc9P//CGvJ/j2Z41gw8u8oB7rS50djvoaWb5myj7bhacTB
+dfah3U8dVXcIi1ZFvtiaGAYD+gIF7eNIdpaYiB0427un4ggc26+Y9nkF93DaMnZE
+aYSeum6g/g7D1vwINFgQkMYEWi4DK3W+uH0E/n8o20wS2wvMrbeYaQm5v6ucd001
+wwFDY6AdwpwP7UCLQcu6qqvwNHdxWYK6+gIsSufLmeMGrsvC0WQqYeu1GfGpHIMC
+ZJlZtCJUZXN0IHR3byAobm8gcHApIDx0d29AZXhhbXBsZS5jb20+iF8EExECAB8F
+Aj/yUmsCGwMHCwkIBwMCAQMVAgMDFgIBAh4BAheAAAoJEJc9UOHED97PgEMAn0F8
+RGDrnmXv7rqM2+pic2oDz1kpAJ0SWPHxdjJHWzoGMrHqocAy/3wFi7kBDQQ/8lJv
+EAQAzNix+drHTYCMxS8NiUZNpVTGnWfzMjxCqVyZYt9CEm7A4JcfSbgRUppqKunw
+reuDmmNGFc1W+lT1oLfvJaDi/oQ/oubgIcq0EZ5gOUydaj961PV3ltNmaaUSZsJ6
+jRxaa0FB1cgx6EVB88gR6JB4mAM4KV+Ct/f9QzPv2TMS8qsAAwYD/jdzptnsiJ12
+4yTW5ewhvUVpmDGuT9CuA3ggW65bjOhfravX5rfHMCXLPXMNXFgpA012vghVwun/
+ekkj7/rxapZmlE28YpSDj8Pwn/lkqNAjy466My+wUeoCgg7mEg/75is2ogKzx1L5
+2nay7BGmfS415m7BBjWHsiUA6KRtFXt1iEkEGBECAAkFAj/yUm8CGwwACgkQlz1Q
+4cQP3s8svgCgmWcpVwvtDN3nAVT1dMFTvCz0hfwAoI4VszJBesG/8GyLW+e2E+Li
+QXVqciq2GGJ3Ap2KvoCwCL/DhCAfcGsAAAHgAgEAAAAAAF4AAAFuAAEAHM8jSQsP
+eLhQu7xzadEgtibsq/UdAAAAIAAAAAAAAAABAAwAAADvAAAAJgAAAAAAAQAE////
+/wAAAAAAAAAAAAAAAFcYtkkAAAAAmQCMBD/yU70BBACoUlZ27OTXX+bQBz8r+Zpv
+STPOvdRSivVuTGHi9zEkc5NkXdr1jq3VZSnCU5d4I2Rj3y1FhSDoDjTAWCQrP/iN
+05qIO0dbZs6qu8mYn/Af/nN2YOm2G7nckSBdQo//6PZ1+u9hNljHLabXUMDrxAr2
+I9IGaSyCUUxATYglq3AQAQAJAQG0JlRlc3QgdGhyZWUgKG5vIHBwKSA8dGhyZWVA
+ZXhhbXBsZS5jb20+iLUEEwECAB8FAj/yU70CGwMHCwkIBwMCAQMVAgMDFgIBAh4B
+AheAAAoJENEgtibsq/UdakMD/2wg19VhpNbtM5CiVif1V57h945OmXr5Lh2SAsI5
+agMb9XXuT9yXsmv+JD5hEE6LRL98XAwGfvaQS9062aJQCocZAWdPJeEEsu+pMn/I
+QdHqGdkr7Oy6xjwSa+gh19JMg4mqR4AIQSkKvRoTSqSAGbi+gytnTmkA7aEUltog
+dYeJLGB5MYPnSPwADYVfNtLxsKZESLA=
+=tULv
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.gpghome/trustdb.gpg.asc b/tests/migrations/extended-private-key-format.gpghome/trustdb.gpg.asc
new file mode 100644 (file)
index 0000000..f4d354d
--- /dev/null
@@ -0,0 +1,31 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+AWdwZwMDAQUBAgAAVxi2IwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+=eBUi
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/extended-private-key-format.test b/tests/migrations/extended-private-key-format.test
new file mode 100755 (executable)
index 0000000..9c373e8
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Copyright 2016 g10 Code GmbH
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.  This file is
+# distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY, to the extent permitted by law; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+if [ -z "$srcdir" ]; then
+   echo "not called from make" >&2
+   exit 1
+fi
+
+unset GNUPGHOME
+set -e
+
+# (We may not use a relative name for gpg-agent.)
+GPG_AGENT="$(cd ../../agent && /bin/pwd)/gpg-agent"
+GPG="../../g10/gpg --no-permission-warning --no-greeting --no-secmem-warning
+--batch --agent-program=${GPG_AGENT}|--debug-quick-random"
+
+TEST="extended-private-key-format"
+
+setup_home()
+{
+    XGNUPGHOME="`mktemp -d`"
+    mkdir -p "$XGNUPGHOME/private-keys-v1.d"
+    for F in $srcdir/$TEST.gpghome/*.asc; do
+       $GPG --dearmor <"$F" >"$XGNUPGHOME/`basename $F .asc`"
+    done
+    for F in $srcdir/$TEST.gpghome/private-keys-v1.d/*.asc; do
+       $GPG --dearmor <"$F" >"$XGNUPGHOME/private-keys-v1.d/`basename $F .asc`"
+    done
+    chmod go-rwx $XGNUPGHOME/* $XGNUPGHOME/*/*
+    export GNUPGHOME="$XGNUPGHOME"
+}
+
+cleanup_home()
+{
+    rm -rf -- "$XGNUPGHOME"
+}
+
+assert_keys_usable()
+{
+    for KEY in C40FDECF ECABF51D; do
+       $GPG --list-secret-keys $KEY >/dev/null
+    done
+}
+
+setup_home
+assert_keys_usable
+cleanup_home
+
+
+# XXX try changing a key, and check that the format is not changed.
diff --git a/tests/migrations/from-classic.gpghome/pubring.gpg.asc b/tests/migrations/from-classic.gpghome/pubring.gpg.asc
new file mode 100644 (file)
index 0000000..ecdfddc
--- /dev/null
@@ -0,0 +1,54 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+mQGiBD/yNQgRBAC/KSfe6uVfDgA3BrGpNLhVxT/ytwXMpBI8pEdTiY0jWnYrb/Yu
+8wtCeZ9GAux/ZA/ted+7pdibHXfX5PzDfgUTZwrIJa57OUpWwI878AzZxNsnVv1I
+P6ufGyESKME4PUQO5heKhwAb0gQwFwArS3v4oeYrEljhJ79kpt319JEAEwCg+hTk
+nylYwYGT/PEVQ4JlLPoWmqUEAJn1HX1Od5tyoK4OEAM5G+wHz3SBj4FMonZNWs1I
+t03JKHoM5ulQ2FgEWmBVIPTKSDm/jQXPYApz5DpxpoGYbTCaEo6zfE32AEzoXDmG
+AZE90Xhq/wcEN+JcHpHytAA/n+hYaR3sYegQ52mWMR+vdd99KO0V0jLRcckgBA7Z
+2jlFA/98cyy2nYt0QI5Tf+t/d4WBeib2yNWVtZH/j7XpDqHLZDgVAYkazCA6ZF7B
+vLddBEqVAh1X5tqua4AXX9L4SGYb7B0LRV72alhYiWWHez126KjVgwRTUxtEJ4En
+HmYJRReLlXosPIRhXSz7HFAqalPXJ0DvC9kzTQnnjPOylyMPTbQjVGVzdCBvbmUg
+KHBwPWRlZikgPG9uZUBleGFtcGxlLmNvbT6IWgQTEQIAGgUCP/I1CAIbAwILAgMV
+AgMDFgIBAh4BAheAAAoJEA73cJbXTF8iUO4AnA8wHb3erMrfWV3ij0d/cEiSJAYF
+AJ9fcbShgTXDN1dIVZvLSW5E93TfC7ACAAOIWgQTEQIAGgUCP/I1CAIbAwILAgMV
+AgMDFgIBAh4BAheAAAoJEA73cJbXTF8iUO4An3DqZUvcr92tYI+Ewj4jcmzFrNKM
+AJ4yYTZj75t4d7WhUv1WjtDgJkkAm7ACAAO5AQ0EP/I1DRAEAOgCS1p47zcdec0U
+vVC0phewalHUU6f7mulWr0j0ZY1RU0IOP18HAeT7INcwPcUaUvC9KYenXmYbvO1i
+7sNNUCOsKUamwg+oSNMcbM3AwNwxlggTyJS1N6WzIX7MjRLUlUqtbLRhPDGlCltt
+6yeAjS0pZT646TANaBDiRIgk94ADAAMFA/9Gh2X1Sy+4Ip/RtMJDPZOY+Y6sWUN7
+OiM2BkdUmCLOmaOVfgrsEevKdSBBj0oVWN81U02i7jQzhhAI3tZMFJmP/hlF7AlS
+5HSaLj2+t1nHAKKy70QhskINR41CCv9sHAc5gN1WrY5NDpeI12GmqsWMPQVPUHsT
+Te0QsT6XbHzvC4hJBBgRAgAJBQI/8jUNAhsMAAoJEA73cJbXTF8icHgAoMoPkG6U
+dFdvTjKc/phZ6XojaDd9AKCokQkuhQ1wgXe2naMXaMGvzRaYzbACAAOZAaIEP/JS
+axEEAKxxqlg9Kz9DZ/3N52BC0w+JtYKke39vpdWVDHR3MHmMJ/31Y2iSpm0fvRs3
+h1j9/fBVmLOZglNQyH62SxdJyZwCelkZzfUy/qLm9Qaqi7wpg0p4EbmWdoFF/A1Z
+g/MU7D5w5xu+EA1J77Z6QyALN9rIOXZ7rLLa64lw/MV4LdIPAKC449htJbbp5rkJ
+HvBDs4YxEIkk5wP/X4hPGlIw5PlHrsG7hdahhTudV5hRGlvosnwsrYJXvKAQLAV1
+EV26SIYUH5pM/ycXrG25dqVoG56uQqnhBdUqo4iSnsxY3ZMA46D14REc9P//CGvJ
+/j2Z41gw8u8oB7rS50djvoaWb5myj7bhacTBdfah3U8dVXcIi1ZFvtiaGAYD+gIF
+7eNIdpaYiB0427un4ggc26+Y9nkF93DaMnZEaYSeum6g/g7D1vwINFgQkMYEWi4D
+K3W+uH0E/n8o20wS2wvMrbeYaQm5v6ucd001wwFDY6AdwpwP7UCLQcu6qqvwNHdx
+WYK6+gIsSufLmeMGrsvC0WQqYeu1GfGpHIMCZJlZtCJUZXN0IHR3byAobm8gcHAp
+IDx0d29AZXhhbXBsZS5jb20+iF8EExECAB8FAj/yUmsCGwMHCwkIBwMCAQMVAgMD
+FgIBAh4BAheAAAoJEJc9UOHED97PgEMAn0F8RGDrnmXv7rqM2+pic2oDz1kpAJ0S
+WPHxdjJHWzoGMrHqocAy/3wFi7ACAAO5AQ0EP/JSbxAEAMzYsfnax02AjMUvDYlG
+TaVUxp1n8zI8QqlcmWLfQhJuwOCXH0m4EVKaairp8K3rg5pjRhXNVvpU9aC37yWg
+4v6EP6Lm4CHKtBGeYDlMnWo/etT1d5bTZmmlEmbCeo0cWmtBQdXIMehFQfPIEeiQ
+eJgDOClfgrf3/UMz79kzEvKrAAMGA/43c6bZ7IidduMk1uXsIb1FaZgxrk/QrgN4
+IFuuW4zoX62r1+a3xzAlyz1zDVxYKQNNdr4IVcLp/3pJI+/68WqWZpRNvGKUg4/D
+8J/5ZKjQI8uOujMvsFHqAoIO5hIP++YrNqICs8dS+dp2suwRpn0uNeZuwQY1h7Il
+AOikbRV7dYhJBBgRAgAJBQI/8lJvAhsMAAoJEJc9UOHED97PLL4AoJlnKVcL7Qzd
+5wFU9XTBU7ws9IX8AKCOFbMyQXrBv/Bsi1vnthPi4kF1arACAAOYjAQ/8lO9AQQA
+qFJWduzk11/m0Ac/K/mab0kzzr3UUor1bkxh4vcxJHOTZF3a9Y6t1WUpwlOXeCNk
+Y98tRYUg6A40wFgkKz/4jdOaiDtHW2bOqrvJmJ/wH/5zdmDpthu53JEgXUKP/+j2
+dfrvYTZYxy2m11DA68QK9iPSBmksglFMQE2IJatwEAEACQEBtCZUZXN0IHRocmVl
+IChubyBwcCkgPHRocmVlQGV4YW1wbGUuY29tPoi1BBMBAgAfBQI/8lO9AhsDBwsJ
+CAcDAgEDFQIDAxYCAQIeAQIXgAAKCRDRILYm7Kv1HWpDA/9sINfVYaTW7TOQolYn
+9Vee4feOTpl6+S4dkgLCOWoDG/V17k/cl7Jr/iQ+YRBOi0S/fFwMBn72kEvdOtmi
+UAqHGQFnTyXhBLLvqTJ/yEHR6hnZK+zsusY8EmvoIdfSTIOJqkeACEEpCr0aE0qk
+gBm4voMrZ05pAO2hFJbaIHWHibACAAM=
+=fphx
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.gpghome/secring.gpg.asc b/tests/migrations/from-classic.gpghome/secring.gpg.asc
new file mode 100644 (file)
index 0000000..6aa367a
--- /dev/null
@@ -0,0 +1,68 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+lQHpBD/yNQgRBAC/KSfe6uVfDgA3BrGpNLhVxT/ytwXMpBI8pEdTiY0jWnYrb/Yu
+8wtCeZ9GAux/ZA/ted+7pdibHXfX5PzDfgUTZwrIJa57OUpWwI878AzZxNsnVv1I
+P6ufGyESKME4PUQO5heKhwAb0gQwFwArS3v4oeYrEljhJ79kpt319JEAEwCg+hTk
+nylYwYGT/PEVQ4JlLPoWmqUEAJn1HX1Od5tyoK4OEAM5G+wHz3SBj4FMonZNWs1I
+t03JKHoM5ulQ2FgEWmBVIPTKSDm/jQXPYApz5DpxpoGYbTCaEo6zfE32AEzoXDmG
+AZE90Xhq/wcEN+JcHpHytAA/n+hYaR3sYegQ52mWMR+vdd99KO0V0jLRcckgBA7Z
+2jlFA/98cyy2nYt0QI5Tf+t/d4WBeib2yNWVtZH/j7XpDqHLZDgVAYkazCA6ZF7B
+vLddBEqVAh1X5tqua4AXX9L4SGYb7B0LRV72alhYiWWHez126KjVgwRTUxtEJ4En
+HmYJRReLlXosPIRhXSz7HFAqalPXJ0DvC9kzTQnnjPOylyMPTf4HAwI+6Mr+dvBp
+XtZVHbBd1xUPHQl/+cIIBV6w3EFQuR6w7OorCYE6OHrHfEsFwCi3PNG5WUsMYIj2
+eddOuyRWtFR/QsaltCNUZXN0IG9uZSAocHA9ZGVmKSA8b25lQGV4YW1wbGUuY29t
+PohaBBMRAgAaBQI/8jUIAhsDAgsCAxUCAwMWAgECHgECF4AACgkQDvdwltdMXyJQ
+7gCcDzAdvd6syt9ZXeKPR39wSJIkBgUAn19xtKGBNcM3V0hVm8tJbkT3dN8LsAIA
+AIhaBBMRAgAaBQI/8jUIAhsDAgsCAxUCAwMWAgECHgECF4AACgkQDvdwltdMXyJQ
+7gCfcOplS9yv3a1gj4TCPiNybMWs0owAnjJhNmPvm3h3taFS/VaO0OAmSQCbsAIA
+AJ0BXwQ/8jUNEAQA6AJLWnjvNx15zRS9ULSmF7BqUdRTp/ua6VavSPRljVFTQg4/
+XwcB5Psg1zA9xRpS8L0ph6deZhu87WLuw01QI6wpRqbCD6hI0xxszcDA3DGWCBPI
+lLU3pbMhfsyNEtSVSq1stGE8MaUKW23rJ4CNLSllPrjpMA1oEOJEiCT3gAMAAwUD
+/0aHZfVLL7gin9G0wkM9k5j5jqxZQ3s6IzYGR1SYIs6Zo5V+CuwR68p1IEGPShVY
+3zVTTaLuNDOGEAje1kwUmY/+GUXsCVLkdJouPb63WccAorLvRCGyQg1HjUIK/2wc
+BzmA3Vatjk0Ol4jXYaaqxYw9BU9QexNN7RCxPpdsfO8L/gcDArbUVjowJlNA1rny
+wPbRkyAfJDY8m6+s1oM56PICi8N/E3TM/0A2fOESbsTfW6eKCmrIB3VDnURtVUTv
+WS71OKAqhddkD8tUtVQWdKXL5YhJBBgRAgAJBQI/8jUNAhsMAAoJEA73cJbXTF8i
+cHgAoMoPkG6UdFdvTjKc/phZ6XojaDd9AKCokQkuhQ1wgXe2naMXaMGvzRaYzbAC
+AACVAekEP/JSaxEEAKxxqlg9Kz9DZ/3N52BC0w+JtYKke39vpdWVDHR3MHmMJ/31
+Y2iSpm0fvRs3h1j9/fBVmLOZglNQyH62SxdJyZwCelkZzfUy/qLm9Qaqi7wpg0p4
+EbmWdoFF/A1Zg/MU7D5w5xu+EA1J77Z6QyALN9rIOXZ7rLLa64lw/MV4LdIPAKC4
+49htJbbp5rkJHvBDs4YxEIkk5wP/X4hPGlIw5PlHrsG7hdahhTudV5hRGlvosnws
+rYJXvKAQLAV1EV26SIYUH5pM/ycXrG25dqVoG56uQqnhBdUqo4iSnsxY3ZMA46D1
+4REc9P//CGvJ/j2Z41gw8u8oB7rS50djvoaWb5myj7bhacTBdfah3U8dVXcIi1ZF
+vtiaGAYD+gIF7eNIdpaYiB0427un4ggc26+Y9nkF93DaMnZEaYSeum6g/g7D1vwI
+NFgQkMYEWi4DK3W+uH0E/n8o20wS2wvMrbeYaQm5v6ucd001wwFDY6AdwpwP7UCL
+Qcu6qqvwNHdxWYK6+gIsSufLmeMGrsvC0WQqYeu1GfGpHIMCZJlZ/gcDAt0kdqtP
+lKPG1udCj4rXVf+JWEOsbdSsnimRh7rcSE5ksh/JzinsE9rm9FRY112AWfzPaj99
+0JAuaDOzn4d/6tPUnHa0IlRlc3QgdHdvIChubyBwcCkgPHR3b0BleGFtcGxlLmNv
+bT6IXwQTEQIAHwUCP/JSawIbAwcLCQgHAwIBAxUCAwMWAgECHgECF4AACgkQlz1Q
+4cQP3s+AQwCfQXxEYOueZe/uuozb6mJzagPPWSkAnRJY8fF2MkdbOgYyseqhwDL/
+fAWLsAIAAJ0BXwQ/8lJvEAQAzNix+drHTYCMxS8NiUZNpVTGnWfzMjxCqVyZYt9C
+Em7A4JcfSbgRUppqKunwreuDmmNGFc1W+lT1oLfvJaDi/oQ/oubgIcq0EZ5gOUyd
+aj961PV3ltNmaaUSZsJ6jRxaa0FB1cgx6EVB88gR6JB4mAM4KV+Ct/f9QzPv2TMS
+8qsAAwYD/jdzptnsiJ124yTW5ewhvUVpmDGuT9CuA3ggW65bjOhfravX5rfHMCXL
+PXMNXFgpA012vghVwun/ekkj7/rxapZmlE28YpSDj8Pwn/lkqNAjy466My+wUeoC
+gg7mEg/75is2ogKzx1L52nay7BGmfS415m7BBjWHsiUA6KRtFXt1/gcDAp6cJdVh
+287E1o1bCCplLBBjGAPRdWYlnZoJXXn7OUTHTSvMQkEZhAgDOKIiiwC88Drlk+bS
+m9MngTW7YnBsrRfIGhpSxLcYSeMk2xu8m4hJBBgRAgAJBQI/8lJvAhsMAAoJEJc9
+UOHED97PLL4AoJlnKVcL7Qzd5wFU9XTBU7ws9IX8AKCOFbMyQXrBv/Bsi1vnthPi
+4kF1arACAACVAgQEP/JTvQEEAKhSVnbs5Ndf5tAHPyv5mm9JM8691FKK9W5MYeL3
+MSRzk2Rd2vWOrdVlKcJTl3gjZGPfLUWFIOgONMBYJCs/+I3Tmog7R1tmzqq7yZif
+8B/+c3Zg6bYbudyRIF1Cj//o9nX672E2WMctptdQwOvECvYj0gZpLIJRTEBNiCWr
+cBABAAkBAf4HAwL3+6VQeHRq3tZqCOiuxPcuaSlTpURzbLJBa70QpeAbLZjOIjbm
+dQuNBzmxYZNe5V8mf33q2gn/P9vjki0Z/k96qJOXBgLSJkyK4FPi2dtqKkrOonkx
+rFv2AZ6Gt3zGp6dN3meYvG8GIiIvFiZmKYOrt4/XsAnPhXetbN23vO3dJxquD9sw
+O8phwR2u6ii789nbXjD6vOyyv7WcogUVQTHC9pJQrOkDX9aMxiVWHvvv2o2FOU/n
+JanwL/QN4J0sL36ytLoqhsUnayhhHbAP5TA+Vbk9JWvwO+6n8KDiUOkyaIzDaOgr
+BvU1eMSv89MiYH8JiNU9nO9ungT0hxJMn9OwFcrXGCXZ6xXct9yN4nlVV0r16032
+DE7m0JQuwoLm4S7OkQEBHlvtfs/WZzMWkFbduOarPr1uzf92BaSjpQLEAKCFgX1/
+zBPnmqDOnOdL4AIZcYR+q+vWvQLI1RoYSCiodfNQt7iq2IRF8j4qis88QC/JMb60
+JlRlc3QgdGhyZWUgKG5vIHBwKSA8dGhyZWVAZXhhbXBsZS5jb20+iLUEEwECAB8F
+Aj/yU70CGwMHCwkIBwMCAQMVAgMDFgIBAh4BAheAAAoJENEgtibsq/UdakMD/2wg
+19VhpNbtM5CiVif1V57h945OmXr5Lh2SAsI5agMb9XXuT9yXsmv+JD5hEE6LRL98
+XAwGfvaQS9062aJQCocZAWdPJeEEsu+pMn/IQdHqGdkr7Oy6xjwSa+gh19JMg4mq
+R4AIQSkKvRoTSqSAGbi+gytnTmkA7aEUltogdYeJsAIAAA==
+=QqWQ
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.gpghome/trustdb.gpg.asc b/tests/migrations/from-classic.gpghome/trustdb.gpg.asc
new file mode 100644 (file)
index 0000000..d4ab65d
--- /dev/null
@@ -0,0 +1,31 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+AWdwZwMDAQUBAgAAVxdnIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+CgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+=XUWW
+-----END PGP ARMORED FILE-----
diff --git a/tests/migrations/from-classic.test b/tests/migrations/from-classic.test
new file mode 100755 (executable)
index 0000000..9b81d45
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+# Copyright 2016 g10 Code GmbH
+#
+# This file is free software; as a special exception the author gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.  This file is
+# distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY, to the extent permitted by law; without even the implied
+# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+if [ -z "$srcdir" ]; then
+   echo "not called from make" >&2
+   exit 1
+fi
+
+unset GNUPGHOME
+set -e
+
+# (We may not use a relative name for gpg-agent.)
+GPG_AGENT="$(cd ../../agent && /bin/pwd)/gpg-agent"
+GPG="../../g10/gpg --no-permission-warning --no-greeting --no-secmem-warning
+--batch --agent-program=${GPG_AGENT}|--debug-quick-random"
+
+TEST="from-classic"
+
+setup_home()
+{
+    XGNUPGHOME="`mktemp -d`"
+    rm -rf -- scratch
+    mkdir -p "$XGNUPGHOME"
+    for F in $srcdir/$TEST.gpghome/*.asc; do
+       $GPG --dearmor <"$F" >"$XGNUPGHOME/`basename $F .asc`"
+    done
+    chmod go-rwx $XGNUPGHOME/*
+    export GNUPGHOME="$XGNUPGHOME"
+}
+
+cleanup_home()
+{
+    rm -rf -- "$XGNUPGHOME"
+}
+
+trigger_migration()
+{
+    $GPG --list-secret-keys >/dev/null 2>&1
+}
+
+assert_migrated()
+{
+    test -f $GNUPGHOME/.gpg-v21-migrated
+
+    for KEY in D74C5F22 C40FDECF ECABF51D; do
+       $GPG --list-secret-keys $KEY >/dev/null
+    done
+}
+
+setup_home
+trigger_migration
+assert_migrated
+cleanup_home
+
+# Test with an existing private-keys-v1.d.
+setup_home
+mkdir "$GNUPGHOME/private-keys-v1.d"
+trigger_migration
+assert_migrated
+cleanup_home
+
+# Test with an existing private-keys-v1.d with weird permissions.
+setup_home
+mkdir "$GNUPGHOME/private-keys-v1.d"
+chmod 0 "$GNUPGHOME/private-keys-v1.d"
+trigger_migration
+assert_migrated
+cleanup_home
+
+# XXX Check a case where the migration fails.
index a04b62c..bab0b7d 100644 (file)
 
 
 # Programs required before we can run these tests.
-required_pgms = ../../g10/gpg2 ../../agent/gpg-agent \
-                ../../tools/gpg-connect-agent ../../tools/mk-tdata
+required_pgms = ../../g10/gpg$(EXEEXT) ../../agent/gpg-agent$(EXEEXT) \
+                ../../tools/gpg-connect-agent$(EXEEXT) \
+               ../../tools/mk-tdata$(EXEEXT)
+
+AM_CPPFLAGS = -I$(top_srcdir)/common
+include $(top_srcdir)/am/cmacros.am
+
+AM_CFLAGS =
+
+noinst_PROGRAMS = fake-pinentry
+
+fake_pinentry_SOURCES = fake-pinentry.c
 
 TESTS_ENVIRONMENT = GNUPGHOME=$(abs_builddir) GPG_AGENT_INFO= LC_ALL=C
 
@@ -52,6 +62,7 @@ TESTS = version.test mds.test \
 
 TEST_FILES = pubring.asc secring.asc plain-1o.asc plain-2o.asc plain-3o.asc \
             plain-1.asc plain-2.asc plain-3.asc plain-1-pgp.asc \
+            plain-largeo.asc \
             pubring.pkr.asc secring.skr.asc secdemo.asc pubdemo.asc \
              gpg.conf.tmpl gpg-agent.conf.tmpl \
             bug537-test.data.asc bug894-test.asc \
index bfb84ac..83e4f79 100755 (executable)
@@ -35,7 +35,7 @@ do
     info "Trying --default-key $x"
 
     if ! echo | $GPG --default-key "$x" -s | $GPG --verify --status-fd=1 \
-            | grep -q 'VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479'
+            | grep 'VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479' >/dev/null
     then
         echo | $GPG --default-key "$x" -s | $GPG --verify --status-fd=2
         error "Unexpected key used for signing (not the signing subkey, specified \"$x\")."
@@ -55,13 +55,13 @@ do
     #
     # Note: it doesn't matter whether we specify the primary key or
     # a subkey: the newest encryption subkey will be used.
-    if ! echo | $GPG --trust-model=always \
+    if ! echo | $GPG ${opt_always} \
                      --default-key "$x" --encrypt-to-default-key \
                      -r 439F02CA -e \
             | $GPG --list-packets \
-            | grep -q "keyid[ ][A-F0-9]*45117079"
+            | grep "keyid[ ][A-F0-9]*45117079" >/dev/null
     then
-        echo | $GPG --trust-model=always \
+        echo | $GPG ${opt_always} \
                     --default-key "$x" --encrypt-to-default-key \
                     -r 439F02CA -e \
             | $GPG --list-packets 1>&2
index 941f786..ea86c69 100755 (executable)
@@ -215,14 +215,14 @@ fi
 unset GPG_AGENT_INFO
 
 # (--no-permission-warning makes only sense on the commandline)
-GPG="../../g10/gpg2 --no-permission-warning "
+GPG="../../g10/gpg --no-permission-warning "
 # (We may not use a relative name for gpg-agent.)
 GPG_AGENT="$(cd ../../agent && /bin/pwd)/gpg-agent"
 GPG_CONNECT_AGENT="../../tools/gpg-connect-agent"
 GPGCONF="../../tools/gpgconf"
 GPG_PRESET_PASSPHRASE="../../agent/gpg-preset-passphrase"
 MKTDATA="../../tools/mk-tdata"
-PINENTRY="$(cd $srcdir && /bin/pwd)/pinentry.sh"
+PINENTRY="$(/bin/pwd)/fake-pinentry${EXEEXT}"
 # Default to empty passphrase for pinentry.sh
 PINENTRY_USER_DATA=
 
diff --git a/tests/openpgp/fake-pinentry.c b/tests/openpgp/fake-pinentry.c
new file mode 100644 (file)
index 0000000..b8aa848
--- /dev/null
@@ -0,0 +1,67 @@
+/* Fake pinentry program for the OpenPGP test suite.
+ *
+ * Copyright (C) 2016 g10 code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+main (int argc, char **argv)
+{
+  static char *passphrase;
+  char *p;
+
+  (void) argc, (void) argv;
+
+  setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
+  setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
+
+  if (!passphrase)
+    {
+      passphrase = getenv ("PINENTRY_USER_DATA");
+      if (!passphrase)
+        passphrase = "";
+      for (p=passphrase; *p; p++)
+        if (*p == '\r' || *p == '\n')
+          *p = '.';
+      printf ("# Passphrase='%s'\n", passphrase);
+    }
+
+  printf ("OK - what's up?\n");
+
+  while (! feof (stdin))
+    {
+      char buffer[1024];
+
+      if (fgets (buffer, sizeof buffer, stdin) == NULL)
+       break;
+
+      if (strncmp (buffer, "GETPIN", 6) == 0)
+       printf ("D %s\nOK\n", passphrase);
+      else if (strncmp (buffer, "BYE", 3) == 0)
+       {
+         printf ("OK\n");
+         break;
+       }
+      else
+       printf ("OK\n");
+    }
+  return 0;
+}
index d9e014a..b3cb54f 100644 (file)
@@ -1,4 +1,3 @@
-use-standard-socket
 allow-preset-passphrase
 no-grab
 
index e6290b0..2f33f75 100755 (executable)
@@ -27,12 +27,18 @@ FILELIST="${TESTDIR}/filelist"
 PPFILE="${TESTDIR}/passphrase"
 PPFLAGS="--gpg-args --passphrase-file=$PPFILE"
 
-GPG=../../g10/gpg2
+GPG=../../g10/gpg
 GPGARGS="$opt_always --no-permission-warning"
 
 GPGTAR="../../tools/gpgtar"
 GPGZIP="sh ../../tools/gpg-zip"
 
+# Skip test if gpgtar has not been built.
+if ! test -x "$GPGTAR"
+then
+    exit 77
+fi
+
 # Create, inspect, and extract an archive with the given options.
 #
 # $1 the tool to test
@@ -59,15 +65,15 @@ do_test()
           >"$FILELIST"
     for F in $TESTFILES
     do
-       grep -qe "\\b${F}\\b" "$FILELIST"
+        awk '{print $NF}' "$FILELIST" | grep "^${F}$" >/dev/null
     done
 
-    $TOOL --gpg "$GPG"  --gpg-args "$GPGARGS" $EXTRACT_FLAGS \
+    $TOOL --gpg "$GPG"  --gpg-args "$GPGARGS" $EXTRACT_FLAGS --quiet \
           --tar-args --directory="${TESTDIR}" \
           "${TESTDIR}/test.tar.pgp"
     for F in $TESTFILES
     do
-       diff -q "$F" "${TESTDIR}/$F"
+       cmp "$F" "${TESTDIR}/$F"
     done
   )
 }
index 944f535..bb73312 100755 (executable)
@@ -26,7 +26,7 @@ cat /dev/null | $GPG --with-colons --print-mds >y
 if have_hash_algo "MD5"; then
   test_one ":1:"    "D41D8CD98F00B204E9800998ECF8427E"
 else
-  echo "Hash algorithm MD5 is not installed (not an error)"
+  echo "    > Hash algorithm MD5 is not installed (not an error)"
 fi
 # SHA-1
 test_one ":2:"    "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
index a381681..fd8a741 100755 (executable)
@@ -4,7 +4,7 @@ set -e
 
 # We need to use --no-options so that a gpg.conf from an older version
 # of gpg is not used.
-GPG="../../g10/gpg2 --no-options --batch --quiet
+GPG="../../g10/gpg --no-options --batch --quiet
      --no-secmem-warning --allow-secret-key-import"
 
 NAMES='Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India
diff --git a/tests/openpgp/plain-largeo.asc b/tests/openpgp/plain-largeo.asc
new file mode 100644 (file)
index 0000000..2f14bdd
--- /dev/null
@@ -0,0 +1,4205 @@
+-----BEGIN PGP ARMORED FILE-----
+Version: GnuPG v2
+Comment: Use "gpg --dearmor" for unpacking
+
+IyBIQUNLSU5HICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgICAgICAgIC0qLSBvcmcgLSotCiMrVElUTEU6IEEgSGFja2VyJ3Mg
+R3VpZGUgdG8gR251UEcKIytURVhUOiBTb21lIG5vdGVzIG9uIEdudVBHIGludGVy
+bmFscwojK1NUQVJUVVA6IHNob3dhbGwKIytPUFRJT05TOiBeOnt9CgoqIEhvdyB0
+byBjb250cmlidXRlCgogIFRoZSBmb2xsb3dpbmcgc3R1ZmYgZXhwbGFpbnMgc29t
+ZSBiYXNpYyBwcm9jZWR1cmVzIHlvdSBuZWVkIHRvCiAgZm9sbG93IGlmIHlvdSB3
+YW50IHRvIGNvbnRyaWJ1dGUgY29kZSBvciBkb2N1bWVudGF0aW9uLgoKKiogTm8g
+bW9yZSBDaGFuZ2VMb2cgZmlsZXMKCkRvIG5vdCBtb2RpZnkgYW55IG9mIHRoZSBD
+aGFuZ2VMb2cgZmlsZXMgaW4gR251UEcuICBTdGFydGluZyBvbgpEZWNlbWJlciAx
+c3QsIDIwMTEgd2UgcHV0IGNoYW5nZSBpbmZvcm1hdGlvbiBvbmx5IGluIHRoZSBH
+SVQgY29tbWl0CmxvZywgYW5kIGdlbmVyYXRlIGEgdG9wLWxldmVsIENoYW5nZUxv
+ZyBmaWxlIGZyb20gbG9ncyBhdCAibWFrZSBkaXN0Igp0aW1lLiAgQXMgc3VjaCwg
+dGhlcmUgYXJlIHN0cmljdCByZXF1aXJlbWVudHMgb24gdGhlIGZvcm0gb2YgdGhl
+CmNvbW1pdCBsb2cgbWVzc2FnZXMuICBUaGUgb2xkIENoYW5nZUxvZyBmaWxlcyBo
+YXZlIGFsbCBiZSByZW5hbWVkIHRvCkNoYW5nZUxvZy0yMDExCgoqKiBDb21taXQg
+bG9nIHJlcXVpcmVtZW50cwoKWW91ciBjb21taXQgbG9nIHNob3VsZCBhbHdheXMg
+c3RhcnQgd2l0aCBhIG9uZS1saW5lIHN1bW1hcnksIHRoZQpzZWNvbmQgbGluZSBz
+aG91bGQgYmUgYmxhbmssIGFuZCB0aGUgcmVtYWluaW5nIGxpbmVzIGFyZSB1c3Vh
+bGx5CkNoYW5nZUxvZy1zdHlsZSBlbnRyaWVzIGZvciBhbGwgYWZmZWN0ZWQgZmls
+ZXMuICBIb3dldmVyLCBpdCdzIGZpbmUKLS0tIGV2ZW4gcmVjb21tZW5kZWQgLS0t
+IHRvIHdyaXRlIGEgZmV3IGxpbmVzIG9mIHByb3NlIGRlc2NyaWJpbmcgdGhlCmNo
+YW5nZSwgd2hlbiB0aGUgc3VtbWFyeSBhbmQgQ2hhbmdlTG9nIGVudHJpZXMgZG9u
+J3QgZ2l2ZSBlbm91Z2ggb2YKdGhlIGJpZyBwaWN0dXJlLiAgT21pdCB0aGUgbGVh
+ZGluZyBUQUJzIHRoYXQgeW91IGFyZSBzZWVpbmcgaW4gYQoicmVhbCIgQ2hhbmdl
+TG9nIGZpbGUsIGJ1dCBrZWVwIHRoZSBtYXhpbXVtIGxpbmUgbGVuZ3RoIGF0IDcy
+IG9yCnNtYWxsZXIsIHNvIHRoYXQgdGhlIGdlbmVyYXRlZCBDaGFuZ2VMb2cgbGlu
+ZXMsIGVhY2ggd2l0aCBpdHMgbGVhZGluZwpUQUIsIHdpbGwgbm90IGV4Y2VlZCA4
+MCBjb2x1bW5zLiAgSWYgeW91IHdhbnQgdG8gYWRkIHRleHQgd2hpY2ggc2hhbGwK
+bm90IGJlIGNvcGllZCB0byB0aGUgQ2hhbmdlTG9nLCBzZXBhcmF0ZSBpdCBieSBh
+IGxpbmUgY29uc2lzdGluZyBvZgp0d28gZGFzaGVzIGF0IHRoZSBiZWdpbiBvZiBh
+IGxpbmUuCgpUaGUgb25lLWxpbmUgc3VtbWFyeSB1c3VhbGx5IHN0YXJ0cyB3aXRo
+IGEga2V5d29yZCB0byBpZGVudGlmeSB0aGUKbWFpbmx5IGFmZmVjdGVkIHN1YnN5
+c3RlbS4gIElmIG1vcmUgdGhhbiBvbmUga2V5d29yZCBpcyByZXF1aXJlZCB0aGUK
+YXJlIGRlbGltaXRlZCBieSBhIGNvbW1hIChlLmcuID1zY2QsdzMyOj0pLiBDb21t
+b25seSBmb3VuZCBrZXl3b3JkcwphcmUKCiAtIGFnZW50ICAgOjogVGhlIGdwZy1h
+Z2VudCBjb21wb25lbnQKIC0gc3NoICAgICA6OiBUaGUgc3NoLWFnZW50IHBhcnQg
+b2YgdGhlIGFnZW50CiAtIGNvbW1vbiAgOjogQ29kZSBpbiBjb21tb24KIC0gaW9i
+dWYgICA6OiBUaGUgSU9CVUYgc3lzdGVtIGluIGNvbW1vbgogLSBncGcgICAgIDo6
+IFRoZSBncGcgb3IgZ3BndiBjb21wb25lbnRzCiAtIGdwZ3NtICAgOjogVGhlIGdw
+Z3NtIGNvbXBvbmVudAogLSBzY2QgICAgIDo6IFRoZSBzY2RhZW1vbiBjb21wb25l
+bnQKIC0gY2NpZCAgICA6OiBUaGUgQ0NJRCBkcml2ZXIgaW4gc2NkYWVtb24KIC0g
+ZGlybW5nciA6OiBUaGUgZGlybW5nciBjb21wb25lbnQKIC0gdzMyICAgICA6OiBX
+aW5kb3dzIHJlbGF0ZWQgY29kZQogLSBwbyAgICAgIDo6IFRyYW5zbGF0aW9ucwog
+LSBidWlsZCAgIDo6IENoYW5nZXMgdG8gdGhlIGJ1aWxkIHN5c3RlbQogLSBzcGVl
+ZG8gIDo6IFNwZWVkbyBidWlsZCBzeXN0ZW0gc3BlY2lmaWMgY2hhbmdlcwogLSBk
+b2MgICAgIDo6IERvY3VtZW50YXRpb24gY2hhbmdlcwoKVHlwbyBmaXhlcyBhbmQg
+ZG9jdW1lbnRhdGlvbiB1cGRhdGVzIGRvbid0IG5lZWQgYSBDaGFuZ2VMb2cgZW50
+cnk7CnRodXMgeW91IHdvdWxkIHVzZSBhIGNvbW1pdCBtZXNzYWdlIGxpa2UKCiMr
+YmVnaW5fZXhhbXBsZQpGaXggdHlwbyBpbiBhIGNvbW1lbnQKCi0tCiMrZW5kX2V4
+YW1wbGUKClRoZSBtYXJrZXIgbGluZSBoZXJlIGlzIGltcG9ydGFudDsgd2l0aG91
+dCBpdCB0aGUgZmlyc3QgbGluZSB3b3VsZAphcHBlYXIgaW4gdGhlIENoYW5nZUxv
+Zy4KCklmIHlvdSBleGNlcHRpb25hbGx5IG5lZWQgdG8gaGF2ZSBsb25nZXIgbGlu
+ZXMgaW4gYSBjb21taXQgbG9nIHlvdSBtYXkKZG8gdGhpcyBhZnRlciB0aGlzIHNj
+aXNzb3IgbGluZToKIytiZWdpbl9leGFtcGxlCiMgLS0tLS0tLS0tLS0tLS0tLS0t
+LS0tLS0tID44IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQojK2VuZF9leGFtcGxl
+CihoYXNoLCBibGFuaywgMjQgZGFzaGVzLCBibGFuaywgc2Npc3NvciwgYmxhbmss
+IDI0IGRhc2hlcykuCk5vdGUgdGhhdCBzdWNoIGEgY29tbWVudCB3aWxsIGJlIHJl
+bW92ZWQgaWYgdGhlIGdpdCBjb21taXQgb3B0aW9uCj0tLWNsZWFudXA9c2Npc3Nv
+cj0gaXMgdXNlZC4KCgoqKiBMaWNlbnNlIHBvbGljeQoKICBHbnVQRyBpcyBsaWNl
+bnNlZCB1bmRlciB0aGUgR1BMdjMrIHdpdGggc29tZSBmaWxlcyB1bmRlciBhIG1p
+eGVkCiAgTEdQTHYzKy9HUEx2MisgbGljZW5zZS4gIEl0IGlzIHRodXMgaW1wb3J0
+YW50LCB0aGF0IGFsbCBjb250cmlidXRlZAogIGNvZGUgYWxsb3dzIGZvciBhbiB1
+cGRhdGUgb2YgdGhlIGxpY2Vuc2U7IGZvciBleGFtcGxlIHdlIGNhbid0CiAgYWNj
+ZXB0IGNvZGUgdW5kZXIgdGhlIEdQTHYyKG9ubHkpLgoKICBHbnVQRyB1c2VkIHRv
+IGhhdmUgYSBzdHJpY3QgcG9saWN5IG9mIHJlcXVpcmluZyBjb3B5cmlnaHQKICBh
+c3NpZ25tZW50cyB0byB0aGUgRlNGLiAgVG8gYXZvaWQgdGhpcyBtYWpvciBvcmdh
+bml6YXRpb25hbCBvdmVyaGVhZAogIGFuZCB0byBhbGxvdyBpbmNsdXNpb24gb2Yg
+Y29kZSwgbm90IGNvcHlyaWdodGVkIGJ5IHRoZSBGU0YsIHRoaXMKICBwb2xpY3kg
+aGFzIGJlZW4gcmVsYXhlZCBvbiAyMDEzLTAzLTI5LiAgSXQgaXMgbm93IGFsc28g
+cG9zc2libGUgdG8KICBjb250cmlidXRlIGNvZGUgYnkgYXNzZXJ0aW5nIHRoYXQg
+dGhlIGNvbnRyaWJ1dGlvbiBpcyBpbiBhY2NvcmRhbmNlCiAgdG8gdGhlICJMaWJn
+Y3J5cHQgRGV2ZWxvcGVyJ3MgQ2VydGlmaWNhdGUgb2YgT3JpZ2luIiBhcyBmb3Vu
+ZCBpbiB0aGUKICBmaWxlICJEQ08iLiAgKEV4Y2VwdCBmb3IgYSBzbGlnaHQgd29y
+ZGluZyBjaGFuZ2UsIHRoaXMgRENPIGlzCiAgaWRlbnRpY2FsIHRvIHRoZSBvbmUg
+dXNlZCBieSB0aGUgTGludXgga2VybmVsLikKCiAgSWYgeW91IHdhbnQgdG8gY29u
+dHJpYnV0ZSBjb2RlIG9yIGRvY3VtZW50YXRpb24gdG8gR251UEcgYW5kIHlvdQog
+IGRpZG4ndCBzaWduIGEgY29weXJpZ2h0IGFzc2lnbm1lbnQgd2l0aCB0aGUgRlNG
+IGluIHRoZSBwYXN0LCB5b3UKICBuZWVkIHRvIHRha2UgdGhlc2Ugc2ltcGxlIHN0
+ZXBzOgoKICAtIERlY2lkZSB3aGljaCBtYWlsIGFkZHJlc3MgeW91IHdhbnQgdG8g
+dXNlLiAgUGxlYXNlIGhhdmUgeW91ciByZWFsCiAgICBuYW1lIGluIHRoZSBhZGRy
+ZXNzIGFuZCBub3QgYSBwc2V1ZG9ueW0uICBBbm9ueW1vdXMgY29udHJpYnV0aW9u
+cwogICAgY2FuIG9ubHkgYmUgZG9uZSBpZiB5b3UgZmluZCBhIHByb3h5IHdobyBj
+ZXJ0aWZpZXMgZm9yIHlvdS4KCiAgLSBJZiB5b3VyIGVtcGxveWVyIG9yIHNjaG9v
+bCBtaWdodCBjbGFpbSBvd25lcnNoaXAgb2YgY29kZSB3cml0dGVuCiAgICBieSB5
+b3U7IHlvdSBuZWVkIHRvIHRhbGsgdG8gdGhlbSB0byBtYWtlIHN1cmUgdGhhdCB5
+b3UgaGF2ZSB0aGUKICAgIHJpZ2h0IHRvIGNvbnRyaWJ1dGUgdW5kZXIgdGhlIERD
+Ty4KCiAgLSBTZW5kIGFuIE9wZW5QR1Agc2lnbmVkIG1haWwgdG8gdGhlIGdudXBn
+LWRldmVsQGdudXBnLm9yZyBtYWlsaW5nCiAgICBsaXN0IGZyb20geW91ciBtYWls
+IGFkZHJlc3MuICBJbmNsdWRlIGEgY29weSBvZiB0aGUgRENPIGFzIGZvdW5kCiAg
+ICBpbiB0aGUgb2ZmaWNpYWwgbWFzdGVyIGJyYW5jaC4gIEluc2VydCB5b3VyIG5h
+bWUgYW5kIGVtYWlsIGFkZHJlc3MKICAgIGludG8gdGhlIERDTyBpbiB0aGUgc2Ft
+ZSB3YXkgeW91IHdhbnQgdG8gdXNlIGl0IGxhdGVyLiAgRXhhbXBsZToKCiAgICAg
+IFNpZ25lZC1vZmYtYnk6IEpvZSBSLiBIYWNrZXIgPGpvZUBleGFtcGxlLm9yZz4K
+CiAgICAoSWYgeW91IHJlYWxseSBuZWVkIGl0LCB5b3UgbWF5IHBlcmZvcm0gc2lt
+cGxlIHRyYW5zZm9ybWF0aW9ucyBvZgogICAgdGhlIG1haWwgYWRkcmVzczogUmVw
+bGFjaW5nICJAIiBieSAiIGF0ICIgb3IgIi4iIGJ5ICIgZG90ICIuKQoKICAtIFRo
+YXQncyBpdC4gIEZyb20gbm93IG9uIHlvdSBvbmx5IG5lZWQgdG8gYWRkIGEgIlNp
+Z25lZC1vZmYtYnk6IgogICAgbGluZSB3aXRoIHlvdXIgbmFtZSBhbmQgbWFpbCBh
+ZGRyZXNzIHRvIHRoZSBjb21taXQgbWVzc2FnZS4gIEl0IGlzCiAgICByZWNvbW1l
+bmRlZCB0byBzZW5kIHRoZSBwYXRjaGVzIHVzaW5nIGEgUEdQL01JTUUgc2lnbmVk
+IG1haWwuCgoqKiBDb2Rpbmcgc3RhbmRhcmRzCgogIFBsZWFzZSBmb2xsb3cgdGhl
+IEdOVSBjb2Rpbmcgc3RhbmRhcmRzLiAgSWYgeW91IGFyZSBpbiBkb3VidCBjb25z
+dWx0CiAgdGhlIGV4aXN0aW5nIGNvZGUgYXMgYW4gZXhhbXBsZS4gIERvIG5vIHJl
+LWluZGVudCBjb2RlIHdpdGhvdXQgYQogIG5lZWQuICBJZiB5b3UgcmVhbGx5IG5l
+ZWQgdG8gZG8gaXQsIHVzZSBhIHNlcGFyYXRlIGNvbW1pdCBmb3Igc3VjaCBhCiAg
+Y2hhbmdlLgoKICAtIE9ubHkgY2VydGFpbiBDOTkgZmVhdHVyZXMgbWF5IGJlIHVz
+ZWQgKHNlZSBiZWxvdyk7IGluIGdlbmVyYWwKICAgIHN0aWNrIHRvIEM5MC4KICAt
+IFBsZWFzZSBkbyBub3QgdXNlIEMrKyA9Ly89IHN0eWxlIGNvbW1lbnRzLgogIC0g
+VHJ5IHRvIGZpdCBsaW5lcyBpbnRvIDgwIGNvbHVtbnMuCiAgLSBJZ25vcmUgc2ln
+bmVkL3Vuc2lnbmVkIHBvaW50ZXIgbWlzbWF0Y2hlcwogIC0gTm8gYXJpdGhtZXRp
+YyBvbiB2b2lkIHBvaW50ZXJzOyBjYXN0IHRvIGNoYXIqIGZpcnN0LgogIC0gV2Ug
+dXNlIG91ciBvd24gcHJpbnRmIHN0eWxlIGZ1bmN0aW9ucyBsaWtlID1lc19wcmlu
+dGY9LCBhbmQKICAgID1lc19hc3ByaW50Zj0gd2hpY2ggaW1wbGVtZW50IG1vc3Qg
+Qzk5IGZlYXR1cmVzIHdpdGggdGhlIGV4Y2VwdGlvbgogICAgb2YgPXdjaGFyX3Q9
+ICh3aGljaCBzaG91bGQgYW55d2F5IG5vdCBiZSB1c2VkKS4gIFBsZWFzZSBhbHdh
+eXMgdXNlCiAgICB0aGVtIGFuZCBkbyBub3QgcmVzb3J0IHRvIHRob3NlIHByb3Zp
+ZGVkIGJ5IGxpYmMuICBUaGUgcmF0aW9uYWxlCiAgICBmb3IgdXNpbmcgdGhlbSBp
+cyB0aGF0IHdlIGtub3cgdGhhdCB0aGUgZm9ybWF0IHNwZWNpZmllcnMgd29yayBv
+bgogICAgYWxsIHBsYXRmb3JtcyBhbmQgdGhhdCB3ZSBkbyBub3QgbmVlZCB0byBj
+aGFzZSBwbGF0Zm9ybSBkZXBlbmRlbnQKICAgIGJ1Z3MuCiAgLSBJdCBpcyBjb21t
+b24gdG8gaGF2ZSBhIGxhYmVsIG5hbWVkICJsZWF2ZSIgZm9yIGEgZnVuY3Rpb24n
+cwogICAgY2xlYW51cCBhbmQgcmV0dXJuIGNvZGUuICBUaGlzIGhlbHBzIHdpdGgg
+ZnJlZWluZyBtZW1vcnkgYW5kIGlzIGEKICAgIGNvbnZlbmllbnQgbG9jYXRpb24g
+dG8gc2V0IGEgYnJlYWtwb2ludCBmb3IgZGVidWdnaW5nLgogIC0gQWx3YXlzIHVz
+ZSB4ZnJlZSgpIGluc3RlYWQgb2YgZnJlZSgpLiAgSWYgaXQgaXMgbm90IGVhc3kg
+dG8gc2VlCiAgICB0aGF0IHRoZSBmcmVlZCB2YXJpYWJsZSBpcyBub3QgYW55bW9y
+ZSB1c2VkLCBleHBsaWNpdGx5IHNldCB0aGUKICAgIHZhcmlhYmxlIHRvIE5VTEwu
+CiAgLSBJbml0IGZ1bmN0aW9uIGxvY2FsIHZhcmlhYmxlcyBvbmx5IGlmIG5lZWRl
+ZCBzbyB0aGF0IHRoZSBjb21waWxlcgogICAgY2FuIGRvIGEgYmV0dGVyIGpvYiBp
+biBkZXRlY3RpbmcgdW5pbml0aWFsaXplZCB2YXJpYWJsZXMgd2hpY2ggbWF5CiAg
+ICBpbmRpY2F0ZSBhIHByb2JsZW0gd2l0aCB0aGUgY29kZS4KICAtIE5ldmVyIGlu
+aXQgc3RhdGljIG9yIGZpbGUgbG9jYWwgdmFyaWFibGVzIHRvIDAgdG8gbWFrZSBz
+dXJlIHRoZXkKICAgIGVuZCB1cCBpbiBCU1MuCiAgLSBVc2UgLS1lbmFibGUtbWFp
+bnRhaW5lci1tb2RlIHdpdGggY29uZmlndXJlLgoKKioqIEM5OSBsYW5ndWFnZSBm
+ZWF0dXJlcwoKICBJbiBHbnVQRyAyLngsIGJ1dCAqbm90IGluIDEuNCogYW5kIG5v
+dCBpbiBtb3N0IGxpYnJhcmllcywgYSBsaW1pdGVkCiAgc2V0IG9mIEM5OSBmZWF0
+dXJlcyBtYXkgYmUgdXNlZDoKCiAgLSBWYXJpYWRpYyBtYWNyb3M6CiAgICA6ICNk
+ZWZpbmUgZm9vKGEsLi4uKSAgYmFyKGEsIF9fVkFfQVJHU19fKQoKICAtIFRoZSBw
+cmVkZWZpbmVkIG1hY3JvID1fX2Z1bmNfXz06CiAgICA6IGxvZ19kZWJ1ZyAoIiVz
+OiBQcm9ibGVtIHdpdGggZm9vXG4iLCBfX2Z1bmNfXyk7CgogIC0gVmFyaWFibGUg
+ZGVjbGFyYXRpb24gaW5zaWRlIGEgZm9yKCk6CiAgICA6IGZvciAoaW50IGkgPSAw
+OyBpIDwgNTsgKyspCiAgICA6ICAgYmFyIChpKTsKCiAgQWx0aG91Z2ggd2UgdXN1
+YWxseSBtYWtlIHVzZSBvZiB0aGUgPXUxNj0sID11MzI9LCBhbmQgPXU2ND0gdHlw
+ZXMsCiAgaXQgaXMgYWxzbyBwb3NzaWJsZSB0byBpbmNsdWRlID08c3RkaW50Lmg+
+PSBhbmQgdXNlID1pbnQxNl90PSwKICA9aW50MzJfdD0sID1pbnQ2NF90PSwgPXVp
+bnQxNl90PSwgPXVpbnQzMl90PSwgYW5kID11aW50NjRfdD0uICBCdXQgZG8KICBu
+b3QgdXNlID1pbnQ4X3Q9IG9yID11aW50OF90PS4KCioqIENvbW1pdCBsb2cga2V5
+d29yZHMKCiAgLSBHbnVQRy1idWctaWQgOjogVmFsdWVzIGFyZSBjb21tYSBvciBz
+cGFjZSBkZWxpbWl0ZWQgYnVnIG51bWJlcnMKICAgICAgICAgICAgICAgICAgICBm
+cm9tIGJ1Zy5nbnVwZy5vcmcgcGVydGFpbmluZyB0byB0aGlzIGNvbW1pdC4KICAt
+IERlYmlhbi1idWctaWQgOjogU2FtZSBhcyBhYm92ZSBidXQgZnJvbSB0aGUgRGVi
+aWFuIGJ1ZyB0cmFja2VyLgogIC0gQ1ZFLWlkIDo6IENWRSBpZCBudW1iZXIgcGVy
+dGFpbmluZyB0byB0aGlzIGNvbW1pdC4KICAtIFJlZ3Jlc3Npb24tZHVlLXRvIDo6
+IENvbW1pdCBpZCBvZiB0aGUgcmVncmVzc2lvbiBmaXhlZCBieSB0aGlzIGNvbW1p
+dC4KICAtIEZpeGVzLWNvbW1pdCA6OiBDb21taXQgaWQgdGhpcyBjb21taXQgZml4
+ZXMuCiAgLSBSZXBvcnRlZC1ieSA6OiBWYWx1ZSBpcyBhIG5hbWUgb3IgbWFpbCBh
+ZGRyZXNzIG9mIGEgYnVnIHJlcG9ydGUuCiAgLSBTdWdnZXN0ZWQtYnkgOjogVmFs
+dWUgaXMgYSBuYW1lIG9yIG1haWwgYWRkcmVzcyBvZiBzb21lb25lIGhvdwogICAg
+ICAgICAgICAgICAgICAgIHN1Z2dlc3RlZCB0aGlzIGNoYW5nZS4KICAtIENvLWF1
+dGhvcmVkLWJ5IDo6IE5hbWUgb3IgbWFpbCBhZGRyZXNzIG9mIGEgY28tYXV0aG9y
+CiAgLSBTb21lLWNvbW1lbnRzLWJ5IDo6IE5hbWUgb3IgbWFpbCBhZGRyZXNzIG9m
+IHRoZSBhdXRob3Igb2YKICAgICAgICAgICAgICAgICAgICAgICAgYWRkaXRpb25h
+bCBjb21tZW50cyAoY29tbWl0IGxvZyBvciBjb2RlKS4KICAtIFByb29mcmVhZC1i
+eSA6OiBTb21ldGltZXMgdXNlZCBieSB0cmFuc2xhdGlvbiBjb21taXRzLgogIC0g
+U2lnbmVkLW9mZi1ieSA6OiBOYW1lIG9yIG1haWwgYWRkcmVzcyBvZiB0aGUgZGV2
+ZWxvcGVyCgoqIFdpbmRvd3MKKiogSG93IHRvIGJ1aWxkIGFuIGluc3RhbGxlciBm
+b3IgV2luZG93cwoKICAgWW91ciBiZXN0IGJldCBpcyB0byB1c2UgYSBkZWNlbnQg
+RGViaWFuIFN5c3RlbSBmb3IgZGV2ZWxvcG1lbnQuCiAgIFlvdSBuZWVkIHRvIGlu
+c3RhbGwgYSBsb25nIGxpc3Qgb2YgdG9vbHMgZm9yIGJ1aWxkaW5nLiAgVGhpcyBs
+aXN0CiAgIHN0aWxsIG5lZWRzIHRvIGJlIGNvbXBpbGVkLiAgSG93ZXZlciwgdGhl
+IGJ1aWxkIHByb2Nlc3Mgd2lsbCBzdG9wCiAgIGlmIGEgdG9vbCBpcyBtaXNzaW5n
+LiAgR05VIG1ha2UgaXMgcmVxdWlyZWQgKG9uIG5vbiBHTlUgc3lzdGVtcwogICBv
+ZnRlbiBpbnN0YWxsZWQgYXMgImdtYWtlIikuICBUaGUgaW5zdGFsbGVyIHJlcXVp
+cmVzIGEgY291cGxlIG9mCiAgIGV4dHJhIHNvZnR3YXJlIHRvIGJlIGF2YWlsYWJs
+ZSBlaXRoZXIgYXMgdGFyYmFsbHMgb3IgYXMgbG9jYWwgZ2l0CiAgIHJlcG9zaXRv
+cmllcy4gIEluIGNhc2UgdGhpcyBmaWxlIGhlcmUgaXMgcGFydCBvZiBhIGdudXBn
+LXczMi0yLioueHoKICAgY29tcGxldGUgdGFyYmFsbCBhcyBkaXN0cmlidXRlZCBm
+cm9tIHRoZSBzYW1lIHBsYWNlIGFzIGEgYmluYXJ5CiAgIGluc3RhbGxlciwgYWxs
+IHN1Y2ggdGFyYmFsbHMgYXJlIGFscmVhZHkgaW5jbHVkZWQuCgogICBDZCB0byB0
+aGUgR251UEcgc291cmNlIGRpcmVjdG9yeSBhbmQgdXNlIG9uZSBvZiBvbmUgb2Yg
+dGhlc2UKICAgY29tbWFuZDoKCiAgIC0gSWYgc291cmNlcyBhcmUgaW5jbHVkZWQg
+KGdudXBnLXczMi0qLnRhci54eikKCiAgICAgbWFrZSAtZiBidWlsZC1hdXgvc3Bl
+ZWRvLm1rIFdIQVQ9dGhpcyBpbnN0YWxsZXIKCiAgIC0gVG8gYnVpbGQgZnJvbSB0
+YXJiYWxscwoKICAgICBtYWtlIC1mIGJ1aWxkLWF1eC9zcGVlZG8ubWsgV0hBVD1y
+ZWxlYXNlIFRBUkJBTExTPVRBUkRJUiBpbnN0YWxsZXIKCiAgIC0gVG8gYnVpbGQg
+ZnJvbSBsb2NhbCBHSVQgcmVwb3MKCiAgICAgbWFrZSAtZiBidWlsZC1hdXgvc3Bl
+ZWRvLm1rIFdIQVQ9Z2l0IFRBUkJBTExTPVRBUkRJUiBpbnN0YWxsZXIKCiAgIE5v
+dGUgdGhhdCBhbHNvIHlvdSBuZWVkIHRvIHN1cHBseSB0YXJiYWxscyB3aXRoIHN1
+cHBvcnRpbmcKICAgbGlicmFyaWVzIGV2ZW4gaWYgeW91IGJ1aWxkIGZyb20gZ2l0
+LiAgVGhlIG1ha2VmaWxlIGV4cGVjdHMgb25seQogICB0aGUgY29yZSBHbnVQRyBz
+b2Z0d2FyZSB0byBiZSBhdmFpbGFibGUgYXMgbG9jYWwgR0lUIHJlcG9zaXRvcmll
+cy4KICAgc3BlZWRvLm1rIGhhcyB0aGUgdmVyc2lvbnMgb2YgdGhlIHRhcmJhbGxz
+IGFuZCB0aGUgYnJhbmNoIG5hbWVzIG9mCiAgIHRoZSBnaXQgcmVwb3NpdG9yaWVz
+LiAgSW4gY2FzZSBvZiBwcm9ibGVtcywgZG9uJ3QgaGVzaXRhdGUgdG8gYXNrCiAg
+IG9uIHRoZSBnbnVwZy1kZXZlbCBtYWlsaW5nIGZvciBoZWxwLgoKKiBEZWJ1ZyBo
+aW50cwoKICBTZWUgdGhlIG1hbnVhbCBmb3Igc29tZSBoaW50cy4KCiogU3RhbmRh
+cmRzCioqIFJGQ3MKCjE0MjMgIFByaXZhY3kgRW5oYW5jZW1lbnQgZm9yIEludGVy
+bmV0IEVsZWN0cm9uaWMgTWFpbDoKICAgICAgUGFydCBJSUk6IEFsZ29yaXRobXMs
+IE1vZGVzLCBhbmQgSWRlbnRpZmllcnMuCgoxNDg5ICBSZWdpc3RyYXRpb24gb2Yg
+YSBDeXJpbGxpYyBDaGFyYWN0ZXIgU2V0LgoKMTc1MCAgUmFuZG9tbmVzcyBSZWNv
+bW1lbmRhdGlvbnMgZm9yIFNlY3VyaXR5LgoKMTk5MSAgUEdQIE1lc3NhZ2UgRXhj
+aGFuZ2UgRm9ybWF0cyAob2Jzb2xldGUpCgoyMTQ0ICBUaGUgQ0FTVC0xMjggRW5j
+cnlwdGlvbiBBbGdvcml0aG0uCgoyMjc5ICBVVEYtOCwgYSB0cmFuc2Zvcm1hdGlv
+biBmb3JtYXQgb2YgSVNPIDEwNjQ2LgoKMjQ0MCAgT3BlblBHUCAob2Jzb2xldGUp
+LgoKMzE1NiAgTUlNRSBTZWN1cml0eSB3aXRoIFByZXR0eSBHb29kIFByaXZhY3kg
+KFBHUCkuCgo0ODgwICBDdXJyZW50IE9wZW5QR1Agc3BlY2lmaWNhdGlvbi4KCjYz
+MzcgIEVsbGlwdGljIEN1cnZlIENyeXB0b2dyYXBoeSAoRUNDKSBpbiBPcGVuUEdQ
+CgoqIFZhcmlvdXMgaW5mb3JtYXRpb24KCioqIERpcmVjdG9yeSBMYXlvdXQKCiAg
+LSAuLwkgICAgICA6OiBSZWFkbWUsIGNvbmZpZ3VyZQogIC0gLi9hZ2VudCAgIDo6
+IEdwZy1hZ2VudCBhbmQgcmVsYXRlZCB0b29scwogIC0gLi9kb2MgICAgIDo6IERv
+Y3VtZW50YXRpb24KICAtIC4vZzEwICAgICA6OiBHcGcgcHJvZ3JhbSBoZXJlIGNh
+bGxlZCBncGcyCiAgLSAuL3NtICAgICAgOjogR3Bnc20gcHJvZ3JhbQogIC0gLi9q
+bmxpYiAgIDo6IE5vdCB1c2VkIChmb3JtZXJseSB1c2VkIHV0aWxpdHkgZnVuY3Rp
+b25zKQogIC0gLi9jb21tb24gIDo6IFV0aWxpdHkgZnVuY3Rpb25zCiAgLSAuL2ti
+eCAgICAgOjogS2V5Ym94IGxpYnJhcnkKICAtIC4vc2NkICAgICA6OiBTbWFydGNh
+cmQgZGFlbW9uCiAgLSAuL3NjcmlwdHMgOjogU2NyaXB0cyBuZWVkZWQgYnkgY29u
+ZmlndXJlIGFuZCBvdGhlcnMKICAtIC4vZGlybW5nciA6OiBUaGUgZGlyZWN0b3J5
+IG1hbmFnZXIKCioqIERldGFpbGVkIFJvYWRtYXAKCiAgVGhpcyBsaXN0IG9mIGZp
+bGVzIGlzIG5vdCB1cCB0byBkYXRlIQoKICAtIGcxMC9ncGcuYyA6OiBNYWluIG1v
+ZHVsZSB3aXRoIG9wdGlvbiBwYXJzaW5nIGFuZCBhbGwgdGhlIHN0dWZmIHlvdQog
+ICAgICAgICAgICAgICAgIGhhdmUgdG8gZG8gb24gc3RhcnR1cC4gIEFsc28gaGFz
+IHRoZSBleGl0IGhhbmRsZXIgYW5kCiAgICAgICAgICAgICAgICAgc29tZSBoZWxw
+ZXIgZnVuY3Rpb25zLgoKICAtIGcxMC9wYXJzZS1wYWNrZXQuYyA6OgogIC0gZzEw
+L2J1aWxkLXBhY2tldC5jIDo6CiAgLSBnMTAvZnJlZS1wYWNrZXQuYyA6OiBQYXJz
+aW5nIGFuZCBjcmVhdGluZyBvZiBPcGVuUEdQIG1lc3NhZ2UgcGFja2V0cy4KCiAg
+LSBnMTAvZ2V0a2V5LmMgICA6OiBLZXkgc2VsZWN0aW9uIGNvZGUKICAtIGcxMC9w
+a2NsaXN0LmMgIDo6IEJ1aWxkIGEgbGlzdCBvZiBwdWJsaWMga2V5cwogIC0gZzEw
+L3NrY2xpc3QuYyAgOjogQnVpbGQgYSBsaXN0IG9mIHNlY3JldCBrZXlzCiAgLSBn
+MTAva2V5cmluZy5jICA6OiBLZXlyaW5nIGFjY2VzcyBmdW5jdGlvbnMKICAtIGcx
+MC9rZXlkYi5oICAgIDo6CgogIC0gZzEwL2tleWlkLmMJICA6OiBIZWxwZXIgZnVu
+Y3Rpb25zIHRvIGdldCB0aGUga2V5aWQsIGZpbmdlcnByaW50IGV0Yy4KCiAgLSBn
+MTAvdHJ1c3RkYi5jIDo6IFdlYi1vZi1UcnVzdCBjb21wdXRhdGlvbnMKICAtIGcx
+MC90cnVzdGRiLmggOjoKICAtIGcxMC90ZGJkdW1wLmMgOjogRXhwb3J0L2ltcG9y
+dC9saXN0IHRoZSB0cnVzdGRiLmdwZwogIC0gZzEwL3RkYmlvLmMgICA6OiBJL08g
+aGFuZGxpbmcgZm9yIHRoZSB0cnVzdGRiLmdwZwogIC0gZzEwL3RkYmlvLmggICA6
+OgoKICAtIGcxMC9jb21wcmVzcy5jIDo6IEZpbHRlciB0byBoYW5kbGUgY29tcHJl
+c3Npb24KICAtIGcxMC9maWx0ZXIuaCAgIDo6IERlY2xhcmF0aW9ucyBmb3IgYWxs
+IGZpbHRlciBmdW5jdGlvbnMKICAtIGcxMC9kZWxrZXkuYyAgIDo6IERlbGV0ZSBh
+IGtleQogIC0gZzEwL2tibm9kZS5jICAgOjogSGVscGVyIGZvciB0aGUga2Jub2Rl
+X3QgbGlua2VkIGxpc3QKICAtIGcxMC9tYWluLmggICAgIDo6IFByb3RvdHlwZXMg
+YW5kIHNvbWUgY29uc3RhbnRzCiAgLSBnMTAvbWFpbnByb2MuYyA6OiBNZXNzYWdl
+IHByb2Nlc3NpbmcKICAtIGcxMC9hcm1vci5jICAgIDo6IEFzY2lpIGFybW9yIGZp
+bHRlcgogIC0gZzEwL21kZmlsdGVyLmMgOjogRmlsdGVyIHRvIGNhbGN1bGF0ZSBo
+YXNocwogIC0gZzEwL3RleHRmaWx0ZXIuYyA6OiBGaWx0ZXIgdG8gaGFuZGxlIENS
+L0xGIGFuZCB0cmFpbGluZyB3aGl0ZSBzcGFjZQogIC0gZzEwL2NpcGhlci5jICAg
+OjogRW4tL0RlY3J5cHRpb24gZmlsdGVyCiAgLSBnMTAvbWlzYy5jICAgICA6OiBV
+dGxpdHkgZnVuY3Rpb25zCiAgLSBnMTAvb3B0aW9ucy5oICA6OiBTdHJ1Y3R1cmUg
+d2l0aCBhbGwgdGhlIGNvbW1hbmQgbGluZSBvcHRpb25zCiAgICAgICAgICAgICAg
+ICAgICAgICBhbmQgcmVsYXRlZCBjb25zdGFudHMKICAtIGcxMC9vcGVuZmlsZS5j
+IDo6IENyZWF0ZS9PcGVuIEZpbGVzCiAgLSBnMTAva2V5c2VydmVyLmggOjogS2V5
+c2VydmVyIGFjY2VzcyBkaXNwYXRjaGVyLgogIC0gZzEwL3BhY2tldC5oICAgOjog
+RGVmaW50aW9uIG9mIE9wZW5QR1Agc3RydWN0dXJlcy4KICAtIGcxMC9wYXNzcGhy
+YXNlLmMgOjogUGFzc3BocmFzZSBoYW5kbGluZyBjb2RlCgogIC0gZzEwL3B1Ymtl
+eS1lbmMuYyA6OiBQcm9jZXNzIGEgcHVibGljIGtleSBlbmNvZGVkIHBhY2tldC4K
+ICAtIGcxMC9zZWNrZXktY2VydC5jIDo6IE5vdCBhbnltb3JlIHVzZWQKICAtIGcx
+MC9zZXNrZXkuYyAgICAgOjogTWFrZSBzZXNzc2lvbiBrZXlzIGV0Yy4KICAtIGcx
+MC9pbXBvcnQuYyAgICAgOjogSW1wb3J0IGtleXMgaW50byBvdXIga2V5IHN0b3Jh
+Z2UuCiAgLSBnMTAvZXhwb3J0LmMgICAgIDo6IEV4cG9ydCBrZXlzIHRvIHRoZSBP
+cGVuUEdQIGZvcm1hdC4KICAtIGcxMC9zaWduLmMgICAgICAgOjogQ3JlYXRlIHNp
+Z25hdHVyZSBhbmQgb3B0aW9uYWxseSBlbmNyeXB0LgogIC0gZzEwL3BsYWludGV4
+dC5jICA6OiBQcm9jZXNzIHBsYWludGV4dCBwYWNrZXRzLgogIC0gZzEwL2RlY3J5
+cHQtZGF0YS5jIDo6IERlY3J5cHQgYW4gZW5jcnlwdGVkIGRhdGEgcGFja2V0CiAg
+LSBnMTAvZW5jcnlwdC5jICAgIDo6IE1haW4gZW5jcnlwdGlvbiBkcml2ZXIKICAt
+IGcxMC9yZXZva2UuYyAgICAgOjogQ3JlYXRlIHJlY292YXRpb24gY2VydGlmaWNh
+dGVzLgogIC0gZzEwL2tleWxpc3QuYyAgICA6OiBQcmludCBpbmZvcm1hdGlvbiBh
+Ym91dCBPcGVuUEdQIGtleXMKICAtIGcxMC9zaWctY2hlY2suYyAgOjogQ2hlY2sg
+YSBzaWduYXR1cmUKICAtIGcxMC9oZWxwdGV4dC5jICAgOjogU2hvdyBvbmxpbmUg
+aGVscCB0ZXh0cwogIC0gZzEwL3ZlcmlmeS5jICAgICA6OiBWZXJpZnkgc2lnbmVk
+IGRhdGEuCiAgLSBnMTAvZGVjcnlwdC5jICAgIDo6IERlY3J5cHQgYW5kIHZlcmlm
+eSBkYXRhLgogIC0gZzEwL2tleWVkaXQuYyAgICA6OiBFZGl0IHByb3BlcnRpZXMg
+b2YgYSBrZXkuCiAgLSBnMTAvZGVhcm1vci5jICAgIDo6IEFybW9yIHV0aWxpdHku
+CiAgLSBnMTAva2V5Z2VuLmMgICAgIDo6IEdlbmVyYXRlIGEga2V5IHBhaXIKCioq
+IE1lbW9yeSBhbGxvY2F0aW9uCgpVc2Ugb25seSB0aGUgZnVuY3Rpb25zOgoKIC0g
+eG1hbGxvYwogLSB4bWFsbG9jX3NlY3VyZQogLSB4dHJ5bWFsbG9jCiAtIHh0cnlt
+YWxsb2Nfc2VjdXJlCiAtIHhjYWxsb2MKIC0geGNhbGxvY19zZWN1cmUKIC0geHRy
+eWNhbGxvYwogLSB4dHJ5Y2FsbG9jX3NlY3VyZQogLSB4cmVhbGxvYwogLSB4dHJ5
+cmVhbGxvYwogLSB4c3RyZHVwCiAtIHh0cnlzdHJkdXAKIC0geGZyZWUKCgpUaGUg
+KnNlY3VyZSB2ZXJzaW9ucyBhbGxvY2F0ZSBtZW1vcnkgaW4gdGhlIHNlY3VyZSBt
+ZW1vcnkuICBUaGF0IGlzLApzd2FwcGluZyBvdXQgb2YgdGhpcyBtZW1vcnkgaXMg
+YXZvaWRlZCBhbmQgaXMgZ2V0cyBvdmVyd3JpdHRlbiBvbgpmcmVlLiAgVXNlIHRo
+aXMgZm9yIHBhc3NwaHJhc2VzLCBzZXNzaW9uIGtleXMgYW5kIG90aGVyIHNlbnNp
+dGl2ZQptYXRlcmlhbC4gIFRoaXMgbWVtb3J5IHNldCBhc2lkZSBmb3Igc2VjdXJl
+IG1lbW9yeSBpcyBsaW5pdGVkIHRvIGEgZmV3CmsuICBJbiBnZW5lcmFsIHRoZSBm
+dW5jdGlvbiBkb24ndCBwcmludCBhIG1lbWVvcnkgbWVzc2FnZSBhbmQKdGVybWlu
+YXRlIHRoZSBwcm9jZXNzIGlmIHRoZXJlIGlzIG5vdCBlbm91Z2ggbWVtb3J5IGF2
+YWlsYWJsZS4gIFRoZQoidHJ5IiB2ZXJzaW9ucyBvZiB0aGUgZnVuY3Rpb25zIHJl
+dHVybiBOVUxMIGluc3RlYWQuCgoqKiBMb2dnaW5nCgogVE9ETwoKKiogT3B0aW9u
+IHBhcnNpbmcKCkdudVBHIGRvZXMgbm90IHVzZSBnZXRvcHQgb3IgR05VIGdldG9w
+dCBidXQgZnVuY3Rpb25zIG9mIGl0J3Mgb3duLgpTZWUgdXRpbC9hcmdwYXJzZS5j
+IGZvciBkZXRhaWxzLiAgVGhlIGFkdmFudGFnZSBvZiB0aGVzZSBmdW5jdGlvbnMg
+aXMKdGhhdCBpdCBpcyBtb3JlIGVhc3kgdG8gZGlzcGxheSBhbmQgbWFpbnRhaW4g
+dGhlIGhlbHAgdGV4dHMgZm9yIHRoZQpvcHRpb25zLiAgVGhlIHNhbWUgb3B0aW9u
+IHRhYmxlIGlzIGFsc28gdXNlZCB0byBwYXJzZSByZXNvdXJjZSBmaWxlcy4KCioq
+IFdoYXQgaXMgYW4gSU9CVUYKClRoaXMgaXMgdGhlIGRhdGEgc3RydWN0dXJlIHVz
+ZWQgZm9yIG1vc3QgSS9PIG9mIGdudXBnLiBJdCBpcyBzaW1pbGFyCnRvIFN5c3Rl
+bcKgViBTdHJlYW1zIGJ1dCBtdWNoIHNpbXBsZXIuICBCZWNhdXNlIE9wZW5QR1Ag
+bWVzc2FnZXMgYXJlCm5lc3RlZCBpbiBkaWZmZXJlbnQgd2F5czsgdGhlIHVzZSBv
+ZiBzdWNoIGEgc3lzdGVtIGhhcyBiaWcgYWR2YW50YWdlcy4KSGVyZSBpcyBhbiBl
+eGFtcGxlLCBob3cgaXQgd29ya3M6IElmIHRoZSBwYXJzZXIgc2VlcyBhIHBhY2tl
+dCBoZWFkZXIKd2l0aCBhIHBhcnRpYWwgbGVuZ3RoLCBpdCBwdXNoZXMgdGhlIGJs
+b2NrX2ZpbHRlciBvbnRvIHRoZSBJT0JVRiB0bwpoYW5kbGUgdGhlc2UgcGFydGlh
+bCBsZW5ndGggcGFja2V0czogZnJvbSBub3cgb24geW91IGRvbid0IGhhdmUgdG8K
+d29ycnkgYWJvdXQgdGhpcy4gIFdoZW4gaXQgc2VlcyBhIGNvbXByZXNzZWQgcGFj
+a2V0IGl0IHB1c2hlcyB0aGUKdW5jb21wcmVzcyBmaWx0ZXIgYW5kIHRoZSBuZXh0
+IHJlYWQgYnl0ZSBpcyBvbmUgd2hpY2ggaGFzIGFscmVhZHkgYmVlbgp1bmNvbXBy
+ZXNzZWQgYnkgdGhpcyBmaWx0ZXIuIFNhbWUgZ29lcyBmb3IgZW5jaXBoZXJlZCBw
+YWNrZXQsCnBsYWludGV4dCBwYWNrZXRzIGFuZCBzbyBvbi4gIFRoZSBmaWxlIGcx
+MC9lbmNvZGUuYyBtaWdodCBiZSBhIGdvb2QKc3RhcnRpbmcgcG9pbnQgdG8gc2Vl
+IGhvdyBpdCBpcyB1c2VkIC0gYWN0dWFsbHkgdGhpcyBpcyB0aGUgb3RoZXIgd2F5
+Ogpjb25zdHJ1Y3RpbmcgbWVzc2FnZXMgdXNpbmcgcHVzaGVkIGZpbHRlcnMgYnV0
+IGl0IG1heSBiZSBlYXNpZXIgdG8KdW5kZXJzdGFuZC4KCgojIGRvYy9ERVRBSUxT
+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
+LSotIG9yZyAtKi0KIytUSVRMRTogR251UEcgRGV0YWlscwojIEdsb2JhbGx5IGRp
+c2FibGUgc3VwZXJzY3JpcHRzIGFuZCBzdWJzY3JpcHRzOgojK09QVElPTlM6IF46
+e30KIwoKIyBOb3RlOiBUaGlzIGZpbGUgdXNlcyBvcmctbW9kZTsgaXQgc2hvdWxk
+IGJlIGVhc3kgdG8gcmVhZCBhcyBwbGFpbgojIHRleHQgYnV0IGJlIGF3YXJlIG9m
+IHNvbWUgbWFya3VwIHBlY3VsaWFyaXRpZXM6IFZlcmJhdGltIGNvZGUgaXMKIyBl
+bmNsb3NlZCBpbiAjK2JlZ2luLWV4YW1wbGUsICMrZW5kLWV4YW1wbGUgYmxvY2tz
+IG9yIG1hcmtlZCBieSBhCiMgY29sb24gYXMgdGhlIGZpcnN0IG5vbi13aGl0ZS1z
+cGFjZSBjaGFyYWN0ZXIsIHdvcmRzIGJyYWNrZXRlZCB3aXRoCiMgZXF1YWwgc2ln
+bnMgaW5kaWNhdGUgYSBtb25vc3BhY2UgZm9udCwgYW5kIHRoZSB1c3VhbCAvaXRh
+bGljcy8sCiMgKmJvbGQqLCBhbmQgX3VuZGVybGluZV8gY29udmVudGlvbnMgYXJl
+IHJlY29nbml6ZWQuCgpUaGlzIGlzIHRoZSBERVRBSUxTIGZpbGUgZm9yIEdudVBH
+IHdoaWNoIHNwZWNpZmllcyBzb21lIGludGVybmFscyBhbmQKcGFydHMgb2YgdGhl
+IGV4dGVybmFsIEFQSSBmb3IgR1BHIGFuZCBHUEdTTS4KCiogRm9ybWF0IG9mIHRo
+ZSBjb2xvbiBsaXN0aW5ncwogIFRoZSBmb3JtYXQgaXMgYSBiYXNlZCBvbiBjb2xv
+biBzZXBhcmF0ZWQgcmVjb3JkLCBlYWNoIHJlY29kcyBzdGFydHMKICB3aXRoIGEg
+dGFnIHN0cmluZyBhbmQgZXh0ZW5kcyB0byB0aGUgZW5kIG9mIHRoZSBsaW5lLiAg
+SGVyZSBpcyBhbgogIGV4YW1wbGU6CiMrYmVnaW5fZXhhbXBsZQokIGdwZyAtLXdp
+dGgtY29sb25zIC0tbGlzdC1rZXlzIFwKICAgICAgLS13aXRoLWZpbmdlcnByaW50
+IC0td2l0aC1maW5nZXJwcmludCB3a0BnbnVwZy5vcmcKcHViOmY6MTAyNDoxNzo2
+QzdFRTFCODYyMUNDMDEzOjg5OTgxNzcxNToxMDU1ODk4MjM1OjptOjo6c2NFU0M6
+CmZwcjo6Ojo6Ojo6OkVDQUY3NTkwRUIzNDQzQjVDN0NGM0FDQjZDN0VFMUI4NjIx
+Q0MwMTM6CnVpZDpmOjo6Ojo6OjpXZXJuZXIgS29jaCA8d2tAZzEwY29kZS5jb20+
+Ogp1aWQ6Zjo6Ojo6Ojo6V2VybmVyIEtvY2ggPHdrQGdudXBnLm9yZz46CnN1Yjpm
+OjE1MzY6MTY6MDZBRDIyMkNBREY2QTZFMTo5MTk1Mzc0MTY6MTAzNjE3NzQxNjo6
+Ojo6ZToKZnByOjo6Ojo6Ojo6Q0Y4QkNDNEIxOERFMDhGQ0Q4QTE2MTU5MDZBRDIy
+MkNBREY2QTZFMToKc3ViOnI6MTUzNjoyMDo1Q0UwODZCNUI1QTE4RkY0Ojg5OTgx
+Nzc4ODoxMDI1OTYxNzg4Ojo6Ojplc2M6CmZwcjo6Ojo6Ojo6OkFCMDU5MzU5QTNC
+ODFGNDEwRkNGRjk3RjVDRTA4NkI1QjVBMThGRjQ6CiMrZW5kX2V4YW1wbGUKClRo
+ZSBkb3VibGUgPS0td2l0aC1maW5nZXJwcmludD0gcHJpbnRzIHRoZSBmaW5nZXJw
+cmludCBmb3IgdGhlIHN1YmtleXMKdG9vLiAgT2xkIHZlcnNpb25zIG9mIGdwZyB1
+c2VkIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdCBhbmQgcmVxdWlyZWQKdGhl
+IHVzZSBvZiB0aGUgb3B0aW9uID0tLWZpeGVkLWxpc3QtbW9kZT0gdG8gY29uZm9y
+bSB0byB0aGUgZm9ybWF0CmRlc2NyaWJlZCBoZXJlLgoKKiogRGVzY3JpcHRpb24g
+b2YgdGhlIGZpZWxkcwoqKiogRmllbGQgMSAtIFR5cGUgb2YgcmVjb3JkCgogICAg
+LSBwdWIgOjogUHVibGljIGtleQogICAgLSBjcnQgOjogWC41MDkgY2VydGlmaWNh
+dGUKICAgIC0gY3JzIDo6IFguNTA5IGNlcnRpZmljYXRlIGFuZCBwcml2YXRlIGtl
+eSBhdmFpbGFibGUKICAgIC0gc3ViIDo6IFN1YmtleSAoc2Vjb25kYXJ5IGtleSkK
+ICAgIC0gc2VjIDo6IFNlY3JldCBrZXkKICAgIC0gc3NiIDo6IFNlY3JldCBzdWJr
+ZXkgKHNlY29uZGFyeSBrZXkpCiAgICAtIHVpZCA6OiBVc2VyIGlkIChvbmx5IGZp
+ZWxkIDEwIGlzIHVzZWQpLgogICAgLSB1YXQgOjogVXNlciBhdHRyaWJ1dGUgKHNh
+bWUgYXMgdXNlciBpZCBleGNlcHQgZm9yIGZpZWxkIDEwKS4KICAgIC0gc2lnIDo6
+IFNpZ25hdHVyZQogICAgLSByZXYgOjogUmV2b2NhdGlvbiBzaWduYXR1cmUKICAg
+IC0gZnByIDo6IEZpbmdlcnByaW50IChmaW5nZXJwcmludCBpcyBpbiBmaWVsZCAx
+MCkKICAgIC0gcGtkIDo6IFB1YmxpYyBrZXkgZGF0YSBbKl0KICAgIC0gZ3JwIDo6
+IEtleWdyaXAKICAgIC0gcnZrIDo6IFJldm9jYXRpb24ga2V5CiAgICAtIHRydSA6
+OiBUcnVzdCBkYXRhYmFzZSBpbmZvcm1hdGlvbiBbKl0KICAgIC0gc3BrIDo6IFNp
+Z25hdHVyZSBzdWJwYWNrZXQgWypdCiAgICAtIGNmZyA6OiBDb25maWd1cmF0aW9u
+IGRhdGEgWypdCgogICAgUmVjb3JkcyBtYXJrZWQgd2l0aCBhbiBhc3RlcmlzayBh
+cmUgZGVzY3JpYmVkIGF0IFtbKlNwZWNpYWwlMjBmaWVsZCUyMGZvcm1hdHNdWypT
+cGVjaWFsIGZpZWxkc11dLgoKKioqIEZpZWxkIDIgLSBWYWxpZGl0eQoKICAgIFRo
+aXMgaXMgYSBsZXR0ZXIgZGVzY3JpYmluZyB0aGUgY29tcHV0ZWQgdmFsaWRpdHkg
+b2YgYSBrZXkuCiAgICBDdXJyZW50bHkgdGhpcyBpcyBhIHNpbmdsZSBsZXR0ZXIs
+IGJ1dCBiZSBwcmVwYXJlZCB0aGF0IGFkZGl0aW9uYWwKICAgIGluZm9ybWF0aW9u
+IG1heSBmb2xsb3cgaW4gc29tZSBmdXR1cmUgdmVyc2lvbnMuIE5vdGUgdGhhdCBH
+bnVQRyA8CiAgICAyLjEgZG9lcyBub3Qgc2V0IHRoaXMgZmllbGQgZm9yIHNlY3Jl
+dCBrZXkgbGlzdGluZ3MuCgogICAgLSBvIDo6IFVua25vd24gKHRoaXMga2V5IGlz
+IG5ldyB0byB0aGUgc3lzdGVtKQogICAgLSBpIDo6IFRoZSBrZXkgaXMgaW52YWxp
+ZCAoZS5nLiBkdWUgdG8gYSBtaXNzaW5nIHNlbGYtc2lnbmF0dXJlKQogICAgLSBk
+IDo6IFRoZSBrZXkgaGFzIGJlZW4gZGlzYWJsZWQKCSAgIChkZXByZWNhdGVkIC0g
+dXNlIHRoZSAnRCcgaW4gZmllbGQgMTIgaW5zdGVhZCkKICAgIC0gciA6OiBUaGUg
+a2V5IGhhcyBiZWVuIHJldm9rZWQKICAgIC0gZSA6OiBUaGUga2V5IGhhcyBleHBp
+cmVkCiAgICAtIC0gOjogVW5rbm93biB2YWxpZGl0eSAoaS5lLiBubyB2YWx1ZSBh
+c3NpZ25lZCkKICAgIC0gcSA6OiBVbmRlZmluZWQgdmFsaWRpdHkuICAnLScgYW5k
+ICdxJyBtYXkgc2FmZWx5IGJlIHRyZWF0ZWQgYXMKICAgICAgICAgICB0aGUgc2Ft
+ZSB2YWx1ZSBmb3IgbW9zdCBwdXJwb3NlcwogICAgLSBuIDo6IFRoZSBrZXkgaXMg
+bm90IHZhbGlkCiAgICAtIG0gOjogVGhlIGtleSBpcyBtYXJnaW5hbCB2YWxpZC4K
+ICAgIC0gZiA6OiBUaGUga2V5IGlzIGZ1bGx5IHZhbGlkCiAgICAtIHUgOjogVGhl
+IGtleSBpcyB1bHRpbWF0ZWx5IHZhbGlkLiAgVGhpcyBvZnRlbiBtZWFucyB0aGF0
+IHRoZQogICAgICAgICAgIHNlY3JldCBrZXkgaXMgYXZhaWxhYmxlLCBidXQgYW55
+IGtleSBtYXkgYmUgbWFya2VkIGFzCiAgICAgICAgICAgdWx0aW1hdGVseSB2YWxp
+ZC4KICAgIC0gdyA6OiBUaGUga2V5IGhhcyBhIHdlbGwga25vd24gcHJpdmF0ZSBw
+YXJ0LgogICAgLSBzIDo6IFRoZSBrZXkgaGFzIHNwZWNpYWwgdmFsaWRpdHkuICBU
+aGlzIG1lYW5zIHRoYXQgaXQgbWlnaHQgYmUKICAgICAgICAgICBzZWxmLXNpZ25l
+ZCBhbmQgZXhwZWN0ZWQgdG8gYmUgdXNlZCBpbiB0aGUgU1RFRUQgc3l0ZW0uCgog
+ICAgSWYgdGhlIHZhbGlkaXR5IGluZm9ybWF0aW9uIGlzIGdpdmVuIGZvciBhIFVJ
+RCBvciBVQVQgcmVjb3JkLCBpdAogICAgZGVzY3JpYmVzIHRoZSB2YWxpZGl0eSBj
+YWxjdWxhdGVkIGJhc2VkIG9uIHRoaXMgdXNlciBJRC4gIElmIGdpdmVuCiAgICBm
+b3IgYSBrZXkgcmVjb3JkIGl0IGRlc2NyaWJlcyB0aGUgdmFsaWRpdHkgdGFrZW4g
+ZnJvbSB0aGUgYmVzdAogICAgcmF0ZWQgdXNlciBJRC4KCiAgICBGb3IgWC41MDkg
+Y2VydGlmaWNhdGVzIGEgJ3UnIGlzIHVzZWQgZm9yIGEgdHJ1c3RlZCByb290CiAg
+ICBjZXJ0aWZpY2F0ZSAoaS5lLiBmb3IgdGhlIHRydXN0IGFuY2hvcikgYW5kIGFu
+ICdmJyBmb3IgYWxsIG90aGVyCiAgICB2YWxpZCBjZXJ0aWZpY2F0ZXMuCgoqKiog
+RmllbGQgMyAtIEtleSBsZW5ndGgKCiAgICBUaGUgbGVuZ3RoIG9mIGtleSBpbiBi
+aXRzLgoKKioqIEZpZWxkIDQgLSBQdWJsaWMga2V5IGFsZ29yaXRobQoKICAgIFRo
+ZSB2YWx1ZXMgaGVyZSBhcmUgdGhvc2UgZnJvbSB0aGUgT3BlblBHUCBzcGVjcyBv
+ciBpZiB0aGV5IGFyZQogICAgZ3JlYXRoZXIgdGhhbiAyNTUgdGhlIGFsZ29yaXRo
+bSBpZHMgYXMgdXNlZCBieSBMaWJnY3J5cHQuCgoqKiogRmllbGQgNSAtIEtleUlE
+CgogICAgVGhpcyBpcyB0aGUgNjQgYml0IGtleWlkIGFzIHNwZWNpZmllZCBieSBP
+cGVuUEdQIGFuZCB0aGUgbGFzdCA2NAogICAgYml0IG9mIHRoZSBTSEEtMSBmaW5n
+ZXJwcmludCBvZiBhbiBYLjUwOSBjZXJ0aWZjaWF0ZS4KCioqKiBGaWVsZCA2IC0g
+Q3JlYXRpb24gZGF0ZQoKICAgIFRoZSBjcmVhdGlvbiBkYXRlIG9mIHRoZSBrZXkg
+aXMgZ2l2ZW4gaW4gVVRDLiAgRm9yIFVJRCBhbmQgVUFUCiAgICByZWNvcmRzLCB0
+aGlzIGlzIHVzZWQgZm9yIHRoZSBzZWxmLXNpZ25hdHVyZSBkYXRlLiAgTm90ZSB0
+aGF0IHRoZQogICAgZGF0ZSBpcyB1c2FsbHkgcHJpbnRlZCBpbiBzZWNvbmRzIHNp
+bmNlIGVwb2NoLCBob3dldmVyLCB3ZSBhcmUKICAgIG1pZ3JhdGluZyB0byBhbiBJ
+U08gODYwMSBmb3JtYXQgKGUuZy4gIjE5NjYwMjA1VDA5MTUwMCIpLiAgVGhpcyBp
+cwogICAgY3VycmVudGx5IG9ubHkgcmVsZXZhbnQgZm9yIFguNTA5LiAgQSBzaW1w
+bGUgd2F5IHRvIGRldGVjdCB0aGUgbmV3CiAgICBmb3JtYXQgaXMgdG8gc2NhbiBm
+b3IgdGhlICdUJy4gIE5vdGUgdGhhdCBvbGQgdmVyc2lvbnMgb2YgZ3BnCiAgICB3
+aXRob3V0IHVzaW5nIHRoZSA9LS1maXhlZC1saXN0LW1vZGU9IG9wdGlvbiB1c2Vk
+IGEgInl5eXktbW0tdHQiCiAgICBmb3JtYXQuCgoqKiogRmllbGQgNyAtIEV4cGly
+YXRpb24gZGF0ZQoKICAgIEtleSBvciBVSUQvVUFUIGV4cGlyYXRpb24gZGF0ZSBv
+ciBlbXB0eSBpZiBpdCBkb2VzIG5vdCBleHBpcmUuCgoqKiogRmllbGQgOCAtIENl
+cnRpZmljYXRlIFMvTiwgVUlEIGhhc2gsIHRydXN0IHNpZ25hdHVyZSBpbmZvCgog
+ICAgVXNlZCBmb3Igc2VyaWFsIG51bWJlciBpbiBjcnQgcmVjb3Jkcy4gIEZvciBV
+SUQgYW5kIFVBVCByZWNvcmRzLAogICAgdGhpcyBpcyBhIGhhc2ggb2YgdGhlIHVz
+ZXIgSUQgY29udGVudHMgdXNlZCB0byByZXByZXNlbnQgdGhhdAogICAgZXhhY3Qg
+dXNlciBJRC4gIEZvciB0cnVzdCBzaWduYXR1cmVzLCB0aGlzIGlzIHRoZSB0cnVz
+dCBkZXB0aAogICAgc2VwZXJhdGVkIGJ5IHRoZSB0cnVzdCB2YWx1ZSBieSBhIHNw
+YWNlLgoKKioqIEZpZWxkIDkgLSAgT3duZXJ0cnVzdAoKICAgIFRoaXMgaXMgb25s
+eSB1c2VkIG9uIHByaW1hcnkga2V5cy4gIFRoaXMgaXMgYSBzaW5nbGUgbGV0dGVy
+LCBidXQKICAgIGJlIHByZXBhcmVkIHRoYXQgYWRkaXRpb25hbCBpbmZvcm1hdGlv
+biBtYXkgZm9sbG93IGluIGZ1dHVyZQogICAgdmVyc2lvbnMuICBGb3IgdHJ1c3Qg
+c2lnbmF0dXJlcyB3aXRoIGEgcmVndWxhciBleHByZXNzaW9uLCB0aGlzIGlzCiAg
+ICB0aGUgcmVndWxhciBleHByZXNzaW9uIHZhbHVlLCBxdW90ZWQgYXMgaW4gZmll
+bGQgMTAuCgoqKiogRmllbGQgMTAgLSBVc2VyLUlECiAgICBUaGUgdmFsdWUgaXMg
+cXVvdGVkIGxpa2UgYSBDIHN0cmluZyB0byBhdm9pZCBjb250cm9sIGNoYXJhY3Rl
+cnMKICAgICh0aGUgY29sb24gaXMgcXVvdGVkID1ceDNhPSkuICBGb3IgYSAicHVi
+IiByZWNvcmQgdGhpcyBmaWVsZCBpcwogICAgbm90IHVzZWQgb24gLS1maXhlZC1s
+aXN0LW1vZGUuICBBIFVBVCByZWNvcmQgcHV0cyB0aGUgYXR0cmlidXRlCiAgICBz
+dWJwYWNrZXQgY291bnQgaGVyZSwgYSBzcGFjZSwgYW5kIHRoZW4gdGhlIHRvdGFs
+IGF0dHJpYnV0ZQogICAgc3VicGFja2V0IHNpemUuICBJbiBncGdzbSB0aGUgaXNz
+dWVyIG5hbWUgY29tZXMgaGVyZS4gIEEgRlBSCiAgICByZWNvcmQgc3RvcmVzIHRo
+ZSBmaW5nZXJwcmludCBoZXJlLiAgVGhlIGZpbmdlcnByaW50IG9mIGEKICAgIHJl
+dm9jYXRpb24ga2V5IGlzIHN0b3JlZCBoZXJlLgoqKiogRmllbGQgMTEgLSBTaWdu
+YXR1cmUgY2xhc3MKCiAgICBTaWduYXR1cmUgY2xhc3MgYXMgcGVyIFJGQy00ODgw
+LiAgVGhpcyBpcyBhIDIgZGlnaXQgaGV4bnVtYmVyCiAgICBmb2xsb3dlZCBieSBl
+aXRoZXIgdGhlIGxldHRlciAneCcgZm9yIGFuIGV4cG9ydGFibGUgc2lnbmF0dXJl
+IG9yCiAgICB0aGUgbGV0dGVyICdsJyBmb3IgYSBsb2NhbC1vbmx5IHNpZ25hdHVy
+ZS4gIFRoZSBjbGFzcyBieXRlIG9mIGFuCiAgICByZXZvY2F0aW9uIGtleSBpcyBh
+bHNvIGdpdmVuIGhlcmUsICd4JyBhbmQgJ2wnIGlzIHVzZWQgdGhlIHNhbWUKICAg
+IHdheS4gIFRoaXMgZmllbGQgaWYgbm90IHVzZWQgZm9yIFguNTA5LgoKKioqIEZp
+ZWxkIDEyIC0gS2V5IGNhcGFiaWxpdGllcwoKICAgIFRoZSBkZWZpbmVkIGNhcGFi
+aWxpdGllcyBhcmU6CgogICAgLSBlIDo6IEVuY3J5cHQKICAgIC0gcyA6OiBTaWdu
+CiAgICAtIGMgOjogQ2VydGlmeQogICAgLSBhIDo6IEF1dGhlbnRpY2F0aW9uCiAg
+ICAtID8gOjogVW5rbm93biBjYXBhYmlsaXR5CgogICAgQSBrZXkgbWF5IGhhdmUg
+YW55IGNvbWJpbmF0aW9uIG9mIHRoZW0gaW4gYW55IG9yZGVyLiAgSW4gYWRkaXRp
+b24KICAgIHRvIHRoZXNlIGxldHRlcnMsIHRoZSBwcmltYXJ5IGtleSBoYXMgdXBw
+ZXJjYXNlIHZlcnNpb25zIG9mIHRoZQogICAgbGV0dGVycyB0byBkZW5vdGUgdGhl
+IF91c2FibGVfIGNhcGFiaWxpdGllcyBvZiB0aGUgZW50aXJlIGtleSwgYW5kCiAg
+ICBhIHBvdGVudGlhbCBsZXR0ZXIgJ0QnIHRvIGluZGljYXRlIGEgZGlzYWJsZWQg
+a2V5LgoKKioqIEZpZWxkIDEzIC0gSXNzdWVyIGNlcnRpZmljYXRlIGZpbmdlcnBy
+aW50IG9yIG90aGVyIGluZm8KCiAgICBVc2VkIGluIEZQUiByZWNvcmRzIGZvciBT
+L01JTUUga2V5cyB0byBzdG9yZSB0aGUgZmluZ2VycHJpbnQgb2YKICAgIHRoZSBp
+c3N1ZXIgY2VydGlmaWNhdGUuICBUaGlzIGlzIHVzZWZ1bCB0byBidWlsZCB0aGUg
+Y2VydGlmaWNhdGUKICAgIHBhdGggYmFzZWQgb24gY2VydGlmaWNhdGVzIHN0b3Jl
+ZCBpbiB0aGUgbG9jYWwga2V5IGRhdGFiYXNlIGl0IGlzCiAgICBvbmx5IGZpbGxl
+ZCBpZiB0aGUgaXNzdWVyIGNlcnRpZmljYXRlIGlzIGF2YWlsYWJsZS4gVGhlIHJv
+b3QgaGFzCiAgICBiZWVuIHJlYWNoZWQgaWYgdGhpcyBpcyB0aGUgc2FtZSBzdHJp
+bmcgYXMgdGhlIGZpbmdlcnByaW50LiBUaGUKICAgIGFkdmFudGFnZSBvZiB1c2lu
+ZyB0aGlzIHZhbHVlIGlzIHRoYXQgaXQgaXMgZ3VhcmFudGVlZCB0byBoYXZlCiAg
+ICBiZWVuIGJlZW4gYnVpbGQgYnkgdGhlIHNhbWUgbG9va3VwIGFsZ29yaXRobSBh
+cyBncGdzbSB1c2VzLgoKICAgIEZvciAidWlkIiByZWNvcmRzIHRoaXMgZmllbGQg
+bGlzdHMgdGhlIHByZWZlcmVuY2VzIGluIHRoZSBzYW1lIHdheQogICAgZ3BnJ3Mg
+LS1lZGl0LWtleSBtZW51IGRvZXMuCgogICAgRm9yICJzaWciIHJlY29yZHMsIHRo
+aXMgaXMgdGhlIGZpbmdlcnByaW50IG9mIHRoZSBrZXkgdGhhdCBpc3N1ZWQKICAg
+IHRoZSBzaWduYXR1cmUuICBOb3RlIHRoYXQgdGhpcyBpcyBvbmx5IGZpbGxlZCBp
+biBpZiB0aGUgc2lnbmF0dXJlCiAgICB2ZXJpZmllZCBjb3JyZWN0bHkuICBOb3Rl
+IGFsc28gdGhhdCBmb3IgdmFyaW91cyB0ZWNobmljYWwgcmVhc29ucywKICAgIHRo
+aXMgZmluZ2VycHJpbnQgaXMgb25seSBhdmFpbGFibGUgaWYgLS1uby1zaWctY2Fj
+aGUgaXMgdXNlZC4KCioqKiBGaWVsZCAxNCAtIEZsYWcgZmllbGQKCiAgICBGbGFn
+IGZpZWxkIHVzZWQgaW4gdGhlIC0tZWRpdCBtZW51IG91dHB1dAoKKioqIEZpZWxk
+IDE1IC0gUy9OIG9mIGEgdG9rZW4KCiAgICBVc2VkIGluIHNlYy9zc2IgdG8gcHJp
+bnQgdGhlIHNlcmlhbCBudW1iZXIgb2YgYSB0b2tlbiAoaW50ZXJuYWwKICAgIHBy
+b3RlY3QgbW9kZSAxMDAyKSBvciBhICcjJyBpZiB0aGF0IGtleSBpcyBhIHNpbXBs
+ZSBzdHViIChpbnRlcm5hbAogICAgcHJvdGVjdCBtb2RlIDEwMDEpLiAgSWYgdGhl
+IG9wdGlvbiAtLXdpdGgtc2VjcmV0IGlzIHVzZWQgYW5kIGEKICAgIHNlY3JldCBr
+ZXkgaXMgYXZhaWxhYmxlIGZvciB0aGUgcHVibGljIGtleSwgYSAnKycgaW5kaWNh
+dGVzIHRoaXMuCgoqKiogRmllbGQgMTYgLSBIYXNoIGFsZ29yaXRobQoKICAgIEZv
+ciBzaWcgcmVjb3JkcywgdGhpcyBpcyB0aGUgdXNlZCBoYXNoIGFsZ29yaXRobS4g
+IEZvciBleGFtcGxlOgogICAgMiA9IFNIQS0xLCA4ID0gU0hBLTI1Ni4KCioqKiBG
+aWVsZCAxNyAtIEN1cnZlIG5hbWUKCiAgICBGb3IgcHViLCBzdWIsIHNlYywgYW5k
+IHNzYiByZWNvcmRzIHRoaXMgZmllbGQgaXMgdXNlZCBmb3IgdGhlIEVDQwogICAg
+Y3VydmUgbmFtZS4KKioqIEZpZWxkIDE4IC0gVE9GVSBQb2xpY3kKCiAgICBUaGlz
+IGlzIHRoZSBUT0ZVIHBvbGljeS4gIEl0IGlzIGVpdGhlciBnb29kLCBiYWQsIHVu
+a25vd24sIGFzayBvcgogICAgYXV0by4gIFRoaXMgaXMgb25seSBzaG93cyBmb3Ig
+dWlkIHJlY29yZHMuCgoqKiBTcGVjaWFsIGZpZWxkcwoKKioqIFBLRCAtIFB1Ymxp
+YyBrZXkgZGF0YQoKICAgIElmIGZpZWxkIDEgaGFzIHRoZSB0YWcgInBrZCIsIGEg
+bGlzdGluZyBsb29rcyBsaWtlIHRoaXM6CiMrYmVnaW5fZXhhbXBsZQpwa2Q6MDox
+MDI0OkI2NjVCMTQzNUY0QzIgLi4uLiBGRjI2QUJCOgogICAgISAgISAgICEtLSB0
+aGUgdmFsdWUKICAgICEgICEtLS0tLS0gZm9yIGluZm9ybWF0aW9uIG51bWJlciBv
+ZiBiaXRzIGluIHRoZSB2YWx1ZQogICAgIS0tLS0tLS0tLSBpbmRleCAoZWcuIERT
+QSBnb2VzIGZyb20gMCB0byAzOiBwLHEsZyx5KQojK2VuZF9leGFtcGxlCgoqKiog
+VFJVIC0gVHJ1c3QgZGF0YWJhc2UgaW5mb3JtYXRpb24KICAgIEV4YW1wbGUgZm9y
+IGEgInRydSIgdHJ1c3QgYmFzZSByZWNvcmQ6CiMrYmVnaW5fZXhhbXBsZQogICAg
+dHJ1Om86MDoxMTY2Njk3NjU0OjE6MzoxOjUKIytlbmRfZXhhbXBsZQoKICAgIC0g
+RmllbGQgMiA6OiBSZWFzb24gZm9yIHN0YWxlbmVzcyBvZiB0cnVzdC4gIElmIHRo
+aXMgZmllbGQgaXMKICAgICAgICAgICAgICAgICBlbXB0eSwgdGhlbiB0aGUgdHJ1
+c3RkYiBpcyBub3Qgc3RhbGUuICBUaGlzIGZpZWxkIG1heQogICAgICAgICAgICAg
+ICAgIGhhdmUgbXVsdGlwbGUgZmxhZ3MgaW4gaXQ6CgogICAgICAgICAgICAgICAg
+IC0gbyA6OiBUcnVzdGRiIGlzIG9sZAogICAgICAgICAgICAgICAgIC0gdCA6OiBU
+cnVzdGRiIHdhcyBidWlsdCB3aXRoIGEgZGlmZmVyZW50IHRydXN0IG1vZGVsCiAg
+ICAgICAgICAgICAgICAgICAgICAgIHRoYW4gdGhlIG9uZSB3ZSBhcmUgdXNpbmcg
+bm93LgoKICAgIC0gRmllbGQgMyA6OiBUcnVzdCBtb2RlbAoKICAgICAgICAgICAg
+ICAgICAtIDAgOjogQ2xhc3NpYyB0cnVzdCBtb2RlbCwgYXMgdXNlZCBpbiBQR1Ag
+Mi54LgogICAgICAgICAgICAgICAgIC0gMSA6OiBQR1AgdHJ1c3QgbW9kZWwsIGFz
+IHVzZWQgaW4gUEdQIDYgYW5kIGxhdGVyLgogICAgICAgICAgICAgICAgICAgICAg
+ICBUaGlzIGlzIHRoZSBzYW1lIGFzIHRoZSBjbGFzc2ljIHRydXN0IG1vZGVsLAog
+ICAgICAgICAgICAgICAgICAgICAgICBleGNlcHQgZm9yIHRoZSBhZGRpdGlvbiBv
+ZiB0cnVzdCBzaWduYXR1cmVzLgoKICAgICAgICAgICAgICAgICBHbnVQRyBiZWZv
+cmUgdmVyc2lvbiAxLjQgdXNlZCB0aGUgY2xhc3NpYyB0cnVzdCBtb2RlbAogICAg
+ICAgICAgICAgICAgIGJ5IGRlZmF1bHQuIEdudVBHIDEuNCBhbmQgbGF0ZXIgdXNl
+cyB0aGUgUEdQIHRydXN0CiAgICAgICAgICAgICAgICAgbW9kZWwgYnkgZGVmYXVs
+dC4KCiAgICAtIEZpZWxkIDQgOjogRGF0ZSB0cnVzdGRiIHdhcyBjcmVhdGVkIGlu
+IHNlY29uZHMgc2luY2UgRXBvY2guCiAgICAtIEZpZWxkIDUgOjogRGF0ZSB0cnVz
+dGRiIHdpbGwgZXhwaXJlIGluIHNlY29uZHMgc2luY2UgRXBvY2guCiAgICAtIEZp
+ZWxkIDYgOjogTnVtYmVyIG9mIG1hcmdpbmFsbHkgdHJ1c3RlZCB1c2VycyB0byBp
+bnRyb2R1Y2UgYSBuZXcKICAgICAgICAgICAgICAgICBrZXkgc2lnbmVyIChncGcn
+cyBvcHRpb24gLS1tYXJnaW5hbHMtbmVlZGVkKS4KICAgIC0gRmllbGQgNyA6OiBO
+dW1iZXIgb2YgY29tcGxldGVseSB0cnVzdGVkIHVzZXJzIHRvIGludHJvZHVjZSBh
+IG5ldwogICAgICAgICAgICAgICAgIGtleSBzaWduZXIuICAoZ3BnJ3Mgb3B0aW9u
+IC0tY29tcGxldGVzLW5lZWRlZCkKCiAgICAtIEZpZWxkIDggOjogTWF4aW11bSBk
+ZXB0aCBvZiBhIGNlcnRpZmljYXRpb24gY2hhaW4uIChncGcncyBvcHRpb24KICAg
+ICAgICAgICAgICAgICAtLW1heC1jZXJ0LWRlcHRoKQoKKioqIFNQSyAtIFNpZ25h
+dHVyZSBzdWJwYWNrZXQgcmVjb3JkcwoKICAgIC0gRmllbGQgMiA6OiBTdWJwYWNr
+ZXQgbnVtYmVyIGFzIHBlciBSRkMtNDg4MCBhbmQgbGF0ZXIuCiAgICAtIEZpZWxk
+IDMgOjogRmxhZ3MgaW4gaGV4LiAgQ3VycmVudGx5IHRoZSBvbmx5IHR3byBiaXRz
+IGFzc2lnbmVkCiAgICAgICAgICAgICAgICAgYXJlIDEsIHRvIGluZGljYXRlIHRo
+YXQgdGhlIHN1YnBhY2tldCBjYW1lIGZyb20gdGhlCiAgICAgICAgICAgICAgICAg
+aGFzaGVkIHBhcnQgb2YgdGhlIHNpZ25hdHVyZSwgYW5kIDIsIHRvIGluZGljYXRl
+IHRoZQogICAgICAgICAgICAgICAgIHN1YnBhY2tldCB3YXMgbWFya2VkIGNyaXRp
+Y2FsLgogICAgLSBGaWVsZCA0IDo6IExlbmd0aCBvZiB0aGUgc3VicGFja2V0LiAg
+Tm90ZSB0aGF0IHRoaXMgaXMgdGhlCiAgICAgICAgICAgICAgICAgbGVuZ3RoIG9m
+IHRoZSBzdWJwYWNrZXQsIGFuZCBub3QgdGhlIGxlbmd0aCBvZiBmaWVsZAogICAg
+ICAgICAgICAgICAgIDUgYmVsb3cuICBEdWUgdG8gdGhlIG5lZWQgZm9yICUtZW5j
+b2RpbmcsIHRoZSBsZW5ndGgKICAgICAgICAgICAgICAgICBvZiBmaWVsZCA1IG1h
+eSBiZSB1cCB0byAzeCB0aGlzIHZhbHVlLgogICAgLSBGaWVsZCA1IDo6IFRoZSBz
+dWJwYWNrZXQgZGF0YS4gIFByaW50YWJsZSBBU0NJSSBpcyBzaG93biBhcwogICAg
+ICAgICAgICAgICAgIEFTQ0lJLCBidXQgb3RoZXIgdmFsdWVzIGFyZSByZW5kZXJl
+ZCBhcyAlWFggd2hlcmUgWFgKICAgICAgICAgICAgICAgICBpcyB0aGUgaGV4IHZh
+bHVlIGZvciB0aGUgYnl0ZS4KCioqKiBDRkcgLSBDb25maWd1cmF0aW9uIGRhdGEK
+CiAgICAtLWxpc3QtY29uZmlnIG91dHB1dHMgaW5mb3JtYXRpb24gYWJvdXQgdGhl
+IEdudVBHIGNvbmZpZ3VyYXRpb24KICAgIGZvciB0aGUgYmVuZWZpdCBvZiBmcm9u
+dGVuZHMgb3Igb3RoZXIgcHJvZ3JhbXMgdGhhdCBjYWxsIEdudVBHLgogICAgVGhl
+cmUgYXJlIHNldmVyYWwgbGlzdC1jb25maWcgaXRlbXMsIGFsbCBjb2xvbiBkZWxp
+bWl0ZWQgbGlrZSB0aGUKICAgIHJlc3Qgb2YgdGhlIC0td2l0aC1jb2xvbnMgb3V0
+cHV0LiAgVGhlIGZpcnN0IGZpZWxkIGlzIGFsd2F5cyAiY2ZnIgogICAgdG8gaW5k
+aWNhdGUgY29uZmlndXJhdGlvbiBpbmZvcm1hdGlvbi4gIFRoZSBzZWNvbmQgZmll
+bGQgaXMgb25lIG9mCiAgICAod2l0aCBleGFtcGxlcyk6CgogICAgLSB2ZXJzaW9u
+IDo6IFRoZSB0aGlyZCBmaWVsZCBjb250YWlucyB0aGUgdmVyc2lvbiBvZiBHbnVQ
+Ry4KCiAgICAgICAgICAgICAgICAgOiBjZmc6dmVyc2lvbjoxLjMuNQoKICAgIC0g
+cHVia2V5IDo6IFRoZSB0aGlyZCBmaWVsZCBjb250YWlucyB0aGUgcHVibGljIGtl
+eSBhbGdvcml0aG1zCiAgICAgICAgICAgICAgICB0aGlzIHZlcnNpb24gb2YgR251
+UEcgc3VwcG9ydHMsIHNlcGFyYXRlZCBieQogICAgICAgICAgICAgICAgc2VtaWNv
+bG9ucy4gIFRoZSBhbGdvcml0aG0gbnVtYmVycyBhcmUgYXMgc3BlY2lmaWVkIGlu
+CiAgICAgICAgICAgICAgICBSRkMtNDg4MC4gIE5vdGUgdGhhdCBpbiBjb250cmFz
+dCB0byB0aGUgLS1zdGF0dXMtZmQKICAgICAgICAgICAgICAgIGludGVyZmFjZSB0
+aGVzZSBhcmUgX25vdF8gdGhlIExpYmdjcnlwdCBpZGVudGlmaWVycy4KICAgICAg
+ICAgICAgICAgIFVzaW5nID1wdWJrZXluYW1lPSBwcmludHMgbmFtZXMgaW5zdGVh
+ZCBvZiBudW1iZXJzLgoKICAgICAgICAgICAgICAgICA6IGNmZzpwdWJrZXk6MTsy
+OzM7MTY7MTcKCiAgICAtIGNpcGhlciA6OiBUaGUgdGhpcmQgZmllbGQgY29udGFp
+bnMgdGhlIHN5bW1ldHJpYyBjaXBoZXJzIHRoaXMKICAgICAgICAgICAgICAgIHZl
+cnNpb24gb2YgR251UEcgc3VwcG9ydHMsIHNlcGFyYXRlZCBieSBzZW1pY29sb25z
+LgogICAgICAgICAgICAgICAgVGhlIGNpcGhlciBudW1iZXJzIGFyZSBhcyBzcGVj
+aWZpZWQgaW4gUkZDLTQ4ODAuCiAgICAgICAgICAgICAgICBVc2luZyA9Y2lwaGVy
+bmFtZT0gcHJpbnRzIG5hbWVzIGluc3RlYWQgb2YgbnVtYmVycy4KCiAgICAgICAg
+ICAgICAgICAgOiBjZmc6Y2lwaGVyOjI7Mzs0Ozc7ODs5OzEwCgogICAgLSBkaWdl
+c3QgOjogVGhlIHRoaXJkIGZpZWxkIGNvbnRhaW5zIHRoZSBkaWdlc3QgKGhhc2gp
+IGFsZ29yaXRobXMKICAgICAgICAgICAgICAgIHRoaXMgdmVyc2lvbiBvZiBHbnVQ
+RyBzdXBwb3J0cywgc2VwYXJhdGVkIGJ5CiAgICAgICAgICAgICAgICBzZW1pY29s
+b25zLiAgVGhlIGRpZ2VzdCBudW1iZXJzIGFyZSBhcyBzcGVjaWZpZWQgaW4KICAg
+ICAgICAgICAgICAgIFJGQy00ODgwLiAgVXNpbmcgPWRpZ2VzdG5hbWU9IHByaW50
+cyBuYW1lcyBpbnN0ZWFkIG9mCiAgICAgICAgICAgICAgICBudW1iZXJzLgoKICAg
+ICAgICAgICAgICAgICA6IGNmZzpkaWdlc3Q6MTsyOzM7ODs5OzEwCgogICAgLSBj
+b21wcmVzcyA6OiBUaGUgdGhpcmQgZmllbGQgY29udGFpbnMgdGhlIGNvbXByZXNz
+aW9uIGFsZ29yaXRobXMKICAgICAgICAgICAgICAgICAgdGhpcyB2ZXJzaW9uIG9m
+IEdudVBHIHN1cHBvcnRzLCBzZXBhcmF0ZWQgYnkKICAgICAgICAgICAgICAgICAg
+c2VtaWNvbG9ucy4gIFRoZSBhbGdvcml0aG0gbnVtYmVycyBhcmUgYXMgc3BlY2lm
+aWVkCiAgICAgICAgICAgICAgICAgIGluIFJGQy00ODgwLgoKICAgICAgICAgICAg
+ICAgICA6IGNmZzpjb21wcmVzczowOzE7MjszCgogICAgLSBncm91cCA6OiBUaGUg
+dGhpcmQgZmllbGQgY29udGFpbnMgdGhlIG5hbWUgb2YgdGhlIGdyb3VwLCBhbmQg
+dGhlCiAgICAgICAgICAgICAgIGZvdXJ0aCBmaWVsZCBjb250YWlucyB0aGUgdmFs
+dWVzIHRoYXQgdGhlIGdyb3VwIGV4cGFuZHMKICAgICAgICAgICAgICAgdG8sIHNl
+cGFyYXRlZCBieSBzZW1pY29sb25zLgoKICAgICAgICAgICAgICAgRm9yIGV4YW1w
+bGUsIGEgZ3JvdXAgb2Y6CiAgICAgICAgICAgICAgICAgOiBncm91cCBteW5hbWVz
+ID0gcGFpZ2UgMHgxMjM0NTY3OCBqb2UgcGF0dGkKICAgICAgICAgICAgICAgd291
+bGQgcmVzdWx0IGluOgogICAgICAgICAgICAgICAgIDogY2ZnOmdyb3VwOm15bmFt
+ZXM6cGF0dGk7am9lOzB4MTIzNDU2Nzg7cGFpZ2UKCiAgICAtIGN1cnZlIDo6IFRo
+ZSB0aGlyZCBmaWVsZCBjb250YWlucyB0aGUgY3VydmUgbmFtZXMgdGhpcyB2ZXJz
+aW9uCiAgICAgICAgICAgICAgIG9mIEdudVBHIHN1cHBvcnRzLCBzZXBhcmF0ZWQg
+Ynkgc2VtaWNvbG9ucy4gVXNpbmcKICAgICAgICAgICAgICAgPWN1cnZlb2lkPSBw
+cmludHMgT0lEcyBpbnN0ZWFkIG9mIG51bWJlcnMuCgogICAgICAgICAgICAgICAg
+IDogY2ZnOmN1cnZlOmVkMjU1MTk7bmlzdHAyNTY7bmlzdHAzODQ7bmlzdHA1MjEK
+CgoqIEZvcm1hdCBvZiB0aGUgLS1zdGF0dXMtZmQgb3V0cHV0CgogIEV2ZXJ5IGxp
+bmUgaXMgcHJlZml4ZWQgd2l0aCAiW0dOVVBHOl0gIiwgZm9sbG93ZWQgYnkgYSBr
+ZXl3b3JkIHdpdGgKICB0aGUgdHlwZSBvZiB0aGUgc3RhdHVzIGxpbmUgYW5kIHNv
+bWUgYXJndW1lbnRzIGRlcGVuZGluZyBvbiB0aGUgdHlwZQogIChtYXliZSBub25l
+KTsgYW4gYXBwbGljYXRpb24gc2hvdWxkIGFsd2F5cyBiZSBwcmVwYXJlZCB0byBz
+ZWUgbW9yZQogIGFyZ3VtZW50cyBpbiBmdXR1cmUgdmVyc2lvbnMuCgoqKiBHZW5l
+cmFsIHN0YXR1cyBjb2RlcwoqKiogTkVXU0lHCiAgICBJcyBpc3N1ZWQgcmlnaHQg
+YmVmb3JlIGEgc2lnbmF0dXJlIHZlcmlmaWNhdGlvbiBzdGFydHMuICBUaGlzIGlz
+CiAgICB1c2VmdWwgdG8gZGVmaW5lIGEgY29udGV4dCBmb3IgcGFyc2luZyBFUlJP
+UiBzdGF0dXMgbWVzc2FnZXMuICBObwogICAgYXJndW1lbnRzIGFyZSBjdXJyZW50
+bHkgZGVmaW5lZC4KCioqKiBHT09EU0lHICA8bG9uZ19rZXlpZF9vcl9mcHI+ICA8
+dXNlcm5hbWU+CiAgICBUaGUgc2lnbmF0dXJlIHdpdGggdGhlIGtleWlkIGlzIGdv
+b2QuICBGb3IgZWFjaCBzaWduYXR1cmUgb25seSBvbmUKICAgIG9mIHRoZSBjb2Rl
+cyBHT09EU0lHLCBCQURTSUcsIEVYUFNJRywgRVhQS0VZU0lHLCBSRVZLRVlTSUcg
+b3IKICAgIEVSUlNJRyB3aWxsIGJlIGVtaXR0ZWQuICBJbiB0aGUgcGFzdCB0aGV5
+IHdlcmUgdXNlZCBhcyBhIG1hcmtlcgogICAgZm9yIGEgbmV3IHNpZ25hdHVyZTsg
+bmV3IGNvZGUgc2hvdWxkIHVzZSB0aGUgTkVXU0lHIHN0YXR1cwogICAgaW5zdGVh
+ZC4gIFRoZSB1c2VybmFtZSBpcyB0aGUgcHJpbWFyeSBvbmUgZW5jb2RlZCBpbiBV
+VEYtOCBhbmQgJVhYCiAgICBlc2NhcGVkLiBUaGUgZmluZ2VycHJpbnQgbWF5IGJl
+IHVzZWQgaW5zdGVhZCBvZiB0aGUgbG9uZyBrZXlpZCBpZgogICAgaXQgaXMgYXZh
+aWxhYmxlLiAgVGhpcyBpcyB0aGUgY2FzZSB3aXRoIENNUyBhbmQgbWlnaHQgZXZl
+bnR1YWxseQogICAgYWxzbyBiZSBhdmFpbGFibGUgZm9yIE9wZW5QR1AuCgoqKiog
+RVhQU0lHICA8bG9uZ19rZXlpZF9vcl9mcHI+ICA8dXNlcm5hbWU+CiAgICBUaGUg
+c2lnbmF0dXJlIHdpdGggdGhlIGtleWlkIGlzIGdvb2QsIGJ1dCB0aGUgc2lnbmF0
+dXJlIGlzCiAgICBleHBpcmVkLiBUaGUgdXNlcm5hbWUgaXMgdGhlIHByaW1hcnkg
+b25lIGVuY29kZWQgaW4gVVRGLTggYW5kICVYWAogICAgZXNjYXBlZC4gVGhlIGZp
+bmdlcnByaW50IG1heSBiZSB1c2VkIGluc3RlYWQgb2YgdGhlIGxvbmcga2V5aWQg
+aWYKICAgIGl0IGlzIGF2YWlsYWJsZS4gIFRoaXMgaXMgdGhlIGNhc2Ugd2l0aCBD
+TVMgYW5kIG1pZ2h0IGV2ZW50dWFsbHkKICAgIGFsc28gYmUgYXZhaWxhYmxlIGZv
+ciBPcGVuUEdQLgoKKioqIEVYUEtFWVNJRyAgPGxvbmdfa2V5aWRfb3JfZnByPiA8
+dXNlcm5hbWU+CiAgICBUaGUgc2lnbmF0dXJlIHdpdGggdGhlIGtleWlkIGlzIGdv
+b2QsIGJ1dCB0aGUgc2lnbmF0dXJlIHdhcyBtYWRlCiAgICBieSBhbiBleHBpcmVk
+IGtleS4gVGhlIHVzZXJuYW1lIGlzIHRoZSBwcmltYXJ5IG9uZSBlbmNvZGVkIGlu
+CiAgICBVVEYtOCBhbmQgJVhYIGVzY2FwZWQuICBUaGUgZmluZ2VycHJpbnQgbWF5
+IGJlIHVzZWQgaW5zdGVhZCBvZiB0aGUKICAgIGxvbmcga2V5aWQgaWYgaXQgaXMg
+YXZhaWxhYmxlLiAgVGhpcyBpcyB0aGUgY2FzZSB3aXRoIENNUyBhbmQKICAgIG1p
+Z2h0IGV2ZW50dWFsbHkgYWxzbyBiZSBhdmFpbGFibGUgZm9yIE9wZW5QR1AuCgoq
+KiogUkVWS0VZU0lHICA8bG9uZ19rZXlpZF9vcl9mcHI+ICA8dXNlcm5hbWU+CiAg
+ICBUaGUgc2lnbmF0dXJlIHdpdGggdGhlIGtleWlkIGlzIGdvb2QsIGJ1dCB0aGUg
+c2lnbmF0dXJlIHdhcyBtYWRlCiAgICBieSBhIHJldm9rZWQga2V5LiBUaGUgdXNl
+cm5hbWUgaXMgdGhlIHByaW1hcnkgb25lIGVuY29kZWQgaW4gVVRGLTgKICAgIGFu
+ZCAlWFggZXNjYXBlZC4gVGhlIGZpbmdlcnByaW50IG1heSBiZSB1c2VkIGluc3Rl
+YWQgb2YgdGhlIGxvbmcKICAgIGtleWlkIGlmIGl0IGlzIGF2YWlsYWJsZS4gIFRo
+aXMgaXMgdGhlIGNhc2Ugd2l0aCBDTVMgYW5kIG1pZ2h0CiAgICBldmVudHVhbGx5
+IGFsc28gYmXDsSBhdmFpbGFibGUgZm9yIE9wZW5QR1AuCgoqKiogQkFEU0lHICA8
+bG9uZ19rZXlpZF9vcl9mcHI+ICA8dXNlcm5hbWU+CiAgICBUaGUgc2lnbmF0dXJl
+IHdpdGggdGhlIGtleWlkIGhhcyBub3QgYmVlbiB2ZXJpZmllZCBva2F5LiAgVGhl
+CiAgICB1c2VybmFtZSBpcyB0aGUgcHJpbWFyeSBvbmUgZW5jb2RlZCBpbiBVVEYt
+OCBhbmQgJVhYIGVzY2FwZWQuIFRoZQogICAgZmluZ2VycHJpbnQgbWF5IGJlIHVz
+ZWQgaW5zdGVhZCBvZiB0aGUgbG9uZyBrZXlpZCBpZiBpdCBpcwogICAgYXZhaWxh
+YmxlLiAgVGhpcyBpcyB0aGUgY2FzZSB3aXRoIENNUyBhbmQgbWlnaHQgZXZlbnR1
+YWxseSBhbHNvIGJlCiAgICBhdmFpbGFibGUgZm9yIE9wZW5QR1AuCgoqKiogRVJS
+U0lHICA8a2V5aWQ+ICA8cGthbGdvPiA8aGFzaGFsZ28+IDxzaWdfY2xhc3M+IDx0
+aW1lPiA8cmM+CiAgICBJdCB3YXMgbm90IHBvc3NpYmxlIHRvIGNoZWNrIHRoZSBz
+aWduYXR1cmUuICBUaGlzIG1heSBiZSBjYXVzZWQgYnkKICAgIGEgbWlzc2luZyBw
+dWJsaWMga2V5IG9yIGFuIHVuc3VwcG9ydGVkIGFsZ29yaXRobS4gIEEgUkMgb2Yg
+NAogICAgaW5kaWNhdGVzIHVua25vd24gYWxnb3JpdGhtLCBhIDkgaW5kaWNhdGVz
+IGEgbWlzc2luZyBwdWJsaWMKICAgIGtleS4gVGhlIG90aGVyIGZpZWxkcyBnaXZl
+IG1vcmUgaW5mb3JtYXRpb24gYWJvdXQgdGhpcyBzaWduYXR1cmUuCiAgICBzaWdf
+Y2xhc3MgaXMgYSAyIGJ5dGUgaGV4LXZhbHVlLiAgVGhlIGZpbmdlcnByaW50IG1h
+eSBiZSB1c2VkCiAgICBpbnN0ZWFkIG9mIHRoZSBrZXlpZCBpZiBpdCBpcyBhdmFp
+bGFibGUuICBUaGlzIGlzIHRoZSBjYXNlIHdpdGgKICAgIGdwZ3NtIGFuZCBtaWdo
+dCBldmVudHVhbGx5IGFsc28gYmUgYXZhaWxhYmxlIGZvciBPcGVuUEdQLgoKICAg
+IE5vdGUsIHRoYXQgVElNRSBtYXkgZWl0aGVyIGJlIHRoZSBudW1iZXIgb2Ygc2Vj
+b25kcyBzaW5jZSBFcG9jaCBvcgogICAgYW4gSVNPIDg2MDEgc3RyaW5nLiAgVGhl
+IGxhdHRlciBjYW4gYmUgZGV0ZWN0ZWQgYnkgdGhlIHByZXNlbmNlIG9mCiAgICB0
+aGUgbGV0dGVyICdUJy4KCioqKiBWQUxJRFNJRyA8YXJncz4KCiAgICBUaGUgYXJn
+cyBhcmU6CgogICAgLSA8ZmluZ2VycHJpbnRfaW5faGV4PgogICAgLSA8c2lnX2Ny
+ZWF0aW9uX2RhdGU+CiAgICAtIDxzaWctdGltZXN0YW1wPgogICAgLSA8ZXhwaXJl
+LXRpbWVzdGFtcD4KICAgIC0gPHNpZy12ZXJzaW9uPgogICAgLSA8cmVzZXJ2ZWQ+
+CiAgICAtIDxwdWJrZXktYWxnbz4KICAgIC0gPGhhc2gtYWxnbz4KICAgIC0gPHNp
+Zy1jbGFzcz4KICAgIC0gWyA8cHJpbWFyeS1rZXktZnByPiBdCgogICAgVGhpcyBz
+dGF0dXMgaW5kaWNhdGVzIHRoYXQgdGhlIHNpZ25hdHVyZSBpcyBjcnlwdG9ncmFw
+aGljYWxseQogICAgdmFsaWQuIFRoaXMgaXMgc2ltaWxhciB0byBHT09EU0lHLCBF
+WFBTSUcsIEVYUEtFWVNJRywgb3IgUkVWS0VZU0lHCiAgICAoZGVwZW5kaW5nIG9u
+IHRoZSBkYXRlIGFuZCB0aGUgc3RhdGUgb2YgdGhlIHNpZ25hdHVyZSBhbmQgc2ln
+bmluZwogICAga2V5KSBidXQgaGFzIHRoZSBmaW5nZXJwcmludCBhcyB0aGUgYXJn
+dW1lbnQuIE11bHRpcGxlIHN0YXR1cwogICAgbGluZXMgKFZBTElEU0lHIGFuZCB0
+aGUgb3RoZXIgYXBwcm9wcmlhdGUgKlNJRyBzdGF0dXMpIGFyZSBlbWl0dGVkCiAg
+ICBmb3IgYSB2YWxpZCBzaWduYXR1cmUuICBBbGwgYXJndW1lbnRzIGhlcmUgYXJl
+IG9uIG9uZSBsb25nIGxpbmUuCiAgICBzaWctdGltZXN0YW1wIGlzIHRoZSBzaWdu
+YXR1cmUgY3JlYXRpb24gdGltZSBpbiBzZWNvbmRzIGFmdGVyIHRoZQogICAgZXBv
+Y2guIGV4cGlyZS10aW1lc3RhbXAgaXMgdGhlIHNpZ25hdHVyZSBleHBpcmF0aW9u
+IHRpbWUgaW4KICAgIHNlY29uZHMgYWZ0ZXIgdGhlIGVwb2NoICh6ZXJvIG1lYW5z
+ICJkb2VzIG5vdAogICAgZXhwaXJlIikuIHNpZy12ZXJzaW9uLCBwdWJrZXktYWxn
+bywgaGFzaC1hbGdvLCBhbmQgc2lnLWNsYXNzIChhCiAgICAyLWJ5dGUgaGV4IHZh
+bHVlKSBhcmUgYWxsIHN0cmFpZ2h0IGZyb20gdGhlIHNpZ25hdHVyZSBwYWNrZXQu
+CiAgICBQUklNQVJZLUtFWS1GUFIgaXMgdGhlIGZpbmdlcnByaW50IG9mIHRoZSBw
+cmltYXJ5IGtleSBvciBpZGVudGljYWwKICAgIHRvIHRoZSBmaXJzdCBhcmd1bWVu
+dC4gIFRoaXMgaXMgdXNlZnVsIHRvIGdldCBiYWNrIHRvIHRoZSBwcmltYXJ5CiAg
+ICBrZXkgd2l0aG91dCBydW5uaW5nIGdwZyBhZ2FpbiBmb3IgdGhpcyBwdXJwb3Nl
+LgoKICAgIFRoZSBwcmltYXJ5LWtleS1mcHIgcGFyYW1ldGVyIGlzIHVzZWQgZm9y
+IE9wZW5QR1AgYW5kIG5vdAogICAgYXZhaWxhYmxlIGZvciBDTVMgc2lnbmF0dXJl
+cy4gIFRoZSBzaWctdmVyc2lvbiBhcyB3ZWxsIGFzIHRoZSBzaWcKICAgIGNsYXNz
+IGlzIG5vdCBkZWZpbmVkIGZvciBDTVMgYW5kIGN1cnJlbnRseSBzZXQgdG8gMCBh
+bmQgMDAuCgogICAgTm90ZSwgdGhhdCAqLVRJTUVTVEFNUCBtYXkgZWl0aGVyIGJl
+IGEgbnVtYmVyIG9mIHNlY29uZHMgc2luY2UKICAgIEVwb2NoIG9yIGFuIElTTyA4
+NjAxIHN0cmluZyB3aGljaCBjYW4gYmUgZGV0ZWN0ZWQgYnkgdGhlIHByZXNlbmNl
+CiAgICBvZiB0aGUgbGV0dGVyICdUJy4KCioqKiBTSUdfSUQgIDxyYWRpeDY0X3N0
+cmluZz4gIDxzaWdfY3JlYXRpb25fZGF0ZT4gIDxzaWctdGltZXN0YW1wPgogICAg
+VGhpcyBpcyBlbWl0dGVkIG9ubHkgZm9yIHNpZ25hdHVyZXMgb2YgY2xhc3MgMCBv
+ciAxIHdoaWNoIGhhdmUKICAgIGJlZW4gdmVyaWZpZWQgb2theS4gIFRoZSBzdHJp
+bmcgaXMgYSBzaWduYXR1cmUgaWQgYW5kIG1heSBiZSB1c2VkCiAgICBpbiBhcHBs
+aWNhdGlvbnMgdG8gZGV0ZWN0IHJlcGxheSBhdHRhY2tzIG9mIHNpZ25lZCBtZXNz
+YWdlcy4gIE5vdGUKICAgIHRoYXQgb25seSBETFAgYWxnb3JpdGhtcyBnaXZlIHVu
+aXF1ZSBpZHMgLSBvdGhlcnMgbWF5IHlpZWxkCiAgICBkdXBsaWNhdGVkIG9uZXMg
+d2hlbiB0aGV5IGhhdmUgYmVlbiBjcmVhdGVkIGluIHRoZSBzYW1lIHNlY29uZC4K
+CiAgICBOb3RlLCB0aGF0IFNJRy1USU1FU1RBTVAgbWF5IGVpdGhlciBiZSBhIG51
+bWJlciBvZiBzZWNvbmRzIHNpbmNlCiAgICBFcG9jaCBvciBhbiBJU08gODYwMSBz
+dHJpbmcgd2hpY2ggY2FuIGJlIGRldGVjdGVkIGJ5IHRoZSBwcmVzZW5jZQogICAg
+b2YgdGhlIGxldHRlciAnVCcuCgoqKiogRU5DX1RPICA8bG9uZ19rZXlpZD4gIDxr
+ZXl0eXBlPiAgPGtleWxlbmd0aD4KICAgIFRoZSBtZXNzYWdlIGlzIGVuY3J5cHRl
+ZCB0byB0aGlzIExPTkdfS0VZSUQuICBLRVlUWVBFIGlzIHRoZQogICAgbnVtZXJp
+Y2FsIHZhbHVlIG9mIHRoZSBwdWJsaWMga2V5IGFsZ29yaXRobSBvciAwIGlmIGl0
+IGlzIG5vdAogICAga25vd24sIEtFWUxFTkdUSCBpcyB0aGUgbGVuZ3RoIG9mIHRo
+ZSBrZXkgb3IgMCBpZiBpdCBpcyBub3Qga25vd24KICAgICh3aGljaCBpcyBjdXJy
+ZW50bHkgYWx3YXlzIHRoZSBjYXNlKS4gIEdwZyBwcmludHMgdGhpcyBsaW5lCiAg
+ICBhbHdheXM7IEdwZ3NtIG9ubHkgaWYgaXQga25vd3MgdGhlIGNlcnRpZmljYXRl
+LgoKKioqIEJFR0lOX0RFQ1JZUFRJT04KICAgIE1hcmsgdGhlIHN0YXJ0IG9mIHRo
+ZSBhY3R1YWwgZGVjcnlwdGlvbiBwcm9jZXNzLiAgVGhpcyBpcyBhbHNvCiAgICBl
+bWl0dGVkIHdoZW4gaW4gLS1saXN0LW9ubHkgbW9kZS4KKioqIEVORF9ERUNSWVBU
+SU9OCiAgICBNYXJrIHRoZSBlbmQgb2YgdGhlIGFjdHVhbCBkZWNyeXB0aW9uIHBy
+b2Nlc3MuICBUaGlzIGFyZSBhbHNvCiAgICBlbWl0dGVkIHdoZW4gaW4gLS1saXN0
+LW9ubHkgbW9kZS4KKioqIERFQ1JZUFRJT05fSU5GTyA8bWRjX21ldGhvZD4gPHN5
+bV9hbGdvPgogICAgUHJpbnQgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHN5bW1ldHJp
+YyBlbmNyeXB0aW9uIGFsZ29yaXRobSBhbmQgdGhlCiAgICBNREMgbWV0aG9kLiAg
+VGhpcyB3aWxsIGJlIGVtaXR0ZWQgZXZlbiBpZiB0aGUgZGVjcnlwdGlvbiBmYWls
+cy4KCioqKiBERUNSWVBUSU9OX0ZBSUxFRAogICAgVGhlIHN5bW1ldHJpYyBkZWNy
+eXB0aW9uIGZhaWxlZCAtIG9uZSByZWFzb24gY291bGQgYmUgYSB3cm9uZwogICAg
+cGFzc3BocmFzZSBmb3IgYSBzeW1tZXRyaWNhbCBlbmNyeXB0ZWQgbWVzc2FnZS4K
+CioqKiBERUNSWVBUSU9OX09LQVkKICAgIFRoZSBkZWNyeXB0aW9uIHByb2Nlc3Mg
+c3VjY2VlZGVkLiAgVGhpcyBtZWFucywgdGhhdCBlaXRoZXIgdGhlCiAgICBjb3Jy
+ZWN0IHNlY3JldCBrZXkgaGFzIGJlZW4gdXNlZCBvciB0aGUgY29ycmVjdCBwYXNz
+cGhyYXNlIGZvciBhCiAgICBzeW1tZXRyaWMgZW5jcnlwdGVkIG1lc3NhZ2Ugd2Fz
+IGdpdmVuLiAgVGhlIHByb2dyYW0gaXRzZWxmIG1heQogICAgcmV0dXJuIGFuIGVy
+cm9yY29kZSBiZWNhdXNlIGl0IG1heSBub3QgYmUgcG9zc2libGUgdG8gdmVyaWZ5
+IGEKICAgIHNpZ25hdHVyZSBmb3Igc29tZSByZWFzb25zLgoKKioqIFNFU1NJT05f
+S0VZIDxhbGdvPjo8aGV4ZGlnaXRzPgogICAgVGhlIHNlc3Npb24ga2V5IHVzZWQg
+dG8gZGVjcnlwdCB0aGUgbWVzc2FnZS4gIFRoaXMgbWVzc2FnZSB3aWxsCiAgICBv
+bmx5IGJlIGVtaXR0ZWQgaWYgdGhlIG9wdGlvbiAtLXNob3ctc2Vzc2lvbi1rZXkg
+aXMgdXNlZC4gIFRoZQogICAgZm9ybWF0IGlzIHN1aXRhYmxlIHRvIGJlIHBhc3Nl
+ZCBhcyB2YWx1ZSBmb3IgdGhlIG9wdGlvbgogICAgLS1vdmVycmlkZS1zZXNzaW9u
+LWtleS4gIEl0IGlzIG5vdCBhbiBpbmRpY2F0aW9uIHRoYXQgdGhlCiAgICBkZWNy
+eXB0aW9uIHdpbGwgb3IgaGFzIHN1Y2NlZWRlZC4KCioqKiBCRUdJTl9FTkNSWVBU
+SU9OICA8bWRjX21ldGhvZD4gPHN5bV9hbGdvPgogICAgTWFyayB0aGUgc3RhcnQg
+b2YgdGhlIGFjdHVhbCBlbmNyeXB0aW9uIHByb2Nlc3MuCgoqKiogRU5EX0VOQ1JZ
+UFRJT04KICAgIE1hcmsgdGhlIGVuZCBvZiB0aGUgYWN0dWFsIGVuY3J5cHRpb24g
+cHJvY2Vzcy4KCioqKiBGSUxFX1NUQVJUIDx3aGF0PiA8ZmlsZW5hbWU+CiAgICBT
+dGFydCBwcm9jZXNzaW5nIGEgZmlsZSA8ZmlsZW5hbWU+LiAgPHdoYXQ+IGluZGlj
+YXRlcyB0aGUgcGVyZm9ybWVkCiAgICBvcGVyYXRpb246CiAgICAtIDEgOjogdmVy
+aWZ5CiAgICAtIDIgOjogZW5jcnlwdAogICAgLSAzIDo6IGRlY3J5cHQKCioqKiBG
+SUxFX0RPTkUKICAgIE1hcmtzIHRoZSBlbmQgb2YgYSBmaWxlIHByb2Nlc3Npbmcg
+d2hpY2ggaGFzIGJlZW4gc3RhcnRlZAogICAgYnkgRklMRV9TVEFSVC4KCioqKiBC
+RUdJTl9TSUdOSU5HCiAgICBNYXJrIHRoZSBzdGFydCBvZiB0aGUgYWN0dWFsIHNp
+Z25pbmcgcHJvY2Vzcy4gVGhpcyBtYXkgYmUgdXNlZCBhcwogICAgYW4gaW5kaWNh
+dGlvbiB0aGF0IGFsbCByZXF1ZXN0ZWQgc2VjcmV0IGtleXMgYXJlIHJlYWR5IGZv
+ciB1c2UuCgoqKiogQUxSRUFEWV9TSUdORUQgPGxvbmcta2V5aWQ+CiAgICBXYXJu
+aW5nOiBUaGlzIGlzIGV4cGVyaW1lbnRhbCBhbmQgbWlnaHQgYmUgcmVtb3ZlZCBh
+dCBhbnkgdGltZS4KCioqKiBTSUdfQ1JFQVRFRCA8dHlwZT4gPHBrX2FsZ28+IDxo
+YXNoX2FsZ28+IDxjbGFzcz4gPHRpbWVzdGFtcD4gPGtleWZwcj4KICAgIEEgc2ln
+bmF0dXJlIGhhcyBiZWVuIGNyZWF0ZWQgdXNpbmcgdGhlc2UgcGFyYW1ldGVycy4K
+ICAgIFZhbHVlcyBmb3IgdHlwZSA8dHlwZT4gYXJlOgogICAgICAtIEQgOjogZGV0
+YWNoZWQKICAgICAgLSBDIDo6IGNsZWFydGV4dAogICAgICAtIFMgOjogc3RhbmRh
+cmQKICAgIChvbmx5IHRoZSBmaXJzdCBjaGFyYWN0ZXIgc2hvdWxkIGJlIGNoZWNr
+ZWQpCgogICAgPGNsYXNzPiBhcmUgMiBoZXggZGlnaXRzIHdpdGggdGhlIE9wZW5Q
+R1Agc2lnbmF0dXJlIGNsYXNzLgoKICAgIE5vdGUsIHRoYXQgVElNRVNUQU1QIG1h
+eSBlaXRoZXIgYmUgYSBudW1iZXIgb2Ygc2Vjb25kcyBzaW5jZSBFcG9jaAogICAg
+b3IgYW4gSVNPIDg2MDEgc3RyaW5nIHdoaWNoIGNhbiBiZSBkZXRlY3RlZCBieSB0
+aGUgcHJlc2VuY2Ugb2YgdGhlCiAgICBsZXR0ZXIgJ1QnLgoKKioqIE5PVEFUSU9O
+XwogICAgVGhlcmUgYXJlIGFjdHVhbGx5IHR3byByZWxhdGVkIHN0YXR1cyBjb2Rl
+cyB0byBjb252ZXkgbm90YXRpb24KICAgIGRhdGE6CgogICAgLSBOT1RBVElPTl9O
+QU1FIDxuYW1lPgogICAgLSBOT1RBVElPTl9EQVRBIDxzdHJpbmc+CgogICAgPG5h
+bWU+IGFuZCA8c3RyaW5nPiBhcmUgJVhYIGVzY2FwZWQ7IHRoZSBkYXRhIG1heSBi
+ZSBzcGxpdCBhbW9uZwogICAgc2V2ZXJhbCBOT1RBVElPTl9EQVRBIGxpbmVzLgoK
+KioqIFBPTElDWV9VUkwgPHN0cmluZz4KICAgIE5vdGUgdGhhdCBVUkwgaW4gPHN0
+cmluZz4gaXMgJVhYIGVzY2FwZWQuCgoqKiogUExBSU5URVhUIDxmb3JtYXQ+IDx0
+aW1lc3RhbXA+IDxmaWxlbmFtZT4KICAgIFRoaXMgaW5kaWNhdGVzIHRoZSBmb3Jt
+YXQgb2YgdGhlIHBsYWludGV4dCB0aGF0IGlzIGFib3V0IHRvIGJlCiAgICB3cml0
+dGVuLiAgVGhlIGZvcm1hdCBpcyBhIDEgYnl0ZSBoZXggY29kZSB0aGF0IHNob3dz
+IHRoZSBmb3JtYXQgb2YKICAgIHRoZSBwbGFpbnRleHQ6IDYyICgnYicpIGlzIGJp
+bmFyeSBkYXRhLCA3NCAoJ3QnKSBpcyB0ZXh0IGRhdGEgd2l0aAogICAgbm8gY2hh
+cmFjdGVyIHNldCBzcGVjaWZpZWQsIGFuZCA3NSAoJ3UnKSBpcyB0ZXh0IGRhdGEg
+ZW5jb2RlZCBpbgogICAgdGhlIFVURi04IGNoYXJhY3RlciBzZXQuICBUaGUgdGlt
+ZXN0YW1wIGlzIGluIHNlY29uZHMgc2luY2UgdGhlCiAgICBlcG9jaC4gIElmIGEg
+ZmlsZW5hbWUgaXMgYXZhaWxhYmxlIGl0IGdldHMgcHJpbnRlZCBhcyB0aGUgdGhp
+cmQKICAgIGFyZ3VtZW50LCBwZXJjZW50LWVzY2FwZWQgYXMgdXN1YWwuCgoqKiog
+UExBSU5URVhUX0xFTkdUSCA8bGVuZ3RoPgogICAgVGhpcyBpbmRpY2F0ZXMgdGhl
+IGxlbmd0aCBvZiB0aGUgcGxhaW50ZXh0IHRoYXQgaXMgYWJvdXQgdG8gYmUKICAg
+IHdyaXR0ZW4uICBOb3RlIHRoYXQgaWYgdGhlIHBsYWludGV4dCBwYWNrZXQgaGFz
+IHBhcnRpYWwgbGVuZ3RoCiAgICBlbmNvZGluZyBpdCBpcyBub3QgcG9zc2libGUg
+dG8ga25vdyB0aGUgbGVuZ3RoIGFoZWFkIG9mIHRpbWUuICBJbgogICAgdGhhdCBj
+YXNlLCB0aGlzIHN0YXR1cyB0YWcgZG9lcyBub3QgYXBwZWFyLgoKKioqIEFUVFJJ
+QlVURSA8YXJndW1lbnRzPgogICAgVGhlIGxpc3Qgb3IgYXJnZW1udHMgYXJlOgog
+ICAgLSA8ZnByPgogICAgLSA8b2N0ZXRzPgogICAgLSA8dHlwZT4KICAgIC0gPGlu
+ZGV4PgogICAgLSA8Y291bnQ+CiAgICAtIDx0aW1lc3RhbXA+CiAgICAtIDxleHBp
+cmVkYXRlPgogICAgLSA8ZmxhZ3M+CgogICAgVGhpcyBpcyBvbmUgbG9uZyBsaW5l
+IGlzc3VlZCBmb3IgZWFjaCBhdHRyaWJ1dGUgc3VicGFja2V0IHdoZW4gYW4KICAg
+IGF0dHJpYnV0ZSBwYWNrZXQgaXMgc2VlbiBkdXJpbmcga2V5IGxpc3RpbmcuICA8
+ZnByPiBpcyB0aGUKICAgIGZpbmdlcnByaW50IG9mIHRoZSBrZXkuICA8b2N0ZXRz
+PiBpcyB0aGUgbGVuZ3RoIG9mIHRoZSBhdHRyaWJ1dGUKICAgIHN1YnBhY2tldC4g
+IDx0eXBlPiBpcyB0aGUgYXR0cmlidXRlIHR5cGUgKGUuZy4gMSBmb3IgYW4gaW1h
+Z2UpLgogICAgPGluZGV4PiBhbmQgPGNvdW50PiBpbmRpY2F0ZSB0aGF0IHRoaXMg
+aXMgdGhlIE4tdGggaW5kZXhlZAogICAgc3VicGFja2V0IG9mIGNvdW50IHRvdGFs
+IHN1YnBhY2tldHMgaW4gdGhpcyBhdHRyaWJ1dGUgcGFja2V0LgogICAgPHRpbWVz
+dGFtcD4gYW5kIDxleHBpcmVkYXRlPiBhcmUgZnJvbSB0aGUgc2VsZi1zaWduYXR1
+cmUgb24gdGhlCiAgICBhdHRyaWJ1dGUgcGFja2V0LiAgSWYgdGhlIGF0dHJpYnV0
+ZSBwYWNrZXQgZG9lcyBub3QgaGF2ZSBhIHZhbGlkCiAgICBzZWxmLXNpZ25hdHVy
+ZSwgdGhlbiB0aGUgdGltZXN0YW1wIGlzIDAuICA8ZmxhZ3M+IGFyZSBhIGJpdHdp
+c2UgT1IKICAgIG9mOgogICAgLSAweDAxIDo6IHRoaXMgYXR0cmlidXRlIHBhY2tl
+dCBpcyBhIHByaW1hcnkgdWlkCiAgICAtIDB4MDIgOjogdGhpcyBhdHRyaWJ1dGUg
+cGFja2V0IGlzIHJldm9rZWQKICAgIC0gMHgwNCA6OiB0aGlzIGF0dHJpYnV0ZSBw
+YWNrZXQgaXMgZXhwaXJlZAoKKioqIFNJR19TVUJQQUNLRVQgPHR5cGU+IDxmbGFn
+cz4gPGxlbj4gPGRhdGE+CiAgICBUaGlzIGluZGljYXRlcyB0aGF0IGEgc2lnbmF0
+dXJlIHN1YnBhY2tldCB3YXMgc2Vlbi4gIFRoZSBmb3JtYXQgaXMKICAgIHRoZSBz
+YW1lIGFzIHRoZSAic3BrIiByZWNvcmQgYWJvdmUuCgoqKiBLZXkgcmVsYXRlZAoq
+KiogSU5WX1JFQ1AsIElOVl9TR05SCiAgICBUaGUgdHdvIHNpbWlsYXIgc3RhdHVz
+IGNvZGVzOgoKICAgIC0gSU5WX1JFQ1AgPHJlYXNvbj4gPHJlcXVlc3RlZF9yZWNp
+cGllbnQ+CiAgICAtIElOVl9TR05SIDxyZWFzb24+IDxyZXF1ZXN0ZWRfc2VuZGVy
+PgoKICAgIGFyZSBpc3N1ZWQgZm9yIGVhY2ggdW51c2FibGUgcmVjaXBpZW50L3Nl
+bmRlci4gVGhlIHJlYXNvbnMgY29kZXMKICAgIGN1cnJlbnRseSBpbiB1c2UgYXJl
+OgoKICAgICAgIC0gIDAgOjogTm8gc3BlY2lmaWMgcmVhc29uIGdpdmVuCiAgICAg
+ICAtICAxIDo6IE5vdCBGb3VuZAogICAgICAgLSAgMiA6OiBBbWJpZ2lvdXMgc3Bl
+Y2lmaWNhdGlvbgogICAgICAgLSAgMyA6OiBXcm9uZyBrZXkgdXNhZ2UKICAgICAg
+IC0gIDQgOjogS2V5IHJldm9rZWQKICAgICAgIC0gIDUgOjogS2V5IGV4cGlyZWQK
+ICAgICAgIC0gIDYgOjogTm8gQ1JMIGtub3duCiAgICAgICAtICA3IDo6IENSTCB0
+b28gb2xkCiAgICAgICAtICA4IDo6IFBvbGljeSBtaXNtYXRjaAogICAgICAgLSAg
+OSA6OiBOb3QgYSBzZWNyZXQga2V5CiAgICAgICAtIDEwIDo6IEtleSBub3QgdHJ1
+c3RlZAogICAgICAgLSAxMSA6OiBNaXNzaW5nIGNlcnRpZmljYXRlCiAgICAgICAt
+IDEyIDo6IE1pc3NpbmcgaXNzdWVyIGNlcnRpZmljYXRlCiAgICAgICAtIDEzIDo6
+IEtleSBkaXNhYmxlZAogICAgICAgLSAxNCA6OiBTeW50YXggZXJyb3IgaW4gc3Bl
+Y2lmaWNhdGlvbgoKICAgIE5vdGUgdGhhdCBmb3IgaGlzdG9yaWNhbCByZWFzb25z
+IHRoZSBJTlZfUkVDUCBzdGF0dXMgaXMgYWxzbyB1c2VkCiAgICBmb3IgZ3Bnc20n
+cyBTSUdORVIgY29tbWFuZCB3aGVyZSBpdCByZWxhdGVzIHRvIHNpZ25lcidzIG9m
+IGNvdXJzZS4KICAgIE5ld2VyIEdudVBHIHZlcnNpb25zIGFyZSB1c2luZyBJTlZf
+U0dOUjsgYXBwbGljYXRpb25zIHNob3VsZAogICAgaWdub3JlIHRoZSBJTlZfUkVD
+UCBkdXJpbmcgdGhlIHNlbmRlcidzIGNvbW1hbmQgcHJvY2Vzc2luZyBvbmNlCiAg
+ICB0aGV5IGhhdmUgc2VlbiBhbiBJTlZfU0dOUi4gIERpZmZlcmVudCBjb2RlcyBh
+cmUgdXNlZCBzbyB0aGF0IHRoZXkKICAgIGNhbiBiZSBkaXN0aW5ndWlzaCB3aGls
+ZSBkb2luZyBhbiBlbmNyeXB0K3NpZ24gb3BlcmF0aW9uLgoqKiogTk9fUkVDUCA8
+cmVzZXJ2ZWQ+CiAgICBJc3N1ZWQgaWYgbm8gcmVjaXBpZW50cyBhcmUgdXNhYmxl
+LgoKKioqIE5PX1NHTlIgPHJlc2VydmVkPgogICAgSXNzdWVkIGlmIG5vIHNlbmRl
+cnMgYXJlIHVzYWJsZS4KCioqKiBLRVlFWFBJUkVEIDxleHBpcmUtdGltZXN0YW1w
+PgogICAgVGhlIGtleSBoYXMgZXhwaXJlZC4gIGV4cGlyZS10aW1lc3RhbXAgaXMg
+dGhlIGV4cGlyYXRpb24gdGltZSBpbgogICAgc2Vjb25kcyBzaW5jZSBFcG9jaC4g
+IFRoaXMgc3RhdHVzIGxpbmUgaXMgbm90IHZlcnkgdXNlZnVsIGJlY2F1c2UKICAg
+IGl0IHdpbGwgYWxzbyBiZSBlbWl0dGVkIGZvciBleHBpcmVkIHN1YmtleXMgZXZl
+biBpZiB0aGlzIHN1YmtleSBpcwogICAgbm90IHVzZWQuICBUbyBjaGVjayB3aGV0
+aGVyIGEga2V5IHVzZWQgdG8gc2lnbiBhIG1lc3NhZ2UgaGFzCiAgICBleHBpcmVk
+LCB0aGUgRVhQS0VZU0lHIHN0YXR1cyBsaW5lIGlzIHRvIGJlIHVzZWQuCgogICAg
+Tm90ZSwgdGhhdCB0aGUgVElNRVNUQU1QIG1heSBlaXRoZXIgYmUgYSBudW1iZXIg
+b2Ygc2Vjb25kcyBzaW5jZQogICAgRXBvY2ggb3IgYW4gSVNPIDg2MDEgc3RyaW5n
+IHdoaWNoIGNhbiBiZSBkZXRlY3RlZCBieSB0aGUgcHJlc2VuY2UKICAgIG9mIHRo
+ZSBsZXR0ZXIgJ1QnLgoKKioqIEtFWVJFVk9LRUQKICAgIFRoZSB1c2VkIGtleSBo
+YXMgYmVlbiByZXZva2VkIGJ5IGl0cyBvd25lci4gIE5vIGFyZ3VtZW50cyB5ZXQu
+CgoqKiogTk9fUFVCS0VZICA8bG9uZyBrZXlpZD4KICAgIFRoZSBwdWJsaWMga2V5
+IGlzIG5vdCBhdmFpbGFibGUKCioqKiBOT19TRUNLRVkgIDxsb25nIGtleWlkPgog
+ICAgVGhlIHNlY3JldCBrZXkgaXMgbm90IGF2YWlsYWJsZQoKKioqIEtFWV9DUkVB
+VEVEIDx0eXBlPiA8ZmluZ2VycHJpbnQ+IFs8aGFuZGxlPl0KICAgIEEga2V5IGhh
+cyBiZWVuIGNyZWF0ZWQuICBWYWx1ZXMgZm9yIDx0eXBlPiBhcmU6CiAgICAgIC0g
+QiA6OiBwcmltYXJ5IGFuZCBzdWJrZXkKICAgICAgLSBQIDo6IHByaW1hcnkKICAg
+ICAgLSBTIDo6IHN1YmtleQogICAgVGhlIGZpbmdlcnByaW50IGlzIG9uZSBvZiB0
+aGUgcHJpbWFyeSBrZXkgZm9yIHR5cGUgQiBhbmQgUCBhbmQgdGhlCiAgICBvbmUg
+b2YgdGhlIHN1YmtleSBmb3IgUy4gIEhhbmRsZSBpcyBhbiBhcmJpdHJhcnkgbm9u
+LXdoaXRlc3BhY2UKICAgIHN0cmluZyB1c2VkIHRvIG1hdGNoIGtleSBwYXJhbWV0
+ZXJzIGZyb20gYmF0Y2gga2V5IGNyZWF0aW9uIHJ1bi4KCioqKiBLRVlfTk9UX0NS
+RUFURUQgWzxoYW5kbGU+XQogICAgVGhlIGtleSBmcm9tIGJhdGNoIHJ1biBoYXMg
+bm90IGJlZW4gY3JlYXRlZCBkdWUgdG8gZXJyb3JzLgoKKioqIFRSVVNUXwogICAg
+VGhlc2UgYXJlIHNldmVyYWwgc2ltaWxhciBzdGF0dXMgY29kZXM6CgogICAgLSBU
+UlVTVF9VTkRFRklORUQgPGVycm9yX3Rva2VuPgogICAgLSBUUlVTVF9ORVZFUiAg
+ICAgPGVycm9yX3Rva2VuPgogICAgLSBUUlVTVF9NQVJHSU5BTCAgWzAgIFs8dmFs
+aWRhdGlvbl9tb2RlbD5dXQogICAgLSBUUlVTVF9GVUxMWSAgICAgWzAgIFs8dmFs
+aWRhdGlvbl9tb2RlbD5dXQogICAgLSBUUlVTVF9VTFRJTUFURSAgWzAgIFs8dmFs
+aWRhdGlvbl9tb2RlbD5dXQoKICAgIEZvciBnb29kIHNpZ25hdHVyZXMgb25lIG9m
+IHRoZXNlIHN0YXR1cyBsaW5lcyBhcmUgZW1pdHRlZCB0bwogICAgaW5kaWNhdGUg
+dGhlIHZhbGlkaXR5IG9mIHRoZSBrZXkgdXNlZCB0byBjcmVhdGUgdGhlIHNpZ25h
+dHVyZS4KICAgIFRoZSBlcnJvciB0b2tlbiB2YWx1ZXMgYXJlIGN1cnJlbnRseSBv
+bmx5IGVtaXR0ZWQgYnkgZ3Bnc20uCgogICAgVkFMSURBVElPTl9NT0RFTCBkZXNj
+cmliZXMgdGhlIGFsZ29yaXRobSB1c2VkIHRvIGNoZWNrIHRoZQogICAgdmFsaWRp
+dHkgb2YgdGhlIGtleS4gIFRoZSBkZWZhdWx0cyBhcmUgdGhlIHN0YW5kYXJkIFdl
+YiBvZiBUcnVzdAogICAgbW9kZWwgZm9yIGdwZyBhbmQgdGhlIHRoZSBzdGFuZGFy
+ZCBYLjUwOSBtb2RlbCBmb3IgZ3Bnc20uICBUaGUKICAgIGRlZmluZWQgdmFsdWVz
+IGFyZQoKICAgICAgIC0gcGdwICAgOjogVGhlIHN0YW5kYXJkIFBHUCBXb1QuCiAg
+ICAgICAtIHNoZWxsIDo6IFRoZSBzdGFuZGFyZCBYLjUwOSBtb2RlbC4KICAgICAg
+IC0gY2hhaW4gOjogVGhlIGNoYWluIG1vZGVsLgogICAgICAgLSBzdGVlZCA6OiBU
+aGUgU1RFRUQgbW9kZWwuCgogICAgTm90ZSB0aGF0IHRoZSB0ZXJtID1UUlVTVF89
+IGluIHRoZSBzdGF0dXMgbmFtZXMgaXMgdXNlZCBmb3IKICAgIGhpc3RvcmljIHJl
+YXNvbnM7IHdlIG5vdyBzcGVhayBvZiB2YWxpZGl0eS4KCioqKiBQS0FfVFJVU1Rf
+CiAgICBUaGlzIGlzIGlzIG9uZToKCiAgICAtIFBLQV9UUlVTVF9HT09EIDxtYWls
+Ym94PgogICAgLSBQS0FfVFJVU1RfQkFEICA8bWFpbGJveD4KCiAgICBEZXBlbmRp
+bmcgb24gdGhlIG91dGNvbWUgb2YgdGhlIFBLQSBjaGVjayBvbmUgb2YgdGhlIGFi
+b3ZlIHN0YXR1cwogICAgY29kZXMgaXMgZW1pdHRlZCBpbiBhZGRpdGlvbiB0byBh
+ID1UUlVTVF8qPSBzdGF0dXMuCgoqKiBSZW1vdGUgY29udHJvbAoqKiogR0VUX0JP
+T0wsIEdFVF9MSU5FLCBHRVRfSElEREVOLCBHT1RfSVQKCiAgICBUaGVzZSBzdGF0
+dXMgbGluZSBhcmUgdXNlZCB3aXRoIC0tY29tbWFuZC1mZCBmb3IgaW50ZXJhY3Rp
+dmUKICAgIGNvbnRyb2wgb2YgdGhlIHByb2Nlc3MuCgoqKiogVVNFUklEX0hJTlQg
+PGxvbmcgbWFpbiBrZXlpZD4gPHN0cmluZz4KICAgIEdpdmUgYSBoaW50IGFib3V0
+IHRoZSB1c2VyIElEIGZvciBhIGNlcnRhaW4ga2V5SUQuCgoqKiogTkVFRF9QQVNT
+UEhSQVNFIDxsb25nIGtleWlkPiA8bG9uZyBtYWluIGtleWlkPiA8a2V5dHlwZT4g
+PGtleWxlbmd0aD4KICAgIElzc3VlZCB3aGVuZXZlciBhIHBhc3NwaHJhc2UgaXMg
+bmVlZGVkLiAgS0VZVFlQRSBpcyB0aGUgbnVtZXJpY2FsCiAgICB2YWx1ZSBvZiB0
+aGUgcHVibGljIGtleSBhbGdvcml0aG0gb3IgMCBpZiB0aGlzIGlzIG5vdCBhcHBs
+aWNhYmxlLAogICAgS0VZTEVOR1RIIGlzIHRoZSBsZW5ndGggb2YgdGhlIGtleSBv
+ciAwIGlmIGl0IGlzIG5vdCBrbm93biAodGhpcwogICAgaXMgY3VycmVudGx5IGFs
+d2F5cyB0aGUgY2FzZSkuCgoqKiogTkVFRF9QQVNTUEhSQVNFX1NZTSA8Y2lwaGVy
+X2FsZ28+IDxzMmtfbW9kZT4gPHMya19oYXNoPgogICAgSXNzdWVkIHdoZW5ldmVy
+IGEgcGFzc3BocmFzZSBmb3Igc3ltbWV0cmljIGVuY3J5cHRpb24gaXMgbmVlZGVk
+LgoKKioqIE5FRURfUEFTU1BIUkFTRV9QSU4gPGNhcmRfdHlwZT4gPGNodm5vPiBb
+PHNlcmlhbG5vPl0KICAgIElzc3VlZCB3aGVuZXZlciBhIFBJTiBpcyByZXF1ZXN0
+ZWQgdG8gdW5sb2NrIGEgY2FyZC4KCioqKiBNSVNTSU5HX1BBU1NQSFJBU0UKICAg
+IE5vIHBhc3NwaHJhc2Ugd2FzIHN1cHBsaWVkLiAgQW4gYXBwbGljYXRpb24gd2hp
+Y2ggZW5jb3VudGVycyB0aGlzCiAgICBtZXNzYWdlIG1heSB3YW50IHRvIHN0b3Ag
+cGFyc2luZyBpbW1lZGlhdGVseSBiZWNhdXNlIHRoZSBuZXh0CiAgICBtZXNzYWdl
+IHdpbGwgcHJvYmFibHkgYmUgYSBCQURfUEFTU1BIUkFTRS4gIEhvd2V2ZXIsIGlm
+IHRoZQogICAgYXBwbGljYXRpb24gaXMgYSB3cmFwcGVyIGFyb3VuZCB0aGUga2V5
+IGVkaXQgbWVudSBmdW5jdGlvbmFsaXR5IGl0CiAgICBtaWdodCBub3QgbWFrZSBz
+ZW5zZSB0byBzdG9wIHBhcnNpbmcgYnV0IHNpbXBseSBpZ25vcmluZyB0aGUKICAg
+IGZvbGxvd2luZyBCQURfUEFTU1BIUkFTRS4KCioqKiBCQURfUEFTU1BIUkFTRSA8
+bG9uZyBrZXlpZD4KICAgIFRoZSBzdXBwbGllZCBwYXNzcGhyYXNlIHdhcyB3cm9u
+ZyBvciBub3QgZ2l2ZW4uICBJbiB0aGUgbGF0dGVyCiAgICBjYXNlIHlvdSBtYXkg
+aGF2ZSBzZWVuIGEgTUlTU0lOR19QQVNTUEhSQVNFLgoKKioqIEdPT0RfUEFTU1BI
+UkFTRQogICAgVGhlIHN1cHBsaWVkIHBhc3NwaHJhc2Ugd2FzIGdvb2QgYW5kIHRo
+ZSBzZWNyZXQga2V5IG1hdGVyaWFsCiAgICBpcyB0aGVyZWZvcmUgdXNhYmxlLgoK
+KiogSW1wb3J0L0V4cG9ydAoqKiogSU1QT1JUX0NIRUNLIDxsb25nIGtleWlkPiA8
+ZmluZ2VycHJpbnQ+IDx1c2VyIElEPgogICAgVGhpcyBzdGF0dXMgaXMgZW1pdHRl
+ZCBpbiBpbnRlcmFjdGl2ZSBtb2RlIHJpZ2h0IGJlZm9yZQogICAgdGhlICJpbXBv
+cnQub2theSIgcHJvbXB0LgoKKioqIElNUE9SVEVEICAgPGxvbmcga2V5aWQ+ICA8
+dXNlcm5hbWU+CiAgICBUaGUga2V5aWQgYW5kIG5hbWUgb2YgdGhlIHNpZ25hdHVy
+ZSBqdXN0IGltcG9ydGVkCgoqKiogSU1QT1JUX09LICA8cmVhc29uPiBbPGZpbmdl
+cnByaW50Pl0KICAgIFRoZSBrZXkgd2l0aCB0aGUgcHJpbWFyeSBrZXkncyBGSU5H
+RVJQUklOVCBoYXMgYmVlbiBpbXBvcnRlZC4KICAgIFJFQVNPTiBmbGFncyBhcmU6
+CgogICAgLSAwIDo6IE5vdCBhY3R1YWxseSBjaGFuZ2VkCiAgICAtIDEgOjogRW50
+aXJlbHkgbmV3IGtleS4KICAgIC0gMiA6OiBOZXcgdXNlciBJRHMKICAgIC0gNCA6
+OiBOZXcgc2lnbmF0dXJlcwogICAgLSA4IDo6IE5ldyBzdWJrZXlzCiAgICAtIDE2
+IDo6IENvbnRhaW5zIHByaXZhdGUga2V5LgoKICAgIFRoZSBmbGFncyBtYXkgYmUg
+T1JlZC4KCioqKiBJTVBPUlRfUFJPQkxFTSA8cmVhc29uPiBbPGZpbmdlcnByaW50
+Pl0KICAgIElzc3VlZCBmb3IgZWFjaCBpbXBvcnQgZmFpbHVyZS4gIFJlYXNvbiBj
+b2RlcyBhcmU6CgogICAgLSAwIDo6IE5vIHNwZWNpZmljIHJlYXNvbiBnaXZlbi4K
+ICAgIC0gMSA6OiBJbnZhbGlkIENlcnRpZmljYXRlLgogICAgLSAyIDo6IElzc3Vl
+ciBDZXJ0aWZpY2F0ZSBtaXNzaW5nLgogICAgLSAzIDo6IENlcnRpZmljYXRlIENo
+YWluIHRvbyBsb25nLgogICAgLSA0IDo6IEVycm9yIHN0b3JpbmcgY2VydGlmaWNh
+dGUuCgoqKiogSU1QT1JUX1JFUyA8YXJncz4KICAgIEZpbmFsIHN0YXRpc3RpY3Mg
+b24gaW1wb3J0IHByb2Nlc3MgKHRoaXMgaXMgb25lIGxvbmcgbGluZSkuIFRoZQog
+ICAgYXJncyBhcmUgYSBsaXN0IG9mIHVuc2lnbmVkIG51bWJlcnMgc2VwYXJhdGVk
+IGJ5IHdoaXRlIHNwYWNlOgoKICAgIC0gPGNvdW50PgogICAgLSA8bm9fdXNlcl9p
+ZD4KICAgIC0gPGltcG9ydGVkPgogICAgLSBhbHdheXMgMCAoZm9ybWVybHkgdXNl
+ZCBmb3IgdGhlIG51bWJlciBvZiBSU0Ega2V5cykKICAgIC0gPHVuY2hhbmdlZD4K
+ICAgIC0gPG5fdWlkcz4KICAgIC0gPG5fc3Viaz4KICAgIC0gPG5fc2lncz4KICAg
+IC0gPG5fcmV2b2M+CiAgICAtIDxzZWNfcmVhZD4KICAgIC0gPHNlY19pbXBvcnRl
+ZD4KICAgIC0gPHNlY19kdXBzPgogICAgLSA8c2tpcHBlZF9uZXdfa2V5cz4KICAg
+IC0gPG5vdF9pbXBvcnRlZD4KICAgIC0gPHNraXBwZWRfdjNfa2V5cz4KCioqKiBF
+WFBPUlRFRCAgPGZpbmdlcnByaW50PgogICAgVGhlIGtleSB3aXRoIDxmaW5nZXJw
+cmludD4gaGFzIGJlZW4gZXhwb3J0ZWQuICBUaGUgZmluZ2VycHJpbnQgaXMKICAg
+IHRoZSBmaW5nZXJwcmludCBvZiB0aGUgcHJpbWFyeSBrZXkgZXZlbiBpZiB0aGUg
+cHJpbWFyeSBrZXkgaGFzCiAgICBiZWVuIHJlcGxhY2VkIGJ5IGEgc3R1YiBrZXkg
+ZHVyaW5nIHNlY3JldCBrZXkgZXhwb3J0LgoKKioqIEVYUE9SVF9SRVMgPGFyZ3M+
+CgogICAgRmluYWwgc3RhdGlzdGljcyBvbiBleHBvcnQgcHJvY2VzcyAodGhpcyBp
+cyBvbmUgbG9uZyBsaW5lKS4gVGhlCiAgICBhcmdzIGFyZSBhIGxpc3Qgb2YgdW5z
+aWduZWQgbnVtYmVycyBzZXBhcmF0ZWQgYnkgd2hpdGUgc3BhY2U6CgogICAgLSA8
+Y291bnQ+CiAgICAtIDxzZWNyZXRfY291bnQ+CiAgICAtIDxleHBvcnRlZD4KCgoq
+KiBTbWFydGNhcmQgcmVsYXRlZAoqKiogQ0FSRENUUkwgPHdoYXQ+IFs8c2VyaWFs
+bm8+XQogICAgVGhpcyBpcyB1c2VkIHRvIGNvbnRyb2wgc21hcnRjYXJkIG9wZXJh
+dGlvbnMuICBEZWZpbmVkIHZhbHVlcyBmb3IKICAgIFdIQVQgYXJlOgoKICAgICAg
+LSAxIDo6IFJlcXVlc3QgaW5zZXJ0aW9uIG9mIGEgY2FyZC4gIFNlcmlhbG51bWJl
+ciBtYXkgYmUgZ2l2ZW4KICAgICAgICAgICAgIHRvIHJlcXVlc3QgYSBzcGVjaWZp
+YyBjYXJkLiAgVXNlZCBieSBncGcgMS40IHcvbwogICAgICAgICAgICAgc2NkYWVt
+b24KICAgICAgLSAyIDo6IFJlcXVlc3QgcmVtb3ZhbCBvZiBhIGNhcmQuICBVc2Vk
+IGJ5IGdwZyAxLjQgdy9vIHNjZGFlbW9uLgogICAgICAtIDMgOjogQ2FyZCB3aXRo
+IHNlcmlhbG51bWJlciBkZXRlY3RlZAogICAgICAtIDQgOjogTm8gY2FyZCBhdmFp
+bGFibGUKICAgICAgLSA1IDo6IE5vIGNhcmQgcmVhZGVyIGF2YWlsYWJsZQogICAg
+ICAtIDYgOjogTm8gY2FyZCBzdXBwb3J0IGF2YWlsYWJsZQogICAgICAtIDcgOjog
+Q2FyZCBpcyBpbiB0ZXJtaW5hdGlvbiBzdGF0ZQoKKioqIFNDX09QX0ZBSUxVUkUg
+Wzxjb2RlPl0KICAgIEFuIG9wZXJhdGlvbiBvbiBhIHNtYXJ0Y2FyZCBkZWZpbml0
+ZWx5IGZhaWxlZC4gIEN1cnJlbnRseSB0aGVyZSBpcwogICAgbm8gaW5kaWNhdGlv
+biBvZiB0aGUgYWN0dWFsIGVycm9yIGNvZGUsIGJ1dCBhcHBsaWNhdGlvbiBzaG91
+bGQgYmUKICAgIHByZXBhcmVkIHRvIGxhdGVyIGFjY2VwdCBtb3JlIGFyZ3VtZW50
+cy4gIERlZmluZWQgdmFsdWVzIGZvcgogICAgPGNvZGU+IGFyZToKCiAgICAgIC0g
+MCA6OiB1bnNwZWNpZmllZCBlcnJvciAoaWRlbnRpY2FsbHkgdG8gYSBtaXNzaW5n
+IENPREUpCiAgICAgIC0gMSA6OiBjYW5jZWxlZAogICAgICAtIDIgOjogYmFkIFBJ
+TgoKKioqIFNDX09QX1NVQ0NFU1MKICAgIEEgc21hcnQgY2FyZCBvcGVyYWlvbiBz
+dWNjZWVkZWQuICBUaGlzIHN0YXR1cyBpcyBvbmx5IHByaW50ZWQgZm9yCiAgICBj
+ZXJ0YWluIG9wZXJhdGlvbiBhbmQgaXMgbW9zdGx5IHVzZWZ1bCB0byBjaGVjayB3
+aGV0aGVyIGEgUElOCiAgICBjaGFuZ2UgcmVhbGx5IHdvcmtlZC4KCioqIE1pc2Nl
+bGxhbmVvdXMgc3RhdHVzIGNvZGVzCioqKiBOT0RBVEEgIDx3aGF0PgogICAgTm8g
+ZGF0YSBoYXMgYmVlbiBmb3VuZC4gIENvZGVzIGZvciBXSEFUIGFyZToKCiAgICAt
+IDEgOjogTm8gYXJtb3JlZCBkYXRhLgogICAgLSAyIDo6IEV4cGVjdGVkIGEgcGFj
+a2V0IGJ1dCBkaWQgbm90IGZvdW5kIG9uZS4KICAgIC0gMyA6OiBJbnZhbGlkIHBh
+Y2tldCBmb3VuZCwgdGhpcyBtYXkgaW5kaWNhdGUgYSBub24gT3BlblBHUAogICAg
+ICAgICAgIG1lc3NhZ2UuCiAgICAtIDQgOjogU2lnbmF0dXJlIGV4cGVjdGVkIGJ1
+dCBub3QgZm91bmQKCiAgICBZb3UgbWF5IHNlZSBtb3JlIHRoYW4gb25lIG9mIHRo
+ZXNlIHN0YXR1cyBsaW5lcy4KCioqKiBVTkVYUEVDVEVEIDx3aGF0PgogICAgVW5l
+eHBlY3RlZCBkYXRhIGhhcyBiZWVuIGVuY291bnRlcmVkLiAgQ29kZXMgZm9yIFdI
+QVQgYXJlOgogICAgLSAwIDo6IE5vdCBmdXJ0aGVyIHNwZWNpZmllZAogICAgLSAx
+IDo6IENvcnJ1cHRlZCBtZXNzYWdlIHN0cnVjdHVyZQoKKioqIFRSVU5DQVRFRCA8
+bWF4bm8+CiAgICBUaGUgb3V0cHV0IHdhcyB0cnVuY2F0ZWQgdG8gTUFYTk8gaXRl
+bXMuICBUaGlzIHN0YXR1cyBjb2RlIGlzCiAgICBpc3N1ZWQgZm9yIGNlcnRhaW4g
+ZXh0ZXJuYWwgcmVxdWVzdHMuCgoqKiogRVJST1IgPGVycm9yIGxvY2F0aW9uPiA8
+ZXJyb3IgY29kZT4gWzxtb3JlPl0KICAgIFRoaXMgaXMgYSBnZW5lcmljIGVycm9y
+IHN0YXR1cyBtZXNzYWdlLCBpdCBtaWdodCBiZSBmb2xsb3dlZCBieQogICAgZXJy
+b3IgbG9jYXRpb24gc3BlY2lmaWMgZGF0YS4gPGVycm9yIGNvZGU+IGFuZCA8ZXJy
+b3JfbG9jYXRpb24+CiAgICBzaG91bGQgbm90IGNvbnRhaW4gc3BhY2VzLiAgVGhl
+IGVycm9yIGNvZGUgaXMgYSBlaXRoZXIgYSBzdHJpbmcKICAgIGNvbW1lbmNpbmcg
+d2l0aCBhIGxldHRlciBvciBzdWNoIGEgc3RyaW5nIHByZWZpeGVkIHdpdGggYQog
+ICAgbnVtZXJpY2FsIGVycm9yIGNvZGUgYW5kIGFuIHVuZGVyc2NvcmU7IGUuZy46
+ICIxNTEwMTEzMjdfRU9GIi4KKioqIFdBUk5JTkcgPGxvY2F0aW9uPiA8ZXJyb3Ig
+Y29kZT4gWzx0ZXh0Pl0KICAgIFRoaXMgaXMgYSBnZW5lcmljIHdhcm5pbmcgc3Rh
+dHVzIG1lc3NhZ2UsIGl0IG1pZ2h0IGJlIGZvbGxvd2VkIGJ5CiAgICBlcnJvciBs
+b2NhdGlvbiBzcGVjaWZpYyBkYXRhLiA8ZXJyb3IgY29kZT4gYW5kIDxsb2NhdGlv
+bj4KICAgIHNob3VsZCBub3QgY29udGFpbiBzcGFjZXMuICBUaGUgZXJyb3IgY29k
+ZSBpcyBhIGVpdGhlciBhIHN0cmluZwogICAgY29tbWVuY2luZyB3aXRoIGEgbGV0
+dGVyIG9yIHN1Y2ggYSBzdHJpbmcgcHJlZml4ZWQgd2l0aCBhCiAgICBudW1lcmlj
+YWwgZXJyb3IgY29kZSBhbmQgYW4gdW5kZXJzY29yZTsgZS5nLjogIjE1MTAxMTMy
+N19FT0YiLgoqKiogU1VDQ0VTUyBbPGxvY2F0aW9uPl0KICAgIFBvc3RpdmUgY29u
+ZmlybWF0aW9uIHRoYXQgYW4gb3BlcmF0aW9uIHN1Y2NlZWRlZC4gIEl0IGlzIHVz
+ZWQKICAgIHNpbWlsYXIgdG8gSVNPLUMncyBFWElUX1NVQ0NFU1MuICA8bG9jYXRp
+b24+IGlzIG9wdGlvbmFsIGJ1dCBpZgogICAgZ2l2ZW4gc2hvdWxkIG5vdCBjb250
+YWluIHNwYWNlcy4gIFVzZWQgb25seSB3aXRoIGEgZmV3IGNvbW1hbmRzLgoKKioq
+IEZBSUxVUkUgPGxvY2F0aW9uPiA8ZXJyb3JfY29kZT4KICAgIFRoaXMgaXMgdGhl
+IGNvdW50ZXJwYXJ0IHRvIFNVQ0NFU1MgYW5kIHVzZWQgdG8gaW5kaWNhdGUgYSBw
+cm9ncmFtCiAgICBmYWlsdXJlLiAgSXQgaXMgdXNlZCBzaW1pbGFyIHRvIElTTy1D
+J3MgRVhJVF9GQUlMVVJFIGJ1dCBhbGxvd3MgdG8KICAgIGNvbnZleSBtb3JlIGlu
+Zm9ybWF0aW9uLCBpbiBwYXJ0aWN1bGFyIGFuIGdwZy1lcnJvciBlcnJvciBjb2Rl
+LgogICAgVGhhdCBudW1lcmljYWwgZXJyb3IgY29kZSBtYXkgb3B0aW9uYWxseSBo
+YXZlIGEgc3VmZml4IG1hZGUgb2YgYW4KICAgIHVuZGVyc2NvcmUgYW5kIGEgc3Ry
+aW5nIHdpdGggYW4gZXJyb3Igc3ltYm9sIGxpa2UgIjE1MTAxMTMyN19FT0YiLgog
+ICAgQSBkYXNoIG1heSBiZSB1c2VkIGluc3RlYWQgb2YgPGxvY2F0aW9uPi4KCioq
+KiBCQURBUk1PUgogICAgVGhlIEFTQ0lJIGFybW9yIGlzIGNvcnJ1cHRlZC4gIE5v
+IGFyZ3VtZW50cyB5ZXQuCgoqKiogREVMRVRFX1BST0JMRU0gPHJlYXNvbl9jb2Rl
+PgogICAgRGVsZXRpbmcgYSBrZXkgZmFpbGVkLiAgUmVhc29uIGNvZGVzIGFyZToK
+ICAgIC0gMSA6OiBObyBzdWNoIGtleQogICAgLSAyIDo6IE11c3QgZGVsZXRlIHNl
+Y3JldCBrZXkgZmlyc3QKICAgIC0gMyA6OiBBbWJpZ2lvdXMgc3BlY2lmaWNhdGlv
+bgogICAgLSA0IDo6IEtleSBpcyBzdG9yZWQgb24gYSBzbWFydGNhcmQuCgoqKiog
+UFJPR1JFU1MgPHdoYXQ+IDxjaGFyPiA8Y3VyPiA8dG90YWw+CiAgICBVc2VkIGJ5
+IHRoZSBwcmltZWdlbiBhbmQgUHVibGljIGtleSBmdW5jdGlvbnMgdG8gaW5kaWNh
+dGUKICAgIHByb2dyZXNzLiAgPGNoYXI+IGlzIHRoZSBjaGFyYWN0ZXIgZGlzcGxh
+eWVkIHdpdGggbm8gLS1zdGF0dXMtZmQKICAgIGVuYWJsZWQsIHdpdGggdGhlIGxp
+bmVmZWVkIHJlcGxhY2VkIGJ5IGFuICdYJy4gIDxjdXI+IGlzIHRoZQogICAgY3Vy
+cmVudCBhbW91bnQgZG9uZSBhbmQgPHRvdGFsPiBpcyBhbW91bnQgdG8gYmUgZG9u
+ZTsgYSA8dG90YWw+IG9mCiAgICAwIGluZGljYXRlcyB0aGF0IHRoZSB0b3RhbCBh
+bW91bnQgaXMgbm90IGtub3duLiBUaGUgY29uZGl0aW9uCiAgICAgIDogICAgICAg
+VE9UQUwgJiYgQ1VSID09IFRPVEFMCiAgICBtYXkgYmUgdXNlZCB0byBkZXRlY3Qg
+dGhlIGVuZCBvZiBhbiBvcGVyYXRpb24uCgogICAgV2VsbCBrbm93biB2YWx1ZXMg
+Zm9yIFdIQVQgYXJlOgoKICAgICAgICAgICAtIHBrX2RzYSAgIDo6IERTQSBrZXkg
+Z2VuZXJhdGlvbgogICAgICAgICAgIC0gcGtfZWxnICAgOjogRWxnYW1hbCBrZXkg
+Z2VuZXJhdGlvbgogICAgICAgICAgIC0gcHJpbWVnZW4gOjogUHJpbWUgZ2VuZXJh
+dGlvbgogICAgICAgICAgIC0gbmVlZF9lbnRyb3B5IDo6IFdhaXRpbmcgZm9yIG5l
+dyBlbnRyb3B5IGluIHRoZSBSTkcKICAgICAgICAgICAtIHRpY2sgOjogR2VuZXJp
+YyB0aWNrIHdpdGhvdXQgYW55IHNwZWNpYWwgbWVhbmluZyAtIHVzZWZ1bAogICAg
+ICAgICAgICAgICAgICAgICBmb3IgbGV0dGluZyBjbGllbnRzIGtub3cgdGhhdCB0
+aGUgc2VydmVyIGlzIHN0aWxsCiAgICAgICAgICAgICAgICAgICAgIHdvcmtpbmcu
+CiAgICAgICAgICAgLSBzdGFydGluZ19hZ2VudCA6OiBBIGdwZy1hZ2VudCB3YXMg
+c3RhcnRlZCBiZWNhdXNlIGl0IGlzIG5vdAogICAgICAgICAgICAgICAgICAgICAg
+ICAgICAgICAgIHJ1bm5pbmcgYXMgYSBkYWVtb24uCiAgICAgICAgICAgLSBsZWFy
+bmNhcmQgOjogU2VuZCBieSB0aGUgYWdlbnQgYW5kIGdwZ3NtIHdoaWxlIGxlYXJp
+bmcKICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgZGF0YSBvZiBhIHNtYXJ0
+Y2FyZC4KICAgICAgICAgICAtIGNhcmRfYnVzeSA6OiBBIHNtYXJ0Y2FyZCBpcyBz
+dGlsbCB3b3JraW5nCgoqKiogQkFDS1VQX0tFWV9DUkVBVEVEIDxmaW5nZXJwcmlu
+dD4gPGZuYW1lPgogICAgQSBiYWNrdXAgb2YgYSBrZXkgaWRlbnRpZmllZCBieSA8
+ZmluZ2VycHJpbnQ+IGhhcyBiZWVuIHdyaXR0ZSB0bwogICAgdGhlIGZpbGUgPGZu
+YW1lPjsgPGZuYW1lPiBpcyBwZXJjZW50LWVzY2FwZWQuCgoqKiogTU9VTlRQT0lO
+VCA8bmFtZT4KICAgIDxuYW1lPiBpcyBhIHBlcmNlbnQtcGx1cyBlc2NhcGVkIGZp
+bGVuYW1lIGRlc2NyaWJpbmcgdGhlCiAgICBtb3VudHBvaW50IGZvciB0aGUgY3Vy
+cmVudCBvcGVyYXRpb24gKGUuZy4gdXNlZCBieSAiZzEzIC0tbW91bnQiKS4KICAg
+IFRoaXMgbWF5IGVpdGhlciBiZSB0aGUgc3BlY2lmaWVkIG1vdW50cG9pbnQgb3Ig
+b25lIHJhbmRvbWx5CiAgICBjaG9vc2VuIGJ5IGcxMy4KCioqKiBQSU5FTlRSWV9M
+QVVOQ0hFRCA8cGlkPgogICAgVGhpcyBzdGF0dXMgbGluZSBpcyBlbWl0dGVkIGJ5
+IGdwZyB0byBub3RpZnkgYSBjbGllbnQgdGhhdCBhCiAgICBQaW5lbnRyeSBoYXMg
+YmVlbiBsYXVuY2hlZC4gIDxwaWQ+IGlzIHRoZSBQSUQgb2YgdGhlIFBpbmVudHJ5
+LiAgSXQKICAgIG1heSBiZSB1c2VkIHRvIGRpc3BsYXkgYSBoaW50IHRvIHRoZSB1
+c2VyIGJ1dCBjYW4ndCBiZSB1c2VkIHRvCiAgICBzeW5jaHJvbml6ZSB3aXRoIFBp
+bmVudHJ5LiAgTm90ZSB0aGF0IHRoZXJlIGlzIGFsc28gYW4gQXNzdWFuCiAgICBp
+bnF1aXJ5IGxpbmUgd2l0aCB0aGUgc2FtZSBuYW1lIHVzZWQgaW50ZXJuYWxseSBv
+ciwgaWYgZW5hYmxlZCwKICAgIHNlbmQgdG8gdGhlIGNsaWVudCBpbnN0ZWFkIG9m
+IHRoaXMgc3RhdHVzIGxpbmUuICBTdWNoIGFuIGlucXVpcnkKICAgIG1heSBiZSB1
+c2VkIHRvIHN5bmMgd2l0aCBQaW5lbnRyeQoKKiogT2Jzb2xldGUgc3RhdHVzIGNv
+ZGVzCioqKiBTSUdFWFBJUkVECiAgICBSZW1vdmVkIG9uIDIwMTEtMDItMDQuICBU
+aGlzIGlzIGRlcHJlY2F0ZWQgaW4gZmF2b3Igb2YgS0VZRVhQSVJFRC4KKioqIFJT
+QV9PUl9JREVBCiAgICBPYnNvbGV0ZS4gIFRoaXMgc3RhdHVzIG1lc3NhZ2UgdXNl
+ZCB0byBiZSBlbWl0dGVkIGZvciByZXF1ZXN0cyB0bwogICAgdXNlIHRoZSBJREVB
+IG9yIFJTQSBhbGdvcml0aG1zLiAgSXQgaGFzIGJlZW4gZHJvcHBlZCBmcm9tIEdu
+dVBHCiAgICAyLjEgYWZ0ZXIgdGhlIHJlc3BlY3RpdmUgcGF0ZW50cyBleHBpcmVk
+LgoqKiogU0hNX0lORk8sIFNITV9HRVQsIFNITV9HRVRfQk9PTCwgU0hNX0dFVF9I
+SURERU4KICAgIFRoZXNlIHdlcmUgdXNlZCBmb3IgdGhlIGFuY2llbnQgc2hhcmVk
+IG1lbW9yeSBiYXNlZCBjby1wcm9jZXNzaW5nLgoqKiogQkVHSU5fU1RSRUFNLCBF
+TkRfU1RSRUFNCiAgICBVc2VkIHRvIGlzc3VlZCBieSB0aGUgZXhwZXJpbWVudGFs
+IHBpcGVtb2RlLgoKCiogRm9ybWF0IG9mIHRoZSAtLWF0dHJpYnV0ZS1mZCBvdXRw
+dXQKCiAgV2hlbiAtLWF0dHJpYnV0ZS1mZCBpcyBzZXQsIGR1cmluZyBrZXkgbGlz
+dGluZ3MgKC0tbGlzdC1rZXlzLAogIC0tbGlzdC1zZWNyZXQta2V5cykgR251UEcg
+ZHVtcHMgZWFjaCBhdHRyaWJ1dGUgcGFja2V0IHRvIHRoZSBmaWxlCiAgZGVzY3Jp
+cHRvciBzcGVjaWZpZWQuICAtLWF0dHJpYnV0ZS1mZCBpcyBpbnRlbmRlZCBmb3Ig
+dXNlIHdpdGgKICAtLXN0YXR1cy1mZCBhcyBwYXJ0IG9mIHRoZSByZXF1aXJlZCBp
+bmZvcm1hdGlvbiBpcyBjYXJyaWVkIG9uIHRoZQogIEFUVFJJQlVURSBzdGF0dXMg
+dGFnIChzZWUgYWJvdmUpLgoKICBUaGUgY29udGVudHMgb2YgdGhlIGF0dHJpYnV0
+ZSBkYXRhIGlzIHNwZWNpZmllZCBieSBSRkMgNDg4MC4gIEZvcgogIGNvbnZlbmll
+bmNlLCBoZXJlIGlzIHRoZSBQaG90byBJRCBmb3JtYXQsIGFzIGl0IGlzIGN1cnJl
+bnRseSB0aGUKICBvbmx5IGF0dHJpYnV0ZSBkZWZpbmVkOgoKICAtIEJ5dGUgMC0x
+IDo6IFRoZSBsZW5ndGggb2YgdGhlIGltYWdlIGhlYWRlci4gIER1ZSB0byBhIGhp
+c3RvcmljYWwKICAgICAgICAgICAgICAgIGFjY2lkZW50IChpLmUuIG9vcHMhKSBi
+YWNrIGluIHRoZSBOQUkgUEdQIGRheXMsIHRoaXMKICAgICAgICAgICAgICAgIGlz
+IGEgbGl0dGxlLWVuZGlhbiBudW1iZXIuICBDdXJyZW50bHkgMTYgKDB4MTAgMHgw
+MCkuCgogIC0gQnl0ZSAyIDo6IFRoZSBpbWFnZSBoZWFkZXIgdmVyc2lvbi4gIEN1
+cnJlbnRseSAweDAxLgoKICAtIEJ5dGUgMyA6OiBFbmNvZGluZyBmb3JtYXQuICAw
+eDAxID09IEpQRUcuCgogIC0gQnl0ZSA0LTE1IDo6IFJlc2VydmVkLCBhbmQgY3Vy
+cmVudGx5IHVudXNlZC4KCiAgQWxsIG90aGVyIGRhdGEgYWZ0ZXIgdGhpcyBoZWFk
+ZXIgaXMgcmF3IGltYWdlIChKUEVHKSBkYXRhLgoKCiogVW5hdHRlbmRlZCBrZXkg
+Z2VuZXJhdGlvbgoKICAgUGxlYXNlIHNlZSB0aGUgR251UEcgbWFudWFsIGZvciBh
+IGRlc2NyaXB0aW9uLgoKCiogTGF5b3V0IG9mIHRoZSBUcnVzdERCCgogIFRoZSBU
+cnVzdERCIGlzIGJ1aWx0IGZyb20gZml4ZWQgbGVuZ3RoIHJlY29yZHMsIHdoZXJl
+IHRoZSBmaXJzdCBieXRlCiAgZGVzY3JpYmVzIHRoZSByZWNvcmQgdHlwZS4gIEFs
+bCBudW1lcmljIHZhbHVlcyBhcmUgc3RvcmVkIGluIG5ldHdvcmsKICBieXRlIG9y
+ZGVyLiAgVGhlIGxlbmd0aCBvZiBlYWNoIHJlY29yZCBpcyA0MCBieXRlcy4gIFRo
+ZSBmaXJzdAogIHJlY29yZCBvZiB0aGUgREIgaXMgYWx3YXlzIG9mIHR5cGUgMSBh
+bmQgdGhpcyBpcyB0aGUgb25seSByZWNvcmQgb2YKICB0aGlzIHR5cGUuCgogIFRo
+ZSByZWNvcmQgdHlwZXM6IGRpcmVjdG9yeSgyKSwga2V5KDMpLCB1aWQoNCksIHBy
+ZWYoNSksIHNpZ3JlYyg2KSwKICBhbmQgc2hhZG93IGRpcmVjdG9yeSg4KSBhcmUg
+bm90IGFueW1vcmUgdXNlZCBieSB2ZXJzaW9uIDIgb2YgdGhlCiAgVHJ1c3REQi4K
+CioqIFJlY29yZCB0eXBlIDAKCiAgIFVudXNlZCByZWNvcmQgb3IgZGVsZXRlZCwg
+Y2FuIGJlIHJldXNlZCBmb3IgYW55IHB1cnBvc2UuICBTdWNoCiAgIHJlY29yZHMg
+c2hvdWxkIGluIGdlbmVyYWwgbm90IGV4aXN0IGJlY2F1c2UgZGVsZXRlZCByZWNv
+cmRzIGFyZSBvZgogICB0eXBlIDI1NCBhbmQga2VwdCBpbiBhIGxpbmtlZCBsaXN0
+LgoKKiogVmVyc2lvbiBpbmZvIChSRUNUWVBFX1ZFUiwgMSkKCiAgIFZlcnNpb24g
+aW5mb3JtYXRpb24gZm9yIHRoaXMgVHJ1c3REQi4gIFRoaXMgaXMgYWx3YXlzIHRo
+ZSBmaXJzdAogICByZWNvcmQgb2YgdGhlIERCIGFuZCB0aGUgb25seSBvbmUgb2Yg
+dGhpcyB0eXBlLgoKICAgLSAxIHU4IDo6IFJlY29yZCB0eXBlICh2YWx1ZTogMSku
+CiAgIC0gMyBieXRlIDo6IE1hZ2ljIHZhbHVlICgiZ3BnIikKICAgLSAxIHU4IDo6
+IFRydXN0REIgdmVyc2lvbiAodmFsdWU6IDIpLgogICAtIDEgdTggOjogPW1hcmdp
+bmFscz0uIEhvdyBtYW55IG1hcmdpbmFsIHRydXN0ZWQga2V5cyBhcmUgcmVxdWly
+ZWQuCiAgIC0gMSB1OCA6OiA9Y29tcGxldGVzPS4gSG93IG1hbnkgY29tcGxldGVs
+eSB0cnVzdGVkIGtleXMgYXJlCiAgICAgICAgICAgICByZXF1aXJlZC4KICAgLSAx
+IHU4IDo6ID1tYXhfY2VydF9kZXB0aD0uICBIb3cgZGVlcCBpcyB0aGUgV29UIGV2
+YWx1YXRlZC4gIEFsb25nCiAgICAgICAgICAgICB3aXRoID1tYXJnaW5hbHM9IGFu
+ZCA9Y29tcGxldGVzPSwgdGhpcyB2YWx1ZSBpcyB1c2VkIHRvCiAgICAgICAgICAg
+ICBjaGVjayB3aGV0aGVyIHRoZSBjYWNoZWQgdmFsaWRpdHkgdmFsdWUgZnJvbSBh
+IFtGSVhNRQogICAgICAgICAgICAgZGlyXSByZWNvcmQgY2FuIGJlIHVzZWQuCiAg
+IC0gMSB1OCA6OiA9dHJ1c3RfbW9kZWw9CiAgIC0gMSB1OCA6OiA9bWluX2NlcnRf
+bGV2ZWw9CiAgIC0gMiBieXRlIDo6IE5vdCB1c2VkCiAgIC0gMSB1MzIgOjogPWNy
+ZWF0ZWQ9LiBUaW1lc3RhbXAgb2YgdHJ1c3RkYiBjcmVhdGlvbi4KICAgLSAxIHUz
+MiA6OiA9bmV4dGNoZWNrPS4gVGltZXN0YW1wIG9mIGxhc3QgbW9kaWZpY2F0aW9u
+IHdoaWNoIG1heQogICAgICAgICAgICAgIGFmZmVjdCB0aGUgdmFsaWRpdHkgb2Yg
+a2V5cyBpbiB0aGUgdHJ1c3RkYi4gIFRoaXMgdmFsdWUKICAgICAgICAgICAgICBp
+cyBjaGVja2VkIGFnYWluc3QgdGhlIHZhbGlkaXR5IHRpbWVzdGFtcCBpbiB0aGUg
+ZGlyCiAgICAgICAgICAgICAgcmVjb3Jkcy4KICAgLSAxIHUzMiA6OiA9cmVzZXJ2
+ZWQ9LiAgTm90IHVzZWQuCiAgIC0gMSB1MzIgOjogPXJlc2VydmVkMj0uIE5vdCB1
+c2VkLgogICAtIDEgdTMyIDo6ID1maXJzdGZyZWU9LiBOdW1iZXIgb2YgdGhlIHJl
+Y29yZCB3aXRoIHRoZSBoZWFkIHJlY29yZAogICAgICAgICAgICAgIG9mIHRoZSBS
+RUNUWVBFX0ZSRUUgbGlua2VkIGxpc3QuCiAgIC0gMSB1MzIgOjogPXJlc2VydmVk
+Mz0uIE5vdCB1c2VkLgogICAtIDEgdTMyIDo6ID10cnVzdGhhc2h0Ymw9LiBSZWNv
+cmQgbnVtYmVyIG9mIHRoZSB0cnVzdGhhc2h0YWJsZS4KCgoqKiBIYXNoIHRhYmxl
+IChSRUNUWVBFX0hUQkwsIDEwKQoKICAgRHVlIHRvIHRoZSBmYWN0IHRoYXQgd2Ug
+dXNlIGZpbmdlcnByaW50cyB0byBsb29rdXAga2V5cywgd2UgY2FuCiAgIGltcGxl
+bWVudCBxdWljayBhY2Nlc3MgYnkgc29tZSBzaW1wbGUgaGFzaCBtZXRob2RzLCBh
+bmQgYXZvaWQgdGhlCiAgIG92ZXJoZWFkIG9mIGdkYm0uICBBIHByb3BlcnR5IG9m
+IGZpbmdlcnByaW50cyBpcyB0aGF0IHRoZXkgY2FuIGJlCiAgIHVzZWQgZGlyZWN0
+bHkgYXMgaGFzaCB2YWx1ZXMuICBXaGF0IHdlIHVzZSBpcyBhIGR5bmFtaWMgbXVs
+dGlsZXZlbAogICBhcmNoaXRlY3R1cmUsIHdoaWNoIGNvbWJpbmVzIGhhc2ggdGFi
+bGVzLCByZWNvcmQgbGlzdHMsIGFuZCBsaW5rZWQKICAgbGlzdHMuCgogICBUaGlz
+IHJlY29yZCBpcyBhIGhhc2ggdGFibGUgb2YgMjU2IGVudHJpZXMgd2l0aCB0aGUg
+cHJvcGVydHkgdGhhdAogICBhbGwgdGhlc2UgcmVjb3JkcyBhcmUgc3RvcmVkIGNv
+bnNlY3V0aXZlbHkgdG8gbWFrZSBvbmUgYmlnCiAgIHRhYmxlLiBUaGUgaGFzaCB2
+YWx1ZSBpcyBzaW1wbGUgdGhlIDFzdCwgMm5kLCAuLi4gYnl0ZSBvZiB0aGUKICAg
+ZmluZ2VycHJpbnQgKGRlcGVuZGluZyBvbiB0aGUgaW5kaXJlY3Rpb24gbGV2ZWwp
+LgoKICAgLSAxIHU4IDo6IFJlY29yZCB0eXBlICh2YWx1ZTogMTApLgogICAtIDEg
+dTggOjogUmVzZXJ2ZWQKICAgLSBuIHUzMiA6OiA9cmVjbnVtPS4gIEEgdGFibGUg
+d2l0aCB0aGUgaGFzaCB0YWJsZSBpdGVtcyBmaXR0aW5nIGludG8KICAgICAgICAg
+ICAgICB0aGlzIHJlY29yZC4gID1uPSBkZXBlbmRzIG9uIHRoZSByZWNvcmQgbGVu
+Z3RoOgogICAgICAgICAgICAgICRuPShyZWNsZW4tMikvNCQgd2hpY2ggeWllbGRz
+IDkgZm9yIG91cmUgY3VycmVudCByZWNvcmQKICAgICAgICAgICAgICBsZW5ndGgg
+b2YgNDAgYnl0ZXMuCgogICBUaGUgdG90YWwgbnVtYmVyIG9mIGhhc2ggdGFibGUg
+cmVjb3JkcyB0byBmb3JtIHRoZSB0YWJsZSBpczoKICAgJG09KDI1NituLTEpL24k
+LiAgVGhpcyBpcyAyOSBmb3Igb3VyIHJlY29yZCBsZW5ndGggb2YgNDAuCgogICBU
+byBsb29rIHVwIGEga2V5IHdlIHVzZSB0aGUgZmlyc3QgYnl0ZSBvZiB0aGUgZmlu
+Z2VycHJpbnQgdG8gZ2V0CiAgIHRoZSByZWNudW0gZnJvbSB0aGlzIGhhc2ggdGFi
+bGUgYW5kIHRoZW4gbG9vayB1cCB0aGUgYWRkcmVzc2VkCiAgIHJlY29yZDoKCiAg
+IC0gSWYgdGhhdCByZWNvcmQgaXMgYW5vdGhlciBoYXNoIHRhYmxlLCB3ZSB1c2Ug
+Mm5kIGJ5dGUgdG8gaW5kZXgKICAgICB0aGF0IGhhc2ggdGFibGUgYW5kIHNvIG9u
+OwogICAtIGlmIHRoYXQgcmVjb3JkIGlzIGEgaGFzaCBsaXN0LCB3ZSB3YWxrIGFs
+bCBlbnRyaWVzIHVudGlsIHdlIGZpbmQKICAgICBhIG1hdGNoaW5nIG9uZTsgb3IK
+ICAgLSBpZiB0aGF0IHJlY29yZCBpcyBhIGtleSByZWNvcmQsIHdlIGNvbXBhcmUg
+dGhlIGZpbmdlcnByaW50IHRvCiAgICAgZGVjaWRlIHdoZXRoZXIgaXQgaXMgdGhl
+IHJlcXVlc3RlZCBrZXk7CgoKKiogSGFzaCBsaXN0IChSRUNUWVBFX0hMU1QsIDEx
+KQoKICAgU2VlIGhhc2ggdGFibGUgYWJvdmUgb24gaG93IGl0IGlzIHVzZWQuICBJ
+dCBtYXkgYWxzbyBiZSB1c2VkIGZvcgogICBvdGhlciBwdXJwb3Nlcy4KCiAgIC0g
+MSB1OCA6OiBSZWNvcmQgdHlwZSAodmFsdWU6IDExKS4KICAgLSAxIHU4IDo6IFJl
+c2VydmVkLgogICAtIDEgdTMyIDo6ID1uZXh0PS4gIFJlY29yZCBudW1iZXIgb2Yg
+dGhlIG5leHQgaGFzaCBsaXN0IHJlY29yZCBvciAwCiAgICAgICAgICAgICAgaWYg
+bm9uZS4KICAgLSBuIHUzMiA6OiA9cm51bT0uICBBcnJheSB3aXRoIHJlY29yZCBu
+dW1iZXJzIHRvIHZhbHVlcy4gIFdpdGgKICAgICAgICAgICAgICAkbj0ocmVjbGVu
+LTUpLzUkIGFuZCBvdXIgcmVjb3JkIGxlbmd0aCBvZiA0MCwgbiBpcyA3LgoKKiog
+VHJ1c3QgcmVjb3JkIChSRUNUWVBFX1RSVVNULCAxMikKCiAgIC0gMSB1OCA6OiBS
+ZWNvcmQgdHlwZSAodmFsdWU6IDEyKS4KICAgLSAxIHU4IDo6IFJlc2VydmVkLgog
+ICAtIDIwIGJ5dGUgOjogPWZpbmdlcnByaW50PS4KICAgLSAxIHU4IDo6ID1vd25l
+cnRydXN0PS4KICAgLSAxIHU4IDo6ID1kZXB0aD0uCiAgIC0gMSB1OCA6OiA9bWlu
+X293bmVydHJ1c3Q9LgogICAtIDEgYnl0ZSA6OiBOb3QgdXNlZC4KICAgLSAxIHUz
+MiA6OiA9dmFsaWRsaXN0PS4KICAgLSAxMCBieXRlIDo6IE5vdCB1c2VkLgoKKiog
+VmFsaWRpdHkgcmVjb3JkIChSRUNUWVBFX1ZBTElELCAxMykKCiAgIC0gMSB1OCA6
+OiBSZWNvcmQgdHlwZSAodmFsdWU6IDEzKS4KICAgLSAxIHU4IDo6IFJlc2VydmVk
+LgogICAtIDIwIGJ5dGUgOjogPW5hbWVoYXNoPS4KICAgLSAxIHU4IDo6ID12YWxp
+ZGl0eT0KICAgLSAxIHUzMiA6OiA9bmV4dD0uCiAgIC0gMSB1OCA6OiA9ZnVsbF9j
+b3VudD0uCiAgIC0gMSB1OCA6OiA9bWFyZ2luYWxfY291bnQ9LgogICAtIDExIGJ5
+dGUgOjogTm90IHVzZWQuCgoqKiBGcmVlIHJlY29yZCAoUkVDVFlQRV9GUkVFLCAy
+NTQpCgogICBBbGwgdGhlc2UgcmVjb3JkcyBmb3JtIGEgbGlua2VkIGxpc3Qgb2Yg
+dW51c2VkIHJlY29yZHMgaW4gdGhlIFRydXN0REIuCgogICAtIDEgdTggOjogUmVj
+b3JkIHR5cGUgKHZhbHVlOiAyNTQpCiAgIC0gMSB1OCA6OiBSZXNlcnZlZC4KICAg
+LSAxIHUzMiA6OiA9bmV4dD0uICBSZWNvcmQgbnVtYmVyIG9mIHRoZSBuZXh0IHJj
+b3JkIG9mIHRoaXMgdHlwZS4KICAgICAgICAgICAgICBUaGUgcmVjb3JkIG51bWJl
+ciB0byB0aGUgaGVhZCBvZiB0aGlzIGxpbmtlZCBsaXN0IGlzCiAgICAgICAgICAg
+ICAgc3RvcmVkIGluIHRoZSB2ZXJzaW9uIGluZm8gcmVjb3JkLgoKCiogR05VIGV4
+dGVuc2lvbnMgdG8gdGhlIFMySyBhbGdvcml0aG0KCiAgMSBvY3RldCAgLSBTMksg
+VXNhZ2U6IGVpdGhlciAyNTQgb3IgMjU1LgogIDEgb2N0ZXQgIC0gUzJLIENpcGhl
+ciBBbGdvOiAwCiAgMSBvY3RldCAgLSBTMksgU3BlY2lmaWVyOiAxMDEKICAzIG9j
+dGV0cyAtICJHTlUiCiAgMSBvY3RldCAgLSBHTlUgUzJLIEV4dGVuc2lvbiBOdW1i
+ZXIuCgogIElmIHN1Y2ggYSBHTlUgZXh0ZW5zaW9uIGlzIHVzZWQgbmVpdGhlciBh
+biBJViBub3IgYW55IGtpbmQgb2YKICBjaGVja3N1bSBpcyB1c2VkLiAgVGhlIGRl
+ZmluZWQgR05VIFMySyBFeHRlbnNpb24gTnVtYmVycyBhcmU6CgogIC0gMSA6OiBE
+byBub3Qgc3RvcmUgdGhlIHNlY3JldCBwYXJ0IGF0IGFsbC4gIE5vIHNwZWNpZmlj
+IGRhdGEKICAgICAgICAgZm9sbG93cy4KCiAgLSAyIDo6IEEgc3R1YiB0byBhY2Nl
+c3Mgc21hcnRjYXJkcy4gIFRoaXMgZGF0YSBmb2xsb3dzOgogICAgICAgICAtIE9u
+ZSBvY3RldCB3aXRoIHRoZSBsZW5ndGggb2YgdGhlIGZvbGxvd2luZyBzZXJpYWwg
+bnVtYmVyLgogICAgICAgICAtIFRoZSBzZXJpYWwgbnVtYmVyLiBSZWdhcmRsZXNz
+IG9mIHdoYXQgdGhlIGxlbmd0aCBvY3RldAogICAgICAgICAgIGluZGljYXRlcyBu
+byBtb3JlIHRoYW4gMTYgb2N0ZXRzIGFyZSBzdG9yZWQuCgogIE5vdGUgdGhhdCBn
+cGcgc3RvcmVzIHRoZSBHTlUgUzJLIEV4dGVuc2lvbiBOdW1iZXIgaW50ZXJuYWxs
+eSBhcyBhbgogIFMySyBTcGVjaWZpZXIgd2l0aCBhbiBvZmZzZXQgb2YgMTAwMC4K
+CgoqIEtleXNlcnZlciBoZWxwZXIgbWVzc2FnZSBmb3JtYXQKCiAgVGhlIGtleXNl
+cnZlciBtYXkgYmUgY29udGFjdGVkIGJ5IGEgVW5peCBEb21haW4gc29ja2V0IG9y
+IHZpYSBUQ1AuCgogIFRoZSBmb3JtYXQgb2YgYSByZXF1ZXN0IGlzOgojK2JlZ2lu
+X2V4YW1wbGUKICBjb21tYW5kLXRhZwogICJDb250ZW50LWxlbmd0aDoiIGRpZ2l0
+cwogIENSTEYKIytlbmRfZXhhbXBsZQoKICBXaGVyZSBjb21tYW5kLXRhZyBpcwoK
+IytiZWdpbl9leGFtcGxlCiAgTk9PUAogIEdFVCA8dXNlci1uYW1lPgogIFBVVAog
+IERFTEVURSA8dXNlci1uYW1lPgojK2VuZF9leGFtcGxlCgpUaGUgZm9ybWF0IG9m
+IGEgcmVzcG9uc2UgaXM6CgojK2JlZ2luX2V4YW1wbGUKICAiR05VUEcvMS4wIiBz
+dGF0dXMtY29kZSBzdGF0dXMtdGV4dAogICJDb250ZW50LWxlbmd0aDoiIGRpZ2l0
+cwogIENSTEYKIytlbmRfZXhhbXBsZQpmb2xsb3dlZCBieSA8ZGlnaXRzPiBieXRl
+cyBvZiBkYXRhCgpTdGF0dXMgY29kZXMgYXJlOgoKICAtIDF4eCA6OiBJbmZvcm1h
+dGlvbmFsIC0gUmVxdWVzdCByZWNlaXZlZCwgY29udGludWluZyBwcm9jZXNzCgog
+IC0gMnh4IDo6IFN1Y2Nlc3MgLSBUaGUgYWN0aW9uIHdhcyBzdWNjZXNzZnVsbHkg
+cmVjZWl2ZWQsIHVuZGVyc3Rvb2QsCiAgICAgICAgICAgYW5kIGFjY2VwdGVkCgog
+IC0gNHh4IDo6IENsaWVudCBFcnJvciAtIFRoZSByZXF1ZXN0IGNvbnRhaW5zIGJh
+ZCBzeW50YXggb3IgY2Fubm90IGJlCiAgICAgICAgICAgZnVsZmlsbGVkCgogIC0g
+NXh4IDo6IFNlcnZlciBFcnJvciAtIFRoZSBzZXJ2ZXIgZmFpbGVkIHRvIGZ1bGZp
+bGwgYW4gYXBwYXJlbnRseQogICAgICAgICAgIHZhbGlkIHJlcXVlc3QKCgoqIE9i
+amVjdCBpZGVudGlmaWVycwoKICBPSURzIGJlbG93IHRoZSBHbnVQRyBhcmM6Cgoj
+K2JlZ2luX2V4YW1wbGUKICAxLjMuNi4xLjQuMS4xMTU5MS4yICAgICAgICAgIEdu
+dVBHCiAgMS4zLjYuMS40LjEuMTE1OTEuMi4xICAgICAgICAgIG5vdGF0aW9uCiAg
+MS4zLjYuMS40LjEuMTE1OTEuMi4xLjEgICAgICAgICAgcGthQWRkcmVzcwogIDEu
+My42LjEuNC4xLjExNTkxLjIuMiAgICAgICAgICBYLjUwOSBleHRlbnNpb25zCiAg
+MS4zLjYuMS40LjEuMTE1OTEuMi4yLjEgICAgICAgICAgc3RhbmRhbG9uZUNlcnRp
+ZmljYXRlCiAgMS4zLjYuMS40LjEuMTE1OTEuMi4yLjIgICAgICAgICAgd2VsbEtu
+b3duUHJpdmF0ZUtleQogIDEuMy42LjEuNC4xLjExNTkxLjIuMTIyNDI5NzMgICBp
+bnZhbGlkIGVuY29kZWQgT0lECiMrZW5kX2V4YW1wbGUKCgoKKiBNaXNjZWxsYW5l
+b3VzIG5vdGVzCgoqKiB2MyBmaW5nZXJwcmludHMKICAgRm9yIHBhY2tldCB2ZXJz
+aW9uIDMgd2UgY2FsY3VsYXRlIHRoZSBrZXlpZHMgdGhpcyB3YXk6CiAgICAtIFJT
+QSA6OiBMb3cgNjQgYml0cyBvZiBuCiAgICAtIEVMR0FNQUwgOjogQnVpbGQgYSB2
+MyBwdWJrZXkgcGFja2V0ICh3aXRoIENUQiAweDk5KSBhbmQKICAgICAgICAgICAg
+ICAgICBjYWxjdWxhdGUgYSBSTUQxNjAgaGFzaCB2YWx1ZSBmcm9tIGl0LiBUaGlz
+IGlzIHVzZWQKICAgICAgICAgICAgICAgICBhcyB0aGUgZmluZ2VycHJpbnQgYW5k
+IHRoZSBsb3cgNjQgYml0cyBhcmUgdGhlIGtleWlkLgoKKiogU2ltcGxpZmllZCBy
+ZXZvY2F0aW9uIGNlcnRpZmljYXRlcwogIFJldm9jYXRpb24gY2VydGlmaWNhdGVz
+IGNvbnNpc3Qgb25seSBvZiB0aGUgc2lnbmF0dXJlIHBhY2tldDsKICAiLS1pbXBv
+cnQiIGtub3dzIGhvdyB0byBoYW5kbGUgdGhpcy4gIFRoZSByYXRpb25hbGUgYmVo
+aW5kIGl0IGlzIHRvCiAga2VlcCB0aGVtIHNtYWxsLgoKKiogRG9jdW1lbnRhdGlv
+biBvbiBIS1AgKHRoZSBodHRwIGtleXNlcnZlciBwcm90b2NvbCk6CgogICBBIG1p
+bmltYWxpc3RpYyBIVFRQIHNlcnZlciBvbiBwb3J0IDExMzcxIHJlY29nbml6ZXMg
+YSBHRVQgZm9yCiAgIC9wa3MvbG9va3VwLiAgVGhlIHN0YW5kYXJkIGh0dHAgVVJM
+IGVuY29kZWQgcXVlcnkgcGFyYW1ldGVycyBhcmUKICAgdGhpcyAoYWx3YXlzIGtl
+eT12YWx1ZSk6CgogICAtIG9wPWluZGV4IChsaWtlIHBncCAta3YpLCBvcD12aW5k
+ZXggKGxpa2UgcGdwIC1rdnYpIGFuZCBvcD1nZXQgKGxpa2UKICAgICBwZ3AgLWt4
+YSkKCiAgIC0gc2VhcmNoPTxzdHJpbmdsaXN0Pi4gVGhpcyBpcyBhIGxpc3Qgb2Yg
+d29yZHMgdGhhdCBtdXN0IG9jY3VyIGluIHRoZSBrZXkuCiAgICAgVGhlIHdvcmRz
+IGFyZSBkZWxpbWl0ZWQgd2l0aCBzcGFjZSwgcG9pbnRzLCBAIGFuZCBzbyBvbi4g
+VGhlIGRlbGltaXRlcnMKICAgICBhcmUgbm90IHNlYXJjaGVkIGZvciBhbmQgdGhl
+IG9yZGVyIG9mIHRoZSB3b3JkcyBkb2Vzbid0IG1hdHRlciAoYnV0IHNlZQogICAg
+IG5leHQgb3B0aW9uKS4KCiAgIC0gZXhhY3Q9b24uIFRoaXMgc3dpdGNoIHRlbGxz
+IHRoZSBoa3Agc2VydmVyIHRvIG9ubHkgcmVwb3J0IGV4YWN0IG1hdGNoaW5nCiAg
+ICAga2V5cyBiYWNrLiBJbiB0aGlzIGNhc2UgdGhlIG9yZGVyIGFuZCB0aGUgImRl
+bGltaXRlcnMiIGFyZSBpbXBvcnRhbnQuCgogICAtIGZpbmdlcnByaW50PW9uLiBB
+bHNvIHJlcG9ydHMgdGhlIGZpbmdlcnByaW50cyB3aGVuIHVzZWQgd2l0aCAnaW5k
+ZXgnIG9yCiAgICAgJ3ZpbmRleCcKCiAgIFRoZSBrZXlzZXJ2ZXIgYWxzbyByZWNv
+Z25pemVzIGh0dHAtUE9TVHMgdG8gL3Brcy9hZGQuIFVzZSB0aGlzIHRvIHVwbG9h
+ZAogICBrZXlzLgoKCiAgIEEgYmV0dGVyIHdheSB0byBkbyB0aGlzIHdvdWxkIGJl
+IGEgcmVxdWVzdCBsaWtlOgoKICAgICAgL3Brcy9sb29rdXAvPGdudXBnX2Zvcm1h
+dGllcnRlX3VzZXJfaWQ+P29wPTxvcGVyYXRpb24+CgogICBUaGlzIGNhbiBiZSBp
+bXBsZW1lbnRlZCB1c2luZyBIdXJkJ3MgdHJhbnNsYXRvciBtZWNoYW5pc20uCiAg
+IEhvd2V2ZXIsIEkgdGhpbmsgdGhlIHdob2xlIGtleSBzZXJ2ZXIgc3R1ZmYgaGFz
+IHRvIGJlIHJlLXRob3VnaHQ7CiAgIEkgaGF2ZSBzb21lIGlkZWFzIGFuZCBwcm9i
+YWJseSBjcmVhdGUgYSB3aGl0ZSBwYXBlci4KKiogQWxnb3JpdGhtIG5hbWVzIGZv
+ciB0aGUgImtleWdlbi5hbGdvIiBwcm9tcHQKCiAgV2hlbiB1c2luZyBhIC0tY29t
+bWFuZC1mZCBjb250cm9sbGVkIGtleSBnZW5lcmF0aW9uIG9yICJhZGRrZXkiCiAg
+dGhlcmUgaXMgd2F5IHRvIGtub3cgdGhlIG51bWJlciB0byBlbnRlciBvbiB0aGUg
+ImtleWdlbi5hbGdvIgogIHByb21wdC4gIFRoZSBkaXNwbGF5ZWQgbnVtYmVycyBh
+cmUgZm9yIGh1bWFuIHJlY2VwdGlvbiBhbmQgbWF5CiAgY2hhbmdlIHdpdGggcmVs
+ZWFzZXMuICBUbyBwcm92aWRlIGEgc3RhYmxlIHdheSB0byBlbnRlciBhIGRlc2ly
+ZWQKICBhbGdvcml0aG0gY2hvaWNlIHRoZSBwcm9tcHQgYWxzbyBhY2NlcHRzIHBy
+ZWRlZmluZWQgbmFtZXMgZm9yIHRoZQogIGFsZ29yaXRobXMsIHdoaWNoIHdpbGwg
+bm90IGNoYW5nZS4KCiAgIHwgTmFtZSAgICB8IE5vIHwgRGVzY3JpcHRpb24gICAg
+ICAgICAgICAgICAgICAgICB8CiAgIHwtLS0tLS0tLS0rLS0tLSstLS0tLS0tLS0t
+LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CiAgIHwgcnNhK3JzYSB8ICAxIHwgUlNB
+IGFuZCBSU0EgKGRlZmF1bHQpICAgICAgICAgICB8CiAgIHwgZHNhK2VsZyB8ICAy
+IHwgRFNBIGFuZCBFbGdhbWFsICAgICAgICAgICAgICAgICB8CiAgIHwgZHNhICAg
+ICB8ICAzIHwgRFNBIChzaWduIG9ubHkpICAgICAgICAgICAgICAgICB8CiAgIHwg
+cnNhL3MgICB8ICA0IHwgUlNBIChzaWduIG9ubHkpICAgICAgICAgICAgICAgICB8
+CiAgIHwgZWxnICAgICB8ICA1IHwgRWxnYW1hbCAoZW5jcnlwdCBvbmx5KSAgICAg
+ICAgICB8CiAgIHwgcnNhL2UgICB8ICA2IHwgUlNBIChlbmNyeXB0IG9ubHkpICAg
+ICAgICAgICAgICB8CiAgIHwgZHNhLyogICB8ICA3IHwgRFNBIChzZXQgeW91ciBv
+d24gY2FwYWJpbGl0aWVzKSB8CiAgIHwgcnNhLyogICB8ICA4IHwgUlNBIChzZXQg
+eW91ciBvd24gY2FwYWJpbGl0aWVzKSB8CiAgIHwgZWNjK2VjYyB8ICA5IHwgRUND
+IGFuZCBFQ0MgICAgICAgICAgICAgICAgICAgICB8CiAgIHwgZWNjL3MgICB8IDEw
+IHwgRUNDIChzaWduIG9ubHkpICAgICAgICAgICAgICAgICB8CiAgIHwgZWNjLyog
+ICB8IDExIHwgRUNDIChzZXQgeW91ciBvd24gY2FwYWJpbGl0aWVzKSB8CiAgIHwg
+ZWNjL2UgICB8IDEyIHwgRUNDIChlbmNyeXB0IG9ubHkpICAgICAgICAgICAgICB8
+CiAgIHwga2V5Z3JpcCB8IDEzIHwgRXhpc3Rpbmcga2V5ICAgICAgICAgICAgICAg
+ICAgICB8CgogICBJZiBvbmUgb2YgdGhlICJmb28vKiIgbmFtZXMgYXJlIHVzZWQg
+YSAia2V5Z2VuLmZsYWdzIiBwcm9tcHQgbmVlZHMKICAgdG8gYmUgYW5zd2VyZWQg
+YXMgd2VsbC4gIEluc3RlYWQgb2YgdG9nZ2xpbmcgdGhlIHByZWRlZmluZWQgZmxh
+Z3MsCiAgIGl0IGlzIGFsc28gcG9zc2libGUgdG8gc2V0IHRoZW0gZGlyZWN0OiBV
+c2UgYSAiPSIgY2hhcmFjdGVyCiAgIGRpcmVjdGx5IGZvbGxvd2VkIGJ5IGEgY29t
+aW5hdGlvbiBvZiAiYSIgKGZvciBhdXRoZW50aWNhdGlvbiksICJzIgogICAoZm9y
+IHNpZ25pbmcpLCBvciAiYyIgKGZvciBjZXJ0aWZpY2F0aW9uKS4KQGMgQ29weXJp
+Z2h0IChDKSAxOTk4LCAxOTk5LCAyMDAwLCAyMDAxLCAyMDAyLCAyMDAzLCAyMDA0
+LCAyMDA1LCAyMDA2LCAyMDA3LApAYyAgICAgICAgICAgICAgIDIwMDgsIDIwMDks
+IDIwMTAgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uLCBJbmMuCkBjIFRoaXMgaXMg
+cGFydCBvZiB0aGUgR251UEcgbWFudWFsLgpAYyBGb3IgY29weWluZyBjb25kaXRp
+b25zLCBzZWUgdGhlIGZpbGUgZ251cGcudGV4aS4KCkBpbmNsdWRlIGRlZnMuaW5j
+CgpAbm9kZSBJbnZva2luZyBHUEcKQGNoYXB0ZXIgSW52b2tpbmcgR1BHCkBjaW5k
+ZXggR1BHIGNvbW1hbmQgb3B0aW9ucwpAY2luZGV4IGNvbW1hbmQgb3B0aW9ucwpA
+Y2luZGV4IG9wdGlvbnMsIEdQRyBjb21tYW5kCgpAbWFjcm8gZ3BnbmFtZQpncGcy
+CkBlbmQgbWFjcm8KQG1hbnBhZ2UgZ3BnMi4xCkBpZnNldCBtYW52ZXJiCi5CIGdw
+ZzIKXC0gT3BlblBHUCBlbmNyeXB0aW9uIGFuZCBzaWduaW5nIHRvb2wKQGVuZCBp
+ZnNldAoKQG1hbnNlY3Qgc3lub3BzaXMKQGlmc2V0IG1hbnZlcmIKLkIgIGdwZzIK
+LlJCIFsgXC1cLWhvbWVkaXIKLklSIGRpciBdCi5SQiBbIFwtXC1vcHRpb25zCi5J
+UiBmaWxlIF0KLlJJIFsgb3B0aW9ucyBdCi5JIGNvbW1hbmQKLlJJIFsgYXJncyBd
+CkBlbmQgaWZzZXQKCgpAbWFuc2VjdCBkZXNjcmlwdGlvbgpAY29tbWFuZHtAZ3Bn
+bmFtZX0gaXMgdGhlIE9wZW5QR1AgcGFydCBvZiB0aGUgR05VIFByaXZhY3kgR3Vh
+cmQgKEdudVBHKS4gSXQKaXMgYSB0b29sIHRvIHByb3ZpZGUgZGlnaXRhbCBlbmNy
+eXB0aW9uIGFuZCBzaWduaW5nIHNlcnZpY2VzIHVzaW5nIHRoZQpPcGVuUEdQIHN0
+YW5kYXJkLiBAY29tbWFuZHtAZ3BnbmFtZX0gZmVhdHVyZXMgY29tcGxldGUga2V5
+IG1hbmFnZW1lbnQgYW5kCmFsbCBiZWxscyBhbmQgd2hpc3RsZXMgeW91IGNhbiBl
+eHBlY3QgZnJvbSBhIGRlY2VudCBPcGVuUEdQCmltcGxlbWVudGF0aW9uLgoKSW4g
+Y29udHJhc3QgdG8gdGhlIHN0YW5kYWxvbmUgY29tbWFuZCBncGcgZnJvbSBHbnVQ
+RyAxLngsIHdoaWNoIGlzCm1pZ2h0IGJlIGJldHRlciBzdWl0ZWQgZm9yIHNlcnZl
+ciBhbmQgZW1iZWRkZWQgcGxhdGZvcm1zLCB0aGUgMi54CnZlcnNpb24gaXMgY29t
+bW9ubHkgaW5zdGFsbGVkIHVuZGVyIHRoZSBuYW1lIEBjb21tYW5ke2dwZzJ9IGFu
+ZAp0YXJnZXRlZCB0byB0aGUgZGVza3RvcCBhcyBpdCByZXF1aXJlcyBzZXZlcmFs
+IG90aGVyIG1vZHVsZXMgdG8gYmUKaW5zdGFsbGVkLgoKQG1hbnBhdXNlClRoZSBv
+bGQgMS54IHZlcnNpb24gd2lsbCBiZSBrZXB0IG1haW50YWluZWQgYW5kIGl0IGlz
+IHBvc3NpYmxlIHRvCmluc3RhbGwgYm90aCB2ZXJzaW9ucyBvbiB0aGUgc2FtZSBz
+eXN0ZW0uICBEb2N1bWVudGF0aW9uIGZvciB0aGUgb2xkCkdudVBHIDEueCBjb21t
+YW5kIGlzIGF2YWlsYWJsZSBhcyBhIG1hbiBwYWdlIGFuZCBhdApAaW5mb3JlZntU
+b3AsR251UEcgMSxncGd9LgoKQHhyZWZ7T3B0aW9uIEluZGV4fSwgZm9yIGFuIGlu
+ZGV4IHRvIEBjb21tYW5ke0BncGduYW1lfSdzIGNvbW1hbmRzIGFuZCBvcHRpb25z
+LgpAbWFuY29udAoKQG1lbnUKKiBHUEcgQ29tbWFuZHM6OiAgICAgICAgICAgIExp
+c3Qgb2YgYWxsIGNvbW1hbmRzLgoqIEdQRyBPcHRpb25zOjogICAgICAgICAgICAg
+TGlzdCBvZiBhbGwgb3B0aW9ucy4KKiBHUEcgQ29uZmlndXJhdGlvbjo6ICAgICAg
+IENvbmZpZ3VyYXRpb24gZmlsZXMuCiogR1BHIEV4YW1wbGVzOjogICAgICAgICAg
+ICBTb21lIHVzYWdlIGV4YW1wbGVzLgoKRGV2ZWxvcGVyIGluZm9ybWF0aW9uOgoq
+IFVuYXR0ZW5kZWQgVXNhZ2Ugb2YgR1BHOjogVXNpbmcgQGNvbW1hbmR7Z3BnfSBm
+cm9tIG90aGVyIHByb2dyYW1zLgpAZW5kIG1lbnUKCkBjICogR1BHIFByb3RvY29s
+OjogICAgICAgIFRoZSBwcm90b2NvbCB0aGUgc2VydmVyIG1vZGUgdXNlcy4KCgpA
+YyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCkBj
+ICoqKioqKioqKioqKioqKiAgICAgICAgICAgICoqKioqKioqKioqKioqKioKQGMg
+KioqKioqKioqKioqKioqICBDT01NQU5EUyAgKioqKioqKioqKioqKioqKgpAYyAq
+KioqKioqKioqKioqKiogICAgICAgICAgICAqKioqKioqKioqKioqKioqCkBjICoq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKQG1hbnNl
+Y3QgY29tbWFuZHMKQG5vZGUgR1BHIENvbW1hbmRzCkBzZWN0aW9uIENvbW1hbmRz
+CgpDb21tYW5kcyBhcmUgbm90IGRpc3Rpbmd1aXNoZWQgZnJvbSBvcHRpb25zIGV4
+Y2VwdCBmb3IgdGhlIGZhY3QgdGhhdApvbmx5IG9uZSBjb21tYW5kIGlzIGFsbG93
+ZWQuCgpAY29tbWFuZHtAZ3BnbmFtZX0gbWF5IGJlIHJ1biB3aXRoIG5vIGNvbW1h
+bmRzLCBpbiB3aGljaCBjYXNlIGl0IHdpbGwKcGVyZm9ybSBhIHJlYXNvbmFibGUg
+YWN0aW9uIGRlcGVuZGluZyBvbiB0aGUgdHlwZSBvZiBmaWxlIGl0IGlzIGdpdmVu
+CmFzIGlucHV0IChhbiBlbmNyeXB0ZWQgbWVzc2FnZSBpcyBkZWNyeXB0ZWQsIGEg
+c2lnbmF0dXJlIGlzIHZlcmlmaWVkLAphIGZpbGUgY29udGFpbmluZyBrZXlzIGlz
+IGxpc3RlZCkuCgpQbGVhc2UgcmVtZW1iZXIgdGhhdCBvcHRpb24gYXMgd2VsbCBh
+cyBjb21tYW5kIHBhcnNpbmcgc3RvcHMgYXMgc29vbiBhcwphIG5vbi1vcHRpb24g
+aXMgZW5jb3VudGVyZWQsIHlvdSBjYW4gZXhwbGljaXRseSBzdG9wIHBhcnNpbmcg
+YnkKdXNpbmcgdGhlIHNwZWNpYWwgb3B0aW9uIEBvcHRpb257LS19LgoKCkBtZW51
+CiogR2VuZXJhbCBHUEcgQ29tbWFuZHM6OiAgICAgICAgQ29tbWFuZHMgbm90IHNw
+ZWNpZmljIHRvIHRoZSBmdW5jdGlvbmFsaXR5LgoqIE9wZXJhdGlvbmFsIEdQRyBD
+b21tYW5kczo6ICAgIENvbW1hbmRzIHRvIHNlbGVjdCB0aGUgdHlwZSBvZiBvcGVy
+YXRpb24uCiogT3BlblBHUCBLZXkgTWFuYWdlbWVudDo6ICAgICAgSG93IHRvIG1h
+bmFnZSB5b3VyIGtleXMuCkBlbmQgbWVudQoKCkBjICoqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioKQGMgKioqKioqKioqKiAgR0VORVJB
+TCBDT01NQU5EUyAgKioqKioqKioqKioqKgpAYyAqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqCkBub2RlIEdlbmVyYWwgR1BHIENvbW1h
+bmRzCkBzdWJzZWN0aW9uIENvbW1hbmRzIG5vdCBzcGVjaWZpYyB0byB0aGUgZnVu
+Y3Rpb24KCkB0YWJsZSBAZ251cGd0YWJvcHQKQGl0ZW0gLS12ZXJzaW9uCkBvcGlu
+ZGV4IHZlcnNpb24KUHJpbnQgdGhlIHByb2dyYW0gdmVyc2lvbiBhbmQgbGljZW5z
+aW5nIGluZm9ybWF0aW9uLiAgTm90ZSB0aGF0IHlvdQpjYW5ub3QgYWJicmV2aWF0
+ZSB0aGlzIGNvbW1hbmQuCgpAaXRlbSAtLWhlbHAKQGl0ZW14IC1oCkBvcGluZGV4
+IGhlbHAKUHJpbnQgYSB1c2FnZSBtZXNzYWdlIHN1bW1hcml6aW5nIHRoZSBtb3N0
+IHVzZWZ1bCBjb21tYW5kIGxpbmUgb3B0aW9ucy4KTm90ZSB0aGF0IHlvdSBjYW5u
+b3QgYWJicmV2aWF0ZSB0aGlzIGNvbW1hbmQuCgpAaXRlbSAtLXdhcnJhbnR5CkBv
+cGluZGV4IHdhcnJhbnR5ClByaW50IHdhcnJhbnR5IGluZm9ybWF0aW9uLgoKQGl0
+ZW0gLS1kdW1wLW9wdGlvbnMKQG9waW5kZXggZHVtcC1vcHRpb25zClByaW50IGEg
+bGlzdCBvZiBhbGwgYXZhaWxhYmxlIG9wdGlvbnMgYW5kIGNvbW1hbmRzLiAgTm90
+ZSB0aGF0IHlvdSBjYW5ub3QKYWJicmV2aWF0ZSB0aGlzIGNvbW1hbmQuCkBlbmQg
+dGFibGUKCgpAYyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqCkBjICoqKioqKioqICBPUEVSQVRJT05BTCBDT01NQU5EUyAgKioqKioq
+KioqKioKQGMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKgpAbm9kZSBPcGVyYXRpb25hbCBHUEcgQ29tbWFuZHMKQHN1YnNlY3Rpb24g
+Q29tbWFuZHMgdG8gc2VsZWN0IHRoZSB0eXBlIG9mIG9wZXJhdGlvbgoKCkB0YWJs
+ZSBAZ251cGd0YWJvcHQKCkBpdGVtIC0tc2lnbgpAaXRlbXggLXMKQG9waW5kZXgg
+c2lnbgpNYWtlIGEgc2lnbmF0dXJlLiBUaGlzIGNvbW1hbmQgbWF5IGJlIGNvbWJp
+bmVkIHdpdGggQG9wdGlvbnstLWVuY3J5cHR9Cihmb3IgYSBzaWduZWQgYW5kIGVu
+Y3J5cHRlZCBtZXNzYWdlKSwgQG9wdGlvbnstLXN5bW1ldHJpY30gKGZvciBhCnNp
+Z25lZCBhbmQgc3ltbWV0cmljYWxseSBlbmNyeXB0ZWQgbWVzc2FnZSksIG9yIEBv
+cHRpb257LS1lbmNyeXB0fSBhbmQKQG9wdGlvbnstLXN5bW1ldHJpY30gdG9nZXRo
+ZXIgKGZvciBhIHNpZ25lZCBtZXNzYWdlIHRoYXQgbWF5IGJlCmRlY3J5cHRlZCB2
+aWEgYSBzZWNyZXQga2V5IG9yIGEgcGFzc3BocmFzZSkuICBUaGUga2V5IHRvIGJl
+IHVzZWQgZm9yCnNpZ25pbmcgaXMgY2hvc2VuIGJ5IGRlZmF1bHQgb3IgY2FuIGJl
+IHNldCB3aXRoIHRoZQpAb3B0aW9uey0tbG9jYWwtdXNlcn0gYW5kIEBvcHRpb257
+LS1kZWZhdWx0LWtleX0gb3B0aW9ucy4KCkBpdGVtIC0tY2xlYXJzaWduCkBvcGlu
+ZGV4IGNsZWFyc2lnbgpNYWtlIGEgY2xlYXIgdGV4dCBzaWduYXR1cmUuICBUaGUg
+Y29udGVudCBpbiBhIGNsZWFyIHRleHQgc2lnbmF0dXJlIGlzCnJlYWRhYmxlIHdp
+dGhvdXQgYW55IHNwZWNpYWwgc29mdHdhcmUuIE9wZW5QR1Agc29mdHdhcmUgaXMg
+b25seSBuZWVkZWQKdG8gdmVyaWZ5IHRoZSBzaWduYXR1cmUuICBDbGVhciB0ZXh0
+IHNpZ25hdHVyZXMgbWF5IG1vZGlmeSBlbmQtb2YtbGluZQp3aGl0ZXNwYWNlIGZv
+ciBwbGF0Zm9ybSBpbmRlcGVuZGVuY2UgYW5kIGFyZSBub3QgaW50ZW5kZWQgdG8g
+YmUKcmV2ZXJzaWJsZS4gIFRoZSBrZXkgdG8gYmUgdXNlZCBmb3Igc2lnbmluZyBp
+cyBjaG9zZW4gYnkgZGVmYXVsdCBvcgpjYW4gYmUgc2V0IHdpdGggdGhlIEBvcHRp
+b257LS1sb2NhbC11c2VyfSBhbmQgQG9wdGlvbnstLWRlZmF1bHQta2V5fQpvcHRp
+b25zLgoKCkBpdGVtIC0tZGV0YWNoLXNpZ24KQGl0ZW14IC1iCkBvcGluZGV4IGRl
+dGFjaC1zaWduCk1ha2UgYSBkZXRhY2hlZCBzaWduYXR1cmUuCgpAaXRlbSAtLWVu
+Y3J5cHQKQGl0ZW14IC1lCkBvcGluZGV4IGVuY3J5cHQKRW5jcnlwdCBkYXRhLiBU
+aGlzIG9wdGlvbiBtYXkgYmUgY29tYmluZWQgd2l0aCBAb3B0aW9uey0tc2lnbn0g
+KGZvciBhCnNpZ25lZCBhbmQgZW5jcnlwdGVkIG1lc3NhZ2UpLCBAb3B0aW9uey0t
+c3ltbWV0cmljfSAoZm9yIGEgbWVzc2FnZSB0aGF0Cm1heSBiZSBkZWNyeXB0ZWQg
+dmlhIGEgc2VjcmV0IGtleSBvciBhIHBhc3NwaHJhc2UpLCBvciBAb3B0aW9uey0t
+c2lnbn0KYW5kIEBvcHRpb257LS1zeW1tZXRyaWN9IHRvZ2V0aGVyIChmb3IgYSBz
+aWduZWQgbWVzc2FnZSB0aGF0IG1heSBiZQpkZWNyeXB0ZWQgdmlhIGEgc2VjcmV0
+IGtleSBvciBhIHBhc3NwaHJhc2UpLgoKQGl0ZW0gLS1zeW1tZXRyaWMKQGl0ZW14
+IC1jCkBvcGluZGV4IHN5bW1ldHJpYwpFbmNyeXB0IHdpdGggYSBzeW1tZXRyaWMg
+Y2lwaGVyIHVzaW5nIGEgcGFzc3BocmFzZS4gVGhlIGRlZmF1bHQKc3ltbWV0cmlj
+IGNpcGhlciB1c2VkIGlzIEB2YWx1ZXtHUEdTWU1FTkNBTEdPfSwgYnV0IG1heSBi
+ZSBjaG9zZW4gd2l0aCB0aGUKQG9wdGlvbnstLWNpcGhlci1hbGdvfSBvcHRpb24u
+IFRoaXMgb3B0aW9uIG1heSBiZSBjb21iaW5lZCB3aXRoCkBvcHRpb257LS1zaWdu
+fSAoZm9yIGEgc2lnbmVkIGFuZCBzeW1tZXRyaWNhbGx5IGVuY3J5cHRlZCBtZXNz
+YWdlKSwKQG9wdGlvbnstLWVuY3J5cHR9IChmb3IgYSBtZXNzYWdlIHRoYXQgbWF5
+IGJlIGRlY3J5cHRlZCB2aWEgYSBzZWNyZXQga2V5Cm9yIGEgcGFzc3BocmFzZSks
+IG9yIEBvcHRpb257LS1zaWdufSBhbmQgQG9wdGlvbnstLWVuY3J5cHR9IHRvZ2V0
+aGVyCihmb3IgYSBzaWduZWQgbWVzc2FnZSB0aGF0IG1heSBiZSBkZWNyeXB0ZWQg
+dmlhIGEgc2VjcmV0IGtleSBvciBhCnBhc3NwaHJhc2UpLgoKQGl0ZW0gLS1zdG9y
+ZQpAb3BpbmRleCBzdG9yZQpTdG9yZSBvbmx5IChtYWtlIGEgc2ltcGxlIFJGQzE5
+OTEgbGl0ZXJhbCBkYXRhIHBhY2tldCkuCgpAaXRlbSAtLWRlY3J5cHQKQGl0ZW14
+IC1kCkBvcGluZGV4IGRlY3J5cHQKRGVjcnlwdCB0aGUgZmlsZSBnaXZlbiBvbiB0
+aGUgY29tbWFuZCBsaW5lIChvciBTVERJTiBpZiBubyBmaWxlCmlzIHNwZWNpZmll
+ZCkgYW5kIHdyaXRlIGl0IHRvIFNURE9VVCAob3IgdGhlIGZpbGUgc3BlY2lmaWVk
+IHdpdGgKQG9wdGlvbnstLW91dHB1dH0pLiBJZiB0aGUgZGVjcnlwdGVkIGZpbGUg
+aXMgc2lnbmVkLCB0aGUgc2lnbmF0dXJlIGlzIGFsc28KdmVyaWZpZWQuIFRoaXMg
+Y29tbWFuZCBkaWZmZXJzIGZyb20gdGhlIGRlZmF1bHQgb3BlcmF0aW9uLCBhcyBp
+dCBuZXZlcgp3cml0ZXMgdG8gdGhlIGZpbGVuYW1lIHdoaWNoIGlzIGluY2x1ZGVk
+IGluIHRoZSBmaWxlIGFuZCBpdCByZWplY3RzCmZpbGVzIHdoaWNoIGRvbid0IGJl
+Z2luIHdpdGggYW4gZW5jcnlwdGVkIG1lc3NhZ2UuCgpAaXRlbSAtLXZlcmlmeQpA
+b3BpbmRleCB2ZXJpZnkKQXNzdW1lIHRoYXQgdGhlIGZpcnN0IGFyZ3VtZW50IGlz
+IGEgc2lnbmVkIGZpbGUgYW5kIHZlcmlmeSBpdCB3aXRob3V0CmdlbmVyYXRpbmcg
+YW55IG91dHB1dC4gIFdpdGggbm8gYXJndW1lbnRzLCB0aGUgc2lnbmF0dXJlIHBh
+Y2tldCBpcwpyZWFkIGZyb20gU1RESU4uICBJZiBvbmx5IGEgb25lIGFyZ3VtZW50
+IGlzIGdpdmVuLCBpdCBpcyBleHBlY3RlZCB0bwpiZSBhIGNvbXBsZXRlIHNpZ25h
+dHVyZS4KCldpdGggbW9yZSB0aGFuIDEgYXJndW1lbnQsIHRoZSBmaXJzdCBzaG91
+bGQgYmUgYSBkZXRhY2hlZCBzaWduYXR1cmUKYW5kIHRoZSByZW1haW5pbmcgZmls
+ZXMgYWtlIHVwIHRoZSB0aGUgc2lnbmVkIGRhdGEuIFRvIHJlYWQgdGhlIHNpZ25l
+ZApkYXRhIGZyb20gU1RESU4sIHVzZSBAc2FtcHstfSBhcyB0aGUgc2Vjb25kIGZp
+bGVuYW1lLiAgRm9yIHNlY3VyaXR5CnJlYXNvbnMgYSBkZXRhY2hlZCBzaWduYXR1
+cmUgY2Fubm90IHJlYWQgdGhlIHNpZ25lZCBtYXRlcmlhbCBmcm9tClNURElOIHdp
+dGhvdXQgZGVub3RpbmcgaXQgaW4gdGhlIGFib3ZlIHdheS4KCk5vdGU6IElmIHRo
+ZSBvcHRpb24gQG9wdGlvbnstLWJhdGNofSBpcyBub3QgdXNlZCwgQGNvbW1hbmR7
+QGdwZ25hbWV9Cm1heSBhc3N1bWUgdGhhdCBhIHNpbmdsZSBhcmd1bWVudCBpcyBh
+IGZpbGUgd2l0aCBhIGRldGFjaGVkIHNpZ25hdHVyZQphbmQgaXQgd2lsbCB0cnkg
+dG8gZmluZCBhIG1hdGNoaW5nIGRhdGEgZmlsZSBieSBzdHJpcHBpbmcgY2VydGFp
+bgpzdWZmaXhlcy4gIFVzaW5nIHRoaXMgaGlzdG9yaWNhbCBmZWF0dXJlIHRvIHZl
+cmlmeSBhIGRldGFjaGVkCnNpZ25hdHVyZSBpcyBzdHJvbmdseSBkaXNjb3VyYWdl
+ZDsgYWx3YXlzIHNwZWNpZnkgdGhlIGRhdGEgZmlsZSB0b28uCgpOb3RlOiBXaGVu
+IHZlcmlmeWluZyBhIGNsZWFydGV4dCBzaWduYXR1cmUsIEBjb21tYW5ke2dwZ30g
+dmVyaWZpZXMKb25seSB3aGF0IG1ha2VzIHVwIHRoZSBjbGVhcnRleHQgc2lnbmVk
+IGRhdGEgYW5kIG5vdCBhbnkgZXh0cmEgZGF0YQpvdXRzaWRlIG9mIHRoZSBjbGVh
+cnRleHQgc2lnbmF0dXJlIG9yIGhlYWRlciBsaW5lcyBmb2xsb3dpbmcgZGlyZWN0
+bHkKdGhlIGRhc2ggbWFya2VyIGxpbmUuICBUaGUgb3B0aW9uIEBjb2Rley0tb3V0
+cHV0fSBtYXkgYmUgdXNlZCB0byB3cml0ZQpvdXQgdGhlIGFjdHVhbCBzaWduZWQg
+ZGF0YTsgYnV0IHRoZXJlIGFyZSBvdGhlciBwaXRmYWxscyB3aXRoIHRoaXMKZm9y
+bWF0IGFzIHdlbGwuICBJdCBpcyBzdWdnZXN0ZWQgdG8gYXZvaWQgY2xlYXJ0ZXh0
+IHNpZ25hdHVyZXMgaW4KZmF2b3Igb2YgZGV0YWNoZWQgc2lnbmF0dXJlcy4KCkBp
+dGVtIC0tbXVsdGlmaWxlCkBvcGluZGV4IG11bHRpZmlsZQpUaGlzIG1vZGlmaWVz
+IGNlcnRhaW4gb3RoZXIgY29tbWFuZHMgdG8gYWNjZXB0IG11bHRpcGxlIGZpbGVz
+IGZvcgpwcm9jZXNzaW5nIG9uIHRoZSBjb21tYW5kIGxpbmUgb3IgcmVhZCBmcm9t
+IFNURElOIHdpdGggZWFjaCBmaWxlbmFtZSBvbgphIHNlcGFyYXRlIGxpbmUuIFRo
+aXMgYWxsb3dzIGZvciBtYW55IGZpbGVzIHRvIGJlIHByb2Nlc3NlZCBhdApvbmNl
+LiBAb3B0aW9uey0tbXVsdGlmaWxlfSBtYXkgY3VycmVudGx5IGJlIHVzZWQgYWxv
+bmcgd2l0aApAb3B0aW9uey0tdmVyaWZ5fSwgQG9wdGlvbnstLWVuY3J5cHR9LCBh
+bmQgQG9wdGlvbnstLWRlY3J5cHR9LiBOb3RlIHRoYXQKQG9wdGlvbnstLW11bHRp
+ZmlsZSAtLXZlcmlmeX0gbWF5IG5vdCBiZSB1c2VkIHdpdGggZGV0YWNoZWQgc2ln
+bmF0dXJlcy4KCkBpdGVtIC0tdmVyaWZ5LWZpbGVzCkBvcGluZGV4IHZlcmlmeS1m
+aWxlcwpJZGVudGljYWwgdG8gQG9wdGlvbnstLW11bHRpZmlsZSAtLXZlcmlmeX0u
+CgpAaXRlbSAtLWVuY3J5cHQtZmlsZXMKQG9waW5kZXggZW5jcnlwdC1maWxlcwpJ
+ZGVudGljYWwgdG8gQG9wdGlvbnstLW11bHRpZmlsZSAtLWVuY3J5cHR9LgoKQGl0
+ZW0gLS1kZWNyeXB0LWZpbGVzCkBvcGluZGV4IGRlY3J5cHQtZmlsZXMKSWRlbnRp
+Y2FsIHRvIEBvcHRpb257LS1tdWx0aWZpbGUgLS1kZWNyeXB0fS4KCkBpdGVtIC0t
+bGlzdC1rZXlzCkBpdGVteCAtawpAaXRlbXggLS1saXN0LXB1YmxpYy1rZXlzCkBv
+cGluZGV4IGxpc3Qta2V5cwpMaXN0IGFsbCBrZXlzIGZyb20gdGhlIHB1YmxpYyBr
+ZXlyaW5ncywgb3IganVzdCB0aGUga2V5cyBnaXZlbiBvbiB0aGUKY29tbWFuZCBs
+aW5lLgoKQXZvaWQgdXNpbmcgdGhlIG91dHB1dCBvZiB0aGlzIGNvbW1hbmQgaW4g
+c2NyaXB0cyBvciBvdGhlciBwcm9ncmFtcyBhcwppdCBpcyBsaWtlbHkgdG8gY2hh
+bmdlIGFzIEdudVBHIGNoYW5nZXMuIFNlZSBAb3B0aW9uey0td2l0aC1jb2xvbnN9
+IGZvciBhCm1hY2hpbmUtcGFyc2VhYmxlIGtleSBsaXN0aW5nIGNvbW1hbmQgdGhh
+dCBpcyBhcHByb3ByaWF0ZSBmb3IgdXNlIGluCnNjcmlwdHMgYW5kIG90aGVyIHBy
+b2dyYW1zLgoKQGl0ZW0gLS1saXN0LXNlY3JldC1rZXlzCkBpdGVteCAtSwpAb3Bp
+bmRleCBsaXN0LXNlY3JldC1rZXlzCkxpc3QgYWxsIGtleXMgZnJvbSB0aGUgc2Vj
+cmV0IGtleXJpbmdzLCBvciBqdXN0IHRoZSBvbmVzIGdpdmVuIG9uIHRoZQpjb21t
+YW5kIGxpbmUuIEEgQGNvZGV7I30gYWZ0ZXIgdGhlIGxldHRlcnMgQGNvZGV7c2Vj
+fSBtZWFucyB0aGF0IHRoZQpzZWNyZXQga2V5IGlzIG5vdCB1c2FibGUgKGZvciBl
+eGFtcGxlLCBpZiBpdCB3YXMgY3JlYXRlZCB2aWEKQG9wdGlvbnstLWV4cG9ydC1z
+ZWNyZXQtc3Via2V5c30pLgoKQGl0ZW0gLS1saXN0LXNpZ3MKQG9waW5kZXggbGlz
+dC1zaWdzClNhbWUgYXMgQG9wdGlvbnstLWxpc3Qta2V5c30sIGJ1dCB0aGUgc2ln
+bmF0dXJlcyBhcmUgbGlzdGVkIHRvby4KVGhpcyBjb21tYW5kIGhhcyB0aGUgc2Ft
+ZSBlZmZlY3QgYXMKdXNpbmcgQG9wdGlvbnstLWxpc3Qta2V5c30gd2l0aCBAb3B0
+aW9uey0td2l0aC1zaWctbGlzdH0uCgpGb3IgZWFjaCBzaWduYXR1cmUgbGlzdGVk
+LCB0aGVyZSBhcmUgc2V2ZXJhbCBmbGFncyBpbiBiZXR3ZWVuIHRoZSAic2lnIgp0
+YWcgYW5kIGtleWlkLiBUaGVzZSBmbGFncyBnaXZlIGFkZGl0aW9uYWwgaW5mb3Jt
+YXRpb24gYWJvdXQgZWFjaApzaWduYXR1cmUuIEZyb20gbGVmdCB0byByaWdodCwg
+dGhleSBhcmUgdGhlIG51bWJlcnMgMS0zIGZvciBjZXJ0aWZpY2F0ZQpjaGVjayBs
+ZXZlbCAoc2VlIEBvcHRpb257LS1hc2stY2VydC1sZXZlbH0pLCAiTCIgZm9yIGEg
+bG9jYWwgb3IKbm9uLWV4cG9ydGFibGUgc2lnbmF0dXJlIChzZWUgQG9wdGlvbnst
+LWxzaWduLWtleX0pLCAiUiIgZm9yIGEKbm9uUmV2b2NhYmxlIHNpZ25hdHVyZSAo
+c2VlIHRoZSBAb3B0aW9uey0tZWRpdC1rZXl9IGNvbW1hbmQgIm5yc2lnbiIpLAoi
+UCIgZm9yIGEgc2lnbmF0dXJlIHRoYXQgY29udGFpbnMgYSBwb2xpY3kgVVJMIChz
+ZWUKQG9wdGlvbnstLWNlcnQtcG9saWN5LXVybH0pLCAiTiIgZm9yIGEgc2lnbmF0
+dXJlIHRoYXQgY29udGFpbnMgYQpub3RhdGlvbiAoc2VlIEBvcHRpb257LS1jZXJ0
+LW5vdGF0aW9ufSksICJYIiBmb3IgYW4gZVhwaXJlZCBzaWduYXR1cmUKKHNlZSBA
+b3B0aW9uey0tYXNrLWNlcnQtZXhwaXJlfSksIGFuZCB0aGUgbnVtYmVycyAxLTkg
+b3IgIlQiIGZvciAxMCBhbmQKYWJvdmUgdG8gaW5kaWNhdGUgdHJ1c3Qgc2lnbmF0
+dXJlIGxldmVscyAoc2VlIHRoZSBAb3B0aW9uey0tZWRpdC1rZXl9CmNvbW1hbmQg
+InRzaWduIikuCgpAaXRlbSAtLWNoZWNrLXNpZ3MKQG9waW5kZXggY2hlY2stc2ln
+cwpTYW1lIGFzIEBvcHRpb257LS1saXN0LXNpZ3N9LCBidXQgdGhlIHNpZ25hdHVy
+ZXMgYXJlIHZlcmlmaWVkLiAgTm90ZQp0aGF0IGZvciBwZXJmb3JtYW5jZSByZWFz
+b25zIHRoZSByZXZvY2F0aW9uIHN0YXR1cyBvZiBhIHNpZ25pbmcga2V5IGlzCm5v
+dCBzaG93bi4KVGhpcyBjb21tYW5kIGhhcyB0aGUgc2FtZSBlZmZlY3QgYXMKdXNp
+bmcgQG9wdGlvbnstLWxpc3Qta2V5c30gd2l0aCBAb3B0aW9uey0td2l0aC1zaWct
+Y2hlY2t9LgoKVGhlIHN0YXR1cyBvZiB0aGUgdmVyaWZpY2F0aW9uIGlzIGluZGlj
+YXRlZCBieSBhIGZsYWcgZGlyZWN0bHkgZm9sbG93aW5nCnRoZSAic2lnIiB0YWcg
+KGFuZCB0aHVzIGJlZm9yZSB0aGUgZmxhZ3MgZGVzY3JpYmVkIGFib3ZlIGZvcgpA
+b3B0aW9uey0tbGlzdC1zaWdzfSkuICBBICIhIiBpbmRpY2F0ZXMgdGhhdCB0aGUg
+c2lnbmF0dXJlIGhhcyBiZWVuCnN1Y2Nlc3NmdWxseSB2ZXJpZmllZCwgYSAiLSIg
+ZGVub3RlcyBhIGJhZCBzaWduYXR1cmUgYW5kIGEgIiUiIGlzIHVzZWQKaWYgYW4g
+ZXJyb3Igb2NjdXJyZWQgd2hpbGUgY2hlY2tpbmcgdGhlIHNpZ25hdHVyZSAoZS5n
+LiBhIG5vbiBzdXBwb3J0ZWQKYWxnb3JpdGhtKS4KCkBpdGVtIC0tbG9jYXRlLWtl
+eXMKQG9waW5kZXggbG9jYXRlLWtleXMKTG9jYXRlIHRoZSBrZXlzIGdpdmVuIGFz
+IGFyZ3VtZW50cy4gIFRoaXMgY29tbWFuZCBiYXNpY2FsbHkgdXNlcyB0aGUKc2Ft
+ZSBhbGdvcml0aG0gYXMgdXNlZCB3aGVuIGxvY2F0aW5nIGtleXMgZm9yIGVuY3J5
+cHRpb24gb3Igc2lnbmluZyBhbmQKbWF5IHRodXMgYmUgdXNlZCB0byBzZWUgd2hh
+dCBrZXlzIEBjb21tYW5ke0BncGduYW1lfSBtaWdodCB1c2UuICBJbgpwYXJ0aWN1
+bGFyIGV4dGVybmFsIG1ldGhvZHMgYXMgZGVmaW5lZCBieSBAb3B0aW9uey0tYXV0
+by1rZXktbG9jYXRlfSBtYXkKYmUgdXNlZCB0byBsb2NhdGUgYSBrZXkuICBPbmx5
+IHB1YmxpYyBrZXlzIGFyZSBsaXN0ZWQuCgpAaXRlbSAtLWZpbmdlcnByaW50CkBv
+cGluZGV4IGZpbmdlcnByaW50Ckxpc3QgYWxsIGtleXMgKG9yIHRoZSBzcGVjaWZp
+ZWQgb25lcykgYWxvbmcgd2l0aCB0aGVpcgpmaW5nZXJwcmludHMuIFRoaXMgaXMg
+dGhlIHNhbWUgb3V0cHV0IGFzIEBvcHRpb257LS1saXN0LWtleXN9IGJ1dCB3aXRo
+CnRoZSBhZGRpdGlvbmFsIG91dHB1dCBvZiBhIGxpbmUgd2l0aCB0aGUgZmluZ2Vy
+cHJpbnQuIE1heSBhbHNvIGJlCmNvbWJpbmVkIHdpdGggQG9wdGlvbnstLWxpc3Qt
+c2lnc30gb3IgQG9wdGlvbnstLWNoZWNrLXNpZ3N9LiAgSWYgdGhpcwpjb21tYW5k
+IGlzIGdpdmVuIHR3aWNlLCB0aGUgZmluZ2VycHJpbnRzIG9mIGFsbCBzZWNvbmRh
+cnkga2V5cyBhcmUKbGlzdGVkIHRvby4KCkBpdGVtIC0tbGlzdC1wYWNrZXRzCkBv
+cGluZGV4IGxpc3QtcGFja2V0cwpMaXN0IG9ubHkgdGhlIHNlcXVlbmNlIG9mIHBh
+Y2tldHMuIFRoaXMgaXMgbWFpbmx5IHVzZWZ1bCBmb3IKZGVidWdnaW5nLiAgV2hl
+biB1c2VkIHdpdGggb3B0aW9uIEBvcHRpb257LS12ZXJib3NlfSB0aGUgYWN0dWFs
+IE1QSQp2YWx1ZXMgYXJlIGR1bXBlZCBhbmQgbm90IG9ubHkgdGhlaXIgbGVuZ3Ro
+cy4KCgpAaXRlbSAtLWNhcmQtZWRpdApAb3BpbmRleCBjYXJkLWVkaXQKUHJlc2Vu
+dCBhIG1lbnUgdG8gd29yayB3aXRoIGEgc21hcnRjYXJkLiBUaGUgc3ViY29tbWFu
+ZCAiaGVscCIgcHJvdmlkZXMKYW4gb3ZlcnZpZXcgb24gYXZhaWxhYmxlIGNvbW1h
+bmRzLiBGb3IgYSBkZXRhaWxlZCBkZXNjcmlwdGlvbiwgcGxlYXNlCnNlZSB0aGUg
+Q2FyZCBIT1dUTyBhdApodHRwczovL2dudXBnLm9yZy9kb2N1bWVudGF0aW9uL2hv
+d3Rvcy5odG1sI0dudVBHLWNhcmRIT1dUTyAuCgpAaXRlbSAtLWNhcmQtc3RhdHVz
+CkBvcGluZGV4IGNhcmQtc3RhdHVzClNob3cgdGhlIGNvbnRlbnQgb2YgdGhlIHNt
+YXJ0IGNhcmQuCgpAaXRlbSAtLWNoYW5nZS1waW4KQG9waW5kZXggY2hhbmdlLXBp
+bgpQcmVzZW50IGEgbWVudSB0byBhbGxvdyBjaGFuZ2luZyB0aGUgUElOIG9mIGEg
+c21hcnRjYXJkLiBUaGlzCmZ1bmN0aW9uYWxpdHkgaXMgYWxzbyBhdmFpbGFibGUg
+YXMgdGhlIHN1YmNvbW1hbmQgInBhc3N3ZCIgd2l0aCB0aGUKQG9wdGlvbnstLWNh
+cmQtZWRpdH0gY29tbWFuZC4KCkBpdGVtIC0tZGVsZXRlLWtleXMgQGNvZGV7bmFt
+ZX0KQGl0ZW14IC0tZGVsZXRlLWtleXMgQGNvZGV7bmFtZX0KUmVtb3ZlIGtleSBm
+cm9tIHRoZSBwdWJsaWMga2V5cmluZy4gSW4gYmF0Y2ggbW9kZSBlaXRoZXIgQG9w
+dGlvbnstLXllc30gaXMKcmVxdWlyZWQgb3IgdGhlIGtleSBtdXN0IGJlIHNwZWNp
+ZmllZCBieSBmaW5nZXJwcmludC4gVGhpcyBpcyBhCnNhZmVndWFyZCBhZ2FpbnN0
+IGFjY2lkZW50YWwgZGVsZXRpb24gb2YgbXVsdGlwbGUga2V5cy4KCkBpdGVtIC0t
+ZGVsZXRlLXNlY3JldC1rZXlzIEBjb2Rle25hbWV9CkBvcGluZGV4IGRlbGV0ZS1z
+ZWNyZXQta2V5cwpSZW1vdmUga2V5IGZyb20gdGhlIHNlY3JldCBrZXlyaW5nLiBJ
+biBiYXRjaCBtb2RlIHRoZSBrZXkKbXVzdCBiZSBzcGVjaWZpZWQgYnkgZmluZ2Vy
+cHJpbnQuCgpAaXRlbSAtLWRlbGV0ZS1zZWNyZXQtYW5kLXB1YmxpYy1rZXkgQGNv
+ZGV7bmFtZX0KQG9waW5kZXggZGVsZXRlLXNlY3JldC1hbmQtcHVibGljLWtleQpT
+YW1lIGFzIEBvcHRpb257LS1kZWxldGUta2V5fSwgYnV0IGlmIGEgc2VjcmV0IGtl
+eSBleGlzdHMsIGl0IHdpbGwgYmUKcmVtb3ZlZCBmaXJzdC4gSW4gYmF0Y2ggbW9k
+ZSB0aGUga2V5IG11c3QgYmUgc3BlY2lmaWVkIGJ5IGZpbmdlcnByaW50LgoKQGl0
+ZW0gLS1leHBvcnQKQG9waW5kZXggZXhwb3J0CkVpdGhlciBleHBvcnQgYWxsIGtl
+eXMgZnJvbSBhbGwga2V5cmluZ3MgKGRlZmF1bHQga2V5cmluZ3MgYW5kIHRob3Nl
+CnJlZ2lzdGVyZWQgdmlhIG9wdGlvbiBAb3B0aW9uey0ta2V5cmluZ30pLCBvciBp
+ZiBhdCBsZWFzdCBvbmUgbmFtZSBpcyBnaXZlbiwKdGhvc2Ugb2YgdGhlIGdpdmVu
+IG5hbWUuIFRoZSBleHBvcnRlZCBrZXlzIGFyZSB3cml0dGVuIHRvIFNURE9VVCBv
+ciB0byB0aGUKZmlsZSBnaXZlbiB3aXRoIG9wdGlvbiBAb3B0aW9uey0tb3V0cHV0
+fS4gIFVzZSB0b2dldGhlciB3aXRoCkBvcHRpb257LS1hcm1vcn0gdG8gbWFpbCB0
+aG9zZSBrZXlzLgoKQGl0ZW0gLS1zZW5kLWtleXMgQGNvZGV7a2V5IElEc30KQG9w
+aW5kZXggc2VuZC1rZXlzClNpbWlsYXIgdG8gQG9wdGlvbnstLWV4cG9ydH0gYnV0
+IHNlbmRzIHRoZSBrZXlzIHRvIGEga2V5c2VydmVyLgpGaW5nZXJwcmludHMgbWF5
+IGJlIHVzZWQgaW5zdGVhZCBvZiBrZXkgSURzLiBPcHRpb24gQG9wdGlvbnstLWtl
+eXNlcnZlcn0KbXVzdCBiZSB1c2VkIHRvIGdpdmUgdGhlIG5hbWUgb2YgdGhpcyBr
+ZXlzZXJ2ZXIuIERvbid0IHNlbmQgeW91cgpjb21wbGV0ZSBrZXlyaW5nIHRvIGEg
+a2V5c2VydmVyIC0tLSBzZWxlY3Qgb25seSB0aG9zZSBrZXlzIHdoaWNoIGFyZSBu
+ZXcKb3IgY2hhbmdlZCBieSB5b3UuICBJZiBubyBrZXkgSURzIGFyZSBnaXZlbiwg
+QGNvbW1hbmR7Z3BnfSBkb2VzIG5vdGhpbmcuCgpAaXRlbSAtLWV4cG9ydC1zZWNy
+ZXQta2V5cwpAaXRlbXggLS1leHBvcnQtc2VjcmV0LXN1YmtleXMKQG9waW5kZXgg
+ZXhwb3J0LXNlY3JldC1rZXlzCkBvcGluZGV4IGV4cG9ydC1zZWNyZXQtc3Via2V5
+cwpTYW1lIGFzIEBvcHRpb257LS1leHBvcnR9LCBidXQgZXhwb3J0cyB0aGUgc2Vj
+cmV0IGtleXMgaW5zdGVhZC4gIFRoZQpleHBvcnRlZCBrZXlzIGFyZSB3cml0dGVu
+IHRvIFNURE9VVCBvciB0byB0aGUgZmlsZSBnaXZlbiB3aXRoIG9wdGlvbgpAb3B0
+aW9uey0tb3V0cHV0fS4gIFRoaXMgY29tbWFuZCBpcyBvZnRlbiB1c2VkIGFsb25n
+IHdpdGggdGhlIG9wdGlvbgpAb3B0aW9uey0tYXJtb3J9IHRvIGFsbG93IGVhc3kg
+cHJpbnRpbmcgb2YgdGhlIGtleSBmb3IgcGFwZXIgYmFja3VwOwpob3dldmVyIHRo
+ZSBleHRlcm5hbCB0b29sIEBjb21tYW5ke3BhcGVya2V5fSBkb2VzIGEgYmV0dGVy
+IGpvYiBmb3IKY3JlYXRpbmcgYmFja3VwcyBvbiBwYXBlci4gIE5vdGUgdGhhdCBl
+eHBvcnRpbmcgYSBzZWNyZXQga2V5IGNhbiBiZSBhCnNlY3VyaXR5IHJpc2sgaWYg
+dGhlIGV4cG9ydGVkIGtleXMgYXJlIHNlbmQgb3ZlciBhbiBpbnNlY3VyZSBjaGFu
+bmVsLgoKVGhlIHNlY29uZCBmb3JtIG9mIHRoZSBjb21tYW5kIGhhcyB0aGUgc3Bl
+Y2lhbCBwcm9wZXJ0eSB0byByZW5kZXIgdGhlCnNlY3JldCBwYXJ0IG9mIHRoZSBw
+cmltYXJ5IGtleSB1c2VsZXNzOyB0aGlzIGlzIGEgR05VIGV4dGVuc2lvbiB0bwpP
+cGVuUEdQIGFuZCBvdGhlciBpbXBsZW1lbnRhdGlvbnMgY2FuIG5vdCBiZSBleHBl
+Y3RlZCB0byBzdWNjZXNzZnVsbHkKaW1wb3J0IHN1Y2ggYSBrZXkuICBJdHMgaW50
+ZW5kZWQgdXNlIGlzIHRvIGdlbmVyYXRlZCBhIGZ1bGwga2V5IHdpdGgKYW4gYWRk
+aXRpb25hbCBzaWduaW5nIHN1YmtleSBvbiBhIGRlZGljYXRlZCBtYWNoaW5lIGFu
+ZCB0aGVuIHVzaW5nCnRoaXMgY29tbWFuZCB0byBleHBvcnQgdGhlIGtleSB3aXRo
+b3V0IHRoZSBwcmltYXJ5IGtleSB0byB0aGUgbWFpbgptYWNoaW5lLgoKR251UEcg
+bWF5IGFzayB5b3UgdG8gZW50ZXIgdGhlIHBhc3NwaHJhc2UgZm9yIHRoZSBrZXku
+ICBUaGlzIGlzCnJlcXVpcmVkIGJlY2F1c2UgdGhlIGludGVybmFsIHByb3RlY3Rp
+b24gbWV0aG9kIG9mIHRoZSBzZWNyZXQga2V5IGlzCmRpZmZlcmVudCBmcm9tIHRo
+ZSBvbmUgc3BlY2lmaWVkIGJ5IHRoZSBPcGVuUEdQIHByb3RvY29sLgoKQGl0ZW0g
+LS1leHBvcnQtc3NoLWtleQpAb3BpbmRleCBleHBvcnQtc3NoLWtleQpUaGlzIGNv
+bW1hbmQgaXMgdXNlZCB0byBleHBvcnQgYSBrZXkgaW4gdGhlIE9wZW5TU0ggcHVi
+bGljIGtleSBmb3JtYXQuCkl0IHJlcXVpcmVzIHRoZSBzcGVjaWZpY2F0aW9uIG9m
+IG9uZSBrZXkgYnkgdGhlIHVzdWFsIG1lYW5zIGFuZApleHBvcnRzIHRoZSBsYXRl
+c3QgdmFsaWQgc3Via2V5IHdoaWNoIGhhcyBhbiBhdXRoZW50aWNhdGlvbiBjYXBh
+YmlsaXR5CnRvIFNURE9VVCBvciB0byB0aGUgZmlsZSBnaXZlbiB3aXRoIG9wdGlv
+biBAb3B0aW9uey0tb3V0cHV0fS4gIFRoYXQKb3V0cHV0IGNhbiBkaXJlY3RseSBi
+ZSBhZGRlZCB0byBzc2gncyBAZmlsZXthdXRob3JpemVkX2tleX0gZmlsZS4KCkJ5
+IHNwZWNpZnlpbmcgdGhlIGtleSB0byBleHBvcnQgdXNpbmcgYSBrZXkgSUQgb3Ig
+YSBmaW5nZXJwcmludApzdWZmaXhlZCB3aXRoIGFuIGV4Y2xhbWF0aW9uIG1hcmsg
+KCEpLCBhIHNwZWNpZmljIHN1YmtleSBvciB0aGUKcHJpbWFyeSBrZXkgY2FuIGJl
+IGV4cG9ydGVkLiAgVGhpcyBkb2VzIG5vdCBldmVuIHJlcXVpcmUgdGhhdCB0aGUg
+a2V5CmhhcyB0aGUgYXV0aGVudGljYXRpb24gY2FwYWJpbGl0eSBmbGFnIHNldC4g
+IFRvIHZpZXcgdGhlIGNhcGFiaWxpdHkKZmxhZ3Mgb2YgYSBrZXkgdXNlIEBjb2Rl
+ey0tbGlzdC1vcHRpb25zIHNob3ctdXNhZ2V9IGFsb25nIHdpdGggYSBrZXkKbGlz
+dGluZyBjb21tYW5kLgoKQGl0ZW0gLS1pbXBvcnQKQGl0ZW14IC0tZmFzdC1pbXBv
+cnQKQG9waW5kZXggaW1wb3J0CkltcG9ydC9tZXJnZSBrZXlzLiBUaGlzIGFkZHMg
+dGhlIGdpdmVuIGtleXMgdG8gdGhlCmtleXJpbmcuIFRoZSBmYXN0IHZlcnNpb24g
+aXMgY3VycmVudGx5IGp1c3QgYSBzeW5vbnltLgoKVGhlcmUgYXJlIGEgZmV3IG90
+aGVyIG9wdGlvbnMgd2hpY2ggY29udHJvbCBob3cgdGhpcyBjb21tYW5kIHdvcmtz
+LgpNb3N0IG5vdGFibGUgaGVyZSBpcyB0aGUgQG9wdGlvbnstLWltcG9ydC1vcHRp
+b25zIG1lcmdlLW9ubHl9IG9wdGlvbgp3aGljaCBkb2VzIG5vdCBpbnNlcnQgbmV3
+IGtleXMgYnV0IGRvZXMgb25seSB0aGUgbWVyZ2luZyBvZiBuZXcKc2lnbmF0dXJl
+cywgdXNlci1JRHMgYW5kIHN1YmtleXMuCgpAaXRlbSAtLXJlY3Yta2V5cyBAY29k
+ZXtrZXkgSURzfQpAb3BpbmRleCByZWN2LWtleXMKSW1wb3J0IHRoZSBrZXlzIHdp
+dGggdGhlIGdpdmVuIGtleSBJRHMgZnJvbSBhIGtleXNlcnZlci4gT3B0aW9uCkBv
+cHRpb257LS1rZXlzZXJ2ZXJ9IG11c3QgYmUgdXNlZCB0byBnaXZlIHRoZSBuYW1l
+IG9mIHRoaXMga2V5c2VydmVyLgoKQGl0ZW0gLS1yZWZyZXNoLWtleXMKQG9waW5k
+ZXggcmVmcmVzaC1rZXlzClJlcXVlc3QgdXBkYXRlcyBmcm9tIGEga2V5c2VydmVy
+IGZvciBrZXlzIHRoYXQgYWxyZWFkeSBleGlzdCBvbiB0aGUKbG9jYWwga2V5cmlu
+Zy4gVGhpcyBpcyB1c2VmdWwgZm9yIHVwZGF0aW5nIGEga2V5IHdpdGggdGhlIGxh
+dGVzdApzaWduYXR1cmVzLCB1c2VyIElEcywgZXRjLiBDYWxsaW5nIHRoaXMgd2l0
+aCBubyBhcmd1bWVudHMgd2lsbCByZWZyZXNoCnRoZSBlbnRpcmUga2V5cmluZy4g
+T3B0aW9uIEBvcHRpb257LS1rZXlzZXJ2ZXJ9IG11c3QgYmUgdXNlZCB0byBnaXZl
+IHRoZQpuYW1lIG9mIHRoZSBrZXlzZXJ2ZXIgZm9yIGFsbCBrZXlzIHRoYXQgZG8g
+bm90IGhhdmUgcHJlZmVycmVkIGtleXNlcnZlcnMKc2V0IChzZWUgQG9wdGlvbnst
+LWtleXNlcnZlci1vcHRpb25zIGhvbm9yLWtleXNlcnZlci11cmx9KS4KCkBpdGVt
+IC0tc2VhcmNoLWtleXMgQGNvZGV7bmFtZXN9CkBvcGluZGV4IHNlYXJjaC1rZXlz
+ClNlYXJjaCB0aGUga2V5c2VydmVyIGZvciB0aGUgZ2l2ZW4gbmFtZXMuIE11bHRp
+cGxlIG5hbWVzIGdpdmVuIGhlcmUgd2lsbApiZSBqb2luZWQgdG9nZXRoZXIgdG8g
+Y3JlYXRlIHRoZSBzZWFyY2ggc3RyaW5nIGZvciB0aGUga2V5c2VydmVyLgpPcHRp
+b24gQG9wdGlvbnstLWtleXNlcnZlcn0gbXVzdCBiZSB1c2VkIHRvIGdpdmUgdGhl
+IG5hbWUgb2YgdGhpcwprZXlzZXJ2ZXIuICBLZXlzZXJ2ZXJzIHRoYXQgc3VwcG9y
+dCBkaWZmZXJlbnQgc2VhcmNoIG1ldGhvZHMgYWxsb3cgdXNpbmcKdGhlIHN5bnRh
+eCBzcGVjaWZpZWQgaW4gIkhvdyB0byBzcGVjaWZ5IGEgdXNlciBJRCIgYmVsb3cu
+IE5vdGUgdGhhdApkaWZmZXJlbnQga2V5c2VydmVyIHR5cGVzIHN1cHBvcnQgZGlm
+ZmVyZW50IHNlYXJjaCBtZXRob2RzLiBDdXJyZW50bHkKb25seSBMREFQIHN1cHBv
+cnRzIHRoZW0gYWxsLgoKQGl0ZW0gLS1mZXRjaC1rZXlzIEBjb2Rle1VSSXN9CkBv
+cGluZGV4IGZldGNoLWtleXMKUmV0cmlldmUga2V5cyBsb2NhdGVkIGF0IHRoZSBz
+cGVjaWZpZWQgVVJJcy4gTm90ZSB0aGF0IGRpZmZlcmVudAppbnN0YWxsYXRpb25z
+IG9mIEdudVBHIG1heSBzdXBwb3J0IGRpZmZlcmVudCBwcm90b2NvbHMgKEhUVFAs
+IEZUUCwKTERBUCwgZXRjLikKCkBpdGVtIC0tdXBkYXRlLXRydXN0ZGIKQG9waW5k
+ZXggdXBkYXRlLXRydXN0ZGIKRG8gdHJ1c3QgZGF0YWJhc2UgbWFpbnRlbmFuY2Uu
+IFRoaXMgY29tbWFuZCBpdGVyYXRlcyBvdmVyIGFsbCBrZXlzIGFuZApidWlsZHMg
+dGhlIFdlYiBvZiBUcnVzdC4gVGhpcyBpcyBhbiBpbnRlcmFjdGl2ZSBjb21tYW5k
+IGJlY2F1c2UgaXQgbWF5CmhhdmUgdG8gYXNrIGZvciB0aGUgIm93bmVydHJ1c3Qi
+IHZhbHVlcyBmb3Iga2V5cy4gVGhlIHVzZXIgaGFzIHRvIGdpdmUKYW4gZXN0aW1h
+dGlvbiBvZiBob3cgZmFyIHNoZSB0cnVzdHMgdGhlIG93bmVyIG9mIHRoZSBkaXNw
+bGF5ZWQga2V5IHRvCmNvcnJlY3RseSBjZXJ0aWZ5IChzaWduKSBvdGhlciBrZXlz
+LiBHbnVQRyBvbmx5IGFza3MgZm9yIHRoZSBvd25lcnRydXN0CnZhbHVlIGlmIGl0
+IGhhcyBub3QgeWV0IGJlZW4gYXNzaWduZWQgdG8gYSBrZXkuIFVzaW5nIHRoZQpA
+b3B0aW9uey0tZWRpdC1rZXl9IG1lbnUsIHRoZSBhc3NpZ25lZCB2YWx1ZSBjYW4g
+YmUgY2hhbmdlZCBhdCBhbnkgdGltZS4KCkBpdGVtIC0tY2hlY2stdHJ1c3RkYgpA
+b3BpbmRleCBjaGVjay10cnVzdGRiCkRvIHRydXN0IGRhdGFiYXNlIG1haW50ZW5h
+bmNlIHdpdGhvdXQgdXNlciBpbnRlcmFjdGlvbi4gRnJvbSB0aW1lIHRvCnRpbWUg
+dGhlIHRydXN0IGRhdGFiYXNlIG11c3QgYmUgdXBkYXRlZCBzbyB0aGF0IGV4cGly
+ZWQga2V5cyBvcgpzaWduYXR1cmVzIGFuZCB0aGUgcmVzdWx0aW5nIGNoYW5nZXMg
+aW4gdGhlIFdlYiBvZiBUcnVzdCBjYW4gYmUKdHJhY2tlZC4gTm9ybWFsbHksIEdu
+dVBHIHdpbGwgY2FsY3VsYXRlIHdoZW4gdGhpcyBpcyByZXF1aXJlZCBhbmQgZG8g
+aXQKYXV0b21hdGljYWxseSB1bmxlc3MgQG9wdGlvbnstLW5vLWF1dG8tY2hlY2st
+dHJ1c3RkYn0gaXMgc2V0LiBUaGlzCmNvbW1hbmQgY2FuIGJlIHVzZWQgdG8gZm9y
+Y2UgYSB0cnVzdCBkYXRhYmFzZSBjaGVjayBhdCBhbnkgdGltZS4gVGhlCnByb2Nl
+c3NpbmcgaXMgaWRlbnRpY2FsIHRvIHRoYXQgb2YgQG9wdGlvbnstLXVwZGF0ZS10
+cnVzdGRifSBidXQgaXQKc2tpcHMga2V5cyB3aXRoIGEgbm90IHlldCBkZWZpbmVk
+ICJvd25lcnRydXN0Ii4KCkZvciB1c2Ugd2l0aCBjcm9uIGpvYnMsIHRoaXMgY29t
+bWFuZCBjYW4gYmUgdXNlZCB0b2dldGhlciB3aXRoCkBvcHRpb257LS1iYXRjaH0g
+aW4gd2hpY2ggY2FzZSB0aGUgdHJ1c3QgZGF0YWJhc2UgY2hlY2sgaXMgZG9uZSBv
+bmx5IGlmCmEgY2hlY2sgaXMgbmVlZGVkLiBUbyBmb3JjZSBhIHJ1biBldmVuIGlu
+IGJhdGNoIG1vZGUgYWRkIHRoZSBvcHRpb24KQG9wdGlvbnstLXllc30uCgpAYW5j
+aG9ye29wdGlvbiAtLWV4cG9ydC1vd25lcnRydXN0fQpAaXRlbSAtLWV4cG9ydC1v
+d25lcnRydXN0CkBvcGluZGV4IGV4cG9ydC1vd25lcnRydXN0ClNlbmQgdGhlIG93
+bmVydHJ1c3QgdmFsdWVzIHRvIFNURE9VVC4gVGhpcyBpcyB1c2VmdWwgZm9yIGJh
+Y2t1cCBwdXJwb3NlcwphcyB0aGVzZSB2YWx1ZXMgYXJlIHRoZSBvbmx5IG9uZXMg
+d2hpY2ggY2FuJ3QgYmUgcmUtY3JlYXRlZCBmcm9tIGEKY29ycnVwdGVkIHRydXN0
+ZGIuICBFeGFtcGxlOgpAYyBtYW46LlJTCkBleGFtcGxlCiAgQGdwZ25hbWV7fSAt
+LWV4cG9ydC1vd25lcnRydXN0ID4gb3RydXN0LnR4dApAZW5kIGV4YW1wbGUKQGMg
+bWFuOi5SRQoKCkBpdGVtIC0taW1wb3J0LW93bmVydHJ1c3QKQG9waW5kZXggaW1w
+b3J0LW93bmVydHJ1c3QKVXBkYXRlIHRoZSB0cnVzdGRiIHdpdGggdGhlIG93bmVy
+dHJ1c3QgdmFsdWVzIHN0b3JlZCBpbiBAY29kZXtmaWxlc30gKG9yClNURElOIGlm
+IG5vdCBnaXZlbik7IGV4aXN0aW5nIHZhbHVlcyB3aWxsIGJlIG92ZXJ3cml0dGVu
+LiAgSW4gY2FzZSBvZiBhCnNldmVyZWx5IGRhbWFnZWQgdHJ1c3RkYiBhbmQgaWYg
+eW91IGhhdmUgYSByZWNlbnQgYmFja3VwIG9mIHRoZQpvd25lcnRydXN0IHZhbHVl
+cyAoZS5nLiBpbiB0aGUgZmlsZSBAZmlsZXtvdHJ1c3QudHh0fSwgeW91IG1heSBy
+ZS1jcmVhdGUKdGhlIHRydXN0ZGIgdXNpbmcgdGhlc2UgY29tbWFuZHM6CkBjIG1h
+bjouUlMKQGV4YW1wbGUKICBjZCB+Ly5nbnVwZwogIHJtIHRydXN0ZGIuZ3BnCiAg
+QGdwZ25hbWV7fSAtLWltcG9ydC1vd25lcnRydXN0IDwgb3RydXN0LnR4dApAZW5k
+IGV4YW1wbGUKQGMgbWFuOi5SRQoKCkBpdGVtIC0tcmVidWlsZC1rZXlkYi1jYWNo
+ZXMKQG9waW5kZXggcmVidWlsZC1rZXlkYi1jYWNoZXMKV2hlbiB1cGRhdGluZyBm
+cm9tIHZlcnNpb24gMS4wLjYgdG8gMS4wLjcgdGhpcyBjb21tYW5kIHNob3VsZCBi
+ZSB1c2VkCnRvIGNyZWF0ZSBzaWduYXR1cmUgY2FjaGVzIGluIHRoZSBrZXlyaW5n
+LiBJdCBtaWdodCBiZSBoYW5keSBpbiBvdGhlcgpzaXR1YXRpb25zIHRvby4KCkBp
+dGVtIC0tcHJpbnQtbWQgQGNvZGV7YWxnb30KQGl0ZW14IC0tcHJpbnQtbWRzCkBv
+cGluZGV4IHByaW50LW1kClByaW50IG1lc3NhZ2UgZGlnZXN0IG9mIGFsZ29yaXRo
+bSBBTEdPIGZvciBhbGwgZ2l2ZW4gZmlsZXMgb3IgU1RESU4uCldpdGggdGhlIHNl
+Y29uZCBmb3JtIChvciBhIGRlcHJlY2F0ZWQgIioiIGFzIGFsZ28pIGRpZ2VzdHMg
+Zm9yIGFsbAphdmFpbGFibGUgYWxnb3JpdGhtcyBhcmUgcHJpbnRlZC4KCkBpdGVt
+IC0tZ2VuLXJhbmRvbSBAY29kZXswfDF8Mn0gQGNvZGV7Y291bnR9CkBvcGluZGV4
+IGdlbi1yYW5kb20KRW1pdCBAdmFye2NvdW50fSByYW5kb20gYnl0ZXMgb2YgdGhl
+IGdpdmVuIHF1YWxpdHkgbGV2ZWwgMCwgMSBvciAyLiBJZgpAdmFye2NvdW50fSBp
+cyBub3QgZ2l2ZW4gb3IgemVybywgYW4gZW5kbGVzcyBzZXF1ZW5jZSBvZiByYW5k
+b20gYnl0ZXMKd2lsbCBiZSBlbWl0dGVkLiAgSWYgdXNlZCB3aXRoIEBvcHRpb257
+LS1hcm1vcn0gdGhlIG91dHB1dCB3aWxsIGJlCmJhc2U2NCBlbmNvZGVkLiAgUExF
+QVNFLCBkb24ndCB1c2UgdGhpcyBjb21tYW5kIHVubGVzcyB5b3Uga25vdyB3aGF0
+CnlvdSBhcmUgZG9pbmc7IGl0IG1heSByZW1vdmUgcHJlY2lvdXMgZW50cm9weSBm
+cm9tIHRoZSBzeXN0ZW0hCgpAaXRlbSAtLWdlbi1wcmltZSBAY29kZXttb2RlfSAg
+QGNvZGV7Yml0c30KQG9waW5kZXggZ2VuLXByaW1lClVzZSB0aGUgc291cmNlLCBM
+dWtlIDotKS4gVGhlIG91dHB1dCBmb3JtYXQgaXMgc3RpbGwgc3ViamVjdCB0byBj
+aGFuZ2UuCgoKQGl0ZW0gLS1lbmFybW9yCkBpdGVtIC0tZGVhcm1vcgpAb3BpbmRl
+eCBlbmFybW9yCkBvcGluZGV4IGRlYXJtb3IKUGFjayBvciB1bnBhY2sgYW4gYXJi
+aXRyYXJ5IGlucHV0IGludG8vZnJvbSBhbiBPcGVuUEdQIEFTQ0lJIGFybW9yLgpU
+aGlzIGlzIGEgR251UEcgZXh0ZW5zaW9uIHRvIE9wZW5QR1AgYW5kIGluIGdlbmVy
+YWwgbm90IHZlcnkgdXNlZnVsLgoKQGl0ZW0gLS10b2Z1LXNldC1wb2xpY3kgQGNv
+ZGV7YXV0b3xnb29kfHVua25vd258YmFkfGFza30gIEBjb2Rle2tleS4uLn0KQG9w
+aW5kZXggdG9mdS1zZXQtcG9saWN5ClNldCB0aGUgVE9GVSBwb2xpY3kgZm9yIGFs
+bCB0aGUgYmluZGluZ3MgYXNzb2NpYXRlZCB3aXRoIHRoZSBzcGVjaWZpZWQKa2V5
+cy4gIEZvciBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHRoZSBtZWFuaW5nIG9mIHRo
+ZSBwb2xpY2llcywKQHB4cmVme3RydXN0LW1vZGVsLXRvZnV9LiAgVGhlIGtleXMg
+bWF5IGJlIHNwZWNpZmllZCBlaXRoZXIgYnkgdGhlaXIKZmluZ2VycHJpbnQgKHBy
+ZWZlcnJlZCkgb3IgdGhlaXIga2V5aWQuCgpAYyBAaXRlbSAtLXNlcnZlcgpAYyBA
+b3BpbmRleCBzZXJ2ZXIKQGMgUnVuIGdwZyBpbiBzZXJ2ZXIgbW9kZS4gIFRoaXMg
+ZmVhdHVyZSBpcyBub3QgeWV0IHJlYWR5IGZvciB1c2UgYW5kCkBjIHRodXMgbm90
+IGRvY3VtZW50ZWQuCgpAZW5kIHRhYmxlCgoKQGMgKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKgpAYyAqKioqKioqICBLRVkgTUFOR0VN
+RU5UIENPTU1BTkRTICAqKioqKioqKioqCkBjICoqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioKQG5vZGUgT3BlblBHUCBLZXkgTWFuYWdl
+bWVudApAc3Vic2VjdGlvbiBIb3cgdG8gbWFuYWdlIHlvdXIga2V5cwoKVGhpcyBz
+ZWN0aW9uIGV4cGxhaW5zIHRoZSBtYWluIGNvbW1hbmRzIGZvciBrZXkgbWFuYWdl
+bWVudAoKQHRhYmxlIEBnbnVwZ3RhYm9wdAoKQGl0ZW0gLS1xdWljay1nZW4ta2V5
+IEBjb2Rle3VzZXItaWR9CkBvcGluZGV4IHF1aWNrLWdlbi1rZXkKVGhpcyBpcyBh
+IHNpbXBsZSBjb21tYW5kIHRvIGdlbmVyYXRlIGEgc3RhbmRhcmQga2V5IHdpdGgg
+b25lIHVzZXIgaWQuCkluIGNvbnRyYXN0IHRvIEBvcHRpb257LS1nZW4ta2V5fSB0
+aGUga2V5IGlzIGdlbmVyYXRlZCBkaXJlY3RseQp3aXRob3V0IHRoZSBuZWVkIHRv
+IGFuc3dlciBhIGJ1bmNoIG9mIHByb21wdHMuICBVbmxlc3MgdGhlIG9wdGlvbgpA
+b3B0aW9uey0teWVzfSBpcyBnaXZlbiwgdGhlIGtleSBjcmVhdGlvbiB3aWxsIGJl
+IGNhbmNlbGVkIGlmIHRoZQpnaXZlbiB1c2VyIGlkIGFscmVhZHkgZXhpc3RzIGlu
+IHRoZSBrZXkgcmluZy4KCklmIGludm9rZWQgZGlyZWN0bHkgb24gdGhlIGNvbnNv
+bGUgd2l0aG91dCBhbnkgc3BlY2lhbCBvcHRpb25zIGFuCmFuc3dlciB0byBhIGBg
+Q29udGludWU/Jycgc3R5bGUgY29uZmlybWF0aW9uIHByb21wdCBpcyByZXF1aXJl
+ZC4gIEluCmNhc2UgdGhlIHVzZXIgaWQgYWxyZWFkeSBleGlzdHMgaW4gdGhlIGtl
+eSByaW5nIGEgc2Vjb25kIHByb21wdCB0bwpmb3JjZSB0aGUgY3JlYXRpb24gb2Yg
+dGhlIGtleSB3aWxsIHNob3cgdXAuCgpJZiB0aGlzIGNvbW1hbmQgaXMgdXNlZCB3
+aXRoIEBvcHRpb257LS1iYXRjaH0sCkBvcHRpb257LS1waW5lbnRyeS1tb2RlfSBo
+YXMgYmVlbiBzZXQgdG8gQGNvZGV7bG9vcGJhY2t9LCBhbmQgb25lIG9mCnRoZSBw
+YXNzcGhyYXNlIG9wdGlvbnMgKEBvcHRpb257LS1wYXNzcGhyYXNlfSwKQG9wdGlv
+bnstLXBhc3NwaHJhc2UtZmR9LCBvciBAb3B0aW9ue3Bhc3NwaHJhc2UtZmlsZX0p
+IGlzIHVzZWQsIHRoZQpzdXBwbGllZCBwYXNzcGhyYXNlIGlzIHVzZWQgZm9yIHRo
+ZSBuZXcga2V5IGFuZCB0aGUgYWdlbnQgZG9lcyBub3QgYXNrCmZvciBpdC4gIFRv
+IGNyZWF0ZSBhIGtleSB3aXRob3V0IGFueSBwcm90ZWN0aW9uIEBjb2Rley0tcGFz
+c3BocmFzZSAnJ30KbWF5IGJlIHVzZWQuCgpAaXRlbSAtLWdlbi1rZXkKQG9waW5k
+ZXggZ2VuLWtleQpHZW5lcmF0ZSBhIG5ldyBrZXkgcGFpciB1c2luZyB0aGUgY3Vy
+cmVudCBkZWZhdWx0IHBhcmFtZXRlcnMuICBUaGlzIGlzCnRoZSBzdGFuZGFyZCBj
+b21tYW5kIHRvIGNyZWF0ZSBhIG5ldyBrZXkuCgpAaXRlbSAtLWZ1bGwtZ2VuLWtl
+eQpAb3BpbmRleCBnZW4ta2V5CkdlbmVyYXRlIGEgbmV3IGtleSBwYWlyIHdpdGgg
+ZGlhbG9ncyBmb3IgYWxsIG9wdGlvbnMuICBUaGlzIGlzIGFuCmV4dGVuZGVkIHZl
+cnNpb24gb2YgQG9wdGlvbnstLWdlbi1rZXl9LgoKVGhlcmUgaXMgYWxzbyBhIGZl
+YXR1cmUgd2hpY2ggYWxsb3dzIHlvdSB0byBjcmVhdGUga2V5cyBpbiBiYXRjaApt
+b2RlLiBTZWUgdGhlIHRoZSBtYW51YWwgc2VjdGlvbiBgYFVuYXR0ZW5kZWQga2V5
+IGdlbmVyYXRpb24nJyBvbiBob3cKdG8gdXNlIHRoaXMuCgpAaXRlbSAtLWdlbi1y
+ZXZva2UgQGNvZGV7bmFtZX0KQG9waW5kZXggZ2VuLXJldm9rZQpHZW5lcmF0ZSBh
+IHJldm9jYXRpb24gY2VydGlmaWNhdGUgZm9yIHRoZSBjb21wbGV0ZSBrZXkuIFRv
+IHJldm9rZQphIHN1YmtleSBvciBhIHNpZ25hdHVyZSwgdXNlIHRoZSBAb3B0aW9u
+ey0tZWRpdH0gY29tbWFuZC4KCkBpdGVtIC0tZGVzaWctcmV2b2tlIEBjb2Rle25h
+bWV9CkBvcGluZGV4IGRlc2lnLXJldm9rZQpHZW5lcmF0ZSBhIGRlc2lnbmF0ZWQg
+cmV2b2NhdGlvbiBjZXJ0aWZpY2F0ZSBmb3IgYSBrZXkuIFRoaXMgYWxsb3dzIGEK
+dXNlciAod2l0aCB0aGUgcGVybWlzc2lvbiBvZiB0aGUga2V5aG9sZGVyKSB0byBy
+ZXZva2Ugc29tZW9uZSBlbHNlJ3MKa2V5LgoKCkBpdGVtIC0tZWRpdC1rZXkKQG9w
+aW5kZXggZWRpdC1rZXkKUHJlc2VudCBhIG1lbnUgd2hpY2ggZW5hYmxlcyB5b3Ug
+dG8gZG8gbW9zdCBvZiB0aGUga2V5IG1hbmFnZW1lbnQKcmVsYXRlZCB0YXNrcy4g
+IEl0IGV4cGVjdHMgdGhlIHNwZWNpZmljYXRpb24gb2YgYSBrZXkgb24gdGhlIGNv
+bW1hbmQKbGluZS4KCkBjICoqKioqKioqIEJlZ2luIEVkaXQta2V5IE9wdGlvbnMg
+KioqKioqKioqKgpAdGFibGUgQGFzaXMKCiAgQGl0ZW0gdWlkIEBjb2Rle259CiAg
+QG9waW5kZXgga2V5ZWRpdDp1aWQKICBUb2dnbGUgc2VsZWN0aW9uIG9mIHVzZXIg
+SUQgb3IgcGhvdG9ncmFwaGljIHVzZXIgSUQgd2l0aCBpbmRleCBAY29kZXtufS4K
+ICBVc2UgQGNvZGV7Kn0gdG8gc2VsZWN0IGFsbCBhbmQgQGNvZGV7MH0gdG8gZGVz
+ZWxlY3QgYWxsLgoKICBAaXRlbSBrZXkgQGNvZGV7bn0KICBAb3BpbmRleCBrZXll
+ZGl0OmtleQogIFRvZ2dsZSBzZWxlY3Rpb24gb2Ygc3Via2V5IHdpdGggaW5kZXgg
+QGNvZGV7bn0gb3Iga2V5IElEIEBjb2Rle259LgogIFVzZSBAY29kZXsqfSB0byBz
+ZWxlY3QgYWxsIGFuZCBAY29kZXswfSB0byBkZXNlbGVjdCBhbGwuCgogIEBpdGVt
+IHNpZ24KICBAb3BpbmRleCBrZXllZGl0OnNpZ24KICBNYWtlIGEgc2lnbmF0dXJl
+IG9uIGtleSBvZiB1c2VyIEBjb2Rle25hbWV9IElmIHRoZSBrZXkgaXMgbm90IHll
+dAogIHNpZ25lZCBieSB0aGUgZGVmYXVsdCB1c2VyIChvciB0aGUgdXNlcnMgZ2l2
+ZW4gd2l0aCAtdSksIHRoZSBwcm9ncmFtCiAgZGlzcGxheXMgdGhlIGluZm9ybWF0
+aW9uIG9mIHRoZSBrZXkgYWdhaW4sIHRvZ2V0aGVyIHdpdGggaXRzCiAgZmluZ2Vy
+cHJpbnQgYW5kIGFza3Mgd2hldGhlciBpdCBzaG91bGQgYmUgc2lnbmVkLiBUaGlz
+IHF1ZXN0aW9uIGlzCiAgcmVwZWF0ZWQgZm9yIGFsbCB1c2VycyBzcGVjaWZpZWQg
+d2l0aAogIC11LgoKICBAaXRlbSBsc2lnbgogIEBvcGluZGV4IGtleWVkaXQ6bHNp
+Z24KICBTYW1lIGFzICJzaWduIiBidXQgdGhlIHNpZ25hdHVyZSBpcyBtYXJrZWQg
+YXMgbm9uLWV4cG9ydGFibGUgYW5kIHdpbGwKICB0aGVyZWZvcmUgbmV2ZXIgYmUg
+dXNlZCBieSBvdGhlcnMuIFRoaXMgbWF5IGJlIHVzZWQgdG8gbWFrZSBrZXlzCiAg
+dmFsaWQgb25seSBpbiB0aGUgbG9jYWwgZW52aXJvbm1lbnQuCgogIEBpdGVtIG5y
+c2lnbgogIEBvcGluZGV4IGtleWVkaXQ6bnJzaWduCiAgU2FtZSBhcyAic2lnbiIg
+YnV0IHRoZSBzaWduYXR1cmUgaXMgbWFya2VkIGFzIG5vbi1yZXZvY2FibGUgYW5k
+IGNhbgogIHRoZXJlZm9yZSBuZXZlciBiZSByZXZva2VkLgoKICBAaXRlbSB0c2ln
+bgogIEBvcGluZGV4IGtleWVkaXQ6dHNpZ24KICBNYWtlIGEgdHJ1c3Qgc2lnbmF0
+dXJlLiBUaGlzIGlzIGEgc2lnbmF0dXJlIHRoYXQgY29tYmluZXMgdGhlIG5vdGlv
+bnMKICBvZiBjZXJ0aWZpY2F0aW9uIChsaWtlIGEgcmVndWxhciBzaWduYXR1cmUp
+LCBhbmQgdHJ1c3QgKGxpa2UgdGhlCiAgInRydXN0IiBjb21tYW5kKS4gSXQgaXMg
+Z2VuZXJhbGx5IG9ubHkgdXNlZnVsIGluIGRpc3RpbmN0IGNvbW11bml0aWVzCiAg
+b3IgZ3JvdXBzLgpAZW5kIHRhYmxlCgpAYyBtYW46LlJTCk5vdGUgdGhhdCAibCIg
+KGZvciBsb2NhbCAvIG5vbi1leHBvcnRhYmxlKSwgIm5yIiAoZm9yIG5vbi1yZXZv
+Y2FibGUsCmFuZCAidCIgKGZvciB0cnVzdCkgbWF5IGJlIGZyZWVseSBtaXhlZCBh
+bmQgcHJlZml4ZWQgdG8gInNpZ24iIHRvCmNyZWF0ZSBhIHNpZ25hdHVyZSBvZiBh
+bnkgdHlwZSBkZXNpcmVkLgpAYyBtYW46LlJFCgpJZiB0aGUgb3B0aW9uIEBvcHRp
+b257LS1vbmx5LXNpZ24tdGV4dC1pZHN9IGlzIHNwZWNpZmllZCwgdGhlbiBhbnkK
+bm9uLXRleHQgYmFzZWQgdXNlciBpZHMgKGUuZy4sIHBob3RvIElEcykgd2lsbCBu
+b3QgYmUgc2VsZWN0ZWQgZm9yCnNpZ25pbmcuCgpAdGFibGUgQGFzaXMKCiAgQGl0
+ZW0gZGVsc2lnCiAgQG9waW5kZXgga2V5ZWRpdDpkZWxzaWcKICBEZWxldGUgYSBz
+aWduYXR1cmUuIE5vdGUgdGhhdCBpdCBpcyBub3QgcG9zc2libGUgdG8gcmV0cmFj
+dCBhIHNpZ25hdHVyZSwKICBvbmNlIGl0IGhhcyBiZWVuIHNlbmQgdG8gdGhlIHB1
+YmxpYyAoaS5lLiB0byBhIGtleXNlcnZlcikuICBJbiB0aGF0IGNhc2UKICB5b3Ug
+YmV0dGVyIHVzZSBAY29kZXtyZXZzaWd9LgoKICBAaXRlbSByZXZzaWcKICBAb3Bp
+bmRleCBrZXllZGl0OnJldnNpZwogIFJldm9rZSBhIHNpZ25hdHVyZS4gRm9yIGV2
+ZXJ5IHNpZ25hdHVyZSB3aGljaCBoYXMgYmVlbiBnZW5lcmF0ZWQgYnkKICBvbmUg
+b2YgdGhlIHNlY3JldCBrZXlzLCBHbnVQRyBhc2tzIHdoZXRoZXIgYSByZXZvY2F0
+aW9uIGNlcnRpZmljYXRlCiAgc2hvdWxkIGJlIGdlbmVyYXRlZC4KCiAgQGl0ZW0g
+Y2hlY2sKICBAb3BpbmRleCBrZXllZGl0OmNoZWNrCiAgQ2hlY2sgdGhlIHNpZ25h
+dHVyZXMgb24gYWxsIHNlbGVjdGVkIHVzZXIgSURzLiAgV2l0aCB0aGUgZXh0cmEK
+ICBvcHRpb24gQGNvZGV7c2VsZnNpZ30gb25seSBzZWxmLXNpZ25hdHVyZXMgYXJl
+IHNob3duLgoKICBAaXRlbSBhZGR1aWQKICBAb3BpbmRleCBrZXllZGl0OmFkZHVp
+ZAogIENyZWF0ZSBhbiBhZGRpdGlvbmFsIHVzZXIgSUQuCgogIEBpdGVtIGFkZHBo
+b3RvCiAgQG9waW5kZXgga2V5ZWRpdDphZGRwaG90bwogIENyZWF0ZSBhIHBob3Rv
+Z3JhcGhpYyB1c2VyIElELiBUaGlzIHdpbGwgcHJvbXB0IGZvciBhIEpQRUcgZmls
+ZSB0aGF0CiAgd2lsbCBiZSBlbWJlZGRlZCBpbnRvIHRoZSB1c2VyIElELiBOb3Rl
+IHRoYXQgYSB2ZXJ5IGxhcmdlIEpQRUcgd2lsbCBtYWtlCiAgZm9yIGEgdmVyeSBs
+YXJnZSBrZXkuIEFsc28gbm90ZSB0aGF0IHNvbWUgcHJvZ3JhbXMgd2lsbCBkaXNw
+bGF5IHlvdXIKICBKUEVHIHVuY2hhbmdlZCAoR251UEcpLCBhbmQgc29tZSBwcm9n
+cmFtcyB3aWxsIHNjYWxlIGl0IHRvIGZpdCBpbiBhCiAgZGlhbG9nIGJveCAoUEdQ
+KS4KCiAgQGl0ZW0gc2hvd3Bob3RvCiAgQG9waW5kZXgga2V5ZWRpdDpzaG93cGhv
+dG8KICBEaXNwbGF5IHRoZSBzZWxlY3RlZCBwaG90b2dyYXBoaWMgdXNlciBJRC4K
+CiAgQGl0ZW0gZGVsdWlkCiAgQG9waW5kZXgga2V5ZWRpdDpkZWx1aWQKICBEZWxl
+dGUgYSB1c2VyIElEIG9yIHBob3RvZ3JhcGhpYyB1c2VyIElELiAgTm90ZSB0aGF0
+IGl0IGlzIG5vdAogIHBvc3NpYmxlIHRvIHJldHJhY3QgYSB1c2VyIGlkLCBvbmNl
+IGl0IGhhcyBiZWVuIHNlbmQgdG8gdGhlIHB1YmxpYwogIChpLmUuIHRvIGEga2V5
+c2VydmVyKS4gIEluIHRoYXQgY2FzZSB5b3UgYmV0dGVyIHVzZSBAY29kZXtyZXZ1
+aWR9LgoKICBAaXRlbSByZXZ1aWQKICBAb3BpbmRleCBrZXllZGl0OnJldnVpZAog
+IFJldm9rZSBhIHVzZXIgSUQgb3IgcGhvdG9ncmFwaGljIHVzZXIgSUQuCgogIEBp
+dGVtIHByaW1hcnkKICBAb3BpbmRleCBrZXllZGl0OnByaW1hcnkKICBGbGFnIHRo
+ZSBjdXJyZW50IHVzZXIgaWQgYXMgdGhlIHByaW1hcnkgb25lLCByZW1vdmVzIHRo
+ZSBwcmltYXJ5IHVzZXIKICBpZCBmbGFnIGZyb20gYWxsIG90aGVyIHVzZXIgaWRz
+IGFuZCBzZXRzIHRoZSB0aW1lc3RhbXAgb2YgYWxsIGFmZmVjdGVkCiAgc2VsZi1z
+aWduYXR1cmVzIG9uZSBzZWNvbmQgYWhlYWQuIE5vdGUgdGhhdCBzZXR0aW5nIGEg
+cGhvdG8gdXNlciBJRAogIGFzIHByaW1hcnkgbWFrZXMgaXQgcHJpbWFyeSBvdmVy
+IG90aGVyIHBob3RvIHVzZXIgSURzLCBhbmQgc2V0dGluZyBhCiAgcmVndWxhciB1
+c2VyIElEIGFzIHByaW1hcnkgbWFrZXMgaXQgcHJpbWFyeSBvdmVyIG90aGVyIHJl
+Z3VsYXIgdXNlcgogIElEcy4KCiAgQGl0ZW0ga2V5c2VydmVyCiAgQG9waW5kZXgg
+a2V5ZWRpdDprZXlzZXJ2ZXIKICBTZXQgYSBwcmVmZXJyZWQga2V5c2VydmVyIGZv
+ciB0aGUgc3BlY2lmaWVkIHVzZXIgSUQocykuIFRoaXMgYWxsb3dzCiAgb3RoZXIg
+dXNlcnMgdG8ga25vdyB3aGVyZSB5b3UgcHJlZmVyIHRoZXkgZ2V0IHlvdXIga2V5
+IGZyb20uIFNlZQogIEBvcHRpb257LS1rZXlzZXJ2ZXItb3B0aW9ucyBob25vci1r
+ZXlzZXJ2ZXItdXJsfSBmb3IgbW9yZSBvbiBob3cgdGhpcwogIHdvcmtzLiAgU2V0
+dGluZyBhIHZhbHVlIG9mICJub25lIiByZW1vdmVzIGFuIGV4aXN0aW5nIHByZWZl
+cnJlZAogIGtleXNlcnZlci4KCiAgQGl0ZW0gbm90YXRpb24KICBAb3BpbmRleCBr
+ZXllZGl0Om5vdGF0aW9uCiAgU2V0IGEgbmFtZT12YWx1ZSBub3RhdGlvbiBmb3Ig
+dGhlIHNwZWNpZmllZCB1c2VyIElEKHMpLiBTZWUKICBAb3B0aW9uey0tY2VydC1u
+b3RhdGlvbn0gZm9yIG1vcmUgb24gaG93IHRoaXMgd29ya3MuIFNldHRpbmcgYSB2
+YWx1ZSBvZgogICJub25lIiByZW1vdmVzIGFsbCBub3RhdGlvbnMsIHNldHRpbmcg
+YSBub3RhdGlvbiBwcmVmaXhlZCB3aXRoIGEgbWludXMKICBzaWduICgtKSByZW1v
+dmVzIHRoYXQgbm90YXRpb24sIGFuZCBzZXR0aW5nIGEgbm90YXRpb24gbmFtZSAo
+d2l0aG91dCB0aGUKICA9dmFsdWUpIHByZWZpeGVkIHdpdGggYSBtaW51cyBzaWdu
+IHJlbW92ZXMgYWxsIG5vdGF0aW9ucyB3aXRoIHRoYXQgbmFtZS4KCiAgQGl0ZW0g
+cHJlZgogIEBvcGluZGV4IGtleWVkaXQ6cHJlZgogIExpc3QgcHJlZmVyZW5jZXMg
+ZnJvbSB0aGUgc2VsZWN0ZWQgdXNlciBJRC4gVGhpcyBzaG93cyB0aGUgYWN0dWFs
+CiAgcHJlZmVyZW5jZXMsIHdpdGhvdXQgaW5jbHVkaW5nIGFueSBpbXBsaWVkIHBy
+ZWZlcmVuY2VzLgoKICBAaXRlbSBzaG93cHJlZgogIEBvcGluZGV4IGtleWVkaXQ6
+c2hvd3ByZWYKICBNb3JlIHZlcmJvc2UgcHJlZmVyZW5jZXMgbGlzdGluZyBmb3Ig
+dGhlIHNlbGVjdGVkIHVzZXIgSUQuIFRoaXMgc2hvd3MKICB0aGUgcHJlZmVyZW5j
+ZXMgaW4gZWZmZWN0IGJ5IGluY2x1ZGluZyB0aGUgaW1wbGllZCBwcmVmZXJlbmNl
+cyBvZiAzREVTCiAgKGNpcGhlciksIFNIQS0xIChkaWdlc3QpLCBhbmQgVW5jb21w
+cmVzc2VkIChjb21wcmVzc2lvbikgaWYgdGhleSBhcmUKICBub3QgYWxyZWFkeSBp
+bmNsdWRlZCBpbiB0aGUgcHJlZmVyZW5jZSBsaXN0LiBJbiBhZGRpdGlvbiwgdGhl
+CiAgcHJlZmVycmVkIGtleXNlcnZlciBhbmQgc2lnbmF0dXJlIG5vdGF0aW9ucyAo
+aWYgYW55KSBhcmUgc2hvd24uCgogIEBpdGVtIHNldHByZWYgQGNvZGV7c3RyaW5n
+fQogIEBvcGluZGV4IGtleWVkaXQ6c2V0cHJlZgogIFNldCB0aGUgbGlzdCBvZiB1
+c2VyIElEIHByZWZlcmVuY2VzIHRvIEBjb2Rle3N0cmluZ30gZm9yIGFsbCAob3Ig
+anVzdAogIHRoZSBzZWxlY3RlZCkgdXNlciBJRHMuIENhbGxpbmcgc2V0cHJlZiB3
+aXRoIG5vIGFyZ3VtZW50cyBzZXRzIHRoZQogIHByZWZlcmVuY2UgbGlzdCB0byB0
+aGUgZGVmYXVsdCAoZWl0aGVyIGJ1aWx0LWluIG9yIHNldCB2aWEKICBAb3B0aW9u
+ey0tZGVmYXVsdC1wcmVmZXJlbmNlLWxpc3R9KSwgYW5kIGNhbGxpbmcgc2V0cHJl
+ZiB3aXRoICJub25lIgogIGFzIHRoZSBhcmd1bWVudCBzZXRzIGFuIGVtcHR5IHBy
+ZWZlcmVuY2UgbGlzdC4gVXNlIEBjb21tYW5ke0BncGduYW1lCiAgLS12ZXJzaW9u
+fSB0byBnZXQgYSBsaXN0IG9mIGF2YWlsYWJsZSBhbGdvcml0aG1zLiBOb3RlIHRo
+YXQgd2hpbGUgeW91CiAgY2FuIGNoYW5nZSB0aGUgcHJlZmVyZW5jZXMgb24gYW4g
+YXR0cmlidXRlIHVzZXIgSUQgKGFrYSAicGhvdG8gSUQiKSwKICBHbnVQRyBkb2Vz
+IG5vdCBzZWxlY3Qga2V5cyB2aWEgYXR0cmlidXRlIHVzZXIgSURzIHNvIHRoZXNl
+IHByZWZlcmVuY2VzCiAgd2lsbCBub3QgYmUgdXNlZCBieSBHbnVQRy4KCiAgV2hl
+biBzZXR0aW5nIHByZWZlcmVuY2VzLCB5b3Ugc2hvdWxkIGxpc3QgdGhlIGFsZ29y
+aXRobXMgaW4gdGhlIG9yZGVyCiAgd2hpY2ggeW91J2QgbGlrZSB0byBzZWUgdGhl
+bSB1c2VkIGJ5IHNvbWVvbmUgZWxzZSB3aGVuIGVuY3J5cHRpbmcgYQogIG1lc3Nh
+Z2UgdG8geW91ciBrZXkuICBJZiB5b3UgZG9uJ3QgaW5jbHVkZSAzREVTLCBpdCB3
+aWxsIGJlCiAgYXV0b21hdGljYWxseSBhZGRlZCBhdCB0aGUgZW5kLiAgTm90ZSB0
+aGF0IHRoZXJlIGFyZSBtYW55IGZhY3RvcnMgdGhhdAogIGdvIGludG8gY2hvb3Np
+bmcgYW4gYWxnb3JpdGhtIChmb3IgZXhhbXBsZSwgeW91ciBrZXkgbWF5IG5vdCBi
+ZSB0aGUKICBvbmx5IHJlY2lwaWVudCksIGFuZCBzbyB0aGUgcmVtb3RlIE9wZW5Q
+R1AgYXBwbGljYXRpb24gYmVpbmcgdXNlZCB0bwogIHNlbmQgdG8geW91IG1heSBv
+ciBtYXkgbm90IGZvbGxvdyB5b3VyIGV4YWN0IGNob3NlbiBvcmRlciBmb3IgYSBn
+aXZlbgogIG1lc3NhZ2UuICBJdCB3aWxsLCBob3dldmVyLCBvbmx5IGNob29zZSBh
+biBhbGdvcml0aG0gdGhhdCBpcyBwcmVzZW50CiAgb24gdGhlIHByZWZlcmVuY2Ug
+bGlzdCBvZiBldmVyeSByZWNpcGllbnQga2V5LiAgU2VlIGFsc28gdGhlCiAgSU5U
+RVJPUEVSQUJJTElUWSBXSVRIIE9USEVSIE9QRU5QR1AgUFJPR1JBTVMgc2VjdGlv
+biBiZWxvdy4KCiAgQGl0ZW0gYWRka2V5CiAgQG9waW5kZXgga2V5ZWRpdDphZGRr
+ZXkKICBBZGQgYSBzdWJrZXkgdG8gdGhpcyBrZXkuCgogIEBpdGVtIGFkZGNhcmRr
+ZXkKICBAb3BpbmRleCBrZXllZGl0OmFkZGNhcmRrZXkKICBHZW5lcmF0ZSBhIHN1
+YmtleSBvbiBhIGNhcmQgYW5kIGFkZCBpdCB0byB0aGlzIGtleS4KCiAgQGl0ZW0g
+a2V5dG9jYXJkCiAgQG9waW5kZXgga2V5ZWRpdDprZXl0b2NhcmQKICBUcmFuc2Zl
+ciB0aGUgc2VsZWN0ZWQgc2VjcmV0IHN1YmtleSAob3IgdGhlIHByaW1hcnkga2V5
+IGlmIG5vIHN1YmtleQogIGhhcyBiZWVuIHNlbGVjdGVkKSB0byBhIHNtYXJ0Y2Fy
+ZC4gVGhlIHNlY3JldCBrZXkgaW4gdGhlIGtleXJpbmcgd2lsbAogIGJlIHJlcGxh
+Y2VkIGJ5IGEgc3R1YiBpZiB0aGUga2V5IGNvdWxkIGJlIHN0b3JlZCBzdWNjZXNz
+ZnVsbHkgb24gdGhlCiAgY2FyZCBhbmQgeW91IHVzZSB0aGUgc2F2ZSBjb21tYW5k
+IGxhdGVyLiBPbmx5IGNlcnRhaW4ga2V5IHR5cGVzIG1heSBiZQogIHRyYW5zZmVy
+cmVkIHRvIHRoZSBjYXJkLiBBIHN1YiBtZW51IGFsbG93cyB5b3UgdG8gc2VsZWN0
+IG9uIHdoYXQgY2FyZAogIHRvIHN0b3JlIHRoZSBrZXkuIE5vdGUgdGhhdCBpdCBp
+cyBub3QgcG9zc2libGUgdG8gZ2V0IHRoYXQga2V5IGJhY2sKICBmcm9tIHRoZSBj
+YXJkIC0gaWYgdGhlIGNhcmQgZ2V0cyBicm9rZW4geW91ciBzZWNyZXQga2V5IHdp
+bGwgYmUgbG9zdAogIHVubGVzcyB5b3UgaGF2ZSBhIGJhY2t1cCBzb21ld2hlcmUu
+CgogIEBpdGVtIGJrdXB0b2NhcmQgQGNvZGV7ZmlsZX0KICBAb3BpbmRleCBrZXll
+ZGl0OmJrdXB0b2NhcmQKICBSZXN0b3JlIHRoZSBnaXZlbiBmaWxlIHRvIGEgY2Fy
+ZC4gVGhpcyBjb21tYW5kIG1heSBiZSB1c2VkIHRvIHJlc3RvcmUgYQogIGJhY2t1
+cCBrZXkgKGFzIGdlbmVyYXRlZCBkdXJpbmcgY2FyZCBpbml0aWFsaXphdGlvbikg
+dG8gYSBuZXcgY2FyZC4gSW4KICBhbG1vc3QgYWxsIGNhc2VzIHRoaXMgd2lsbCBi
+ZSB0aGUgZW5jcnlwdGlvbiBrZXkuIFlvdSBzaG91bGQgdXNlIHRoaXMKICBjb21t
+YW5kIG9ubHkgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBwdWJsaWMga2V5IGFuZCBt
+YWtlIHN1cmUgdGhhdCB0aGUKICBmaWxlIGdpdmVuIGFzIGFyZ3VtZW50IGlzIGlu
+ZGVlZCB0aGUgYmFja3VwIHRvIHJlc3RvcmUuIFlvdSBzaG91bGQgdGhlbgogIHNl
+bGVjdCAyIHRvIHJlc3RvcmUgYXMgZW5jcnlwdGlvbiBrZXkuICBZb3Ugd2lsbCBm
+aXJzdCBiZSBhc2tlZCB0byBlbnRlcgogIHRoZSBwYXNzcGhyYXNlIG9mIHRoZSBi
+YWNrdXAga2V5IGFuZCB0aGVuIGZvciB0aGUgQWRtaW4gUElOIG9mIHRoZSBjYXJk
+LgoKICBAaXRlbSBkZWxrZXkKICBAb3BpbmRleCBrZXllZGl0OmRlbGtleQogIFJl
+bW92ZSBhIHN1YmtleSAoc2Vjb25kYXJ5IGtleSkuIE5vdGUgdGhhdCBpdCBpcyBu
+b3QgcG9zc2libGUgdG8gcmV0cmFjdAogIGEgc3Via2V5LCBvbmNlIGl0IGhhcyBi
+ZWVuIHNlbmQgdG8gdGhlIHB1YmxpYyAoaS5lLiB0byBhIGtleXNlcnZlcikuICBJ
+bgogIHRoYXQgY2FzZSB5b3UgYmV0dGVyIHVzZSBAY29kZXtyZXZrZXl9LgoKICBA
+aXRlbSByZXZrZXkKICBAb3BpbmRleCBrZXllZGl0OnJldmtleQogIFJldm9rZSBh
+IHN1YmtleS4KCiAgQGl0ZW0gZXhwaXJlCiAgQG9waW5kZXgga2V5ZWRpdDpleHBp
+cmUKICBDaGFuZ2UgdGhlIGtleSBvciBzdWJrZXkgZXhwaXJhdGlvbiB0aW1lLiBJ
+ZiBhIHN1YmtleSBpcyBzZWxlY3RlZCwgdGhlCiAgZXhwaXJhdGlvbiB0aW1lIG9m
+IHRoaXMgc3Via2V5IHdpbGwgYmUgY2hhbmdlZC4gV2l0aCBubyBzZWxlY3Rpb24s
+IHRoZQogIGtleSBleHBpcmF0aW9uIG9mIHRoZSBwcmltYXJ5IGtleSBpcyBjaGFu
+Z2VkLgoKICBAaXRlbSB0cnVzdAogIEBvcGluZGV4IGtleWVkaXQ6dHJ1c3QKICBD
+aGFuZ2UgdGhlIG93bmVyIHRydXN0IHZhbHVlIGZvciB0aGUga2V5LiBUaGlzIHVw
+ZGF0ZXMgdGhlIHRydXN0LWRiCiAgaW1tZWRpYXRlbHkgYW5kIG5vIHNhdmUgaXMg
+cmVxdWlyZWQuCgogIEBpdGVtIGRpc2FibGUKICBAaXRlbXggZW5hYmxlCiAgQG9w
+aW5kZXgga2V5ZWRpdDpkaXNhYmxlCiAgQG9waW5kZXgga2V5ZWRpdDplbmFibGUK
+ICBEaXNhYmxlIG9yIGVuYWJsZSBhbiBlbnRpcmUga2V5LiBBIGRpc2FibGVkIGtl
+eSBjYW4gbm90IG5vcm1hbGx5IGJlCiAgdXNlZCBmb3IgZW5jcnlwdGlvbi4KCiAg
+QGl0ZW0gYWRkcmV2b2tlcgogIEBvcGluZGV4IGtleWVkaXQ6YWRkcmV2b2tlcgog
+IEFkZCBhIGRlc2lnbmF0ZWQgcmV2b2tlciB0byB0aGUga2V5LiBUaGlzIHRha2Vz
+IG9uZSBvcHRpb25hbCBhcmd1bWVudDoKICAic2Vuc2l0aXZlIi4gSWYgYSBkZXNp
+Z25hdGVkIHJldm9rZXIgaXMgbWFya2VkIGFzIHNlbnNpdGl2ZSwgaXQgd2lsbAog
+IG5vdCBiZSBleHBvcnRlZCBieSBkZWZhdWx0IChzZWUgZXhwb3J0LW9wdGlvbnMp
+LgoKICBAaXRlbSBwYXNzd2QKICBAb3BpbmRleCBrZXllZGl0OnBhc3N3ZAogIENo
+YW5nZSB0aGUgcGFzc3BocmFzZSBvZiB0aGUgc2VjcmV0IGtleS4KCiAgQGl0ZW0g
+dG9nZ2xlCiAgQG9waW5kZXgga2V5ZWRpdDp0b2dnbGUKICBUaGlzIGlzIGR1bW15
+IGNvbW1hbmQgd2hpY2ggZXhpc3RzIG9ubHkgZm9yIGJhY2t3YXJkIGNvbXBhdGli
+aWxpdHkuCgogIEBpdGVtIGNsZWFuCiAgQG9waW5kZXgga2V5ZWRpdDpjbGVhbgog
+IENvbXBhY3QgKGJ5IHJlbW92aW5nIGFsbCBzaWduYXR1cmVzIGV4Y2VwdCB0aGUg
+c2VsZnNpZykgYW55IHVzZXIgSUQKICB0aGF0IGlzIG5vIGxvbmdlciB1c2FibGUg
+KGUuZy4gcmV2b2tlZCwgb3IgZXhwaXJlZCkuIFRoZW4sIHJlbW92ZSBhbnkKICBz
+aWduYXR1cmVzIHRoYXQgYXJlIG5vdCB1c2FibGUgYnkgdGhlIHRydXN0IGNhbGN1
+bGF0aW9ucy4KICBTcGVjaWZpY2FsbHksIHRoaXMgcmVtb3ZlcyBhbnkgc2lnbmF0
+dXJlIHRoYXQgZG9lcyBub3QgdmFsaWRhdGUsIGFueQogIHNpZ25hdHVyZSB0aGF0
+IGlzIHN1cGVyc2VkZWQgYnkgYSBsYXRlciBzaWduYXR1cmUsIHJldm9rZWQgc2ln
+bmF0dXJlcywKICBhbmQgc2lnbmF0dXJlcyBpc3N1ZWQgYnkga2V5cyB0aGF0IGFy
+ZSBub3QgcHJlc2VudCBvbiB0aGUga2V5cmluZy4KCiAgQGl0ZW0gbWluaW1pemUK
+ICBAb3BpbmRleCBrZXllZGl0Om1pbmltaXplCiAgTWFrZSB0aGUga2V5IGFzIHNt
+YWxsIGFzIHBvc3NpYmxlLiBUaGlzIHJlbW92ZXMgYWxsIHNpZ25hdHVyZXMgZnJv
+bQogIGVhY2ggdXNlciBJRCBleGNlcHQgZm9yIHRoZSBtb3N0IHJlY2VudCBzZWxm
+LXNpZ25hdHVyZS4KCiAgQGl0ZW0gY3Jvc3MtY2VydGlmeQogIEBvcGluZGV4IGtl
+eWVkaXQ6Y3Jvc3MtY2VydGlmeQogIEFkZCBjcm9zcy1jZXJ0aWZpY2F0aW9uIHNp
+Z25hdHVyZXMgdG8gc2lnbmluZyBzdWJrZXlzIHRoYXQgbWF5IG5vdAogIGN1cnJl
+bnRseSBoYXZlIHRoZW0uIENyb3NzLWNlcnRpZmljYXRpb24gc2lnbmF0dXJlcyBw
+cm90ZWN0IGFnYWluc3QgYQogIHN1YnRsZSBhdHRhY2sgYWdhaW5zdCBzaWduaW5n
+IHN1YmtleXMuIFNlZQogIEBvcHRpb257LS1yZXF1aXJlLWNyb3NzLWNlcnRpZmlj
+YXRpb259LiAgQWxsIG5ldyBrZXlzIGdlbmVyYXRlZCBoYXZlCiAgdGhpcyBzaWdu
+YXR1cmUgYnkgZGVmYXVsdCwgc28gdGhpcyBvcHRpb24gaXMgb25seSB1c2VmdWwg
+dG8gYnJpbmcKICBvbGRlciBrZXlzIHVwIHRvIGRhdGUuCgogIEBpdGVtIHNhdmUK
+ICBAb3BpbmRleCBrZXllZGl0OnNhdmUKICBTYXZlIGFsbCBjaGFuZ2VzIHRvIHRo
+ZSBrZXkgcmluZ3MgYW5kIHF1aXQuCgogIEBpdGVtIHF1aXQKICBAb3BpbmRleCBr
+ZXllZGl0OnF1aXQKICBRdWl0IHRoZSBwcm9ncmFtIHdpdGhvdXQgdXBkYXRpbmcg
+dGhlCiAga2V5IHJpbmdzLgpAZW5kIHRhYmxlCgpAYyBtYW46LlJTClRoZSBsaXN0
+aW5nIHNob3dzIHlvdSB0aGUga2V5IHdpdGggaXRzIHNlY29uZGFyeSBrZXlzIGFu
+ZCBhbGwgdXNlcgppZHMuICBUaGUgcHJpbWFyeSB1c2VyIGlkIGlzIGluZGljYXRl
+ZCBieSBhIGRvdCwgYW5kIHNlbGVjdGVkIGtleXMgb3IKdXNlciBpZHMgYXJlIGlu
+ZGljYXRlZCBieSBhbiBhc3Rlcmlzay4gIFRoZSB0cnVzdAp2YWx1ZSBpcyBkaXNw
+bGF5ZWQgd2l0aCB0aGUgcHJpbWFyeSBrZXk6IHRoZSBmaXJzdCBpcyB0aGUgYXNz
+aWduZWQgb3duZXIKdHJ1c3QgYW5kIHRoZSBzZWNvbmQgaXMgdGhlIGNhbGN1bGF0
+ZWQgdHJ1c3QgdmFsdWUuIExldHRlcnMgYXJlIHVzZWQgZm9yCnRoZSB2YWx1ZXM6
+CkBjIG1hbjouUkUKCkB0YWJsZSBAYXNpcwoKICBAaXRlbSAtCiAgTm8gb3duZXJ0
+cnVzdCBhc3NpZ25lZCAvIG5vdCB5ZXQgY2FsY3VsYXRlZC4KCiAgQGl0ZW0gZQog
+IFRydXN0CiAgY2FsY3VsYXRpb24gaGFzIGZhaWxlZDsgcHJvYmFibHkgZHVlIHRv
+IGFuIGV4cGlyZWQga2V5LgoKICBAaXRlbSBxCiAgTm90IGVub3VnaCBpbmZvcm1h
+dGlvbiBmb3IgY2FsY3VsYXRpb24uCgogIEBpdGVtIG4KICBOZXZlciB0cnVzdCB0
+aGlzIGtleS4KCiAgQGl0ZW0gbQogIE1hcmdpbmFsbHkgdHJ1c3RlZC4KCiAgQGl0
+ZW0gZgogIEZ1bGx5IHRydXN0ZWQuCgogIEBpdGVtIHUKICBVbHRpbWF0ZWx5IHRy
+dXN0ZWQuCgpAZW5kIHRhYmxlCkBjICoqKioqKioqIEVuZCBFZGl0LWtleSBPcHRp
+b25zICoqKioqKioqKioKCkBpdGVtIC0tc2lnbi1rZXkgQGNvZGV7bmFtZX0KQG9w
+aW5kZXggc2lnbi1rZXkKU2lnbnMgYSBwdWJsaWMga2V5IHdpdGggeW91ciBzZWNy
+ZXQga2V5LiBUaGlzIGlzIGEgc2hvcnRjdXQgdmVyc2lvbiBvZgp0aGUgc3ViY29t
+bWFuZCAic2lnbiIgZnJvbSBAb3B0aW9uey0tZWRpdH0uCgpAaXRlbSAtLWxzaWdu
+LWtleSBAY29kZXtuYW1lfQpAb3BpbmRleCBsc2lnbi1rZXkKU2lnbnMgYSBwdWJs
+aWMga2V5IHdpdGggeW91ciBzZWNyZXQga2V5IGJ1dCBtYXJrcyBpdCBhcwpub24t
+ZXhwb3J0YWJsZS4gVGhpcyBpcyBhIHNob3J0Y3V0IHZlcnNpb24gb2YgdGhlIHN1
+YmNvbW1hbmQgImxzaWduIgpmcm9tIEBvcHRpb257LS1lZGl0LWtleX0uCgpAaXRl
+bSAtLXF1aWNrLXNpZ24ta2V5IEBjb2Rle2Zwcn0gW0Bjb2Rle25hbWVzfV0KQGl0
+ZW14IC0tcXVpY2stbHNpZ24ta2V5IEBjb2Rle2Zwcn0gW0Bjb2Rle25hbWVzfV0K
+QG9waW5kZXggcXVpY2stc2lnbi1rZXkKQG9waW5kZXggcXVpY2stbHNpZ24ta2V5
+CkRpcmVjdGx5IHNpZ24gYSBrZXkgZnJvbSB0aGUgcGFzc3BocmFzZSB3aXRob3V0
+IGFueSBmdXJ0aGVyIHVzZXIKaW50ZXJhY3Rpb24uICBUaGUgQGNvZGV7ZnByfSBt
+dXN0IGJlIHRoZSB2ZXJpZmllZCBwcmltYXJ5IGZpbmdlcnByaW50Cm9mIGEga2V5
+IGluIHRoZSBsb2NhbCBrZXlyaW5nLiBJZiBubyBAY29kZXtuYW1lc30gYXJlIGdp
+dmVuLCBhbGwKdXNlZnVsIHVzZXIgaWRzIGFyZSBzaWduZWQ7IHdpdGggZ2l2ZW4g
+W0Bjb2Rle25hbWVzfV0gb25seSB1c2VmdWwgdXNlcgppZHMgbWF0Y2hpbmcgb25l
+IG9mIHRoZXNlcyBuYW1lcyBhcmUgc2lnbmVkLiAgVGhlIGNvbW1hbmQKQG9wdGlv
+bnstLXF1aWNrLWxzaWduLWtleX0gbWFya3MgdGhlIHNpZ25hdHVyZXMgYXMgbm9u
+LWV4cG9ydGFibGUuICBJZgpzdWNoIGEgbm9uLWV4cG9ydGFibGUgc2lnbmF0dXJl
+IGFscmVhZHkgZXhpc3RzIHRoZQpAb3B0aW9uey0tcXVpY2stc2lnbi1rZXl9IHR1
+cm5zIGl0IGludG8gYSBleHBvcnRhYmxlIHNpZ25hdHVyZS4KClRoaXMgY29tbWFu
+ZCB1c2VzIHJlYXNvbmFibGUgZGVmYXVsdHMgYW5kIHRodXMgZG9lcyBub3QgcHJv
+dmlkZSB0aGUKZnVsbCBmbGV4aWJpbGl0eSBvZiB0aGUgInNpZ24iIHN1YmNvbW1h
+bmQgZnJvbSBAb3B0aW9uey0tZWRpdC1rZXl9LgpJdHMgaW50ZW5kZWQgdXNlIGlz
+IHRvIGhlbHAgdW5hdHRlbmRlZCBrZXkgc2lnbmluZyBieSB1dGlsaXppbmcgYSBs
+aXN0Cm9mIHZlcmlmaWVkIGZpbmdlcnByaW50cy4KCkBpdGVtIC0tcXVpY2stYWRk
+dWlkICBAdmFye3VzZXItaWR9IEB2YXJ7bmV3LXVzZXItaWR9CkBvcGluZGV4IHF1
+aWNrLWFkZHVpZApUaGlzIGNvbW1hbmQgYWRkcyBhIG5ldyB1c2VyIGlkIHRvIGFu
+IGV4aXN0aW5nIGtleS4gIEluIGNvbnRyYXN0IHRvCnRoZSBpbnRlcmFjdGl2ZSBz
+dWItY29tbWFuZCBAY29kZXthZGR1aWR9IG9mIEBvcHRpb257LS1lZGl0LWtleX0g
+dGhlCkB2YXJ7bmV3LXVzZXItaWR9IGlzIGFkZGVkIHZlcmJhdGltIHdpdGggb25s
+eSBsZWFkaW5nIGFuZCB0cmFpbGluZwp3aGl0ZSBzcGFjZSByZW1vdmVkLCBpdCBp
+cyBleHBlY3RlZCB0byBiZSBVVEYtOCBlbmNvZGVkLCBhbmQgbm8gY2hlY2tzCm9u
+IGl0cyBmb3JtIGFyZSBhcHBsaWVkLgoKQGl0ZW0gLS1wYXNzd2QgQHZhcnt1c2Vy
+X2lkfQpAb3BpbmRleCBwYXNzd2QKQ2hhbmdlIHRoZSBwYXNzcGhyYXNlIG9mIHRo
+ZSBzZWNyZXQga2V5IGJlbG9uZ2luZyB0byB0aGUgY2VydGlmaWNhdGUKc3BlY2lm
+aWVkIGFzIEB2YXJ7dXNlcl9pZH0uICBUaGlzIGlzIGEgc2hvcnRjdXQgZm9yIHRo
+ZSBzdWItY29tbWFuZApAY29kZXtwYXNzd2R9IG9mIHRoZSBlZGl0IGtleSBtZW51
+LgoKQGVuZCB0YWJsZQoKCkBjICoqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioKQGMgKioqKioqKioqKioqKioqICAgICAgICAgICAgKioq
+KioqKioqKioqKioqKgpAYyAqKioqKioqKioqKioqKiogIE9QVElPTlMgICAqKioq
+KioqKioqKioqKioqCkBjICoqKioqKioqKioqKioqKiAgICAgICAgICAgICoqKioq
+KioqKioqKioqKioKQGMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKgpAbWFuc2VjdCBvcHRpb25zCkBub2RlIEdQRyBPcHRpb25zCkBz
+ZWN0aW9uIE9wdGlvbiBTdW1tYXJ5CgpAY29tbWFuZHtAZ3BnbmFtZX0gZmVhdHVy
+ZXMgYSBidW5jaCBvZiBvcHRpb25zIHRvIGNvbnRyb2wgdGhlIGV4YWN0CmJlaGF2
+aW91ciBhbmQgdG8gY2hhbmdlIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24uCgpA
+bWVudQoqIEdQRyBDb25maWd1cmF0aW9uIE9wdGlvbnM6OiAgIEhvdyB0byBjaGFu
+Z2UgdGhlIGNvbmZpZ3VyYXRpb24uCiogR1BHIEtleSByZWxhdGVkIE9wdGlvbnM6
+OiAgICAgS2V5IHJlbGF0ZWQgb3B0aW9ucy4KKiBHUEcgSW5wdXQgYW5kIE91dHB1
+dDo6ICAgICAgICBJbnB1dCBhbmQgT3V0cHV0LgoqIE9wZW5QR1AgT3B0aW9uczo6
+ICAgICAgICAgICAgIE9wZW5QR1AgcHJvdG9jb2wgc3BlY2lmaWMgb3B0aW9ucy4K
+KiBDb21wbGlhbmNlIE9wdGlvbnM6OiAgICAgICAgICBDb21wbGlhbmNlIG9wdGlv
+bnMuCiogR1BHIEVzb3RlcmljIE9wdGlvbnM6OiAgICAgICAgRG9pbmcgdGhpbmdz
+IG9uZSB1c3VhbGx5IGRvbid0IHdhbnQgdG8gZG8uCiogRGVwcmVjYXRlZCBPcHRp
+b25zOjogICAgICAgICAgRGVwcmVjYXRlZCBvcHRpb25zLgpAZW5kIG1lbnUKCkxv
+bmcgb3B0aW9ucyBjYW4gYmUgcHV0IGluIGFuIG9wdGlvbnMgZmlsZSAoZGVmYXVs
+dAoifi8uZ251cGcvZ3BnLmNvbmYiKS4gU2hvcnQgb3B0aW9uIG5hbWVzIHdpbGwg
+bm90IHdvcmsgLSBmb3IgZXhhbXBsZSwKImFybW9yIiBpcyBhIHZhbGlkIG9wdGlv
+biBmb3IgdGhlIG9wdGlvbnMgZmlsZSwgd2hpbGUgImEiIGlzIG5vdC4gRG8gbm90
+CndyaXRlIHRoZSAyIGRhc2hlcywgYnV0IHNpbXBseSB0aGUgbmFtZSBvZiB0aGUg
+b3B0aW9uIGFuZCBhbnkgcmVxdWlyZWQKYXJndW1lbnRzLiBMaW5lcyB3aXRoIGEg
+aGFzaCAoJyMnKSBhcyB0aGUgZmlyc3Qgbm9uLXdoaXRlLXNwYWNlCmNoYXJhY3Rl
+ciBhcmUgaWdub3JlZC4gQ29tbWFuZHMgbWF5IGJlIHB1dCBpbiB0aGlzIGZpbGUg
+dG9vLCBidXQgdGhhdCBpcwpub3QgZ2VuZXJhbGx5IHVzZWZ1bCBhcyB0aGUgY29t
+bWFuZCB3aWxsIGV4ZWN1dGUgYXV0b21hdGljYWxseSB3aXRoCmV2ZXJ5IGV4ZWN1
+dGlvbiBvZiBncGcuCgpQbGVhc2UgcmVtZW1iZXIgdGhhdCBvcHRpb24gcGFyc2lu
+ZyBzdG9wcyBhcyBzb29uIGFzIGEgbm9uLW9wdGlvbiBpcwplbmNvdW50ZXJlZCwg
+eW91IGNhbiBleHBsaWNpdGx5IHN0b3AgcGFyc2luZyBieSB1c2luZyB0aGUgc3Bl
+Y2lhbCBvcHRpb24KQG9wdGlvbnstLX0uCgpAYyAqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqCkBjICoqKioqKioqICBDT05GSUdVUkFU
+SU9OIE9QVElPTlMgICoqKioqKioqKioKQGMgKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKgpAbm9kZSBHUEcgQ29uZmlndXJhdGlvbiBP
+cHRpb25zCkBzdWJzZWN0aW9uIEhvdyB0byBjaGFuZ2UgdGhlIGNvbmZpZ3VyYXRp
+b24KClRoZXNlIG9wdGlvbnMgYXJlIHVzZWQgdG8gY2hhbmdlIHRoZSBjb25maWd1
+cmF0aW9uIGFuZCBhcmUgdXN1YWxseSBmb3VuZAppbiB0aGUgb3B0aW9uIGZpbGUu
+CgpAdGFibGUgQGdudXBndGFib3B0CgpAaXRlbSAtLWRlZmF1bHQta2V5IEB2YXJ7
+bmFtZX0KQG9waW5kZXggZGVmYXVsdC1rZXkKVXNlIEB2YXJ7bmFtZX0gYXMgdGhl
+IGRlZmF1bHQga2V5IHRvIHNpZ24gd2l0aC4gSWYgdGhpcyBvcHRpb24gaXMgbm90
+CnVzZWQsIHRoZSBkZWZhdWx0IGtleSBpcyB0aGUgZmlyc3Qga2V5IGZvdW5kIGlu
+IHRoZSBzZWNyZXQga2V5cmluZy4KTm90ZSB0aGF0IEBvcHRpb257LXV9IG9yIEBv
+cHRpb257LS1sb2NhbC11c2VyfSBvdmVycmlkZXMgdGhpcyBvcHRpb24uClRoaXMg
+b3B0aW9uIG1heSBiZSBnaXZlbiBtdWx0aXBsZSB0aW1lcy4gIEluIHRoaXMgY2Fz
+ZSwgdGhlIGxhc3Qga2V5CmZvciB3aGljaCBhIHNlY3JldCBrZXkgaXMgYXZhaWxh
+YmxlIGlzIHVzZWQuICBJZiB0aGVyZSBpcyBubyBzZWNyZXQKa2V5IGF2YWlsYWJs
+ZSBmb3IgYW55IG9mIHRoZSBzcGVjaWZpZWQgdmFsdWVzLCBHbnVQRyB3aWxsIG5v
+dCBlbWl0IGFuCmVycm9yIG1lc3NhZ2UgYnV0IGNvbnRpbnVlIGFzIGlmIHRoaXMg
+b3B0aW9uIHdhc24ndCBnaXZlbi4KCkBpdGVtIC0tZGVmYXVsdC1yZWNpcGllbnQg
+QHZhcntuYW1lfQpAb3BpbmRleCBkZWZhdWx0LXJlY2lwaWVudApVc2UgQHZhcntu
+YW1lfSBhcyBkZWZhdWx0IHJlY2lwaWVudCBpZiBvcHRpb24gQG9wdGlvbnstLXJl
+Y2lwaWVudH0gaXMKbm90IHVzZWQgYW5kIGRvbid0IGFzayBpZiB0aGlzIGlzIGEg
+dmFsaWQgb25lLiBAdmFye25hbWV9IG11c3QgYmUKbm9uLWVtcHR5LgoKQGl0ZW0g
+LS1kZWZhdWx0LXJlY2lwaWVudC1zZWxmCkBvcGluZGV4IGRlZmF1bHQtcmVjaXBp
+ZW50LXNlbGYKVXNlIHRoZSBkZWZhdWx0IGtleSBhcyBkZWZhdWx0IHJlY2lwaWVu
+dCBpZiBvcHRpb24gQG9wdGlvbnstLXJlY2lwaWVudH0gaXMgbm90CnVzZWQgYW5k
+IGRvbid0IGFzayBpZiB0aGlzIGlzIGEgdmFsaWQgb25lLiBUaGUgZGVmYXVsdCBr
+ZXkgaXMgdGhlIGZpcnN0Cm9uZSBmcm9tIHRoZSBzZWNyZXQga2V5cmluZyBvciB0
+aGUgb25lIHNldCB3aXRoIEBvcHRpb257LS1kZWZhdWx0LWtleX0uCgpAaXRlbSAt
+LW5vLWRlZmF1bHQtcmVjaXBpZW50CkBvcGluZGV4IG5vLWRlZmF1bHQtcmVjaXBp
+ZW50ClJlc2V0IEBvcHRpb257LS1kZWZhdWx0LXJlY2lwaWVudH0gYW5kIEBvcHRp
+b257LS1kZWZhdWx0LXJlY2lwaWVudC1zZWxmfS4KCkBpdGVtIC12LCAtLXZlcmJv
+c2UKQG9waW5kZXggdmVyYm9zZQpHaXZlIG1vcmUgaW5mb3JtYXRpb24gZHVyaW5n
+IHByb2Nlc3NpbmcuIElmIHVzZWQKdHdpY2UsIHRoZSBpbnB1dCBkYXRhIGlzIGxp
+c3RlZCBpbiBkZXRhaWwuCgpAaXRlbSAtLW5vLXZlcmJvc2UKQG9waW5kZXggbm8t
+dmVyYm9zZQpSZXNldCB2ZXJib3NlIGxldmVsIHRvIDAuCgpAaXRlbSAtcSwgLS1x
+dWlldApAb3BpbmRleCBxdWlldApUcnkgdG8gYmUgYXMgcXVpZXQgYXMgcG9zc2li
+bGUuCgpAaXRlbSAtLWJhdGNoCkBpdGVteCAtLW5vLWJhdGNoCkBvcGluZGV4IGJh
+dGNoCkBvcGluZGV4IG5vLWJhdGNoClVzZSBiYXRjaCBtb2RlLiAgTmV2ZXIgYXNr
+LCBkbyBub3QgYWxsb3cgaW50ZXJhY3RpdmUgY29tbWFuZHMuCkBvcHRpb257LS1u
+by1iYXRjaH0gZGlzYWJsZXMgdGhpcyBvcHRpb24uICBOb3RlIHRoYXQgZXZlbiB3
+aXRoIGEKZmlsZW5hbWUgZ2l2ZW4gb24gdGhlIGNvbW1hbmQgbGluZSwgZ3BnIG1p
+Z2h0IHN0aWxsIG5lZWQgdG8gcmVhZCBmcm9tClNURElOIChpbiBwYXJ0aWN1bGFy
+IGlmIGdwZyBmaWd1cmVzIHRoYXQgdGhlIGlucHV0IGlzIGEKZGV0YWNoZWQgc2ln
+bmF0dXJlIGFuZCBubyBkYXRhIGZpbGUgaGFzIGJlZW4gc3BlY2lmaWVkKS4gIFRo
+dXMgaWYgeW91CmRvIG5vdCB3YW50IHRvIGZlZWQgZGF0YSB2aWEgU1RESU4sIHlv
+dSBzaG91bGQgY29ubmVjdCBTVERJTiB0bwpAZmlsZXsvZGV2L251bGx9LgoKQGl0
+ZW0gLS1uby10dHkKQG9waW5kZXggbm8tdHR5Ck1ha2Ugc3VyZSB0aGF0IHRoZSBU
+VFkgKHRlcm1pbmFsKSBpcyBuZXZlciB1c2VkIGZvciBhbnkgb3V0cHV0LgpUaGlz
+IG9wdGlvbiBpcyBuZWVkZWQgaW4gc29tZSBjYXNlcyBiZWNhdXNlIEdudVBHIHNv
+bWV0aW1lcyBwcmludHMKd2FybmluZ3MgdG8gdGhlIFRUWSBldmVuIGlmIEBvcHRp
+b257LS1iYXRjaH0gaXMgdXNlZC4KCkBpdGVtIC0teWVzCkBvcGluZGV4IHllcwpB
+c3N1bWUgInllcyIgb24gbW9zdCBxdWVzdGlvbnMuCgpAaXRlbSAtLW5vCkBvcGlu
+ZGV4IG5vCkFzc3VtZSAibm8iIG9uIG1vc3QgcXVlc3Rpb25zLgoKCkBpdGVtIC0t
+bGlzdC1vcHRpb25zIEBjb2Rle3BhcmFtZXRlcnN9CkBvcGluZGV4IGxpc3Qtb3B0
+aW9ucwpUaGlzIGlzIGEgc3BhY2Ugb3IgY29tbWEgZGVsaW1pdGVkIHN0cmluZyB0
+aGF0IGdpdmVzIG9wdGlvbnMgdXNlZCB3aGVuCmxpc3Rpbmcga2V5cyBhbmQgc2ln
+bmF0dXJlcyAodGhhdCBpcywgQG9wdGlvbnstLWxpc3Qta2V5c30sCkBvcHRpb257
+LS1saXN0LXNpZ3N9LCBAb3B0aW9uey0tbGlzdC1wdWJsaWMta2V5c30sCkBvcHRp
+b257LS1saXN0LXNlY3JldC1rZXlzfSwgYW5kIHRoZSBAb3B0aW9uey0tZWRpdC1r
+ZXl9IGZ1bmN0aW9ucykuCk9wdGlvbnMgY2FuIGJlIHByZXBlbmRlZCB3aXRoIGEg
+QG9wdGlvbntuby19IChhZnRlciB0aGUgdHdvIGRhc2hlcykgdG8KZ2l2ZSB0aGUg
+b3Bwb3NpdGUgbWVhbmluZy4gIFRoZSBvcHRpb25zIGFyZToKCkB0YWJsZSBAYXNp
+cwoKICBAaXRlbSBzaG93LXBob3RvcwogIEBvcGluZGV4IGxpc3Qtb3B0aW9uczpz
+aG93LXBob3RvcwogIENhdXNlcyBAb3B0aW9uey0tbGlzdC1rZXlzfSwgQG9wdGlv
+bnstLWxpc3Qtc2lnc30sCiAgQG9wdGlvbnstLWxpc3QtcHVibGljLWtleXN9LCBh
+bmQgQG9wdGlvbnstLWxpc3Qtc2VjcmV0LWtleXN9IHRvCiAgZGlzcGxheSBhbnkg
+cGhvdG8gSURzIGF0dGFjaGVkIHRvIHRoZSBrZXkuICBEZWZhdWx0cyB0byBuby4g
+U2VlIGFsc28KICBAb3B0aW9uey0tcGhvdG8tdmlld2VyfS4gIERvZXMgbm90IHdv
+cmsgd2l0aCBAb3B0aW9uey0td2l0aC1jb2xvbnN9OgogIHNlZSBAb3B0aW9uey0t
+YXR0cmlidXRlLWZkfSBmb3IgdGhlIGFwcHJvcHJpYXRlIHdheSB0byBnZXQgcGhv
+dG8gZGF0YQogIGZvciBzY3JpcHRzIGFuZCBvdGhlciBmcm9udGVuZHMuCgogIEBp
+dGVtIHNob3ctdXNhZ2UKICBAb3BpbmRleCBsaXN0LW9wdGlvbnM6c2hvdy11c2Fn
+ZQogIFNob3cgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIGtleXMgYW5kIHN1YmtleXMg
+aW4gdGhlIHN0YW5kYXJkIGtleQogIGxpc3RpbmcuICBUaGlzIGlzIGEgbGlzdCBv
+ZiBsZXR0ZXJzIGluZGljYXRpbmcgdGhlIGFsbG93ZWQgdXNhZ2UgZm9yIGEKICBr
+ZXkgKEBjb2Rle0V9PWVuY3J5cHRpb24sIEBjb2Rle1N9PXNpZ25pbmcsIEBjb2Rl
+e0N9PWNlcnRpZmljYXRpb24sCiAgQGNvZGV7QX09YXV0aGVudGljYXRpb24pLiAg
+RGVmYXVsdHMgdG8gbm8uCgogIEBpdGVtIHNob3ctcG9saWN5LXVybHMKICBAb3Bp
+bmRleCBsaXN0LW9wdGlvbnM6c2hvdy1wb2xpY3ktdXJscwogIFNob3cgcG9saWN5
+IFVSTHMgaW4gdGhlIEBvcHRpb257LS1saXN0LXNpZ3N9IG9yIEBvcHRpb257LS1j
+aGVjay1zaWdzfQogIGxpc3RpbmdzLiAgRGVmYXVsdHMgdG8gbm8uCgogIEBpdGVt
+IHNob3ctbm90YXRpb25zCiAgQGl0ZW14IHNob3ctc3RkLW5vdGF0aW9ucwogIEBp
+dGVteCBzaG93LXVzZXItbm90YXRpb25zCiAgQG9waW5kZXggbGlzdC1vcHRpb25z
+OnNob3ctbm90YXRpb25zCiAgQG9waW5kZXggbGlzdC1vcHRpb25zOnNob3ctc3Rk
+LW5vdGF0aW9ucwogIEBvcGluZGV4IGxpc3Qtb3B0aW9uczpzaG93LXVzZXItbm90
+YXRpb25zCiAgU2hvdyBhbGwsIElFVEYgc3RhbmRhcmQsIG9yIHVzZXItZGVmaW5l
+ZCBzaWduYXR1cmUgbm90YXRpb25zIGluIHRoZQogIEBvcHRpb257LS1saXN0LXNp
+Z3N9IG9yIEBvcHRpb257LS1jaGVjay1zaWdzfSBsaXN0aW5ncy4gRGVmYXVsdHMg
+dG8gbm8uCgogIEBpdGVtIHNob3cta2V5c2VydmVyLXVybHMKICBAb3BpbmRleCBs
+aXN0LW9wdGlvbnM6c2hvdy1rZXlzZXJ2ZXItdXJscwogIFNob3cgYW55IHByZWZl
+cnJlZCBrZXlzZXJ2ZXIgVVJMIGluIHRoZSBAb3B0aW9uey0tbGlzdC1zaWdzfSBv
+cgogIEBvcHRpb257LS1jaGVjay1zaWdzfSBsaXN0aW5ncy4gRGVmYXVsdHMgdG8g
+bm8uCgogIEBpdGVtIHNob3ctdWlkLXZhbGlkaXR5CiAgQG9waW5kZXggbGlzdC1v
+cHRpb25zOnNob3ctdWlkLXZhbGlkaXR5CiAgRGlzcGxheSB0aGUgY2FsY3VsYXRl
+ZCB2YWxpZGl0eSBvZiB1c2VyIElEcyBkdXJpbmcga2V5IGxpc3RpbmdzLgogIERl
+ZmF1bHRzIHRvIHllcy4KCiAgQGl0ZW0gc2hvdy11bnVzYWJsZS11aWRzCiAgQG9w
+aW5kZXggbGlzdC1vcHRpb25zOnNob3ctdW51c2FibGUtdWlkcwogIFNob3cgcmV2
+b2tlZCBhbmQgZXhwaXJlZCB1c2VyIElEcyBpbiBrZXkgbGlzdGluZ3MuIERlZmF1
+bHRzIHRvIG5vLgoKICBAaXRlbSBzaG93LXVudXNhYmxlLXN1YmtleXMKICBAb3Bp
+bmRleCBsaXN0LW9wdGlvbnM6c2hvdy11bnVzYWJsZS1zdWJrZXlzCiAgU2hvdyBy
+ZXZva2VkIGFuZCBleHBpcmVkIHN1YmtleXMgaW4ga2V5IGxpc3RpbmdzLiBEZWZh
+dWx0cyB0byBuby4KCiAgQGl0ZW0gc2hvdy1rZXlyaW5nCiAgQG9waW5kZXggbGlz
+dC1vcHRpb25zOnNob3cta2V5cmluZwogIERpc3BsYXkgdGhlIGtleXJpbmcgbmFt
+ZSBhdCB0aGUgaGVhZCBvZiBrZXkgbGlzdGluZ3MgdG8gc2hvdyB3aGljaAogIGtl
+eXJpbmcgYSBnaXZlbiBrZXkgcmVzaWRlcyBvbi4gRGVmYXVsdHMgdG8gbm8uCgog
+IEBpdGVtIHNob3ctc2lnLWV4cGlyZQogIEBvcGluZGV4IGxpc3Qtb3B0aW9uczpz
+aG93LXNpZy1leHBpcmUKICBTaG93IHNpZ25hdHVyZSBleHBpcmF0aW9uIGRhdGVz
+IChpZiBhbnkpIGR1cmluZyBAb3B0aW9uey0tbGlzdC1zaWdzfSBvcgogIEBvcHRp
+b257LS1jaGVjay1zaWdzfSBsaXN0aW5ncy4gRGVmYXVsdHMgdG8gbm8uCgogIEBp
+dGVtIHNob3ctc2lnLXN1YnBhY2tldHMKICBAb3BpbmRleCBsaXN0LW9wdGlvbnM6
+c2hvdy1zaWctc3VicGFja2V0cwogIEluY2x1ZGUgc2lnbmF0dXJlIHN1YnBhY2tl
+dHMgaW4gdGhlIGtleSBsaXN0aW5nLiBUaGlzIG9wdGlvbiBjYW4gdGFrZSBhbgog
+IG9wdGlvbmFsIGFyZ3VtZW50IGxpc3Qgb2YgdGhlIHN1YnBhY2tldHMgdG8gbGlz
+dC4gSWYgbm8gYXJndW1lbnQgaXMKICBwYXNzZWQsIGxpc3QgYWxsIHN1YnBhY2tl
+dHMuIERlZmF1bHRzIHRvIG5vLiBUaGlzIG9wdGlvbiBpcyBvbmx5CiAgbWVhbmlu
+Z2Z1bCB3aGVuIHVzaW5nIEBvcHRpb257LS13aXRoLWNvbG9uc30gYWxvbmcgd2l0
+aAogIEBvcHRpb257LS1saXN0LXNpZ3N9IG9yIEBvcHRpb257LS1jaGVjay1zaWdz
+fS4KCkBlbmQgdGFibGUKCkBpdGVtIC0tdmVyaWZ5LW9wdGlvbnMgQGNvZGV7cGFy
+YW1ldGVyc30KQG9waW5kZXggdmVyaWZ5LW9wdGlvbnMKVGhpcyBpcyBhIHNwYWNl
+IG9yIGNvbW1hIGRlbGltaXRlZCBzdHJpbmcgdGhhdCBnaXZlcyBvcHRpb25zIHVz
+ZWQgd2hlbgp2ZXJpZnlpbmcgc2lnbmF0dXJlcy4gT3B0aW9ucyBjYW4gYmUgcHJl
+cGVuZGVkIHdpdGggYSBgbm8tJyB0byBnaXZlCnRoZSBvcHBvc2l0ZSBtZWFuaW5n
+LiBUaGUgb3B0aW9ucyBhcmU6CgpAdGFibGUgQGFzaXMKCiAgQGl0ZW0gc2hvdy1w
+aG90b3MKICBAb3BpbmRleCB2ZXJpZnktb3B0aW9uczpzaG93LXBob3RvcwogIERp
+c3BsYXkgYW55IHBob3RvIElEcyBwcmVzZW50IG9uIHRoZSBrZXkgdGhhdCBpc3N1
+ZWQgdGhlIHNpZ25hdHVyZS4KICBEZWZhdWx0cyB0byBuby4gU2VlIGFsc28gQG9w
+dGlvbnstLXBob3RvLXZpZXdlcn0uCgogIEBpdGVtIHNob3ctcG9saWN5LXVybHMK
+ICBAb3BpbmRleCB2ZXJpZnktb3B0aW9uczpzaG93LXBvbGljeS11cmxzCiAgU2hv
+dyBwb2xpY3kgVVJMcyBpbiB0aGUgc2lnbmF0dXJlIGJlaW5nIHZlcmlmaWVkLiBE
+ZWZhdWx0cyB0byB5ZXMuCgogIEBpdGVtIHNob3ctbm90YXRpb25zCiAgQGl0ZW14
+IHNob3ctc3RkLW5vdGF0aW9ucwogIEBpdGVteCBzaG93LXVzZXItbm90YXRpb25z
+CiAgQG9waW5kZXggdmVyaWZ5LW9wdGlvbnM6c2hvdy1ub3RhdGlvbnMKICBAb3Bp
+bmRleCB2ZXJpZnktb3B0aW9uczpzaG93LXN0ZC1ub3RhdGlvbnMKICBAb3BpbmRl
+eCB2ZXJpZnktb3B0aW9uczpzaG93LXVzZXItbm90YXRpb25zCiAgU2hvdyBhbGws
+IElFVEYgc3RhbmRhcmQsIG9yIHVzZXItZGVmaW5lZCBzaWduYXR1cmUgbm90YXRp
+b25zIGluIHRoZQogIHNpZ25hdHVyZSBiZWluZyB2ZXJpZmllZC4gRGVmYXVsdHMg
+dG8gSUVURiBzdGFuZGFyZC4KCiAgQGl0ZW0gc2hvdy1rZXlzZXJ2ZXItdXJscwog
+IEBvcGluZGV4IHZlcmlmeS1vcHRpb25zOnNob3cta2V5c2VydmVyLXVybHMKICBT
+aG93IGFueSBwcmVmZXJyZWQga2V5c2VydmVyIFVSTCBpbiB0aGUgc2lnbmF0dXJl
+IGJlaW5nIHZlcmlmaWVkLgogIERlZmF1bHRzIHRvIHllcy4KCiAgQGl0ZW0gc2hv
+dy11aWQtdmFsaWRpdHkKICBAb3BpbmRleCB2ZXJpZnktb3B0aW9uczpzaG93LXVp
+ZC12YWxpZGl0eQogIERpc3BsYXkgdGhlIGNhbGN1bGF0ZWQgdmFsaWRpdHkgb2Yg
+dGhlIHVzZXIgSURzIG9uIHRoZSBrZXkgdGhhdCBpc3N1ZWQKICB0aGUgc2lnbmF0
+dXJlLiBEZWZhdWx0cyB0byB5ZXMuCgogIEBpdGVtIHNob3ctdW51c2FibGUtdWlk
+cwogIEBvcGluZGV4IHZlcmlmeS1vcHRpb25zOnNob3ctdW51c2FibGUtdWlkcwog
+IFNob3cgcmV2b2tlZCBhbmQgZXhwaXJlZCB1c2VyIElEcyBkdXJpbmcgc2lnbmF0
+dXJlIHZlcmlmaWNhdGlvbi4KICBEZWZhdWx0cyB0byBuby4KCiAgQGl0ZW0gc2hv
+dy1wcmltYXJ5LXVpZC1vbmx5CiAgQG9waW5kZXggdmVyaWZ5LW9wdGlvbnM6c2hv
+dy1wcmltYXJ5LXVpZC1vbmx5CiAgU2hvdyBvbmx5IHRoZSBwcmltYXJ5IHVzZXIg
+SUQgZHVyaW5nIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24uICBUaGF0IGlzCiAgYWxs
+IHRoZSBBS0EgbGluZXMgYXMgd2VsbCBhcyBwaG90byBJZHMgYXJlIG5vdCBzaG93
+biB3aXRoIHRoZSBzaWduYXR1cmUKICB2ZXJpZmljYXRpb24gc3RhdHVzLgoKICBA
+aXRlbSBwa2EtbG9va3VwcwogIEBvcGluZGV4IHZlcmlmeS1vcHRpb25zOnBrYS1s
+b29rdXBzCiAgRW5hYmxlIFBLQSBsb29rdXBzIHRvIHZlcmlmeSBzZW5kZXIgYWRk
+cmVzc2VzLiBOb3RlIHRoYXQgUEtBIGlzIGJhc2VkCiAgb24gRE5TLCBhbmQgc28g
+ZW5hYmxpbmcgdGhpcyBvcHRpb24gbWF5IGRpc2Nsb3NlIGluZm9ybWF0aW9uIG9u
+IHdoZW4KICBhbmQgd2hhdCBzaWduYXR1cmVzIGFyZSB2ZXJpZmllZCBvciB0byB3
+aG9tIGRhdGEgaXMgZW5jcnlwdGVkLiBUaGlzCiAgaXMgc2ltaWxhciB0byB0aGUg
+IndlYiBidWciIGRlc2NyaWJlZCBmb3IgdGhlIGF1dG8ta2V5LXJldHJpZXZlCiAg
+ZmVhdHVyZS4KCiAgQGl0ZW0gcGthLXRydXN0LWluY3JlYXNlCiAgQG9waW5kZXgg
+dmVyaWZ5LW9wdGlvbnM6cGthLXRydXN0LWluY3JlYXNlCiAgUmFpc2UgdGhlIHRy
+dXN0IGluIGEgc2lnbmF0dXJlIHRvIGZ1bGwgaWYgdGhlIHNpZ25hdHVyZSBwYXNz
+ZXMgUEtBCiAgdmFsaWRhdGlvbi4gVGhpcyBvcHRpb24gaXMgb25seSBtZWFuaW5n
+ZnVsIGlmIHBrYS1sb29rdXBzIGlzIHNldC4KQGVuZCB0YWJsZQoKQGl0ZW0gLS1l
+bmFibGUtbGFyZ2UtcnNhCkBpdGVteCAtLWRpc2FibGUtbGFyZ2UtcnNhCkBvcGlu
+ZGV4IGVuYWJsZS1sYXJnZS1yc2EKQG9waW5kZXggZGlzYWJsZS1sYXJnZS1yc2EK
+V2l0aCAtLWdlbi1rZXkgYW5kIC0tYmF0Y2gsIGVuYWJsZSB0aGUgY3JlYXRpb24g
+b2YgbGFyZ2VyIFJTQSBzZWNyZXQKa2V5cyB0aGFuIGlzIGdlbmVyYWxseSByZWNv
+bW1lbmRlZCAodXAgdG8gODE5MiBiaXRzKS4gIFRoZXNlIGxhcmdlCmtleXMgYXJl
+IG1vcmUgZXhwZW5zaXZlIHRvIHVzZSwgYW5kIHRoZWlyIHNpZ25hdHVyZXMgYW5k
+CmNlcnRpZmljYXRpb25zIGFyZSBhbHNvIGxhcmdlci4KCkBpdGVtIC0tZW5hYmxl
+LWRzYTIKQGl0ZW14IC0tZGlzYWJsZS1kc2EyCkBvcGluZGV4IGVuYWJsZS1kc2Ey
+CkBvcGluZGV4IGRpc2FibGUtZHNhMgpFbmFibGUgaGFzaCB0cnVuY2F0aW9uIGZv
+ciBhbGwgRFNBIGtleXMgZXZlbiBmb3Igb2xkIERTQSBLZXlzIHVwIHRvCjEwMjQg
+Yml0LiAgVGhpcyBpcyBhbHNvIHRoZSBkZWZhdWx0IHdpdGggQG9wdGlvbnstLW9w
+ZW5wZ3B9LiAgTm90ZQp0aGF0IG9sZGVyIHZlcnNpb25zIG9mIEdudVBHIGFsc28g
+cmVxdWlyZWQgdGhpcyBmbGFnIHRvIGFsbG93IHRoZQpnZW5lcmF0aW9uIG9mIERT
+QSBsYXJnZXIgdGhhbiAxMDI0IGJpdC4KCkBpdGVtIC0tcGhvdG8tdmlld2VyIEBj
+b2Rle3N0cmluZ30KQG9waW5kZXggcGhvdG8tdmlld2VyClRoaXMgaXMgdGhlIGNv
+bW1hbmQgbGluZSB0aGF0IHNob3VsZCBiZSBydW4gdG8gdmlldyBhIHBob3RvIElE
+LiAiJWkiCndpbGwgYmUgZXhwYW5kZWQgdG8gYSBmaWxlbmFtZSBjb250YWluaW5n
+IHRoZSBwaG90by4gIiVJIiBkb2VzIHRoZQpzYW1lLCBleGNlcHQgdGhlIGZpbGUg
+d2lsbCBub3QgYmUgZGVsZXRlZCBvbmNlIHRoZSB2aWV3ZXIgZXhpdHMuCk90aGVy
+IGZsYWdzIGFyZSAiJWsiIGZvciB0aGUga2V5IElELCAiJUsiIGZvciB0aGUgbG9u
+ZyBrZXkgSUQsICIlZiIKZm9yIHRoZSBrZXkgZmluZ2VycHJpbnQsICIldCIgZm9y
+IHRoZSBleHRlbnNpb24gb2YgdGhlIGltYWdlIHR5cGUKKGUuZy4gImpwZyIpLCAi
+JVQiIGZvciB0aGUgTUlNRSB0eXBlIG9mIHRoZSBpbWFnZSAoZS5nLiAiaW1hZ2Uv
+anBlZyIpLAoiJXYiIGZvciB0aGUgc2luZ2xlLWNoYXJhY3RlciBjYWxjdWxhdGVk
+IHZhbGlkaXR5IG9mIHRoZSBpbWFnZSBiZWluZwp2aWV3ZWQgKGUuZy4gImYiKSwg
+IiVWIiBmb3IgdGhlIGNhbGN1bGF0ZWQgdmFsaWRpdHkgYXMgYSBzdHJpbmcgKGUu
+Zy4KImZ1bGwiKSwgIiVVIiBmb3IgYSBiYXNlMzIgZW5jb2RlZCBoYXNoIG9mIHRo
+ZSB1c2VyIElELAphbmQgIiUlIiBmb3IgYW4gYWN0dWFsIHBlcmNlbnQgc2lnbi4g
+SWYgbmVpdGhlciAlaSBvciAlSSBhcmUgcHJlc2VudCwKdGhlbiB0aGUgcGhvdG8g
+d2lsbCBiZSBzdXBwbGllZCB0byB0aGUgdmlld2VyIG9uIHN0YW5kYXJkIGlucHV0
+LgoKVGhlIGRlZmF1bHQgdmlld2VyIGlzICJ4bG9hZGltYWdlIC1mb3JrIC1xdWll
+dCAtdGl0bGUgJ0tleUlEIDB4JWsnClNURElOIi4gTm90ZSB0aGF0IGlmIHlvdXIg
+aW1hZ2Ugdmlld2VyIHByb2dyYW0gaXMgbm90IHNlY3VyZSwgdGhlbgpleGVjdXRp
+bmcgaXQgZnJvbSBHbnVQRyBkb2VzIG5vdCBtYWtlIGl0IHNlY3VyZS4KCkBpdGVt
+IC0tZXhlYy1wYXRoIEBjb2Rle3N0cmluZ30KQG9waW5kZXggZXhlYy1wYXRoClNl
+dHMgYSBsaXN0IG9mIGRpcmVjdG9yaWVzIHRvIHNlYXJjaCBmb3IgcGhvdG8gdmll
+d2VycyBhbmQga2V5c2VydmVyCmhlbHBlcnMuIElmIG5vdCBwcm92aWRlZCwga2V5
+c2VydmVyIGhlbHBlcnMgdXNlIHRoZSBjb21waWxlZC1pbgpkZWZhdWx0IGRpcmVj
+dG9yeSwgYW5kIHBob3RvIHZpZXdlcnMgdXNlIHRoZSAkUEFUSCBlbnZpcm9ubWVu
+dAp2YXJpYWJsZS4KTm90ZSwgdGhhdCBvbiBXMzIgc3lzdGVtIHRoaXMgdmFsdWUg
+aXMgaWdub3JlZCB3aGVuIHNlYXJjaGluZyBmb3IKa2V5c2VydmVyIGhlbHBlcnMu
+CgpAaXRlbSAtLWtleXJpbmcgQGNvZGV7ZmlsZX0KQG9waW5kZXgga2V5cmluZwpB
+ZGQgQGNvZGV7ZmlsZX0gdG8gdGhlIGN1cnJlbnQgbGlzdCBvZiBrZXlyaW5ncy4g
+SWYgQGNvZGV7ZmlsZX0gYmVnaW5zCndpdGggYSB0aWxkZSBhbmQgYSBzbGFzaCwg
+dGhlc2UgYXJlIHJlcGxhY2VkIGJ5IHRoZSAkSE9NRSBkaXJlY3RvcnkuIElmCnRo
+ZSBmaWxlbmFtZSBkb2VzIG5vdCBjb250YWluIGEgc2xhc2gsIGl0IGlzIGFzc3Vt
+ZWQgdG8gYmUgaW4gdGhlIEdudVBHCmhvbWUgZGlyZWN0b3J5ICgifi8uZ251cGci
+IGlmIEBvcHRpb257LS1ob21lZGlyfSBvciAkR05VUEdIT01FIGlzIG5vdAp1c2Vk
+KS4KCk5vdGUgdGhhdCB0aGlzIGFkZHMgYSBrZXlyaW5nIHRvIHRoZSBjdXJyZW50
+IGxpc3QuIElmIHRoZSBpbnRlbnQgaXMgdG8KdXNlIHRoZSBzcGVjaWZpZWQga2V5
+cmluZyBhbG9uZSwgdXNlIEBvcHRpb257LS1rZXlyaW5nfSBhbG9uZyB3aXRoCkBv
+cHRpb257LS1uby1kZWZhdWx0LWtleXJpbmd9LgoKQGl0ZW0gLS1zZWNyZXQta2V5
+cmluZyBAY29kZXtmaWxlfQpAb3BpbmRleCBzZWNyZXQta2V5cmluZwpUaGlzIGlz
+IGFuIG9ic29sZXRlIG9wdGlvbiBhbmQgaWdub3JlZC4gIEFsbCBzZWNyZXQga2V5
+cyBhcmUgc3RvcmVkIGluCnRoZSBAZmlsZXtwcml2YXRlLWtleXMtdjEuZH0gZGly
+ZWN0b3J5IGJlbG93IHRoZSBHbnVQRyBob21lIGRpcmVjdG9yeS4KCkBpdGVtIC0t
+cHJpbWFyeS1rZXlyaW5nIEBjb2Rle2ZpbGV9CkBvcGluZGV4IHByaW1hcnkta2V5
+cmluZwpEZXNpZ25hdGUgQGNvZGV7ZmlsZX0gYXMgdGhlIHByaW1hcnkgcHVibGlj
+IGtleXJpbmcuIFRoaXMgbWVhbnMgdGhhdApuZXdseSBpbXBvcnRlZCBrZXlzICh2
+aWEgQG9wdGlvbnstLWltcG9ydH0gb3Iga2V5c2VydmVyCkBvcHRpb257LS1yZWN2
+LWZyb219KSB3aWxsIGdvIHRvIHRoaXMga2V5cmluZy4KCkBpdGVtIC0tdHJ1c3Rk
+Yi1uYW1lIEBjb2Rle2ZpbGV9CkBvcGluZGV4IHRydXN0ZGItbmFtZQpVc2UgQGNv
+ZGV7ZmlsZX0gaW5zdGVhZCBvZiB0aGUgZGVmYXVsdCB0cnVzdGRiLiBJZiBAY29k
+ZXtmaWxlfSBiZWdpbnMKd2l0aCBhIHRpbGRlIGFuZCBhIHNsYXNoLCB0aGVzZSBh
+cmUgcmVwbGFjZWQgYnkgdGhlICRIT01FIGRpcmVjdG9yeS4gSWYKdGhlIGZpbGVu
+YW1lIGRvZXMgbm90IGNvbnRhaW4gYSBzbGFzaCwgaXQgaXMgYXNzdW1lZCB0byBi
+ZSBpbiB0aGUgR251UEcKaG9tZSBkaXJlY3RvcnkgKEBmaWxle34vLmdudXBnfSBp
+ZiBAb3B0aW9uey0taG9tZWRpcn0gb3IgJEdOVVBHSE9NRSBpcwpub3QgdXNlZCku
+CgpAaW5jbHVkZSBvcHQtaG9tZWRpci50ZXhpCgoKQGl0ZW0gLS1kaXNwbGF5LWNo
+YXJzZXQgQGNvZGV7bmFtZX0KQG9waW5kZXggZGlzcGxheS1jaGFyc2V0ClNldCB0
+aGUgbmFtZSBvZiB0aGUgbmF0aXZlIGNoYXJhY3RlciBzZXQuIFRoaXMgaXMgdXNl
+ZCB0byBjb252ZXJ0CnNvbWUgaW5mb3JtYXRpb25hbCBzdHJpbmdzIGxpa2UgdXNl
+ciBJRHMgdG8gdGhlIHByb3BlciBVVEYtOCBlbmNvZGluZy4KTm90ZSB0aGF0IHRo
+aXMgaGFzIG5vdGhpbmcgdG8gZG8gd2l0aCB0aGUgY2hhcmFjdGVyIHNldCBvZiBk
+YXRhIHRvIGJlCmVuY3J5cHRlZCBvciBzaWduZWQ7IEdudVBHIGRvZXMgbm90IHJl
+Y29kZSB1c2VyLXN1cHBsaWVkIGRhdGEuIElmCnRoaXMgb3B0aW9uIGlzIG5vdCB1
+c2VkLCB0aGUgZGVmYXVsdCBjaGFyYWN0ZXIgc2V0IGlzIGRldGVybWluZWQgZnJv
+bQp0aGUgY3VycmVudCBsb2NhbGUuIEEgdmVyYm9zaXR5IGxldmVsIG9mIDMgc2hv
+d3MgdGhlIGNob3NlbiBzZXQuClZhbGlkIHZhbHVlcyBmb3IgQGNvZGV7bmFtZX0g
+YXJlOgoKQHRhYmxlIEBhc2lzCgogIEBpdGVtIGlzby04ODU5LTEKICBAb3BpbmRl
+eCBkaXNwbGF5LWNoYXJzZXQ6aXNvLTg4NTktMQogIFRoaXMgaXMgdGhlIExhdGlu
+IDEgc2V0LgoKICBAaXRlbSBpc28tODg1OS0yCiAgQG9waW5kZXggZGlzcGxheS1j
+aGFyc2V0Omlzby04ODU5LTIKICBUaGUgTGF0aW4gMiBzZXQuCgogIEBpdGVtIGlz
+by04ODU5LTE1CiAgQG9waW5kZXggZGlzcGxheS1jaGFyc2V0Omlzby04ODU5LTE1
+CiAgVGhpcyBpcyBjdXJyZW50bHkgYW4gYWxpYXMgZm9yCiAgdGhlIExhdGluIDEg
+c2V0LgoKICBAaXRlbSBrb2k4LXIKICBAb3BpbmRleCBkaXNwbGF5LWNoYXJzZXQ6
+a29pOC1yCiAgVGhlIHVzdWFsIFJ1c3NpYW4gc2V0IChyZmMxNDg5KS4KCiAgQGl0
+ZW0gdXRmLTgKICBAb3BpbmRleCBkaXNwbGF5LWNoYXJzZXQ6dXRmLTgKICBCeXBh
+c3MgYWxsIHRyYW5zbGF0aW9ucyBhbmQgYXNzdW1lCiAgdGhhdCB0aGUgT1MgdXNl
+cyBuYXRpdmUgVVRGLTggZW5jb2RpbmcuCkBlbmQgdGFibGUKCkBpdGVtIC0tdXRm
+OC1zdHJpbmdzCkBpdGVteCAtLW5vLXV0Zjgtc3RyaW5ncwpAb3BpbmRleCB1dGY4
+LXN0cmluZ3MKQXNzdW1lIHRoYXQgY29tbWFuZCBsaW5lIGFyZ3VtZW50cyBhcmUg
+Z2l2ZW4gYXMgVVRGOCBzdHJpbmdzLiBUaGUKZGVmYXVsdCAoQG9wdGlvbnstLW5v
+LXV0Zjgtc3RyaW5nc30pIGlzIHRvIGFzc3VtZSB0aGF0IGFyZ3VtZW50cyBhcmUK
+ZW5jb2RlZCBpbiB0aGUgY2hhcmFjdGVyIHNldCBhcyBzcGVjaWZpZWQgYnkKQG9w
+dGlvbnstLWRpc3BsYXktY2hhcnNldH0uIFRoZXNlIG9wdGlvbnMgYWZmZWN0IGFs
+bCBmb2xsb3dpbmcKYXJndW1lbnRzLiBCb3RoIG9wdGlvbnMgbWF5IGJlIHVzZWQg
+bXVsdGlwbGUgdGltZXMuCgpAYW5jaG9ye2dwZy1vcHRpb24gLS1vcHRpb25zfQpA
+aXRlbSAtLW9wdGlvbnMgQGNvZGV7ZmlsZX0KQG9waW5kZXggb3B0aW9ucwpSZWFk
+IG9wdGlvbnMgZnJvbSBAY29kZXtmaWxlfSBhbmQgZG8gbm90IHRyeSB0byByZWFk
+IHRoZW0gZnJvbSB0aGUKZGVmYXVsdCBvcHRpb25zIGZpbGUgaW4gdGhlIGhvbWVk
+aXIgKHNlZSBAb3B0aW9uey0taG9tZWRpcn0pLiBUaGlzCm9wdGlvbiBpcyBpZ25v
+cmVkIGlmIHVzZWQgaW4gYW4gb3B0aW9ucyBmaWxlLgoKQGl0ZW0gLS1uby1vcHRp
+b25zCkBvcGluZGV4IG5vLW9wdGlvbnMKU2hvcnRjdXQgZm9yIEBvcHRpb257LS1v
+cHRpb25zIC9kZXYvbnVsbH0uIFRoaXMgb3B0aW9uIGlzIGRldGVjdGVkCmJlZm9y
+ZSBhbiBhdHRlbXB0IHRvIG9wZW4gYW4gb3B0aW9uIGZpbGUuICBVc2luZyB0aGlz
+IG9wdGlvbiB3aWxsIGFsc28KcHJldmVudCB0aGUgY3JlYXRpb24gb2YgYSBAZmls
+ZXt+Ly5nbnVwZ30gaG9tZWRpci4KCkBpdGVtIC16IEBjb2Rle259CkBpdGVteCAt
+LWNvbXByZXNzLWxldmVsIEBjb2Rle259CkBpdGVteCAtLWJ6aXAyLWNvbXByZXNz
+LWxldmVsIEBjb2Rle259CkBvcGluZGV4IGNvbXByZXNzLWxldmVsCkBvcGluZGV4
+IGJ6aXAyLWNvbXByZXNzLWxldmVsClNldCBjb21wcmVzc2lvbiBsZXZlbCB0byBA
+Y29kZXtufSBmb3IgdGhlIFpJUCBhbmQgWkxJQiBjb21wcmVzc2lvbgphbGdvcml0
+aG1zLiBUaGUgZGVmYXVsdCBpcyB0byB1c2UgdGhlIGRlZmF1bHQgY29tcHJlc3Np
+b24gbGV2ZWwgb2YgemxpYgoobm9ybWFsbHkgNikuIEBvcHRpb257LS1iemlwMi1j
+b21wcmVzcy1sZXZlbH0gc2V0cyB0aGUgY29tcHJlc3Npb24gbGV2ZWwKZm9yIHRo
+ZSBCWklQMiBjb21wcmVzc2lvbiBhbGdvcml0aG0gKGRlZmF1bHRpbmcgdG8gNiBh
+cyB3ZWxsKS4gVGhpcyBpcyBhCmRpZmZlcmVudCBvcHRpb24gZnJvbSBAb3B0aW9u
+ey0tY29tcHJlc3MtbGV2ZWx9IHNpbmNlIEJaSVAyIHVzZXMgYQpzaWduaWZpY2Fu
+dCBhbW91bnQgb2YgbWVtb3J5IGZvciBlYWNoIGFkZGl0aW9uYWwgY29tcHJlc3Np
+b24gbGV2ZWwuCkBvcHRpb257LXp9IHNldHMgYm90aC4gQSB2YWx1ZSBvZiAwIGZv
+ciBAY29kZXtufSBkaXNhYmxlcyBjb21wcmVzc2lvbi4KCkBpdGVtIC0tYnppcDIt
+ZGVjb21wcmVzcy1sb3dtZW0KQG9waW5kZXggYnppcDItZGVjb21wcmVzcy1sb3dt
+ZW0KVXNlIGEgZGlmZmVyZW50IGRlY29tcHJlc3Npb24gbWV0aG9kIGZvciBCWklQ
+MiBjb21wcmVzc2VkIGZpbGVzLiBUaGlzCmFsdGVybmF0ZSBtZXRob2QgdXNlcyBh
+IGJpdCBtb3JlIHRoYW4gaGFsZiB0aGUgbWVtb3J5LCBidXQgYWxzbyBydW5zCmF0
+IGhhbGYgdGhlIHNwZWVkLiBUaGlzIGlzIHVzZWZ1bCB1bmRlciBleHRyZW1lIGxv
+dyBtZW1vcnkKY2lyY3Vtc3RhbmNlcyB3aGVuIHRoZSBmaWxlIHdhcyBvcmlnaW5h
+bGx5IGNvbXByZXNzZWQgYXQgYSBoaWdoCkBvcHRpb257LS1iemlwMi1jb21wcmVz
+cy1sZXZlbH0uCgoKQGl0ZW0gLS1tYW5nbGUtZG9zLWZpbGVuYW1lcwpAaXRlbXgg
+LS1uby1tYW5nbGUtZG9zLWZpbGVuYW1lcwpAb3BpbmRleCBtYW5nbGUtZG9zLWZp
+bGVuYW1lcwpAb3BpbmRleCBuby1tYW5nbGUtZG9zLWZpbGVuYW1lcwpPbGRlciB2
+ZXJzaW9uIG9mIFdpbmRvd3MgY2Fubm90IGhhbmRsZSBmaWxlbmFtZXMgd2l0aCBt
+b3JlIHRoYW4gb25lCmRvdC4gQG9wdGlvbnstLW1hbmdsZS1kb3MtZmlsZW5hbWVz
+fSBjYXVzZXMgR251UEcgdG8gcmVwbGFjZSAocmF0aGVyCnRoYW4gYWRkIHRvKSB0
+aGUgZXh0ZW5zaW9uIG9mIGFuIG91dHB1dCBmaWxlbmFtZSB0byBhdm9pZCB0aGlz
+CnByb2JsZW0uIFRoaXMgb3B0aW9uIGlzIG9mZiBieSBkZWZhdWx0IGFuZCBoYXMg
+bm8gZWZmZWN0IG9uIG5vbi1XaW5kb3dzCnBsYXRmb3Jtcy4KCkBpdGVtIC0tYXNr
+LWNlcnQtbGV2ZWwKQGl0ZW14IC0tbm8tYXNrLWNlcnQtbGV2ZWwKQG9waW5kZXgg
+YXNrLWNlcnQtbGV2ZWwKV2hlbiBtYWtpbmcgYSBrZXkgc2lnbmF0dXJlLCBwcm9t
+cHQgZm9yIGEgY2VydGlmaWNhdGlvbiBsZXZlbC4gSWYgdGhpcwpvcHRpb24gaXMg
+bm90IHNwZWNpZmllZCwgdGhlIGNlcnRpZmljYXRpb24gbGV2ZWwgdXNlZCBpcyBz
+ZXQgdmlhCkBvcHRpb257LS1kZWZhdWx0LWNlcnQtbGV2ZWx9LiBTZWUgQG9wdGlv
+bnstLWRlZmF1bHQtY2VydC1sZXZlbH0gZm9yCmluZm9ybWF0aW9uIG9uIHRoZSBz
+cGVjaWZpYyBsZXZlbHMgYW5kIGhvdyB0aGV5IGFyZQp1c2VkLiBAb3B0aW9uey0t
+bm8tYXNrLWNlcnQtbGV2ZWx9IGRpc2FibGVzIHRoaXMgb3B0aW9uLiBUaGlzIG9w
+dGlvbgpkZWZhdWx0cyB0byBuby4KCkBpdGVtIC0tZGVmYXVsdC1jZXJ0LWxldmVs
+IEBjb2Rle259CkBvcGluZGV4IGRlZmF1bHQtY2VydC1sZXZlbApUaGUgZGVmYXVs
+dCB0byB1c2UgZm9yIHRoZSBjaGVjayBsZXZlbCB3aGVuIHNpZ25pbmcgYSBrZXku
+CgowIG1lYW5zIHlvdSBtYWtlIG5vIHBhcnRpY3VsYXIgY2xhaW0gYXMgdG8gaG93
+IGNhcmVmdWxseSB5b3UgdmVyaWZpZWQKdGhlIGtleS4KCjEgbWVhbnMgeW91IGJl
+bGlldmUgdGhlIGtleSBpcyBvd25lZCBieSB0aGUgcGVyc29uIHdobyBjbGFpbXMg
+dG8gb3duCml0IGJ1dCB5b3UgY291bGQgbm90LCBvciBkaWQgbm90IHZlcmlmeSB0
+aGUga2V5IGF0IGFsbC4gVGhpcyBpcwp1c2VmdWwgZm9yIGEgInBlcnNvbmEiIHZl
+cmlmaWNhdGlvbiwgd2hlcmUgeW91IHNpZ24gdGhlIGtleSBvZiBhCnBzZXVkb255
+bW91cyB1c2VyLgoKMiBtZWFucyB5b3UgZGlkIGNhc3VhbCB2ZXJpZmljYXRpb24g
+b2YgdGhlIGtleS4gRm9yIGV4YW1wbGUsIHRoaXMKY291bGQgbWVhbiB0aGF0IHlv
+dSB2ZXJpZmllZCB0aGUga2V5IGZpbmdlcnByaW50IGFuZCBjaGVja2VkIHRoZQp1
+c2VyIElEIG9uIHRoZSBrZXkgYWdhaW5zdCBhIHBob3RvIElELgoKMyBtZWFucyB5
+b3UgZGlkIGV4dGVuc2l2ZSB2ZXJpZmljYXRpb24gb2YgdGhlIGtleS4gRm9yIGV4
+YW1wbGUsIHRoaXMKY291bGQgbWVhbiB0aGF0IHlvdSB2ZXJpZmllZCB0aGUga2V5
+IGZpbmdlcnByaW50IHdpdGggdGhlIG93bmVyIG9mIHRoZQprZXkgaW4gcGVyc29u
+LCBhbmQgdGhhdCB5b3UgY2hlY2tlZCwgYnkgbWVhbnMgb2YgYSBoYXJkIHRvIGZv
+cmdlCmRvY3VtZW50IHdpdGggYSBwaG90byBJRCAoc3VjaCBhcyBhIHBhc3Nwb3J0
+KSB0aGF0IHRoZSBuYW1lIG9mIHRoZSBrZXkKb3duZXIgbWF0Y2hlcyB0aGUgbmFt
+ZSBpbiB0aGUgdXNlciBJRCBvbiB0aGUga2V5LCBhbmQgZmluYWxseSB0aGF0IHlv
+dQp2ZXJpZmllZCAoYnkgZXhjaGFuZ2Ugb2YgZW1haWwpIHRoYXQgdGhlIGVtYWls
+IGFkZHJlc3Mgb24gdGhlIGtleQpiZWxvbmdzIHRvIHRoZSBrZXkgb3duZXIuCgpO
+b3RlIHRoYXQgdGhlIGV4YW1wbGVzIGdpdmVuIGFib3ZlIGZvciBsZXZlbHMgMiBh
+bmQgMyBhcmUganVzdCB0aGF0OgpleGFtcGxlcy4gSW4gdGhlIGVuZCwgaXQgaXMg
+dXAgdG8geW91IHRvIGRlY2lkZSBqdXN0IHdoYXQgImNhc3VhbCIKYW5kICJleHRl
+bnNpdmUiIG1lYW4gdG8geW91LgoKVGhpcyBvcHRpb24gZGVmYXVsdHMgdG8gMCAo
+bm8gcGFydGljdWxhciBjbGFpbSkuCgpAaXRlbSAtLW1pbi1jZXJ0LWxldmVsCkBv
+cGluZGV4IG1pbi1jZXJ0LWxldmVsCldoZW4gYnVpbGRpbmcgdGhlIHRydXN0IGRh
+dGFiYXNlLCB0cmVhdCBhbnkgc2lnbmF0dXJlcyB3aXRoIGEKY2VydGlmaWNhdGlv
+biBsZXZlbCBiZWxvdyB0aGlzIGFzIGludmFsaWQuIERlZmF1bHRzIHRvIDIsIHdo
+aWNoCmRpc3JlZ2FyZHMgbGV2ZWwgMSBzaWduYXR1cmVzLiBOb3RlIHRoYXQgbGV2
+ZWwgMCAibm8gcGFydGljdWxhcgpjbGFpbSIgc2lnbmF0dXJlcyBhcmUgYWx3YXlz
+IGFjY2VwdGVkLgoKQGl0ZW0gLS10cnVzdGVkLWtleSBAY29kZXtsb25nIGtleSBJ
+RH0KQG9waW5kZXggdHJ1c3RlZC1rZXkKQXNzdW1lIHRoYXQgdGhlIHNwZWNpZmll
+ZCBrZXkgKHdoaWNoIG11c3QgYmUgZ2l2ZW4KYXMgYSBmdWxsIDggYnl0ZSBrZXkg
+SUQpIGlzIGFzIHRydXN0d29ydGh5IGFzIG9uZSBvZgp5b3VyIG93biBzZWNyZXQg
+a2V5cy4gVGhpcyBvcHRpb24gaXMgdXNlZnVsIGlmIHlvdQpkb24ndCB3YW50IHRv
+IGtlZXAgeW91ciBzZWNyZXQga2V5cyAob3Igb25lIG9mIHRoZW0pCm9ubGluZSBi
+dXQgc3RpbGwgd2FudCB0byBiZSBhYmxlIHRvIGNoZWNrIHRoZSB2YWxpZGl0eSBv
+ZiBhIGdpdmVuCnJlY2lwaWVudCdzIG9yIHNpZ25hdG9yJ3Mga2V5LgoKQGl0ZW0g
+LS10cnVzdC1tb2RlbCBAY29kZXtwZ3B8Y2xhc3NpY3x0b2Z1fHRvZnUrcGdwfGRp
+cmVjdHxhbHdheXN8YXV0b30KQG9waW5kZXggdHJ1c3QtbW9kZWwKU2V0IHdoYXQg
+dHJ1c3QgbW9kZWwgR251UEcgc2hvdWxkIGZvbGxvdy4gVGhlIG1vZGVscyBhcmU6
+CgpAdGFibGUgQGFzaXMKCiAgQGl0ZW0gcGdwCiAgQG9waW5kZXggdHJ1c3QtbW9k
+ZTpwZ3AKICBUaGlzIGlzIHRoZSBXZWIgb2YgVHJ1c3QgY29tYmluZWQgd2l0aCB0
+cnVzdCBzaWduYXR1cmVzIGFzIHVzZWQgaW4gUEdQCiAgNS54IGFuZCBsYXRlci4g
+VGhpcyBpcyB0aGUgZGVmYXVsdCB0cnVzdCBtb2RlbCB3aGVuIGNyZWF0aW5nIGEg
+bmV3CiAgdHJ1c3QgZGF0YWJhc2UuCgogIEBpdGVtIGNsYXNzaWMKICBAb3BpbmRl
+eCB0cnVzdC1tb2RlOmNsYXNzaWMKICBUaGlzIGlzIHRoZSBzdGFuZGFyZCBXZWIg
+b2YgVHJ1c3QgYXMgaW50cm9kdWNlZCBieSBQR1AgMi4KCiAgQGl0ZW0gdG9mdQog
+IEBvcGluZGV4IHRydXN0LW1vZGU6dG9mdQogIEBhbmNob3J7dHJ1c3QtbW9kZWwt
+dG9mdX0KICBUT0ZVIHN0YW5kcyBmb3IgVHJ1c3QgT24gRmlyc3QgVXNlLiAgSW4g
+dGhpcyB0cnVzdCBtb2RlbCwgdGhlIGZpcnN0CiAgdGltZSBhIGtleSBpcyBzZWVu
+LCBpdCBpcyBtZW1vcml6ZWQuICBJZiBsYXRlciBhbm90aGVyIGtleSBpcyBzZWVu
+CiAgd2l0aCBhIHVzZXIgaWQgd2l0aCB0aGUgc2FtZSBlbWFpbCBhZGRyZXNzLCBh
+IHdhcm5pbmcgaXMgZGlzcGxheWVkCiAgaW5kaWNhdGluZyB0aGF0IHRoZXJlIGlz
+IGEgY29uZmxpY3QgYW5kIHRoYXQgdGhlIGtleSBtaWdodCBiZSBhCiAgZm9yZ2Vy
+eSBhbmQgYW4gYXR0ZW1wdCBhdCBhIG1hbi1pbi10aGUtbWlkZGxlIGF0dGFjay4K
+CiAgQmVjYXVzZSBhIHBvdGVudGlhbCBhdHRhY2tlciBpcyBhYmxlIHRvIGNvbnRy
+b2wgdGhlIGVtYWlsIGFkZHJlc3MKICBhbmQgdGhlcmVieSBjaXJjdW12ZW50IHRo
+ZSBjb25mbGljdCBkZXRlY3Rpb24gYWxnb3JpdGhtIGJ5IHVzaW5nIGFuCiAgZW1h
+aWwgYWRkcmVzcyB0aGF0IGlzIHNpbWlsYXIgaW4gYXBwZWFyYW5jZSB0byBhIHRy
+dXN0ZWQgZW1haWwKICBhZGRyZXNzLCB3aGVuZXZlciBhIG1lc3NhZ2UgaXMgdmVy
+aWZpZWQsIHN0YXRpc3RpY3MgYWJvdXQgdGhlIG51bWJlcgogIG9mIG1lc3NhZ2Vz
+IHNpZ25lZCB3aXRoIHRoZSBrZXkgYXJlIHNob3duLiAgSW4gdGhpcyB3YXksIGEg
+dXNlciBjYW4KICBlYXNpbHkgaWRlbnRpZnkgYXR0YWNrcyB1c2luZyBmYWtlIGtl
+eXMgZm9yIHJlZ3VsYXIgY29ycmVzcG9uZGVudHMuCgogIFdoZW4gY29tcGFyZWQg
+d2l0aCB0aGUgV2ViIG9mIFRydXN0LCBUT0ZVIG9mZmVycyBzaWduaWZpY2FudGx5
+CiAgd2Vha2VyIHNlY3VyaXR5IGd1YXJhbnRlZXMuICBJbiBwYXJ0aWN1bGFyLCBU
+T0ZVIG9ubHkgaGVscHMgZW5zdXJlCiAgY29uc2lzdGVuY3kgKHRoYXQgaXMsIHRo
+YXQgdGhlIGJpbmRpbmcgYmV0d2VlbiBhIGtleSBhbmQgZW1haWwKICBhZGRyZXNz
+IGRvZXNuJ3QgY2hhbmdlKS4gIEEgbWFqb3IgYWR2YW50YWdlIG9mIFRPRlUgaXMg
+dGhhdCBpdAogIHJlcXVpcmVzIGxpdHRsZSBtYWludGVuYW5jZSB0byB1c2UgY29y
+cmVjdGx5LiAgVG8gdXNlIHRoZSB3ZWIgb2YKICB0cnVzdCBwcm9wZXJseSwgeW91
+IG5lZWQgdG8gYWN0aXZlbHkgc2lnbiBrZXlzIGFuZCBtYXJrIHVzZXJzIGFzCiAg
+dHJ1c3RlZCBpbnRyb2R1Y2Vycy4gIFRoaXMgaXMgYSB0aW1lLWNvbnN1bWluZyBw
+cm9jZXNzIGFuZCBhbmVjZG90YWwKICBldmlkZW5jZSBzdWdnZXN0cyB0aGF0IGV2
+ZW4gc2VjdXJpdHktY29uc2Npb3VzIHVzZXJzIHJhcmVseSB0YWtlIHRoZQogIHRp
+bWUgdG8gZG8gdGhpcyB0aG9yb3VnaGx5IGFuZCBpbnN0ZWFkIHJlbHkgb24gYW4g
+YWQtaG9jIFRPRlUKICBwcm9jZXNzLgoKICBJbiB0aGUgVE9GVSBtb2RlbCwgcG9s
+aWNpZXMgYXJlIGFzc29jaWF0ZWQgd2l0aCBiaW5kaW5ncyBiZXR3ZWVuCiAga2V5
+cyBhbmQgZW1haWwgYWRkcmVzc2VzICh3aGljaCBhcmUgZXh0cmFjdGVkIGZyb20g
+dXNlciBpZHMgYW5kCiAgbm9ybWFsaXplZCkuICBUaGVyZSBhcmUgZml2ZSBwb2xp
+Y2llcywgd2hpY2ggY2FuIGJlIHNldCBtYW51YWxseQogIHVzaW5nIHRoZSBAb3B0
+aW9uey0tdG9mdS1wb2xpY3l9IG9wdGlvbi4gIFRoZSBkZWZhdWx0IHBvbGljeSBj
+YW4gYmUKICBzZXQgdXNpbmcgdGhlIEBvcHRpb257LS10b2Z1LWRlZmF1bHQtcG9s
+aWN5fSBwb2xpY3kuCgogIFRoZSBUT0ZVIHBvbGljaWVzIGFyZTogQGNvZGV7YXV0
+b30sIEBjb2Rle2dvb2R9LCBAY29kZXt1bmtub3dufSwKICBAY29kZXtiYWR9IGFu
+ZCBAY29kZXthc2t9LiAgVGhlIEBjb2Rle2F1dG99IHBvbGljeSBpcyB1c2VkIGJ5
+CiAgZGVmYXVsdCAodW5sZXNzIG92ZXJyaWRkZW4gYnkgQG9wdGlvbnstLXRvZnUt
+ZGVmYXVsdC1wb2xpY3l9KSBhbmQKICBtYXJrcyBhIGJpbmRpbmcgYXMgbWFyZ2lu
+YWxseSB0cnVzdGVkLiAgVGhlIEBjb2Rle2dvb2R9LAogIEBjb2Rle3Vua25vd259
+IGFuZCBAY29kZXtiYWR9IHBvbGljaWVzIG1hcmsgYSBiaW5kaW5nIGFzIGZ1bGx5
+CiAgdHJ1c3RlZCwgYXMgaGF2aW5nIHVua25vd24gdHJ1c3Qgb3IgYXMgaGF2aW5n
+IHRydXN0IG5ldmVyLAogIHJlc3BlY3RpdmVseS4gIFRoZSBAY29kZXt1bmtub3du
+fSBwb2xpY3kgaXMgdXNlZnVsIGZvciBqdXN0IHVzaW5nCiAgVE9GVSB0byBkZXRl
+Y3QgY29uZmxpY3RzLCBidXQgdG8gbmV2ZXIgYXNzaWduIHBvc2l0aXZlIHRydXN0
+IHRvIGEKICBiaW5kaW5nLiAgVGhlIGZpbmFsIHBvbGljeSwgQGNvZGV7YXNrfSBw
+cm9tcHRzIHRoZSB1c2VyIHRvIGluZGljYXRlCiAgdGhlIGJpbmRpbmcncyB0cnVz
+dC4gIElmIGJhdGNoIG1vZGUgaXMgZW5hYmxlZCAob3IgaW5wdXQgaXMKICBpbmFw
+cHJvcHJpYXRlIGluIHRoZSBjb250ZXh0KSwgdGhlbiB0aGUgdXNlciBpcyBub3Qg
+cHJvbXB0ZWQgYW5kIHRoZQogIEBjb2Rle3VuZGVmaW5lZH0gdHJ1c3QgbGV2ZWwg
+aXMgcmV0dXJuZWQuCgogIEBpdGVtIHRvZnUrcGdwCiAgQG9waW5kZXggdHJ1c3Qt
+bW9kZTp0b2Z1K3BncAogIFRoaXMgdHJ1c3QgbW9kZWwgY29tYmluZXMgVE9GVSB3
+aXRoIHRoZSBXZWIgb2YgVHJ1c3QuICBUaGlzIGlzIGRvbmUKICBieSBjb21wdXRp
+bmcgdGhlIHRydXN0IGxldmVsIGZvciBlYWNoIG1vZGVsIGFuZCB0aGVuIHRha2lu
+ZyB0aGUKICBtYXhpbXVtIHRydXN0IGxldmVsIHdoZXJlIHRoZSB0cnVzdCBsZXZl
+bHMgYXJlIG9yZGVyZWQgYXMgZm9sbG93czoKICBAY29kZXt1bmtub3duIDwgdW5k
+ZWZpbmVkIDwgbWFyZ2luYWwgPCBmdWxseSA8IHVsdGltYXRlIDwgZXhwaXJlZCA8
+CiAgbmV2ZXJ9LgoKICBCeSBzZXR0aW5nIEBvcHRpb257LS10b2Z1LWRlZmF1bHQt
+cG9saWN5PXVua25vd259LCB0aGlzIG1vZGVsIGNhbiBiZQogIHVzZWQgdG8gaW1w
+bGVtZW50IHRoZSB3ZWIgb2YgdHJ1c3Qgd2l0aCBUT0ZVJ3MgY29uZmxpY3QgZGV0
+ZWN0aW9uCiAgYWxnb3JpdGhtLCBidXQgd2l0aG91dCBpdHMgYXNzaWdubWVudCBv
+ZiBwb3NpdGl2ZSB0cnVzdCB2YWx1ZXMsCiAgd2hpY2ggc29tZSBzZWN1cml0eS1j
+b25zY2lvdXMgdXNlcnMgZG9uJ3QgbGlrZS4KCiAgQGl0ZW0gZGlyZWN0CiAgQG9w
+aW5kZXggdHJ1c3QtbW9kZTpkaXJlY3QKICBLZXkgdmFsaWRpdHkgaXMgc2V0IGRp
+cmVjdGx5IGJ5IHRoZSB1c2VyIGFuZCBub3QgY2FsY3VsYXRlZCB2aWEgdGhlCiAg
+V2ViIG9mIFRydXN0LgoKICBAaXRlbSBhbHdheXMKICBAb3BpbmRleCB0cnVzdC1t
+b2RlOmFsd2F5cwogIFNraXAga2V5IHZhbGlkYXRpb24gYW5kIGFzc3VtZSB0aGF0
+IHVzZWQga2V5cyBhcmUgYWx3YXlzIGZ1bGx5CiAgdmFsaWQuIFlvdSBnZW5lcmFs
+bHkgd29uJ3QgdXNlIHRoaXMgdW5sZXNzIHlvdSBhcmUgdXNpbmcgc29tZQogIGV4
+dGVybmFsIHZhbGlkYXRpb24gc2NoZW1lLiBUaGlzIG9wdGlvbiBhbHNvIHN1cHBy
+ZXNzZXMgdGhlCiAgIlt1bmNlcnRhaW5dIiB0YWcgcHJpbnRlZCB3aXRoIHNpZ25h
+dHVyZSBjaGVja3Mgd2hlbiB0aGVyZSBpcyBubwogIGV2aWRlbmNlIHRoYXQgdGhl
+IHVzZXIgSUQgaXMgYm91bmQgdG8gdGhlIGtleS4gIE5vdGUgdGhhdCB0aGlzCiAg
+dHJ1c3QgbW9kZWwgc3RpbGwgZG9lcyBub3QgYWxsb3cgdGhlIHVzZSBvZiBleHBp
+cmVkLCByZXZva2VkLCBvcgogIGRpc2FibGVkIGtleXMuCgogIEBpdGVtIGF1dG8K
+ICBAb3BpbmRleCB0cnVzdC1tb2RlOmF1dG8KICBTZWxlY3QgdGhlIHRydXN0IG1v
+ZGVsIGRlcGVuZGluZyBvbiB3aGF0ZXZlciB0aGUgaW50ZXJuYWwgdHJ1c3QKICBk
+YXRhYmFzZSBzYXlzLiBUaGlzIGlzIHRoZSBkZWZhdWx0IG1vZGVsIGlmIHN1Y2gg
+YSBkYXRhYmFzZSBhbHJlYWR5CiAgZXhpc3RzLgpAZW5kIHRhYmxlCgpAaXRlbSAt
+LWF1dG8ta2V5LWxvY2F0ZSBAY29kZXtwYXJhbWV0ZXJzfQpAaXRlbXggLS1uby1h
+dXRvLWtleS1sb2NhdGUKQG9waW5kZXggYXV0by1rZXktbG9jYXRlCkdudVBHIGNh
+biBhdXRvbWF0aWNhbGx5IGxvY2F0ZSBhbmQgcmV0cmlldmUga2V5cyBhcyBuZWVk
+ZWQgdXNpbmcgdGhpcwpvcHRpb24uIFRoaXMgaGFwcGVucyB3aGVuIGVuY3J5cHRp
+bmcgdG8gYW4gZW1haWwgYWRkcmVzcyAoaW4gdGhlCiJ1c2VyQEBleGFtcGxlLmNv
+bSIgZm9ybSksIGFuZCB0aGVyZSBhcmUgbm8gdXNlckBAZXhhbXBsZS5jb20ga2V5
+cyBvbgp0aGUgbG9jYWwga2V5cmluZy4gIFRoaXMgb3B0aW9uIHRha2VzIGFueSBu
+dW1iZXIgb2YgdGhlIGZvbGxvd2luZwptZWNoYW5pc21zLCBpbiB0aGUgb3JkZXIg
+dGhleSBhcmUgdG8gYmUgdHJpZWQ6CgpAdGFibGUgQGFzaXMKCiAgQGl0ZW0gY2Vy
+dAogIExvY2F0ZSBhIGtleSB1c2luZyBETlMgQ0VSVCwgYXMgc3BlY2lmaWVkIGlu
+IHJmYzQzOTguCgogIEBpdGVtIHBrYQogIExvY2F0ZSBhIGtleSB1c2luZyBETlMg
+UEtBLgoKICBAaXRlbSBkYW5lCiAgTG9jYXRlIGEga2V5IHVzaW5nIERBTkUsIGFz
+IHNwZWNpZmllZAogIGluIGRyYWZ0LWlldGYtZGFuZS1vcGVucGdwa2V5LTA1LnR4
+dC4KCiAgQGl0ZW0gbGRhcAogIFVzaW5nIEROUyBTZXJ2aWNlIERpc2NvdmVyeSwg
+Y2hlY2sgdGhlIGRvbWFpbiBpbiBxdWVzdGlvbiBmb3IgYW55IExEQVAKICBrZXlz
+ZXJ2ZXJzIHRvIHVzZS4gIElmIHRoaXMgZmFpbHMsIGF0dGVtcHQgdG8gbG9jYXRl
+IHRoZSBrZXkgdXNpbmcgdGhlCiAgUEdQIFVuaXZlcnNhbCBtZXRob2Qgb2YgY2hl
+Y2tpbmcgQHNhbXB7bGRhcDovL2tleXMuKHRoZWRvbWFpbil9LgoKICBAaXRlbSBr
+ZXlzZXJ2ZXIKICBMb2NhdGUgYSBrZXkgdXNpbmcgd2hhdGV2ZXIga2V5c2VydmVy
+IGlzIGRlZmluZWQgdXNpbmcgdGhlCiAgQG9wdGlvbnstLWtleXNlcnZlcn0gb3B0
+aW9uLgoKICBAaXRlbSBrZXlzZXJ2ZXItVVJMCiAgSW4gYWRkaXRpb24sIGEga2V5
+c2VydmVyIFVSTCBhcyB1c2VkIGluIHRoZSBAb3B0aW9uey0ta2V5c2VydmVyfSBv
+cHRpb24KICBtYXkgYmUgdXNlZCBoZXJlIHRvIHF1ZXJ5IHRoYXQgcGFydGljdWxh
+ciBrZXlzZXJ2ZXIuCgogIEBpdGVtIGxvY2FsCiAgTG9jYXRlIHRoZSBrZXkgdXNp
+bmcgdGhlIGxvY2FsIGtleXJpbmdzLiAgVGhpcyBtZWNoYW5pc20gYWxsb3dzIHRv
+CiAgc2VsZWN0IHRoZSBvcmRlciBhIGxvY2FsIGtleSBsb29rdXAgaXMgZG9uZS4g
+IFRodXMgdXNpbmcKICBAc2FtcHstLWF1dG8ta2V5LWxvY2F0ZSBsb2NhbH0gaXMg
+aWRlbnRpY2FsIHRvCiAgQG9wdGlvbnstLW5vLWF1dG8ta2V5LWxvY2F0ZX0uCgog
+IEBpdGVtIG5vZGVmYXVsdAogIFRoaXMgZmxhZyBkaXNhYmxlcyB0aGUgc3RhbmRh
+cmQgbG9jYWwga2V5IGxvb2t1cCwgZG9uZSBiZWZvcmUgYW55IG9mIHRoZQogIG1l
+Y2hhbmlzbXMgZGVmaW5lZCBieSB0aGUgQG9wdGlvbnstLWF1dG8ta2V5LWxvY2F0
+ZX0gYXJlIHRyaWVkLiAgVGhlCiAgcG9zaXRpb24gb2YgdGhpcyBtZWNoYW5pc20g
+aW4gdGhlIGxpc3QgZG9lcyBub3QgbWF0dGVyLiAgSXQgaXMgbm90CiAgcmVxdWly
+ZWQgaWYgQGNvZGV7bG9jYWx9IGlzIGFsc28gdXNlZC4KCiAgQGl0ZW0gY2xlYXIK
+ICBDbGVhciBhbGwgZGVmaW5lZCBtZWNoYW5pc21zLiAgVGhpcyBpcyB1c2VmdWwg
+dG8gb3ZlcnJpZGUKICBtZWNoYW5pc21zIGdpdmVuIGluIGEgY29uZmlnIGZpbGUu
+CgpAZW5kIHRhYmxlCgpAaXRlbSAtLWtleWlkLWZvcm1hdCBAY29kZXtzaG9ydHww
+eHNob3J0fGxvbmd8MHhsb25nfQpAb3BpbmRleCBrZXlpZC1mb3JtYXQKU2VsZWN0
+IGhvdyB0byBkaXNwbGF5IGtleSBJRHMuICJzaG9ydCIgaXMgdGhlIHRyYWRpdGlv
+bmFsIDgtY2hhcmFjdGVyCmtleSBJRC4gImxvbmciIGlzIHRoZSBtb3JlIGFjY3Vy
+YXRlIChidXQgbGVzcyBjb252ZW5pZW50KQoxNi1jaGFyYWN0ZXIga2V5IElELiBB
+ZGQgYW4gIjB4IiB0byBlaXRoZXIgdG8gaW5jbHVkZSBhbiAiMHgiIGF0IHRoZQpi
+ZWdpbm5pbmcgb2YgdGhlIGtleSBJRCwgYXMgaW4gMHg5OTI0MjU2MC4gIE5vdGUg
+dGhhdCB0aGlzIG9wdGlvbiBpcwppZ25vcmVkIGlmIHRoZSBvcHRpb24gLS13aXRo
+LWNvbG9ucyBpcyB1c2VkLgoKQGl0ZW0gLS1rZXlzZXJ2ZXIgQGNvZGV7bmFtZX0K
+QG9waW5kZXgga2V5c2VydmVyClRoaXMgb3B0aW9uIGlzIGRlcHJlY2F0ZWQgLSBw
+bGVhc2UgdXNlIHRoZSBAb3B0aW9uey0ta2V5c2VydmVyfSBpbgpAZmlsZXtkaXJt
+bmdyLmNvbmZ9IGluc3RlYWQuCgpVc2UgQGNvZGV7bmFtZX0gYXMgeW91ciBrZXlz
+ZXJ2ZXIuIFRoaXMgaXMgdGhlIHNlcnZlciB0aGF0CkBvcHRpb257LS1yZWN2LWtl
+eXN9LCBAb3B0aW9uey0tc2VuZC1rZXlzfSwgYW5kIEBvcHRpb257LS1zZWFyY2gt
+a2V5c30Kd2lsbCBjb21tdW5pY2F0ZSB3aXRoIHRvIHJlY2VpdmUga2V5cyBmcm9t
+LCBzZW5kIGtleXMgdG8sIGFuZCBzZWFyY2ggZm9yCmtleXMgb24uIFRoZSBmb3Jt
+YXQgb2YgdGhlIEBjb2Rle25hbWV9IGlzIGEgVVJJOgpgc2NoZW1lOlsvL11rZXlz
+ZXJ2ZXJuYW1lWzpwb3J0XScgVGhlIHNjaGVtZSBpcyB0aGUgdHlwZSBvZiBrZXlz
+ZXJ2ZXI6CiJoa3AiIGZvciB0aGUgSFRUUCAob3IgY29tcGF0aWJsZSkga2V5c2Vy
+dmVycywgImxkYXAiIGZvciB0aGUgTERBUAprZXlzZXJ2ZXJzLCBvciAibWFpbHRv
+IiBmb3IgdGhlIEdyYWZmIGVtYWlsIGtleXNlcnZlci4gTm90ZSB0aGF0IHlvdXIK
+cGFydGljdWxhciBpbnN0YWxsYXRpb24gb2YgR251UEcgbWF5IGhhdmUgb3RoZXIg
+a2V5c2VydmVyIHR5cGVzCmF2YWlsYWJsZSBhcyB3ZWxsLiBLZXlzZXJ2ZXIgc2No
+ZW1lcyBhcmUgY2FzZS1pbnNlbnNpdGl2ZS4gQWZ0ZXIgdGhlCmtleXNlcnZlciBu
+YW1lLCBvcHRpb25hbCBrZXlzZXJ2ZXIgY29uZmlndXJhdGlvbiBvcHRpb25zIG1h
+eSBiZQpwcm92aWRlZC4gVGhlc2UgYXJlIHRoZSBzYW1lIGFzIHRoZSBnbG9iYWwg
+QG9wdGlvbnstLWtleXNlcnZlci1vcHRpb25zfQpmcm9tIGJlbG93LCBidXQgYXBw
+bHkgb25seSB0byB0aGlzIHBhcnRpY3VsYXIga2V5c2VydmVyLgoKTW9zdCBrZXlz
+ZXJ2ZXJzIHN5bmNocm9uaXplIHdpdGggZWFjaCBvdGhlciwgc28gdGhlcmUgaXMg
+Z2VuZXJhbGx5IG5vCm5lZWQgdG8gc2VuZCBrZXlzIHRvIG1vcmUgdGhhbiBvbmUg
+c2VydmVyLiBUaGUga2V5c2VydmVyCkBjb2Rle2hrcDovL2tleXMuZ251cGcubmV0
+fSB1c2VzIHJvdW5kIHJvYmluIEROUyB0byBnaXZlIGEgZGlmZmVyZW50CmtleXNl
+cnZlciBlYWNoIHRpbWUgeW91IHVzZSBpdC4KCkBpdGVtIC0ta2V5c2VydmVyLW9w
+dGlvbnMgQGNvZGV7bmFtZT12YWx1ZX0KQG9waW5kZXgga2V5c2VydmVyLW9wdGlv
+bnMKVGhpcyBpcyBhIHNwYWNlIG9yIGNvbW1hIGRlbGltaXRlZCBzdHJpbmcgdGhh
+dCBnaXZlcyBvcHRpb25zIGZvciB0aGUKa2V5c2VydmVyLiBPcHRpb25zIGNhbiBi
+ZSBwcmVmaXhlZCB3aXRoIGEgYG5vLScgdG8gZ2l2ZSB0aGUgb3Bwb3NpdGUKbWVh
+bmluZy4gVmFsaWQgaW1wb3J0LW9wdGlvbnMgb3IgZXhwb3J0LW9wdGlvbnMgbWF5
+IGJlIHVzZWQgaGVyZSBhcwp3ZWxsIHRvIGFwcGx5IHRvIGltcG9ydGluZyAoQG9w
+dGlvbnstLXJlY3Yta2V5fSkgb3IgZXhwb3J0aW5nCihAb3B0aW9uey0tc2VuZC1r
+ZXl9KSBhIGtleSBmcm9tIGEga2V5c2VydmVyLiBXaGlsZSBub3QgYWxsIG9wdGlv
+bnMKYXJlIGF2YWlsYWJsZSBmb3IgYWxsIGtleXNlcnZlciB0eXBlcywgc29tZSBj
+b21tb24gb3B0aW9ucyBhcmU6CgpAdGFibGUgQGFzaXMKCiAgQGl0ZW0gaW5jbHVk
+ZS1yZXZva2VkCiAgV2hlbiBzZWFyY2hpbmcgZm9yIGEga2V5IHdpdGggQG9wdGlv
+bnstLXNlYXJjaC1rZXlzfSwgaW5jbHVkZSBrZXlzIHRoYXQKICBhcmUgbWFya2Vk
+IG9uIHRoZSBrZXlzZXJ2ZXIgYXMgcmV2b2tlZC4gTm90ZSB0aGF0IG5vdCBhbGwg
+a2V5c2VydmVycwogIGRpZmZlcmVudGlhdGUgYmV0d2VlbiByZXZva2VkIGFuZCB1
+bnJldm9rZWQga2V5cywgYW5kIGZvciBzdWNoCiAga2V5c2VydmVycyB0aGlzIG9w
+dGlvbiBpcyBtZWFuaW5nbGVzcy4gTm90ZSBhbHNvIHRoYXQgbW9zdCBrZXlzZXJ2
+ZXJzIGRvCiAgbm90IGhhdmUgY3J5cHRvZ3JhcGhpYyB2ZXJpZmljYXRpb24gb2Yg
+a2V5IHJldm9jYXRpb25zLCBhbmQgc28gdHVybmluZwogIHRoaXMgb3B0aW9uIG9m
+ZiBtYXkgcmVzdWx0IGluIHNraXBwaW5nIGtleXMgdGhhdCBhcmUgaW5jb3JyZWN0
+bHkgbWFya2VkCiAgYXMgcmV2b2tlZC4KCiAgQGl0ZW0gaW5jbHVkZS1kaXNhYmxl
+ZAogIFdoZW4gc2VhcmNoaW5nIGZvciBhIGtleSB3aXRoIEBvcHRpb257LS1zZWFy
+Y2gta2V5c30sIGluY2x1ZGUga2V5cyB0aGF0CiAgYXJlIG1hcmtlZCBvbiB0aGUg
+a2V5c2VydmVyIGFzIGRpc2FibGVkLiBOb3RlIHRoYXQgdGhpcyBvcHRpb24gaXMg
+bm90CiAgdXNlZCB3aXRoIEhLUCBrZXlzZXJ2ZXJzLgoKICBAaXRlbSBhdXRvLWtl
+eS1yZXRyaWV2ZQogIFRoaXMgb3B0aW9uIGVuYWJsZXMgdGhlIGF1dG9tYXRpYyBy
+ZXRyaWV2aW5nIG9mIGtleXMgZnJvbSBhIGtleXNlcnZlcgogIHdoZW4gdmVyaWZ5
+aW5nIHNpZ25hdHVyZXMgbWFkZSBieSBrZXlzIHRoYXQgYXJlIG5vdCBvbiB0aGUg
+bG9jYWwKICBrZXlyaW5nLgoKICBOb3RlIHRoYXQgdGhpcyBvcHRpb24gbWFrZXMg
+YSAid2ViIGJ1ZyIgbGlrZSBiZWhhdmlvciBwb3NzaWJsZS4KICBLZXlzZXJ2ZXIg
+b3BlcmF0b3JzIGNhbiBzZWUgd2hpY2gga2V5cyB5b3UgcmVxdWVzdCwgc28gYnkg
+c2VuZGluZyB5b3UKICBhIG1lc3NhZ2Ugc2lnbmVkIGJ5IGEgYnJhbmQgbmV3IGtl
+eSAod2hpY2ggeW91IG5hdHVyYWxseSB3aWxsIG5vdCBoYXZlCiAgb24geW91ciBs
+b2NhbCBrZXlyaW5nKSwgdGhlIG9wZXJhdG9yIGNhbiB0ZWxsIGJvdGggeW91ciBJ
+UCBhZGRyZXNzIGFuZAogIHRoZSB0aW1lIHdoZW4geW91IHZlcmlmaWVkIHRoZSBz
+aWduYXR1cmUuCgogIEBpdGVtIGhvbm9yLWtleXNlcnZlci11cmwKICBXaGVuIHVz
+aW5nIEBvcHRpb257LS1yZWZyZXNoLWtleXN9LCBpZiB0aGUga2V5IGluIHF1ZXN0
+aW9uIGhhcyBhIHByZWZlcnJlZAogIGtleXNlcnZlciBVUkwsIHRoZW4gdXNlIHRo
+YXQgcHJlZmVycmVkIGtleXNlcnZlciB0byByZWZyZXNoIHRoZSBrZXkKICBmcm9t
+LiBJbiBhZGRpdGlvbiwgaWYgYXV0by1rZXktcmV0cmlldmUgaXMgc2V0LCBhbmQg
+dGhlIHNpZ25hdHVyZQogIGJlaW5nIHZlcmlmaWVkIGhhcyBhIHByZWZlcnJlZCBr
+ZXlzZXJ2ZXIgVVJMLCB0aGVuIHVzZSB0aGF0IHByZWZlcnJlZAogIGtleXNlcnZl
+ciB0byBmZXRjaCB0aGUga2V5IGZyb20uIE5vdGUgdGhhdCB0aGlzIG9wdGlvbiBp
+bnRyb2R1Y2VzIGEKICAid2ViIGJ1ZyI6IFRoZSBjcmVhdG9yIG9mIHRoZSBrZXkg
+Y2FuIHNlZSB3aGVuIHRoZSBrZXlzIGlzCiAgcmVmcmVzaGVkLiAgVGh1cyB0aGlz
+IG9wdGlvbiBpcyBub3QgZW5hYmxlZCBieSBkZWZhdWx0LgoKICBAaXRlbSBob25v
+ci1wa2EtcmVjb3JkCiAgSWYgYXV0by1rZXktcmV0cmlldmUgaXMgc2V0LCBhbmQg
+dGhlIHNpZ25hdHVyZSBiZWluZyB2ZXJpZmllZCBoYXMgYQogIFBLQSByZWNvcmQs
+IHRoZW4gdXNlIHRoZSBQS0EgaW5mb3JtYXRpb24gdG8gZmV0Y2ggdGhlIGtleS4g
+RGVmYXVsdHMKICB0byAieWVzIi4KCiAgQGl0ZW0gaW5jbHVkZS1zdWJrZXlzCiAg
+V2hlbiByZWNlaXZpbmcgYSBrZXksIGluY2x1ZGUgc3Via2V5cyBhcyBwb3RlbnRp
+YWwgdGFyZ2V0cy4gTm90ZSB0aGF0CiAgdGhpcyBvcHRpb24gaXMgbm90IHVzZWQg
+d2l0aCBIS1Aga2V5c2VydmVycywgYXMgdGhleSBkbyBub3Qgc3VwcG9ydAogIHJl
+dHJpZXZpbmcga2V5cyBieSBzdWJrZXkgaWQuCgogIEBpdGVtIHRpbWVvdXQKICBU
+ZWxsIHRoZSBrZXlzZXJ2ZXIgaGVscGVyIHByb2dyYW0gaG93IGxvbmcgKGluIHNl
+Y29uZHMpIHRvIHRyeSBhbmQKICBwZXJmb3JtIGEga2V5c2VydmVyIGFjdGlvbiBi
+ZWZvcmUgZ2l2aW5nIHVwLiBOb3RlIHRoYXQgcGVyZm9ybWluZwogIG11bHRpcGxl
+IGFjdGlvbnMgYXQgdGhlIHNhbWUgdGltZSB1c2VzIHRoaXMgdGltZW91dCB2YWx1
+ZSBwZXIgYWN0aW9uLgogIEZvciBleGFtcGxlLCB3aGVuIHJldHJpZXZpbmcgbXVs
+dGlwbGUga2V5cyB2aWEgQG9wdGlvbnstLXJlY3Yta2V5c30sIHRoZQogIHRpbWVv
+dXQgYXBwbGllcyBzZXBhcmF0ZWx5IHRvIGVhY2gga2V5IHJldHJpZXZhbCwgYW5k
+IG5vdCB0byB0aGUKICBAb3B0aW9uey0tcmVjdi1rZXlzfSBjb21tYW5kIGFzIGEg
+d2hvbGUuIERlZmF1bHRzIHRvIDMwIHNlY29uZHMuCgogIEBpdGVtIGh0dHAtcHJv
+eHk9QGNvZGV7dmFsdWV9CiAgVGhpcyBvcHRpb25zIGlzIGRlcHJlY2F0ZWQuCiAg
+U2V0IHRoZSBwcm94eSB0byB1c2UgZm9yIEhUVFAgYW5kIEhLUCBrZXlzZXJ2ZXJz
+LgogIFRoaXMgb3ZlcnJpZGVzIGFueSBwcm94eSBkZWZpbmVkIGluIEBmaWxle2Rp
+cm1uZ3IuY29uZn0uCgogIEBpdGVtIHZlcmJvc2UKICBUaGlzIG9wdGlvbiBoYXMg
+bm8gbW9yZSBmdW5jdGlvbiBzaW5jZSBHbnVQRyAyLjEuICBVc2UgdGhlCiAgQGNv
+ZGV7ZGlybW5ncn0gY29uZmlndXJhdGlvbiBvcHRpb25zIGluc3RlYWQuCgogIEBp
+dGVtIGRlYnVnCiAgVGhpcyBvcHRpb24gaGFzIG5vIG1vcmUgZnVuY3Rpb24gc2lu
+Y2UgR251UEcgMi4xLiAgVXNlIHRoZQogIEBjb2Rle2Rpcm1uZ3J9IGNvbmZpZ3Vy
+YXRpb24gb3B0aW9ucyBpbnN0ZWFkLgoKICBAaXRlbSBjaGVjay1jZXJ0CiAgVGhp
+cyBvcHRpb24gaGFzIG5vIG1vcmUgZnVuY3Rpb24gc2luY2UgR251UEcgMi4xLiAg
+VXNlIHRoZQogIEBjb2Rle2Rpcm1uZ3J9IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBp
+bnN0ZWFkLgoKICBAaXRlbSBjYS1jZXJ0LWZpbGUKICBUaGlzIG9wdGlvbiBoYXMg
+bm8gbW9yZSBmdW5jdGlvbiBzaW5jZSBHbnVQRyAyLjEuICBVc2UgdGhlCiAgQGNv
+ZGV7ZGlybW5ncn0gY29uZmlndXJhdGlvbiBvcHRpb25zIGluc3RlYWQuCgpAZW5k
+IHRhYmxlCgpAaXRlbSAtLWNvbXBsZXRlcy1uZWVkZWQgQGNvZGV7bn0KQG9waW5k
+ZXggY29tcGxpYW50LW5lZWRlZApOdW1iZXIgb2YgY29tcGxldGVseSB0cnVzdGVk
+IHVzZXJzIHRvIGludHJvZHVjZSBhIG5ldwprZXkgc2lnbmVyIChkZWZhdWx0cyB0
+byAxKS4KCkBpdGVtIC0tbWFyZ2luYWxzLW5lZWRlZCBAY29kZXtufQpAb3BpbmRl
+eCBtYXJnaW5hbHMtbmVlZGVkCk51bWJlciBvZiBtYXJnaW5hbGx5IHRydXN0ZWQg
+dXNlcnMgdG8gaW50cm9kdWNlIGEgbmV3CmtleSBzaWduZXIgKGRlZmF1bHRzIHRv
+IDMpCgpAaXRlbSAtLXRvZnUtZGVmYXVsdC1wb2xpY3kgQGNvZGV7YXV0b3xnb29k
+fHVua25vd258YmFkfGFza30KQG9waW5kZXggdG9mdS1kZWZhdWx0LXBvbGljeQpU
+aGUgZGVmYXVsdCBUT0ZVIHBvbGljeSAoZGVmYXVsdHMgdG8gQGNvZGV7YXV0b30p
+LiAgRm9yIG1vcmUKaW5mb3JtYXRpb24gYWJvdXQgdGhlIG1lYW5pbmcgb2YgdGhp
+cyBvcHRpb24sIEB4cmVme3RydXN0LW1vZGVsLXRvZnV9LgoKQGl0ZW0gLS10b2Z1
+LWRiLWZvcm1hdCBAY29kZXthdXRvfHNwbGl0fGZsYXR9CkBvcGluZGV4IHRvZnUt
+ZGVmYXVsdC1wb2xpY3kKVGhlIGZvcm1hdCBmb3IgdGhlIFRPRlUgREIuCgpUaGUg
+c3BsaXQgZmlsZSBmb3JtYXQgc3BsaXRzIHRoZSBkYXRhIGFjcm9zcyBtYW55IERC
+cyB1bmRlciB0aGUKQGNvZGV7dG9mdS5kfSBkaXJlY3RvcnkgKG9uZSBwZXIgZW1h
+aWwgYWRkcmVzcyBhbmQgb25lIHBlciBrZXkpLiAgVGhpcwptYWtlcyBpdCBlYXNp
+ZXIgdG8gYXV0b21hdGljYWxseSBzeW5jaHJvbml6ZSB0aGUgZGF0YSB1c2luZyBh
+IHRvb2wKc3VjaCBhcyBVbmlzb24gKEB1cmx7aHR0cHM6Ly93d3cuY2lzLnVwZW5u
+LmVkdS9+YmNwaWVyY2UvdW5pc29uL30pLApzaW5jZSB0aGUgaW5kaXZpZHVhbCBm
+aWxlcyBjaGFuZ2UgcmFyZWx5LgoKVGhlIGZsYXQgZmlsZSBmb3JtYXQga2VlcHMg
+YWxsIG9mIHRoZSBkYXRhIGluIHRoZSBzaW5nbGUgZmlsZQpAY29kZXt0b2Z1LmRi
+fS4gIFRoaXMgZm9ybWF0IHJlc3VsdHMgaW4gYmV0dGVyIHBlcmZvcm1hbmNlLgoK
+SWYgc2V0IHRvIGF1dG8gKHdoaWNoIGlzIHRoZSBkZWZhdWx0KSwgR251UEcgd2ls
+bCBmaXJzdCBjaGVjayBmb3IgdGhlCmV4aXN0ZW5jZSBvZiBAY29kZXt0b2Z1LmR9
+IGFuZCBAY29kZXt0b2Z1LmRifS4gIElmIG9uZSBvZiB0aGVzZQpleGlzdHMsIHRo
+ZSBjb3JyZXNwb25kaW5nIGZvcm1hdCBpcyB1c2VkLiAgSWYgbmVpdGhlciBvciBi
+b3RoIG9mIHRoZXNlCmV4aXN0LCB0aGVuIEdudVBHIGRlZmF1bHRzIHRvIHRoZSBA
+Y29kZXtzcGxpdH0gZm9ybWF0LiAgSW4gdGhlIGxhdHRlcgpjYXNlLCBhIHdhcm5p
+bmcgaXMgZW1pdHRlZC4KCkBpdGVtIC0tbWF4LWNlcnQtZGVwdGggQGNvZGV7bn0K
+QG9waW5kZXggbWF4LWNlcnQtZGVwdGgKTWF4aW11bSBkZXB0aCBvZiBhIGNlcnRp
+ZmljYXRpb24gY2hhaW4gKGRlZmF1bHQgaXMgNSkuCgpAaXRlbSAtLW5vLXNpZy1j
+YWNoZQpAb3BpbmRleCBuby1zaWctY2FjaGUKRG8gbm90IGNhY2hlIHRoZSB2ZXJp
+ZmljYXRpb24gc3RhdHVzIG9mIGtleSBzaWduYXR1cmVzLgpDYWNoaW5nIGdpdmVz
+IGEgbXVjaCBiZXR0ZXIgcGVyZm9ybWFuY2UgaW4ga2V5IGxpc3RpbmdzLiBIb3dl
+dmVyLCBpZgp5b3Ugc3VzcGVjdCB0aGF0IHlvdXIgcHVibGljIGtleXJpbmcgaXMg
+bm90IHNhdmUgYWdhaW5zdCB3cml0ZQptb2RpZmljYXRpb25zLCB5b3UgY2FuIHVz
+ZSB0aGlzIG9wdGlvbiB0byBkaXNhYmxlIHRoZSBjYWNoaW5nLiBJdApwcm9iYWJs
+eSBkb2VzIG5vdCBtYWtlIHNlbnNlIHRvIGRpc2FibGUgaXQgYmVjYXVzZSBhbGwg
+a2luZCBvZiBkYW1hZ2UKY2FuIGJlIGRvbmUgaWYgc29tZW9uZSBlbHNlIGhhcyB3
+cml0ZSBhY2Nlc3MgdG8geW91ciBwdWJsaWMga2V5cmluZy4KCkBpdGVtIC0tYXV0
+by1jaGVjay10cnVzdGRiCkBpdGVteCAtLW5vLWF1dG8tY2hlY2stdHJ1c3RkYgpA
+b3BpbmRleCBhdXRvLWNoZWNrLXRydXN0ZGIKSWYgR251UEcgZmVlbHMgdGhhdCBp
+dHMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIFdlYiBvZiBUcnVzdCBoYXMgdG8gYmUK
+dXBkYXRlZCwgaXQgYXV0b21hdGljYWxseSBydW5zIHRoZSBAb3B0aW9uey0tY2hl
+Y2stdHJ1c3RkYn0gY29tbWFuZAppbnRlcm5hbGx5LiAgVGhpcyBtYXkgYmUgYSB0
+aW1lIGNvbnN1bWluZwpwcm9jZXNzLiBAb3B0aW9uey0tbm8tYXV0by1jaGVjay10
+cnVzdGRifSBkaXNhYmxlcyB0aGlzIG9wdGlvbi4KCkBpdGVtIC0tdXNlLWFnZW50
+CkBpdGVteCAtLW5vLXVzZS1hZ2VudApAb3BpbmRleCB1c2UtYWdlbnQKVGhpcyBp
+cyBkdW1teSBvcHRpb24uIEBjb21tYW5ke0BncGduYW1lfSBhbHdheXMgcmVxdWly
+ZXMgdGhlIGFnZW50LgoKQGl0ZW0gLS1ncGctYWdlbnQtaW5mbwpAb3BpbmRleCBn
+cGctYWdlbnQtaW5mbwpUaGlzIGlzIGR1bW15IG9wdGlvbi4gSXQgaGFzIG5vIGVm
+ZmVjdCB3aGVuIHVzZWQgd2l0aCBAY29tbWFuZHtncGcyfS4KCgpAaXRlbSAtLWFn
+ZW50LXByb2dyYW0gQHZhcntmaWxlfQpAb3BpbmRleCBhZ2VudC1wcm9ncmFtClNw
+ZWNpZnkgYW4gYWdlbnQgcHJvZ3JhbSB0byBiZSB1c2VkIGZvciBzZWNyZXQga2V5
+IG9wZXJhdGlvbnMuICBUaGUKZGVmYXVsdCB2YWx1ZSBpcyBkZXRlcm1pbmVkIGJ5
+IHJ1bm5pbmcgQGNvbW1hbmR7Z3BnY29uZn0gd2l0aCB0aGUKb3B0aW9uIEBvcHRp
+b257LS1saXN0LWRpcnN9LiAgTm90ZSB0aGF0IHRoZSBwaXBlIHN5bWJvbCAoQGNv
+ZGV7fH0pIGlzCnVzZWQgZm9yIGEgcmVncmVzc2lvbiB0ZXN0IHN1aXRlIGhhY2sg
+YW5kIG1heSB0aHVzIG5vdCBiZSB1c2VkIGluIHRoZQpmaWxlIG5hbWUuCgpAaXRl
+bSAtLWRpcm1uZ3ItcHJvZ3JhbSBAdmFye2ZpbGV9CkBvcGluZGV4IGRpcm1uZ3It
+cHJvZ3JhbQpTcGVjaWZ5IGEgZGlybW5nciBwcm9ncmFtIHRvIGJlIHVzZWQgZm9y
+IGtleXNlcnZlciBhY2Nlc3MuICBUaGUKZGVmYXVsdCB2YWx1ZSBpcyBAZmlsZXtA
+dmFsdWV7QklORElSfS9kaXJtbmdyfS4gIFRoaXMgaXMgb25seSB1c2VkIGFzIGEK
+ZmFsbGJhY2sgd2hlbiB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGUgQGNvZGV7RElS
+TU5HUl9JTkZPfSBpcyBub3Qgc2V0IG9yCmEgcnVubmluZyBkaXJtbmdyIGNhbm5v
+dCBiZSBjb25uZWN0ZWQuCgpAaXRlbSAtLW5vLWF1dG9zdGFydApAb3BpbmRleCBu
+by1hdXRvc3RhcnQKRG8gbm90IHN0YXJ0IHRoZSBncGctYWdlbnQgb3IgdGhlIGRp
+cm1uZ3IgaWYgaXQgaGFzIG5vdCB5ZXQgYmVlbgpzdGFydGVkIGFuZCBpdHMgc2Vy
+dmljZSBpcyByZXF1aXJlZC4gIFRoaXMgb3B0aW9uIGlzIG1vc3RseSB1c2VmdWwg
+b24KbWFjaGluZXMgd2hlcmUgdGhlIGNvbm5lY3Rpb24gdG8gZ3BnLWFnZW50IGhh
+cyBiZWVuIHJlZGlyZWN0ZWQgdG8KYW5vdGhlciBtYWNoaW5lcy4gIElmIGRpcm1u
+Z3IgaXMgcmVxdWlyZWQgb24gdGhlIHJlbW90ZSBtYWNoaW5lLCBpdAptYXkgYmUg
+c3RhcnRlZCBtYW51YWxseSB1c2luZyBAY29tbWFuZHtncGdjb25mIC0tbGF1bmNo
+IGRpcm1uZ3J9LgoKQGl0ZW0gLS1sb2NrLW9uY2UKQG9waW5kZXggbG9jay1vbmNl
+CkxvY2sgdGhlIGRhdGFiYXNlcyB0aGUgZmlyc3QgdGltZSBhIGxvY2sgaXMgcmVx
+dWVzdGVkCmFuZCBkbyBub3QgcmVsZWFzZSB0aGUgbG9jayB1bnRpbCB0aGUgcHJv
+Y2Vzcwp0ZXJtaW5hdGVzLgoKQGl0ZW0gLS1sb2NrLW11bHRpcGxlCkBvcGluZGV4
+IGxvY2stbXVsdGlwbGUKUmVsZWFzZSB0aGUgbG9ja3MgZXZlcnkgdGltZSBhIGxv
+Y2sgaXMgbm8gbG9uZ2VyCm5lZWRlZC4gVXNlIHRoaXMgdG8gb3ZlcnJpZGUgYSBw
+cmV2aW91cyBAb3B0aW9uey0tbG9jay1vbmNlfQpmcm9tIGEgY29uZmlnIGZpbGUu
+CgpAaXRlbSAtLWxvY2stbmV2ZXIKQG9waW5kZXggbG9jay1uZXZlcgpEaXNhYmxl
+IGxvY2tpbmcgZW50aXJlbHkuIFRoaXMgb3B0aW9uIHNob3VsZCBiZSB1c2VkIG9u
+bHkgaW4gdmVyeQpzcGVjaWFsIGVudmlyb25tZW50cywgd2hlcmUgaXQgY2FuIGJl
+IGFzc3VyZWQgdGhhdCBvbmx5IG9uZSBwcm9jZXNzCmlzIGFjY2Vzc2luZyB0aG9z
+ZSBmaWxlcy4gQSBib290YWJsZSBmbG9wcHkgd2l0aCBhIHN0YW5kLWFsb25lCmVu
+Y3J5cHRpb24gc3lzdGVtIHdpbGwgcHJvYmFibHkgdXNlIHRoaXMuIEltcHJvcGVy
+IHVzYWdlIG9mIHRoaXMKb3B0aW9uIG1heSBsZWFkIHRvIGRhdGEgYW5kIGtleSBj
+b3JydXB0aW9uLgoKQGl0ZW0gLS1leGl0LW9uLXN0YXR1cy13cml0ZS1lcnJvcgpA
+b3BpbmRleCBleGl0LW9uLXN0YXR1cy13cml0ZS1lcnJvcgpUaGlzIG9wdGlvbiB3
+aWxsIGNhdXNlIHdyaXRlIGVycm9ycyBvbiB0aGUgc3RhdHVzIEZEIHRvIGltbWVk
+aWF0ZWx5CnRlcm1pbmF0ZSB0aGUgcHJvY2Vzcy4gVGhhdCBzaG91bGQgaW4gZmFj
+dCBiZSB0aGUgZGVmYXVsdCBidXQgaXQgbmV2ZXIKd29ya2VkIHRoaXMgd2F5IGFu
+ZCB0aHVzIHdlIG5lZWQgYW4gb3B0aW9uIHRvIGVuYWJsZSB0aGlzLCBzbyB0aGF0
+IHRoZQpjaGFuZ2Ugd29uJ3QgYnJlYWsgYXBwbGljYXRpb25zIHdoaWNoIGNsb3Nl
+IHRoZWlyIGVuZCBvZiBhIHN0YXR1cyBmZApjb25uZWN0ZWQgcGlwZSB0b28gZWFy
+bHkuIFVzaW5nIHRoaXMgb3B0aW9uIGFsb25nIHdpdGgKQG9wdGlvbnstLWVuYWJs
+ZS1wcm9ncmVzcy1maWx0ZXJ9IG1heSBiZSB1c2VkIHRvIGNsZWFubHkgY2FuY2Vs
+IGxvbmcKcnVubmluZyBncGcgb3BlcmF0aW9ucy4KCkBpdGVtIC0tbGltaXQtY2Fy
+ZC1pbnNlcnQtdHJpZXMgQGNvZGV7bn0KQG9waW5kZXggbGltaXQtY2FyZC1pbnNl
+cnQtdHJpZXMKV2l0aCBAY29kZXtufSBncmVhdGVyIHRoYW4gMCB0aGUgbnVtYmVy
+IG9mIHByb21wdHMgYXNraW5nIHRvIGluc2VydCBhCnNtYXJ0Y2FyZCBnZXRzIGxp
+bWl0ZWQgdG8gTi0xLiBUaHVzIHdpdGggYSB2YWx1ZSBvZiAxIGdwZyB3b24ndCBh
+dAphbGwgYXNrIHRvIGluc2VydCBhIGNhcmQgaWYgbm9uZSBoYXMgYmVlbiBpbnNl
+cnRlZCBhdCBzdGFydHVwLiBUaGlzCm9wdGlvbiBpcyB1c2VmdWwgaW4gdGhlIGNv
+bmZpZ3VyYXRpb24gZmlsZSBpbiBjYXNlIGFuIGFwcGxpY2F0aW9uIGRvZXMKbm90
+IGtub3cgYWJvdXQgdGhlIHNtYXJ0Y2FyZCBzdXBwb3J0IGFuZCB3YWl0cyBhZCBp
+bmZpbml0dW0gZm9yIGFuCmluc2VydGVkIGNhcmQuCgpAaXRlbSAtLW5vLXJhbmRv
+bS1zZWVkLWZpbGUKQG9waW5kZXggbm8tcmFuZG9tLXNlZWQtZmlsZQpHbnVQRyB1
+c2VzIGEgZmlsZSB0byBzdG9yZSBpdHMgaW50ZXJuYWwgcmFuZG9tIHBvb2wgb3Zl
+ciBpbnZvY2F0aW9ucy4KVGhpcyBtYWtlcyByYW5kb20gZ2VuZXJhdGlvbiBmYXN0
+ZXI7IGhvd2V2ZXIgc29tZXRpbWVzIHdyaXRlIG9wZXJhdGlvbnMKYXJlIG5vdCBk
+ZXNpcmVkLiBUaGlzIG9wdGlvbiBjYW4gYmUgdXNlZCB0byBhY2hpZXZlIHRoYXQg
+d2l0aCB0aGUgY29zdCBvZgpzbG93ZXIgcmFuZG9tIGdlbmVyYXRpb24uCgpAaXRl
+bSAtLW5vLWdyZWV0aW5nCkBvcGluZGV4IG5vLWdyZWV0aW5nClN1cHByZXNzIHRo
+ZSBpbml0aWFsIGNvcHlyaWdodCBtZXNzYWdlLgoKQGl0ZW0gLS1uby1zZWNtZW0t
+d2FybmluZwpAb3BpbmRleCBuby1zZWNtZW0td2FybmluZwpTdXBwcmVzcyB0aGUg
+d2FybmluZyBhYm91dCAidXNpbmcgaW5zZWN1cmUgbWVtb3J5Ii4KCkBpdGVtIC0t
+bm8tcGVybWlzc2lvbi13YXJuaW5nCkBvcGluZGV4IHBlcm1pc3Npb24td2Fybmlu
+ZwpTdXBwcmVzcyB0aGUgd2FybmluZyBhYm91dCB1bnNhZmUgZmlsZSBhbmQgaG9t
+ZSBkaXJlY3RvcnkgKEBvcHRpb257LS1ob21lZGlyfSkKcGVybWlzc2lvbnMuIE5v
+dGUgdGhhdCB0aGUgcGVybWlzc2lvbiBjaGVja3MgdGhhdCBHbnVQRyBwZXJmb3Jt
+cyBhcmUKbm90IGludGVuZGVkIHRvIGJlIGF1dGhvcml0YXRpdmUsIGJ1dCByYXRo
+ZXIgdGhleSBzaW1wbHkgd2FybiBhYm91dApjZXJ0YWluIGNvbW1vbiBwZXJtaXNz
+aW9uIHByb2JsZW1zLiBEbyBub3QgYXNzdW1lIHRoYXQgdGhlIGxhY2sgb2YgYQp3
+YXJuaW5nIG1lYW5zIHRoYXQgeW91ciBzeXN0ZW0gaXMgc2VjdXJlLgoKTm90ZSB0
+aGF0IHRoZSB3YXJuaW5nIGZvciB1bnNhZmUgQG9wdGlvbnstLWhvbWVkaXJ9IHBl
+cm1pc3Npb25zIGNhbm5vdCBiZQpzdXBwcmVzc2VkIGluIHRoZSBncGcuY29uZiBm
+aWxlLCBhcyB0aGlzIHdvdWxkIGFsbG93IGFuIGF0dGFja2VyIHRvCnBsYWNlIGFu
+IHVuc2FmZSBncGcuY29uZiBmaWxlIGluIHBsYWNlLCBhbmQgdXNlIHRoaXMgZmls
+ZSB0byBzdXBwcmVzcwp3YXJuaW5ncyBhYm91dCBpdHNlbGYuIFRoZSBAb3B0aW9u
+ey0taG9tZWRpcn0gcGVybWlzc2lvbnMgd2FybmluZyBtYXkgb25seSBiZQpzdXBw
+cmVzc2VkIG9uIHRoZSBjb21tYW5kIGxpbmUuCgpAaXRlbSAtLW5vLW1kYy13YXJu
+aW5nCkBvcGluZGV4IG5vLW1kYy13YXJuaW5nClN1cHByZXNzIHRoZSB3YXJuaW5n
+IGFib3V0IG1pc3NpbmcgTURDIGludGVncml0eSBwcm90ZWN0aW9uLgoKQGl0ZW0g
+LS1yZXF1aXJlLXNlY21lbQpAaXRlbXggLS1uby1yZXF1aXJlLXNlY21lbQpAb3Bp
+bmRleCByZXF1aXJlLXNlY21lbQpSZWZ1c2UgdG8gcnVuIGlmIEdudVBHIGNhbm5v
+dCBnZXQgc2VjdXJlIG1lbW9yeS4gRGVmYXVsdHMgdG8gbm8KKGkuZS4gcnVuLCBi
+dXQgZ2l2ZSBhIHdhcm5pbmcpLgoKCkBpdGVtIC0tcmVxdWlyZS1jcm9zcy1jZXJ0
+aWZpY2F0aW9uCkBpdGVteCAtLW5vLXJlcXVpcmUtY3Jvc3MtY2VydGlmaWNhdGlv
+bgpAb3BpbmRleCByZXF1aXJlLWNyb3NzLWNlcnRpZmljYXRpb24KV2hlbiB2ZXJp
+ZnlpbmcgYSBzaWduYXR1cmUgbWFkZSBmcm9tIGEgc3Via2V5LCBlbnN1cmUgdGhh
+dCB0aGUgY3Jvc3MKY2VydGlmaWNhdGlvbiAiYmFjayBzaWduYXR1cmUiIG9uIHRo
+ZSBzdWJrZXkgaXMgcHJlc2VudCBhbmQgdmFsaWQuICBUaGlzCnByb3RlY3RzIGFn
+YWluc3QgYSBzdWJ0bGUgYXR0YWNrIGFnYWluc3Qgc3Via2V5cyB0aGF0IGNhbiBz
+aWduLgpEZWZhdWx0cyB0byBAb3B0aW9uey0tcmVxdWlyZS1jcm9zcy1jZXJ0aWZp
+Y2F0aW9ufSBmb3IKQGNvbW1hbmR7QGdwZ25hbWV9LgoKQGl0ZW0gLS1leHBlcnQK
+QGl0ZW14IC0tbm8tZXhwZXJ0CkBvcGluZGV4IGV4cGVydApBbGxvdyB0aGUgdXNl
+ciB0byBkbyBjZXJ0YWluIG5vbnNlbnNpY2FsIG9yICJzaWxseSIgdGhpbmdzIGxp
+a2UKc2lnbmluZyBhbiBleHBpcmVkIG9yIHJldm9rZWQga2V5LCBvciBjZXJ0YWlu
+IHBvdGVudGlhbGx5IGluY29tcGF0aWJsZQp0aGluZ3MgbGlrZSBnZW5lcmF0aW5n
+IHVudXN1YWwga2V5IHR5cGVzLiBUaGlzIGFsc28gZGlzYWJsZXMgY2VydGFpbgp3
+YXJuaW5nIG1lc3NhZ2VzIGFib3V0IHBvdGVudGlhbGx5IGluY29tcGF0aWJsZSBh
+Y3Rpb25zLiBBcyB0aGUgbmFtZQppbXBsaWVzLCB0aGlzIG9wdGlvbiBpcyBmb3Ig
+ZXhwZXJ0cyBvbmx5LiBJZiB5b3UgZG9uJ3QgZnVsbHkKdW5kZXJzdGFuZCB0aGUg
+aW1wbGljYXRpb25zIG9mIHdoYXQgaXQgYWxsb3dzIHlvdSB0byBkbywgbGVhdmUg
+dGhpcwpvZmYuIEBvcHRpb257LS1uby1leHBlcnR9IGRpc2FibGVzIHRoaXMgb3B0
+aW9uLgoKQGVuZCB0YWJsZQoKCkBjICoqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioKQGMgKioqKioqKiogIEtFWSBSRUxBVEVEIE9QVElP
+TlMgICoqKioqKioqKioqKgpAYyAqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqCkBub2RlIEdQRyBLZXkgcmVsYXRlZCBPcHRpb25zCkBz
+dWJzZWN0aW9uIEtleSByZWxhdGVkIG9wdGlvbnMKCkB0YWJsZSBAZ251cGd0YWJv
+cHQKCkBpdGVtIC0tcmVjaXBpZW50IEB2YXJ7bmFtZX0KQGl0ZW14IC1yCkBvcGlu
+ZGV4IHJlY2lwaWVudApFbmNyeXB0IGZvciB1c2VyIGlkIEB2YXJ7bmFtZX0uIElm
+IHRoaXMgb3B0aW9uIG9yCkBvcHRpb257LS1oaWRkZW4tcmVjaXBpZW50fSBpcyBu
+b3Qgc3BlY2lmaWVkLCBHbnVQRyBhc2tzIGZvciB0aGUgdXNlci1pZAp1bmxlc3Mg
+QG9wdGlvbnstLWRlZmF1bHQtcmVjaXBpZW50fSBpcyBnaXZlbi4KCkBpdGVtIC0t
+aGlkZGVuLXJlY2lwaWVudCBAdmFye25hbWV9CkBpdGVteCAtUgpAb3BpbmRleCBo
+aWRkZW4tcmVjaXBpZW50CkVuY3J5cHQgZm9yIHVzZXIgSUQgQHZhcntuYW1lfSwg
+YnV0IGhpZGUgdGhlIGtleSBJRCBvZiB0aGlzIHVzZXIncwprZXkuIFRoaXMgb3B0
+aW9uIGhlbHBzIHRvIGhpZGUgdGhlIHJlY2VpdmVyIG9mIHRoZSBtZXNzYWdlIGFu
+ZCBpcyBhCmxpbWl0ZWQgY291bnRlcm1lYXN1cmUgYWdhaW5zdCB0cmFmZmljIGFu
+YWx5c2lzLiBJZiB0aGlzIG9wdGlvbiBvcgpAb3B0aW9uey0tcmVjaXBpZW50fSBp
+cyBub3Qgc3BlY2lmaWVkLCBHbnVQRyBhc2tzIGZvciB0aGUgdXNlciBJRCB1bmxl
+c3MKQG9wdGlvbnstLWRlZmF1bHQtcmVjaXBpZW50fSBpcyBnaXZlbi4KCkBpdGVt
+IC0tZW5jcnlwdC10byBAY29kZXtuYW1lfQpAb3BpbmRleCBlbmNyeXB0LXRvClNh
+bWUgYXMgQG9wdGlvbnstLXJlY2lwaWVudH0gYnV0IHRoaXMgb25lIGlzIGludGVu
+ZGVkIGZvciB1c2UgaW4gdGhlCm9wdGlvbnMgZmlsZSBhbmQgbWF5IGJlIHVzZWQg
+d2l0aCB5b3VyIG93biB1c2VyLWlkIGFzIGFuCiJlbmNyeXB0LXRvLXNlbGYiLiBU
+aGVzZSBrZXlzIGFyZSBvbmx5IHVzZWQgd2hlbiB0aGVyZSBhcmUgb3RoZXIKcmVj
+aXBpZW50cyBnaXZlbiBlaXRoZXIgYnkgdXNlIG9mIEBvcHRpb257LS1yZWNpcGll
+bnR9IG9yIGJ5IHRoZSBhc2tlZAp1c2VyIGlkLiAgTm8gdHJ1c3QgY2hlY2tpbmcg
+aXMgcGVyZm9ybWVkIGZvciB0aGVzZSB1c2VyIGlkcyBhbmQgZXZlbgpkaXNhYmxl
+ZCBrZXlzIGNhbiBiZSB1c2VkLgoKQGl0ZW0gLS1oaWRkZW4tZW5jcnlwdC10byBA
+Y29kZXtuYW1lfQpAb3BpbmRleCBoaWRkZW4tZW5jcnlwdC10bwpTYW1lIGFzIEBv
+cHRpb257LS1oaWRkZW4tcmVjaXBpZW50fSBidXQgdGhpcyBvbmUgaXMgaW50ZW5k
+ZWQgZm9yIHVzZSBpbiB0aGUKb3B0aW9ucyBmaWxlIGFuZCBtYXkgYmUgdXNlZCB3
+aXRoIHlvdXIgb3duIHVzZXItaWQgYXMgYSBoaWRkZW4KImVuY3J5cHQtdG8tc2Vs
+ZiIuIFRoZXNlIGtleXMgYXJlIG9ubHkgdXNlZCB3aGVuIHRoZXJlIGFyZSBvdGhl
+cgpyZWNpcGllbnRzIGdpdmVuIGVpdGhlciBieSB1c2Ugb2YgQG9wdGlvbnstLXJl
+Y2lwaWVudH0gb3IgYnkgdGhlIGFza2VkIHVzZXIgaWQuCk5vIHRydXN0IGNoZWNr
+aW5nIGlzIHBlcmZvcm1lZCBmb3IgdGhlc2UgdXNlciBpZHMgYW5kIGV2ZW4gZGlz
+YWJsZWQKa2V5cyBjYW4gYmUgdXNlZC4KCkBpdGVtIC0tZW5jcnlwdC10by1kZWZh
+dWx0LWtleQpAb3BpbmRleCBlbmNyeXB0LXRvLWRlZmF1bHQta2V5CklmIHRoZSBk
+ZWZhdWx0IHNlY3JldCBrZXkgaXMgdGFrZW4gZnJvbSBAb3B0aW9uey0tZGVmYXVs
+dC1rZXl9LCB0aGVuCmFsc28gZW5jcnlwdCB0byB0aGF0IGtleS4KCkBpdGVtIC0t
+bm8tZW5jcnlwdC10bwpAb3BpbmRleCBuby1lbmNyeXB0LXRvCkRpc2FibGUgdGhl
+IHVzZSBvZiBhbGwgQG9wdGlvbnstLWVuY3J5cHQtdG99IGFuZApAb3B0aW9uey0t
+aGlkZGVuLWVuY3J5cHQtdG99IGtleXMuCgpAaXRlbSAtLWdyb3VwIEBjb2Rle25h
+bWU9dmFsdWUxIH0KQG9waW5kZXggZ3JvdXAKU2V0cyB1cCBhIG5hbWVkIGdyb3Vw
+LCB3aGljaCBpcyBzaW1pbGFyIHRvIGFsaWFzZXMgaW4gZW1haWwgcHJvZ3JhbXMu
+CkFueSB0aW1lIHRoZSBncm91cCBuYW1lIGlzIGEgcmVjaXBpZW50IChAb3B0aW9u
+ey1yfSBvcgpAb3B0aW9uey0tcmVjaXBpZW50fSksIGl0IHdpbGwgYmUgZXhwYW5k
+ZWQgdG8gdGhlIHZhbHVlcwpzcGVjaWZpZWQuIE11bHRpcGxlIGdyb3VwcyB3aXRo
+IHRoZSBzYW1lIG5hbWUgYXJlIGF1dG9tYXRpY2FsbHkgbWVyZ2VkCmludG8gYSBz
+aW5nbGUgZ3JvdXAuCgpUaGUgdmFsdWVzIGFyZSBAY29kZXtrZXkgSURzfSBvciBm
+aW5nZXJwcmludHMsIGJ1dCBhbnkga2V5IGRlc2NyaXB0aW9uCmlzIGFjY2VwdGVk
+LiBOb3RlIHRoYXQgYSB2YWx1ZSB3aXRoIHNwYWNlcyBpbiBpdCB3aWxsIGJlIHRy
+ZWF0ZWQgYXMKdHdvIGRpZmZlcmVudCB2YWx1ZXMuIE5vdGUgYWxzbyB0aGVyZSBp
+cyBvbmx5IG9uZSBsZXZlbCBvZiBleHBhbnNpb24KLS0tIHlvdSBjYW5ub3QgbWFr
+ZSBhbiBncm91cCB0aGF0IHBvaW50cyB0byBhbm90aGVyIGdyb3VwLiBXaGVuIHVz
+ZWQKZnJvbSB0aGUgY29tbWFuZCBsaW5lLCBpdCBtYXkgYmUgbmVjZXNzYXJ5IHRv
+IHF1b3RlIHRoZSBhcmd1bWVudCB0bwp0aGlzIG9wdGlvbiB0byBwcmV2ZW50IHRo
+ZSBzaGVsbCBmcm9tIHRyZWF0aW5nIGl0IGFzIG11bHRpcGxlCmFyZ3VtZW50cy4K
+CkBpdGVtIC0tdW5ncm91cCBAY29kZXtuYW1lfQpAb3BpbmRleCB1bmdyb3VwClJl
+bW92ZSBhIGdpdmVuIGVudHJ5IGZyb20gdGhlIEBvcHRpb257LS1ncm91cH0gbGlz
+dC4KCkBpdGVtIC0tbm8tZ3JvdXBzCkBvcGluZGV4IG5vLWdyb3VwcwpSZW1vdmUg
+YWxsIGVudHJpZXMgZnJvbSB0aGUgQG9wdGlvbnstLWdyb3VwfSBsaXN0LgoKQGl0
+ZW0gLS1sb2NhbC11c2VyIEB2YXJ7bmFtZX0KQGl0ZW14IC11CkBvcGluZGV4IGxv
+Y2FsLXVzZXIKVXNlIEB2YXJ7bmFtZX0gYXMgdGhlIGtleSB0byBzaWduIHdpdGgu
+IE5vdGUgdGhhdCB0aGlzIG9wdGlvbiBvdmVycmlkZXMKQG9wdGlvbnstLWRlZmF1
+bHQta2V5fS4KCkBpdGVtIC0tdHJ5LXNlY3JldC1rZXkgQHZhcntuYW1lfQpAb3Bp
+bmRleCB0cnktc2VjcmV0LWtleQpGb3IgaGlkZGVuIHJlY2lwaWVudHMgR1BHIG5l
+ZWRzIHRvIGtub3cgdGhlIGtleXMgdG8gdXNlIGZvciB0cmlhbApkZWNyeXB0aW9u
+LiAgVGhlIGtleSBzZXQgd2l0aCBAb3B0aW9uey0tZGVmYXVsdC1rZXl9IGlzIGFs
+d2F5cyB0cmllZApmaXJzdCwgYnV0IHRoaXMgaXMgb2Z0ZW4gbm90IHN1ZmZpY2ll
+bnQuICBUaGlzIG9wdGlvbiBhbGxvd3MgdG8gc2V0IG1vcmUKa2V5cyB0byBiZSB1
+c2VkIGZvciB0cmlhbCBkZWNyeXB0aW9uLiAgQWx0aG91Z2ggYW55IHZhbGlkIHVz
+ZXItaWQKc3BlY2lmaWNhdGlvbiBtYXkgYmUgdXNlZCBmb3IgQHZhcntuYW1lfSBp
+dCBtYWtlcyBzZW5zZSB0byB1c2UgYXQgbGVhc3QKdGhlIGxvbmcga2V5aWQgdG8g
+YXZvaWQgYW1iaWd1aXRpZXMuICBOb3RlIHRoYXQgZ3BnLWFnZW50IG1pZ2h0IHBv
+cCB1cCBhCnBpbmVudHJ5IGZvciBhIGxvdCBrZXlzIHRvIGRvIHRoZSB0cmlhbCBk
+ZWNyeXB0aW9uLiAgSWYgeW91IHdhbnQgdG8gc3RvcAphbGwgZnVydGhlciB0cmlh
+bCBkZWNyeXB0aW9uIHlvdSBtYXkgdXNlIGNsb3NlLXdpbmRvdyBidXR0b24gaW5z
+dGVhZCBvZgp0aGUgY2FuY2VsIGJ1dHRvbi4KCkBpdGVtIC0tdHJ5LWFsbC1zZWNy
+ZXRzCkBvcGluZGV4IHRyeS1hbGwtc2VjcmV0cwpEb24ndCBsb29rIGF0IHRoZSBr
+ZXkgSUQgYXMgc3RvcmVkIGluIHRoZSBtZXNzYWdlIGJ1dCB0cnkgYWxsIHNlY3Jl
+dAprZXlzIGluIHR1cm4gdG8gZmluZCB0aGUgcmlnaHQgZGVjcnlwdGlvbiBrZXku
+IFRoaXMgb3B0aW9uIGZvcmNlcyB0aGUKYmVoYXZpb3VyIGFzIHVzZWQgYnkgYW5v
+bnltb3VzIHJlY2lwaWVudHMgKGNyZWF0ZWQgYnkgdXNpbmcKQG9wdGlvbnstLXRo
+cm93LWtleWlkc30gb3IgQG9wdGlvbnstLWhpZGRlbi1yZWNpcGllbnR9KSBhbmQg
+bWlnaHQgY29tZQpoYW5keSBpbiBjYXNlIHdoZXJlIGFuIGVuY3J5cHRlZCBtZXNz
+YWdlIGNvbnRhaW5zIGEgYm9ndXMga2V5IElELgoKQGl0ZW0gLS1za2lwLWhpZGRl
+bi1yZWNpcGllbnRzCkBpdGVteCAtLW5vLXNraXAtaGlkZGVuLXJlY2lwaWVudHMK
+QG9waW5kZXggc2tpcC1oaWRkZW4tcmVjaXBpZW50cwpAb3BpbmRleCBuby1za2lw
+LWhpZGRlbi1yZWNpcGllbnRzCkR1cmluZyBkZWNyeXB0aW9uIHNraXAgYWxsIGFu
+b255bW91cyByZWNpcGllbnRzLiAgVGhpcyBvcHRpb24gaGVscHMgaW4KdGhlIGNh
+c2UgdGhhdCBwZW9wbGUgdXNlIHRoZSBoaWRkZW4gcmVjaXBpZW50cyBmZWF0dXJl
+IHRvIGhpZGUgdGhlcmUKb3duIGVuY3J5cHQtdG8ga2V5IGZyb20gb3RoZXJzLiAg
+SWYgb25lc2VsZiBoYXMgbWFueSBzZWNyZXQga2V5cyB0aGlzCm1heSBsZWFkIHRv
+IGEgbWFqb3IgYW5ub3lhbmNlIGJlY2F1c2UgYWxsIGtleXMgYXJlIHRyaWVkIGlu
+IHR1cm4gdG8KZGVjcnlwdCBzb21ldGhpbmcgd2hpY2ggd2FzIG5vdCByZWFsbHkg
+aW50ZW5kZWQgZm9yIGl0LiAgVGhlIGRyYXdiYWNrCm9mIHRoaXMgb3B0aW9uIGlz
+IHRoYXQgaXQgaXMgY3VycmVudGx5IG5vdCBwb3NzaWJsZSB0byBkZWNyeXB0IGEK
+bWVzc2FnZSB3aGljaCBpbmNsdWRlcyByZWFsIGFub255bW91cyByZWNpcGllbnRz
+LgoKCkBlbmQgdGFibGUKCkBjICoqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioKQGMgKioqKioqKiogIElOUFVUIEFORCBPVVRQVVQgICoq
+KioqKioqKioqKioqKgpAYyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqCkBub2RlIEdQRyBJbnB1dCBhbmQgT3V0cHV0CkBzdWJzZWN0
+aW9uIElucHV0IGFuZCBPdXRwdXQKCkB0YWJsZSBAZ251cGd0YWJvcHQKCkBpdGVt
+IC0tYXJtb3IKQGl0ZW14IC1hCkBvcGluZGV4IGFybW9yCkNyZWF0ZSBBU0NJSSBh
+cm1vcmVkIG91dHB1dC4gIFRoZSBkZWZhdWx0IGlzIHRvIGNyZWF0ZSB0aGUgYmlu
+YXJ5Ck9wZW5QR1AgZm9ybWF0LgoKQGl0ZW0gLS1uby1hcm1vcgpAb3BpbmRleCBu
+by1hcm1vcgpBc3N1bWUgdGhlIGlucHV0IGRhdGEgaXMgbm90IGluIEFTQ0lJIGFy
+bW9yZWQgZm9ybWF0LgoKQGl0ZW0gLS1vdXRwdXQgQHZhcntmaWxlfQpAaXRlbXgg
+LW8gQHZhcntmaWxlfQpAb3BpbmRleCBvdXRwdXQKV3JpdGUgb3V0cHV0IHRvIEB2
+YXJ7ZmlsZX0uCgpAaXRlbSAtLW1heC1vdXRwdXQgQGNvZGV7bn0KQG9waW5kZXgg
+bWF4LW91dHB1dApUaGlzIG9wdGlvbiBzZXRzIGEgbGltaXQgb24gdGhlIG51bWJl
+ciBvZiBieXRlcyB0aGF0IHdpbGwgYmUgZ2VuZXJhdGVkCndoZW4gcHJvY2Vzc2lu
+ZyBhIGZpbGUuIFNpbmNlIE9wZW5QR1Agc3VwcG9ydHMgdmFyaW91cyBsZXZlbHMg
+b2YKY29tcHJlc3Npb24sIGl0IGlzIHBvc3NpYmxlIHRoYXQgdGhlIHBsYWludGV4
+dCBvZiBhIGdpdmVuIG1lc3NhZ2UgbWF5IGJlCnNpZ25pZmljYW50bHkgbGFyZ2Vy
+IHRoYW4gdGhlIG9yaWdpbmFsIE9wZW5QR1AgbWVzc2FnZS4gV2hpbGUgR251UEcK
+d29ya3MgcHJvcGVybHkgd2l0aCBzdWNoIG1lc3NhZ2VzLCB0aGVyZSBpcyBvZnRl
+biBhIGRlc2lyZSB0byBzZXQgYQptYXhpbXVtIGZpbGUgc2l6ZSB0aGF0IHdpbGwg
+YmUgZ2VuZXJhdGVkIGJlZm9yZSBwcm9jZXNzaW5nIGlzIGZvcmNlZCB0bwpzdG9w
+IGJ5IHRoZSBPUyBsaW1pdHMuIERlZmF1bHRzIHRvIDAsIHdoaWNoIG1lYW5zICJu
+byBsaW1pdCIuCgpAaXRlbSAtLWltcG9ydC1vcHRpb25zIEBjb2Rle3BhcmFtZXRl
+cnN9CkBvcGluZGV4IGltcG9ydC1vcHRpb25zClRoaXMgaXMgYSBzcGFjZSBvciBj
+b21tYSBkZWxpbWl0ZWQgc3RyaW5nIHRoYXQgZ2l2ZXMgb3B0aW9ucyBmb3IKaW1w
+b3J0aW5nIGtleXMuIE9wdGlvbnMgY2FuIGJlIHByZXBlbmRlZCB3aXRoIGEgYG5v
+LScgdG8gZ2l2ZSB0aGUKb3Bwb3NpdGUgbWVhbmluZy4gVGhlIG9wdGlvbnMgYXJl
+OgoKQHRhYmxlIEBhc2lzCgogIEBpdGVtIGltcG9ydC1sb2NhbC1zaWdzCiAgQWxs
+b3cgaW1wb3J0aW5nIGtleSBzaWduYXR1cmVzIG1hcmtlZCBhcyAibG9jYWwiLiBU
+aGlzIGlzIG5vdAogIGdlbmVyYWxseSB1c2VmdWwgdW5sZXNzIGEgc2hhcmVkIGtl
+eXJpbmcgc2NoZW1lIGlzIGJlaW5nIHVzZWQuCiAgRGVmYXVsdHMgdG8gbm8uCgog
+IEBpdGVtIGtlZXAtb3duZXJ0cnVzdAogIE5vcm1hbGx5IHBvc3NpYmxlIHN0aWxs
+IGV4aXN0aW5nIG93bmVydHJ1c3QgdmFsdWVzIG9mIGEga2V5IGFyZQogIGNsZWFy
+ZWQgaWYgYSBrZXkgaXMgaW1wb3J0ZWQuICBUaGlzIGlzIGluIGdlbmVyYWwgZGVz
+aXJhYmxlIHNvIHRoYXQKICBhIGZvcm1lcmx5IGRlbGV0ZWQga2V5IGRvZXMgbm90
+IGF1dG9tYXRpY2FsbHkgZ2FpbiBhbiBvd25lcnRydXN0CiAgdmFsdWVzIG1lcmVs
+eSBkdWUgdG8gaW1wb3J0LiAgT24gdGhlIG90aGVyIGhhbmQgaXQgaXMgc29tZXRp
+bWVzCiAgbmVjZXNzYXJ5IHRvIHJlLWltcG9ydCBhIHRydXN0ZWQgc2V0IG9mIGtl
+eXMgYWdhaW4gYnV0IGtlZXBpbmcKICBhbHJlYWR5IGFzc2lnbmVkIG93bmVydHJ1
+c3QgdmFsdWVzLiAgVGhpcyBjYW4gYmUgYWNoaXZlZCBieSB1c2luZwogIHRoaXMg
+b3B0aW9uLgoKICBAaXRlbSByZXBhaXItcGtzLXN1YmtleS1idWcKICBEdXJpbmcg
+aW1wb3J0LCBhdHRlbXB0IHRvIHJlcGFpciB0aGUgZGFtYWdlIGNhdXNlZCBieSB0
+aGUgUEtTIGtleXNlcnZlcgogIGJ1ZyAocHJlIHZlcnNpb24gMC45LjYpIHRoYXQg
+bWFuZ2xlcyBrZXlzIHdpdGggbXVsdGlwbGUgc3Via2V5cy4gTm90ZQogIHRoYXQg
+dGhpcyBjYW5ub3QgY29tcGxldGVseSByZXBhaXIgdGhlIGRhbWFnZWQga2V5IGFz
+IHNvbWUgY3J1Y2lhbCBkYXRhCiAgaXMgcmVtb3ZlZCBieSB0aGUga2V5c2VydmVy
+LCBidXQgaXQgZG9lcyBhdCBsZWFzdCBnaXZlIHlvdSBiYWNrIG9uZQogIHN1Ymtl
+eS4gRGVmYXVsdHMgdG8gbm8gZm9yIHJlZ3VsYXIgQG9wdGlvbnstLWltcG9ydH0g
+YW5kIHRvIHllcyBmb3IKICBrZXlzZXJ2ZXIgQG9wdGlvbnstLXJlY3Yta2V5c30u
+CgogIEBpdGVtIG1lcmdlLW9ubHkKICBEdXJpbmcgaW1wb3J0LCBhbGxvdyBrZXkg
+dXBkYXRlcyB0byBleGlzdGluZyBrZXlzLCBidXQgZG8gbm90IGFsbG93CiAgYW55
+IG5ldyBrZXlzIHRvIGJlIGltcG9ydGVkLiBEZWZhdWx0cyB0byBuby4KCiAgQGl0
+ZW0gaW1wb3J0LWNsZWFuCiAgQWZ0ZXIgaW1wb3J0LCBjb21wYWN0IChyZW1vdmUg
+YWxsIHNpZ25hdHVyZXMgZXhjZXB0IHRoZQogIHNlbGYtc2lnbmF0dXJlKSBhbnkg
+dXNlciBJRHMgZnJvbSB0aGUgbmV3IGtleSB0aGF0IGFyZSBub3QgdXNhYmxlLgog
+IFRoZW4sIHJlbW92ZSBhbnkgc2lnbmF0dXJlcyBmcm9tIHRoZSBuZXcga2V5IHRo
+YXQgYXJlIG5vdCB1c2FibGUuCiAgVGhpcyBpbmNsdWRlcyBzaWduYXR1cmVzIHRo
+YXQgd2VyZSBpc3N1ZWQgYnkga2V5cyB0aGF0IGFyZSBub3QgcHJlc2VudAogIG9u
+IHRoZSBrZXlyaW5nLiBUaGlzIG9wdGlvbiBpcyB0aGUgc2FtZSBhcyBydW5uaW5n
+IHRoZSBAb3B0aW9uey0tZWRpdC1rZXl9CiAgY29tbWFuZCAiY2xlYW4iIGFmdGVy
+IGltcG9ydC4gRGVmYXVsdHMgdG8gbm8uCgogIEBpdGVtIGltcG9ydC1taW5pbWFs
+CiAgSW1wb3J0IHRoZSBzbWFsbGVzdCBrZXkgcG9zc2libGUuIFRoaXMgcmVtb3Zl
+cyBhbGwgc2lnbmF0dXJlcyBleGNlcHQKICB0aGUgbW9zdCByZWNlbnQgc2VsZi1z
+aWduYXR1cmUgb24gZWFjaCB1c2VyIElELiBUaGlzIG9wdGlvbiBpcyB0aGUKICBz
+YW1lIGFzIHJ1bm5pbmcgdGhlIEBvcHRpb257LS1lZGl0LWtleX0gY29tbWFuZCAi
+bWluaW1pemUiIGFmdGVyIGltcG9ydC4KICBEZWZhdWx0cyB0byBuby4KQGVuZCB0
+YWJsZQoKQGl0ZW0gLS1leHBvcnQtb3B0aW9ucyBAY29kZXtwYXJhbWV0ZXJzfQpA
+b3BpbmRleCBleHBvcnQtb3B0aW9ucwpUaGlzIGlzIGEgc3BhY2Ugb3IgY29tbWEg
+ZGVsaW1pdGVkIHN0cmluZyB0aGF0IGdpdmVzIG9wdGlvbnMgZm9yCmV4cG9ydGlu
+ZyBrZXlzLiBPcHRpb25zIGNhbiBiZSBwcmVwZW5kZWQgd2l0aCBhIGBuby0nIHRv
+IGdpdmUgdGhlCm9wcG9zaXRlIG1lYW5pbmcuIFRoZSBvcHRpb25zIGFyZToKCkB0
+YWJsZSBAYXNpcwoKICBAaXRlbSBleHBvcnQtbG9jYWwtc2lncwogIEFsbG93IGV4
+cG9ydGluZyBrZXkgc2lnbmF0dXJlcyBtYXJrZWQgYXMgImxvY2FsIi4gVGhpcyBp
+cyBub3QKICBnZW5lcmFsbHkgdXNlZnVsIHVubGVzcyBhIHNoYXJlZCBrZXlyaW5n
+IHNjaGVtZSBpcyBiZWluZyB1c2VkLgogIERlZmF1bHRzIHRvIG5vLgoKICBAaXRl
+bSBleHBvcnQtYXR0cmlidXRlcwogIEluY2x1ZGUgYXR0cmlidXRlIHVzZXIgSURz
+IChwaG90byBJRHMpIHdoaWxlIGV4cG9ydGluZy4gVGhpcyBpcwogIHVzZWZ1bCB0
+byBleHBvcnQga2V5cyBpZiB0aGV5IGFyZSBnb2luZyB0byBiZSB1c2VkIGJ5IGFu
+IE9wZW5QR1AKICBwcm9ncmFtIHRoYXQgZG9lcyBub3QgYWNjZXB0IGF0dHJpYnV0
+ZSB1c2VyIElEcy4gRGVmYXVsdHMgdG8geWVzLgoKICBAaXRlbSBleHBvcnQtc2Vu
+c2l0aXZlLXJldmtleXMKICBJbmNsdWRlIGRlc2lnbmF0ZWQgcmV2b2tlciBpbmZv
+cm1hdGlvbiB0aGF0IHdhcyBtYXJrZWQgYXMKICAic2Vuc2l0aXZlIi4gRGVmYXVs
+dHMgdG8gbm8uCgogIEBjIFNpbmNlIEdudVBHIDIuMSBncGctYWdlbnQgbWFuYWdl
+cyB0aGUgc2VjcmV0IGtleSBhbmQgdGh1cyB0aGUKICBAYyBleHBvcnQtcmVzZXQt
+c3Via2V5LXBhc3N3ZCBoYWNrIGlzIG5vdCBhbnltb3JlIGp1c3RpZmllZC4gIFN1
+Y2ggdXNlCiAgQGMgY2FzZXMgbWF5IGJlIGltcGxlbWVudGVkIHVzaW5nIGEgc3Bl
+Y2lhbGl6ZWQgc2VjcmV0IGtleSBleHBvcnQKICBAYyB0b29sLgogIEBjIEBpdGVt
+IGV4cG9ydC1yZXNldC1zdWJrZXktcGFzc3dkCiAgQGMgV2hlbiB1c2luZyB0aGUg
+QG9wdGlvbnstLWV4cG9ydC1zZWNyZXQtc3Via2V5c30gY29tbWFuZCwgdGhpcyBv
+cHRpb24gcmVzZXRzCiAgQGMgdGhlIHBhc3NwaHJhc2VzIGZvciBhbGwgZXhwb3J0
+ZWQgc3Via2V5cyB0byBlbXB0eS4gVGhpcyBpcyB1c2VmdWwKICBAYyB3aGVuIHRo
+ZSBleHBvcnRlZCBzdWJrZXkgaXMgdG8gYmUgdXNlZCBvbiBhbiB1bmF0dGVuZGVk
+IG1hY2hpbmUgd2hlcmUKICBAYyBhIHBhc3NwaHJhc2UgZG9lc24ndCBuZWNlc3Nh
+cmlseSBtYWtlIHNlbnNlLiBEZWZhdWx0cyB0byBuby4KCiAgQGl0ZW0gZXhwb3J0
+LWNsZWFuCiAgQ29tcGFjdCAocmVtb3ZlIGFsbCBzaWduYXR1cmVzIGZyb20pIHVz
+ZXIgSURzIG9uIHRoZSBrZXkgYmVpbmcKICBleHBvcnRlZCBpZiB0aGUgdXNlciBJ
+RHMgYXJlIG5vdCB1c2FibGUuIEFsc28sIGRvIG5vdCBleHBvcnQgYW55CiAgc2ln
+bmF0dXJlcyB0aGF0IGFyZSBub3QgdXNhYmxlLiBUaGlzIGluY2x1ZGVzIHNpZ25h
+dHVyZXMgdGhhdCB3ZXJlCiAgaXNzdWVkIGJ5IGtleXMgdGhhdCBhcmUgbm90IHBy
+ZXNlbnQgb24gdGhlIGtleXJpbmcuIFRoaXMgb3B0aW9uIGlzCiAgdGhlIHNhbWUg
+YXMgcnVubmluZyB0aGUgQG9wdGlvbnstLWVkaXQta2V5fSBjb21tYW5kICJjbGVh
+biIgYmVmb3JlIGV4cG9ydAogIGV4Y2VwdCB0aGF0IHRoZSBsb2NhbCBjb3B5IG9m
+IHRoZSBrZXkgaXMgbm90IG1vZGlmaWVkLiBEZWZhdWx0cyB0bwogIG5vLgoKICBA
+aXRlbSBleHBvcnQtbWluaW1hbAogIEV4cG9ydCB0aGUgc21hbGxlc3Qga2V5IHBv
+c3NpYmxlLiBUaGlzIHJlbW92ZXMgYWxsIHNpZ25hdHVyZXMgZXhjZXB0IHRoZQog
+IG1vc3QgcmVjZW50IHNlbGYtc2lnbmF0dXJlIG9uIGVhY2ggdXNlciBJRC4gVGhp
+cyBvcHRpb24gaXMgdGhlIHNhbWUgYXMKICBydW5uaW5nIHRoZSBAb3B0aW9uey0t
+ZWRpdC1rZXl9IGNvbW1hbmQgIm1pbmltaXplIiBiZWZvcmUgZXhwb3J0IGV4Y2Vw
+dAogIHRoYXQgdGhlIGxvY2FsIGNvcHkgb2YgdGhlIGtleSBpcyBub3QgbW9kaWZp
+ZWQuIERlZmF1bHRzIHRvIG5vLgpAZW5kIHRhYmxlCgpAaXRlbSAtLXdpdGgtY29s
+b25zCkBvcGluZGV4IHdpdGgtY29sb25zClByaW50IGtleSBsaXN0aW5ncyBkZWxp
+bWl0ZWQgYnkgY29sb25zLiBOb3RlIHRoYXQgdGhlIG91dHB1dCB3aWxsIGJlCmVu
+Y29kZWQgaW4gVVRGLTggcmVnYXJkbGVzcyBvZiBhbnkgQG9wdGlvbnstLWRpc3Bs
+YXktY2hhcnNldH0gc2V0dGluZy4gVGhpcwpmb3JtYXQgaXMgdXNlZnVsIHdoZW4g
+R251UEcgaXMgY2FsbGVkIGZyb20gc2NyaXB0cyBhbmQgb3RoZXIgcHJvZ3JhbXMK
+YXMgaXQgaXMgZWFzaWx5IG1hY2hpbmUgcGFyc2VkLiBUaGUgZGV0YWlscyBvZiB0
+aGlzIGZvcm1hdCBhcmUKZG9jdW1lbnRlZCBpbiB0aGUgZmlsZSBAZmlsZXtkb2Mv
+REVUQUlMU30sIHdoaWNoIGlzIGluY2x1ZGVkIGluIHRoZSBHbnVQRwpzb3VyY2Ug
+ZGlzdHJpYnV0aW9uLgoKCkBpdGVtIC0tcHJpbnQtcGthLXJlY29yZHMKQG9waW5k
+ZXggcHJpbnQtcGthLXJlY29yZHMKTW9kaWZ5IHRoZSBvdXRwdXQgb2YgdGhlIGxp
+c3QgY29tbWFuZHMgdG8gcHJpbnQgUEtBIHJlY29yZHMgc3VpdGFibGUKdG8gcHV0
+IGludG8gRE5TIHpvbmUgZmlsZXMuICBBbiBPUklHSU4gbGluZSBpcyBwcmludGVk
+IGJlZm9yZSBlYWNoCnJlY29yZCB0byBhbGxvdyBkaXZlcnRpbmcgdGhlIHJlY29y
+ZHMgdG8gdGhlIGNvcnJlc3BvbmRpbmcgem9uZSBmaWxlLgoKQGl0ZW0gLS1wcmlu
+dC1kYW5lLXJlY29yZHMKQG9waW5kZXggcHJpbnQtZGFuZS1yZWNvcmRzCk1vZGlm
+eSB0aGUgb3V0cHV0IG9mIHRoZSBsaXN0IGNvbW1hbmRzIHRvIHByaW50IE9wZW5Q
+R1AgREFORSByZWNvcmRzCnN1aXRhYmxlIHRvIHB1dCBpbnRvIEROUyB6b25lIGZp
+bGVzLiAgQW4gT1JJR0lOIGxpbmUgaXMgcHJpbnRlZCBiZWZvcmUKZWFjaCByZWNv
+cmQgdG8gYWxsb3cgZGl2ZXJ0aW5nIHRoZSByZWNvcmRzIHRvIHRoZSBjb3JyZXNw
+b25kaW5nIHpvbmUKZmlsZS4KCkBpdGVtIC0tZml4ZWQtbGlzdC1tb2RlCkBvcGlu
+ZGV4IGZpeGVkLWxpc3QtbW9kZQpEbyBub3QgbWVyZ2UgcHJpbWFyeSB1c2VyIElE
+IGFuZCBwcmltYXJ5IGtleSBpbiBAb3B0aW9uey0td2l0aC1jb2xvbn0KbGlzdGlu
+ZyBtb2RlIGFuZCBwcmludCBhbGwgdGltZXN0YW1wcyBhcyBzZWNvbmRzIHNpbmNl
+IDE5NzAtMDEtMDEuClNpbmNlIEdudVBHIDIuMC4xMCwgdGhpcyBtb2RlIGlzIGFs
+d2F5cyB1c2VkIGFuZCB0aHVzIHRoaXMgb3B0aW9uIGlzCm9ic29sZXRlOyBpdCBk
+b2VzIG5vdCBoYXJtIHRvIHVzZSBpdCB0aG91Z2guCgpAaXRlbSAtLWxlZ2FjeS1s
+aXN0LW1vZGUKQG9waW5kZXggbGVnYWN5LWxpc3QtbW9kZQpSZXZlcnQgdG8gdGhl
+IHByZS0yLjEgcHVibGljIGtleSBsaXN0IG1vZGUuICBUaGlzIG9ubHkgYWZmZWN0
+cyB0aGUKaHVtYW4gcmVhZGFibGUgb3V0cHV0IGFuZCBub3QgdGhlIG1hY2hpbmUg
+aW50ZXJmYWNlCihpLmUuIEBjb2Rley0td2l0aC1jb2xvbnN9KS4gIE5vdGUgdGhh
+dCB0aGUgbGVnYWN5IGZvcm1hdCBkb2VzIG5vdAphbGxvdyB0byBjb252ZXkgc3Vp
+dGFibGUgaW5mb3JtYXRpb24gZm9yIGVsbGlwdGljIGN1cnZlcy4KCkBpdGVtIC0t
+d2l0aC1maW5nZXJwcmludApAb3BpbmRleCB3aXRoLWZpbmdlcnByaW50ClNhbWUg
+YXMgdGhlIGNvbW1hbmQgQG9wdGlvbnstLWZpbmdlcnByaW50fSBidXQgY2hhbmdl
+cyBvbmx5IHRoZSBmb3JtYXQKb2YgdGhlIG91dHB1dCBhbmQgbWF5IGJlIHVzZWQg
+dG9nZXRoZXIgd2l0aCBhbm90aGVyIGNvbW1hbmQuCgpAaXRlbSAtLXdpdGgtaWNh
+by1zcGVsbGluZwpAb3BpbmRleCB3aXRoLWljYW8tc3BlbGxpbmcKUHJpbnQgdGhl
+IElDQU8gc3BlbGxpbmcgb2YgdGhlIGZpbmdlcnByaW50IGluIGFkZGl0aW9uIHRv
+IHRoZSBoZXggZGlnaXRzLgoKQGl0ZW0gLS13aXRoLWtleWdyaXAKQG9waW5kZXgg
+d2l0aC1rZXlncmlwCkluY2x1ZGUgdGhlIGtleWdyaXAgaW4gdGhlIGtleSBsaXN0
+aW5ncy4KCkBpdGVtIC0td2l0aC1zZWNyZXQKQG9waW5kZXggd2l0aC1zZWNyZXQK
+SW5jbHVkZSBpbmZvIGFib3V0IHRoZSBwcmVzZW5jZSBvZiBhIHNlY3JldCBrZXkg
+aW4gcHVibGljIGtleSBsaXN0aW5ncwpkb25lIHdpdGggQGNvZGV7LS13aXRoLWNv
+bG9uc30uCgpAZW5kIHRhYmxlCgpAYyAqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqCkBjICoqKioqKioqICBPUEVOUEdQIE9QVElPTlMg
+ICoqKioqKioqKioqKioqKioKQGMgKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKgpAbm9kZSBPcGVuUEdQIE9wdGlvbnMKQHN1YnNlY3Rp
+b24gT3BlblBHUCBwcm90b2NvbCBzcGVjaWZpYyBvcHRpb25zLgoKQHRhYmxlIEBn
+bnVwZ3RhYm9wdAoKQGl0ZW0gLXQsIC0tdGV4dG1vZGUKQGl0ZW14IC0tbm8tdGV4
+dG1vZGUKQG9waW5kZXggdGV4dG1vZGUKVHJlYXQgaW5wdXQgZmlsZXMgYXMgdGV4
+dCBhbmQgc3RvcmUgdGhlbSBpbiB0aGUgT3BlblBHUCBjYW5vbmljYWwgdGV4dApm
+b3JtIHdpdGggc3RhbmRhcmQgIkNSTEYiIGxpbmUgZW5kaW5ncy4gVGhpcyBhbHNv
+IHNldHMgdGhlIG5lY2Vzc2FyeQpmbGFncyB0byBpbmZvcm0gdGhlIHJlY2lwaWVu
+dCB0aGF0IHRoZSBlbmNyeXB0ZWQgb3Igc2lnbmVkIGRhdGEgaXMgdGV4dAphbmQg
+bWF5IG5lZWQgaXRzIGxpbmUgZW5kaW5ncyBjb252ZXJ0ZWQgYmFjayB0byB3aGF0
+ZXZlciB0aGUgbG9jYWwKc3lzdGVtIHVzZXMuIFRoaXMgb3B0aW9uIGlzIHVzZWZ1
+bCB3aGVuIGNvbW11bmljYXRpbmcgYmV0d2VlbiB0d28KcGxhdGZvcm1zIHRoYXQg
+aGF2ZSBkaWZmZXJlbnQgbGluZSBlbmRpbmcgY29udmVudGlvbnMgKFVOSVgtbGlr
+ZSB0byBNYWMsCk1hYyB0byBXaW5kb3dzLCBldGMpLiBAb3B0aW9uey0tbm8tdGV4
+dG1vZGV9IGRpc2FibGVzIHRoaXMgb3B0aW9uLCBhbmQKaXMgdGhlIGRlZmF1bHQu
+CgpAaXRlbSAtLWZvcmNlLXYzLXNpZ3MKQGl0ZW14IC0tbm8tZm9yY2UtdjMtc2ln
+cwpAaXRlbSAtLWZvcmNlLXY0LWNlcnRzCkBpdGVteCAtLW5vLWZvcmNlLXY0LWNl
+cnRzClRoZXNlIG9wdGlvbnMgYXJlIG9ic29sZXRlIGFuZCBoYXZlIG5vIGVmZmVj
+dCBzaW5jZSBHbnVQRyAyLjEuCgpAaXRlbSAtLWZvcmNlLW1kYwpAb3BpbmRleCBm
+b3JjZS1tZGMKRm9yY2UgdGhlIHVzZSBvZiBlbmNyeXB0aW9uIHdpdGggYSBtb2Rp
+ZmljYXRpb24gZGV0ZWN0aW9uIGNvZGUuIFRoaXMKaXMgYWx3YXlzIHVzZWQgd2l0
+aCB0aGUgbmV3ZXIgY2lwaGVycyAodGhvc2Ugd2l0aCBhIGJsb2Nrc2l6ZSBncmVh
+dGVyCnRoYW4gNjQgYml0cyksIG9yIGlmIGFsbCBvZiB0aGUgcmVjaXBpZW50IGtl
+eXMgaW5kaWNhdGUgTURDIHN1cHBvcnQgaW4KdGhlaXIgZmVhdHVyZSBmbGFncy4K
+CkBpdGVtIC0tZGlzYWJsZS1tZGMKQG9waW5kZXggZGlzYWJsZS1tZGMKRGlzYWJs
+ZSB0aGUgdXNlIG9mIHRoZSBtb2RpZmljYXRpb24gZGV0ZWN0aW9uIGNvZGUuIE5v
+dGUgdGhhdCBieQp1c2luZyB0aGlzIG9wdGlvbiwgdGhlIGVuY3J5cHRlZCBtZXNz
+YWdlIGJlY29tZXMgdnVsbmVyYWJsZSB0byBhCm1lc3NhZ2UgbW9kaWZpY2F0aW9u
+IGF0dGFjay4KCkBpdGVtIC0tcGVyc29uYWwtY2lwaGVyLXByZWZlcmVuY2VzIEBj
+b2Rle3N0cmluZ30KQG9waW5kZXggcGVyc29uYWwtY2lwaGVyLXByZWZlcmVuY2Vz
+ClNldCB0aGUgbGlzdCBvZiBwZXJzb25hbCBjaXBoZXIgcHJlZmVyZW5jZXMgdG8g
+QGNvZGV7c3RyaW5nfS4gIFVzZQpAY29tbWFuZHtAZ3BnbmFtZSAtLXZlcnNpb259
+IHRvIGdldCBhIGxpc3Qgb2YgYXZhaWxhYmxlIGFsZ29yaXRobXMsCmFuZCB1c2Ug
+QGNvZGV7bm9uZX0gdG8gc2V0IG5vIHByZWZlcmVuY2UgYXQgYWxsLiAgVGhpcyBh
+bGxvd3MgdGhlIHVzZXIKdG8gc2FmZWx5IG92ZXJyaWRlIHRoZSBhbGdvcml0aG0g
+Y2hvc2VuIGJ5IHRoZSByZWNpcGllbnQga2V5CnByZWZlcmVuY2VzLCBhcyBHUEcg
+d2lsbCBvbmx5IHNlbGVjdCBhbiBhbGdvcml0aG0gdGhhdCBpcyB1c2FibGUgYnkK
+YWxsIHJlY2lwaWVudHMuICBUaGUgbW9zdCBoaWdobHkgcmFua2VkIGNpcGhlciBp
+biB0aGlzIGxpc3QgaXMgYWxzbwp1c2VkIGZvciB0aGUgQG9wdGlvbnstLXN5bW1l
+dHJpY30gZW5jcnlwdGlvbiBjb21tYW5kLgoKQGl0ZW0gLS1wZXJzb25hbC1kaWdl
+c3QtcHJlZmVyZW5jZXMgQGNvZGV7c3RyaW5nfQpAb3BpbmRleCBwZXJzb25hbC1k
+aWdlc3QtcHJlZmVyZW5jZXMKU2V0IHRoZSBsaXN0IG9mIHBlcnNvbmFsIGRpZ2Vz
+dCBwcmVmZXJlbmNlcyB0byBAY29kZXtzdHJpbmd9LiAgVXNlCkBjb21tYW5ke0Bn
+cGduYW1lIC0tdmVyc2lvbn0gdG8gZ2V0IGEgbGlzdCBvZiBhdmFpbGFibGUgYWxn
+b3JpdGhtcywKYW5kIHVzZSBAY29kZXtub25lfSB0byBzZXQgbm8gcHJlZmVyZW5j
+ZSBhdCBhbGwuICBUaGlzIGFsbG93cyB0aGUgdXNlcgp0byBzYWZlbHkgb3ZlcnJp
+ZGUgdGhlIGFsZ29yaXRobSBjaG9zZW4gYnkgdGhlIHJlY2lwaWVudCBrZXkKcHJl
+ZmVyZW5jZXMsIGFzIEdQRyB3aWxsIG9ubHkgc2VsZWN0IGFuIGFsZ29yaXRobSB0
+aGF0IGlzIHVzYWJsZSBieQphbGwgcmVjaXBpZW50cy4gIFRoZSBtb3N0IGhpZ2hs
+eSByYW5rZWQgZGlnZXN0IGFsZ29yaXRobSBpbiB0aGlzIGxpc3QKaXMgYWxzbyB1
+c2VkIHdoZW4gc2lnbmluZyB3aXRob3V0IGVuY3J5cHRpb24KKGUuZy4gQG9wdGlv
+bnstLWNsZWFyc2lnbn0gb3IgQG9wdGlvbnstLXNpZ259KS4KCkBpdGVtIC0tcGVy
+c29uYWwtY29tcHJlc3MtcHJlZmVyZW5jZXMgQGNvZGV7c3RyaW5nfQpAb3BpbmRl
+eCBwZXJzb25hbC1jb21wcmVzcy1wcmVmZXJlbmNlcwpTZXQgdGhlIGxpc3Qgb2Yg
+cGVyc29uYWwgY29tcHJlc3Npb24gcHJlZmVyZW5jZXMgdG8gQGNvZGV7c3RyaW5n
+fS4KVXNlIEBjb21tYW5ke0BncGduYW1lIC0tdmVyc2lvbn0gdG8gZ2V0IGEgbGlz
+dCBvZiBhdmFpbGFibGUKYWxnb3JpdGhtcywgYW5kIHVzZSBAY29kZXtub25lfSB0
+byBzZXQgbm8gcHJlZmVyZW5jZSBhdCBhbGwuICBUaGlzCmFsbG93cyB0aGUgdXNl
+ciB0byBzYWZlbHkgb3ZlcnJpZGUgdGhlIGFsZ29yaXRobSBjaG9zZW4gYnkgdGhl
+CnJlY2lwaWVudCBrZXkgcHJlZmVyZW5jZXMsIGFzIEdQRyB3aWxsIG9ubHkgc2Vs
+ZWN0IGFuIGFsZ29yaXRobSB0aGF0CmlzIHVzYWJsZSBieSBhbGwgcmVjaXBpZW50
+cy4gIFRoZSBtb3N0IGhpZ2hseSByYW5rZWQgY29tcHJlc3Npb24KYWxnb3JpdGht
+IGluIHRoaXMgbGlzdCBpcyBhbHNvIHVzZWQgd2hlbiB0aGVyZSBhcmUgbm8gcmVj
+aXBpZW50IGtleXMKdG8gY29uc2lkZXIgKGUuZy4gQG9wdGlvbnstLXN5bW1ldHJp
+Y30pLgoKQGl0ZW0gLS1zMmstY2lwaGVyLWFsZ28gQGNvZGV7bmFtZX0KQG9waW5k
+ZXggczJrLWNpcGhlci1hbGdvClVzZSBAY29kZXtuYW1lfSBhcyB0aGUgY2lwaGVy
+IGFsZ29yaXRobSB1c2VkIHRvIHByb3RlY3Qgc2VjcmV0IGtleXMuClRoZSBkZWZh
+dWx0IGNpcGhlciBpcyBAdmFsdWV7R1BHU1lNRU5DQUxHT30uIFRoaXMgY2lwaGVy
+IGlzIGFsc28gdXNlZApmb3Igc3ltbWV0cmljIGVuY3J5cHRpb24gd2l0aCBhIHBh
+c3NwaHJhc2UgaWYKQG9wdGlvbnstLXBlcnNvbmFsLWNpcGhlci1wcmVmZXJlbmNl
+c30gYW5kIEBvcHRpb257LS1jaXBoZXItYWxnb30gaXMKbm90IGdpdmVuLgoKQGl0
+ZW0gLS1zMmstZGlnZXN0LWFsZ28gQGNvZGV7bmFtZX0KQG9waW5kZXggczJrLWRp
+Z2VzdC1hbGdvClVzZSBAY29kZXtuYW1lfSBhcyB0aGUgZGlnZXN0IGFsZ29yaXRo
+bSB1c2VkIHRvIG1hbmdsZSB0aGUgcGFzc3BocmFzZXMuClRoZSBkZWZhdWx0IGFs
+Z29yaXRobSBpcyBTSEEtMS4KCkBpdGVtIC0tczJrLW1vZGUgQGNvZGV7bn0KQG9w
+aW5kZXggczJrLW1vZGUKU2VsZWN0cyBob3cgcGFzc3BocmFzZXMgYXJlIG1hbmds
+ZWQuIElmIEBjb2Rle259IGlzIDAgYSBwbGFpbgpwYXNzcGhyYXNlICh3aGljaCBp
+cyBub3QgcmVjb21tZW5kZWQpIHdpbGwgYmUgdXNlZCwgYSAxIGFkZHMgYSBzYWx0
+IHRvCnRoZSBwYXNzcGhyYXNlIGFuZCBhIDMgKHRoZSBkZWZhdWx0KSBpdGVyYXRl
+cyB0aGUgd2hvbGUgcHJvY2VzcyBhCm51bWJlciBvZiB0aW1lcyAoc2VlIC0tczJr
+LWNvdW50KS4gIFVubGVzcyBAb3B0aW9uey0tcmZjMTk5MX0gaXMgdXNlZCwKdGhp
+cyBtb2RlIGlzIGFsc28gdXNlZCBmb3Igc3ltbWV0cmljIGVuY3J5cHRpb24gd2l0
+aCBhIHBhc3NwaHJhc2UuCgpAaXRlbSAtLXMyay1jb3VudCBAY29kZXtufQpAb3Bp
+bmRleCBzMmstY291bnQKU3BlY2lmeSBob3cgbWFueSB0aW1lcyB0aGUgcGFzc3Bo
+cmFzZSBtYW5nbGluZyBpcyByZXBlYXRlZC4gIFRoaXMKdmFsdWUgbWF5IHJhbmdl
+IGJldHdlZW4gMTAyNCBhbmQgNjUwMTE3MTIgaW5jbHVzaXZlLiAgVGhlIGRlZmF1
+bHQgaXMKaW5xdWlyZWQgZnJvbSBncGctYWdlbnQuICBOb3RlIHRoYXQgbm90IGFs
+bCB2YWx1ZXMgaW4gdGhlCjEwMjQtNjUwMTE3MTIgcmFuZ2UgYXJlIGxlZ2FsIGFu
+ZCBpZiBhbiBpbGxlZ2FsIHZhbHVlIGlzIHNlbGVjdGVkLApHbnVQRyB3aWxsIHJv
+dW5kIHVwIHRvIHRoZSBuZWFyZXN0IGxlZ2FsIHZhbHVlLiAgVGhpcyBvcHRpb24g
+aXMgb25seQptZWFuaW5nZnVsIGlmIEBvcHRpb257LS1zMmstbW9kZX0gaXMgMy4K
+CgpAZW5kIHRhYmxlCgpAYyAqKioqKioqKioqKioqKioqKioqKioqKioqKioKQGMg
+KioqKioqKiBDb21wbGlhbmNlICoqKioqKioqCkBjICoqKioqKioqKioqKioqKioq
+KioqKioqKioqKgpAbm9kZSBDb21wbGlhbmNlIE9wdGlvbnMKQHN1YnNlY3Rpb24g
+Q29tcGxpYW5jZSBvcHRpb25zCgpUaGVzZSBvcHRpb25zIGNvbnRyb2wgd2hhdCBH
+bnVQRyBpcyBjb21wbGlhbnQgdG8uIE9ubHkgb25lIG9mIHRoZXNlCm9wdGlvbnMg
+bWF5IGJlIGFjdGl2ZSBhdCBhIHRpbWUuIE5vdGUgdGhhdCB0aGUgZGVmYXVsdCBz
+ZXR0aW5nIG9mCnRoaXMgaXMgbmVhcmx5IGFsd2F5cyB0aGUgY29ycmVjdCBvbmUu
+IFNlZSB0aGUgSU5URVJPUEVSQUJJTElUWSBXSVRICk9USEVSIE9QRU5QR1AgUFJP
+R1JBTVMgc2VjdGlvbiBiZWxvdyBiZWZvcmUgdXNpbmcgb25lIG9mIHRoZXNlCm9w
+dGlvbnMuCgpAdGFibGUgQGdudXBndGFib3B0CgpAaXRlbSAtLWdudXBnCkBvcGlu
+ZGV4IGdudXBnClVzZSBzdGFuZGFyZCBHbnVQRyBiZWhhdmlvci4gVGhpcyBpcyBl
+c3NlbnRpYWxseSBPcGVuUEdQIGJlaGF2aW9yCihzZWUgQG9wdGlvbnstLW9wZW5w
+Z3B9KSwgYnV0IHdpdGggc29tZSBhZGRpdGlvbmFsIHdvcmthcm91bmRzIGZvciBj
+b21tb24KY29tcGF0aWJpbGl0eSBwcm9ibGVtcyBpbiBkaWZmZXJlbnQgdmVyc2lv
+bnMgb2YgUEdQLiBUaGlzIGlzIHRoZQpkZWZhdWx0IG9wdGlvbiwgc28gaXQgaXMg
+bm90IGdlbmVyYWxseSBuZWVkZWQsIGJ1dCBpdCBtYXkgYmUgdXNlZnVsIHRvCm92
+ZXJyaWRlIGEgZGlmZmVyZW50IGNvbXBsaWFuY2Ugb3B0aW9uIGluIHRoZSBncGcu
+Y29uZiBmaWxlLgoKQGl0ZW0gLS1vcGVucGdwCkBvcGluZGV4IG9wZW5wZ3AKUmVz
+ZXQgYWxsIHBhY2tldCwgY2lwaGVyIGFuZCBkaWdlc3Qgb3B0aW9ucyB0byBzdHJp
+Y3QgT3BlblBHUApiZWhhdmlvci4gVXNlIHRoaXMgb3B0aW9uIHRvIHJlc2V0IGFs
+bCBwcmV2aW91cyBvcHRpb25zIGxpa2UKQG9wdGlvbnstLXMyay0qfSwgQG9wdGlv
+bnstLWNpcGhlci1hbGdvfSwgQG9wdGlvbnstLWRpZ2VzdC1hbGdvfSBhbmQKQG9w
+dGlvbnstLWNvbXByZXNzLWFsZ299IHRvIE9wZW5QR1AgY29tcGxpYW50IHZhbHVl
+cy4gQWxsIFBHUAp3b3JrYXJvdW5kcyBhcmUgZGlzYWJsZWQuCgpAaXRlbSAtLXJm
+YzQ4ODAKQG9waW5kZXggcmZjNDg4MApSZXNldCBhbGwgcGFja2V0LCBjaXBoZXIg
+YW5kIGRpZ2VzdCBvcHRpb25zIHRvIHN0cmljdCBSRkMtNDg4MApiZWhhdmlvci4g
+Tm90ZSB0aGF0IHRoaXMgaXMgY3VycmVudGx5IHRoZSBzYW1lIHRoaW5nIGFzCkBv
+cHRpb257LS1vcGVucGdwfS4KCkBpdGVtIC0tcmZjMjQ0MApAb3BpbmRleCByZmMy
+NDQwClJlc2V0IGFsbCBwYWNrZXQsIGNpcGhlciBhbmQgZGlnZXN0IG9wdGlvbnMg
+dG8gc3RyaWN0IFJGQy0yNDQwCmJlaGF2aW9yLgoKQGlmY2xlYXIgZ3BndG93b25l
+CkBpdGVtIC0tcmZjMTk5MQpAb3BpbmRleCByZmMxOTkxClRyeSB0byBiZSBtb3Jl
+IFJGQy0xOTkxIChQR1AgMi54KSBjb21wbGlhbnQuICBUaGlzIG9wdGlvbiBpcwpk
+ZXByZWNhdGVkIHdpbGwgYmUgcmVtb3ZlZCBpbiBHbnVQRyAyLjEuCgpAaXRlbSAt
+LXBncDIKQG9waW5kZXggcGdwMgpTZXQgdXAgYWxsIG9wdGlvbnMgdG8gYmUgYXMg
+UEdQIDIueCBjb21wbGlhbnQgYXMgcG9zc2libGUsIGFuZCB3YXJuIGlmCmFuIGFj
+dGlvbiBpcyB0YWtlbiAoZS5nLiBlbmNyeXB0aW5nIHRvIGEgbm9uLVJTQSBrZXkp
+IHRoYXQgd2lsbCBjcmVhdGUKYSBtZXNzYWdlIHRoYXQgUEdQIDIueCB3aWxsIG5v
+dCBiZSBhYmxlIHRvIGhhbmRsZS4gTm90ZSB0aGF0IGBQR1AKMi54JyBoZXJlIG1l
+YW5zIGBNSVQgUEdQIDIuNi4yJy4gVGhlcmUgYXJlIG90aGVyIHZlcnNpb25zIG9m
+IFBHUCAyLngKYXZhaWxhYmxlLCBidXQgdGhlIE1JVCByZWxlYXNlIGlzIGEgZ29v
+ZCBjb21tb24gYmFzZWxpbmUuCgpUaGlzIG9wdGlvbiBpbXBsaWVzCkBvcHRpb257
+LS1yZmMxOTkxIC0tZGlzYWJsZS1tZGMgLS1uby1mb3JjZS12NC1jZXJ0cwogLS1l
+c2NhcGUtZnJvbS1saW5lcyAgLS1mb3JjZS12My1zaWdzIC0tYWxsb3ctd2Vhay1k
+aWdlc3QtYWxnb3MKIC0tY2lwaGVyLWFsZ28gSURFQSAtLWRpZ2VzdC1hbGdvIE1E
+NSAtLWNvbXByZXNzLWFsZ28gWklQfS4KSXQgYWxzbyBkaXNhYmxlcyBAb3B0aW9u
+ey0tdGV4dG1vZGV9IHdoZW4gZW5jcnlwdGluZy4KClRoaXMgb3B0aW9uIGlzIGRl
+cHJlY2F0ZWQgd2lsbCBiZSByZW1vdmVkIGluIEdudVBHIDIuMS4gIFRoZSByZWFz
+b24KZm9yIGRyb3BwaW5nIFBHUC0yIHN1cHBvcnQgaXMgdGhhdCB0aGUgUEdQIDIg
+Zm9ybWF0IGlzIG5vdCBhbnltb3JlCmNvbnNpZGVyZWQgc2FmZSAoZm9yIGV4YW1w
+bGUgZHVlIHRvIHRoZSB1c2Ugb2YgdGhlIGJyb2tlbiBNRDUgYWxnb3JpdGhtKS4K
+Tm90ZSB0aGF0IHRoZSBkZWNyeXB0aW9uIG9mIFBHUC0yIGNyZWF0ZWQgbWVzc2Fn
+ZXMgd2lsbCBjb250aW51ZSB0byB3b3JrLgpAZW5kIGlmY2xlYXIKCkBpdGVtIC0t
+cGdwNgpAb3BpbmRleCBwZ3A2ClNldCB1cCBhbGwgb3B0aW9ucyB0byBiZSBhcyBQ
+R1AgNiBjb21wbGlhbnQgYXMgcG9zc2libGUuIFRoaXMKcmVzdHJpY3RzIHlvdSB0
+byB0aGUgY2lwaGVycyBJREVBIChpZiB0aGUgSURFQSBwbHVnaW4gaXMgaW5zdGFs
+bGVkKSwKM0RFUywgYW5kIENBU1Q1LCB0aGUgaGFzaGVzIE1ENSwgU0hBMSBhbmQg
+UklQRU1EMTYwLCBhbmQgdGhlCmNvbXByZXNzaW9uIGFsZ29yaXRobXMgbm9uZSBh
+bmQgWklQLiBUaGlzIGFsc28gZGlzYWJsZXMKLS10aHJvdy1rZXlpZHMsIGFuZCBt
+YWtpbmcgc2lnbmF0dXJlcyB3aXRoIHNpZ25pbmcgc3Via2V5cyBhcyBQR1AgNgpk
+b2VzIG5vdCB1bmRlcnN0YW5kIHNpZ25hdHVyZXMgbWFkZSBieSBzaWduaW5nIHN1
+YmtleXMuCgpUaGlzIG9wdGlvbiBpbXBsaWVzIEBvcHRpb257LS1kaXNhYmxlLW1k
+YyAtLWVzY2FwZS1mcm9tLWxpbmVzfS4KCkBpdGVtIC0tcGdwNwpAb3BpbmRleCBw
+Z3A3ClNldCB1cCBhbGwgb3B0aW9ucyB0byBiZSBhcyBQR1AgNyBjb21wbGlhbnQg
+YXMgcG9zc2libGUuIFRoaXMgaXMKaWRlbnRpY2FsIHRvIEBvcHRpb257LS1wZ3A2
+fSBleGNlcHQgdGhhdCBNRENzIGFyZSBub3QgZGlzYWJsZWQsIGFuZCB0aGUKbGlz
+dCBvZiBhbGxvd2FibGUgY2lwaGVycyBpcyBleHBhbmRlZCB0byBhZGQgQUVTMTI4
+LCBBRVMxOTIsIEFFUzI1NiwgYW5kClRXT0ZJU0guCgpAaXRlbSAtLXBncDgKQG9w
+aW5kZXggcGdwOApTZXQgdXAgYWxsIG9wdGlvbnMgdG8gYmUgYXMgUEdQIDggY29t
+cGxpYW50IGFzIHBvc3NpYmxlLiBQR1AgOCBpcyBhIGxvdApjbG9zZXIgdG8gdGhl
+IE9wZW5QR1Agc3RhbmRhcmQgdGhhbiBwcmV2aW91cyB2ZXJzaW9ucyBvZiBQR1As
+IHNvIGFsbAp0aGlzIGRvZXMgaXMgZGlzYWJsZSBAb3B0aW9uey0tdGhyb3cta2V5
+aWRzfSBhbmQgc2V0CkBvcHRpb257LS1lc2NhcGUtZnJvbS1saW5lc30uICBBbGwg
+YWxnb3JpdGhtcyBhcmUgYWxsb3dlZCBleGNlcHQgZm9yIHRoZQpTSEEyMjQsIFNI
+QTM4NCwgYW5kIFNIQTUxMiBkaWdlc3RzLgoKQGVuZCB0YWJsZQoKCkBjICoqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKQGMgKioqKioq
+KiogIEVTT1RFUklDIE9QVElPTlMgICoqKioqKioqKioqKioqKgpAYyAqKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCkBub2RlIEdQRyBF
+c290ZXJpYyBPcHRpb25zCkBzdWJzZWN0aW9uIERvaW5nIHRoaW5ncyBvbmUgdXN1
+YWxseSBkb2Vzbid0IHdhbnQgdG8gZG8uCgpAdGFibGUgQGdudXBndGFib3B0CgpA
+aXRlbSAtbgpAaXRlbXggLS1kcnktcnVuCkBvcGluZGV4IGRyeS1ydW4KRG9uJ3Qg
+bWFrZSBhbnkgY2hhbmdlcyAodGhpcyBpcyBub3QgY29tcGxldGVseSBpbXBsZW1l
+bnRlZCkuCgpAaXRlbSAtLWxpc3Qtb25seQpAb3BpbmRleCBsaXN0LW9ubHkKQ2hh
+bmdlcyB0aGUgYmVoYXZpb3VyIG9mIHNvbWUgY29tbWFuZHMuIFRoaXMgaXMgbGlr
+ZSBAb3B0aW9uey0tZHJ5LXJ1bn0gYnV0CmRpZmZlcmVudCBpbiBzb21lIGNhc2Vz
+LiBUaGUgc2VtYW50aWMgb2YgdGhpcyBjb21tYW5kIG1heSBiZSBleHRlbmRlZCBp
+bgp0aGUgZnV0dXJlLiBDdXJyZW50bHkgaXQgb25seSBza2lwcyB0aGUgYWN0dWFs
+IGRlY3J5cHRpb24gcGFzcyBhbmQKdGhlcmVmb3JlIGVuYWJsZXMgYSBmYXN0IGxp
+c3Rpbmcgb2YgdGhlIGVuY3J5cHRpb24ga2V5cy4KCkBpdGVtIC1pCkBpdGVteCAt
+LWludGVyYWN0aXZlCkBvcGluZGV4IGludGVyYWN0aXZlClByb21wdCBiZWZvcmUg
+b3ZlcndyaXRpbmcgYW55IGZpbGVzLgoKQGl0ZW0gLS1kZWJ1Zy1sZXZlbCBAdmFy
+e2xldmVsfQpAb3BpbmRleCBkZWJ1Zy1sZXZlbApTZWxlY3QgdGhlIGRlYnVnIGxl
+dmVsIGZvciBpbnZlc3RpZ2F0aW5nIHByb2JsZW1zLiBAdmFye2xldmVsfSBtYXkg
+YmUKYSBudW1lcmljIHZhbHVlIG9yIGJ5IGEga2V5d29yZDoKCkB0YWJsZSBAY29k
+ZQogIEBpdGVtIG5vbmUKICBObyBkZWJ1Z2dpbmcgYXQgYWxsLiAgQSB2YWx1ZSBv
+ZiBsZXNzIHRoYW4gMSBtYXkgYmUgdXNlZCBpbnN0ZWFkIG9mCiAgdGhlIGtleXdv
+cmQuCiAgQGl0ZW0gYmFzaWMKICBTb21lIGJhc2ljIGRlYnVnIG1lc3NhZ2VzLiAg
+QSB2YWx1ZSBiZXR3ZWVuIDEgYW5kIDIgbWF5IGJlIHVzZWQKICBpbnN0ZWFkIG9m
+IHRoZSBrZXl3b3JkLgogIEBpdGVtIGFkdmFuY2VkCiAgTW9yZSB2ZXJib3NlIGRl
+YnVnIG1lc3NhZ2VzLiAgQSB2YWx1ZSBiZXR3ZWVuIDMgYW5kIDUgbWF5IGJlIHVz
+ZWQKICBpbnN0ZWFkIG9mIHRoZSBrZXl3b3JkLgogIEBpdGVtIGV4cGVydAogIEV2
+ZW4gbW9yZSBkZXRhaWxlZCBtZXNzYWdlcy4gIEEgdmFsdWUgYmV0d2VlbiA2IGFu
+ZCA4IG1heSBiZSB1c2VkCiAgaW5zdGVhZCBvZiB0aGUga2V5d29yZC4KICBAaXRl
+bSBndXJ1CiAgQWxsIG9mIHRoZSBkZWJ1ZyBtZXNzYWdlcyB5b3UgY2FuIGdldC4g
+QSB2YWx1ZSBncmVhdGVyIHRoYW4gOCBtYXkgYmUKICB1c2VkIGluc3RlYWQgb2Yg
+dGhlIGtleXdvcmQuICBUaGUgY3JlYXRpb24gb2YgaGFzaCB0cmFjaW5nIGZpbGVz
+IGlzCiAgb25seSBlbmFibGVkIGlmIHRoZSBrZXl3b3JkIGlzIHVzZWQuCkBlbmQg
+dGFibGUKCkhvdyB0aGVzZSBtZXNzYWdlcyBhcmUgbWFwcGVkIHRvIHRoZSBhY3R1
+YWwgZGVidWdnaW5nIGZsYWdzIGlzIG5vdApzcGVjaWZpZWQgYW5kIG1heSBjaGFu
+Z2Ugd2l0aCBuZXdlciByZWxlYXNlcyBvZiB0aGlzIHByb2dyYW0uIFRoZXkgYXJl
+Cmhvd2V2ZXIgY2FyZWZ1bGx5IHNlbGVjdGVkIHRvIGJlc3QgYWlkIGluIGRlYnVn
+Z2luZy4KCkBpdGVtIC0tZGVidWcgQHZhcntmbGFnc30KQG9waW5kZXggZGVidWcK
+U2V0IGRlYnVnZ2luZyBmbGFncy4gQWxsIGZsYWdzIGFyZSBvci1lZCBhbmQgQHZh
+cntmbGFnc30gbWF5IGJlIGdpdmVuCmluIEMgc3ludGF4IChlLmcuIDB4MDA0Mikg
+b3IgYXMgYSBjb21tYSBzZXBhcmF0ZWQgbGlzdCBvZiBmbGFnIG5hbWVzLgpUbyBn
+ZXQgYSBsaXN0IG9mIGFsbCBzdXBwb3J0ZWQgZmxhZ3MgdGhlIHNpbmdsZSB3b3Jk
+ICJoZWxwIiBjYW4gYmUKdXNlZC4KCkBpdGVtIC0tZGVidWctYWxsCkBvcGluZGV4
+IGRlYnVnLWFsbApTZXQgYWxsIHVzZWZ1bCBkZWJ1Z2dpbmcgZmxhZ3MuCgpAaXRl
+bSAtLWRlYnVnLWlvbGJmCkBvcGluZGV4IGRlYnVnLWlvbGJmClNldCBzdGRvdXQg
+aW50byBsaW5lIGJ1ZmZlcmVkIG1vZGUuICBUaGlzIG9wdGlvbiBpcyBvbmx5IGhv
+bm9yZWQgd2hlbgpnaXZlbiBvbiB0aGUgY29tbWFuZCBsaW5lLgoKQGl0ZW0gLS1m
+YWtlZC1zeXN0ZW0tdGltZSBAdmFye2Vwb2NofQpAb3BpbmRleCBmYWtlZC1zeXN0
+ZW0tdGltZQpUaGlzIG9wdGlvbiBpcyBvbmx5IHVzZWZ1bCBmb3IgdGVzdGluZzsg
+aXQgc2V0cyB0aGUgc3lzdGVtIHRpbWUgYmFjayBvcgpmb3J0aCB0byBAdmFye2Vw
+b2NofSB3aGljaCBpcyB0aGUgbnVtYmVyIG9mIHNlY29uZHMgZWxhcHNlZCBzaW5j
+ZSB0aGUgeWVhcgoxOTcwLiAgQWx0ZXJuYXRpdmVseSBAdmFye2Vwb2NofSBtYXkg
+YmUgZ2l2ZW4gYXMgYSBmdWxsIElTTyB0aW1lIHN0cmluZwooZS5nLiAiMjAwNzA5
+MjRUMTU0ODEyIikuCgpAaXRlbSAtLWVuYWJsZS1wcm9ncmVzcy1maWx0ZXIKQG9w
+aW5kZXggZW5hYmxlLXByb2dyZXNzLWZpbHRlcgpFbmFibGUgY2VydGFpbiBQUk9H
+UkVTUyBzdGF0dXMgb3V0cHV0cy4gVGhpcyBvcHRpb24gYWxsb3dzIGZyb250ZW5k
+cwp0byBkaXNwbGF5IGEgcHJvZ3Jlc3MgaW5kaWNhdG9yIHdoaWxlIGdwZyBpcyBw
+cm9jZXNzaW5nIGxhcmdlciBmaWxlcy4KVGhlcmUgaXMgYSBzbGlnaHQgcGVyZm9y
+bWFuY2Ugb3ZlcmhlYWQgdXNpbmcgaXQuCgpAaXRlbSAtLXN0YXR1cy1mZCBAY29k
+ZXtufQpAb3BpbmRleCBzdGF0dXMtZmQKV3JpdGUgc3BlY2lhbCBzdGF0dXMgc3Ry
+aW5ncyB0byB0aGUgZmlsZSBkZXNjcmlwdG9yIEBjb2Rle259LgpTZWUgdGhlIGZp
+bGUgREVUQUlMUyBpbiB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgYSBsaXN0aW5nIG9m
+IHRoZW0uCgpAaXRlbSAtLXN0YXR1cy1maWxlIEBjb2Rle2ZpbGV9CkBvcGluZGV4
+IHN0YXR1cy1maWxlClNhbWUgYXMgQG9wdGlvbnstLXN0YXR1cy1mZH0sIGV4Y2Vw
+dCB0aGUgc3RhdHVzIGRhdGEgaXMgd3JpdHRlbiB0byBmaWxlCkBjb2Rle2ZpbGV9
+LgoKQGl0ZW0gLS1sb2dnZXItZmQgQGNvZGV7bn0KQG9waW5kZXggbG9nZ2VyLWZk
+CldyaXRlIGxvZyBvdXRwdXQgdG8gZmlsZSBkZXNjcmlwdG9yIEBjb2Rle259IGFu
+ZCBub3QgdG8gU1RERVJSLgoKQGl0ZW0gLS1sb2ctZmlsZSBAY29kZXtmaWxlfQpA
+aXRlbXggLS1sb2dnZXItZmlsZSBAY29kZXtmaWxlfQpAb3BpbmRleCBsb2ctZmls
+ZQpTYW1lIGFzIEBvcHRpb257LS1sb2dnZXItZmR9LCBleGNlcHQgdGhlIGxvZ2dl
+ciBkYXRhIGlzIHdyaXR0ZW4gdG8gZmlsZQpAY29kZXtmaWxlfS4gIE5vdGUgdGhh
+dCBAb3B0aW9uey0tbG9nLWZpbGV9IGlzIG9ubHkgaW1wbGVtZW50ZWQgZm9yCkdu
+dVBHLTIuCgpAaXRlbSAtLWF0dHJpYnV0ZS1mZCBAY29kZXtufQpAb3BpbmRleCBh
+dHRyaWJ1dGUtZmQKV3JpdGUgYXR0cmlidXRlIHN1YnBhY2tldHMgdG8gdGhlIGZp
+bGUgZGVzY3JpcHRvciBAY29kZXtufS4gVGhpcyBpcyBtb3N0CnVzZWZ1bCBmb3Ig
+dXNlIHdpdGggQG9wdGlvbnstLXN0YXR1cy1mZH0sIHNpbmNlIHRoZSBzdGF0dXMg
+bWVzc2FnZXMgYXJlCm5lZWRlZCB0byBzZXBhcmF0ZSBvdXQgdGhlIHZhcmlvdXMg
+c3VicGFja2V0cyBmcm9tIHRoZSBzdHJlYW0gZGVsaXZlcmVkCnRvIHRoZSBmaWxl
+IGRlc2NyaXB0b3IuCgpAaXRlbSAtLWF0dHJpYnV0ZS1maWxlIEBjb2Rle2ZpbGV9
+CkBvcGluZGV4IGF0dHJpYnV0ZS1maWxlClNhbWUgYXMgQG9wdGlvbnstLWF0dHJp
+YnV0ZS1mZH0sIGV4Y2VwdCB0aGUgYXR0cmlidXRlIGRhdGEgaXMgd3JpdHRlbiB0
+bwpmaWxlIEBjb2Rle2ZpbGV9LgoKQGl0ZW0gLS1jb21tZW50IEBjb2Rle3N0cmlu
+Z30KQGl0ZW14IC0tbm8tY29tbWVudHMKQG9waW5kZXggY29tbWVudApVc2UgQGNv
+ZGV7c3RyaW5nfSBhcyBhIGNvbW1lbnQgc3RyaW5nIGluIGNsZWFyIHRleHQgc2ln
+bmF0dXJlcyBhbmQgQVNDSUkKYXJtb3JlZCBtZXNzYWdlcyBvciBrZXlzIChzZWUg
+QG9wdGlvbnstLWFybW9yfSkuIFRoZSBkZWZhdWx0IGJlaGF2aW9yIGlzCm5vdCB0
+byB1c2UgYSBjb21tZW50IHN0cmluZy4gQG9wdGlvbnstLWNvbW1lbnR9IG1heSBi
+ZSByZXBlYXRlZCBtdWx0aXBsZQp0aW1lcyB0byBnZXQgbXVsdGlwbGUgY29tbWVu
+dCBzdHJpbmdzLiBAb3B0aW9uey0tbm8tY29tbWVudHN9IHJlbW92ZXMKYWxsIGNv
+bW1lbnRzLiAgSXQgaXMgYSBnb29kIGlkZWEgdG8ga2VlcCB0aGUgbGVuZ3RoIG9m
+IGEgc2luZ2xlIGNvbW1lbnQKYmVsb3cgNjAgY2hhcmFjdGVycyB0byBhdm9pZCBw
+cm9ibGVtcyB3aXRoIG1haWwgcHJvZ3JhbXMgd3JhcHBpbmcgc3VjaApsaW5lcy4g
+IE5vdGUgdGhhdCBjb21tZW50IGxpbmVzLCBsaWtlIGFsbCBvdGhlciBoZWFkZXIg
+bGluZXMsIGFyZSBub3QKcHJvdGVjdGVkIGJ5IHRoZSBzaWduYXR1cmUuCgpAaXRl
+bSAtLWVtaXQtdmVyc2lvbgpAaXRlbXggLS1uby1lbWl0LXZlcnNpb24KQG9waW5k
+ZXggZW1pdC12ZXJzaW9uCkZvcmNlIGluY2x1c2lvbiBvZiB0aGUgdmVyc2lvbiBz
+dHJpbmcgaW4gQVNDSUkgYXJtb3JlZCBvdXRwdXQuICBJZgpnaXZlbiBvbmNlIG9u
+bHkgdGhlIG5hbWUgb2YgdGhlIHByb2dyYW0gYW5kIHRoZSBtYWpvciBudW1iZXIg
+aXMKZW1pdHRlZCAoZGVmYXVsdCksIGdpdmVuIHR3aWNlIHRoZSBtaW5vciBpcyBh
+bHNvIGVtaXR0ZWQsIGdpdmVuIHRyaXBsZQp0aGUgbWljcm8gaXMgYWRkZWQsIGFu
+ZCBnaXZlbiBxdWFkIGFuIG9wZXJhdGluZyBzeXN0ZW0gaWRlbnRpZmljYXRpb24K
+aXMgYWxzbyBlbWl0dGVkLiAgQG9wdGlvbnstLW5vLWVtaXQtdmVyc2lvbn0gZGlz
+YWJsZXMgdGhlIHZlcnNpb24KbGluZS4KCkBpdGVtIC0tc2lnLW5vdGF0aW9uIEBj
+b2Rle25hbWU9dmFsdWV9CkBpdGVteCAtLWNlcnQtbm90YXRpb24gQGNvZGV7bmFt
+ZT12YWx1ZX0KQGl0ZW14IC1OLCAtLXNldC1ub3RhdGlvbiBAY29kZXtuYW1lPXZh
+bHVlfQpAb3BpbmRleCBzaWctbm90YXRpb24KQG9waW5kZXggY2VydC1ub3RhdGlv
+bgpAb3BpbmRleCBzZXQtbm90YXRpb24KUHV0IHRoZSBuYW1lIHZhbHVlIHBhaXIg
+aW50byB0aGUgc2lnbmF0dXJlIGFzIG5vdGF0aW9uIGRhdGEuCkBjb2Rle25hbWV9
+IG11c3QgY29uc2lzdCBvbmx5IG9mIHByaW50YWJsZSBjaGFyYWN0ZXJzIG9yIHNw
+YWNlcywgYW5kCm11c3QgY29udGFpbiBhICdAQCcgY2hhcmFjdGVyIGluIHRoZSBm
+b3JtIGtleW5hbWVAQGRvbWFpbi5leGFtcGxlLmNvbQooc3Vic3RpdHV0aW5nIHRo
+ZSBhcHByb3ByaWF0ZSBrZXluYW1lIGFuZCBkb21haW4gbmFtZSwgb2YgY291cnNl
+KS4gIFRoaXMKaXMgdG8gaGVscCBwcmV2ZW50IHBvbGx1dGlvbiBvZiB0aGUgSUVU
+RiByZXNlcnZlZCBub3RhdGlvbgpuYW1lc3BhY2UuIFRoZSBAb3B0aW9uey0tZXhw
+ZXJ0fSBmbGFnIG92ZXJyaWRlcyB0aGUgJ0BAJwpjaGVjay4gQGNvZGV7dmFsdWV9
+IG1heSBiZSBhbnkgcHJpbnRhYmxlIHN0cmluZzsgaXQgd2lsbCBiZSBlbmNvZGVk
+IGluClVURjgsIHNvIHlvdSBzaG91bGQgY2hlY2sgdGhhdCB5b3VyIEBvcHRpb257
+LS1kaXNwbGF5LWNoYXJzZXR9IGlzIHNldApjb3JyZWN0bHkuIElmIHlvdSBwcmVm
+aXggQGNvZGV7bmFtZX0gd2l0aCBhbiBleGNsYW1hdGlvbiBtYXJrICghKSwgdGhl
+Cm5vdGF0aW9uIGRhdGEgd2lsbCBiZSBmbGFnZ2VkIGFzIGNyaXRpY2FsCihyZmM0
+ODgwOjUuMi4zLjE2KS4gQG9wdGlvbnstLXNpZy1ub3RhdGlvbn0gc2V0cyBhIG5v
+dGF0aW9uIGZvciBkYXRhCnNpZ25hdHVyZXMuIEBvcHRpb257LS1jZXJ0LW5vdGF0
+aW9ufSBzZXRzIGEgbm90YXRpb24gZm9yIGtleSBzaWduYXR1cmVzCihjZXJ0aWZp
+Y2F0aW9ucykuIEBvcHRpb257LS1zZXQtbm90YXRpb259IHNldHMgYm90aC4KClRo
+ZXJlIGFyZSBzcGVjaWFsIGNvZGVzIHRoYXQgbWF5IGJlIHVzZWQgaW4gbm90YXRp
+b24gbmFtZXMuICIlayIgd2lsbApiZSBleHBhbmRlZCBpbnRvIHRoZSBrZXkgSUQg
+b2YgdGhlIGtleSBiZWluZyBzaWduZWQsICIlSyIgaW50byB0aGUKbG9uZyBrZXkg
+SUQgb2YgdGhlIGtleSBiZWluZyBzaWduZWQsICIlZiIgaW50byB0aGUgZmluZ2Vy
+cHJpbnQgb2YgdGhlCmtleSBiZWluZyBzaWduZWQsICIlcyIgaW50byB0aGUga2V5
+IElEIG9mIHRoZSBrZXkgbWFraW5nIHRoZQpzaWduYXR1cmUsICIlUyIgaW50byB0
+aGUgbG9uZyBrZXkgSUQgb2YgdGhlIGtleSBtYWtpbmcgdGhlIHNpZ25hdHVyZSwK
+IiVnIiBpbnRvIHRoZSBmaW5nZXJwcmludCBvZiB0aGUga2V5IG1ha2luZyB0aGUg
+c2lnbmF0dXJlICh3aGljaCBtaWdodApiZSBhIHN1YmtleSksICIlcCIgaW50byB0
+aGUgZmluZ2VycHJpbnQgb2YgdGhlIHByaW1hcnkga2V5IG9mIHRoZSBrZXkKbWFr
+aW5nIHRoZSBzaWduYXR1cmUsICIlYyIgaW50byB0aGUgc2lnbmF0dXJlIGNvdW50
+IGZyb20gdGhlIE9wZW5QR1AKc21hcnRjYXJkLCBhbmQgIiUlIiByZXN1bHRzIGlu
+IGEgc2luZ2xlICIlIi4gJWssICVLLCBhbmQgJWYgYXJlIG9ubHkKbWVhbmluZ2Z1
+bCB3aGVuIG1ha2luZyBhIGtleSBzaWduYXR1cmUgKGNlcnRpZmljYXRpb24pLCBh
+bmQgJWMgaXMgb25seQptZWFuaW5nZnVsIHdoZW4gdXNpbmcgdGhlIE9wZW5QR1Ag
+c21hcnRjYXJkLgoKQGl0ZW0gLS1zaWctcG9saWN5LXVybCBAY29kZXtzdHJpbmd9
+CkBpdGVteCAtLWNlcnQtcG9saWN5LXVybCBAY29kZXtzdHJpbmd9CkBpdGVteCAt
+LXNldC1wb2xpY3ktdXJsIEBjb2Rle3N0cmluZ30KQG9waW5kZXggc2lnLXBvbGlj
+eS11cmwKQG9waW5kZXggY2VydC1wb2xpY3ktdXJsCkBvcGluZGV4IHNldC1wb2xp
+Y3ktdXJsClVzZSBAY29kZXtzdHJpbmd9IGFzIGEgUG9saWN5IFVSTCBmb3Igc2ln
+bmF0dXJlcyAocmZjNDg4MDo1LjIuMy4yMCkuICBJZgp5b3UgcHJlZml4IGl0IHdp
+dGggYW4gZXhjbGFtYXRpb24gbWFyayAoISksIHRoZSBwb2xpY3kgVVJMIHBhY2tl
+dCB3aWxsCmJlIGZsYWdnZWQgYXMgY3JpdGljYWwuIEBvcHRpb257LS1zaWctcG9s
+aWN5LXVybH0gc2V0cyBhIHBvbGljeSB1cmwgZm9yCmRhdGEgc2lnbmF0dXJlcy4g
+QG9wdGlvbnstLWNlcnQtcG9saWN5LXVybH0gc2V0cyBhIHBvbGljeSB1cmwgZm9y
+IGtleQpzaWduYXR1cmVzIChjZXJ0aWZpY2F0aW9ucykuIEBvcHRpb257LS1zZXQt
+cG9saWN5LXVybH0gc2V0cyBib3RoLgoKVGhlIHNhbWUgJS1leHBhbmRvcyB1c2Vk
+IGZvciBub3RhdGlvbiBkYXRhIGFyZSBhdmFpbGFibGUgaGVyZSBhcyB3ZWxsLgoK
+QGl0ZW0gLS1zaWcta2V5c2VydmVyLXVybCBAY29kZXtzdHJpbmd9CkBvcGluZGV4
+IHNpZy1rZXlzZXJ2ZXItdXJsClVzZSBAY29kZXtzdHJpbmd9IGFzIGEgcHJlZmVy
+cmVkIGtleXNlcnZlciBVUkwgZm9yIGRhdGEgc2lnbmF0dXJlcy4gSWYKeW91IHBy
+ZWZpeCBpdCB3aXRoIGFuIGV4Y2xhbWF0aW9uIG1hcmsgKCEpLCB0aGUga2V5c2Vy
+dmVyIFVSTCBwYWNrZXQKd2lsbCBiZSBmbGFnZ2VkIGFzIGNyaXRpY2FsLgoKVGhl
+IHNhbWUgJS1leHBhbmRvcyB1c2VkIGZvciBub3RhdGlvbiBkYXRhIGFyZSBhdmFp
+bGFibGUgaGVyZSBhcyB3ZWxsLgoKQGl0ZW0gLS1zZXQtZmlsZW5hbWUgQGNvZGV7
+c3RyaW5nfQpAb3BpbmRleCBzZXQtZmlsZW5hbWUKVXNlIEBjb2Rle3N0cmluZ30g
+YXMgdGhlIGZpbGVuYW1lIHdoaWNoIGlzIHN0b3JlZCBpbnNpZGUgbWVzc2FnZXMu
+ClRoaXMgb3ZlcnJpZGVzIHRoZSBkZWZhdWx0LCB3aGljaCBpcyB0byB1c2UgdGhl
+IGFjdHVhbCBmaWxlbmFtZSBvZiB0aGUKZmlsZSBiZWluZyBlbmNyeXB0ZWQuICBV
+c2luZyB0aGUgZW1wdHkgc3RyaW5nIGZvciBAdmFye3N0cmluZ30KZWZmZWN0aXZl
+bHkgcmVtb3ZlcyB0aGUgZmlsZW5hbWUgZnJvbSB0aGUgb3V0cHV0LgoKQGl0ZW0g
+LS1mb3IteW91ci1leWVzLW9ubHkKQGl0ZW14IC0tbm8tZm9yLXlvdXItZXllcy1v
+bmx5CkBvcGluZGV4IGZvci15b3VyLWV5ZXMtb25seQpTZXQgdGhlIGBmb3IgeW91
+ciBleWVzIG9ubHknIGZsYWcgaW4gdGhlIG1lc3NhZ2UuIFRoaXMgY2F1c2VzIEdu
+dVBHIHRvCnJlZnVzZSB0byBzYXZlIHRoZSBmaWxlIHVubGVzcyB0aGUgQG9wdGlv
+bnstLW91dHB1dH0gb3B0aW9uIGlzIGdpdmVuLAphbmQgUEdQIHRvIHVzZSBhICJz
+ZWN1cmUgdmlld2VyIiB3aXRoIGEgY2xhaW1lZCBUZW1wZXN0LXJlc2lzdGFudCBm
+b250CnRvIGRpc3BsYXkgdGhlIG1lc3NhZ2UuIFRoaXMgb3B0aW9uIG92ZXJyaWRl
+cyBAb3B0aW9uey0tc2V0LWZpbGVuYW1lfS4KQG9wdGlvbnstLW5vLWZvci15b3Vy
+LWV5ZXMtb25seX0gZGlzYWJsZXMgdGhpcyBvcHRpb24uCgpAaXRlbSAtLXVzZS1l
+bWJlZGRlZC1maWxlbmFtZQpAaXRlbXggLS1uby11c2UtZW1iZWRkZWQtZmlsZW5h
+bWUKQG9waW5kZXggdXNlLWVtYmVkZGVkLWZpbGVuYW1lClRyeSB0byBjcmVhdGUg
+YSBmaWxlIHdpdGggYSBuYW1lIGFzIGVtYmVkZGVkIGluIHRoZSBkYXRhLiBUaGlz
+IGNhbiBiZQphIGRhbmdlcm91cyBvcHRpb24gYXMgaXQgYWxsb3dzIHRvIG92ZXJ3
+cml0ZSBmaWxlcy4gRGVmYXVsdHMgdG8gbm8uCgpAaXRlbSAtLWNpcGhlci1hbGdv
+IEBjb2Rle25hbWV9CkBvcGluZGV4IGNpcGhlci1hbGdvClVzZSBAY29kZXtuYW1l
+fSBhcyBjaXBoZXIgYWxnb3JpdGhtLiBSdW5uaW5nIHRoZSBwcm9ncmFtIHdpdGgg
+dGhlCmNvbW1hbmQgQG9wdGlvbnstLXZlcnNpb259IHlpZWxkcyBhIGxpc3Qgb2Yg
+c3VwcG9ydGVkIGFsZ29yaXRobXMuIElmCnRoaXMgaXMgbm90IHVzZWQgdGhlIGNp
+cGhlciBhbGdvcml0aG0gaXMgc2VsZWN0ZWQgZnJvbSB0aGUgcHJlZmVyZW5jZXMK
+c3RvcmVkIHdpdGggdGhlIGtleS4gSW4gZ2VuZXJhbCwgeW91IGRvIG5vdCB3YW50
+IHRvIHVzZSB0aGlzIG9wdGlvbiBhcwppdCBhbGxvd3MgeW91IHRvIHZpb2xhdGUg
+dGhlIE9wZW5QR1Agc3RhbmRhcmQuCkBvcHRpb257LS1wZXJzb25hbC1jaXBoZXIt
+cHJlZmVyZW5jZXN9IGlzIHRoZSBzYWZlIHdheSB0byBhY2NvbXBsaXNoIHRoZQpz
+YW1lIHRoaW5nLgoKQGl0ZW0gLS1kaWdlc3QtYWxnbyBAY29kZXtuYW1lfQpAb3Bp
+bmRleCBkaWdlc3QtYWxnbwpVc2UgQGNvZGV7bmFtZX0gYXMgdGhlIG1lc3NhZ2Ug
+ZGlnZXN0IGFsZ29yaXRobS4gUnVubmluZyB0aGUgcHJvZ3JhbQp3aXRoIHRoZSBj
+b21tYW5kIEBvcHRpb257LS12ZXJzaW9ufSB5aWVsZHMgYSBsaXN0IG9mIHN1cHBv
+cnRlZCBhbGdvcml0aG1zLiBJbgpnZW5lcmFsLCB5b3UgZG8gbm90IHdhbnQgdG8g
+dXNlIHRoaXMgb3B0aW9uIGFzIGl0IGFsbG93cyB5b3UgdG8KdmlvbGF0ZSB0aGUg
+T3BlblBHUCBzdGFuZGFyZC4gQG9wdGlvbnstLXBlcnNvbmFsLWRpZ2VzdC1wcmVm
+ZXJlbmNlc30gaXMgdGhlCnNhZmUgd2F5IHRvIGFjY29tcGxpc2ggdGhlIHNhbWUg
+dGhpbmcuCgpAaXRlbSAtLWNvbXByZXNzLWFsZ28gQGNvZGV7bmFtZX0KQG9waW5k
+ZXggY29tcHJlc3MtYWxnbwpVc2UgY29tcHJlc3Npb24gYWxnb3JpdGhtIEBjb2Rl
+e25hbWV9LiAiemxpYiIgaXMgUkZDLTE5NTAgWkxJQgpjb21wcmVzc2lvbi4gInpp
+cCIgaXMgUkZDLTE5NTEgWklQIGNvbXByZXNzaW9uIHdoaWNoIGlzIHVzZWQgYnkg
+UEdQLgoiYnppcDIiIGlzIGEgbW9yZSBtb2Rlcm4gY29tcHJlc3Npb24gc2NoZW1l
+IHRoYXQgY2FuIGNvbXByZXNzIHNvbWUKdGhpbmdzIGJldHRlciB0aGFuIHppcCBv
+ciB6bGliLCBidXQgYXQgdGhlIGNvc3Qgb2YgbW9yZSBtZW1vcnkgdXNlZApkdXJp
+bmcgY29tcHJlc3Npb24gYW5kIGRlY29tcHJlc3Npb24uICJ1bmNvbXByZXNzZWQi
+IG9yICJub25lIgpkaXNhYmxlcyBjb21wcmVzc2lvbi4gSWYgdGhpcyBvcHRpb24g
+aXMgbm90IHVzZWQsIHRoZSBkZWZhdWx0CmJlaGF2aW9yIGlzIHRvIGV4YW1pbmUg
+dGhlIHJlY2lwaWVudCBrZXkgcHJlZmVyZW5jZXMgdG8gc2VlIHdoaWNoCmFsZ29y
+aXRobXMgdGhlIHJlY2lwaWVudCBzdXBwb3J0cy4gSWYgYWxsIGVsc2UgZmFpbHMs
+IFpJUCBpcyB1c2VkIGZvcgptYXhpbXVtIGNvbXBhdGliaWxpdHkuCgpaTElCIG1h
+eSBnaXZlIGJldHRlciBjb21wcmVzc2lvbiByZXN1bHRzIHRoYW4gWklQLCBhcyB0
+aGUgY29tcHJlc3Npb24Kd2luZG93IHNpemUgaXMgbm90IGxpbWl0ZWQgdG8gOGsu
+IEJaSVAyIG1heSBnaXZlIGV2ZW4gYmV0dGVyCmNvbXByZXNzaW9uIHJlc3VsdHMg
+dGhhbiB0aGF0LCBidXQgd2lsbCB1c2UgYSBzaWduaWZpY2FudGx5IGxhcmdlcgph
+bW91bnQgb2YgbWVtb3J5IHdoaWxlIGNvbXByZXNzaW5nIGFuZCBkZWNvbXByZXNz
+aW5nLiBUaGlzIG1heSBiZQpzaWduaWZpY2FudCBpbiBsb3cgbWVtb3J5IHNpdHVh
+dGlvbnMuIE5vdGUsIGhvd2V2ZXIsIHRoYXQgUEdQIChhbGwKdmVyc2lvbnMpIG9u
+bHkgc3VwcG9ydHMgWklQIGNvbXByZXNzaW9uLiBVc2luZyBhbnkgYWxnb3JpdGht
+IG90aGVyCnRoYW4gWklQIG9yICJub25lIiB3aWxsIG1ha2UgdGhlIG1lc3NhZ2Ug
+dW5yZWFkYWJsZSB3aXRoIFBHUC4gSW4KZ2VuZXJhbCwgeW91IGRvIG5vdCB3YW50
+IHRvIHVzZSB0aGlzIG9wdGlvbiBhcyBpdCBhbGxvd3MgeW91IHRvCnZpb2xhdGUg
+dGhlIE9wZW5QR1Agc3RhbmRhcmQuIEBvcHRpb257LS1wZXJzb25hbC1jb21wcmVz
+cy1wcmVmZXJlbmNlc30gaXMgdGhlCnNhZmUgd2F5IHRvIGFjY29tcGxpc2ggdGhl
+IHNhbWUgdGhpbmcuCgpAaXRlbSAtLWNlcnQtZGlnZXN0LWFsZ28gQGNvZGV7bmFt
+ZX0KQG9waW5kZXggY2VydC1kaWdlc3QtYWxnbwpVc2UgQGNvZGV7bmFtZX0gYXMg
+dGhlIG1lc3NhZ2UgZGlnZXN0IGFsZ29yaXRobSB1c2VkIHdoZW4gc2lnbmluZyBh
+CmtleS4gUnVubmluZyB0aGUgcHJvZ3JhbSB3aXRoIHRoZSBjb21tYW5kIEBvcHRp
+b257LS12ZXJzaW9ufSB5aWVsZHMgYQpsaXN0IG9mIHN1cHBvcnRlZCBhbGdvcml0
+aG1zLiBCZSBhd2FyZSB0aGF0IGlmIHlvdSBjaG9vc2UgYW4gYWxnb3JpdGhtCnRo
+YXQgR251UEcgc3VwcG9ydHMgYnV0IG90aGVyIE9wZW5QR1AgaW1wbGVtZW50YXRp
+b25zIGRvIG5vdCwgdGhlbiBzb21lCnVzZXJzIHdpbGwgbm90IGJlIGFibGUgdG8g
+dXNlIHRoZSBrZXkgc2lnbmF0dXJlcyB5b3UgbWFrZSwgb3IgcXVpdGUKcG9zc2li
+bHkgeW91ciBlbnRpcmUga2V5LgoKQGl0ZW0gLS1kaXNhYmxlLWNpcGhlci1hbGdv
+IEBjb2Rle25hbWV9CkBvcGluZGV4IGRpc2FibGUtY2lwaGVyLWFsZ28KTmV2ZXIg
+YWxsb3cgdGhlIHVzZSBvZiBAY29kZXtuYW1lfSBhcyBjaXBoZXIgYWxnb3JpdGht
+LgpUaGUgZ2l2ZW4gbmFtZSB3aWxsIG5vdCBiZSBjaGVja2VkIHNvIHRoYXQgYSBs
+YXRlciBsb2FkZWQgYWxnb3JpdGhtCndpbGwgc3RpbGwgZ2V0IGRpc2FibGVkLgoK
+QGl0ZW0gLS1kaXNhYmxlLXB1YmtleS1hbGdvIEBjb2Rle25hbWV9CkBvcGluZGV4
+IGRpc2FibGUtcHVia2V5LWFsZ28KTmV2ZXIgYWxsb3cgdGhlIHVzZSBvZiBAY29k
+ZXtuYW1lfSBhcyBwdWJsaWMga2V5IGFsZ29yaXRobS4KVGhlIGdpdmVuIG5hbWUg
+d2lsbCBub3QgYmUgY2hlY2tlZCBzbyB0aGF0IGEgbGF0ZXIgbG9hZGVkIGFsZ29y
+aXRobQp3aWxsIHN0aWxsIGdldCBkaXNhYmxlZC4KCkBpdGVtIC0tdGhyb3cta2V5
+aWRzCkBpdGVteCAtLW5vLXRocm93LWtleWlkcwpAb3BpbmRleCB0aHJvdy1rZXlp
+ZHMKRG8gbm90IHB1dCB0aGUgcmVjaXBpZW50IGtleSBJRHMgaW50byBlbmNyeXB0
+ZWQgbWVzc2FnZXMuIFRoaXMgaGVscHMgdG8KaGlkZSB0aGUgcmVjZWl2ZXJzIG9m
+IHRoZSBtZXNzYWdlIGFuZCBpcyBhIGxpbWl0ZWQgY291bnRlcm1lYXN1cmUKYWdh
+aW5zdCB0cmFmZmljIGFuYWx5c2lzLkBmb290bm90ZXtVc2luZyBhIGxpdHRsZSBz
+b2NpYWwgZW5naW5lZXJpbmcKYW55b25lIHdobyBpcyBhYmxlIHRvIGRlY3J5cHQg
+dGhlIG1lc3NhZ2UgY2FuIGNoZWNrIHdoZXRoZXIgb25lIG9mIHRoZQpvdGhlciBy
+ZWNpcGllbnRzIGlzIHRoZSBvbmUgaGUgc3VzcGVjdHMufSAgT24gdGhlIHJlY2Vp
+dmluZyBzaWRlLCBpdCBtYXkKc2xvdyBkb3duIHRoZSBkZWNyeXB0aW9uIHByb2Nl
+c3MgYmVjYXVzZSBhbGwgYXZhaWxhYmxlIHNlY3JldCBrZXlzIG11c3QKYmUgdHJp
+ZWQuICBAb3B0aW9uey0tbm8tdGhyb3cta2V5aWRzfSBkaXNhYmxlcyB0aGlzIG9w
+dGlvbi4gVGhpcyBvcHRpb24KaXMgZXNzZW50aWFsbHkgdGhlIHNhbWUgYXMgdXNp
+bmcgQG9wdGlvbnstLWhpZGRlbi1yZWNpcGllbnR9IGZvciBhbGwKcmVjaXBpZW50
+cy4KCkBpdGVtIC0tbm90LWRhc2gtZXNjYXBlZApAb3BpbmRleCBub3QtZGFzaC1l
+c2NhcGVkClRoaXMgb3B0aW9uIGNoYW5nZXMgdGhlIGJlaGF2aW9yIG9mIGNsZWFy
+dGV4dCBzaWduYXR1cmVzCnNvIHRoYXQgdGhleSBjYW4gYmUgdXNlZCBmb3IgcGF0
+Y2ggZmlsZXMuIFlvdSBzaG91bGQgbm90CnNlbmQgc3VjaCBhbiBhcm1vcmVkIGZp
+bGUgdmlhIGVtYWlsIGJlY2F1c2UgYWxsIHNwYWNlcwphbmQgbGluZSBlbmRpbmdz
+IGFyZSBoYXNoZWQgdG9vLiBZb3UgY2FuIG5vdCB1c2UgdGhpcwpvcHRpb24gZm9y
+IGRhdGEgd2hpY2ggaGFzIDUgZGFzaGVzIGF0IHRoZSBiZWdpbm5pbmcgb2YgYQps
+aW5lLCBwYXRjaCBmaWxlcyBkb24ndCBoYXZlIHRoaXMuIEEgc3BlY2lhbCBhcm1v
+ciBoZWFkZXIKbGluZSB0ZWxscyBHbnVQRyBhYm91dCB0aGlzIGNsZWFydGV4dCBz
+aWduYXR1cmUgb3B0aW9uLgoKQGl0ZW0gLS1lc2NhcGUtZnJvbS1saW5lcwpAaXRl
+bXggLS1uby1lc2NhcGUtZnJvbS1saW5lcwpAb3BpbmRleCBlc2NhcGUtZnJvbS1s
+aW5lcwpCZWNhdXNlIHNvbWUgbWFpbGVycyBjaGFuZ2UgbGluZXMgc3RhcnRpbmcg
+d2l0aCAiRnJvbSAiIHRvICI+RnJvbSAiIGl0CmlzIGdvb2QgdG8gaGFuZGxlIHN1
+Y2ggbGluZXMgaW4gYSBzcGVjaWFsIHdheSB3aGVuIGNyZWF0aW5nIGNsZWFydGV4
+dApzaWduYXR1cmVzIHRvIHByZXZlbnQgdGhlIG1haWwgc3lzdGVtIGZyb20gYnJl
+YWtpbmcgdGhlIHNpZ25hdHVyZS4gTm90ZQp0aGF0IGFsbCBvdGhlciBQR1AgdmVy
+c2lvbnMgZG8gaXQgdGhpcyB3YXkgdG9vLiAgRW5hYmxlZCBieQpkZWZhdWx0LiBA
+b3B0aW9uey0tbm8tZXNjYXBlLWZyb20tbGluZXN9IGRpc2FibGVzIHRoaXMgb3B0
+aW9uLgoKQGl0ZW0gLS1wYXNzcGhyYXNlLXJlcGVhdCBAY29kZXtufQpAb3BpbmRl
+eCBwYXNzcGhyYXNlLXJlcGVhdApTcGVjaWZ5IGhvdyBtYW55IHRpbWVzIEBjb21t
+YW5ke0BncGduYW1lfSB3aWxsIHJlcXVlc3QgYSBuZXcKcGFzc3BocmFzZSBiZSBy
+ZXBlYXRlZC4gIFRoaXMgaXMgdXNlZnVsIGZvciBoZWxwaW5nIG1lbW9yaXplIGEK
+cGFzc3BocmFzZS4gIERlZmF1bHRzIHRvIDEgcmVwZXRpdGlvbi4KCkBpdGVtIC0t
+cGFzc3BocmFzZS1mZCBAY29kZXtufQpAb3BpbmRleCBwYXNzcGhyYXNlLWZkClJl
+YWQgdGhlIHBhc3NwaHJhc2UgZnJvbSBmaWxlIGRlc2NyaXB0b3IgQGNvZGV7bn0u
+IE9ubHkgdGhlIGZpcnN0IGxpbmUKd2lsbCBiZSByZWFkIGZyb20gZmlsZSBkZXNj
+cmlwdG9yIEBjb2Rle259LiBJZiB5b3UgdXNlIDAgZm9yIEBjb2Rle259LAp0aGUg
+cGFzc3BocmFzZSB3aWxsIGJlIHJlYWQgZnJvbSBTVERJTi4gVGhpcyBjYW4gb25s
+eSBiZSB1c2VkIGlmIG9ubHkKb25lIHBhc3NwaHJhc2UgaXMgc3VwcGxpZWQuCgpO
+b3RlIHRoYXQgdGhpcyBwYXNzcGhyYXNlIGlzIG9ubHkgdXNlZCBpZiB0aGUgb3B0
+aW9uIEBvcHRpb257LS1iYXRjaH0KaGFzIGFsc28gYmVlbiBnaXZlbi4gIFRoaXMg
+aXMgZGlmZmVyZW50IGZyb20gR251UEcgdmVyc2lvbiAxLnguCgpAaXRlbSAtLXBh
+c3NwaHJhc2UtZmlsZSBAY29kZXtmaWxlfQpAb3BpbmRleCBwYXNzcGhyYXNlLWZp
+bGUKUmVhZCB0aGUgcGFzc3BocmFzZSBmcm9tIGZpbGUgQGNvZGV7ZmlsZX0uIE9u
+bHkgdGhlIGZpcnN0IGxpbmUgd2lsbApiZSByZWFkIGZyb20gZmlsZSBAY29kZXtm
+aWxlfS4gVGhpcyBjYW4gb25seSBiZSB1c2VkIGlmIG9ubHkgb25lCnBhc3NwaHJh
+c2UgaXMgc3VwcGxpZWQuIE9idmlvdXNseSwgYSBwYXNzcGhyYXNlIHN0b3JlZCBp
+biBhIGZpbGUgaXMKb2YgcXVlc3Rpb25hYmxlIHNlY3VyaXR5IGlmIG90aGVyIHVz
+ZXJzIGNhbiByZWFkIHRoaXMgZmlsZS4gRG9uJ3QgdXNlCnRoaXMgb3B0aW9uIGlm
+IHlvdSBjYW4gYXZvaWQgaXQuCk5vdGUgdGhhdCB0aGlzIHBhc3NwaHJhc2UgaXMg
+b25seSB1c2VkIGlmIHRoZSBvcHRpb24gQG9wdGlvbnstLWJhdGNofQpoYXMgYWxz
+byBiZWVuIGdpdmVuLiAgVGhpcyBpcyBkaWZmZXJlbnQgZnJvbSBHbnVQRyB2ZXJz
+aW9uIDEueC4KCkBpdGVtIC0tcGFzc3BocmFzZSBAY29kZXtzdHJpbmd9CkBvcGlu
+ZGV4IHBhc3NwaHJhc2UKVXNlIEBjb2Rle3N0cmluZ30gYXMgdGhlIHBhc3NwaHJh
+c2UuIFRoaXMgY2FuIG9ubHkgYmUgdXNlZCBpZiBvbmx5IG9uZQpwYXNzcGhyYXNl
+IGlzIHN1cHBsaWVkLiBPYnZpb3VzbHksIHRoaXMgaXMgb2YgdmVyeSBxdWVzdGlv
+bmFibGUKc2VjdXJpdHkgb24gYSBtdWx0aS11c2VyIHN5c3RlbS4gRG9uJ3QgdXNl
+IHRoaXMgb3B0aW9uIGlmIHlvdSBjYW4KYXZvaWQgaXQuCk5vdGUgdGhhdCB0aGlz
+IHBhc3NwaHJhc2UgaXMgb25seSB1c2VkIGlmIHRoZSBvcHRpb24gQG9wdGlvbnst
+LWJhdGNofQpoYXMgYWxzbyBiZWVuIGdpdmVuLiAgVGhpcyBpcyBkaWZmZXJlbnQg
+ZnJvbSBHbnVQRyB2ZXJzaW9uIDEueC4KCkBpdGVtIC0tcGluZW50cnktbW9kZSBA
+Y29kZXttb2RlfQpAb3BpbmRleCBwaW5lbnRyeS1tb2RlClNldCB0aGUgcGluZW50
+cnkgbW9kZSB0byBAY29kZXttb2RlfS4gIEFsbG93ZWQgdmFsdWVzIGZvciBAY29k
+ZXttb2RlfQphcmU6CkB0YWJsZSBAYXNpcwogIEBpdGVtIGRlZmF1bHQKICBVc2Ug
+dGhlIGRlZmF1bHQgb2YgdGhlIGFnZW50LCB3aGljaCBpcyBAY29kZXthc2t9Lgog
+IEBpdGVtIGFzawogIEZvcmNlIHRoZSB1c2Ugb2YgdGhlIFBpbmVudHJ5LgogIEBp
+dGVtIGNhbmNlbAogIEVtdWxhdGUgdXNlIG9mIFBpbmVudHJ5J3MgY2FuY2VsIGJ1
+dHRvbi4KICBAaXRlbSBlcnJvcgogIFJldHVybiBhIFBpbmVudHJ5IGVycm9yIChg
+YE5vIFBpbmVudHJ5JycpLgogIEBpdGVtIGxvb3BiYWNrCiAgUmVkaXJlY3QgUGlu
+ZW50cnkgcXVlcmllcyB0byB0aGUgY2FsbGVyLiAgTm90ZSB0aGF0IGluIGNvbnRy
+YXN0IHRvCiAgUGluZW50cnkgdGhlIHVzZXIgaXMgbm90IHByb21wdGVkIGFnYWlu
+IGlmIGhlIGVudGVycyBhIGJhZCBwYXNzd29yZC4KQGVuZCB0YWJsZQoKQGl0ZW0g
+LS1jb21tYW5kLWZkIEBjb2Rle259CkBvcGluZGV4IGNvbW1hbmQtZmQKVGhpcyBp
+cyBhIHJlcGxhY2VtZW50IGZvciB0aGUgZGVwcmVjYXRlZCBzaGFyZWQtbWVtb3J5
+IElQQyBtb2RlLgpJZiB0aGlzIG9wdGlvbiBpcyBlbmFibGVkLCB1c2VyIGlucHV0
+IG9uIHF1ZXN0aW9ucyBpcyBub3QgZXhwZWN0ZWQKZnJvbSB0aGUgVFRZIGJ1dCBm
+cm9tIHRoZSBnaXZlbiBmaWxlIGRlc2NyaXB0b3IuIEl0IHNob3VsZCBiZSB1c2Vk
+CnRvZ2V0aGVyIHdpdGggQG9wdGlvbnstLXN0YXR1cy1mZH0uIFNlZSB0aGUgZmls
+ZSBkb2MvREVUQUlMUyBpbiB0aGUgc291cmNlCmRpc3RyaWJ1dGlvbiBmb3IgZGV0
+YWlscyBvbiBob3cgdG8gdXNlIGl0LgoKQGl0ZW0gLS1jb21tYW5kLWZpbGUgQGNv
+ZGV7ZmlsZX0KQG9waW5kZXggY29tbWFuZC1maWxlClNhbWUgYXMgQG9wdGlvbnst
+LWNvbW1hbmQtZmR9LCBleGNlcHQgdGhlIGNvbW1hbmRzIGFyZSByZWFkIG91dCBv
+ZiBmaWxlCkBjb2Rle2ZpbGV9CgpAaXRlbSAtLWFsbG93LW5vbi1zZWxmc2lnbmVk
+LXVpZApAaXRlbXggLS1uby1hbGxvdy1ub24tc2VsZnNpZ25lZC11aWQKQG9waW5k
+ZXggYWxsb3ctbm9uLXNlbGZzaWduZWQtdWlkCkFsbG93IHRoZSBpbXBvcnQgYW5k
+IHVzZSBvZiBrZXlzIHdpdGggdXNlciBJRHMgd2hpY2ggYXJlIG5vdApzZWxmLXNp
+Z25lZC4gVGhpcyBpcyBub3QgcmVjb21tZW5kZWQsIGFzIGEgbm9uIHNlbGYtc2ln
+bmVkIHVzZXIgSUQgaXMKdHJpdmlhbCB0byBmb3JnZS4gQG9wdGlvbnstLW5vLWFs
+bG93LW5vbi1zZWxmc2lnbmVkLXVpZH0gZGlzYWJsZXMuCgpAaXRlbSAtLWFsbG93
+LWZyZWVmb3JtLXVpZApAb3BpbmRleCBhbGxvdy1mcmVlZm9ybS11aWQKRGlzYWJs
+ZSBhbGwgY2hlY2tzIG9uIHRoZSBmb3JtIG9mIHRoZSB1c2VyIElEIHdoaWxlIGdl
+bmVyYXRpbmcgYSBuZXcKb25lLiBUaGlzIG9wdGlvbiBzaG91bGQgb25seSBiZSB1
+c2VkIGluIHZlcnkgc3BlY2lhbCBlbnZpcm9ubWVudHMgYXMKaXQgZG9lcyBub3Qg
+ZW5zdXJlIHRoZSBkZS1mYWN0byBzdGFuZGFyZCBmb3JtYXQgb2YgdXNlciBJRHMu
+CgpAaXRlbSAtLWlnbm9yZS10aW1lLWNvbmZsaWN0CkBvcGluZGV4IGlnbm9yZS10
+aW1lLWNvbmZsaWN0CkdudVBHIG5vcm1hbGx5IGNoZWNrcyB0aGF0IHRoZSB0aW1l
+c3RhbXBzIGFzc29jaWF0ZWQgd2l0aCBrZXlzIGFuZApzaWduYXR1cmVzIGhhdmUg
+cGxhdXNpYmxlIHZhbHVlcy4gSG93ZXZlciwgc29tZXRpbWVzIGEgc2lnbmF0dXJl
+CnNlZW1zIHRvIGJlIG9sZGVyIHRoYW4gdGhlIGtleSBkdWUgdG8gY2xvY2sgcHJv
+YmxlbXMuIFRoaXMgb3B0aW9uCm1ha2VzIHRoZXNlIGNoZWNrcyBqdXN0IGEgd2Fy
+bmluZy4gU2VlIGFsc28gQG9wdGlvbnstLWlnbm9yZS12YWxpZC1mcm9tfSBmb3IK
+dGltZXN0YW1wIGlzc3VlcyBvbiBzdWJrZXlzLgoKQGl0ZW0gLS1pZ25vcmUtdmFs
+aWQtZnJvbQpAb3BpbmRleCBpZ25vcmUtdmFsaWQtZnJvbQpHbnVQRyBub3JtYWxs
+eSBkb2VzIG5vdCBzZWxlY3QgYW5kIHVzZSBzdWJrZXlzIGNyZWF0ZWQgaW4gdGhl
+IGZ1dHVyZS4KVGhpcyBvcHRpb24gYWxsb3dzIHRoZSB1c2Ugb2Ygc3VjaCBrZXlz
+IGFuZCB0aHVzIGV4aGliaXRzIHRoZQpwcmUtMS4wLjcgYmVoYXZpb3VyLiBZb3Ug
+c2hvdWxkIG5vdCB1c2UgdGhpcyBvcHRpb24gdW5sZXNzIHRoZXJlCmlzIHNvbWUg
+Y2xvY2sgcHJvYmxlbS4gU2VlIGFsc28gQG9wdGlvbnstLWlnbm9yZS10aW1lLWNv
+bmZsaWN0fSBmb3IgdGltZXN0YW1wCmlzc3VlcyB3aXRoIHNpZ25hdHVyZXMuCgpA
+aXRlbSAtLWlnbm9yZS1jcmMtZXJyb3IKQG9waW5kZXggaWdub3JlLWNyYy1lcnJv
+cgpUaGUgQVNDSUkgYXJtb3IgdXNlZCBieSBPcGVuUEdQIGlzIHByb3RlY3RlZCBi
+eSBhIENSQyBjaGVja3N1bSBhZ2FpbnN0CnRyYW5zbWlzc2lvbiBlcnJvcnMuIE9j
+Y2FzaW9uYWxseSB0aGUgQ1JDIGdldHMgbWFuZ2xlZCBzb21ld2hlcmUgb24KdGhl
+IHRyYW5zbWlzc2lvbiBjaGFubmVsIGJ1dCB0aGUgYWN0dWFsIGNvbnRlbnQgKHdo
+aWNoIGlzIHByb3RlY3RlZCBieQp0aGUgT3BlblBHUCBwcm90b2NvbCBhbnl3YXkp
+IGlzIHN0aWxsIG9rYXkuIFRoaXMgb3B0aW9uIGFsbG93cyBHbnVQRwp0byBpZ25v
+cmUgQ1JDIGVycm9ycy4KCkBpdGVtIC0taWdub3JlLW1kYy1lcnJvcgpAb3BpbmRl
+eCBpZ25vcmUtbWRjLWVycm9yClRoaXMgb3B0aW9uIGNoYW5nZXMgYSBNREMgaW50
+ZWdyaXR5IHByb3RlY3Rpb24gZmFpbHVyZSBpbnRvIGEgd2FybmluZy4KVGhpcyBj
+YW4gYmUgdXNlZnVsIGlmIGEgbWVzc2FnZSBpcyBwYXJ0aWFsbHkgY29ycnVwdCwg
+YnV0IGl0IGlzCm5lY2Vzc2FyeSB0byBnZXQgYXMgbXVjaCBkYXRhIGFzIHBvc3Np
+YmxlIG91dCBvZiB0aGUgY29ycnVwdCBtZXNzYWdlLgpIb3dldmVyLCBiZSBhd2Fy
+ZSB0aGF0IGEgTURDIHByb3RlY3Rpb24gZmFpbHVyZSBtYXkgYWxzbyBtZWFuIHRo
+YXQgdGhlCm1lc3NhZ2Ugd2FzIHRhbXBlcmVkIHdpdGggaW50ZW50aW9uYWxseSBi
+eSBhbiBhdHRhY2tlci4KCkBpdGVtIC0tYWxsb3ctd2Vhay1kaWdlc3QtYWxnb3MK
+QG9waW5kZXggYWxsb3ctd2Vhay1kaWdlc3QtYWxnb3MKU2lnbmF0dXJlcyBtYWRl
+IHdpdGgga25vd24td2VhayBkaWdlc3QgYWxnb3JpdGhtcyBhcmUgbm9ybWFsbHkK
+cmVqZWN0ZWQgd2l0aCBhbiBgYGludmFsaWQgZGlnZXN0IGFsZ29yaXRobScnIG1l
+c3NhZ2UuICBUaGlzIG9wdGlvbgphbGxvd3MgdGhlIHZlcmlmaWNhdGlvbiBvZiBz
+aWduYXR1cmVzIG1hZGUgd2l0aCBzdWNoIHdlYWsgYWxnb3JpdGhtcy4KTUQ1IGlz
+IHRoZSBvbmx5IGRpZ2VzdCBhbGdvcml0aG0gY29uc2lkZXJlZCB3ZWFrIGJ5IGRl
+ZmF1bHQuICBTZWUgYWxzbwpAb3B0aW9uey0td2Vhay1kaWdlc3R9IHRvIHJlamVj
+dCBvdGhlciBkaWdlc3QgYWxnb3JpdGhtcy4KCkBpdGVtIC0td2Vhay1kaWdlc3Qg
+QGNvZGV7bmFtZX0KQG9waW5kZXggd2Vhay1kaWdlc3QKVHJlYXQgdGhlIHNwZWNp
+ZmllZCBkaWdlc3QgYWxnb3JpdGhtIGFzIHdlYWsuICBTaWduYXR1cmVzIG1hZGUg
+b3Zlcgp3ZWFrIGRpZ2VzdHMgYWxnb3JpdGhtcyBhcmUgbm9ybWFsbHkgcmVqZWN0
+ZWQuIFRoaXMgb3B0aW9uIGNhbiBiZQpzdXBwbGllZCBtdWx0aXBsZSB0aW1lcyBp
+ZiBtdWx0aXBsZSBhbGdvcml0aG1zIHNob3VsZCBiZSBjb25zaWRlcmVkCndlYWsu
+ICBTZWUgYWxzbyBAb3B0aW9uey0tYWxsb3ctd2Vhay1kaWdlc3QtYWxnb3N9IHRv
+IGRpc2FibGUKcmVqZWN0aW9uIG9mIHdlYWsgZGlnZXN0cy4gIE1ENSBpcyBhbHdh
+eXMgY29uc2lkZXJlZCB3ZWFrLCBhbmQgZG9lcwpub3QgbmVlZCB0byBiZSBsaXN0
+ZWQgZXhwbGljaXRseS4KCkBpdGVtIC0tbm8tZGVmYXVsdC1rZXlyaW5nCkBvcGlu
+ZGV4IG5vLWRlZmF1bHQta2V5cmluZwpEbyBub3QgYWRkIHRoZSBkZWZhdWx0IGtl
+eXJpbmdzIHRvIHRoZSBsaXN0IG9mIGtleXJpbmdzLiBOb3RlIHRoYXQKR251UEcg
+d2lsbCBub3Qgb3BlcmF0ZSB3aXRob3V0IGFueSBrZXlyaW5ncywgc28gaWYgeW91
+IHVzZSB0aGlzIG9wdGlvbgphbmQgZG8gbm90IHByb3ZpZGUgYWx0ZXJuYXRlIGtl
+eXJpbmdzIHZpYSBAb3B0aW9uey0ta2V5cmluZ30gb3IKQG9wdGlvbnstLXNlY3Jl
+dC1rZXlyaW5nfSwgdGhlbiBHbnVQRyB3aWxsIHN0aWxsIHVzZSB0aGUgZGVmYXVs
+dCBwdWJsaWMgb3IKc2VjcmV0IGtleXJpbmdzLgoKQGl0ZW0gLS1za2lwLXZlcmlm
+eQpAb3BpbmRleCBza2lwLXZlcmlmeQpTa2lwIHRoZSBzaWduYXR1cmUgdmVyaWZp
+Y2F0aW9uIHN0ZXAuIFRoaXMgbWF5IGJlCnVzZWQgdG8gbWFrZSB0aGUgZGVjcnlw
+dGlvbiBmYXN0ZXIgaWYgdGhlIHNpZ25hdHVyZQp2ZXJpZmljYXRpb24gaXMgbm90
+IG5lZWRlZC4KCkBpdGVtIC0td2l0aC1rZXktZGF0YQpAb3BpbmRleCB3aXRoLWtl
+eS1kYXRhClByaW50IGtleSBsaXN0aW5ncyBkZWxpbWl0ZWQgYnkgY29sb25zIChs
+aWtlIEBvcHRpb257LS13aXRoLWNvbG9uc30pIGFuZApwcmludCB0aGUgcHVibGlj
+IGtleSBkYXRhLgoKQGl0ZW0gLS1mYXN0LWxpc3QtbW9kZQpAb3BpbmRleCBmYXN0
+LWxpc3QtbW9kZQpDaGFuZ2VzIHRoZSBvdXRwdXQgb2YgdGhlIGxpc3QgY29tbWFu
+ZHMgdG8gd29yayBmYXN0ZXI7IHRoaXMgaXMgYWNoaWV2ZWQKYnkgbGVhdmluZyBz
+b21lIHBhcnRzIGVtcHR5LiBTb21lIGFwcGxpY2F0aW9ucyBkb24ndCBuZWVkIHRo
+ZSB1c2VyIElECmFuZCB0aGUgdHJ1c3QgaW5mb3JtYXRpb24gZ2l2ZW4gaW4gdGhl
+IGxpc3RpbmdzLiBCeSB1c2luZyB0aGlzIG9wdGlvbnMKdGhleSBjYW4gZ2V0IGEg
+ZmFzdGVyIGxpc3RpbmcuIFRoZSBleGFjdCBiZWhhdmlvdXIgb2YgdGhpcyBvcHRp
+b24gbWF5CmNoYW5nZSBpbiBmdXR1cmUgdmVyc2lvbnMuICBJZiB5b3UgYXJlIG1p
+c3Npbmcgc29tZSBpbmZvcm1hdGlvbiwgZG9uJ3QKdXNlIHRoaXMgb3B0aW9uLgoK
+QGl0ZW0gLS1uby1saXRlcmFsCkBvcGluZGV4IG5vLWxpdGVyYWwKVGhpcyBpcyBu
+b3QgZm9yIG5vcm1hbCB1c2UuIFVzZSB0aGUgc291cmNlIHRvIHNlZSBmb3Igd2hh
+dCBpdCBtaWdodCBiZSB1c2VmdWwuCgpAaXRlbSAtLXNldC1maWxlc2l6ZQpAb3Bp
+bmRleCBzZXQtZmlsZXNpemUKVGhpcyBpcyBub3QgZm9yIG5vcm1hbCB1c2UuIFVz
+ZSB0aGUgc291cmNlIHRvIHNlZSBmb3Igd2hhdCBpdCBtaWdodCBiZSB1c2VmdWwu
+CgpAaXRlbSAtLXNob3ctc2Vzc2lvbi1rZXkKQG9waW5kZXggc2hvdy1zZXNzaW9u
+LWtleQpEaXNwbGF5IHRoZSBzZXNzaW9uIGtleSB1c2VkIGZvciBvbmUgbWVzc2Fn
+ZS4gU2VlCkBvcHRpb257LS1vdmVycmlkZS1zZXNzaW9uLWtleX0gZm9yIHRoZSBj
+b3VudGVycGFydCBvZiB0aGlzIG9wdGlvbi4KCldlIHRoaW5rIHRoYXQgS2V5IEVz
+Y3JvdyBpcyBhIEJhZCBUaGluZzsgaG93ZXZlciB0aGUgdXNlciBzaG91bGQgaGF2
+ZQp0aGUgZnJlZWRvbSB0byBkZWNpZGUgd2hldGhlciB0byBnbyB0byBwcmlzb24g
+b3IgdG8gcmV2ZWFsIHRoZSBjb250ZW50Cm9mIG9uZSBzcGVjaWZpYyBtZXNzYWdl
+IHdpdGhvdXQgY29tcHJvbWlzaW5nIGFsbCBtZXNzYWdlcyBldmVyCmVuY3J5cHRl
+ZCBmb3Igb25lIHNlY3JldCBrZXkuCgpZb3UgY2FuIGFsc28gdXNlIHRoaXMgb3B0
+aW9uIGlmIHlvdSByZWNlaXZlIGFuIGVuY3J5cHRlZCBtZXNzYWdlIHdoaWNoCmlz
+IGFidXNpdmUgb3Igb2ZmZW5zaXZlLCB0byBwcm92ZSB0byB0aGUgYWRtaW5pc3Ry
+YXRvcnMgb2YgdGhlCm1lc3NhZ2luZyBzeXN0ZW0gdGhhdCB0aGUgY2lwaGVydGV4
+dCB0cmFuc21pdHRlZCBjb3JyZXNwb25kcyB0byBhbgppbmFwcHJvcHJpYXRlIHBs
+YWludGV4dCBzbyB0aGV5IGNhbiB0YWtlIGFjdGlvbiBhZ2FpbnN0IHRoZSBvZmZl
+bmRpbmcKdXNlci4KCkBpdGVtIC0tb3ZlcnJpZGUtc2Vzc2lvbi1rZXkgQGNvZGV7
+c3RyaW5nfQpAb3BpbmRleCBvdmVycmlkZS1zZXNzaW9uLWtleQpEb24ndCB1c2Ug
+dGhlIHB1YmxpYyBrZXkgYnV0IHRoZSBzZXNzaW9uIGtleSBAY29kZXtzdHJpbmd9
+LiBUaGUgZm9ybWF0Cm9mIHRoaXMgc3RyaW5nIGlzIHRoZSBzYW1lIGFzIHRoZSBv
+bmUgcHJpbnRlZCBieQpAb3B0aW9uey0tc2hvdy1zZXNzaW9uLWtleX0uIFRoaXMg
+b3B0aW9uIGlzIG5vcm1hbGx5IG5vdCB1c2VkIGJ1dCBjb21lcwpoYW5keSBpbiBj
+YXNlIHNvbWVvbmUgZm9yY2VzIHlvdSB0byByZXZlYWwgdGhlIGNvbnRlbnQgb2Yg
+YW4gZW5jcnlwdGVkCm1lc3NhZ2U7IHVzaW5nIHRoaXMgb3B0aW9uIHlvdSBjYW4g
+ZG8gdGhpcyB3aXRob3V0IGhhbmRpbmcgb3V0IHRoZQpzZWNyZXQga2V5LgoKQGl0
+ZW0gLS1hc2stc2lnLWV4cGlyZQpAaXRlbXggLS1uby1hc2stc2lnLWV4cGlyZQpA
+b3BpbmRleCBhc2stc2lnLWV4cGlyZQpXaGVuIG1ha2luZyBhIGRhdGEgc2lnbmF0
+dXJlLCBwcm9tcHQgZm9yIGFuIGV4cGlyYXRpb24gdGltZS4gSWYgdGhpcwpvcHRp
+b24gaXMgbm90IHNwZWNpZmllZCwgdGhlIGV4cGlyYXRpb24gdGltZSBzZXQgdmlh
+CkBvcHRpb257LS1kZWZhdWx0LXNpZy1leHBpcmV9IGlzIHVzZWQuIEBvcHRpb257
+LS1uby1hc2stc2lnLWV4cGlyZX0KZGlzYWJsZXMgdGhpcyBvcHRpb24uCgpAaXRl
+bSAtLWRlZmF1bHQtc2lnLWV4cGlyZQpAb3BpbmRleCBkZWZhdWx0LXNpZy1leHBp
+cmUKVGhlIGRlZmF1bHQgZXhwaXJhdGlvbiB0aW1lIHRvIHVzZSBmb3Igc2lnbmF0
+dXJlIGV4cGlyYXRpb24uIFZhbGlkCnZhbHVlcyBhcmUgIjAiIGZvciBubyBleHBp
+cmF0aW9uLCBhIG51bWJlciBmb2xsb3dlZCBieSB0aGUgbGV0dGVyIGQKKGZvciBk
+YXlzKSwgdyAoZm9yIHdlZWtzKSwgbSAoZm9yIG1vbnRocyksIG9yIHkgKGZvciB5
+ZWFycykgKGZvcgpleGFtcGxlICIybSIgZm9yIHR3byBtb250aHMsIG9yICI1eSIg
+Zm9yIGZpdmUgeWVhcnMpLCBvciBhbiBhYnNvbHV0ZQpkYXRlIGluIHRoZSBmb3Jt
+IFlZWVktTU0tREQuIERlZmF1bHRzIHRvICIwIi4KCkBpdGVtIC0tYXNrLWNlcnQt
+ZXhwaXJlCkBpdGVteCAtLW5vLWFzay1jZXJ0LWV4cGlyZQpAb3BpbmRleCBhc2st
+Y2VydC1leHBpcmUKV2hlbiBtYWtpbmcgYSBrZXkgc2lnbmF0dXJlLCBwcm9tcHQg
+Zm9yIGFuIGV4cGlyYXRpb24gdGltZS4gSWYgdGhpcwpvcHRpb24gaXMgbm90IHNw
+ZWNpZmllZCwgdGhlIGV4cGlyYXRpb24gdGltZSBzZXQgdmlhCkBvcHRpb257LS1k
+ZWZhdWx0LWNlcnQtZXhwaXJlfSBpcyB1c2VkLiBAb3B0aW9uey0tbm8tYXNrLWNl
+cnQtZXhwaXJlfQpkaXNhYmxlcyB0aGlzIG9wdGlvbi4KCkBpdGVtIC0tZGVmYXVs
+dC1jZXJ0LWV4cGlyZQpAb3BpbmRleCBkZWZhdWx0LWNlcnQtZXhwaXJlClRoZSBk
+ZWZhdWx0IGV4cGlyYXRpb24gdGltZSB0byB1c2UgZm9yIGtleSBzaWduYXR1cmUg
+ZXhwaXJhdGlvbi4KVmFsaWQgdmFsdWVzIGFyZSAiMCIgZm9yIG5vIGV4cGlyYXRp
+b24sIGEgbnVtYmVyIGZvbGxvd2VkIGJ5IHRoZQpsZXR0ZXIgZCAoZm9yIGRheXMp
+LCB3IChmb3Igd2Vla3MpLCBtIChmb3IgbW9udGhzKSwgb3IgeSAoZm9yIHllYXJz
+KQooZm9yIGV4YW1wbGUgIjJtIiBmb3IgdHdvIG1vbnRocywgb3IgIjV5IiBmb3Ig
+Zml2ZSB5ZWFycyksIG9yIGFuCmFic29sdXRlIGRhdGUgaW4gdGhlIGZvcm0gWVlZ
+WS1NTS1ERC4gRGVmYXVsdHMgdG8gIjAiLgoKQGl0ZW0gLS1hbGxvdy1zZWNyZXQt
+a2V5LWltcG9ydApAb3BpbmRleCBhbGxvdy1zZWNyZXQta2V5LWltcG9ydApUaGlz
+IGlzIGFuIG9ic29sZXRlIG9wdGlvbiBhbmQgaXMgbm90IHVzZWQgYW55d2hlcmUu
+CgpAaXRlbSAtLWFsbG93LW11bHRpcGxlLW1lc3NhZ2VzCkBpdGVtIC0tbm8tYWxs
+b3ctbXVsdGlwbGUtbWVzc2FnZXMKQG9waW5kZXggYWxsb3ctbXVsdGlwbGUtbWVz
+c2FnZXMKQWxsb3cgcHJvY2Vzc2luZyBvZiBtdWx0aXBsZSBPcGVuUEdQIG1lc3Nh
+Z2VzIGNvbnRhaW5lZCBpbiBhIHNpbmdsZSBmaWxlCm9yIHN0cmVhbS4gIFNvbWUg
+cHJvZ3JhbXMgdGhhdCBjYWxsIEdQRyBhcmUgbm90IHByZXBhcmVkIHRvIGRlYWwg
+d2l0aAptdWx0aXBsZSBtZXNzYWdlcyBiZWluZyBwcm9jZXNzZWQgdG9nZXRoZXIs
+IHNvIHRoaXMgb3B0aW9uIGRlZmF1bHRzIHRvCm5vLiAgTm90ZSB0aGF0IHZlcnNp
+b25zIG9mIEdQRyBwcmlvciB0byAxLjQuNyBhbHdheXMgYWxsb3dlZCBtdWx0aXBs
+ZQptZXNzYWdlcy4KCldhcm5pbmc6IERvIG5vdCB1c2UgdGhpcyBvcHRpb24gdW5s
+ZXNzIHlvdSBuZWVkIGl0IGFzIGEgdGVtcG9yYXJ5Cndvcmthcm91bmQhCgoKQGl0
+ZW0gLS1lbmFibGUtc3BlY2lhbC1maWxlbmFtZXMKQG9waW5kZXggZW5hYmxlLXNw
+ZWNpYWwtZmlsZW5hbWVzClRoaXMgb3B0aW9ucyBlbmFibGVzIGEgbW9kZSBpbiB3
+aGljaCBmaWxlbmFtZXMgb2YgdGhlIGZvcm0KQGZpbGV7LSZufSwgd2hlcmUgbiBp
+cyBhIG5vbi1uZWdhdGl2ZSBkZWNpbWFsIG51bWJlciwKcmVmZXIgdG8gdGhlIGZp
+bGUgZGVzY3JpcHRvciBuIGFuZCBub3QgdG8gYSBmaWxlIHdpdGggdGhhdCBuYW1l
+LgoKQGl0ZW0gLS1uby1leHBlbnNpdmUtdHJ1c3QtY2hlY2tzCkBvcGluZGV4IG5v
+LWV4cGVuc2l2ZS10cnVzdC1jaGVja3MKRXhwZXJpbWVudGFsIHVzZSBvbmx5LgoK
+QGl0ZW0gLS1wcmVzZXJ2ZS1wZXJtaXNzaW9ucwpAb3BpbmRleCBwcmVzZXJ2ZS1w
+ZXJtaXNzaW9ucwpEb24ndCBjaGFuZ2UgdGhlIHBlcm1pc3Npb25zIG9mIGEgc2Vj
+cmV0IGtleXJpbmcgYmFjayB0byB1c2VyCnJlYWQvd3JpdGUgb25seS4gVXNlIHRo
+aXMgb3B0aW9uIG9ubHkgaWYgeW91IHJlYWxseSBrbm93IHdoYXQgeW91IGFyZSBk
+b2luZy4KCkBpdGVtIC0tZGVmYXVsdC1wcmVmZXJlbmNlLWxpc3QgQGNvZGV7c3Ry
+aW5nfQpAb3BpbmRleCBkZWZhdWx0LXByZWZlcmVuY2UtbGlzdApTZXQgdGhlIGxp
+c3Qgb2YgZGVmYXVsdCBwcmVmZXJlbmNlcyB0byBAY29kZXtzdHJpbmd9LiBUaGlz
+IHByZWZlcmVuY2UKbGlzdCBpcyB1c2VkIGZvciBuZXcga2V5cyBhbmQgYmVjb21l
+cyB0aGUgZGVmYXVsdCBmb3IgInNldHByZWYiIGluIHRoZQplZGl0IG1lbnUuCgpA
+aXRlbSAtLWRlZmF1bHQta2V5c2VydmVyLXVybCBAY29kZXtuYW1lfQpAb3BpbmRl
+eCBkZWZhdWx0LWtleXNlcnZlci11cmwKU2V0IHRoZSBkZWZhdWx0IGtleXNlcnZl
+ciBVUkwgdG8gQGNvZGV7bmFtZX0uIFRoaXMga2V5c2VydmVyIHdpbGwgYmUKdXNl
+ZCBhcyB0aGUga2V5c2VydmVyIFVSTCB3aGVuIHdyaXRpbmcgYSBuZXcgc2VsZi1z
+aWduYXR1cmUgb24gYSBrZXksCndoaWNoIGluY2x1ZGVzIGtleSBnZW5lcmF0aW9u
+IGFuZCBjaGFuZ2luZyBwcmVmZXJlbmNlcy4KCkBpdGVtIC0tbGlzdC1jb25maWcK
+QG9waW5kZXggbGlzdC1jb25maWcKRGlzcGxheSB2YXJpb3VzIGludGVybmFsIGNv
+bmZpZ3VyYXRpb24gcGFyYW1ldGVycyBvZiBHbnVQRy4gVGhpcyBvcHRpb24KaXMg
+aW50ZW5kZWQgZm9yIGV4dGVybmFsIHByb2dyYW1zIHRoYXQgY2FsbCBHbnVQRyB0
+byBwZXJmb3JtIHRhc2tzLCBhbmQKaXMgdGh1cyBub3QgZ2VuZXJhbGx5IHVzZWZ1
+bC4gU2VlIHRoZSBmaWxlIEBmaWxle2RvYy9ERVRBSUxTfSBpbiB0aGUKc291cmNl
+IGRpc3RyaWJ1dGlvbiBmb3IgdGhlIGRldGFpbHMgb2Ygd2hpY2ggY29uZmlndXJh
+dGlvbiBpdGVtcyBtYXkgYmUKbGlzdGVkLiBAb3B0aW9uey0tbGlzdC1jb25maWd9
+IGlzIG9ubHkgdXNhYmxlIHdpdGgKQG9wdGlvbnstLXdpdGgtY29sb25zfSBzZXQu
+CgpAaXRlbSAtLWxpc3QtZ2NyeXB0LWNvbmZpZwpAb3BpbmRleCBsaXN0LWdjcnlw
+dC1jb25maWcKRGlzcGxheSB2YXJpb3VzIGludGVybmFsIGNvbmZpZ3VyYXRpb24g
+cGFyYW1ldGVycyBvZiBMaWJnY3J5cHQuCgpAaXRlbSAtLWdwZ2NvbmYtbGlzdApA
+b3BpbmRleCBncGdjb25mLWxpc3QKVGhpcyBjb21tYW5kIGlzIHNpbWlsYXIgdG8g
+QG9wdGlvbnstLWxpc3QtY29uZmlnfSBidXQgaW4gZ2VuZXJhbCBvbmx5CmludGVy
+bmFsbHkgdXNlZCBieSB0aGUgQGNvbW1hbmR7Z3BnY29uZn0gdG9vbC4KCkBpdGVt
+IC0tZ3BnY29uZi10ZXN0CkBvcGluZGV4IGdwZ2NvbmYtdGVzdApUaGlzIGlzIG1v
+cmUgb3IgbGVzcyBkdW1teSBhY3Rpb24uICBIb3dldmVyIGl0IHBhcnNlcyB0aGUg
+Y29uZmlndXJhdGlvbgpmaWxlIGFuZCByZXR1cm5zIHdpdGggZmFpbHVyZSBpZiB0
+aGUgY29uZmlndXJhdGlvbiBmaWxlIHdvdWxkIHByZXZlbnQKQGNvbW1hbmR7Z3Bn
+fSBmcm9tIHN0YXJ0dXAuICBUaHVzIGl0IG1heSBiZSB1c2VkIHRvIHJ1biBhIHN5
+bnRheCBjaGVjawpvbiB0aGUgY29uZmlndXJhdGlvbiBmaWxlLgoKQGVuZCB0YWJs
+ZQoKQGMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgpAYyAqKioqKioq
+IERlcHJlY2F0ZWQgKioqKioqKioqKioqCkBjICoqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioKQG5vZGUgRGVwcmVjYXRlZCBPcHRpb25zCkBzdWJzZWN0aW9u
+IERlcHJlY2F0ZWQgb3B0aW9ucwoKQHRhYmxlIEBnbnVwZ3RhYm9wdAoKQGl0ZW0g
+LS1zaG93LXBob3RvcwpAaXRlbXggLS1uby1zaG93LXBob3RvcwpAb3BpbmRleCBz
+aG93LXBob3RvcwpDYXVzZXMgQG9wdGlvbnstLWxpc3Qta2V5c30sIEBvcHRpb257
+LS1saXN0LXNpZ3N9LApAb3B0aW9uey0tbGlzdC1wdWJsaWMta2V5c30sIEBvcHRp
+b257LS1saXN0LXNlY3JldC1rZXlzfSwgYW5kIHZlcmlmeWluZwphIHNpZ25hdHVy
+ZSB0byBhbHNvIGRpc3BsYXkgdGhlIHBob3RvIElEIGF0dGFjaGVkIHRvIHRoZSBr
+ZXksIGlmCmFueS4gU2VlIGFsc28gQG9wdGlvbnstLXBob3RvLXZpZXdlcn0uIFRo
+ZXNlIG9wdGlvbnMgYXJlIGRlcHJlY2F0ZWQuIFVzZQpAb3B0aW9uey0tbGlzdC1v
+cHRpb25zIFtuby1dc2hvdy1waG90b3N9IGFuZC9vciBAb3B0aW9uey0tdmVyaWZ5
+LW9wdGlvbnMKW25vLV1zaG93LXBob3Rvc30gaW5zdGVhZC4KCkBpdGVtIC0tc2hv
+dy1rZXlyaW5nCkBvcGluZGV4IHNob3cta2V5cmluZwpEaXNwbGF5IHRoZSBrZXly
+aW5nIG5hbWUgYXQgdGhlIGhlYWQgb2Yga2V5IGxpc3RpbmdzIHRvIHNob3cgd2hp
+Y2gKa2V5cmluZyBhIGdpdmVuIGtleSByZXNpZGVzIG9uLiBUaGlzIG9wdGlvbiBp
+cyBkZXByZWNhdGVkOiB1c2UKQG9wdGlvbnstLWxpc3Qtb3B0aW9ucyBbbm8tXXNo
+b3cta2V5cmluZ30gaW5zdGVhZC4KCkBpdGVtIC0tYWx3YXlzLXRydXN0CkBvcGlu
+ZGV4IGFsd2F5cy10cnVzdApJZGVudGljYWwgdG8gQG9wdGlvbnstLXRydXN0LW1v
+ZGVsIGFsd2F5c30uIFRoaXMgb3B0aW9uIGlzIGRlcHJlY2F0ZWQuCgpAaXRlbSAt
+LXNob3ctbm90YXRpb24KQGl0ZW14IC0tbm8tc2hvdy1ub3RhdGlvbgpAb3BpbmRl
+eCBzaG93LW5vdGF0aW9uClNob3cgc2lnbmF0dXJlIG5vdGF0aW9ucyBpbiB0aGUg
+QG9wdGlvbnstLWxpc3Qtc2lnc30gb3IgQG9wdGlvbnstLWNoZWNrLXNpZ3N9IGxp
+c3RpbmdzCmFzIHdlbGwgYXMgd2hlbiB2ZXJpZnlpbmcgYSBzaWduYXR1cmUgd2l0
+aCBhIG5vdGF0aW9uIGluIGl0LiBUaGVzZQpvcHRpb25zIGFyZSBkZXByZWNhdGVk
+LiBVc2UgQG9wdGlvbnstLWxpc3Qtb3B0aW9ucyBbbm8tXXNob3ctbm90YXRpb259
+CmFuZC9vciBAb3B0aW9uey0tdmVyaWZ5LW9wdGlvbnMgW25vLV1zaG93LW5vdGF0
+aW9ufSBpbnN0ZWFkLgoKQGl0ZW0gLS1zaG93LXBvbGljeS11cmwKQGl0ZW14IC0t
+bm8tc2hvdy1wb2xpY3ktdXJsCkBvcGluZGV4IHNob3ctcG9saWN5LXVybApTaG93
+IHBvbGljeSBVUkxzIGluIHRoZSBAb3B0aW9uey0tbGlzdC1zaWdzfSBvciBAb3B0
+aW9uey0tY2hlY2stc2lnc30KbGlzdGluZ3MgYXMgd2VsbCBhcyB3aGVuIHZlcmlm
+eWluZyBhIHNpZ25hdHVyZSB3aXRoIGEgcG9saWN5IFVSTCBpbgppdC4gVGhlc2Ug
+b3B0aW9ucyBhcmUgZGVwcmVjYXRlZC4gVXNlIEBvcHRpb257LS1saXN0LW9wdGlv
+bnMKW25vLV1zaG93LXBvbGljeS11cmx9IGFuZC9vciBAb3B0aW9uey0tdmVyaWZ5
+LW9wdGlvbnMKW25vLV1zaG93LXBvbGljeS11cmx9IGluc3RlYWQuCgoKQGVuZCB0
+YWJsZQoKCkBjICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioKQGMgKioqKioqKioqKioqKioqICAgICAgICAgICAgKioqKioqKioqKioq
+KioqKgpAYyAqKioqKioqKioqKioqKiogICBGSUxFUyAgICAqKioqKioqKioqKioq
+KioqCkBjICoqKioqKioqKioqKioqKiAgICAgICAgICAgICoqKioqKioqKioqKioq
+KioKQGMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KgpAbWFuc2VjdCBmaWxlcwpAbm9kZSBHUEcgQ29uZmlndXJhdGlvbgpAc2VjdGlv
+biBDb25maWd1cmF0aW9uIGZpbGVzCgpUaGVyZSBhcmUgYSBmZXcgY29uZmlndXJh
+dGlvbiBmaWxlcyB0byBjb250cm9sIGNlcnRhaW4gYXNwZWN0cyBvZgpAY29tbWFu
+ZHtAZ3BnbmFtZX0ncyBvcGVyYXRpb24uIFVubGVzcyBub3RlZCwgdGhleSBhcmUg
+ZXhwZWN0ZWQgaW4gdGhlCmN1cnJlbnQgaG9tZSBkaXJlY3RvcnkgKEBweHJlZntv
+cHRpb24gLS1ob21lZGlyfSkuCgpAdGFibGUgQGZpbGUKCiAgQGl0ZW0gZ3BnLmNv
+bmYKICBAY2luZGV4IGdwZy5jb25mCiAgVGhpcyBpcyB0aGUgc3RhbmRhcmQgY29u
+ZmlndXJhdGlvbiBmaWxlIHJlYWQgYnkgQGNvbW1hbmR7QGdwZ25hbWV9IG9uCiAg
+c3RhcnR1cC4gIEl0IG1heSBjb250YWluIGFueSB2YWxpZCBsb25nIG9wdGlvbjsg
+dGhlIGxlYWRpbmcgdHdvIGRhc2hlcwogIG1heSBub3QgYmUgZW50ZXJlZCBhbmQg
+dGhlIG9wdGlvbiBtYXkgbm90IGJlIGFiYnJldmlhdGVkLiAgVGhpcyBkZWZhdWx0
+CiAgbmFtZSBtYXkgYmUgY2hhbmdlZCBvbiB0aGUgY29tbWFuZCBsaW5lIChAcHhy
+ZWZ7Z3BnLW9wdGlvbiAtLW9wdGlvbnN9KS4KICBZb3Ugc2hvdWxkIGJhY2t1cCB0
+aGlzIGZpbGUuCgpAZW5kIHRhYmxlCgpAYyBtYW46LlJFCk5vdGUgdGhhdCBvbiBs
+YXJnZXIgaW5zdGFsbGF0aW9ucywgaXQgaXMgdXNlZnVsIHRvIHB1dCBwcmVkZWZp
+bmVkIGZpbGVzCmludG8gdGhlIGRpcmVjdG9yeSBAZmlsZXtAdmFsdWV7U1lTQ09O
+RlNLRUxESVJ9fSBzbyB0aGF0Cm5ld2x5IGNyZWF0ZWQgdXNlcnMgc3RhcnQgdXAg
+d2l0aCBhIHdvcmtpbmcgY29uZmlndXJhdGlvbi4KRm9yIGV4aXN0aW5nIHVzZXJz
+IGEgc21hbGwKaGVscGVyIHNjcmlwdCBpcyBwcm92aWRlZCB0byBjcmVhdGUgdGhl
+c2UgZmlsZXMgKEBweHJlZnthZGRnbnVwZ2hvbWV9KS4KCkZvciBpbnRlcm5hbCBw
+dXJwb3NlcyBAY29tbWFuZHtAZ3BnbmFtZX0gY3JlYXRlcyBhbmQgbWFpbnRhaW5z
+IGEgZmV3IG90aGVyCmZpbGVzOyBUaGV5IGFsbCBsaXZlIGluIGluIHRoZSBjdXJy
+ZW50IGhvbWUgZGlyZWN0b3J5IChAcHhyZWZ7b3B0aW9uCi0taG9tZWRpcn0pLiAg
+T25seSB0aGUgQGNvbW1hbmR7QGdwZ25hbWV9IHByb2dyYW0gbWF5IG1vZGlmeSB0
+aGVzZSBmaWxlcy4KCgpAdGFibGUgQGZpbGUKICBAaXRlbSB+Ly5nbnVwZy9wdWJy
+aW5nLmdwZwogIFRoZSBwdWJsaWMga2V5cmluZy4gIFlvdSBzaG91bGQgYmFja3Vw
+IHRoaXMgZmlsZS4KCiAgQGl0ZW0gfi8uZ251cGcvcHVicmluZy5ncGcubG9jawog
+IFRoZSBsb2NrIGZpbGUgZm9yIHRoZSBwdWJsaWMga2V5cmluZy4KCiAgQGl0ZW0g
+fi8uZ251cGcvcHVicmluZy5rYngKICBUaGUgcHVibGljIGtleXJpbmcgdXNpbmcg
+YSBkaWZmZXJlbnQgZm9ybWF0LiAgVGhpcyBmaWxlIGlzIHNoYXJyZWQKICB3aXRo
+IEBjb21tYW5ke2dwZ3NtfS4gIFlvdSBzaG91bGQgYmFja3VwIHRoaXMgZmlsZS4K
+CiAgQGl0ZW0gfi8uZ251cGcvcHVicmluZy5rYngubG9jawogIFRoZSBsb2NrIGZp
+bGUgZm9yIEBmaWxle3B1YnJpbmcua2J4fS4KCiAgQGl0ZW0gfi8uZ251cGcvc2Vj
+cmluZy5ncGcKICBBIHNlY3JldCBrZXlyaW5nIGFzIHVzZWQgYnkgR251UEcgdmVy
+c2lvbnMgYmVmb3JlIDIuMS4gIEl0IGlzIG5vdAogIHVzZWQgYnkgR251UEcgMi4x
+IGFuZCBsYXRlci4KCiAgQGl0ZW0gfi8uZ251cGcvLmdwZy12MjEtbWlncmF0ZWQK
+ICBGaWxlIGluZGljYXRpbmcgdGhhdCBhIG1pZ3JhdGlvbiB0byBHbnVQRyAyLjEg
+aGFzIGJlZW4gZG9uZS4KCiAgQGl0ZW0gfi8uZ251cGcvdHJ1c3RkYi5ncGcKICBU
+aGUgdHJ1c3QgZGF0YWJhc2UuICBUaGVyZSBpcyBubyBuZWVkIHRvIGJhY2t1cCB0
+aGlzIGZpbGU7IGl0IGlzIGJldHRlcgogIHRvIGJhY2t1cCB0aGUgb3duZXJ0cnVz
+dCB2YWx1ZXMgKEBweHJlZntvcHRpb24gLS1leHBvcnQtb3duZXJ0cnVzdH0pLgoK
+ICBAaXRlbSB+Ly5nbnVwZy90cnVzdGRiLmdwZy5sb2NrCiAgVGhlIGxvY2sgZmls
+ZSBmb3IgdGhlIHRydXN0IGRhdGFiYXNlLgoKICBAaXRlbSB+Ly5nbnVwZy9yYW5k
+b21fc2VlZAogIEEgZmlsZSB1c2VkIHRvIHByZXNlcnZlIHRoZSBzdGF0ZSBvZiB0
+aGUgaW50ZXJuYWwgcmFuZG9tIHBvb2wuCgogIEBpdGVtIH4vLmdudXBnL3NlY3Jp
+bmcuZ3BnLmxvY2sKICBUaGUgbG9jayBmaWxlIGZvciB0aGUgc2VjcmV0IGtleXJp
+bmcuCgogIEBpdGVtIH4vLmdudXBnL29wZW5wZ3AtcmV2b2NzLmQvCiAgVGhpcyBp
+cyB0aGUgZGlyZWN0b3J5IHdoZXJlIGdwZyBzdG9yZXMgcHJlLWdlbmVyYXRlZCBy
+ZXZvY2F0aW9uCiAgY2VydGlmaWNhdGVzLiAgVGhlIGZpbGUgbmFtZSBjb3JyZXNw
+b25kcyB0byB0aGUgT3BlblBHUCBmaW5nZXJwcmludCBvZgogIHRoZSByZXNwZWN0
+aXZlIGtleS4gIEl0IGlzIHN1Z2dlc3RlZCB0byBiYWNrdXAgdGhvc2UgY2VydGlm
+aWNhdGVzIGFuZAogIGlmIHRoZSBwcmltYXJ5IHByaXZhdGUga2V5IGlzIG5vdCBz
+dG9yZWQgb24gdGhlIGRpc2sgdG8gbW92ZSB0aGVtIHRvCiAgYW4gZXh0ZXJuYWwg
+c3RvcmFnZSBkZXZpY2UuICBBbnlvbmUgd2hvIGNhbiBhY2Nlc3MgdGhlc2VzIGZp
+bGVzIGlzCiAgYWJsZSB0byByZXZva2UgdGhlIGNvcnJlc3BvbmRpbmcga2V5LiAg
+WW91IG1heSB3YW50IHRvIHByaW50IHRoZW0gb3V0LgogIFlvdSBzaG91bGQgYmFj
+a3VwIGFsbCBmaWxlcyBpbiB0aGlzIGRpcmVjdG9yeSBhbmQgdGFrZSBjYXJlIHRv
+IGtlZXAKICB0aGlzIGJhY2t1cCBjbG9zZWQgYXdheS4KCiAgQGl0ZW0gQHZhbHVl
+e0RBVEFESVJ9L29wdGlvbnMuc2tlbAogIFRoZSBza2VsZXRvbiBvcHRpb25zIGZp
+bGUuCgogIEBpdGVtIEB2YWx1ZXtMSUJESVJ9LwogIERlZmF1bHQgbG9jYXRpb24g
+Zm9yIGV4dGVuc2lvbnMuCgpAZW5kIHRhYmxlCgpAYyBtYW46LlJFCk9wZXJhdGlv
+biBpcyBmdXJ0aGVyIGNvbnRyb2xsZWQgYnkgYSBmZXcgZW52aXJvbm1lbnQgdmFy
+aWFibGVzOgoKQHRhYmxlIEBhc2lzCgogIEBpdGVtIEhPTUUKICBVc2VkIHRvIGxv
+Y2F0ZSB0aGUgZGVmYXVsdCBob21lIGRpcmVjdG9yeS4KCiAgQGl0ZW0gR05VUEdI
+T01FCiAgSWYgc2V0IGRpcmVjdG9yeSB1c2VkIGluc3RlYWQgb2YgIn4vLmdudXBn
+Ii4KCiAgQGl0ZW0gR1BHX0FHRU5UX0lORk8KICBUaGlzIHZhcmlhYmxlIHdhcyB1
+c2VkIGJ5IEdudVBHIHZlcnNpb25zIGJlZm9yZSAyLjEKCiAgQGl0ZW0gUElORU5U
+UllfVVNFUl9EQVRBCiAgVGhpcyB2YWx1ZSBpcyBwYXNzZWQgdmlhIGdwZy1hZ2Vu
+dCB0byBwaW5lbnRyeS4gIEl0IGlzIHVzZWZ1bCB0byBjb252ZXkKICBleHRyYSBp
+bmZvcm1hdGlvbiB0byBhIGN1c3RvbSBwaW5lbnRyeS4KCiAgQGl0ZW0gQ09MVU1O
+UwogIEBpdGVteCBMSU5FUwogIFVzZWQgdG8gc2l6ZSBzb21lIGRpc3BsYXlzIHRv
+IHRoZSBmdWxsIHNpemUgb2YgdGhlIHNjcmVlbi4KCgogIEBpdGVtIExBTkdVQUdF
+CiAgQXBhcnQgZnJvbSBpdHMgdXNlIGJ5IEdOVSwgaXQgaXMgdXNlZCBpbiB0aGUg
+VzMyIHZlcnNpb24gdG8gb3ZlcnJpZGUgdGhlCiAgbGFuZ3VhZ2Ugc2VsZWN0aW9u
+IGRvbmUgdGhyb3VnaCB0aGUgUmVnaXN0cnkuICBJZiB1c2VkIGFuZCBzZXQgdG8g
+YQogIHZhbGlkIGFuZCBhdmFpbGFibGUgbGFuZ3VhZ2UgbmFtZSAoQHZhcntsYW5n
+aWR9KSwgdGhlIGZpbGUgd2l0aCB0aGUKICB0cmFuc2xhdGlvbiBpcyBsb2FkZWQg
+ZnJvbQoKICBAY29kZXtAdmFye2dwZ2Rpcn0vZ251cGcubmxzL0B2YXJ7bGFuZ2lk
+fS5tb30uICBIZXJlIEB2YXJ7Z3BnZGlyfSBpcyB0aGUKICBkaXJlY3Rvcnkgb3V0
+IG9mIHdoaWNoIHRoZSBncGcgYmluYXJ5IGhhcyBiZWVuIGxvYWRlZC4gIElmIGl0
+IGNhbid0IGJlCiAgbG9hZGVkIHRoZSBSZWdpc3RyeSBpcyB0cmllZCBhbmQgYXMg
+bGFzdCByZXNvcnQgdGhlIG5hdGl2ZSBXaW5kb3dzCiAgbG9jYWxlIHN5c3RlbSBp
+cyB1c2VkLgoKQGVuZCB0YWJsZQoKCkBjICoqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKioqKioKQGMgKioqKioqKioqKioqKioqICAgICAgICAg
+ICAgKioqKioqKioqKioqKioqKgpAYyAqKioqKioqKioqKioqKiogIEVYQU1QTEVT
+ICAqKioqKioqKioqKioqKioqCkBjICoqKioqKioqKioqKioqKiAgICAgICAgICAg
+ICoqKioqKioqKioqKioqKioKQGMgKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqKioqKioqKioqKioqKgpAbWFuc2VjdCBleGFtcGxlcwpAbm9kZSBHUEcgRXhh
+bXBsZXMKQHNlY3Rpb24gRXhhbXBsZXMKCkB0YWJsZSBAYXNpcwoKQGl0ZW0gZ3Bn
+IC1zZSAtciBAY29kZXtCb2J9IEBjb2Rle2ZpbGV9CnNpZ24gYW5kIGVuY3J5cHQg
+Zm9yIHVzZXIgQm9iCgpAaXRlbSBncGcgLS1jbGVhcnNpZ24gQGNvZGV7ZmlsZX0K
+bWFrZSBhIGNsZWFyIHRleHQgc2lnbmF0dXJlCgpAaXRlbSBncGcgLXNiIEBjb2Rl
+e2ZpbGV9Cm1ha2UgYSBkZXRhY2hlZCBzaWduYXR1cmUKCkBpdGVtIGdwZyAtdSAw
+eDEyMzQ1Njc4IC1zYiBAY29kZXtmaWxlfQptYWtlIGEgZGV0YWNoZWQgc2lnbmF0
+dXJlIHdpdGggdGhlIGtleSAweDEyMzQ1Njc4CgpAaXRlbSBncGcgLS1saXN0LWtl
+eXMgQGNvZGV7dXNlcl9JRH0Kc2hvdyBrZXlzCgpAaXRlbSBncGcgLS1maW5nZXJw
+cmludCBAY29kZXt1c2VyX0lEfQpzaG93IGZpbmdlcnByaW50CgpAaXRlbSBncGcg
+LS12ZXJpZnkgQGNvZGV7cGdwZmlsZX0KQGl0ZW14IGdwZyAtLXZlcmlmeSBAY29k
+ZXtzaWdmaWxlfQpWZXJpZnkgdGhlIHNpZ25hdHVyZSBvZiB0aGUgZmlsZSBidXQg
+ZG8gbm90IG91dHB1dCB0aGUgZGF0YS4gVGhlCnNlY29uZCBmb3JtIGlzIHVzZWQg
+Zm9yIGRldGFjaGVkIHNpZ25hdHVyZXMsIHdoZXJlIEBjb2Rle3NpZ2ZpbGV9Cmlz
+IHRoZSBkZXRhY2hlZCBzaWduYXR1cmUgKGVpdGhlciBBU0NJSSBhcm1vcmVkIG9y
+IGJpbmFyeSkgYW5kCmFyZSB0aGUgc2lnbmVkIGRhdGE7IGlmIHRoaXMgaXMgbm90
+IGdpdmVuLCB0aGUgbmFtZSBvZgp0aGUgZmlsZSBob2xkaW5nIHRoZSBzaWduZWQg
+ZGF0YSBpcyBjb25zdHJ1Y3RlZCBieSBjdXR0aW5nIG9mZiB0aGUKZXh0ZW5zaW9u
+ICgiLmFzYyIgb3IgIi5zaWciKSBvZiBAY29kZXtzaWdmaWxlfSBvciBieSBhc2tp
+bmcgdGhlCnVzZXIgZm9yIHRoZSBmaWxlbmFtZS4KQGVuZCB0YWJsZQoKCkBjICoq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioKQGMgKioq
+KioqKioqKioqKioqICAgICAgICAgICAgKioqKioqKioqKioqKioqKgpAYyAqKioq
+KioqKioqKioqKiogIFVTRVIgSUQgICAqKioqKioqKioqKioqKioqCkBjICoqKioq
+KioqKioqKioqKiAgICAgICAgICAgICoqKioqKioqKioqKioqKioKQGMgKioqKioq
+KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgpAbWFuc2VjdCBo
+b3cgdG8gc3BlY2lmeSBhIHVzZXIgaWQKQGlmc2V0IGlzbWFuCkBpbmNsdWRlIHNw
+ZWNpZnktdXNlci1pZC50ZXhpCkBlbmQgaWZzZXQKCkBtYW5zZWN0IHJldHVybiB2
+YWx1ZQpAY2hhcGhlYWRpbmcgUkVUVVJOIFZBTFVFCgpUaGUgcHJvZ3JhbSByZXR1
+cm5zIDAgaWYgZXZlcnl0aGluZyB3YXMgZmluZSwgMSBpZiBhdCBsZWFzdAphIHNp
+Z25hdHVyZSB3YXMgYmFkLCBhbmQgb3RoZXIgZXJyb3IgY29kZXMgZm9yIGZhdGFs
+IGVycm9ycy4KCkBtYW5zZWN0IHdhcm5pbmdzCkBjaGFwaGVhZGluZyBXQVJOSU5H
+UwoKVXNlIGEgKmdvb2QqIHBhc3N3b3JkIGZvciB5b3VyIHVzZXIgYWNjb3VudCBh
+bmQgYSAqZ29vZCogcGFzc3BocmFzZQp0byBwcm90ZWN0IHlvdXIgc2VjcmV0IGtl
+eS4gVGhpcyBwYXNzcGhyYXNlIGlzIHRoZSB3ZWFrZXN0IHBhcnQgb2YgdGhlCndo
+b2xlIHN5c3RlbS4gUHJvZ3JhbXMgdG8gZG8gZGljdGlvbmFyeSBhdHRhY2tzIG9u
+IHlvdXIgc2VjcmV0IGtleXJpbmcKYXJlIHZlcnkgZWFzeSB0byB3cml0ZSBhbmQg
+c28geW91IHNob3VsZCBwcm90ZWN0IHlvdXIgIn4vLmdudXBnLyIKZGlyZWN0b3J5
+IHZlcnkgd2VsbC4KCktlZXAgaW4gbWluZCB0aGF0LCBpZiB0aGlzIHByb2dyYW0g
+aXMgdXNlZCBvdmVyIGEgbmV0d29yayAodGVsbmV0KSwgaXQKaXMgKnZlcnkqIGVh
+c3kgdG8gc3B5IG91dCB5b3VyIHBhc3NwaHJhc2UhCgpJZiB5b3UgYXJlIGdvaW5n
+IHRvIHZlcmlmeSBkZXRhY2hlZCBzaWduYXR1cmVzLCBtYWtlIHN1cmUgdGhhdCB0
+aGUKcHJvZ3JhbSBrbm93cyBhYm91dCBpdDsgZWl0aGVyIGdpdmUgYm90aCBmaWxl
+bmFtZXMgb24gdGhlIGNvbW1hbmQgbGluZQpvciB1c2UgQHNhbXB7LX0gdG8gc3Bl
+Y2lmeSBTVERJTi4KCkBtYW5zZWN0IGludGVyb3BlcmFiaWxpdHkKQGNoYXBoZWFk
+aW5nIElOVEVST1BFUkFCSUxJVFkgV0lUSCBPVEhFUiBPUEVOUEdQIFBST0dSQU1T
+CgpHbnVQRyB0cmllcyB0byBiZSBhIHZlcnkgZmxleGlibGUgaW1wbGVtZW50YXRp
+b24gb2YgdGhlIE9wZW5QR1AKc3RhbmRhcmQuIEluIHBhcnRpY3VsYXIsIEdudVBH
+IGltcGxlbWVudHMgbWFueSBvZiB0aGUgb3B0aW9uYWwgcGFydHMKb2YgdGhlIHN0
+YW5kYXJkLCBzdWNoIGFzIHRoZSBTSEEtNTEyIGhhc2gsIGFuZCB0aGUgWkxJQiBh
+bmQgQlpJUDIKY29tcHJlc3Npb24gYWxnb3JpdGhtcy4gSXQgaXMgaW1wb3J0YW50
+IHRvIGJlIGF3YXJlIHRoYXQgbm90IGFsbApPcGVuUEdQIHByb2dyYW1zIGltcGxl
+bWVudCB0aGVzZSBvcHRpb25hbCBhbGdvcml0aG1zIGFuZCB0aGF0IGJ5CmZvcmNp
+bmcgdGhlaXIgdXNlIHZpYSB0aGUgQG9wdGlvbnstLWNpcGhlci1hbGdvfSwKQG9w
+dGlvbnstLWRpZ2VzdC1hbGdvfSwgQG9wdGlvbnstLWNlcnQtZGlnZXN0LWFsZ299
+LCBvcgpAb3B0aW9uey0tY29tcHJlc3MtYWxnb30gb3B0aW9ucyBpbiBHbnVQRywg
+aXQgaXMgcG9zc2libGUgdG8gY3JlYXRlIGEKcGVyZmVjdGx5IHZhbGlkIE9wZW5Q
+R1AgbWVzc2FnZSwgYnV0IG9uZSB0aGF0IGNhbm5vdCBiZSByZWFkIGJ5IHRoZQpp
+bnRlbmRlZCByZWNpcGllbnQuCgpUaGVyZSBhcmUgZG96ZW5zIG9mIHZhcmlhdGlv
+bnMgb2YgT3BlblBHUCBwcm9ncmFtcyBhdmFpbGFibGUsIGFuZCBlYWNoCnN1cHBv
+cnRzIGEgc2xpZ2h0bHkgZGlmZmVyZW50IHN1YnNldCBvZiB0aGVzZSBvcHRpb25h
+bCBhbGdvcml0aG1zLgpGb3IgZXhhbXBsZSwgdW50aWwgcmVjZW50bHksIG5vICh1
+bmhhY2tlZCkgdmVyc2lvbiBvZiBQR1Agc3VwcG9ydGVkCnRoZSBCTE9XRklTSCBj
+aXBoZXIgYWxnb3JpdGhtLiBBIG1lc3NhZ2UgdXNpbmcgQkxPV0ZJU0ggc2ltcGx5
+IGNvdWxkCm5vdCBiZSByZWFkIGJ5IGEgUEdQIHVzZXIuIEJ5IGRlZmF1bHQsIEdu
+dVBHIHVzZXMgdGhlIHN0YW5kYXJkCk9wZW5QR1AgcHJlZmVyZW5jZXMgc3lzdGVt
+IHRoYXQgd2lsbCBhbHdheXMgZG8gdGhlIHJpZ2h0IHRoaW5nIGFuZApjcmVhdGUg
+bWVzc2FnZXMgdGhhdCBhcmUgdXNhYmxlIGJ5IGFsbCByZWNpcGllbnRzLCByZWdh
+cmRsZXNzIG9mIHdoaWNoCk9wZW5QR1AgcHJvZ3JhbSB0aGV5IHVzZS4gT25seSBv
+dmVycmlkZSB0aGlzIHNhZmUgZGVmYXVsdCBpZiB5b3UKcmVhbGx5IGtub3cgd2hh
+dCB5b3UgYXJlIGRvaW5nLgoKSWYgeW91IGFic29sdXRlbHkgbXVzdCBvdmVycmlk
+ZSB0aGUgc2FmZSBkZWZhdWx0LCBvciBpZiB0aGUgcHJlZmVyZW5jZXMKb24gYSBn
+aXZlbiBrZXkgYXJlIGludmFsaWQgZm9yIHNvbWUgcmVhc29uLCB5b3UgYXJlIGZh
+ciBiZXR0ZXIgb2ZmIHVzaW5nCnRoZSBAb3B0aW9uey0tcGdwNn0sIEBvcHRpb257
+LS1wZ3A3fSwgb3IgQG9wdGlvbnstLXBncDh9IG9wdGlvbnMuIFRoZXNlCm9wdGlv
+bnMgYXJlIHNhZmUgYXMgdGhleSBkbyBub3QgZm9yY2UgYW55IHBhcnRpY3VsYXIg
+YWxnb3JpdGhtcyBpbgp2aW9sYXRpb24gb2YgT3BlblBHUCwgYnV0IHJhdGhlciBy
+ZWR1Y2UgdGhlIGF2YWlsYWJsZSBhbGdvcml0aG1zIHRvIGEKIlBHUC1zYWZlIiBs
+aXN0LgoKQG1hbnNlY3QgYnVncwpAY2hhcGhlYWRpbmcgQlVHUwoKT24gb2xkZXIg
+c3lzdGVtcyB0aGlzIHByb2dyYW0gc2hvdWxkIGJlIGluc3RhbGxlZCBhcyBzZXR1
+aWQocm9vdCkuIFRoaXMKaXMgbmVjZXNzYXJ5IHRvIGxvY2sgbWVtb3J5IHBhZ2Vz
+LiBMb2NraW5nIG1lbW9yeSBwYWdlcyBwcmV2ZW50cyB0aGUKb3BlcmF0aW5nIHN5
+c3RlbSBmcm9tIHdyaXRpbmcgbWVtb3J5IHBhZ2VzICh3aGljaCBtYXkgY29udGFp
+bgpwYXNzcGhyYXNlcyBvciBvdGhlciBzZW5zaXRpdmUgbWF0ZXJpYWwpIHRvIGRp
+c2suIElmIHlvdSBnZXQgbm8Kd2FybmluZyBtZXNzYWdlIGFib3V0IGluc2VjdXJl
+IG1lbW9yeSB5b3VyIG9wZXJhdGluZyBzeXN0ZW0gc3VwcG9ydHMKbG9ja2luZyB3
+aXRob3V0IGJlaW5nIHJvb3QuIFRoZSBwcm9ncmFtIGRyb3BzIHJvb3QgcHJpdmls
+ZWdlcyBhcyBzb29uCmFzIGxvY2tlZCBtZW1vcnkgaXMgYWxsb2NhdGVkLgoKTm90
+ZSBhbHNvIHRoYXQgc29tZSBzeXN0ZW1zIChlc3BlY2lhbGx5IGxhcHRvcHMpIGhh
+dmUgdGhlIGFiaWxpdHkgdG8KYGBzdXNwZW5kIHRvIGRpc2snJyAoYWxzbyBrbm93
+biBhcyBgYHNhZmUgc2xlZXAnJyBvciBgYGhpYmVybmF0ZScnKS4KVGhpcyB3cml0
+ZXMgYWxsIG1lbW9yeSB0byBkaXNrIGJlZm9yZSBnb2luZyBpbnRvIGEgbG93IHBv
+d2VyIG9yIGV2ZW4KcG93ZXJlZCBvZmYgbW9kZS4gIFVubGVzcyBtZWFzdXJlcyBh
+cmUgdGFrZW4gaW4gdGhlIG9wZXJhdGluZyBzeXN0ZW0KdG8gcHJvdGVjdCB0aGUg
+c2F2ZWQgbWVtb3J5LCBwYXNzcGhyYXNlcyBvciBvdGhlciBzZW5zaXRpdmUgbWF0
+ZXJpYWwKbWF5IGJlIHJlY292ZXJhYmxlIGZyb20gaXQgbGF0ZXIuCgpCZWZvcmUg
+eW91IHJlcG9ydCBhIGJ1ZyB5b3Ugc2hvdWxkIGZpcnN0IHNlYXJjaCB0aGUgbWFp
+bGluZyBsaXN0CmFyY2hpdmVzIGZvciBzaW1pbGFyIHByb2JsZW1zIGFuZCBzZWNv
+bmQgY2hlY2sgd2hldGhlciBzdWNoIGEgYnVnIGhhcwphbHJlYWR5IGJlZW4gcmVw
+b3J0ZWQgdG8gb3VyIGJ1ZyB0cmFja2VyIGF0IGh0dHA6Ly9idWdzLmdudXBnLm9y
+ZyAuCgpAYyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq
+KioqCkBjICoqKioqKioqKioqKioqKiAgICAgICAgICAgICAgKioqKioqKioqKioq
+KioKQGMgKioqKioqKioqKioqKioqICBVTkFUVEVOREVEICAqKioqKioqKioqKioq
+KgpAYyAqKioqKioqKioqKioqKiogICAgICAgICAgICAgICoqKioqKioqKioqKioq
+CkBjICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioK
+QG1hbnBhdXNlCkBub2RlIFVuYXR0ZW5kZWQgVXNhZ2Ugb2YgR1BHCkBzZWN0aW9u
+IFVuYXR0ZW5kZWQgVXNhZ2UKCkBjb21tYW5ke2dwZ30gaXMgb2Z0ZW4gdXNlZCBh
+cyBhIGJhY2tlbmQgZW5naW5lIGJ5IG90aGVyIHNvZnR3YXJlLiAgVG8gaGVscAp3
+aXRoIHRoaXMgYSBtYWNoaW5lIGludGVyZmFjZSBoYXMgYmVlbiBkZWZpbmVkIHRv
+IGhhdmUgYW4gdW5hbWJpZ3VvdXMKd2F5IHRvIGRvIHRoaXMuICBUaGUgb3B0aW9u
+cyBAb3B0aW9uey0tc3RhdHVzLWZkfSBhbmQgQG9wdGlvbnstLWJhdGNofQphcmUg
+YWxtb3N0IGFsd2F5cyByZXF1aXJlZCBmb3IgdGhpcy4KCkBtZW51CiogVW5hdHRl
+bmRlZCBHUEcga2V5IGdlbmVyYXRpb246OiAgVW5hdHRlbmRlZCBrZXkgZ2VuZXJh
+dGlvbgpAZW5kIG1lbnUKCgpAbm9kZSBVbmF0dGVuZGVkIEdQRyBrZXkgZ2VuZXJh
+dGlvbgpAc3Vic2VjdGlvbiBVbmF0dGVuZGVkIGtleSBnZW5lcmF0aW9uCgpUaGUg
+Y29tbWFuZCBAb3B0aW9uey0tZ2VuLWtleX0gbWF5IGJlIHVzZWQgYWxvbmcgd2l0
+aCB0aGUgb3B0aW9uCkBvcHRpb257LS1iYXRjaH0gZm9yIHVuYXR0ZW5kZWQga2V5
+IGdlbmVyYXRpb24uICBUaGUgcGFyYW1ldGVycyBhcmUKZWl0aGVyIHJlYWQgZnJv
+bSBzdGRpbiBvciBnaXZlbiBhcyBhIGZpbGUgb24gdGhlIGNvbW1hbmQgbGluZS4K
+VGhlIGZvcm1hdCBvZiB0aGUgcGFyYW1ldGVyIGZpbGUgaXMgYXMgZm9sbG93czoK
+CkBpdGVtaXplIEBidWxsZXQKICBAaXRlbSBUZXh0IG9ubHksIGxpbmUgbGVuZ3Ro
+IGlzIGxpbWl0ZWQgdG8gYWJvdXQgMTAwMCBjaGFyYWN0ZXJzLgogIEBpdGVtIFVU
+Ri04IGVuY29kaW5nIG11c3QgYmUgdXNlZCB0byBzcGVjaWZ5IG5vbi1BU0NJSSBj
+aGFyYWN0ZXJzLgogIEBpdGVtIEVtcHR5IGxpbmVzIGFyZSBpZ25vcmVkLgogIEBp
+dGVtIExlYWRpbmcgYW5kIHRyYWlsaW5nIHdoaWxlIHNwYWNlIGlzIGlnbm9yZWQu
+CiAgQGl0ZW0gQSBoYXNoIHNpZ24gYXMgdGhlIGZpcnN0IG5vbiB3aGl0ZSBzcGFj
+ZSBjaGFyYWN0ZXIgaW5kaWNhdGVzCiAgYSBjb21tZW50IGxpbmUuCiAgQGl0ZW0g
+Q29udHJvbCBzdGF0ZW1lbnRzIGFyZSBpbmRpY2F0ZWQgYnkgYSBsZWFkaW5nIHBl
+cmNlbnQgc2lnbiwgdGhlCiAgYXJndW1lbnRzIGFyZSBzZXBhcmF0ZWQgYnkgd2hp
+dGUgc3BhY2UgZnJvbSB0aGUga2V5d29yZC4KICBAaXRlbSBQYXJhbWV0ZXJzIGFy
+ZSBzcGVjaWZpZWQgYnkgYSBrZXl3b3JkLCBmb2xsb3dlZCBieSBhIGNvbG9uLiAg
+QXJndW1lbnRzCiAgYXJlIHNlcGFyYXRlZCBieSB3aGl0ZSBzcGFjZS4KICBAaXRl
+bQogIFRoZSBmaXJzdCBwYXJhbWV0ZXIgbXVzdCBiZSBAc2FtcHtLZXktVHlwZX07
+IGNvbnRyb2wgc3RhdGVtZW50cyBtYXkgYmUKICBwbGFjZWQgYW55d2hlcmUuCiAg
+QGl0ZW0KICBUaGUgb3JkZXIgb2YgdGhlIHBhcmFtZXRlcnMgZG9lcyBub3QgbWF0
+dGVyIGV4Y2VwdCBmb3IgQHNhbXB7S2V5LVR5cGV9CiAgd2hpY2ggbXVzdCBiZSB0
+aGUgZmlyc3QgcGFyYW1ldGVyLiAgVGhlIHBhcmFtZXRlcnMgYXJlIG9ubHkgdXNl
+ZCBmb3IKICB0aGUgZ2VuZXJhdGVkIGtleWJsb2NrIChwcmltYXJ5IGFuZCBzdWJr
+ZXlzKTsgcGFyYW1ldGVycyBmcm9tIHByZXZpb3VzCiAgc2V0cyBhcmUgbm90IHVz
+ZWQuICBTb21lIHN5bnRhY3RpY2FsbHkgY2hlY2tzIG1heSBiZSBwZXJmb3JtZWQu
+CiAgQGl0ZW0KICBLZXkgZ2VuZXJhdGlvbiB0YWtlcyBwbGFjZSB3aGVuIGVpdGhl
+ciB0aGUgZW5kIG9mIHRoZSBwYXJhbWV0ZXIgZmlsZQogIGlzIHJlYWNoZWQsIHRo
+ZSBuZXh0IEBzYW1we0tleS1UeXBlfSBwYXJhbWV0ZXIgaXMgZW5jb3VudGVyZWQg
+b3IgYXQgdGhlCiAgY29udHJvbCBzdGF0ZW1lbnQgQHNhbXB7JWNvbW1pdH0gaXMg
+ZW5jb3VudGVyZWQuCkBlbmQgaXRlbWl6ZQoKQG5vaW5kZW50CkNvbnRyb2wgc3Rh
+dGVtZW50czoKCkB0YWJsZSBAYXNpcwoKQGl0ZW0gJWVjaG8gQHZhcnt0ZXh0fQpQ
+cmludCBAdmFye3RleHR9IGFzIGRpYWdub3N0aWMuCgpAaXRlbSAlZHJ5LXJ1bgpT
+dXBwcmVzcyBhY3R1YWwga2V5IGdlbmVyYXRpb24gKHVzZWZ1bCBmb3Igc3ludGF4
+IGNoZWNraW5nKS4KCkBpdGVtICVjb21taXQKUGVyZm9ybSB0aGUga2V5IGdlbmVy
+YXRpb24uICBOb3RlIHRoYXQgYW4gaW1wbGljaXQgY29tbWl0IGlzIGRvbmUgYXQK
+dGhlIG5leHQgQGFzaXN7S2V5LVR5cGV9IHBhcmFtZXRlci4KCkBpdGVtICVwdWJy
+aW5nIEB2YXJ7ZmlsZW5hbWV9CkBpdGVteCAlc2VjcmluZyBAdmFye2ZpbGVuYW1l
+fQpEbyBub3Qgd3JpdGUgdGhlIGtleSB0byB0aGUgZGVmYXVsdCBvciBjb21tYW5k
+bGluZSBnaXZlbiBrZXlyaW5nIGJ1dAp0byBAdmFye2ZpbGVuYW1lfS4gIFRoaXMg
+bXVzdCBiZSBnaXZlbiBiZWZvcmUgdGhlIGZpcnN0IGNvbW1pdCB0byB0YWtlCnBs
+YWNlLCBkdXBsaWNhdGUgc3BlY2lmaWNhdGlvbiBvZiB0aGUgc2FtZSBmaWxlbmFt
+ZSBpcyBpZ25vcmVkLCB0aGUKbGFzdCBmaWxlbmFtZSBiZWZvcmUgYSBjb21taXQg
+aXMgdXNlZC4gIFRoZSBmaWxlbmFtZSBpcyB1c2VkIHVudGlsIGEKbmV3IGZpbGVu
+YW1lIGlzIHVzZWQgKGF0IGNvbW1pdCBwb2ludHMpIGFuZCBhbGwga2V5cyBhcmUg
+d3JpdHRlbiB0bwp0aGF0IGZpbGUuIElmIGEgbmV3IGZpbGVuYW1lIGlzIGdpdmVu
+LCB0aGlzIGZpbGUgaXMgY3JlYXRlZCAoYW5kCm92ZXJ3cml0ZXMgYW4gZXhpc3Rp
+bmcgb25lKS4gIEZvciBHbnVQRyB2ZXJzaW9ucyBwcmlvciB0byAyLjEsIGJvdGgK
+Y29udHJvbCBzdGF0ZW1lbnRzIG11c3QgYmUgZ2l2ZW4uIEZvciBHbnVQRyAyLjEg
+YW5kIGxhdGVyCkBzYW1weyVzZWNyaW5nfSBpcyBhIG5vLW9wLgoKQGl0ZW0gJWFz
+ay1wYXNzcGhyYXNlCkBpdGVteCAlbm8tYXNrLXBhc3NwaHJhc2UKVGhpcyBvcHRp
+b24gaXMgYSBuby1vcCBmb3IgR251UEcgMi4xIGFuZCBsYXRlci4KCkBpdGVtICVu
+by1wcm90ZWN0aW9uClVzaW5nIHRoaXMgb3B0aW9uIGFsbG93cyB0aGUgY3JlYXRp
+b24gb2Yga2V5cyB3aXRob3V0IGFueSBwYXNzcGhyYXNlCnByb3RlY3Rpb24uICBU
+aGlzIG9wdGlvbiBpcyBtYWlubHkgaW50ZW5kZWQgZm9yIHJlZ3Jlc3Npb24gdGVz
+dHMuCgpAaXRlbSAldHJhbnNpZW50LWtleQpJZiBnaXZlbiB0aGUga2V5cyBhcmUg
+Y3JlYXRlZCB1c2luZyBhIGZhc3RlciBhbmQgYSBzb21ld2hhdCBsZXNzCnNlY3Vy
+ZSByYW5kb20gbnVtYmVyIGdlbmVyYXRvci4gIFRoaXMgb3B0aW9uIG1heSBiZSB1
+c2VkIGZvciBrZXlzCndoaWNoIGFyZSBvbmx5IHVzZWQgZm9yIGEgc2hvcnQgdGlt
+ZSBhbmQgZG8gbm90IHJlcXVpcmUgZnVsbApjcnlwdG9ncmFwaGljIHN0cmVuZ3Ro
+LiAgSXQgdGFrZXMgb25seSBlZmZlY3QgaWYgdXNlZCB0b2dldGhlciB3aXRoCnRo
+ZSBjb250cm9sIHN0YXRlbWVudCBAc2FtcHslbm8tcHJvdGVjdGlvbn0uCgpAZW5k
+IHRhYmxlCgpAbm9pbmRlbnQKR2VuZXJhbCBQYXJhbWV0ZXJzOgoKQHRhYmxlIEBh
+c2lzCgpAaXRlbSBLZXktVHlwZTogQHZhcnthbGdvfQpTdGFydHMgYSBuZXcgcGFy
+YW1ldGVyIGJsb2NrIGJ5IGdpdmluZyB0aGUgdHlwZSBvZiB0aGUgcHJpbWFyeQpr
+ZXkuIFRoZSBhbGdvcml0aG0gbXVzdCBiZSBjYXBhYmxlIG9mIHNpZ25pbmcuICBU
+aGlzIGlzIGEgcmVxdWlyZWQKcGFyYW1ldGVyLiAgQHZhcnthbGdvfSBtYXkgZWl0
+aGVyIGJlIGFuIE9wZW5QR1AgYWxnb3JpdGhtIG51bWJlciBvciBhCnN0cmluZyB3
+aXRoIHRoZSBhbGdvcml0aG0gbmFtZS4gIFRoZSBzcGVjaWFsIHZhbHVlIEBzYW1w
+e2RlZmF1bHR9IG1heQpiZSB1c2VkIGZvciBAdmFye2FsZ299IHRvIGNyZWF0ZSB0
+aGUgZGVmYXVsdCBrZXkgdHlwZTsgaW4gdGhpcyBjYXNlIGEKQHNhbXB7S2V5LVVz
+YWdlfSBzaGFsbCBub3QgYmUgZ2l2ZW4gYW5kIEBzYW1we2RlZmF1bHR9IGFsc28g
+YmUgdXNlZApmb3IgQHNhbXB7U3Via2V5LVR5cGV9LgoKQGl0ZW0gS2V5LUxlbmd0
+aDogQHZhcntuYml0c30KVGhlIHJlcXVlc3RlZCBsZW5ndGggb2YgdGhlIGdlbmVy
+YXRlZCBrZXkgaW4gYml0cy4gIFRoZSBkZWZhdWx0IGlzCnJldHVybmVkIGJ5IHJ1
+bm5pbmcgdGhlIGNvbW1hbmQgQHNhbXB7Z3BnMiAtLWdwZ2NvbmYtbGlzdH0uCgpA
+aXRlbSBLZXktR3JpcDogQHZhcntoZXhzdHJpbmd9ClRoaXMgaXMgb3B0aW9uYWwg
+YW5kIHVzZWQgdG8gZ2VuZXJhdGUgYSBDU1Igb3IgY2VydGlmaWNhdGUgZm9yIGFu
+CmFscmVhZHkgZXhpc3Rpbmcga2V5LiAgS2V5LUxlbmd0aCB3aWxsIGJlIGlnbm9y
+ZWQgd2hlbiBnaXZlbi4KCkBpdGVtIEtleS1Vc2FnZTogQHZhcnt1c2FnZS1saXN0
+fQpTcGFjZSBvciBjb21tYSBkZWxpbWl0ZWQgbGlzdCBvZiBrZXkgdXNhZ2VzLiAg
+QWxsb3dlZCB2YWx1ZXMgYXJlCkBzYW1we2VuY3J5cHR9LCBAc2FtcHtzaWdufSwg
+YW5kIEBzYW1we2F1dGh9LiAgVGhpcyBpcyB1c2VkIHRvCmdlbmVyYXRlIHRoZSBr
+ZXkgZmxhZ3MuICBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgdGhlIGFsZ29yaXRobSBp
+cwpjYXBhYmxlIG9mIHRoaXMgdXNhZ2UuICBOb3RlIHRoYXQgT3BlblBHUCByZXF1
+aXJlcyB0aGF0IGFsbCBwcmltYXJ5CmtleXMgYXJlIGNhcGFibGUgb2YgY2VydGlm
+aWNhdGlvbiwgc28gbm8gbWF0dGVyIHdoYXQgdXNhZ2UgaXMgZ2l2ZW4KaGVyZSwg
+dGhlIEBzYW1we2NlcnR9IGZsYWcgd2lsbCBiZSBvbi4gIElmIG5vIEBzYW1we0tl
+eS1Vc2FnZX0gaXMKc3BlY2lmaWVkIGFuZCB0aGUgQHNhbXB7S2V5LVR5cGV9IGlz
+IG5vdCBAc2FtcHtkZWZhdWx0fSwgYWxsIGFsbG93ZWQKdXNhZ2VzIGZvciB0aGF0
+IHBhcnRpY3VsYXIgYWxnb3JpdGhtIGFyZSB1c2VkOyBpZiBpdCBpcyBub3QgZ2l2
+ZW4gYnV0CkBzYW1we2RlZmF1bHR9IGlzIHVzZWQgdGhlIHVzYWdlIHdpbGwgYmUg
+QHNhbXB7c2lnbn0uCgpAaXRlbSBTdWJrZXktVHlwZTogQHZhcnthbGdvfQpUaGlz
+IGdlbmVyYXRlcyBhIHNlY29uZGFyeSBrZXkgKHN1YmtleSkuICBDdXJyZW50bHkg
+b25seSBvbmUgc3Via2V5CmNhbiBiZSBoYW5kbGVkLiAgU2VlIGFsc28gQHNhbXB7
+S2V5LVR5cGV9IGFib3ZlLgoKQGl0ZW0gU3Via2V5LUxlbmd0aDogQHZhcntuYml0
+c30KTGVuZ3RoIG9mIHRoZSBzZWNvbmRhcnkga2V5IChzdWJrZXkpIGluIGJpdHMu
+ICBUaGUgZGVmYXVsdCBpcyByZXR1cm5lZApieSBydW5uaW5nIHRoZSBjb21tYW5k
+IEBzYW1we2dwZzIgLS1ncGdjb25mLWxpc3R9Ii4KCkBpdGVtIFN1YmtleS1Vc2Fn
+ZTogQHZhcnt1c2FnZS1saXN0fQpLZXkgdXNhZ2UgbGlzdHMgZm9yIGEgc3Via2V5
+OyBzaW1pbGFyIHRvIEBzYW1we0tleS1Vc2FnZX0uCgpAaXRlbSBQYXNzcGhyYXNl
+OiBAdmFye3N0cmluZ30KSWYgeW91IHdhbnQgdG8gc3BlY2lmeSBhIHBhc3NwaHJh
+c2UgZm9yIHRoZSBzZWNyZXQga2V5LCBlbnRlciBpdCBoZXJlLgpEZWZhdWx0IGlz
+IHRvIHVzZSB0aGUgUGluZW50cnkgZGlhbG9nIHRvIGFzayBmb3IgYSBwYXNzcGhy
+YXNlLgoKQGl0ZW0gTmFtZS1SZWFsOiBAdmFye25hbWV9CkBpdGVteCBOYW1lLUNv
+bW1lbnQ6IEB2YXJ7Y29tbWVudH0KQGl0ZW14IE5hbWUtRW1haWw6IEB2YXJ7ZW1h
+aWx9ClRoZSB0aHJlZSBwYXJ0cyBvZiBhIHVzZXIgbmFtZS4gIFJlbWVtYmVyIHRv
+IHVzZSBVVEYtOCBlbmNvZGluZyBoZXJlLgpJZiB5b3UgZG9uJ3QgZ2l2ZSBhbnkg
+b2YgdGhlbSwgbm8gdXNlciBJRCBpcyBjcmVhdGVkLgoKQGl0ZW0gRXhwaXJlLURh
+dGU6IEB2YXJ7aXNvLWRhdGV9fChAdmFye251bWJlcn1bZHx3fG18eV0pClNldCB0
+aGUgZXhwaXJhdGlvbiBkYXRlIGZvciB0aGUga2V5IChhbmQgdGhlIHN1YmtleSku
+ICBJdCBtYXkgZWl0aGVyCmJlIGVudGVyZWQgaW4gSVNPIGRhdGUgZm9ybWF0IChl
+LmcuICIyMDAwMDgxNVQxNDUwMTIiKSBvciBhcyBudW1iZXIgb2YKZGF5cywgd2Vl
+a3MsIG1vbnRoIG9yIHllYXJzIGFmdGVyIHRoZSBjcmVhdGlvbiBkYXRlLiAgVGhl
+IHNwZWNpYWwKbm90YXRpb24gInNlY29uZHM9TiIgaXMgYWxzbyBhbGxvd2VkIHRv
+IHNwZWNpZnkgYSBudW1iZXIgb2Ygc2Vjb25kcwpzaW5jZSBjcmVhdGlvbi4gIFdp
+dGhvdXQgYSBsZXR0ZXIgZGF5cyBhcmUgYXNzdW1lZC4gIE5vdGUgdGhhdCB0aGVy
+ZQppcyBubyBjaGVjayBkb25lIG9uIHRoZSBvdmVyZmxvdyBvZiB0aGUgdHlwZSB1
+c2VkIGJ5IE9wZW5QR1AgZm9yCnRpbWVzdGFtcHMuICBUaHVzIHlvdSBiZXR0ZXIg
+bWFrZSBzdXJlIHRoYXQgdGhlIGdpdmVuIHZhbHVlIG1ha2UKc2Vuc2UuICBBbHRo
+b3VnaCBPcGVuUEdQIHdvcmtzIHdpdGggdGltZSBpbnRlcnZhbHMsIEdudVBHIHVz
+ZXMgYW4KYWJzb2x1dGUgdmFsdWUgaW50ZXJuYWxseSBhbmQgdGh1cyB0aGUgbGFz
+dCB5ZWFyIHdlIGNhbiByZXByZXNlbnQgaXMKMjEwNS4KCkBpdGVtICBDcmVhdGlv
+bi1EYXRlOiBAdmFye2lzby1kYXRlfQpTZXQgdGhlIGNyZWF0aW9uIGRhdGUgb2Yg
+dGhlIGtleSBhcyBzdG9yZWQgaW4gdGhlIGtleSBpbmZvcm1hdGlvbiBhbmQKd2hp
+Y2ggaXMgYWxzbyBwYXJ0IG9mIHRoZSBmaW5nZXJwcmludCBjYWxjdWxhdGlvbi4g
+IEVpdGhlciBhIGRhdGUgbGlrZQoiMTk4Ni0wNC0yNiIgb3IgYSBmdWxsIHRpbWVz
+dGFtcCBsaWtlICIxOTg2MDQyNlQwNDI2NDAiIG1heSBiZSB1c2VkLgpUaGUgdGlt
+ZSBpcyBjb25zaWRlcmVkIHRvIGJlIFVUQy4gIFRoZSBzcGVjaWFsIG5vdGF0aW9u
+ICJzZWNvbmRzPU4iCm1heSBiZSB1c2VkIHRvIGRpcmVjdGx5IHNwZWNpZnkgYSB0
+aGUgbnVtYmVyIG9mIHNlY29uZHMgc2luY2UgRXBvY2gKKFVuaXggdGltZSkuICBJ
+ZiBpdCBpcyBub3QgZ2l2ZW4gdGhlIGN1cnJlbnQgdGltZSBpcyB1c2VkLgoKQGl0
+ZW0gUHJlZmVyZW5jZXM6IEB2YXJ7c3RyaW5nfQpTZXQgdGhlIGNpcGhlciwgaGFz
+aCwgYW5kIGNvbXByZXNzaW9uIHByZWZlcmVuY2UgdmFsdWVzIGZvciB0aGlzIGtl
+eS4KVGhpcyBleHBlY3RzIHRoZSBzYW1lIHR5cGUgb2Ygc3RyaW5nIGFzIHRoZSBz
+dWItY29tbWFuZCBAc2FtcHtzZXRwcmVmfQppbiB0aGUgQG9wdGlvbnstLWVkaXQt
+a2V5fSBtZW51LgoKQGl0ZW0gIFJldm9rZXI6IEB2YXJ7YWxnb306QHZhcntmcHJ9
+IFtzZW5zaXRpdmVdCkFkZCBhIGRlc2lnbmF0ZWQgcmV2b2tlciB0byB0aGUgZ2Vu
+ZXJhdGVkIGtleS4gIEFsZ28gaXMgdGhlIHB1YmxpYyBrZXkKYWxnb3JpdGhtIG9m
+IHRoZSBkZXNpZ25hdGVkIHJldm9rZXIgKGkuZS4gUlNBPTEsIERTQT0xNywgZXRj
+LikKQHZhcntmcHJ9IGlzIHRoZSBmaW5nZXJwcmludCBvZiB0aGUgZGVzaWduYXRl
+ZCByZXZva2VyLiAgVGhlIG9wdGlvbmFsCkBzYW1we3NlbnNpdGl2ZX0gZmxhZyBt
+YXJrcyB0aGUgZGVzaWduYXRlZCByZXZva2VyIGFzIHNlbnNpdGl2ZQppbmZvcm1h
+dGlvbi4gIE9ubHkgdjQga2V5cyBtYXkgYmUgZGVzaWduYXRlZCByZXZva2Vycy4K
+CkBpdGVtIEtleXNlcnZlcjogQHZhcntzdHJpbmd9ClRoaXMgaXMgYW4gb3B0aW9u
+YWwgcGFyYW1ldGVyIHRoYXQgc3BlY2lmaWVzIHRoZSBwcmVmZXJyZWQga2V5c2Vy
+dmVyClVSTCBmb3IgdGhlIGtleS4KCkBpdGVtIEhhbmRsZTogQHZhcntzdHJpbmd9
+ClRoaXMgaXMgYW4gb3B0aW9uYWwgcGFyYW1ldGVyIG9ubHkgdXNlZCB3aXRoIHRo
+ZSBzdGF0dXMgbGluZXMKS0VZX0NSRUFURUQgYW5kIEtFWV9OT1RfQ1JFQVRFRC4g
+IEB2YXJ7c3RyaW5nfSBtYXkgYmUgdXAgdG8gMTAwCmNoYXJhY3RlcnMgYW5kIHNo
+b3VsZCBub3QgY29udGFpbiBzcGFjZXMuICBJdCBpcyB1c2VmdWwgZm9yIGJhdGNo
+IGtleQpnZW5lcmF0aW9uIHRvIGFzc29jaWF0ZSBhIGtleSBwYXJhbWV0ZXIgYmxv
+Y2sgd2l0aCBhIHN0YXR1cyBsaW5lLgoKQGVuZCB0YWJsZQoKQG5vaW5kZW50Ckhl
+cmUgaXMgYW4gZXhhbXBsZSBvbiBob3cgdG8gY3JlYXRlIGEga2V5OgpAc21hbGxl
+eGFtcGxlCiQgY2F0ID5mb28gPDxFT0YKICAgICAlZWNobyBHZW5lcmF0aW5nIGEg
+YmFzaWMgT3BlblBHUCBrZXkKICAgICBLZXktVHlwZTogRFNBCiAgICAgS2V5LUxl
+bmd0aDogMTAyNAogICAgIFN1YmtleS1UeXBlOiBFTEctRQogICAgIFN1YmtleS1M
+ZW5ndGg6IDEwMjQKICAgICBOYW1lLVJlYWw6IEpvZSBUZXN0ZXIKICAgICBOYW1l
+LUNvbW1lbnQ6IHdpdGggc3R1cGlkIHBhc3NwaHJhc2UKICAgICBOYW1lLUVtYWls
+OiBqb2VAQGZvby5iYXIKICAgICBFeHBpcmUtRGF0ZTogMAogICAgIFBhc3NwaHJh
+c2U6IGFiYwogICAgICVwdWJyaW5nIGZvby5wdWIKICAgICAlc2VjcmluZyBmb28u
+c2VjCiAgICAgIyBEbyBhIGNvbW1pdCBoZXJlLCBzbyB0aGF0IHdlIGNhbiBsYXRl
+ciBwcmludCAiZG9uZSIgOi0pCiAgICAgJWNvbW1pdAogICAgICVlY2hvIGRvbmUK
+RU9GCiQgZ3BnMiAtLWJhdGNoIC0tZ2VuLWtleSBmb28KIFsuLi5dCiQgZ3BnMiAt
+LW5vLWRlZmF1bHQta2V5cmluZyAtLXNlY3JldC1rZXlyaW5nIC4vZm9vLnNlYyBc
+CiAgICAgICAtLWtleXJpbmcgLi9mb28ucHViIC0tbGlzdC1zZWNyZXQta2V5cwov
+aG9tZS93ay93b3JrL2dudXBnLXN0YWJsZS9zY3JhdGNoL2Zvby5zZWMKLS0tLS0t
+LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnNlYyAgMTAyNEQv
+OTE1QTg3OEQgMjAwMC0wMy0wOSBKb2UgVGVzdGVyICh3aXRoIHN0dXBpZCBwYXNz
+cGhyYXNlKSA8am9lQEBmb28uYmFyPgpzc2IgIDEwMjRnLzhGNzBFMkMwIDIwMDAt
+MDMtMDkKQGVuZCBzbWFsbGV4YW1wbGUKCgpAbm9pbmRlbnQKSWYgeW91IHdhbnQg
+dG8gY3JlYXRlIGEga2V5IHdpdGggdGhlIGRlZmF1bHQgYWxnb3JpdGhtcyB5b3Ug
+d291bGQgdXNlCnRoZXNlIHBhcmFtZXRlcnM6CkBzbWFsbGV4YW1wbGUKICAgICAl
+ZWNobyBHZW5lcmF0aW5nIGEgZGVmYXVsdCBrZXkKICAgICBLZXktVHlwZTogZGVm
+YXVsdAogICAgIFN1YmtleS1UeXBlOiBkZWZhdWx0CiAgICAgTmFtZS1SZWFsOiBK
+b2UgVGVzdGVyCiAgICAgTmFtZS1Db21tZW50OiB3aXRoIHN0dXBpZCBwYXNzcGhy
+YXNlCiAgICAgTmFtZS1FbWFpbDogam9lQEBmb28uYmFyCiAgICAgRXhwaXJlLURh
+dGU6IDAKICAgICBQYXNzcGhyYXNlOiBhYmMKICAgICAlcHVicmluZyBmb28ucHVi
+CiAgICAgJXNlY3JpbmcgZm9vLnNlYwogICAgICMgRG8gYSBjb21taXQgaGVyZSwg
+c28gdGhhdCB3ZSBjYW4gbGF0ZXIgcHJpbnQgImRvbmUiIDotKQogICAgICVjb21t
+aXQKICAgICAlZWNobyBkb25lCkBlbmQgc21hbGxleGFtcGxlCgoKCgpAbWFuc2Vj
+dCBzZWUgYWxzbwpAaWZzZXQgaXNtYW4KQGNvbW1hbmR7Z3Bndn0oMSksCkBjb21t
+YW5ke2dwZ3NtfSgxKSwKQGNvbW1hbmR7Z3BnLWFnZW50fSgxKQpAZW5kIGlmc2V0
+CkBpbmNsdWRlIHNlZS1hbHNvLW5vdGUudGV4aQo=
+=jeqE
+-----END PGP ARMORED FILE-----
index 9a1257c..13c5784 100755 (executable)
@@ -10,7 +10,7 @@ name="$1"
 user_id="$2"
 user_id_no="$3"
 
-echo "abc" | ../g10/gpg2 --options ./gpg.conf --homedir $name \
+echo "abc" | ../g10/gpg --options ./gpg.conf --homedir $name \
                --sign-key --batch --yes --passphrase-fd 0 $user_id \
                $user_id_no sign save
 
index cbbd009..3745a2d 100755 (executable)
@@ -32,7 +32,7 @@ fi
 for x in 8BC90111 3E880CFF F5F77B83 45117079 1EA97479
 do
     if ! echo | $GPG -s -u "$x" | $GPG --verify --status-fd=1 \
-            | grep -q 'VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479'
+            | grep 'VALIDSIG 5FBA84ACE02DCB17DA3DFF6BBCA43C441EA97479' >/dev/null
     then
         echo | $GPG -s -u "$x" | $GPG --verify --status-fd=2
         error "Unexpected key used for signing (not the signing subkey, specified \"$x\")."
@@ -44,7 +44,7 @@ done
 for x in 8BC90111 F5F77B83 1EA97479
 do
     if ! echo | $GPG -s -u "$x!" | $GPG --verify --status-fd=1 \
-            | grep -q "VALIDSIG [0-9A-F]*$x "
+            | grep "VALIDSIG [0-9A-F]*$x " >/dev/null
     then
         echo | $GPG -s -u "$x!" | $GPG --verify --status-fd=2
         error "Unexpected key used for signing (specified: \"$x!\")."
index cb3ffa8..9d265ad 100755 (executable)
@@ -31,7 +31,7 @@ if [ -d private-keys-v1.d ]; then
     rmdir private-keys-v1.d
 fi
 for i in pubring.gpg pubring.gpg~ trustdb.gpg trustdb.gpg~ ; do
-  [ -d "$i" ] && rm "$i"
+  [ -f "$i" ] && rm "$i"
 done
 
 # Now start the agent right away, so that there is only one place
@@ -56,14 +56,12 @@ info "Creating sample data files"
 for i in 500 9000 32000 80000; do
     $MKTDATA  $i >data-$i
 done
-cat $srcdir/../../doc/HACKING \
-    $srcdir/../../doc/DETAILS \
-    $srcdir/../../doc/gpg.texi >plain-large
 
 info "Unpacking samples"
 $GPG --dearmor < $srcdir/plain-1o.asc > ./plain-1
 $GPG --dearmor < $srcdir/plain-2o.asc > ./plain-2
 $GPG --dearmor < $srcdir/plain-3o.asc > ./plain-3
+$GPG --dearmor < $srcdir/plain-largeo.asc > ./plain-large
 
 info "Storing private keys"
 for i in 50B2D4FA4122C212611048BC5FC31BD44393626E \
@@ -107,6 +105,6 @@ $GPG_PRESET_PASSPHRASE --preset -P abc A0747D5F9425E6664F4FFBEED20FBCA79FDED2BD
 
 
 info "Printing the GPG version"
-$GPG --version
+$GPG --version | awk '{print "    > " $0}'
 
 #fixme: check that the output is as expected
index a6b4238..48c4766 100644 (file)
@@ -34,6 +34,8 @@ Usage: gpg-zip [--help] [--version] [--encrypt] [--decrypt] [--symmetric]
 
 Encrypt or sign files into an archive."
 
+tar_verbose_opt="v"
+
 while test $# -gt 0 ; do
   case $1 in
     -h | --help | --h*)
@@ -113,6 +115,10 @@ while test $# -gt 0 ; do
       shift
       shift
       ;;
+    --quiet)
+      tar_verbose_opt=""
+      shift
+      ;;
     --)
       shift
       break
@@ -135,7 +141,7 @@ elif test x$list = xyes ; then
    cat "$1" | $GPG $gpg_args | $TAR $tar_args -tf -
 elif test x$unpack = xyes ; then
 #   echo "cat \"$1\" | $GPG $gpg_args | $TAR $tar_args -xvf -" 1>&2
-   cat "$1" | $GPG $gpg_args | $TAR $tar_args -xvf -
+   cat "$1" | $GPG $gpg_args | $TAR $tar_args -x${tar_verbose_opt}f -
 else
    echo "$usage" 1>&2
    exit 1
index 45e5c90..4dd10a4 100644 (file)
@@ -548,8 +548,8 @@ static gc_option_t gc_options_gpg_agent[] =
    { "no-allow-mark-trusted", GC_OPT_FLAG_RUNTIME,
      GC_LEVEL_ADVANCED, "gnupg", "disallow clients to mark keys as \"trusted\"",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
-   { "allow-loopback-pinentry", GC_OPT_FLAG_RUNTIME,
-     GC_LEVEL_EXPERT, "gnupg", "allow caller to override the pinentry",
+   { "no-allow-loopback-pinentry", GC_OPT_FLAG_RUNTIME,
+     GC_LEVEL_EXPERT, "gnupg", "disallow caller to override the pinentry",
      GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
    { "no-grab", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
      "gnupg", "do not grab keyboard and mouse",
index 98bbad0..57a6203 100644 (file)
@@ -67,7 +67,9 @@ struct parse_info_s {
   int smfm_state;              /* State of PGP/MIME or S/MIME parsing.  */
   int is_smime;                /* This is S/MIME and not PGP/MIME. */
 
-  char *signing_protocol;
+  const char *signing_protocol;
+  const char *signing_protocol_2; /* there are two ways to present
+                                     PKCS7 */
   int hashing_level;           /* The nesting level we are hashing. */
   int hashing;
   FILE *hash_file;
@@ -139,15 +141,15 @@ xmalloc (size_t n)
 /*   return p; */
 /* } */
 
-static char *
-xstrdup (const char *string)
-{
-  void *p = malloc (strlen (string)+1);
-  if (!p)
-    die ("out of core: %s", strerror (errno));
-  strcpy (p, string);
-  return p;
-}
+/* static char * */
+/* xstrdup (const char *string) */
+/* { */
+/*   void *p = malloc (strlen (string)+1); */
+/*   if (!p) */
+/*     die ("out of core: %s", strerror (errno)); */
+/*   strcpy (p, string); */
+/*   return p; */
+/* } */
 
 #ifndef HAVE_STPCPY
 static char *
@@ -364,8 +366,8 @@ mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg,
             {
               info->smfm_state = 1;
               info->is_smime = 0;
-              free (info->signing_protocol);
-              info->signing_protocol = xstrdup (s);
+              info->signing_protocol = "application/pgp-signature";
+              info->signing_protocol_2 = NULL;
             }
         }
       else if (!strcmp (s, "application/pkcs7-signature")
@@ -377,8 +379,8 @@ mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg,
             {
               info->smfm_state = 1;
               info->is_smime = 1;
-              free (info->signing_protocol);
-              info->signing_protocol = xstrdup (s);
+              info->signing_protocol = "application/pkcs7-signature";
+              info->signing_protocol_2 = "application/x-pkcs7-signature";
             }
         }
       else if (verbose)
@@ -516,10 +518,15 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
                   char *buf = xmalloc (strlen (s1) + strlen (s2) + 2);
                   strcpy (stpcpy (stpcpy (buf, s1), "/"), s2);
                   assert (info->signing_protocol);
-                  if (strcmp (buf, info->signing_protocol))
-                    err ("invalid %s structure; expected '%s', found '%s'",
+                  if (strcmp (buf, info->signing_protocol) &&
+                      (!info->signing_protocol_2
+                       || strcmp (buf,info->signing_protocol_2)))
+                    err ("invalid %s structure; expected %s%s%s, found '%s'",
                          info->is_smime? "S/MIME":"PGP/MIME",
-                         info->signing_protocol, buf);
+                         info->signing_protocol,
+                         info->signing_protocol_2 ? " or " : "",
+                         info->signing_protocol_2 ? info->signing_protocol_2:"",
+                         buf);
                   else
                     {
                       printf ("c begin_signature\n");
index 46d06bd..416f514 100644 (file)
@@ -29,7 +29,6 @@
 #include <config.h>
 #include <ctype.h>
 #include <errno.h>
-#include <npth.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
index b197961..0aca035 100644 (file)
@@ -17,6 +17,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 
 #ifndef RAND_MAX   /* for SunOS */
@@ -30,6 +31,11 @@ main(int argc, char **argv)
   int limit =0;
   int char_mode = 0;
 
+#if HAVE_W32_SYSTEM
+  if (setmode (fileno (stdout), O_BINARY) == -1)
+    perror ("setmode");
+#endif
+
   if (argc)
     {
       argc--;